18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*  SuperH Ethernet device driver
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *  Copyright (C) 2014 Renesas Electronics Corporation
58c2ecf20Sopenharmony_ci *  Copyright (C) 2006-2012 Nobuhiro Iwamatsu
68c2ecf20Sopenharmony_ci *  Copyright (C) 2008-2014 Renesas Solutions Corp.
78c2ecf20Sopenharmony_ci *  Copyright (C) 2013-2017 Cogent Embedded, Inc.
88c2ecf20Sopenharmony_ci *  Copyright (C) 2014 Codethink Limited
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
168c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
178c2ecf20Sopenharmony_ci#include <linux/delay.h>
188c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
198c2ecf20Sopenharmony_ci#include <linux/mdio-bitbang.h>
208c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
218c2ecf20Sopenharmony_ci#include <linux/of.h>
228c2ecf20Sopenharmony_ci#include <linux/of_device.h>
238c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
248c2ecf20Sopenharmony_ci#include <linux/of_net.h>
258c2ecf20Sopenharmony_ci#include <linux/phy.h>
268c2ecf20Sopenharmony_ci#include <linux/cache.h>
278c2ecf20Sopenharmony_ci#include <linux/io.h>
288c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
298c2ecf20Sopenharmony_ci#include <linux/slab.h>
308c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
318c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
328c2ecf20Sopenharmony_ci#include <linux/sh_eth.h>
338c2ecf20Sopenharmony_ci#include <linux/of_mdio.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include "sh_eth.h"
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#define SH_ETH_DEF_MSG_ENABLE \
388c2ecf20Sopenharmony_ci		(NETIF_MSG_LINK	| \
398c2ecf20Sopenharmony_ci		NETIF_MSG_TIMER	| \
408c2ecf20Sopenharmony_ci		NETIF_MSG_RX_ERR| \
418c2ecf20Sopenharmony_ci		NETIF_MSG_TX_ERR)
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define SH_ETH_OFFSET_INVALID	((u16)~0)
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define SH_ETH_OFFSET_DEFAULTS			\
468c2ecf20Sopenharmony_ci	[0 ... SH_ETH_MAX_REGISTER_OFFSET - 1] = SH_ETH_OFFSET_INVALID
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/* use some intentionally tricky logic here to initialize the whole struct to
498c2ecf20Sopenharmony_ci * 0xffff, but then override certain fields, requiring us to indicate that we
508c2ecf20Sopenharmony_ci * "know" that there are overrides in this structure, and we'll need to disable
518c2ecf20Sopenharmony_ci * that warning from W=1 builds. GCC has supported this option since 4.2.X, but
528c2ecf20Sopenharmony_ci * the macros available to do this only define GCC 8.
538c2ecf20Sopenharmony_ci */
548c2ecf20Sopenharmony_ci__diag_push();
558c2ecf20Sopenharmony_ci__diag_ignore(GCC, 8, "-Woverride-init",
568c2ecf20Sopenharmony_ci	      "logic to initialize all and then override some is OK");
578c2ecf20Sopenharmony_cistatic const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = {
588c2ecf20Sopenharmony_ci	SH_ETH_OFFSET_DEFAULTS,
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	[EDSR]		= 0x0000,
618c2ecf20Sopenharmony_ci	[EDMR]		= 0x0400,
628c2ecf20Sopenharmony_ci	[EDTRR]		= 0x0408,
638c2ecf20Sopenharmony_ci	[EDRRR]		= 0x0410,
648c2ecf20Sopenharmony_ci	[EESR]		= 0x0428,
658c2ecf20Sopenharmony_ci	[EESIPR]	= 0x0430,
668c2ecf20Sopenharmony_ci	[TDLAR]		= 0x0010,
678c2ecf20Sopenharmony_ci	[TDFAR]		= 0x0014,
688c2ecf20Sopenharmony_ci	[TDFXR]		= 0x0018,
698c2ecf20Sopenharmony_ci	[TDFFR]		= 0x001c,
708c2ecf20Sopenharmony_ci	[RDLAR]		= 0x0030,
718c2ecf20Sopenharmony_ci	[RDFAR]		= 0x0034,
728c2ecf20Sopenharmony_ci	[RDFXR]		= 0x0038,
738c2ecf20Sopenharmony_ci	[RDFFR]		= 0x003c,
748c2ecf20Sopenharmony_ci	[TRSCER]	= 0x0438,
758c2ecf20Sopenharmony_ci	[RMFCR]		= 0x0440,
768c2ecf20Sopenharmony_ci	[TFTR]		= 0x0448,
778c2ecf20Sopenharmony_ci	[FDR]		= 0x0450,
788c2ecf20Sopenharmony_ci	[RMCR]		= 0x0458,
798c2ecf20Sopenharmony_ci	[RPADIR]	= 0x0460,
808c2ecf20Sopenharmony_ci	[FCFTR]		= 0x0468,
818c2ecf20Sopenharmony_ci	[CSMR]		= 0x04E4,
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	[ECMR]		= 0x0500,
848c2ecf20Sopenharmony_ci	[ECSR]		= 0x0510,
858c2ecf20Sopenharmony_ci	[ECSIPR]	= 0x0518,
868c2ecf20Sopenharmony_ci	[PIR]		= 0x0520,
878c2ecf20Sopenharmony_ci	[PSR]		= 0x0528,
888c2ecf20Sopenharmony_ci	[PIPR]		= 0x052c,
898c2ecf20Sopenharmony_ci	[RFLR]		= 0x0508,
908c2ecf20Sopenharmony_ci	[APR]		= 0x0554,
918c2ecf20Sopenharmony_ci	[MPR]		= 0x0558,
928c2ecf20Sopenharmony_ci	[PFTCR]		= 0x055c,
938c2ecf20Sopenharmony_ci	[PFRCR]		= 0x0560,
948c2ecf20Sopenharmony_ci	[TPAUSER]	= 0x0564,
958c2ecf20Sopenharmony_ci	[GECMR]		= 0x05b0,
968c2ecf20Sopenharmony_ci	[BCULR]		= 0x05b4,
978c2ecf20Sopenharmony_ci	[MAHR]		= 0x05c0,
988c2ecf20Sopenharmony_ci	[MALR]		= 0x05c8,
998c2ecf20Sopenharmony_ci	[TROCR]		= 0x0700,
1008c2ecf20Sopenharmony_ci	[CDCR]		= 0x0708,
1018c2ecf20Sopenharmony_ci	[LCCR]		= 0x0710,
1028c2ecf20Sopenharmony_ci	[CEFCR]		= 0x0740,
1038c2ecf20Sopenharmony_ci	[FRECR]		= 0x0748,
1048c2ecf20Sopenharmony_ci	[TSFRCR]	= 0x0750,
1058c2ecf20Sopenharmony_ci	[TLFRCR]	= 0x0758,
1068c2ecf20Sopenharmony_ci	[RFCR]		= 0x0760,
1078c2ecf20Sopenharmony_ci	[CERCR]		= 0x0768,
1088c2ecf20Sopenharmony_ci	[CEECR]		= 0x0770,
1098c2ecf20Sopenharmony_ci	[MAFCR]		= 0x0778,
1108c2ecf20Sopenharmony_ci	[RMII_MII]	= 0x0790,
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	[ARSTR]		= 0x0000,
1138c2ecf20Sopenharmony_ci	[TSU_CTRST]	= 0x0004,
1148c2ecf20Sopenharmony_ci	[TSU_FWEN0]	= 0x0010,
1158c2ecf20Sopenharmony_ci	[TSU_FWEN1]	= 0x0014,
1168c2ecf20Sopenharmony_ci	[TSU_FCM]	= 0x0018,
1178c2ecf20Sopenharmony_ci	[TSU_BSYSL0]	= 0x0020,
1188c2ecf20Sopenharmony_ci	[TSU_BSYSL1]	= 0x0024,
1198c2ecf20Sopenharmony_ci	[TSU_PRISL0]	= 0x0028,
1208c2ecf20Sopenharmony_ci	[TSU_PRISL1]	= 0x002c,
1218c2ecf20Sopenharmony_ci	[TSU_FWSL0]	= 0x0030,
1228c2ecf20Sopenharmony_ci	[TSU_FWSL1]	= 0x0034,
1238c2ecf20Sopenharmony_ci	[TSU_FWSLC]	= 0x0038,
1248c2ecf20Sopenharmony_ci	[TSU_QTAGM0]	= 0x0040,
1258c2ecf20Sopenharmony_ci	[TSU_QTAGM1]	= 0x0044,
1268c2ecf20Sopenharmony_ci	[TSU_FWSR]	= 0x0050,
1278c2ecf20Sopenharmony_ci	[TSU_FWINMK]	= 0x0054,
1288c2ecf20Sopenharmony_ci	[TSU_ADQT0]	= 0x0048,
1298c2ecf20Sopenharmony_ci	[TSU_ADQT1]	= 0x004c,
1308c2ecf20Sopenharmony_ci	[TSU_VTAG0]	= 0x0058,
1318c2ecf20Sopenharmony_ci	[TSU_VTAG1]	= 0x005c,
1328c2ecf20Sopenharmony_ci	[TSU_ADSBSY]	= 0x0060,
1338c2ecf20Sopenharmony_ci	[TSU_TEN]	= 0x0064,
1348c2ecf20Sopenharmony_ci	[TSU_POST1]	= 0x0070,
1358c2ecf20Sopenharmony_ci	[TSU_POST2]	= 0x0074,
1368c2ecf20Sopenharmony_ci	[TSU_POST3]	= 0x0078,
1378c2ecf20Sopenharmony_ci	[TSU_POST4]	= 0x007c,
1388c2ecf20Sopenharmony_ci	[TSU_ADRH0]	= 0x0100,
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	[TXNLCR0]	= 0x0080,
1418c2ecf20Sopenharmony_ci	[TXALCR0]	= 0x0084,
1428c2ecf20Sopenharmony_ci	[RXNLCR0]	= 0x0088,
1438c2ecf20Sopenharmony_ci	[RXALCR0]	= 0x008c,
1448c2ecf20Sopenharmony_ci	[FWNLCR0]	= 0x0090,
1458c2ecf20Sopenharmony_ci	[FWALCR0]	= 0x0094,
1468c2ecf20Sopenharmony_ci	[TXNLCR1]	= 0x00a0,
1478c2ecf20Sopenharmony_ci	[TXALCR1]	= 0x00a4,
1488c2ecf20Sopenharmony_ci	[RXNLCR1]	= 0x00a8,
1498c2ecf20Sopenharmony_ci	[RXALCR1]	= 0x00ac,
1508c2ecf20Sopenharmony_ci	[FWNLCR1]	= 0x00b0,
1518c2ecf20Sopenharmony_ci	[FWALCR1]	= 0x00b4,
1528c2ecf20Sopenharmony_ci};
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic const u16 sh_eth_offset_fast_rcar[SH_ETH_MAX_REGISTER_OFFSET] = {
1558c2ecf20Sopenharmony_ci	SH_ETH_OFFSET_DEFAULTS,
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	[ECMR]		= 0x0300,
1588c2ecf20Sopenharmony_ci	[RFLR]		= 0x0308,
1598c2ecf20Sopenharmony_ci	[ECSR]		= 0x0310,
1608c2ecf20Sopenharmony_ci	[ECSIPR]	= 0x0318,
1618c2ecf20Sopenharmony_ci	[PIR]		= 0x0320,
1628c2ecf20Sopenharmony_ci	[PSR]		= 0x0328,
1638c2ecf20Sopenharmony_ci	[RDMLR]		= 0x0340,
1648c2ecf20Sopenharmony_ci	[IPGR]		= 0x0350,
1658c2ecf20Sopenharmony_ci	[APR]		= 0x0354,
1668c2ecf20Sopenharmony_ci	[MPR]		= 0x0358,
1678c2ecf20Sopenharmony_ci	[RFCF]		= 0x0360,
1688c2ecf20Sopenharmony_ci	[TPAUSER]	= 0x0364,
1698c2ecf20Sopenharmony_ci	[TPAUSECR]	= 0x0368,
1708c2ecf20Sopenharmony_ci	[MAHR]		= 0x03c0,
1718c2ecf20Sopenharmony_ci	[MALR]		= 0x03c8,
1728c2ecf20Sopenharmony_ci	[TROCR]		= 0x03d0,
1738c2ecf20Sopenharmony_ci	[CDCR]		= 0x03d4,
1748c2ecf20Sopenharmony_ci	[LCCR]		= 0x03d8,
1758c2ecf20Sopenharmony_ci	[CNDCR]		= 0x03dc,
1768c2ecf20Sopenharmony_ci	[CEFCR]		= 0x03e4,
1778c2ecf20Sopenharmony_ci	[FRECR]		= 0x03e8,
1788c2ecf20Sopenharmony_ci	[TSFRCR]	= 0x03ec,
1798c2ecf20Sopenharmony_ci	[TLFRCR]	= 0x03f0,
1808c2ecf20Sopenharmony_ci	[RFCR]		= 0x03f4,
1818c2ecf20Sopenharmony_ci	[MAFCR]		= 0x03f8,
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	[EDMR]		= 0x0200,
1848c2ecf20Sopenharmony_ci	[EDTRR]		= 0x0208,
1858c2ecf20Sopenharmony_ci	[EDRRR]		= 0x0210,
1868c2ecf20Sopenharmony_ci	[TDLAR]		= 0x0218,
1878c2ecf20Sopenharmony_ci	[RDLAR]		= 0x0220,
1888c2ecf20Sopenharmony_ci	[EESR]		= 0x0228,
1898c2ecf20Sopenharmony_ci	[EESIPR]	= 0x0230,
1908c2ecf20Sopenharmony_ci	[TRSCER]	= 0x0238,
1918c2ecf20Sopenharmony_ci	[RMFCR]		= 0x0240,
1928c2ecf20Sopenharmony_ci	[TFTR]		= 0x0248,
1938c2ecf20Sopenharmony_ci	[FDR]		= 0x0250,
1948c2ecf20Sopenharmony_ci	[RMCR]		= 0x0258,
1958c2ecf20Sopenharmony_ci	[TFUCR]		= 0x0264,
1968c2ecf20Sopenharmony_ci	[RFOCR]		= 0x0268,
1978c2ecf20Sopenharmony_ci	[RMIIMODE]      = 0x026c,
1988c2ecf20Sopenharmony_ci	[FCFTR]		= 0x0270,
1998c2ecf20Sopenharmony_ci	[TRIMD]		= 0x027c,
2008c2ecf20Sopenharmony_ci};
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
2038c2ecf20Sopenharmony_ci	SH_ETH_OFFSET_DEFAULTS,
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	[ECMR]		= 0x0100,
2068c2ecf20Sopenharmony_ci	[RFLR]		= 0x0108,
2078c2ecf20Sopenharmony_ci	[ECSR]		= 0x0110,
2088c2ecf20Sopenharmony_ci	[ECSIPR]	= 0x0118,
2098c2ecf20Sopenharmony_ci	[PIR]		= 0x0120,
2108c2ecf20Sopenharmony_ci	[PSR]		= 0x0128,
2118c2ecf20Sopenharmony_ci	[RDMLR]		= 0x0140,
2128c2ecf20Sopenharmony_ci	[IPGR]		= 0x0150,
2138c2ecf20Sopenharmony_ci	[APR]		= 0x0154,
2148c2ecf20Sopenharmony_ci	[MPR]		= 0x0158,
2158c2ecf20Sopenharmony_ci	[TPAUSER]	= 0x0164,
2168c2ecf20Sopenharmony_ci	[RFCF]		= 0x0160,
2178c2ecf20Sopenharmony_ci	[TPAUSECR]	= 0x0168,
2188c2ecf20Sopenharmony_ci	[BCFRR]		= 0x016c,
2198c2ecf20Sopenharmony_ci	[MAHR]		= 0x01c0,
2208c2ecf20Sopenharmony_ci	[MALR]		= 0x01c8,
2218c2ecf20Sopenharmony_ci	[TROCR]		= 0x01d0,
2228c2ecf20Sopenharmony_ci	[CDCR]		= 0x01d4,
2238c2ecf20Sopenharmony_ci	[LCCR]		= 0x01d8,
2248c2ecf20Sopenharmony_ci	[CNDCR]		= 0x01dc,
2258c2ecf20Sopenharmony_ci	[CEFCR]		= 0x01e4,
2268c2ecf20Sopenharmony_ci	[FRECR]		= 0x01e8,
2278c2ecf20Sopenharmony_ci	[TSFRCR]	= 0x01ec,
2288c2ecf20Sopenharmony_ci	[TLFRCR]	= 0x01f0,
2298c2ecf20Sopenharmony_ci	[RFCR]		= 0x01f4,
2308c2ecf20Sopenharmony_ci	[MAFCR]		= 0x01f8,
2318c2ecf20Sopenharmony_ci	[RTRATE]	= 0x01fc,
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	[EDMR]		= 0x0000,
2348c2ecf20Sopenharmony_ci	[EDTRR]		= 0x0008,
2358c2ecf20Sopenharmony_ci	[EDRRR]		= 0x0010,
2368c2ecf20Sopenharmony_ci	[TDLAR]		= 0x0018,
2378c2ecf20Sopenharmony_ci	[RDLAR]		= 0x0020,
2388c2ecf20Sopenharmony_ci	[EESR]		= 0x0028,
2398c2ecf20Sopenharmony_ci	[EESIPR]	= 0x0030,
2408c2ecf20Sopenharmony_ci	[TRSCER]	= 0x0038,
2418c2ecf20Sopenharmony_ci	[RMFCR]		= 0x0040,
2428c2ecf20Sopenharmony_ci	[TFTR]		= 0x0048,
2438c2ecf20Sopenharmony_ci	[FDR]		= 0x0050,
2448c2ecf20Sopenharmony_ci	[RMCR]		= 0x0058,
2458c2ecf20Sopenharmony_ci	[TFUCR]		= 0x0064,
2468c2ecf20Sopenharmony_ci	[RFOCR]		= 0x0068,
2478c2ecf20Sopenharmony_ci	[FCFTR]		= 0x0070,
2488c2ecf20Sopenharmony_ci	[RPADIR]	= 0x0078,
2498c2ecf20Sopenharmony_ci	[TRIMD]		= 0x007c,
2508c2ecf20Sopenharmony_ci	[RBWAR]		= 0x00c8,
2518c2ecf20Sopenharmony_ci	[RDFAR]		= 0x00cc,
2528c2ecf20Sopenharmony_ci	[TBRAR]		= 0x00d4,
2538c2ecf20Sopenharmony_ci	[TDFAR]		= 0x00d8,
2548c2ecf20Sopenharmony_ci};
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
2578c2ecf20Sopenharmony_ci	SH_ETH_OFFSET_DEFAULTS,
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	[EDMR]		= 0x0000,
2608c2ecf20Sopenharmony_ci	[EDTRR]		= 0x0004,
2618c2ecf20Sopenharmony_ci	[EDRRR]		= 0x0008,
2628c2ecf20Sopenharmony_ci	[TDLAR]		= 0x000c,
2638c2ecf20Sopenharmony_ci	[RDLAR]		= 0x0010,
2648c2ecf20Sopenharmony_ci	[EESR]		= 0x0014,
2658c2ecf20Sopenharmony_ci	[EESIPR]	= 0x0018,
2668c2ecf20Sopenharmony_ci	[TRSCER]	= 0x001c,
2678c2ecf20Sopenharmony_ci	[RMFCR]		= 0x0020,
2688c2ecf20Sopenharmony_ci	[TFTR]		= 0x0024,
2698c2ecf20Sopenharmony_ci	[FDR]		= 0x0028,
2708c2ecf20Sopenharmony_ci	[RMCR]		= 0x002c,
2718c2ecf20Sopenharmony_ci	[EDOCR]		= 0x0030,
2728c2ecf20Sopenharmony_ci	[FCFTR]		= 0x0034,
2738c2ecf20Sopenharmony_ci	[RPADIR]	= 0x0038,
2748c2ecf20Sopenharmony_ci	[TRIMD]		= 0x003c,
2758c2ecf20Sopenharmony_ci	[RBWAR]		= 0x0040,
2768c2ecf20Sopenharmony_ci	[RDFAR]		= 0x0044,
2778c2ecf20Sopenharmony_ci	[TBRAR]		= 0x004c,
2788c2ecf20Sopenharmony_ci	[TDFAR]		= 0x0050,
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	[ECMR]		= 0x0160,
2818c2ecf20Sopenharmony_ci	[ECSR]		= 0x0164,
2828c2ecf20Sopenharmony_ci	[ECSIPR]	= 0x0168,
2838c2ecf20Sopenharmony_ci	[PIR]		= 0x016c,
2848c2ecf20Sopenharmony_ci	[MAHR]		= 0x0170,
2858c2ecf20Sopenharmony_ci	[MALR]		= 0x0174,
2868c2ecf20Sopenharmony_ci	[RFLR]		= 0x0178,
2878c2ecf20Sopenharmony_ci	[PSR]		= 0x017c,
2888c2ecf20Sopenharmony_ci	[TROCR]		= 0x0180,
2898c2ecf20Sopenharmony_ci	[CDCR]		= 0x0184,
2908c2ecf20Sopenharmony_ci	[LCCR]		= 0x0188,
2918c2ecf20Sopenharmony_ci	[CNDCR]		= 0x018c,
2928c2ecf20Sopenharmony_ci	[CEFCR]		= 0x0194,
2938c2ecf20Sopenharmony_ci	[FRECR]		= 0x0198,
2948c2ecf20Sopenharmony_ci	[TSFRCR]	= 0x019c,
2958c2ecf20Sopenharmony_ci	[TLFRCR]	= 0x01a0,
2968c2ecf20Sopenharmony_ci	[RFCR]		= 0x01a4,
2978c2ecf20Sopenharmony_ci	[MAFCR]		= 0x01a8,
2988c2ecf20Sopenharmony_ci	[IPGR]		= 0x01b4,
2998c2ecf20Sopenharmony_ci	[APR]		= 0x01b8,
3008c2ecf20Sopenharmony_ci	[MPR]		= 0x01bc,
3018c2ecf20Sopenharmony_ci	[TPAUSER]	= 0x01c4,
3028c2ecf20Sopenharmony_ci	[BCFR]		= 0x01cc,
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	[ARSTR]		= 0x0000,
3058c2ecf20Sopenharmony_ci	[TSU_CTRST]	= 0x0004,
3068c2ecf20Sopenharmony_ci	[TSU_FWEN0]	= 0x0010,
3078c2ecf20Sopenharmony_ci	[TSU_FWEN1]	= 0x0014,
3088c2ecf20Sopenharmony_ci	[TSU_FCM]	= 0x0018,
3098c2ecf20Sopenharmony_ci	[TSU_BSYSL0]	= 0x0020,
3108c2ecf20Sopenharmony_ci	[TSU_BSYSL1]	= 0x0024,
3118c2ecf20Sopenharmony_ci	[TSU_PRISL0]	= 0x0028,
3128c2ecf20Sopenharmony_ci	[TSU_PRISL1]	= 0x002c,
3138c2ecf20Sopenharmony_ci	[TSU_FWSL0]	= 0x0030,
3148c2ecf20Sopenharmony_ci	[TSU_FWSL1]	= 0x0034,
3158c2ecf20Sopenharmony_ci	[TSU_FWSLC]	= 0x0038,
3168c2ecf20Sopenharmony_ci	[TSU_QTAGM0]	= 0x0040,
3178c2ecf20Sopenharmony_ci	[TSU_QTAGM1]	= 0x0044,
3188c2ecf20Sopenharmony_ci	[TSU_ADQT0]	= 0x0048,
3198c2ecf20Sopenharmony_ci	[TSU_ADQT1]	= 0x004c,
3208c2ecf20Sopenharmony_ci	[TSU_FWSR]	= 0x0050,
3218c2ecf20Sopenharmony_ci	[TSU_FWINMK]	= 0x0054,
3228c2ecf20Sopenharmony_ci	[TSU_ADSBSY]	= 0x0060,
3238c2ecf20Sopenharmony_ci	[TSU_TEN]	= 0x0064,
3248c2ecf20Sopenharmony_ci	[TSU_POST1]	= 0x0070,
3258c2ecf20Sopenharmony_ci	[TSU_POST2]	= 0x0074,
3268c2ecf20Sopenharmony_ci	[TSU_POST3]	= 0x0078,
3278c2ecf20Sopenharmony_ci	[TSU_POST4]	= 0x007c,
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	[TXNLCR0]	= 0x0080,
3308c2ecf20Sopenharmony_ci	[TXALCR0]	= 0x0084,
3318c2ecf20Sopenharmony_ci	[RXNLCR0]	= 0x0088,
3328c2ecf20Sopenharmony_ci	[RXALCR0]	= 0x008c,
3338c2ecf20Sopenharmony_ci	[FWNLCR0]	= 0x0090,
3348c2ecf20Sopenharmony_ci	[FWALCR0]	= 0x0094,
3358c2ecf20Sopenharmony_ci	[TXNLCR1]	= 0x00a0,
3368c2ecf20Sopenharmony_ci	[TXALCR1]	= 0x00a4,
3378c2ecf20Sopenharmony_ci	[RXNLCR1]	= 0x00a8,
3388c2ecf20Sopenharmony_ci	[RXALCR1]	= 0x00ac,
3398c2ecf20Sopenharmony_ci	[FWNLCR1]	= 0x00b0,
3408c2ecf20Sopenharmony_ci	[FWALCR1]	= 0x00b4,
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	[TSU_ADRH0]	= 0x0100,
3438c2ecf20Sopenharmony_ci};
3448c2ecf20Sopenharmony_ci__diag_pop();
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic void sh_eth_rcv_snd_disable(struct net_device *ndev);
3478c2ecf20Sopenharmony_cistatic struct net_device_stats *sh_eth_get_stats(struct net_device *ndev);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic void sh_eth_write(struct net_device *ndev, u32 data, int enum_index)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
3528c2ecf20Sopenharmony_ci	u16 offset = mdp->reg_offset[enum_index];
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
3558c2ecf20Sopenharmony_ci		return;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	iowrite32(data, mdp->addr + offset);
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic u32 sh_eth_read(struct net_device *ndev, int enum_index)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
3638c2ecf20Sopenharmony_ci	u16 offset = mdp->reg_offset[enum_index];
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
3668c2ecf20Sopenharmony_ci		return ~0U;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	return ioread32(mdp->addr + offset);
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic void sh_eth_modify(struct net_device *ndev, int enum_index, u32 clear,
3728c2ecf20Sopenharmony_ci			  u32 set)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	sh_eth_write(ndev, (sh_eth_read(ndev, enum_index) & ~clear) | set,
3758c2ecf20Sopenharmony_ci		     enum_index);
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic u16 sh_eth_tsu_get_offset(struct sh_eth_private *mdp, int enum_index)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	return mdp->reg_offset[enum_index];
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data,
3848c2ecf20Sopenharmony_ci			     int enum_index)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	u16 offset = sh_eth_tsu_get_offset(mdp, enum_index);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
3898c2ecf20Sopenharmony_ci		return;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	iowrite32(data, mdp->tsu_addr + offset);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cistatic u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	u16 offset = sh_eth_tsu_get_offset(mdp, enum_index);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
3998c2ecf20Sopenharmony_ci		return ~0U;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	return ioread32(mdp->tsu_addr + offset);
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic void sh_eth_soft_swap(char *src, int len)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN
4078c2ecf20Sopenharmony_ci	u32 *p = (u32 *)src;
4088c2ecf20Sopenharmony_ci	u32 *maxp = p + DIV_ROUND_UP(len, sizeof(u32));
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	for (; p < maxp; p++)
4118c2ecf20Sopenharmony_ci		*p = swab32(*p);
4128c2ecf20Sopenharmony_ci#endif
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic void sh_eth_select_mii(struct net_device *ndev)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
4188c2ecf20Sopenharmony_ci	u32 value;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	switch (mdp->phy_interface) {
4218c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII ... PHY_INTERFACE_MODE_RGMII_TXID:
4228c2ecf20Sopenharmony_ci		value = 0x3;
4238c2ecf20Sopenharmony_ci		break;
4248c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_GMII:
4258c2ecf20Sopenharmony_ci		value = 0x2;
4268c2ecf20Sopenharmony_ci		break;
4278c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_MII:
4288c2ecf20Sopenharmony_ci		value = 0x1;
4298c2ecf20Sopenharmony_ci		break;
4308c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RMII:
4318c2ecf20Sopenharmony_ci		value = 0x0;
4328c2ecf20Sopenharmony_ci		break;
4338c2ecf20Sopenharmony_ci	default:
4348c2ecf20Sopenharmony_ci		netdev_warn(ndev,
4358c2ecf20Sopenharmony_ci			    "PHY interface mode was not setup. Set to MII.\n");
4368c2ecf20Sopenharmony_ci		value = 0x1;
4378c2ecf20Sopenharmony_ci		break;
4388c2ecf20Sopenharmony_ci	}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	sh_eth_write(ndev, value, RMII_MII);
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic void sh_eth_set_duplex(struct net_device *ndev)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	sh_eth_modify(ndev, ECMR, ECMR_DM, mdp->duplex ? ECMR_DM : 0);
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic void sh_eth_chip_reset(struct net_device *ndev)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	/* reset device */
4558c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, ARSTR_ARST, ARSTR);
4568c2ecf20Sopenharmony_ci	mdelay(1);
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_cistatic int sh_eth_soft_reset(struct net_device *ndev)
4608c2ecf20Sopenharmony_ci{
4618c2ecf20Sopenharmony_ci	sh_eth_modify(ndev, EDMR, EDMR_SRST_ETHER, EDMR_SRST_ETHER);
4628c2ecf20Sopenharmony_ci	mdelay(3);
4638c2ecf20Sopenharmony_ci	sh_eth_modify(ndev, EDMR, EDMR_SRST_ETHER, 0);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	return 0;
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic int sh_eth_check_soft_reset(struct net_device *ndev)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	int cnt;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	for (cnt = 100; cnt > 0; cnt--) {
4738c2ecf20Sopenharmony_ci		if (!(sh_eth_read(ndev, EDMR) & EDMR_SRST_GETHER))
4748c2ecf20Sopenharmony_ci			return 0;
4758c2ecf20Sopenharmony_ci		mdelay(1);
4768c2ecf20Sopenharmony_ci	}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	netdev_err(ndev, "Device reset failed\n");
4798c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cistatic int sh_eth_soft_reset_gether(struct net_device *ndev)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
4858c2ecf20Sopenharmony_ci	int ret;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	sh_eth_write(ndev, EDSR_ENALL, EDSR);
4888c2ecf20Sopenharmony_ci	sh_eth_modify(ndev, EDMR, EDMR_SRST_GETHER, EDMR_SRST_GETHER);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	ret = sh_eth_check_soft_reset(ndev);
4918c2ecf20Sopenharmony_ci	if (ret)
4928c2ecf20Sopenharmony_ci		return ret;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	/* Table Init */
4958c2ecf20Sopenharmony_ci	sh_eth_write(ndev, 0, TDLAR);
4968c2ecf20Sopenharmony_ci	sh_eth_write(ndev, 0, TDFAR);
4978c2ecf20Sopenharmony_ci	sh_eth_write(ndev, 0, TDFXR);
4988c2ecf20Sopenharmony_ci	sh_eth_write(ndev, 0, TDFFR);
4998c2ecf20Sopenharmony_ci	sh_eth_write(ndev, 0, RDLAR);
5008c2ecf20Sopenharmony_ci	sh_eth_write(ndev, 0, RDFAR);
5018c2ecf20Sopenharmony_ci	sh_eth_write(ndev, 0, RDFXR);
5028c2ecf20Sopenharmony_ci	sh_eth_write(ndev, 0, RDFFR);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	/* Reset HW CRC register */
5058c2ecf20Sopenharmony_ci	if (mdp->cd->csmr)
5068c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0, CSMR);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	/* Select MII mode */
5098c2ecf20Sopenharmony_ci	if (mdp->cd->select_mii)
5108c2ecf20Sopenharmony_ci		sh_eth_select_mii(ndev);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	return ret;
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_cistatic void sh_eth_set_rate_gether(struct net_device *ndev)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	if (WARN_ON(!mdp->cd->gecmr))
5208c2ecf20Sopenharmony_ci		return;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	switch (mdp->speed) {
5238c2ecf20Sopenharmony_ci	case 10: /* 10BASE */
5248c2ecf20Sopenharmony_ci		sh_eth_write(ndev, GECMR_10, GECMR);
5258c2ecf20Sopenharmony_ci		break;
5268c2ecf20Sopenharmony_ci	case 100:/* 100BASE */
5278c2ecf20Sopenharmony_ci		sh_eth_write(ndev, GECMR_100, GECMR);
5288c2ecf20Sopenharmony_ci		break;
5298c2ecf20Sopenharmony_ci	case 1000: /* 1000BASE */
5308c2ecf20Sopenharmony_ci		sh_eth_write(ndev, GECMR_1000, GECMR);
5318c2ecf20Sopenharmony_ci		break;
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
5368c2ecf20Sopenharmony_ci/* R7S72100 */
5378c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data r7s72100_data = {
5388c2ecf20Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset_gether,
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	.chip_reset	= sh_eth_chip_reset,
5418c2ecf20Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	.register_type	= SH_ETH_REG_GIGABIT,
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_GETHER,
5468c2ecf20Sopenharmony_ci	.ecsr_value	= ECSR_ICD,
5478c2ecf20Sopenharmony_ci	.ecsipr_value	= ECSIPR_ICDIP,
5488c2ecf20Sopenharmony_ci	.eesipr_value	= EESIPR_TWB1IP | EESIPR_TWBIP | EESIPR_TC1IP |
5498c2ecf20Sopenharmony_ci			  EESIPR_TABTIP | EESIPR_RABTIP | EESIPR_RFCOFIP |
5508c2ecf20Sopenharmony_ci			  EESIPR_ECIIP |
5518c2ecf20Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
5528c2ecf20Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
5538c2ecf20Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_RRFIP |
5548c2ecf20Sopenharmony_ci			  EESIPR_RTLFIP | EESIPR_RTSFIP |
5558c2ecf20Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	.tx_check	= EESR_TC1 | EESR_FTC,
5588c2ecf20Sopenharmony_ci	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
5598c2ecf20Sopenharmony_ci			  EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
5608c2ecf20Sopenharmony_ci			  EESR_TDE,
5618c2ecf20Sopenharmony_ci	.fdr_value	= 0x0000070f,
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	.trscer_err_mask = DESC_I_RINT8 | DESC_I_RINT5,
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	.no_psr		= 1,
5668c2ecf20Sopenharmony_ci	.apr		= 1,
5678c2ecf20Sopenharmony_ci	.mpr		= 1,
5688c2ecf20Sopenharmony_ci	.tpauser	= 1,
5698c2ecf20Sopenharmony_ci	.hw_swap	= 1,
5708c2ecf20Sopenharmony_ci	.rpadir		= 1,
5718c2ecf20Sopenharmony_ci	.no_trimd	= 1,
5728c2ecf20Sopenharmony_ci	.no_ade		= 1,
5738c2ecf20Sopenharmony_ci	.xdfar_rw	= 1,
5748c2ecf20Sopenharmony_ci	.csmr		= 1,
5758c2ecf20Sopenharmony_ci	.rx_csum	= 1,
5768c2ecf20Sopenharmony_ci	.tsu		= 1,
5778c2ecf20Sopenharmony_ci	.no_tx_cntrs	= 1,
5788c2ecf20Sopenharmony_ci};
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_cistatic void sh_eth_chip_reset_r8a7740(struct net_device *ndev)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	sh_eth_chip_reset(ndev);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	sh_eth_select_mii(ndev);
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci/* R8A7740 */
5888c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data r8a7740_data = {
5898c2ecf20Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset_gether,
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	.chip_reset	= sh_eth_chip_reset_r8a7740,
5928c2ecf20Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
5938c2ecf20Sopenharmony_ci	.set_rate	= sh_eth_set_rate_gether,
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	.register_type	= SH_ETH_REG_GIGABIT,
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_GETHER,
5988c2ecf20Sopenharmony_ci	.ecsr_value	= ECSR_ICD | ECSR_MPD,
5998c2ecf20Sopenharmony_ci	.ecsipr_value	= ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
6008c2ecf20Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
6018c2ecf20Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
6028c2ecf20Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
6038c2ecf20Sopenharmony_ci			  0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP |
6048c2ecf20Sopenharmony_ci			  EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP |
6058c2ecf20Sopenharmony_ci			  EESIPR_CEEFIP | EESIPR_CELFIP |
6068c2ecf20Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
6078c2ecf20Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	.tx_check	= EESR_TC1 | EESR_FTC,
6108c2ecf20Sopenharmony_ci	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
6118c2ecf20Sopenharmony_ci			  EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
6128c2ecf20Sopenharmony_ci			  EESR_TDE,
6138c2ecf20Sopenharmony_ci	.fdr_value	= 0x0000070f,
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	.apr		= 1,
6168c2ecf20Sopenharmony_ci	.mpr		= 1,
6178c2ecf20Sopenharmony_ci	.tpauser	= 1,
6188c2ecf20Sopenharmony_ci	.gecmr		= 1,
6198c2ecf20Sopenharmony_ci	.bculr		= 1,
6208c2ecf20Sopenharmony_ci	.hw_swap	= 1,
6218c2ecf20Sopenharmony_ci	.rpadir		= 1,
6228c2ecf20Sopenharmony_ci	.no_trimd	= 1,
6238c2ecf20Sopenharmony_ci	.no_ade		= 1,
6248c2ecf20Sopenharmony_ci	.xdfar_rw	= 1,
6258c2ecf20Sopenharmony_ci	.csmr		= 1,
6268c2ecf20Sopenharmony_ci	.rx_csum	= 1,
6278c2ecf20Sopenharmony_ci	.tsu		= 1,
6288c2ecf20Sopenharmony_ci	.select_mii	= 1,
6298c2ecf20Sopenharmony_ci	.magic		= 1,
6308c2ecf20Sopenharmony_ci	.cexcr		= 1,
6318c2ecf20Sopenharmony_ci};
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci/* There is CPU dependent code */
6348c2ecf20Sopenharmony_cistatic void sh_eth_set_rate_rcar(struct net_device *ndev)
6358c2ecf20Sopenharmony_ci{
6368c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	switch (mdp->speed) {
6398c2ecf20Sopenharmony_ci	case 10: /* 10BASE */
6408c2ecf20Sopenharmony_ci		sh_eth_modify(ndev, ECMR, ECMR_ELB, 0);
6418c2ecf20Sopenharmony_ci		break;
6428c2ecf20Sopenharmony_ci	case 100:/* 100BASE */
6438c2ecf20Sopenharmony_ci		sh_eth_modify(ndev, ECMR, ECMR_ELB, ECMR_ELB);
6448c2ecf20Sopenharmony_ci		break;
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci/* R-Car Gen1 */
6498c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data rcar_gen1_data = {
6508c2ecf20Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
6538c2ecf20Sopenharmony_ci	.set_rate	= sh_eth_set_rate_rcar,
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_RCAR,
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
6588c2ecf20Sopenharmony_ci	.ecsr_value	= ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD,
6598c2ecf20Sopenharmony_ci	.ecsipr_value	= ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP,
6608c2ecf20Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ADEIP | EESIPR_ECIIP |
6618c2ecf20Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
6628c2ecf20Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
6638c2ecf20Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_RRFIP |
6648c2ecf20Sopenharmony_ci			  EESIPR_RTLFIP | EESIPR_RTSFIP |
6658c2ecf20Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	.tx_check	= EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO,
6688c2ecf20Sopenharmony_ci	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
6698c2ecf20Sopenharmony_ci			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE,
6708c2ecf20Sopenharmony_ci	.fdr_value	= 0x00000f0f,
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	.apr		= 1,
6738c2ecf20Sopenharmony_ci	.mpr		= 1,
6748c2ecf20Sopenharmony_ci	.tpauser	= 1,
6758c2ecf20Sopenharmony_ci	.hw_swap	= 1,
6768c2ecf20Sopenharmony_ci	.no_xdfar	= 1,
6778c2ecf20Sopenharmony_ci};
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci/* R-Car Gen2 and RZ/G1 */
6808c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data rcar_gen2_data = {
6818c2ecf20Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
6848c2ecf20Sopenharmony_ci	.set_rate	= sh_eth_set_rate_rcar,
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_RCAR,
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
6898c2ecf20Sopenharmony_ci	.ecsr_value	= ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD | ECSR_MPD,
6908c2ecf20Sopenharmony_ci	.ecsipr_value	= ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP |
6918c2ecf20Sopenharmony_ci			  ECSIPR_MPDIP,
6928c2ecf20Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ADEIP | EESIPR_ECIIP |
6938c2ecf20Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
6948c2ecf20Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
6958c2ecf20Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_RRFIP |
6968c2ecf20Sopenharmony_ci			  EESIPR_RTLFIP | EESIPR_RTSFIP |
6978c2ecf20Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	.tx_check	= EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO,
7008c2ecf20Sopenharmony_ci	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
7018c2ecf20Sopenharmony_ci			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE,
7028c2ecf20Sopenharmony_ci	.fdr_value	= 0x00000f0f,
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	.trscer_err_mask = DESC_I_RINT8,
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	.apr		= 1,
7078c2ecf20Sopenharmony_ci	.mpr		= 1,
7088c2ecf20Sopenharmony_ci	.tpauser	= 1,
7098c2ecf20Sopenharmony_ci	.hw_swap	= 1,
7108c2ecf20Sopenharmony_ci	.no_xdfar	= 1,
7118c2ecf20Sopenharmony_ci	.rmiimode	= 1,
7128c2ecf20Sopenharmony_ci	.magic		= 1,
7138c2ecf20Sopenharmony_ci};
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci/* R8A77980 */
7168c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data r8a77980_data = {
7178c2ecf20Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset_gether,
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
7208c2ecf20Sopenharmony_ci	.set_rate	= sh_eth_set_rate_gether,
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	.register_type  = SH_ETH_REG_GIGABIT,
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_GETHER,
7258c2ecf20Sopenharmony_ci	.ecsr_value	= ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD | ECSR_MPD,
7268c2ecf20Sopenharmony_ci	.ecsipr_value	= ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP |
7278c2ecf20Sopenharmony_ci			  ECSIPR_MPDIP,
7288c2ecf20Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
7298c2ecf20Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
7308c2ecf20Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
7318c2ecf20Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_RRFIP |
7328c2ecf20Sopenharmony_ci			  EESIPR_RTLFIP | EESIPR_RTSFIP |
7338c2ecf20Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	.tx_check       = EESR_FTC | EESR_CD | EESR_TRO,
7368c2ecf20Sopenharmony_ci	.eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
7378c2ecf20Sopenharmony_ci			  EESR_RFE | EESR_RDE | EESR_RFRMER |
7388c2ecf20Sopenharmony_ci			  EESR_TFE | EESR_TDE | EESR_ECI,
7398c2ecf20Sopenharmony_ci	.fdr_value	= 0x0000070f,
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	.apr		= 1,
7428c2ecf20Sopenharmony_ci	.mpr		= 1,
7438c2ecf20Sopenharmony_ci	.tpauser	= 1,
7448c2ecf20Sopenharmony_ci	.gecmr		= 1,
7458c2ecf20Sopenharmony_ci	.bculr		= 1,
7468c2ecf20Sopenharmony_ci	.hw_swap	= 1,
7478c2ecf20Sopenharmony_ci	.nbst		= 1,
7488c2ecf20Sopenharmony_ci	.rpadir		= 1,
7498c2ecf20Sopenharmony_ci	.no_trimd	= 1,
7508c2ecf20Sopenharmony_ci	.no_ade		= 1,
7518c2ecf20Sopenharmony_ci	.xdfar_rw	= 1,
7528c2ecf20Sopenharmony_ci	.csmr		= 1,
7538c2ecf20Sopenharmony_ci	.rx_csum	= 1,
7548c2ecf20Sopenharmony_ci	.select_mii	= 1,
7558c2ecf20Sopenharmony_ci	.magic		= 1,
7568c2ecf20Sopenharmony_ci	.cexcr		= 1,
7578c2ecf20Sopenharmony_ci};
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci/* R7S9210 */
7608c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data r7s9210_data = {
7618c2ecf20Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
7648c2ecf20Sopenharmony_ci	.set_rate	= sh_eth_set_rate_rcar,
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_SH4,
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
7698c2ecf20Sopenharmony_ci	.ecsr_value	= ECSR_ICD,
7708c2ecf20Sopenharmony_ci	.ecsipr_value	= ECSIPR_ICDIP,
7718c2ecf20Sopenharmony_ci	.eesipr_value	= EESIPR_TWBIP | EESIPR_TABTIP | EESIPR_RABTIP |
7728c2ecf20Sopenharmony_ci			  EESIPR_RFCOFIP | EESIPR_ECIIP | EESIPR_FTCIP |
7738c2ecf20Sopenharmony_ci			  EESIPR_TDEIP | EESIPR_TFUFIP | EESIPR_FRIP |
7748c2ecf20Sopenharmony_ci			  EESIPR_RDEIP | EESIPR_RFOFIP | EESIPR_CNDIP |
7758c2ecf20Sopenharmony_ci			  EESIPR_DLCIP | EESIPR_CDIP | EESIPR_TROIP |
7768c2ecf20Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_RRFIP | EESIPR_RTLFIP |
7778c2ecf20Sopenharmony_ci			  EESIPR_RTSFIP | EESIPR_PREIP | EESIPR_CERFIP,
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	.tx_check	= EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO,
7808c2ecf20Sopenharmony_ci	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
7818c2ecf20Sopenharmony_ci			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE,
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	.fdr_value	= 0x0000070f,
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	.trscer_err_mask = DESC_I_RINT8 | DESC_I_RINT5,
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	.apr		= 1,
7888c2ecf20Sopenharmony_ci	.mpr		= 1,
7898c2ecf20Sopenharmony_ci	.tpauser	= 1,
7908c2ecf20Sopenharmony_ci	.hw_swap	= 1,
7918c2ecf20Sopenharmony_ci	.rpadir		= 1,
7928c2ecf20Sopenharmony_ci	.no_ade		= 1,
7938c2ecf20Sopenharmony_ci	.xdfar_rw	= 1,
7948c2ecf20Sopenharmony_ci};
7958c2ecf20Sopenharmony_ci#endif /* CONFIG_OF */
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_cistatic void sh_eth_set_rate_sh7724(struct net_device *ndev)
7988c2ecf20Sopenharmony_ci{
7998c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	switch (mdp->speed) {
8028c2ecf20Sopenharmony_ci	case 10: /* 10BASE */
8038c2ecf20Sopenharmony_ci		sh_eth_modify(ndev, ECMR, ECMR_RTM, 0);
8048c2ecf20Sopenharmony_ci		break;
8058c2ecf20Sopenharmony_ci	case 100:/* 100BASE */
8068c2ecf20Sopenharmony_ci		sh_eth_modify(ndev, ECMR, ECMR_RTM, ECMR_RTM);
8078c2ecf20Sopenharmony_ci		break;
8088c2ecf20Sopenharmony_ci	}
8098c2ecf20Sopenharmony_ci}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci/* SH7724 */
8128c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh7724_data = {
8138c2ecf20Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
8168c2ecf20Sopenharmony_ci	.set_rate	= sh_eth_set_rate_sh7724,
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_SH4,
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
8218c2ecf20Sopenharmony_ci	.ecsr_value	= ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD,
8228c2ecf20Sopenharmony_ci	.ecsipr_value	= ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP,
8238c2ecf20Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ADEIP | EESIPR_ECIIP |
8248c2ecf20Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
8258c2ecf20Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
8268c2ecf20Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_RRFIP |
8278c2ecf20Sopenharmony_ci			  EESIPR_RTLFIP | EESIPR_RTSFIP |
8288c2ecf20Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	.tx_check	= EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO,
8318c2ecf20Sopenharmony_ci	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
8328c2ecf20Sopenharmony_ci			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE,
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	.apr		= 1,
8358c2ecf20Sopenharmony_ci	.mpr		= 1,
8368c2ecf20Sopenharmony_ci	.tpauser	= 1,
8378c2ecf20Sopenharmony_ci	.hw_swap	= 1,
8388c2ecf20Sopenharmony_ci	.rpadir		= 1,
8398c2ecf20Sopenharmony_ci};
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_cistatic void sh_eth_set_rate_sh7757(struct net_device *ndev)
8428c2ecf20Sopenharmony_ci{
8438c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	switch (mdp->speed) {
8468c2ecf20Sopenharmony_ci	case 10: /* 10BASE */
8478c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0, RTRATE);
8488c2ecf20Sopenharmony_ci		break;
8498c2ecf20Sopenharmony_ci	case 100:/* 100BASE */
8508c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 1, RTRATE);
8518c2ecf20Sopenharmony_ci		break;
8528c2ecf20Sopenharmony_ci	}
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci/* SH7757 */
8568c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh7757_data = {
8578c2ecf20Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
8608c2ecf20Sopenharmony_ci	.set_rate	= sh_eth_set_rate_sh7757,
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_SH4,
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
8658c2ecf20Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
8668c2ecf20Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
8678c2ecf20Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
8688c2ecf20Sopenharmony_ci			  0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP |
8698c2ecf20Sopenharmony_ci			  EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP |
8708c2ecf20Sopenharmony_ci			  EESIPR_CEEFIP | EESIPR_CELFIP |
8718c2ecf20Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
8728c2ecf20Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	.tx_check	= EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO,
8758c2ecf20Sopenharmony_ci	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
8768c2ecf20Sopenharmony_ci			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE,
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	.irq_flags	= IRQF_SHARED,
8798c2ecf20Sopenharmony_ci	.apr		= 1,
8808c2ecf20Sopenharmony_ci	.mpr		= 1,
8818c2ecf20Sopenharmony_ci	.tpauser	= 1,
8828c2ecf20Sopenharmony_ci	.hw_swap	= 1,
8838c2ecf20Sopenharmony_ci	.no_ade		= 1,
8848c2ecf20Sopenharmony_ci	.rpadir		= 1,
8858c2ecf20Sopenharmony_ci	.rtrate		= 1,
8868c2ecf20Sopenharmony_ci	.dual_port	= 1,
8878c2ecf20Sopenharmony_ci};
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci#define SH_GIGA_ETH_BASE	0xfee00000UL
8908c2ecf20Sopenharmony_ci#define GIGA_MALR(port)		(SH_GIGA_ETH_BASE + 0x800 * (port) + 0x05c8)
8918c2ecf20Sopenharmony_ci#define GIGA_MAHR(port)		(SH_GIGA_ETH_BASE + 0x800 * (port) + 0x05c0)
8928c2ecf20Sopenharmony_cistatic void sh_eth_chip_reset_giga(struct net_device *ndev)
8938c2ecf20Sopenharmony_ci{
8948c2ecf20Sopenharmony_ci	u32 mahr[2], malr[2];
8958c2ecf20Sopenharmony_ci	int i;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	/* save MAHR and MALR */
8988c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
8998c2ecf20Sopenharmony_ci		malr[i] = ioread32((void *)GIGA_MALR(i));
9008c2ecf20Sopenharmony_ci		mahr[i] = ioread32((void *)GIGA_MAHR(i));
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	sh_eth_chip_reset(ndev);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	/* restore MAHR and MALR */
9068c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
9078c2ecf20Sopenharmony_ci		iowrite32(malr[i], (void *)GIGA_MALR(i));
9088c2ecf20Sopenharmony_ci		iowrite32(mahr[i], (void *)GIGA_MAHR(i));
9098c2ecf20Sopenharmony_ci	}
9108c2ecf20Sopenharmony_ci}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_cistatic void sh_eth_set_rate_giga(struct net_device *ndev)
9138c2ecf20Sopenharmony_ci{
9148c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	if (WARN_ON(!mdp->cd->gecmr))
9178c2ecf20Sopenharmony_ci		return;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	switch (mdp->speed) {
9208c2ecf20Sopenharmony_ci	case 10: /* 10BASE */
9218c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0x00000000, GECMR);
9228c2ecf20Sopenharmony_ci		break;
9238c2ecf20Sopenharmony_ci	case 100:/* 100BASE */
9248c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0x00000010, GECMR);
9258c2ecf20Sopenharmony_ci		break;
9268c2ecf20Sopenharmony_ci	case 1000: /* 1000BASE */
9278c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0x00000020, GECMR);
9288c2ecf20Sopenharmony_ci		break;
9298c2ecf20Sopenharmony_ci	}
9308c2ecf20Sopenharmony_ci}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci/* SH7757(GETHERC) */
9338c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh7757_data_giga = {
9348c2ecf20Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset_gether,
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	.chip_reset	= sh_eth_chip_reset_giga,
9378c2ecf20Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
9388c2ecf20Sopenharmony_ci	.set_rate	= sh_eth_set_rate_giga,
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	.register_type	= SH_ETH_REG_GIGABIT,
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_GETHER,
9438c2ecf20Sopenharmony_ci	.ecsr_value	= ECSR_ICD | ECSR_MPD,
9448c2ecf20Sopenharmony_ci	.ecsipr_value	= ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
9458c2ecf20Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
9468c2ecf20Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
9478c2ecf20Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
9488c2ecf20Sopenharmony_ci			  0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP |
9498c2ecf20Sopenharmony_ci			  EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP |
9508c2ecf20Sopenharmony_ci			  EESIPR_CEEFIP | EESIPR_CELFIP |
9518c2ecf20Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
9528c2ecf20Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	.tx_check	= EESR_TC1 | EESR_FTC,
9558c2ecf20Sopenharmony_ci	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
9568c2ecf20Sopenharmony_ci			  EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
9578c2ecf20Sopenharmony_ci			  EESR_TDE,
9588c2ecf20Sopenharmony_ci	.fdr_value	= 0x0000072f,
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	.irq_flags	= IRQF_SHARED,
9618c2ecf20Sopenharmony_ci	.apr		= 1,
9628c2ecf20Sopenharmony_ci	.mpr		= 1,
9638c2ecf20Sopenharmony_ci	.tpauser	= 1,
9648c2ecf20Sopenharmony_ci	.gecmr		= 1,
9658c2ecf20Sopenharmony_ci	.bculr		= 1,
9668c2ecf20Sopenharmony_ci	.hw_swap	= 1,
9678c2ecf20Sopenharmony_ci	.rpadir		= 1,
9688c2ecf20Sopenharmony_ci	.no_trimd	= 1,
9698c2ecf20Sopenharmony_ci	.no_ade		= 1,
9708c2ecf20Sopenharmony_ci	.xdfar_rw	= 1,
9718c2ecf20Sopenharmony_ci	.tsu		= 1,
9728c2ecf20Sopenharmony_ci	.cexcr		= 1,
9738c2ecf20Sopenharmony_ci	.dual_port	= 1,
9748c2ecf20Sopenharmony_ci};
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci/* SH7734 */
9778c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh7734_data = {
9788c2ecf20Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset_gether,
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	.chip_reset	= sh_eth_chip_reset,
9818c2ecf20Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
9828c2ecf20Sopenharmony_ci	.set_rate	= sh_eth_set_rate_gether,
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	.register_type	= SH_ETH_REG_GIGABIT,
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_GETHER,
9878c2ecf20Sopenharmony_ci	.ecsr_value	= ECSR_ICD | ECSR_MPD,
9888c2ecf20Sopenharmony_ci	.ecsipr_value	= ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
9898c2ecf20Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
9908c2ecf20Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
9918c2ecf20Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
9928c2ecf20Sopenharmony_ci			  EESIPR_DLCIP | EESIPR_CDIP | EESIPR_TROIP |
9938c2ecf20Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_CEEFIP | EESIPR_CELFIP |
9948c2ecf20Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
9958c2ecf20Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	.tx_check	= EESR_TC1 | EESR_FTC,
9988c2ecf20Sopenharmony_ci	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
9998c2ecf20Sopenharmony_ci			  EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
10008c2ecf20Sopenharmony_ci			  EESR_TDE,
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	.apr		= 1,
10038c2ecf20Sopenharmony_ci	.mpr		= 1,
10048c2ecf20Sopenharmony_ci	.tpauser	= 1,
10058c2ecf20Sopenharmony_ci	.gecmr		= 1,
10068c2ecf20Sopenharmony_ci	.bculr		= 1,
10078c2ecf20Sopenharmony_ci	.hw_swap	= 1,
10088c2ecf20Sopenharmony_ci	.no_trimd	= 1,
10098c2ecf20Sopenharmony_ci	.no_ade		= 1,
10108c2ecf20Sopenharmony_ci	.xdfar_rw	= 1,
10118c2ecf20Sopenharmony_ci	.tsu		= 1,
10128c2ecf20Sopenharmony_ci	.csmr		= 1,
10138c2ecf20Sopenharmony_ci	.rx_csum	= 1,
10148c2ecf20Sopenharmony_ci	.select_mii	= 1,
10158c2ecf20Sopenharmony_ci	.magic		= 1,
10168c2ecf20Sopenharmony_ci	.cexcr		= 1,
10178c2ecf20Sopenharmony_ci};
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci/* SH7763 */
10208c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh7763_data = {
10218c2ecf20Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset_gether,
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	.chip_reset	= sh_eth_chip_reset,
10248c2ecf20Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
10258c2ecf20Sopenharmony_ci	.set_rate	= sh_eth_set_rate_gether,
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	.register_type	= SH_ETH_REG_GIGABIT,
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_GETHER,
10308c2ecf20Sopenharmony_ci	.ecsr_value	= ECSR_ICD | ECSR_MPD,
10318c2ecf20Sopenharmony_ci	.ecsipr_value	= ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
10328c2ecf20Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
10338c2ecf20Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
10348c2ecf20Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
10358c2ecf20Sopenharmony_ci			  EESIPR_DLCIP | EESIPR_CDIP | EESIPR_TROIP |
10368c2ecf20Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_CEEFIP | EESIPR_CELFIP |
10378c2ecf20Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
10388c2ecf20Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	.tx_check	= EESR_TC1 | EESR_FTC,
10418c2ecf20Sopenharmony_ci	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
10428c2ecf20Sopenharmony_ci			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE,
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	.apr		= 1,
10458c2ecf20Sopenharmony_ci	.mpr		= 1,
10468c2ecf20Sopenharmony_ci	.tpauser	= 1,
10478c2ecf20Sopenharmony_ci	.gecmr		= 1,
10488c2ecf20Sopenharmony_ci	.bculr		= 1,
10498c2ecf20Sopenharmony_ci	.hw_swap	= 1,
10508c2ecf20Sopenharmony_ci	.no_trimd	= 1,
10518c2ecf20Sopenharmony_ci	.no_ade		= 1,
10528c2ecf20Sopenharmony_ci	.xdfar_rw	= 1,
10538c2ecf20Sopenharmony_ci	.tsu		= 1,
10548c2ecf20Sopenharmony_ci	.irq_flags	= IRQF_SHARED,
10558c2ecf20Sopenharmony_ci	.magic		= 1,
10568c2ecf20Sopenharmony_ci	.cexcr		= 1,
10578c2ecf20Sopenharmony_ci	.rx_csum	= 1,
10588c2ecf20Sopenharmony_ci	.dual_port	= 1,
10598c2ecf20Sopenharmony_ci};
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh7619_data = {
10628c2ecf20Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_SH3_SH2,
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
10678c2ecf20Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
10688c2ecf20Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
10698c2ecf20Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
10708c2ecf20Sopenharmony_ci			  0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP |
10718c2ecf20Sopenharmony_ci			  EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP |
10728c2ecf20Sopenharmony_ci			  EESIPR_CEEFIP | EESIPR_CELFIP |
10738c2ecf20Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
10748c2ecf20Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	.apr		= 1,
10778c2ecf20Sopenharmony_ci	.mpr		= 1,
10788c2ecf20Sopenharmony_ci	.tpauser	= 1,
10798c2ecf20Sopenharmony_ci	.hw_swap	= 1,
10808c2ecf20Sopenharmony_ci};
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh771x_data = {
10838c2ecf20Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_SH3_SH2,
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
10888c2ecf20Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
10898c2ecf20Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
10908c2ecf20Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
10918c2ecf20Sopenharmony_ci			  0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP |
10928c2ecf20Sopenharmony_ci			  EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP |
10938c2ecf20Sopenharmony_ci			  EESIPR_CEEFIP | EESIPR_CELFIP |
10948c2ecf20Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
10958c2ecf20Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	.trscer_err_mask = DESC_I_RINT8,
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	.tsu		= 1,
11008c2ecf20Sopenharmony_ci	.dual_port	= 1,
11018c2ecf20Sopenharmony_ci};
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_cistatic void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd)
11048c2ecf20Sopenharmony_ci{
11058c2ecf20Sopenharmony_ci	if (!cd->ecsr_value)
11068c2ecf20Sopenharmony_ci		cd->ecsr_value = DEFAULT_ECSR_INIT;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	if (!cd->ecsipr_value)
11098c2ecf20Sopenharmony_ci		cd->ecsipr_value = DEFAULT_ECSIPR_INIT;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	if (!cd->fcftr_value)
11128c2ecf20Sopenharmony_ci		cd->fcftr_value = DEFAULT_FIFO_F_D_RFF |
11138c2ecf20Sopenharmony_ci				  DEFAULT_FIFO_F_D_RFD;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	if (!cd->fdr_value)
11168c2ecf20Sopenharmony_ci		cd->fdr_value = DEFAULT_FDR_INIT;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	if (!cd->tx_check)
11198c2ecf20Sopenharmony_ci		cd->tx_check = DEFAULT_TX_CHECK;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	if (!cd->eesr_err_check)
11228c2ecf20Sopenharmony_ci		cd->eesr_err_check = DEFAULT_EESR_ERR_CHECK;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	if (!cd->trscer_err_mask)
11258c2ecf20Sopenharmony_ci		cd->trscer_err_mask = DEFAULT_TRSCER_ERR_MASK;
11268c2ecf20Sopenharmony_ci}
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_cistatic void sh_eth_set_receive_align(struct sk_buff *skb)
11298c2ecf20Sopenharmony_ci{
11308c2ecf20Sopenharmony_ci	uintptr_t reserve = (uintptr_t)skb->data & (SH_ETH_RX_ALIGN - 1);
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	if (reserve)
11338c2ecf20Sopenharmony_ci		skb_reserve(skb, SH_ETH_RX_ALIGN - reserve);
11348c2ecf20Sopenharmony_ci}
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci/* Program the hardware MAC address from dev->dev_addr. */
11378c2ecf20Sopenharmony_cistatic void update_mac_address(struct net_device *ndev)
11388c2ecf20Sopenharmony_ci{
11398c2ecf20Sopenharmony_ci	sh_eth_write(ndev,
11408c2ecf20Sopenharmony_ci		     (ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) |
11418c2ecf20Sopenharmony_ci		     (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]), MAHR);
11428c2ecf20Sopenharmony_ci	sh_eth_write(ndev,
11438c2ecf20Sopenharmony_ci		     (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]), MALR);
11448c2ecf20Sopenharmony_ci}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci/* Get MAC address from SuperH MAC address register
11478c2ecf20Sopenharmony_ci *
11488c2ecf20Sopenharmony_ci * SuperH's Ethernet device doesn't have 'ROM' to MAC address.
11498c2ecf20Sopenharmony_ci * This driver get MAC address that use by bootloader(U-boot or sh-ipl+g).
11508c2ecf20Sopenharmony_ci * When you want use this device, you must set MAC address in bootloader.
11518c2ecf20Sopenharmony_ci *
11528c2ecf20Sopenharmony_ci */
11538c2ecf20Sopenharmony_cistatic void read_mac_address(struct net_device *ndev, unsigned char *mac)
11548c2ecf20Sopenharmony_ci{
11558c2ecf20Sopenharmony_ci	if (mac[0] || mac[1] || mac[2] || mac[3] || mac[4] || mac[5]) {
11568c2ecf20Sopenharmony_ci		memcpy(ndev->dev_addr, mac, ETH_ALEN);
11578c2ecf20Sopenharmony_ci	} else {
11588c2ecf20Sopenharmony_ci		u32 mahr = sh_eth_read(ndev, MAHR);
11598c2ecf20Sopenharmony_ci		u32 malr = sh_eth_read(ndev, MALR);
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci		ndev->dev_addr[0] = (mahr >> 24) & 0xFF;
11628c2ecf20Sopenharmony_ci		ndev->dev_addr[1] = (mahr >> 16) & 0xFF;
11638c2ecf20Sopenharmony_ci		ndev->dev_addr[2] = (mahr >>  8) & 0xFF;
11648c2ecf20Sopenharmony_ci		ndev->dev_addr[3] = (mahr >>  0) & 0xFF;
11658c2ecf20Sopenharmony_ci		ndev->dev_addr[4] = (malr >>  8) & 0xFF;
11668c2ecf20Sopenharmony_ci		ndev->dev_addr[5] = (malr >>  0) & 0xFF;
11678c2ecf20Sopenharmony_ci	}
11688c2ecf20Sopenharmony_ci}
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_cistruct bb_info {
11718c2ecf20Sopenharmony_ci	void (*set_gate)(void *addr);
11728c2ecf20Sopenharmony_ci	struct mdiobb_ctrl ctrl;
11738c2ecf20Sopenharmony_ci	void *addr;
11748c2ecf20Sopenharmony_ci};
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_cistatic void sh_mdio_ctrl(struct mdiobb_ctrl *ctrl, u32 mask, int set)
11778c2ecf20Sopenharmony_ci{
11788c2ecf20Sopenharmony_ci	struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
11798c2ecf20Sopenharmony_ci	u32 pir;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	if (bitbang->set_gate)
11828c2ecf20Sopenharmony_ci		bitbang->set_gate(bitbang->addr);
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	pir = ioread32(bitbang->addr);
11858c2ecf20Sopenharmony_ci	if (set)
11868c2ecf20Sopenharmony_ci		pir |=  mask;
11878c2ecf20Sopenharmony_ci	else
11888c2ecf20Sopenharmony_ci		pir &= ~mask;
11898c2ecf20Sopenharmony_ci	iowrite32(pir, bitbang->addr);
11908c2ecf20Sopenharmony_ci}
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci/* Data I/O pin control */
11938c2ecf20Sopenharmony_cistatic void sh_mmd_ctrl(struct mdiobb_ctrl *ctrl, int bit)
11948c2ecf20Sopenharmony_ci{
11958c2ecf20Sopenharmony_ci	sh_mdio_ctrl(ctrl, PIR_MMD, bit);
11968c2ecf20Sopenharmony_ci}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci/* Set bit data*/
11998c2ecf20Sopenharmony_cistatic void sh_set_mdio(struct mdiobb_ctrl *ctrl, int bit)
12008c2ecf20Sopenharmony_ci{
12018c2ecf20Sopenharmony_ci	sh_mdio_ctrl(ctrl, PIR_MDO, bit);
12028c2ecf20Sopenharmony_ci}
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci/* Get bit data*/
12058c2ecf20Sopenharmony_cistatic int sh_get_mdio(struct mdiobb_ctrl *ctrl)
12068c2ecf20Sopenharmony_ci{
12078c2ecf20Sopenharmony_ci	struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	if (bitbang->set_gate)
12108c2ecf20Sopenharmony_ci		bitbang->set_gate(bitbang->addr);
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	return (ioread32(bitbang->addr) & PIR_MDI) != 0;
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci/* MDC pin control */
12168c2ecf20Sopenharmony_cistatic void sh_mdc_ctrl(struct mdiobb_ctrl *ctrl, int bit)
12178c2ecf20Sopenharmony_ci{
12188c2ecf20Sopenharmony_ci	sh_mdio_ctrl(ctrl, PIR_MDC, bit);
12198c2ecf20Sopenharmony_ci}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci/* mdio bus control struct */
12228c2ecf20Sopenharmony_cistatic const struct mdiobb_ops bb_ops = {
12238c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
12248c2ecf20Sopenharmony_ci	.set_mdc = sh_mdc_ctrl,
12258c2ecf20Sopenharmony_ci	.set_mdio_dir = sh_mmd_ctrl,
12268c2ecf20Sopenharmony_ci	.set_mdio_data = sh_set_mdio,
12278c2ecf20Sopenharmony_ci	.get_mdio_data = sh_get_mdio,
12288c2ecf20Sopenharmony_ci};
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci/* free Tx skb function */
12318c2ecf20Sopenharmony_cistatic int sh_eth_tx_free(struct net_device *ndev, bool sent_only)
12328c2ecf20Sopenharmony_ci{
12338c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
12348c2ecf20Sopenharmony_ci	struct sh_eth_txdesc *txdesc;
12358c2ecf20Sopenharmony_ci	int free_num = 0;
12368c2ecf20Sopenharmony_ci	int entry;
12378c2ecf20Sopenharmony_ci	bool sent;
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	for (; mdp->cur_tx - mdp->dirty_tx > 0; mdp->dirty_tx++) {
12408c2ecf20Sopenharmony_ci		entry = mdp->dirty_tx % mdp->num_tx_ring;
12418c2ecf20Sopenharmony_ci		txdesc = &mdp->tx_ring[entry];
12428c2ecf20Sopenharmony_ci		sent = !(txdesc->status & cpu_to_le32(TD_TACT));
12438c2ecf20Sopenharmony_ci		if (sent_only && !sent)
12448c2ecf20Sopenharmony_ci			break;
12458c2ecf20Sopenharmony_ci		/* TACT bit must be checked before all the following reads */
12468c2ecf20Sopenharmony_ci		dma_rmb();
12478c2ecf20Sopenharmony_ci		netif_info(mdp, tx_done, ndev,
12488c2ecf20Sopenharmony_ci			   "tx entry %d status 0x%08x\n",
12498c2ecf20Sopenharmony_ci			   entry, le32_to_cpu(txdesc->status));
12508c2ecf20Sopenharmony_ci		/* Free the original skb. */
12518c2ecf20Sopenharmony_ci		if (mdp->tx_skbuff[entry]) {
12528c2ecf20Sopenharmony_ci			dma_unmap_single(&mdp->pdev->dev,
12538c2ecf20Sopenharmony_ci					 le32_to_cpu(txdesc->addr),
12548c2ecf20Sopenharmony_ci					 le32_to_cpu(txdesc->len) >> 16,
12558c2ecf20Sopenharmony_ci					 DMA_TO_DEVICE);
12568c2ecf20Sopenharmony_ci			dev_kfree_skb_irq(mdp->tx_skbuff[entry]);
12578c2ecf20Sopenharmony_ci			mdp->tx_skbuff[entry] = NULL;
12588c2ecf20Sopenharmony_ci			free_num++;
12598c2ecf20Sopenharmony_ci		}
12608c2ecf20Sopenharmony_ci		txdesc->status = cpu_to_le32(TD_TFP);
12618c2ecf20Sopenharmony_ci		if (entry >= mdp->num_tx_ring - 1)
12628c2ecf20Sopenharmony_ci			txdesc->status |= cpu_to_le32(TD_TDLE);
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci		if (sent) {
12658c2ecf20Sopenharmony_ci			ndev->stats.tx_packets++;
12668c2ecf20Sopenharmony_ci			ndev->stats.tx_bytes += le32_to_cpu(txdesc->len) >> 16;
12678c2ecf20Sopenharmony_ci		}
12688c2ecf20Sopenharmony_ci	}
12698c2ecf20Sopenharmony_ci	return free_num;
12708c2ecf20Sopenharmony_ci}
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci/* free skb and descriptor buffer */
12738c2ecf20Sopenharmony_cistatic void sh_eth_ring_free(struct net_device *ndev)
12748c2ecf20Sopenharmony_ci{
12758c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
12768c2ecf20Sopenharmony_ci	int ringsize, i;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	if (mdp->rx_ring) {
12798c2ecf20Sopenharmony_ci		for (i = 0; i < mdp->num_rx_ring; i++) {
12808c2ecf20Sopenharmony_ci			if (mdp->rx_skbuff[i]) {
12818c2ecf20Sopenharmony_ci				struct sh_eth_rxdesc *rxdesc = &mdp->rx_ring[i];
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci				dma_unmap_single(&mdp->pdev->dev,
12848c2ecf20Sopenharmony_ci						 le32_to_cpu(rxdesc->addr),
12858c2ecf20Sopenharmony_ci						 ALIGN(mdp->rx_buf_sz, 32),
12868c2ecf20Sopenharmony_ci						 DMA_FROM_DEVICE);
12878c2ecf20Sopenharmony_ci			}
12888c2ecf20Sopenharmony_ci		}
12898c2ecf20Sopenharmony_ci		ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring;
12908c2ecf20Sopenharmony_ci		dma_free_coherent(&mdp->pdev->dev, ringsize, mdp->rx_ring,
12918c2ecf20Sopenharmony_ci				  mdp->rx_desc_dma);
12928c2ecf20Sopenharmony_ci		mdp->rx_ring = NULL;
12938c2ecf20Sopenharmony_ci	}
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	/* Free Rx skb ringbuffer */
12968c2ecf20Sopenharmony_ci	if (mdp->rx_skbuff) {
12978c2ecf20Sopenharmony_ci		for (i = 0; i < mdp->num_rx_ring; i++)
12988c2ecf20Sopenharmony_ci			dev_kfree_skb(mdp->rx_skbuff[i]);
12998c2ecf20Sopenharmony_ci	}
13008c2ecf20Sopenharmony_ci	kfree(mdp->rx_skbuff);
13018c2ecf20Sopenharmony_ci	mdp->rx_skbuff = NULL;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	if (mdp->tx_ring) {
13048c2ecf20Sopenharmony_ci		sh_eth_tx_free(ndev, false);
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci		ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring;
13078c2ecf20Sopenharmony_ci		dma_free_coherent(&mdp->pdev->dev, ringsize, mdp->tx_ring,
13088c2ecf20Sopenharmony_ci				  mdp->tx_desc_dma);
13098c2ecf20Sopenharmony_ci		mdp->tx_ring = NULL;
13108c2ecf20Sopenharmony_ci	}
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	/* Free Tx skb ringbuffer */
13138c2ecf20Sopenharmony_ci	kfree(mdp->tx_skbuff);
13148c2ecf20Sopenharmony_ci	mdp->tx_skbuff = NULL;
13158c2ecf20Sopenharmony_ci}
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci/* format skb and descriptor buffer */
13188c2ecf20Sopenharmony_cistatic void sh_eth_ring_format(struct net_device *ndev)
13198c2ecf20Sopenharmony_ci{
13208c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
13218c2ecf20Sopenharmony_ci	int i;
13228c2ecf20Sopenharmony_ci	struct sk_buff *skb;
13238c2ecf20Sopenharmony_ci	struct sh_eth_rxdesc *rxdesc = NULL;
13248c2ecf20Sopenharmony_ci	struct sh_eth_txdesc *txdesc = NULL;
13258c2ecf20Sopenharmony_ci	int rx_ringsize = sizeof(*rxdesc) * mdp->num_rx_ring;
13268c2ecf20Sopenharmony_ci	int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring;
13278c2ecf20Sopenharmony_ci	int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN + 32 - 1;
13288c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
13298c2ecf20Sopenharmony_ci	u32 buf_len;
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	mdp->cur_rx = 0;
13328c2ecf20Sopenharmony_ci	mdp->cur_tx = 0;
13338c2ecf20Sopenharmony_ci	mdp->dirty_rx = 0;
13348c2ecf20Sopenharmony_ci	mdp->dirty_tx = 0;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	memset(mdp->rx_ring, 0, rx_ringsize);
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	/* build Rx ring buffer */
13398c2ecf20Sopenharmony_ci	for (i = 0; i < mdp->num_rx_ring; i++) {
13408c2ecf20Sopenharmony_ci		/* skb */
13418c2ecf20Sopenharmony_ci		mdp->rx_skbuff[i] = NULL;
13428c2ecf20Sopenharmony_ci		skb = netdev_alloc_skb(ndev, skbuff_size);
13438c2ecf20Sopenharmony_ci		if (skb == NULL)
13448c2ecf20Sopenharmony_ci			break;
13458c2ecf20Sopenharmony_ci		sh_eth_set_receive_align(skb);
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci		/* The size of the buffer is a multiple of 32 bytes. */
13488c2ecf20Sopenharmony_ci		buf_len = ALIGN(mdp->rx_buf_sz, 32);
13498c2ecf20Sopenharmony_ci		dma_addr = dma_map_single(&mdp->pdev->dev, skb->data, buf_len,
13508c2ecf20Sopenharmony_ci					  DMA_FROM_DEVICE);
13518c2ecf20Sopenharmony_ci		if (dma_mapping_error(&mdp->pdev->dev, dma_addr)) {
13528c2ecf20Sopenharmony_ci			kfree_skb(skb);
13538c2ecf20Sopenharmony_ci			break;
13548c2ecf20Sopenharmony_ci		}
13558c2ecf20Sopenharmony_ci		mdp->rx_skbuff[i] = skb;
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci		/* RX descriptor */
13588c2ecf20Sopenharmony_ci		rxdesc = &mdp->rx_ring[i];
13598c2ecf20Sopenharmony_ci		rxdesc->len = cpu_to_le32(buf_len << 16);
13608c2ecf20Sopenharmony_ci		rxdesc->addr = cpu_to_le32(dma_addr);
13618c2ecf20Sopenharmony_ci		rxdesc->status = cpu_to_le32(RD_RACT | RD_RFP);
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci		/* Rx descriptor address set */
13648c2ecf20Sopenharmony_ci		if (i == 0) {
13658c2ecf20Sopenharmony_ci			sh_eth_write(ndev, mdp->rx_desc_dma, RDLAR);
13668c2ecf20Sopenharmony_ci			if (mdp->cd->xdfar_rw)
13678c2ecf20Sopenharmony_ci				sh_eth_write(ndev, mdp->rx_desc_dma, RDFAR);
13688c2ecf20Sopenharmony_ci		}
13698c2ecf20Sopenharmony_ci	}
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	mdp->dirty_rx = (u32) (i - mdp->num_rx_ring);
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	/* Mark the last entry as wrapping the ring. */
13748c2ecf20Sopenharmony_ci	if (rxdesc)
13758c2ecf20Sopenharmony_ci		rxdesc->status |= cpu_to_le32(RD_RDLE);
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	memset(mdp->tx_ring, 0, tx_ringsize);
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	/* build Tx ring buffer */
13808c2ecf20Sopenharmony_ci	for (i = 0; i < mdp->num_tx_ring; i++) {
13818c2ecf20Sopenharmony_ci		mdp->tx_skbuff[i] = NULL;
13828c2ecf20Sopenharmony_ci		txdesc = &mdp->tx_ring[i];
13838c2ecf20Sopenharmony_ci		txdesc->status = cpu_to_le32(TD_TFP);
13848c2ecf20Sopenharmony_ci		txdesc->len = cpu_to_le32(0);
13858c2ecf20Sopenharmony_ci		if (i == 0) {
13868c2ecf20Sopenharmony_ci			/* Tx descriptor address set */
13878c2ecf20Sopenharmony_ci			sh_eth_write(ndev, mdp->tx_desc_dma, TDLAR);
13888c2ecf20Sopenharmony_ci			if (mdp->cd->xdfar_rw)
13898c2ecf20Sopenharmony_ci				sh_eth_write(ndev, mdp->tx_desc_dma, TDFAR);
13908c2ecf20Sopenharmony_ci		}
13918c2ecf20Sopenharmony_ci	}
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	txdesc->status |= cpu_to_le32(TD_TDLE);
13948c2ecf20Sopenharmony_ci}
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci/* Get skb and descriptor buffer */
13978c2ecf20Sopenharmony_cistatic int sh_eth_ring_init(struct net_device *ndev)
13988c2ecf20Sopenharmony_ci{
13998c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
14008c2ecf20Sopenharmony_ci	int rx_ringsize, tx_ringsize;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	/* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the
14038c2ecf20Sopenharmony_ci	 * card needs room to do 8 byte alignment, +2 so we can reserve
14048c2ecf20Sopenharmony_ci	 * the first 2 bytes, and +16 gets room for the status word from the
14058c2ecf20Sopenharmony_ci	 * card.
14068c2ecf20Sopenharmony_ci	 */
14078c2ecf20Sopenharmony_ci	mdp->rx_buf_sz = (ndev->mtu <= 1492 ? PKT_BUF_SZ :
14088c2ecf20Sopenharmony_ci			  (((ndev->mtu + 26 + 7) & ~7) + 2 + 16));
14098c2ecf20Sopenharmony_ci	if (mdp->cd->rpadir)
14108c2ecf20Sopenharmony_ci		mdp->rx_buf_sz += NET_IP_ALIGN;
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	/* Allocate RX and TX skb rings */
14138c2ecf20Sopenharmony_ci	mdp->rx_skbuff = kcalloc(mdp->num_rx_ring, sizeof(*mdp->rx_skbuff),
14148c2ecf20Sopenharmony_ci				 GFP_KERNEL);
14158c2ecf20Sopenharmony_ci	if (!mdp->rx_skbuff)
14168c2ecf20Sopenharmony_ci		return -ENOMEM;
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	mdp->tx_skbuff = kcalloc(mdp->num_tx_ring, sizeof(*mdp->tx_skbuff),
14198c2ecf20Sopenharmony_ci				 GFP_KERNEL);
14208c2ecf20Sopenharmony_ci	if (!mdp->tx_skbuff)
14218c2ecf20Sopenharmony_ci		goto ring_free;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	/* Allocate all Rx descriptors. */
14248c2ecf20Sopenharmony_ci	rx_ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring;
14258c2ecf20Sopenharmony_ci	mdp->rx_ring = dma_alloc_coherent(&mdp->pdev->dev, rx_ringsize,
14268c2ecf20Sopenharmony_ci					  &mdp->rx_desc_dma, GFP_KERNEL);
14278c2ecf20Sopenharmony_ci	if (!mdp->rx_ring)
14288c2ecf20Sopenharmony_ci		goto ring_free;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	mdp->dirty_rx = 0;
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	/* Allocate all Tx descriptors. */
14338c2ecf20Sopenharmony_ci	tx_ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring;
14348c2ecf20Sopenharmony_ci	mdp->tx_ring = dma_alloc_coherent(&mdp->pdev->dev, tx_ringsize,
14358c2ecf20Sopenharmony_ci					  &mdp->tx_desc_dma, GFP_KERNEL);
14368c2ecf20Sopenharmony_ci	if (!mdp->tx_ring)
14378c2ecf20Sopenharmony_ci		goto ring_free;
14388c2ecf20Sopenharmony_ci	return 0;
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ciring_free:
14418c2ecf20Sopenharmony_ci	/* Free Rx and Tx skb ring buffer and DMA buffer */
14428c2ecf20Sopenharmony_ci	sh_eth_ring_free(ndev);
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	return -ENOMEM;
14458c2ecf20Sopenharmony_ci}
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_cistatic int sh_eth_dev_init(struct net_device *ndev)
14488c2ecf20Sopenharmony_ci{
14498c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
14508c2ecf20Sopenharmony_ci	int ret;
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	/* Soft Reset */
14538c2ecf20Sopenharmony_ci	ret = mdp->cd->soft_reset(ndev);
14548c2ecf20Sopenharmony_ci	if (ret)
14558c2ecf20Sopenharmony_ci		return ret;
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	if (mdp->cd->rmiimode)
14588c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0x1, RMIIMODE);
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	/* Descriptor format */
14618c2ecf20Sopenharmony_ci	sh_eth_ring_format(ndev);
14628c2ecf20Sopenharmony_ci	if (mdp->cd->rpadir)
14638c2ecf20Sopenharmony_ci		sh_eth_write(ndev, NET_IP_ALIGN << 16, RPADIR);
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	/* all sh_eth int mask */
14668c2ecf20Sopenharmony_ci	sh_eth_write(ndev, 0, EESIPR);
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
14698c2ecf20Sopenharmony_ci	if (mdp->cd->hw_swap)
14708c2ecf20Sopenharmony_ci		sh_eth_write(ndev, EDMR_EL, EDMR);
14718c2ecf20Sopenharmony_ci	else
14728c2ecf20Sopenharmony_ci#endif
14738c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0, EDMR);
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	/* FIFO size set */
14768c2ecf20Sopenharmony_ci	sh_eth_write(ndev, mdp->cd->fdr_value, FDR);
14778c2ecf20Sopenharmony_ci	sh_eth_write(ndev, 0, TFTR);
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	/* Frame recv control (enable multiple-packets per rx irq) */
14808c2ecf20Sopenharmony_ci	sh_eth_write(ndev, RMCR_RNC, RMCR);
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	sh_eth_write(ndev, mdp->cd->trscer_err_mask, TRSCER);
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	/* DMA transfer burst mode */
14858c2ecf20Sopenharmony_ci	if (mdp->cd->nbst)
14868c2ecf20Sopenharmony_ci		sh_eth_modify(ndev, EDMR, EDMR_NBST, EDMR_NBST);
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	/* Burst cycle count upper-limit */
14898c2ecf20Sopenharmony_ci	if (mdp->cd->bculr)
14908c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0x800, BCULR);
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	sh_eth_write(ndev, mdp->cd->fcftr_value, FCFTR);
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	if (!mdp->cd->no_trimd)
14958c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0, TRIMD);
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	/* Recv frame limit set register */
14988c2ecf20Sopenharmony_ci	sh_eth_write(ndev, ndev->mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN,
14998c2ecf20Sopenharmony_ci		     RFLR);
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	sh_eth_modify(ndev, EESR, 0, 0);
15028c2ecf20Sopenharmony_ci	mdp->irq_enabled = true;
15038c2ecf20Sopenharmony_ci	sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	/* EMAC Mode: PAUSE prohibition; Duplex; RX Checksum; TX; RX */
15068c2ecf20Sopenharmony_ci	sh_eth_write(ndev, ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) |
15078c2ecf20Sopenharmony_ci		     (ndev->features & NETIF_F_RXCSUM ? ECMR_RCSC : 0) |
15088c2ecf20Sopenharmony_ci		     ECMR_TE | ECMR_RE, ECMR);
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	if (mdp->cd->set_rate)
15118c2ecf20Sopenharmony_ci		mdp->cd->set_rate(ndev);
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	/* E-MAC Status Register clear */
15148c2ecf20Sopenharmony_ci	sh_eth_write(ndev, mdp->cd->ecsr_value, ECSR);
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	/* E-MAC Interrupt Enable register */
15178c2ecf20Sopenharmony_ci	sh_eth_write(ndev, mdp->cd->ecsipr_value, ECSIPR);
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	/* Set MAC address */
15208c2ecf20Sopenharmony_ci	update_mac_address(ndev);
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	/* mask reset */
15238c2ecf20Sopenharmony_ci	if (mdp->cd->apr)
15248c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 1, APR);
15258c2ecf20Sopenharmony_ci	if (mdp->cd->mpr)
15268c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 1, MPR);
15278c2ecf20Sopenharmony_ci	if (mdp->cd->tpauser)
15288c2ecf20Sopenharmony_ci		sh_eth_write(ndev, TPAUSER_UNLIMITED, TPAUSER);
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	/* Setting the Rx mode will start the Rx process. */
15318c2ecf20Sopenharmony_ci	sh_eth_write(ndev, EDRRR_R, EDRRR);
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	return ret;
15348c2ecf20Sopenharmony_ci}
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_cistatic void sh_eth_dev_exit(struct net_device *ndev)
15378c2ecf20Sopenharmony_ci{
15388c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
15398c2ecf20Sopenharmony_ci	int i;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	/* Deactivate all TX descriptors, so DMA should stop at next
15428c2ecf20Sopenharmony_ci	 * packet boundary if it's currently running
15438c2ecf20Sopenharmony_ci	 */
15448c2ecf20Sopenharmony_ci	for (i = 0; i < mdp->num_tx_ring; i++)
15458c2ecf20Sopenharmony_ci		mdp->tx_ring[i].status &= ~cpu_to_le32(TD_TACT);
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	/* Disable TX FIFO egress to MAC */
15488c2ecf20Sopenharmony_ci	sh_eth_rcv_snd_disable(ndev);
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	/* Stop RX DMA at next packet boundary */
15518c2ecf20Sopenharmony_ci	sh_eth_write(ndev, 0, EDRRR);
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	/* Aside from TX DMA, we can't tell when the hardware is
15548c2ecf20Sopenharmony_ci	 * really stopped, so we need to reset to make sure.
15558c2ecf20Sopenharmony_ci	 * Before doing that, wait for long enough to *probably*
15568c2ecf20Sopenharmony_ci	 * finish transmitting the last packet and poll stats.
15578c2ecf20Sopenharmony_ci	 */
15588c2ecf20Sopenharmony_ci	msleep(2); /* max frame time at 10 Mbps < 1250 us */
15598c2ecf20Sopenharmony_ci	sh_eth_get_stats(ndev);
15608c2ecf20Sopenharmony_ci	mdp->cd->soft_reset(ndev);
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	/* Set the RMII mode again if required */
15638c2ecf20Sopenharmony_ci	if (mdp->cd->rmiimode)
15648c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0x1, RMIIMODE);
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	/* Set MAC address again */
15678c2ecf20Sopenharmony_ci	update_mac_address(ndev);
15688c2ecf20Sopenharmony_ci}
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_cistatic void sh_eth_rx_csum(struct sk_buff *skb)
15718c2ecf20Sopenharmony_ci{
15728c2ecf20Sopenharmony_ci	u8 *hw_csum;
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	/* The hardware checksum is 2 bytes appended to packet data */
15758c2ecf20Sopenharmony_ci	if (unlikely(skb->len < sizeof(__sum16)))
15768c2ecf20Sopenharmony_ci		return;
15778c2ecf20Sopenharmony_ci	hw_csum = skb_tail_pointer(skb) - sizeof(__sum16);
15788c2ecf20Sopenharmony_ci	skb->csum = csum_unfold((__force __sum16)get_unaligned_le16(hw_csum));
15798c2ecf20Sopenharmony_ci	skb->ip_summed = CHECKSUM_COMPLETE;
15808c2ecf20Sopenharmony_ci	skb_trim(skb, skb->len - sizeof(__sum16));
15818c2ecf20Sopenharmony_ci}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci/* Packet receive function */
15848c2ecf20Sopenharmony_cistatic int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
15858c2ecf20Sopenharmony_ci{
15868c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
15878c2ecf20Sopenharmony_ci	struct sh_eth_rxdesc *rxdesc;
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci	int entry = mdp->cur_rx % mdp->num_rx_ring;
15908c2ecf20Sopenharmony_ci	int boguscnt = (mdp->dirty_rx + mdp->num_rx_ring) - mdp->cur_rx;
15918c2ecf20Sopenharmony_ci	int limit;
15928c2ecf20Sopenharmony_ci	struct sk_buff *skb;
15938c2ecf20Sopenharmony_ci	u32 desc_status;
15948c2ecf20Sopenharmony_ci	int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN + 32 - 1;
15958c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
15968c2ecf20Sopenharmony_ci	u16 pkt_len;
15978c2ecf20Sopenharmony_ci	u32 buf_len;
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	boguscnt = min(boguscnt, *quota);
16008c2ecf20Sopenharmony_ci	limit = boguscnt;
16018c2ecf20Sopenharmony_ci	rxdesc = &mdp->rx_ring[entry];
16028c2ecf20Sopenharmony_ci	while (!(rxdesc->status & cpu_to_le32(RD_RACT))) {
16038c2ecf20Sopenharmony_ci		/* RACT bit must be checked before all the following reads */
16048c2ecf20Sopenharmony_ci		dma_rmb();
16058c2ecf20Sopenharmony_ci		desc_status = le32_to_cpu(rxdesc->status);
16068c2ecf20Sopenharmony_ci		pkt_len = le32_to_cpu(rxdesc->len) & RD_RFL;
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci		if (--boguscnt < 0)
16098c2ecf20Sopenharmony_ci			break;
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci		netif_info(mdp, rx_status, ndev,
16128c2ecf20Sopenharmony_ci			   "rx entry %d status 0x%08x len %d\n",
16138c2ecf20Sopenharmony_ci			   entry, desc_status, pkt_len);
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci		if (!(desc_status & RDFEND))
16168c2ecf20Sopenharmony_ci			ndev->stats.rx_length_errors++;
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci		/* In case of almost all GETHER/ETHERs, the Receive Frame State
16198c2ecf20Sopenharmony_ci		 * (RFS) bits in the Receive Descriptor 0 are from bit 9 to
16208c2ecf20Sopenharmony_ci		 * bit 0. However, in case of the R8A7740 and R7S72100
16218c2ecf20Sopenharmony_ci		 * the RFS bits are from bit 25 to bit 16. So, the
16228c2ecf20Sopenharmony_ci		 * driver needs right shifting by 16.
16238c2ecf20Sopenharmony_ci		 */
16248c2ecf20Sopenharmony_ci		if (mdp->cd->csmr)
16258c2ecf20Sopenharmony_ci			desc_status >>= 16;
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci		skb = mdp->rx_skbuff[entry];
16288c2ecf20Sopenharmony_ci		if (desc_status & (RD_RFS1 | RD_RFS2 | RD_RFS3 | RD_RFS4 |
16298c2ecf20Sopenharmony_ci				   RD_RFS5 | RD_RFS6 | RD_RFS10)) {
16308c2ecf20Sopenharmony_ci			ndev->stats.rx_errors++;
16318c2ecf20Sopenharmony_ci			if (desc_status & RD_RFS1)
16328c2ecf20Sopenharmony_ci				ndev->stats.rx_crc_errors++;
16338c2ecf20Sopenharmony_ci			if (desc_status & RD_RFS2)
16348c2ecf20Sopenharmony_ci				ndev->stats.rx_frame_errors++;
16358c2ecf20Sopenharmony_ci			if (desc_status & RD_RFS3)
16368c2ecf20Sopenharmony_ci				ndev->stats.rx_length_errors++;
16378c2ecf20Sopenharmony_ci			if (desc_status & RD_RFS4)
16388c2ecf20Sopenharmony_ci				ndev->stats.rx_length_errors++;
16398c2ecf20Sopenharmony_ci			if (desc_status & RD_RFS6)
16408c2ecf20Sopenharmony_ci				ndev->stats.rx_missed_errors++;
16418c2ecf20Sopenharmony_ci			if (desc_status & RD_RFS10)
16428c2ecf20Sopenharmony_ci				ndev->stats.rx_over_errors++;
16438c2ecf20Sopenharmony_ci		} else	if (skb) {
16448c2ecf20Sopenharmony_ci			dma_addr = le32_to_cpu(rxdesc->addr);
16458c2ecf20Sopenharmony_ci			if (!mdp->cd->hw_swap)
16468c2ecf20Sopenharmony_ci				sh_eth_soft_swap(
16478c2ecf20Sopenharmony_ci					phys_to_virt(ALIGN(dma_addr, 4)),
16488c2ecf20Sopenharmony_ci					pkt_len + 2);
16498c2ecf20Sopenharmony_ci			mdp->rx_skbuff[entry] = NULL;
16508c2ecf20Sopenharmony_ci			if (mdp->cd->rpadir)
16518c2ecf20Sopenharmony_ci				skb_reserve(skb, NET_IP_ALIGN);
16528c2ecf20Sopenharmony_ci			dma_unmap_single(&mdp->pdev->dev, dma_addr,
16538c2ecf20Sopenharmony_ci					 ALIGN(mdp->rx_buf_sz, 32),
16548c2ecf20Sopenharmony_ci					 DMA_FROM_DEVICE);
16558c2ecf20Sopenharmony_ci			skb_put(skb, pkt_len);
16568c2ecf20Sopenharmony_ci			skb->protocol = eth_type_trans(skb, ndev);
16578c2ecf20Sopenharmony_ci			if (ndev->features & NETIF_F_RXCSUM)
16588c2ecf20Sopenharmony_ci				sh_eth_rx_csum(skb);
16598c2ecf20Sopenharmony_ci			netif_receive_skb(skb);
16608c2ecf20Sopenharmony_ci			ndev->stats.rx_packets++;
16618c2ecf20Sopenharmony_ci			ndev->stats.rx_bytes += pkt_len;
16628c2ecf20Sopenharmony_ci			if (desc_status & RD_RFS8)
16638c2ecf20Sopenharmony_ci				ndev->stats.multicast++;
16648c2ecf20Sopenharmony_ci		}
16658c2ecf20Sopenharmony_ci		entry = (++mdp->cur_rx) % mdp->num_rx_ring;
16668c2ecf20Sopenharmony_ci		rxdesc = &mdp->rx_ring[entry];
16678c2ecf20Sopenharmony_ci	}
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	/* Refill the Rx ring buffers. */
16708c2ecf20Sopenharmony_ci	for (; mdp->cur_rx - mdp->dirty_rx > 0; mdp->dirty_rx++) {
16718c2ecf20Sopenharmony_ci		entry = mdp->dirty_rx % mdp->num_rx_ring;
16728c2ecf20Sopenharmony_ci		rxdesc = &mdp->rx_ring[entry];
16738c2ecf20Sopenharmony_ci		/* The size of the buffer is 32 byte boundary. */
16748c2ecf20Sopenharmony_ci		buf_len = ALIGN(mdp->rx_buf_sz, 32);
16758c2ecf20Sopenharmony_ci		rxdesc->len = cpu_to_le32(buf_len << 16);
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci		if (mdp->rx_skbuff[entry] == NULL) {
16788c2ecf20Sopenharmony_ci			skb = netdev_alloc_skb(ndev, skbuff_size);
16798c2ecf20Sopenharmony_ci			if (skb == NULL)
16808c2ecf20Sopenharmony_ci				break;	/* Better luck next round. */
16818c2ecf20Sopenharmony_ci			sh_eth_set_receive_align(skb);
16828c2ecf20Sopenharmony_ci			dma_addr = dma_map_single(&mdp->pdev->dev, skb->data,
16838c2ecf20Sopenharmony_ci						  buf_len, DMA_FROM_DEVICE);
16848c2ecf20Sopenharmony_ci			if (dma_mapping_error(&mdp->pdev->dev, dma_addr)) {
16858c2ecf20Sopenharmony_ci				kfree_skb(skb);
16868c2ecf20Sopenharmony_ci				break;
16878c2ecf20Sopenharmony_ci			}
16888c2ecf20Sopenharmony_ci			mdp->rx_skbuff[entry] = skb;
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci			skb_checksum_none_assert(skb);
16918c2ecf20Sopenharmony_ci			rxdesc->addr = cpu_to_le32(dma_addr);
16928c2ecf20Sopenharmony_ci		}
16938c2ecf20Sopenharmony_ci		dma_wmb(); /* RACT bit must be set after all the above writes */
16948c2ecf20Sopenharmony_ci		if (entry >= mdp->num_rx_ring - 1)
16958c2ecf20Sopenharmony_ci			rxdesc->status |=
16968c2ecf20Sopenharmony_ci				cpu_to_le32(RD_RACT | RD_RFP | RD_RDLE);
16978c2ecf20Sopenharmony_ci		else
16988c2ecf20Sopenharmony_ci			rxdesc->status |= cpu_to_le32(RD_RACT | RD_RFP);
16998c2ecf20Sopenharmony_ci	}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	/* Restart Rx engine if stopped. */
17028c2ecf20Sopenharmony_ci	/* If we don't need to check status, don't. -KDU */
17038c2ecf20Sopenharmony_ci	if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R)) {
17048c2ecf20Sopenharmony_ci		/* fix the values for the next receiving if RDE is set */
17058c2ecf20Sopenharmony_ci		if (intr_status & EESR_RDE && !mdp->cd->no_xdfar) {
17068c2ecf20Sopenharmony_ci			u32 count = (sh_eth_read(ndev, RDFAR) -
17078c2ecf20Sopenharmony_ci				     sh_eth_read(ndev, RDLAR)) >> 4;
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci			mdp->cur_rx = count;
17108c2ecf20Sopenharmony_ci			mdp->dirty_rx = count;
17118c2ecf20Sopenharmony_ci		}
17128c2ecf20Sopenharmony_ci		sh_eth_write(ndev, EDRRR_R, EDRRR);
17138c2ecf20Sopenharmony_ci	}
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	*quota -= limit - boguscnt - 1;
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	return *quota <= 0;
17188c2ecf20Sopenharmony_ci}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_cistatic void sh_eth_rcv_snd_disable(struct net_device *ndev)
17218c2ecf20Sopenharmony_ci{
17228c2ecf20Sopenharmony_ci	/* disable tx and rx */
17238c2ecf20Sopenharmony_ci	sh_eth_modify(ndev, ECMR, ECMR_RE | ECMR_TE, 0);
17248c2ecf20Sopenharmony_ci}
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_cistatic void sh_eth_rcv_snd_enable(struct net_device *ndev)
17278c2ecf20Sopenharmony_ci{
17288c2ecf20Sopenharmony_ci	/* enable tx and rx */
17298c2ecf20Sopenharmony_ci	sh_eth_modify(ndev, ECMR, ECMR_RE | ECMR_TE, ECMR_RE | ECMR_TE);
17308c2ecf20Sopenharmony_ci}
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci/* E-MAC interrupt handler */
17338c2ecf20Sopenharmony_cistatic void sh_eth_emac_interrupt(struct net_device *ndev)
17348c2ecf20Sopenharmony_ci{
17358c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
17368c2ecf20Sopenharmony_ci	u32 felic_stat;
17378c2ecf20Sopenharmony_ci	u32 link_stat;
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	felic_stat = sh_eth_read(ndev, ECSR) & sh_eth_read(ndev, ECSIPR);
17408c2ecf20Sopenharmony_ci	sh_eth_write(ndev, felic_stat, ECSR);	/* clear int */
17418c2ecf20Sopenharmony_ci	if (felic_stat & ECSR_ICD)
17428c2ecf20Sopenharmony_ci		ndev->stats.tx_carrier_errors++;
17438c2ecf20Sopenharmony_ci	if (felic_stat & ECSR_MPD)
17448c2ecf20Sopenharmony_ci		pm_wakeup_event(&mdp->pdev->dev, 0);
17458c2ecf20Sopenharmony_ci	if (felic_stat & ECSR_LCHNG) {
17468c2ecf20Sopenharmony_ci		/* Link Changed */
17478c2ecf20Sopenharmony_ci		if (mdp->cd->no_psr || mdp->no_ether_link)
17488c2ecf20Sopenharmony_ci			return;
17498c2ecf20Sopenharmony_ci		link_stat = sh_eth_read(ndev, PSR);
17508c2ecf20Sopenharmony_ci		if (mdp->ether_link_active_low)
17518c2ecf20Sopenharmony_ci			link_stat = ~link_stat;
17528c2ecf20Sopenharmony_ci		if (!(link_stat & PHY_ST_LINK)) {
17538c2ecf20Sopenharmony_ci			sh_eth_rcv_snd_disable(ndev);
17548c2ecf20Sopenharmony_ci		} else {
17558c2ecf20Sopenharmony_ci			/* Link Up */
17568c2ecf20Sopenharmony_ci			sh_eth_modify(ndev, EESIPR, EESIPR_ECIIP, 0);
17578c2ecf20Sopenharmony_ci			/* clear int */
17588c2ecf20Sopenharmony_ci			sh_eth_modify(ndev, ECSR, 0, 0);
17598c2ecf20Sopenharmony_ci			sh_eth_modify(ndev, EESIPR, EESIPR_ECIIP, EESIPR_ECIIP);
17608c2ecf20Sopenharmony_ci			/* enable tx and rx */
17618c2ecf20Sopenharmony_ci			sh_eth_rcv_snd_enable(ndev);
17628c2ecf20Sopenharmony_ci		}
17638c2ecf20Sopenharmony_ci	}
17648c2ecf20Sopenharmony_ci}
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci/* error control function */
17678c2ecf20Sopenharmony_cistatic void sh_eth_error(struct net_device *ndev, u32 intr_status)
17688c2ecf20Sopenharmony_ci{
17698c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
17708c2ecf20Sopenharmony_ci	u32 mask;
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	if (intr_status & EESR_TWB) {
17738c2ecf20Sopenharmony_ci		/* Unused write back interrupt */
17748c2ecf20Sopenharmony_ci		if (intr_status & EESR_TABT) {	/* Transmit Abort int */
17758c2ecf20Sopenharmony_ci			ndev->stats.tx_aborted_errors++;
17768c2ecf20Sopenharmony_ci			netif_err(mdp, tx_err, ndev, "Transmit Abort\n");
17778c2ecf20Sopenharmony_ci		}
17788c2ecf20Sopenharmony_ci	}
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	if (intr_status & EESR_RABT) {
17818c2ecf20Sopenharmony_ci		/* Receive Abort int */
17828c2ecf20Sopenharmony_ci		if (intr_status & EESR_RFRMER) {
17838c2ecf20Sopenharmony_ci			/* Receive Frame Overflow int */
17848c2ecf20Sopenharmony_ci			ndev->stats.rx_frame_errors++;
17858c2ecf20Sopenharmony_ci		}
17868c2ecf20Sopenharmony_ci	}
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci	if (intr_status & EESR_TDE) {
17898c2ecf20Sopenharmony_ci		/* Transmit Descriptor Empty int */
17908c2ecf20Sopenharmony_ci		ndev->stats.tx_fifo_errors++;
17918c2ecf20Sopenharmony_ci		netif_err(mdp, tx_err, ndev, "Transmit Descriptor Empty\n");
17928c2ecf20Sopenharmony_ci	}
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	if (intr_status & EESR_TFE) {
17958c2ecf20Sopenharmony_ci		/* FIFO under flow */
17968c2ecf20Sopenharmony_ci		ndev->stats.tx_fifo_errors++;
17978c2ecf20Sopenharmony_ci		netif_err(mdp, tx_err, ndev, "Transmit FIFO Under flow\n");
17988c2ecf20Sopenharmony_ci	}
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	if (intr_status & EESR_RDE) {
18018c2ecf20Sopenharmony_ci		/* Receive Descriptor Empty int */
18028c2ecf20Sopenharmony_ci		ndev->stats.rx_over_errors++;
18038c2ecf20Sopenharmony_ci	}
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	if (intr_status & EESR_RFE) {
18068c2ecf20Sopenharmony_ci		/* Receive FIFO Overflow int */
18078c2ecf20Sopenharmony_ci		ndev->stats.rx_fifo_errors++;
18088c2ecf20Sopenharmony_ci	}
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	if (!mdp->cd->no_ade && (intr_status & EESR_ADE)) {
18118c2ecf20Sopenharmony_ci		/* Address Error */
18128c2ecf20Sopenharmony_ci		ndev->stats.tx_fifo_errors++;
18138c2ecf20Sopenharmony_ci		netif_err(mdp, tx_err, ndev, "Address Error\n");
18148c2ecf20Sopenharmony_ci	}
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci	mask = EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE;
18178c2ecf20Sopenharmony_ci	if (mdp->cd->no_ade)
18188c2ecf20Sopenharmony_ci		mask &= ~EESR_ADE;
18198c2ecf20Sopenharmony_ci	if (intr_status & mask) {
18208c2ecf20Sopenharmony_ci		/* Tx error */
18218c2ecf20Sopenharmony_ci		u32 edtrr = sh_eth_read(ndev, EDTRR);
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci		/* dmesg */
18248c2ecf20Sopenharmony_ci		netdev_err(ndev, "TX error. status=%8.8x cur_tx=%8.8x dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n",
18258c2ecf20Sopenharmony_ci			   intr_status, mdp->cur_tx, mdp->dirty_tx,
18268c2ecf20Sopenharmony_ci			   (u32)ndev->state, edtrr);
18278c2ecf20Sopenharmony_ci		/* dirty buffer free */
18288c2ecf20Sopenharmony_ci		sh_eth_tx_free(ndev, true);
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci		/* SH7712 BUG */
18318c2ecf20Sopenharmony_ci		if (edtrr ^ mdp->cd->edtrr_trns) {
18328c2ecf20Sopenharmony_ci			/* tx dma start */
18338c2ecf20Sopenharmony_ci			sh_eth_write(ndev, mdp->cd->edtrr_trns, EDTRR);
18348c2ecf20Sopenharmony_ci		}
18358c2ecf20Sopenharmony_ci		/* wakeup */
18368c2ecf20Sopenharmony_ci		netif_wake_queue(ndev);
18378c2ecf20Sopenharmony_ci	}
18388c2ecf20Sopenharmony_ci}
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_cistatic irqreturn_t sh_eth_interrupt(int irq, void *netdev)
18418c2ecf20Sopenharmony_ci{
18428c2ecf20Sopenharmony_ci	struct net_device *ndev = netdev;
18438c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
18448c2ecf20Sopenharmony_ci	struct sh_eth_cpu_data *cd = mdp->cd;
18458c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
18468c2ecf20Sopenharmony_ci	u32 intr_status, intr_enable;
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci	spin_lock(&mdp->lock);
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci	/* Get interrupt status */
18518c2ecf20Sopenharmony_ci	intr_status = sh_eth_read(ndev, EESR);
18528c2ecf20Sopenharmony_ci	/* Mask it with the interrupt mask, forcing ECI interrupt  to be always
18538c2ecf20Sopenharmony_ci	 * enabled since it's the one that  comes  thru regardless of the mask,
18548c2ecf20Sopenharmony_ci	 * and  we need to fully handle it  in sh_eth_emac_interrupt() in order
18558c2ecf20Sopenharmony_ci	 * to quench it as it doesn't get cleared by just writing 1 to the  ECI
18568c2ecf20Sopenharmony_ci	 * bit...
18578c2ecf20Sopenharmony_ci	 */
18588c2ecf20Sopenharmony_ci	intr_enable = sh_eth_read(ndev, EESIPR);
18598c2ecf20Sopenharmony_ci	intr_status &= intr_enable | EESIPR_ECIIP;
18608c2ecf20Sopenharmony_ci	if (intr_status & (EESR_RX_CHECK | cd->tx_check | EESR_ECI |
18618c2ecf20Sopenharmony_ci			   cd->eesr_err_check))
18628c2ecf20Sopenharmony_ci		ret = IRQ_HANDLED;
18638c2ecf20Sopenharmony_ci	else
18648c2ecf20Sopenharmony_ci		goto out;
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	if (unlikely(!mdp->irq_enabled)) {
18678c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0, EESIPR);
18688c2ecf20Sopenharmony_ci		goto out;
18698c2ecf20Sopenharmony_ci	}
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	if (intr_status & EESR_RX_CHECK) {
18728c2ecf20Sopenharmony_ci		if (napi_schedule_prep(&mdp->napi)) {
18738c2ecf20Sopenharmony_ci			/* Mask Rx interrupts */
18748c2ecf20Sopenharmony_ci			sh_eth_write(ndev, intr_enable & ~EESR_RX_CHECK,
18758c2ecf20Sopenharmony_ci				     EESIPR);
18768c2ecf20Sopenharmony_ci			__napi_schedule(&mdp->napi);
18778c2ecf20Sopenharmony_ci		} else {
18788c2ecf20Sopenharmony_ci			netdev_warn(ndev,
18798c2ecf20Sopenharmony_ci				    "ignoring interrupt, status 0x%08x, mask 0x%08x.\n",
18808c2ecf20Sopenharmony_ci				    intr_status, intr_enable);
18818c2ecf20Sopenharmony_ci		}
18828c2ecf20Sopenharmony_ci	}
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci	/* Tx Check */
18858c2ecf20Sopenharmony_ci	if (intr_status & cd->tx_check) {
18868c2ecf20Sopenharmony_ci		/* Clear Tx interrupts */
18878c2ecf20Sopenharmony_ci		sh_eth_write(ndev, intr_status & cd->tx_check, EESR);
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci		sh_eth_tx_free(ndev, true);
18908c2ecf20Sopenharmony_ci		netif_wake_queue(ndev);
18918c2ecf20Sopenharmony_ci	}
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci	/* E-MAC interrupt */
18948c2ecf20Sopenharmony_ci	if (intr_status & EESR_ECI)
18958c2ecf20Sopenharmony_ci		sh_eth_emac_interrupt(ndev);
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	if (intr_status & cd->eesr_err_check) {
18988c2ecf20Sopenharmony_ci		/* Clear error interrupts */
18998c2ecf20Sopenharmony_ci		sh_eth_write(ndev, intr_status & cd->eesr_err_check, EESR);
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci		sh_eth_error(ndev, intr_status);
19028c2ecf20Sopenharmony_ci	}
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_ciout:
19058c2ecf20Sopenharmony_ci	spin_unlock(&mdp->lock);
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	return ret;
19088c2ecf20Sopenharmony_ci}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_cistatic int sh_eth_poll(struct napi_struct *napi, int budget)
19118c2ecf20Sopenharmony_ci{
19128c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = container_of(napi, struct sh_eth_private,
19138c2ecf20Sopenharmony_ci						  napi);
19148c2ecf20Sopenharmony_ci	struct net_device *ndev = napi->dev;
19158c2ecf20Sopenharmony_ci	int quota = budget;
19168c2ecf20Sopenharmony_ci	u32 intr_status;
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	for (;;) {
19198c2ecf20Sopenharmony_ci		intr_status = sh_eth_read(ndev, EESR);
19208c2ecf20Sopenharmony_ci		if (!(intr_status & EESR_RX_CHECK))
19218c2ecf20Sopenharmony_ci			break;
19228c2ecf20Sopenharmony_ci		/* Clear Rx interrupts */
19238c2ecf20Sopenharmony_ci		sh_eth_write(ndev, intr_status & EESR_RX_CHECK, EESR);
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci		if (sh_eth_rx(ndev, intr_status, &quota))
19268c2ecf20Sopenharmony_ci			goto out;
19278c2ecf20Sopenharmony_ci	}
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	napi_complete(napi);
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci	/* Reenable Rx interrupts */
19328c2ecf20Sopenharmony_ci	if (mdp->irq_enabled)
19338c2ecf20Sopenharmony_ci		sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
19348c2ecf20Sopenharmony_ciout:
19358c2ecf20Sopenharmony_ci	return budget - quota;
19368c2ecf20Sopenharmony_ci}
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci/* PHY state control function */
19398c2ecf20Sopenharmony_cistatic void sh_eth_adjust_link(struct net_device *ndev)
19408c2ecf20Sopenharmony_ci{
19418c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
19428c2ecf20Sopenharmony_ci	struct phy_device *phydev = ndev->phydev;
19438c2ecf20Sopenharmony_ci	unsigned long flags;
19448c2ecf20Sopenharmony_ci	int new_state = 0;
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	spin_lock_irqsave(&mdp->lock, flags);
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	/* Disable TX and RX right over here, if E-MAC change is ignored */
19498c2ecf20Sopenharmony_ci	if (mdp->cd->no_psr || mdp->no_ether_link)
19508c2ecf20Sopenharmony_ci		sh_eth_rcv_snd_disable(ndev);
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci	if (phydev->link) {
19538c2ecf20Sopenharmony_ci		if (phydev->duplex != mdp->duplex) {
19548c2ecf20Sopenharmony_ci			new_state = 1;
19558c2ecf20Sopenharmony_ci			mdp->duplex = phydev->duplex;
19568c2ecf20Sopenharmony_ci			if (mdp->cd->set_duplex)
19578c2ecf20Sopenharmony_ci				mdp->cd->set_duplex(ndev);
19588c2ecf20Sopenharmony_ci		}
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_ci		if (phydev->speed != mdp->speed) {
19618c2ecf20Sopenharmony_ci			new_state = 1;
19628c2ecf20Sopenharmony_ci			mdp->speed = phydev->speed;
19638c2ecf20Sopenharmony_ci			if (mdp->cd->set_rate)
19648c2ecf20Sopenharmony_ci				mdp->cd->set_rate(ndev);
19658c2ecf20Sopenharmony_ci		}
19668c2ecf20Sopenharmony_ci		if (!mdp->link) {
19678c2ecf20Sopenharmony_ci			sh_eth_modify(ndev, ECMR, ECMR_TXF, 0);
19688c2ecf20Sopenharmony_ci			new_state = 1;
19698c2ecf20Sopenharmony_ci			mdp->link = phydev->link;
19708c2ecf20Sopenharmony_ci		}
19718c2ecf20Sopenharmony_ci	} else if (mdp->link) {
19728c2ecf20Sopenharmony_ci		new_state = 1;
19738c2ecf20Sopenharmony_ci		mdp->link = 0;
19748c2ecf20Sopenharmony_ci		mdp->speed = 0;
19758c2ecf20Sopenharmony_ci		mdp->duplex = -1;
19768c2ecf20Sopenharmony_ci	}
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	/* Enable TX and RX right over here, if E-MAC change is ignored */
19798c2ecf20Sopenharmony_ci	if ((mdp->cd->no_psr || mdp->no_ether_link) && phydev->link)
19808c2ecf20Sopenharmony_ci		sh_eth_rcv_snd_enable(ndev);
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&mdp->lock, flags);
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	if (new_state && netif_msg_link(mdp))
19858c2ecf20Sopenharmony_ci		phy_print_status(phydev);
19868c2ecf20Sopenharmony_ci}
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci/* PHY init function */
19898c2ecf20Sopenharmony_cistatic int sh_eth_phy_init(struct net_device *ndev)
19908c2ecf20Sopenharmony_ci{
19918c2ecf20Sopenharmony_ci	struct device_node *np = ndev->dev.parent->of_node;
19928c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
19938c2ecf20Sopenharmony_ci	struct phy_device *phydev;
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	mdp->link = 0;
19968c2ecf20Sopenharmony_ci	mdp->speed = 0;
19978c2ecf20Sopenharmony_ci	mdp->duplex = -1;
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_ci	/* Try connect to PHY */
20008c2ecf20Sopenharmony_ci	if (np) {
20018c2ecf20Sopenharmony_ci		struct device_node *pn;
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci		pn = of_parse_phandle(np, "phy-handle", 0);
20048c2ecf20Sopenharmony_ci		phydev = of_phy_connect(ndev, pn,
20058c2ecf20Sopenharmony_ci					sh_eth_adjust_link, 0,
20068c2ecf20Sopenharmony_ci					mdp->phy_interface);
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci		of_node_put(pn);
20098c2ecf20Sopenharmony_ci		if (!phydev)
20108c2ecf20Sopenharmony_ci			phydev = ERR_PTR(-ENOENT);
20118c2ecf20Sopenharmony_ci	} else {
20128c2ecf20Sopenharmony_ci		char phy_id[MII_BUS_ID_SIZE + 3];
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_ci		snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
20158c2ecf20Sopenharmony_ci			 mdp->mii_bus->id, mdp->phy_id);
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci		phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
20188c2ecf20Sopenharmony_ci				     mdp->phy_interface);
20198c2ecf20Sopenharmony_ci	}
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	if (IS_ERR(phydev)) {
20228c2ecf20Sopenharmony_ci		netdev_err(ndev, "failed to connect PHY\n");
20238c2ecf20Sopenharmony_ci		return PTR_ERR(phydev);
20248c2ecf20Sopenharmony_ci	}
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci	/* mask with MAC supported features */
20278c2ecf20Sopenharmony_ci	if (mdp->cd->register_type != SH_ETH_REG_GIGABIT) {
20288c2ecf20Sopenharmony_ci		int err = phy_set_max_speed(phydev, SPEED_100);
20298c2ecf20Sopenharmony_ci		if (err) {
20308c2ecf20Sopenharmony_ci			netdev_err(ndev, "failed to limit PHY to 100 Mbit/s\n");
20318c2ecf20Sopenharmony_ci			phy_disconnect(phydev);
20328c2ecf20Sopenharmony_ci			return err;
20338c2ecf20Sopenharmony_ci		}
20348c2ecf20Sopenharmony_ci	}
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci	phy_attached_info(phydev);
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	return 0;
20398c2ecf20Sopenharmony_ci}
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci/* PHY control start function */
20428c2ecf20Sopenharmony_cistatic int sh_eth_phy_start(struct net_device *ndev)
20438c2ecf20Sopenharmony_ci{
20448c2ecf20Sopenharmony_ci	int ret;
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	ret = sh_eth_phy_init(ndev);
20478c2ecf20Sopenharmony_ci	if (ret)
20488c2ecf20Sopenharmony_ci		return ret;
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	phy_start(ndev->phydev);
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	return 0;
20538c2ecf20Sopenharmony_ci}
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci/* If it is ever necessary to increase SH_ETH_REG_DUMP_MAX_REGS, the
20568c2ecf20Sopenharmony_ci * version must be bumped as well.  Just adding registers up to that
20578c2ecf20Sopenharmony_ci * limit is fine, as long as the existing register indices don't
20588c2ecf20Sopenharmony_ci * change.
20598c2ecf20Sopenharmony_ci */
20608c2ecf20Sopenharmony_ci#define SH_ETH_REG_DUMP_VERSION		1
20618c2ecf20Sopenharmony_ci#define SH_ETH_REG_DUMP_MAX_REGS	256
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_cistatic size_t __sh_eth_get_regs(struct net_device *ndev, u32 *buf)
20648c2ecf20Sopenharmony_ci{
20658c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
20668c2ecf20Sopenharmony_ci	struct sh_eth_cpu_data *cd = mdp->cd;
20678c2ecf20Sopenharmony_ci	u32 *valid_map;
20688c2ecf20Sopenharmony_ci	size_t len;
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci	BUILD_BUG_ON(SH_ETH_MAX_REGISTER_OFFSET > SH_ETH_REG_DUMP_MAX_REGS);
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci	/* Dump starts with a bitmap that tells ethtool which
20738c2ecf20Sopenharmony_ci	 * registers are defined for this chip.
20748c2ecf20Sopenharmony_ci	 */
20758c2ecf20Sopenharmony_ci	len = DIV_ROUND_UP(SH_ETH_REG_DUMP_MAX_REGS, 32);
20768c2ecf20Sopenharmony_ci	if (buf) {
20778c2ecf20Sopenharmony_ci		valid_map = buf;
20788c2ecf20Sopenharmony_ci		buf += len;
20798c2ecf20Sopenharmony_ci	} else {
20808c2ecf20Sopenharmony_ci		valid_map = NULL;
20818c2ecf20Sopenharmony_ci	}
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	/* Add a register to the dump, if it has a defined offset.
20848c2ecf20Sopenharmony_ci	 * This automatically skips most undefined registers, but for
20858c2ecf20Sopenharmony_ci	 * some it is also necessary to check a capability flag in
20868c2ecf20Sopenharmony_ci	 * struct sh_eth_cpu_data.
20878c2ecf20Sopenharmony_ci	 */
20888c2ecf20Sopenharmony_ci#define mark_reg_valid(reg) valid_map[reg / 32] |= 1U << (reg % 32)
20898c2ecf20Sopenharmony_ci#define add_reg_from(reg, read_expr) do {				\
20908c2ecf20Sopenharmony_ci		if (mdp->reg_offset[reg] != SH_ETH_OFFSET_INVALID) {	\
20918c2ecf20Sopenharmony_ci			if (buf) {					\
20928c2ecf20Sopenharmony_ci				mark_reg_valid(reg);			\
20938c2ecf20Sopenharmony_ci				*buf++ = read_expr;			\
20948c2ecf20Sopenharmony_ci			}						\
20958c2ecf20Sopenharmony_ci			++len;						\
20968c2ecf20Sopenharmony_ci		}							\
20978c2ecf20Sopenharmony_ci	} while (0)
20988c2ecf20Sopenharmony_ci#define add_reg(reg) add_reg_from(reg, sh_eth_read(ndev, reg))
20998c2ecf20Sopenharmony_ci#define add_tsu_reg(reg) add_reg_from(reg, sh_eth_tsu_read(mdp, reg))
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	add_reg(EDSR);
21028c2ecf20Sopenharmony_ci	add_reg(EDMR);
21038c2ecf20Sopenharmony_ci	add_reg(EDTRR);
21048c2ecf20Sopenharmony_ci	add_reg(EDRRR);
21058c2ecf20Sopenharmony_ci	add_reg(EESR);
21068c2ecf20Sopenharmony_ci	add_reg(EESIPR);
21078c2ecf20Sopenharmony_ci	add_reg(TDLAR);
21088c2ecf20Sopenharmony_ci	if (!cd->no_xdfar)
21098c2ecf20Sopenharmony_ci		add_reg(TDFAR);
21108c2ecf20Sopenharmony_ci	add_reg(TDFXR);
21118c2ecf20Sopenharmony_ci	add_reg(TDFFR);
21128c2ecf20Sopenharmony_ci	add_reg(RDLAR);
21138c2ecf20Sopenharmony_ci	if (!cd->no_xdfar)
21148c2ecf20Sopenharmony_ci		add_reg(RDFAR);
21158c2ecf20Sopenharmony_ci	add_reg(RDFXR);
21168c2ecf20Sopenharmony_ci	add_reg(RDFFR);
21178c2ecf20Sopenharmony_ci	add_reg(TRSCER);
21188c2ecf20Sopenharmony_ci	add_reg(RMFCR);
21198c2ecf20Sopenharmony_ci	add_reg(TFTR);
21208c2ecf20Sopenharmony_ci	add_reg(FDR);
21218c2ecf20Sopenharmony_ci	add_reg(RMCR);
21228c2ecf20Sopenharmony_ci	add_reg(TFUCR);
21238c2ecf20Sopenharmony_ci	add_reg(RFOCR);
21248c2ecf20Sopenharmony_ci	if (cd->rmiimode)
21258c2ecf20Sopenharmony_ci		add_reg(RMIIMODE);
21268c2ecf20Sopenharmony_ci	add_reg(FCFTR);
21278c2ecf20Sopenharmony_ci	if (cd->rpadir)
21288c2ecf20Sopenharmony_ci		add_reg(RPADIR);
21298c2ecf20Sopenharmony_ci	if (!cd->no_trimd)
21308c2ecf20Sopenharmony_ci		add_reg(TRIMD);
21318c2ecf20Sopenharmony_ci	add_reg(ECMR);
21328c2ecf20Sopenharmony_ci	add_reg(ECSR);
21338c2ecf20Sopenharmony_ci	add_reg(ECSIPR);
21348c2ecf20Sopenharmony_ci	add_reg(PIR);
21358c2ecf20Sopenharmony_ci	if (!cd->no_psr)
21368c2ecf20Sopenharmony_ci		add_reg(PSR);
21378c2ecf20Sopenharmony_ci	add_reg(RDMLR);
21388c2ecf20Sopenharmony_ci	add_reg(RFLR);
21398c2ecf20Sopenharmony_ci	add_reg(IPGR);
21408c2ecf20Sopenharmony_ci	if (cd->apr)
21418c2ecf20Sopenharmony_ci		add_reg(APR);
21428c2ecf20Sopenharmony_ci	if (cd->mpr)
21438c2ecf20Sopenharmony_ci		add_reg(MPR);
21448c2ecf20Sopenharmony_ci	add_reg(RFCR);
21458c2ecf20Sopenharmony_ci	add_reg(RFCF);
21468c2ecf20Sopenharmony_ci	if (cd->tpauser)
21478c2ecf20Sopenharmony_ci		add_reg(TPAUSER);
21488c2ecf20Sopenharmony_ci	add_reg(TPAUSECR);
21498c2ecf20Sopenharmony_ci	if (cd->gecmr)
21508c2ecf20Sopenharmony_ci		add_reg(GECMR);
21518c2ecf20Sopenharmony_ci	if (cd->bculr)
21528c2ecf20Sopenharmony_ci		add_reg(BCULR);
21538c2ecf20Sopenharmony_ci	add_reg(MAHR);
21548c2ecf20Sopenharmony_ci	add_reg(MALR);
21558c2ecf20Sopenharmony_ci	if (!cd->no_tx_cntrs) {
21568c2ecf20Sopenharmony_ci		add_reg(TROCR);
21578c2ecf20Sopenharmony_ci		add_reg(CDCR);
21588c2ecf20Sopenharmony_ci		add_reg(LCCR);
21598c2ecf20Sopenharmony_ci		add_reg(CNDCR);
21608c2ecf20Sopenharmony_ci	}
21618c2ecf20Sopenharmony_ci	add_reg(CEFCR);
21628c2ecf20Sopenharmony_ci	add_reg(FRECR);
21638c2ecf20Sopenharmony_ci	add_reg(TSFRCR);
21648c2ecf20Sopenharmony_ci	add_reg(TLFRCR);
21658c2ecf20Sopenharmony_ci	if (cd->cexcr) {
21668c2ecf20Sopenharmony_ci		add_reg(CERCR);
21678c2ecf20Sopenharmony_ci		add_reg(CEECR);
21688c2ecf20Sopenharmony_ci	}
21698c2ecf20Sopenharmony_ci	add_reg(MAFCR);
21708c2ecf20Sopenharmony_ci	if (cd->rtrate)
21718c2ecf20Sopenharmony_ci		add_reg(RTRATE);
21728c2ecf20Sopenharmony_ci	if (cd->csmr)
21738c2ecf20Sopenharmony_ci		add_reg(CSMR);
21748c2ecf20Sopenharmony_ci	if (cd->select_mii)
21758c2ecf20Sopenharmony_ci		add_reg(RMII_MII);
21768c2ecf20Sopenharmony_ci	if (cd->tsu) {
21778c2ecf20Sopenharmony_ci		add_tsu_reg(ARSTR);
21788c2ecf20Sopenharmony_ci		add_tsu_reg(TSU_CTRST);
21798c2ecf20Sopenharmony_ci		if (cd->dual_port) {
21808c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_FWEN0);
21818c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_FWEN1);
21828c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_FCM);
21838c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_BSYSL0);
21848c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_BSYSL1);
21858c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_PRISL0);
21868c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_PRISL1);
21878c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_FWSL0);
21888c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_FWSL1);
21898c2ecf20Sopenharmony_ci		}
21908c2ecf20Sopenharmony_ci		add_tsu_reg(TSU_FWSLC);
21918c2ecf20Sopenharmony_ci		if (cd->dual_port) {
21928c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_QTAGM0);
21938c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_QTAGM1);
21948c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_FWSR);
21958c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_FWINMK);
21968c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_ADQT0);
21978c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_ADQT1);
21988c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_VTAG0);
21998c2ecf20Sopenharmony_ci			add_tsu_reg(TSU_VTAG1);
22008c2ecf20Sopenharmony_ci		}
22018c2ecf20Sopenharmony_ci		add_tsu_reg(TSU_ADSBSY);
22028c2ecf20Sopenharmony_ci		add_tsu_reg(TSU_TEN);
22038c2ecf20Sopenharmony_ci		add_tsu_reg(TSU_POST1);
22048c2ecf20Sopenharmony_ci		add_tsu_reg(TSU_POST2);
22058c2ecf20Sopenharmony_ci		add_tsu_reg(TSU_POST3);
22068c2ecf20Sopenharmony_ci		add_tsu_reg(TSU_POST4);
22078c2ecf20Sopenharmony_ci		/* This is the start of a table, not just a single register. */
22088c2ecf20Sopenharmony_ci		if (buf) {
22098c2ecf20Sopenharmony_ci			unsigned int i;
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci			mark_reg_valid(TSU_ADRH0);
22128c2ecf20Sopenharmony_ci			for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES * 2; i++)
22138c2ecf20Sopenharmony_ci				*buf++ = ioread32(mdp->tsu_addr +
22148c2ecf20Sopenharmony_ci						  mdp->reg_offset[TSU_ADRH0] +
22158c2ecf20Sopenharmony_ci						  i * 4);
22168c2ecf20Sopenharmony_ci		}
22178c2ecf20Sopenharmony_ci		len += SH_ETH_TSU_CAM_ENTRIES * 2;
22188c2ecf20Sopenharmony_ci	}
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci#undef mark_reg_valid
22218c2ecf20Sopenharmony_ci#undef add_reg_from
22228c2ecf20Sopenharmony_ci#undef add_reg
22238c2ecf20Sopenharmony_ci#undef add_tsu_reg
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci	return len * 4;
22268c2ecf20Sopenharmony_ci}
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_cistatic int sh_eth_get_regs_len(struct net_device *ndev)
22298c2ecf20Sopenharmony_ci{
22308c2ecf20Sopenharmony_ci	return __sh_eth_get_regs(ndev, NULL);
22318c2ecf20Sopenharmony_ci}
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_cistatic void sh_eth_get_regs(struct net_device *ndev, struct ethtool_regs *regs,
22348c2ecf20Sopenharmony_ci			    void *buf)
22358c2ecf20Sopenharmony_ci{
22368c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci	regs->version = SH_ETH_REG_DUMP_VERSION;
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_ci	pm_runtime_get_sync(&mdp->pdev->dev);
22418c2ecf20Sopenharmony_ci	__sh_eth_get_regs(ndev, buf);
22428c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&mdp->pdev->dev);
22438c2ecf20Sopenharmony_ci}
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_cistatic u32 sh_eth_get_msglevel(struct net_device *ndev)
22468c2ecf20Sopenharmony_ci{
22478c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
22488c2ecf20Sopenharmony_ci	return mdp->msg_enable;
22498c2ecf20Sopenharmony_ci}
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_cistatic void sh_eth_set_msglevel(struct net_device *ndev, u32 value)
22528c2ecf20Sopenharmony_ci{
22538c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
22548c2ecf20Sopenharmony_ci	mdp->msg_enable = value;
22558c2ecf20Sopenharmony_ci}
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_cistatic const char sh_eth_gstrings_stats[][ETH_GSTRING_LEN] = {
22588c2ecf20Sopenharmony_ci	"rx_current", "tx_current",
22598c2ecf20Sopenharmony_ci	"rx_dirty", "tx_dirty",
22608c2ecf20Sopenharmony_ci};
22618c2ecf20Sopenharmony_ci#define SH_ETH_STATS_LEN  ARRAY_SIZE(sh_eth_gstrings_stats)
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_cistatic int sh_eth_get_sset_count(struct net_device *netdev, int sset)
22648c2ecf20Sopenharmony_ci{
22658c2ecf20Sopenharmony_ci	switch (sset) {
22668c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
22678c2ecf20Sopenharmony_ci		return SH_ETH_STATS_LEN;
22688c2ecf20Sopenharmony_ci	default:
22698c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
22708c2ecf20Sopenharmony_ci	}
22718c2ecf20Sopenharmony_ci}
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_cistatic void sh_eth_get_ethtool_stats(struct net_device *ndev,
22748c2ecf20Sopenharmony_ci				     struct ethtool_stats *stats, u64 *data)
22758c2ecf20Sopenharmony_ci{
22768c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
22778c2ecf20Sopenharmony_ci	int i = 0;
22788c2ecf20Sopenharmony_ci
22798c2ecf20Sopenharmony_ci	/* device-specific stats */
22808c2ecf20Sopenharmony_ci	data[i++] = mdp->cur_rx;
22818c2ecf20Sopenharmony_ci	data[i++] = mdp->cur_tx;
22828c2ecf20Sopenharmony_ci	data[i++] = mdp->dirty_rx;
22838c2ecf20Sopenharmony_ci	data[i++] = mdp->dirty_tx;
22848c2ecf20Sopenharmony_ci}
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_cistatic void sh_eth_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
22878c2ecf20Sopenharmony_ci{
22888c2ecf20Sopenharmony_ci	switch (stringset) {
22898c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
22908c2ecf20Sopenharmony_ci		memcpy(data, sh_eth_gstrings_stats,
22918c2ecf20Sopenharmony_ci		       sizeof(sh_eth_gstrings_stats));
22928c2ecf20Sopenharmony_ci		break;
22938c2ecf20Sopenharmony_ci	}
22948c2ecf20Sopenharmony_ci}
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_cistatic void sh_eth_get_ringparam(struct net_device *ndev,
22978c2ecf20Sopenharmony_ci				 struct ethtool_ringparam *ring)
22988c2ecf20Sopenharmony_ci{
22998c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci	ring->rx_max_pending = RX_RING_MAX;
23028c2ecf20Sopenharmony_ci	ring->tx_max_pending = TX_RING_MAX;
23038c2ecf20Sopenharmony_ci	ring->rx_pending = mdp->num_rx_ring;
23048c2ecf20Sopenharmony_ci	ring->tx_pending = mdp->num_tx_ring;
23058c2ecf20Sopenharmony_ci}
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_cistatic int sh_eth_set_ringparam(struct net_device *ndev,
23088c2ecf20Sopenharmony_ci				struct ethtool_ringparam *ring)
23098c2ecf20Sopenharmony_ci{
23108c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
23118c2ecf20Sopenharmony_ci	int ret;
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci	if (ring->tx_pending > TX_RING_MAX ||
23148c2ecf20Sopenharmony_ci	    ring->rx_pending > RX_RING_MAX ||
23158c2ecf20Sopenharmony_ci	    ring->tx_pending < TX_RING_MIN ||
23168c2ecf20Sopenharmony_ci	    ring->rx_pending < RX_RING_MIN)
23178c2ecf20Sopenharmony_ci		return -EINVAL;
23188c2ecf20Sopenharmony_ci	if (ring->rx_mini_pending || ring->rx_jumbo_pending)
23198c2ecf20Sopenharmony_ci		return -EINVAL;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	if (netif_running(ndev)) {
23228c2ecf20Sopenharmony_ci		netif_device_detach(ndev);
23238c2ecf20Sopenharmony_ci		netif_tx_disable(ndev);
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci		/* Serialise with the interrupt handler and NAPI, then
23268c2ecf20Sopenharmony_ci		 * disable interrupts.  We have to clear the
23278c2ecf20Sopenharmony_ci		 * irq_enabled flag first to ensure that interrupts
23288c2ecf20Sopenharmony_ci		 * won't be re-enabled.
23298c2ecf20Sopenharmony_ci		 */
23308c2ecf20Sopenharmony_ci		mdp->irq_enabled = false;
23318c2ecf20Sopenharmony_ci		synchronize_irq(ndev->irq);
23328c2ecf20Sopenharmony_ci		napi_synchronize(&mdp->napi);
23338c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0x0000, EESIPR);
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci		sh_eth_dev_exit(ndev);
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci		/* Free all the skbuffs in the Rx queue and the DMA buffers. */
23388c2ecf20Sopenharmony_ci		sh_eth_ring_free(ndev);
23398c2ecf20Sopenharmony_ci	}
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci	/* Set new parameters */
23428c2ecf20Sopenharmony_ci	mdp->num_rx_ring = ring->rx_pending;
23438c2ecf20Sopenharmony_ci	mdp->num_tx_ring = ring->tx_pending;
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci	if (netif_running(ndev)) {
23468c2ecf20Sopenharmony_ci		ret = sh_eth_ring_init(ndev);
23478c2ecf20Sopenharmony_ci		if (ret < 0) {
23488c2ecf20Sopenharmony_ci			netdev_err(ndev, "%s: sh_eth_ring_init failed.\n",
23498c2ecf20Sopenharmony_ci				   __func__);
23508c2ecf20Sopenharmony_ci			return ret;
23518c2ecf20Sopenharmony_ci		}
23528c2ecf20Sopenharmony_ci		ret = sh_eth_dev_init(ndev);
23538c2ecf20Sopenharmony_ci		if (ret < 0) {
23548c2ecf20Sopenharmony_ci			netdev_err(ndev, "%s: sh_eth_dev_init failed.\n",
23558c2ecf20Sopenharmony_ci				   __func__);
23568c2ecf20Sopenharmony_ci			return ret;
23578c2ecf20Sopenharmony_ci		}
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_ci		netif_device_attach(ndev);
23608c2ecf20Sopenharmony_ci	}
23618c2ecf20Sopenharmony_ci
23628c2ecf20Sopenharmony_ci	return 0;
23638c2ecf20Sopenharmony_ci}
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_cistatic void sh_eth_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
23668c2ecf20Sopenharmony_ci{
23678c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci	wol->supported = 0;
23708c2ecf20Sopenharmony_ci	wol->wolopts = 0;
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci	if (mdp->cd->magic) {
23738c2ecf20Sopenharmony_ci		wol->supported = WAKE_MAGIC;
23748c2ecf20Sopenharmony_ci		wol->wolopts = mdp->wol_enabled ? WAKE_MAGIC : 0;
23758c2ecf20Sopenharmony_ci	}
23768c2ecf20Sopenharmony_ci}
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_cistatic int sh_eth_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
23798c2ecf20Sopenharmony_ci{
23808c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_ci	if (!mdp->cd->magic || wol->wolopts & ~WAKE_MAGIC)
23838c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci	mdp->wol_enabled = !!(wol->wolopts & WAKE_MAGIC);
23868c2ecf20Sopenharmony_ci
23878c2ecf20Sopenharmony_ci	device_set_wakeup_enable(&mdp->pdev->dev, mdp->wol_enabled);
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci	return 0;
23908c2ecf20Sopenharmony_ci}
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_cistatic const struct ethtool_ops sh_eth_ethtool_ops = {
23938c2ecf20Sopenharmony_ci	.get_regs_len	= sh_eth_get_regs_len,
23948c2ecf20Sopenharmony_ci	.get_regs	= sh_eth_get_regs,
23958c2ecf20Sopenharmony_ci	.nway_reset	= phy_ethtool_nway_reset,
23968c2ecf20Sopenharmony_ci	.get_msglevel	= sh_eth_get_msglevel,
23978c2ecf20Sopenharmony_ci	.set_msglevel	= sh_eth_set_msglevel,
23988c2ecf20Sopenharmony_ci	.get_link	= ethtool_op_get_link,
23998c2ecf20Sopenharmony_ci	.get_strings	= sh_eth_get_strings,
24008c2ecf20Sopenharmony_ci	.get_ethtool_stats  = sh_eth_get_ethtool_stats,
24018c2ecf20Sopenharmony_ci	.get_sset_count     = sh_eth_get_sset_count,
24028c2ecf20Sopenharmony_ci	.get_ringparam	= sh_eth_get_ringparam,
24038c2ecf20Sopenharmony_ci	.set_ringparam	= sh_eth_set_ringparam,
24048c2ecf20Sopenharmony_ci	.get_link_ksettings = phy_ethtool_get_link_ksettings,
24058c2ecf20Sopenharmony_ci	.set_link_ksettings = phy_ethtool_set_link_ksettings,
24068c2ecf20Sopenharmony_ci	.get_wol	= sh_eth_get_wol,
24078c2ecf20Sopenharmony_ci	.set_wol	= sh_eth_set_wol,
24088c2ecf20Sopenharmony_ci};
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci/* network device open function */
24118c2ecf20Sopenharmony_cistatic int sh_eth_open(struct net_device *ndev)
24128c2ecf20Sopenharmony_ci{
24138c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
24148c2ecf20Sopenharmony_ci	int ret;
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_ci	pm_runtime_get_sync(&mdp->pdev->dev);
24178c2ecf20Sopenharmony_ci
24188c2ecf20Sopenharmony_ci	napi_enable(&mdp->napi);
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci	ret = request_irq(ndev->irq, sh_eth_interrupt,
24218c2ecf20Sopenharmony_ci			  mdp->cd->irq_flags, ndev->name, ndev);
24228c2ecf20Sopenharmony_ci	if (ret) {
24238c2ecf20Sopenharmony_ci		netdev_err(ndev, "Can not assign IRQ number\n");
24248c2ecf20Sopenharmony_ci		goto out_napi_off;
24258c2ecf20Sopenharmony_ci	}
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci	/* Descriptor set */
24288c2ecf20Sopenharmony_ci	ret = sh_eth_ring_init(ndev);
24298c2ecf20Sopenharmony_ci	if (ret)
24308c2ecf20Sopenharmony_ci		goto out_free_irq;
24318c2ecf20Sopenharmony_ci
24328c2ecf20Sopenharmony_ci	/* device init */
24338c2ecf20Sopenharmony_ci	ret = sh_eth_dev_init(ndev);
24348c2ecf20Sopenharmony_ci	if (ret)
24358c2ecf20Sopenharmony_ci		goto out_free_irq;
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci	/* PHY control start*/
24388c2ecf20Sopenharmony_ci	ret = sh_eth_phy_start(ndev);
24398c2ecf20Sopenharmony_ci	if (ret)
24408c2ecf20Sopenharmony_ci		goto out_free_irq;
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	netif_start_queue(ndev);
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_ci	mdp->is_opened = 1;
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci	return ret;
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_ciout_free_irq:
24498c2ecf20Sopenharmony_ci	free_irq(ndev->irq, ndev);
24508c2ecf20Sopenharmony_ciout_napi_off:
24518c2ecf20Sopenharmony_ci	napi_disable(&mdp->napi);
24528c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&mdp->pdev->dev);
24538c2ecf20Sopenharmony_ci	return ret;
24548c2ecf20Sopenharmony_ci}
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci/* Timeout function */
24578c2ecf20Sopenharmony_cistatic void sh_eth_tx_timeout(struct net_device *ndev, unsigned int txqueue)
24588c2ecf20Sopenharmony_ci{
24598c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
24608c2ecf20Sopenharmony_ci	struct sh_eth_rxdesc *rxdesc;
24618c2ecf20Sopenharmony_ci	int i;
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_ci	netif_stop_queue(ndev);
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci	netif_err(mdp, timer, ndev,
24668c2ecf20Sopenharmony_ci		  "transmit timed out, status %8.8x, resetting...\n",
24678c2ecf20Sopenharmony_ci		  sh_eth_read(ndev, EESR));
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	/* tx_errors count up */
24708c2ecf20Sopenharmony_ci	ndev->stats.tx_errors++;
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci	/* Free all the skbuffs in the Rx queue. */
24738c2ecf20Sopenharmony_ci	for (i = 0; i < mdp->num_rx_ring; i++) {
24748c2ecf20Sopenharmony_ci		rxdesc = &mdp->rx_ring[i];
24758c2ecf20Sopenharmony_ci		rxdesc->status = cpu_to_le32(0);
24768c2ecf20Sopenharmony_ci		rxdesc->addr = cpu_to_le32(0xBADF00D0);
24778c2ecf20Sopenharmony_ci		dev_kfree_skb(mdp->rx_skbuff[i]);
24788c2ecf20Sopenharmony_ci		mdp->rx_skbuff[i] = NULL;
24798c2ecf20Sopenharmony_ci	}
24808c2ecf20Sopenharmony_ci	for (i = 0; i < mdp->num_tx_ring; i++) {
24818c2ecf20Sopenharmony_ci		dev_kfree_skb(mdp->tx_skbuff[i]);
24828c2ecf20Sopenharmony_ci		mdp->tx_skbuff[i] = NULL;
24838c2ecf20Sopenharmony_ci	}
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci	/* device init */
24868c2ecf20Sopenharmony_ci	sh_eth_dev_init(ndev);
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci	netif_start_queue(ndev);
24898c2ecf20Sopenharmony_ci}
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci/* Packet transmit function */
24928c2ecf20Sopenharmony_cistatic netdev_tx_t sh_eth_start_xmit(struct sk_buff *skb,
24938c2ecf20Sopenharmony_ci				     struct net_device *ndev)
24948c2ecf20Sopenharmony_ci{
24958c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
24968c2ecf20Sopenharmony_ci	struct sh_eth_txdesc *txdesc;
24978c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
24988c2ecf20Sopenharmony_ci	u32 entry;
24998c2ecf20Sopenharmony_ci	unsigned long flags;
25008c2ecf20Sopenharmony_ci
25018c2ecf20Sopenharmony_ci	spin_lock_irqsave(&mdp->lock, flags);
25028c2ecf20Sopenharmony_ci	if ((mdp->cur_tx - mdp->dirty_tx) >= (mdp->num_tx_ring - 4)) {
25038c2ecf20Sopenharmony_ci		if (!sh_eth_tx_free(ndev, true)) {
25048c2ecf20Sopenharmony_ci			netif_warn(mdp, tx_queued, ndev, "TxFD exhausted.\n");
25058c2ecf20Sopenharmony_ci			netif_stop_queue(ndev);
25068c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&mdp->lock, flags);
25078c2ecf20Sopenharmony_ci			return NETDEV_TX_BUSY;
25088c2ecf20Sopenharmony_ci		}
25098c2ecf20Sopenharmony_ci	}
25108c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&mdp->lock, flags);
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci	if (skb_put_padto(skb, ETH_ZLEN))
25138c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	entry = mdp->cur_tx % mdp->num_tx_ring;
25168c2ecf20Sopenharmony_ci	mdp->tx_skbuff[entry] = skb;
25178c2ecf20Sopenharmony_ci	txdesc = &mdp->tx_ring[entry];
25188c2ecf20Sopenharmony_ci	/* soft swap. */
25198c2ecf20Sopenharmony_ci	if (!mdp->cd->hw_swap)
25208c2ecf20Sopenharmony_ci		sh_eth_soft_swap(PTR_ALIGN(skb->data, 4), skb->len + 2);
25218c2ecf20Sopenharmony_ci	dma_addr = dma_map_single(&mdp->pdev->dev, skb->data, skb->len,
25228c2ecf20Sopenharmony_ci				  DMA_TO_DEVICE);
25238c2ecf20Sopenharmony_ci	if (dma_mapping_error(&mdp->pdev->dev, dma_addr)) {
25248c2ecf20Sopenharmony_ci		kfree_skb(skb);
25258c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
25268c2ecf20Sopenharmony_ci	}
25278c2ecf20Sopenharmony_ci	txdesc->addr = cpu_to_le32(dma_addr);
25288c2ecf20Sopenharmony_ci	txdesc->len  = cpu_to_le32(skb->len << 16);
25298c2ecf20Sopenharmony_ci
25308c2ecf20Sopenharmony_ci	dma_wmb(); /* TACT bit must be set after all the above writes */
25318c2ecf20Sopenharmony_ci	if (entry >= mdp->num_tx_ring - 1)
25328c2ecf20Sopenharmony_ci		txdesc->status |= cpu_to_le32(TD_TACT | TD_TDLE);
25338c2ecf20Sopenharmony_ci	else
25348c2ecf20Sopenharmony_ci		txdesc->status |= cpu_to_le32(TD_TACT);
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_ci	wmb(); /* cur_tx must be incremented after TACT bit was set */
25378c2ecf20Sopenharmony_ci	mdp->cur_tx++;
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci	if (!(sh_eth_read(ndev, EDTRR) & mdp->cd->edtrr_trns))
25408c2ecf20Sopenharmony_ci		sh_eth_write(ndev, mdp->cd->edtrr_trns, EDTRR);
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
25438c2ecf20Sopenharmony_ci}
25448c2ecf20Sopenharmony_ci
25458c2ecf20Sopenharmony_ci/* The statistics registers have write-clear behaviour, which means we
25468c2ecf20Sopenharmony_ci * will lose any increment between the read and write.  We mitigate
25478c2ecf20Sopenharmony_ci * this by only clearing when we read a non-zero value, so we will
25488c2ecf20Sopenharmony_ci * never falsely report a total of zero.
25498c2ecf20Sopenharmony_ci */
25508c2ecf20Sopenharmony_cistatic void
25518c2ecf20Sopenharmony_cish_eth_update_stat(struct net_device *ndev, unsigned long *stat, int reg)
25528c2ecf20Sopenharmony_ci{
25538c2ecf20Sopenharmony_ci	u32 delta = sh_eth_read(ndev, reg);
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci	if (delta) {
25568c2ecf20Sopenharmony_ci		*stat += delta;
25578c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0, reg);
25588c2ecf20Sopenharmony_ci	}
25598c2ecf20Sopenharmony_ci}
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_cistatic struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
25628c2ecf20Sopenharmony_ci{
25638c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci	if (mdp->cd->no_tx_cntrs)
25668c2ecf20Sopenharmony_ci		return &ndev->stats;
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_ci	if (!mdp->is_opened)
25698c2ecf20Sopenharmony_ci		return &ndev->stats;
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_ci	sh_eth_update_stat(ndev, &ndev->stats.tx_dropped, TROCR);
25728c2ecf20Sopenharmony_ci	sh_eth_update_stat(ndev, &ndev->stats.collisions, CDCR);
25738c2ecf20Sopenharmony_ci	sh_eth_update_stat(ndev, &ndev->stats.tx_carrier_errors, LCCR);
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci	if (mdp->cd->cexcr) {
25768c2ecf20Sopenharmony_ci		sh_eth_update_stat(ndev, &ndev->stats.tx_carrier_errors,
25778c2ecf20Sopenharmony_ci				   CERCR);
25788c2ecf20Sopenharmony_ci		sh_eth_update_stat(ndev, &ndev->stats.tx_carrier_errors,
25798c2ecf20Sopenharmony_ci				   CEECR);
25808c2ecf20Sopenharmony_ci	} else {
25818c2ecf20Sopenharmony_ci		sh_eth_update_stat(ndev, &ndev->stats.tx_carrier_errors,
25828c2ecf20Sopenharmony_ci				   CNDCR);
25838c2ecf20Sopenharmony_ci	}
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci	return &ndev->stats;
25868c2ecf20Sopenharmony_ci}
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci/* device close function */
25898c2ecf20Sopenharmony_cistatic int sh_eth_close(struct net_device *ndev)
25908c2ecf20Sopenharmony_ci{
25918c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
25928c2ecf20Sopenharmony_ci
25938c2ecf20Sopenharmony_ci	netif_stop_queue(ndev);
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci	/* Serialise with the interrupt handler and NAPI, then disable
25968c2ecf20Sopenharmony_ci	 * interrupts.  We have to clear the irq_enabled flag first to
25978c2ecf20Sopenharmony_ci	 * ensure that interrupts won't be re-enabled.
25988c2ecf20Sopenharmony_ci	 */
25998c2ecf20Sopenharmony_ci	mdp->irq_enabled = false;
26008c2ecf20Sopenharmony_ci	synchronize_irq(ndev->irq);
26018c2ecf20Sopenharmony_ci	napi_disable(&mdp->napi);
26028c2ecf20Sopenharmony_ci	sh_eth_write(ndev, 0x0000, EESIPR);
26038c2ecf20Sopenharmony_ci
26048c2ecf20Sopenharmony_ci	sh_eth_dev_exit(ndev);
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci	/* PHY Disconnect */
26078c2ecf20Sopenharmony_ci	if (ndev->phydev) {
26088c2ecf20Sopenharmony_ci		phy_stop(ndev->phydev);
26098c2ecf20Sopenharmony_ci		phy_disconnect(ndev->phydev);
26108c2ecf20Sopenharmony_ci	}
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	free_irq(ndev->irq, ndev);
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci	/* Free all the skbuffs in the Rx queue and the DMA buffer. */
26158c2ecf20Sopenharmony_ci	sh_eth_ring_free(ndev);
26168c2ecf20Sopenharmony_ci
26178c2ecf20Sopenharmony_ci	mdp->is_opened = 0;
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci	pm_runtime_put(&mdp->pdev->dev);
26208c2ecf20Sopenharmony_ci
26218c2ecf20Sopenharmony_ci	return 0;
26228c2ecf20Sopenharmony_ci}
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_cistatic int sh_eth_change_mtu(struct net_device *ndev, int new_mtu)
26258c2ecf20Sopenharmony_ci{
26268c2ecf20Sopenharmony_ci	if (netif_running(ndev))
26278c2ecf20Sopenharmony_ci		return -EBUSY;
26288c2ecf20Sopenharmony_ci
26298c2ecf20Sopenharmony_ci	ndev->mtu = new_mtu;
26308c2ecf20Sopenharmony_ci	netdev_update_features(ndev);
26318c2ecf20Sopenharmony_ci
26328c2ecf20Sopenharmony_ci	return 0;
26338c2ecf20Sopenharmony_ci}
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_ci/* For TSU_POSTn. Please refer to the manual about this (strange) bitfields */
26368c2ecf20Sopenharmony_cistatic u32 sh_eth_tsu_get_post_mask(int entry)
26378c2ecf20Sopenharmony_ci{
26388c2ecf20Sopenharmony_ci	return 0x0f << (28 - ((entry % 8) * 4));
26398c2ecf20Sopenharmony_ci}
26408c2ecf20Sopenharmony_ci
26418c2ecf20Sopenharmony_cistatic u32 sh_eth_tsu_get_post_bit(struct sh_eth_private *mdp, int entry)
26428c2ecf20Sopenharmony_ci{
26438c2ecf20Sopenharmony_ci	return (0x08 >> (mdp->port << 1)) << (28 - ((entry % 8) * 4));
26448c2ecf20Sopenharmony_ci}
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_cistatic void sh_eth_tsu_enable_cam_entry_post(struct net_device *ndev,
26478c2ecf20Sopenharmony_ci					     int entry)
26488c2ecf20Sopenharmony_ci{
26498c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
26508c2ecf20Sopenharmony_ci	int reg = TSU_POST1 + entry / 8;
26518c2ecf20Sopenharmony_ci	u32 tmp;
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ci	tmp = sh_eth_tsu_read(mdp, reg);
26548c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, tmp | sh_eth_tsu_get_post_bit(mdp, entry), reg);
26558c2ecf20Sopenharmony_ci}
26568c2ecf20Sopenharmony_ci
26578c2ecf20Sopenharmony_cistatic bool sh_eth_tsu_disable_cam_entry_post(struct net_device *ndev,
26588c2ecf20Sopenharmony_ci					      int entry)
26598c2ecf20Sopenharmony_ci{
26608c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
26618c2ecf20Sopenharmony_ci	int reg = TSU_POST1 + entry / 8;
26628c2ecf20Sopenharmony_ci	u32 post_mask, ref_mask, tmp;
26638c2ecf20Sopenharmony_ci
26648c2ecf20Sopenharmony_ci	post_mask = sh_eth_tsu_get_post_mask(entry);
26658c2ecf20Sopenharmony_ci	ref_mask = sh_eth_tsu_get_post_bit(mdp, entry) & ~post_mask;
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci	tmp = sh_eth_tsu_read(mdp, reg);
26688c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, tmp & ~post_mask, reg);
26698c2ecf20Sopenharmony_ci
26708c2ecf20Sopenharmony_ci	/* If other port enables, the function returns "true" */
26718c2ecf20Sopenharmony_ci	return tmp & ref_mask;
26728c2ecf20Sopenharmony_ci}
26738c2ecf20Sopenharmony_ci
26748c2ecf20Sopenharmony_cistatic int sh_eth_tsu_busy(struct net_device *ndev)
26758c2ecf20Sopenharmony_ci{
26768c2ecf20Sopenharmony_ci	int timeout = SH_ETH_TSU_TIMEOUT_MS * 100;
26778c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_ci	while ((sh_eth_tsu_read(mdp, TSU_ADSBSY) & TSU_ADSBSY_0)) {
26808c2ecf20Sopenharmony_ci		udelay(10);
26818c2ecf20Sopenharmony_ci		timeout--;
26828c2ecf20Sopenharmony_ci		if (timeout <= 0) {
26838c2ecf20Sopenharmony_ci			netdev_err(ndev, "%s: timeout\n", __func__);
26848c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
26858c2ecf20Sopenharmony_ci		}
26868c2ecf20Sopenharmony_ci	}
26878c2ecf20Sopenharmony_ci
26888c2ecf20Sopenharmony_ci	return 0;
26898c2ecf20Sopenharmony_ci}
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_cistatic int sh_eth_tsu_write_entry(struct net_device *ndev, u16 offset,
26928c2ecf20Sopenharmony_ci				  const u8 *addr)
26938c2ecf20Sopenharmony_ci{
26948c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
26958c2ecf20Sopenharmony_ci	u32 val;
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci	val = addr[0] << 24 | addr[1] << 16 | addr[2] << 8 | addr[3];
26988c2ecf20Sopenharmony_ci	iowrite32(val, mdp->tsu_addr + offset);
26998c2ecf20Sopenharmony_ci	if (sh_eth_tsu_busy(ndev) < 0)
27008c2ecf20Sopenharmony_ci		return -EBUSY;
27018c2ecf20Sopenharmony_ci
27028c2ecf20Sopenharmony_ci	val = addr[4] << 8 | addr[5];
27038c2ecf20Sopenharmony_ci	iowrite32(val, mdp->tsu_addr + offset + 4);
27048c2ecf20Sopenharmony_ci	if (sh_eth_tsu_busy(ndev) < 0)
27058c2ecf20Sopenharmony_ci		return -EBUSY;
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci	return 0;
27088c2ecf20Sopenharmony_ci}
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_cistatic void sh_eth_tsu_read_entry(struct net_device *ndev, u16 offset, u8 *addr)
27118c2ecf20Sopenharmony_ci{
27128c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
27138c2ecf20Sopenharmony_ci	u32 val;
27148c2ecf20Sopenharmony_ci
27158c2ecf20Sopenharmony_ci	val = ioread32(mdp->tsu_addr + offset);
27168c2ecf20Sopenharmony_ci	addr[0] = (val >> 24) & 0xff;
27178c2ecf20Sopenharmony_ci	addr[1] = (val >> 16) & 0xff;
27188c2ecf20Sopenharmony_ci	addr[2] = (val >> 8) & 0xff;
27198c2ecf20Sopenharmony_ci	addr[3] = val & 0xff;
27208c2ecf20Sopenharmony_ci	val = ioread32(mdp->tsu_addr + offset + 4);
27218c2ecf20Sopenharmony_ci	addr[4] = (val >> 8) & 0xff;
27228c2ecf20Sopenharmony_ci	addr[5] = val & 0xff;
27238c2ecf20Sopenharmony_ci}
27248c2ecf20Sopenharmony_ci
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_cistatic int sh_eth_tsu_find_entry(struct net_device *ndev, const u8 *addr)
27278c2ecf20Sopenharmony_ci{
27288c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
27298c2ecf20Sopenharmony_ci	u16 reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);
27308c2ecf20Sopenharmony_ci	int i;
27318c2ecf20Sopenharmony_ci	u8 c_addr[ETH_ALEN];
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci	for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++, reg_offset += 8) {
27348c2ecf20Sopenharmony_ci		sh_eth_tsu_read_entry(ndev, reg_offset, c_addr);
27358c2ecf20Sopenharmony_ci		if (ether_addr_equal(addr, c_addr))
27368c2ecf20Sopenharmony_ci			return i;
27378c2ecf20Sopenharmony_ci	}
27388c2ecf20Sopenharmony_ci
27398c2ecf20Sopenharmony_ci	return -ENOENT;
27408c2ecf20Sopenharmony_ci}
27418c2ecf20Sopenharmony_ci
27428c2ecf20Sopenharmony_cistatic int sh_eth_tsu_find_empty(struct net_device *ndev)
27438c2ecf20Sopenharmony_ci{
27448c2ecf20Sopenharmony_ci	u8 blank[ETH_ALEN];
27458c2ecf20Sopenharmony_ci	int entry;
27468c2ecf20Sopenharmony_ci
27478c2ecf20Sopenharmony_ci	memset(blank, 0, sizeof(blank));
27488c2ecf20Sopenharmony_ci	entry = sh_eth_tsu_find_entry(ndev, blank);
27498c2ecf20Sopenharmony_ci	return (entry < 0) ? -ENOMEM : entry;
27508c2ecf20Sopenharmony_ci}
27518c2ecf20Sopenharmony_ci
27528c2ecf20Sopenharmony_cistatic int sh_eth_tsu_disable_cam_entry_table(struct net_device *ndev,
27538c2ecf20Sopenharmony_ci					      int entry)
27548c2ecf20Sopenharmony_ci{
27558c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
27568c2ecf20Sopenharmony_ci	u16 reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);
27578c2ecf20Sopenharmony_ci	int ret;
27588c2ecf20Sopenharmony_ci	u8 blank[ETH_ALEN];
27598c2ecf20Sopenharmony_ci
27608c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, sh_eth_tsu_read(mdp, TSU_TEN) &
27618c2ecf20Sopenharmony_ci			 ~(1 << (31 - entry)), TSU_TEN);
27628c2ecf20Sopenharmony_ci
27638c2ecf20Sopenharmony_ci	memset(blank, 0, sizeof(blank));
27648c2ecf20Sopenharmony_ci	ret = sh_eth_tsu_write_entry(ndev, reg_offset + entry * 8, blank);
27658c2ecf20Sopenharmony_ci	if (ret < 0)
27668c2ecf20Sopenharmony_ci		return ret;
27678c2ecf20Sopenharmony_ci	return 0;
27688c2ecf20Sopenharmony_ci}
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_cistatic int sh_eth_tsu_add_entry(struct net_device *ndev, const u8 *addr)
27718c2ecf20Sopenharmony_ci{
27728c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
27738c2ecf20Sopenharmony_ci	u16 reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);
27748c2ecf20Sopenharmony_ci	int i, ret;
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	if (!mdp->cd->tsu)
27778c2ecf20Sopenharmony_ci		return 0;
27788c2ecf20Sopenharmony_ci
27798c2ecf20Sopenharmony_ci	i = sh_eth_tsu_find_entry(ndev, addr);
27808c2ecf20Sopenharmony_ci	if (i < 0) {
27818c2ecf20Sopenharmony_ci		/* No entry found, create one */
27828c2ecf20Sopenharmony_ci		i = sh_eth_tsu_find_empty(ndev);
27838c2ecf20Sopenharmony_ci		if (i < 0)
27848c2ecf20Sopenharmony_ci			return -ENOMEM;
27858c2ecf20Sopenharmony_ci		ret = sh_eth_tsu_write_entry(ndev, reg_offset + i * 8, addr);
27868c2ecf20Sopenharmony_ci		if (ret < 0)
27878c2ecf20Sopenharmony_ci			return ret;
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci		/* Enable the entry */
27908c2ecf20Sopenharmony_ci		sh_eth_tsu_write(mdp, sh_eth_tsu_read(mdp, TSU_TEN) |
27918c2ecf20Sopenharmony_ci				 (1 << (31 - i)), TSU_TEN);
27928c2ecf20Sopenharmony_ci	}
27938c2ecf20Sopenharmony_ci
27948c2ecf20Sopenharmony_ci	/* Entry found or created, enable POST */
27958c2ecf20Sopenharmony_ci	sh_eth_tsu_enable_cam_entry_post(ndev, i);
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci	return 0;
27988c2ecf20Sopenharmony_ci}
27998c2ecf20Sopenharmony_ci
28008c2ecf20Sopenharmony_cistatic int sh_eth_tsu_del_entry(struct net_device *ndev, const u8 *addr)
28018c2ecf20Sopenharmony_ci{
28028c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
28038c2ecf20Sopenharmony_ci	int i, ret;
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci	if (!mdp->cd->tsu)
28068c2ecf20Sopenharmony_ci		return 0;
28078c2ecf20Sopenharmony_ci
28088c2ecf20Sopenharmony_ci	i = sh_eth_tsu_find_entry(ndev, addr);
28098c2ecf20Sopenharmony_ci	if (i) {
28108c2ecf20Sopenharmony_ci		/* Entry found */
28118c2ecf20Sopenharmony_ci		if (sh_eth_tsu_disable_cam_entry_post(ndev, i))
28128c2ecf20Sopenharmony_ci			goto done;
28138c2ecf20Sopenharmony_ci
28148c2ecf20Sopenharmony_ci		/* Disable the entry if both ports was disabled */
28158c2ecf20Sopenharmony_ci		ret = sh_eth_tsu_disable_cam_entry_table(ndev, i);
28168c2ecf20Sopenharmony_ci		if (ret < 0)
28178c2ecf20Sopenharmony_ci			return ret;
28188c2ecf20Sopenharmony_ci	}
28198c2ecf20Sopenharmony_cidone:
28208c2ecf20Sopenharmony_ci	return 0;
28218c2ecf20Sopenharmony_ci}
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_cistatic int sh_eth_tsu_purge_all(struct net_device *ndev)
28248c2ecf20Sopenharmony_ci{
28258c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
28268c2ecf20Sopenharmony_ci	int i, ret;
28278c2ecf20Sopenharmony_ci
28288c2ecf20Sopenharmony_ci	if (!mdp->cd->tsu)
28298c2ecf20Sopenharmony_ci		return 0;
28308c2ecf20Sopenharmony_ci
28318c2ecf20Sopenharmony_ci	for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++) {
28328c2ecf20Sopenharmony_ci		if (sh_eth_tsu_disable_cam_entry_post(ndev, i))
28338c2ecf20Sopenharmony_ci			continue;
28348c2ecf20Sopenharmony_ci
28358c2ecf20Sopenharmony_ci		/* Disable the entry if both ports was disabled */
28368c2ecf20Sopenharmony_ci		ret = sh_eth_tsu_disable_cam_entry_table(ndev, i);
28378c2ecf20Sopenharmony_ci		if (ret < 0)
28388c2ecf20Sopenharmony_ci			return ret;
28398c2ecf20Sopenharmony_ci	}
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci	return 0;
28428c2ecf20Sopenharmony_ci}
28438c2ecf20Sopenharmony_ci
28448c2ecf20Sopenharmony_cistatic void sh_eth_tsu_purge_mcast(struct net_device *ndev)
28458c2ecf20Sopenharmony_ci{
28468c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
28478c2ecf20Sopenharmony_ci	u16 reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);
28488c2ecf20Sopenharmony_ci	u8 addr[ETH_ALEN];
28498c2ecf20Sopenharmony_ci	int i;
28508c2ecf20Sopenharmony_ci
28518c2ecf20Sopenharmony_ci	if (!mdp->cd->tsu)
28528c2ecf20Sopenharmony_ci		return;
28538c2ecf20Sopenharmony_ci
28548c2ecf20Sopenharmony_ci	for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++, reg_offset += 8) {
28558c2ecf20Sopenharmony_ci		sh_eth_tsu_read_entry(ndev, reg_offset, addr);
28568c2ecf20Sopenharmony_ci		if (is_multicast_ether_addr(addr))
28578c2ecf20Sopenharmony_ci			sh_eth_tsu_del_entry(ndev, addr);
28588c2ecf20Sopenharmony_ci	}
28598c2ecf20Sopenharmony_ci}
28608c2ecf20Sopenharmony_ci
28618c2ecf20Sopenharmony_ci/* Update promiscuous flag and multicast filter */
28628c2ecf20Sopenharmony_cistatic void sh_eth_set_rx_mode(struct net_device *ndev)
28638c2ecf20Sopenharmony_ci{
28648c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
28658c2ecf20Sopenharmony_ci	u32 ecmr_bits;
28668c2ecf20Sopenharmony_ci	int mcast_all = 0;
28678c2ecf20Sopenharmony_ci	unsigned long flags;
28688c2ecf20Sopenharmony_ci
28698c2ecf20Sopenharmony_ci	spin_lock_irqsave(&mdp->lock, flags);
28708c2ecf20Sopenharmony_ci	/* Initial condition is MCT = 1, PRM = 0.
28718c2ecf20Sopenharmony_ci	 * Depending on ndev->flags, set PRM or clear MCT
28728c2ecf20Sopenharmony_ci	 */
28738c2ecf20Sopenharmony_ci	ecmr_bits = sh_eth_read(ndev, ECMR) & ~ECMR_PRM;
28748c2ecf20Sopenharmony_ci	if (mdp->cd->tsu)
28758c2ecf20Sopenharmony_ci		ecmr_bits |= ECMR_MCT;
28768c2ecf20Sopenharmony_ci
28778c2ecf20Sopenharmony_ci	if (!(ndev->flags & IFF_MULTICAST)) {
28788c2ecf20Sopenharmony_ci		sh_eth_tsu_purge_mcast(ndev);
28798c2ecf20Sopenharmony_ci		mcast_all = 1;
28808c2ecf20Sopenharmony_ci	}
28818c2ecf20Sopenharmony_ci	if (ndev->flags & IFF_ALLMULTI) {
28828c2ecf20Sopenharmony_ci		sh_eth_tsu_purge_mcast(ndev);
28838c2ecf20Sopenharmony_ci		ecmr_bits &= ~ECMR_MCT;
28848c2ecf20Sopenharmony_ci		mcast_all = 1;
28858c2ecf20Sopenharmony_ci	}
28868c2ecf20Sopenharmony_ci
28878c2ecf20Sopenharmony_ci	if (ndev->flags & IFF_PROMISC) {
28888c2ecf20Sopenharmony_ci		sh_eth_tsu_purge_all(ndev);
28898c2ecf20Sopenharmony_ci		ecmr_bits = (ecmr_bits & ~ECMR_MCT) | ECMR_PRM;
28908c2ecf20Sopenharmony_ci	} else if (mdp->cd->tsu) {
28918c2ecf20Sopenharmony_ci		struct netdev_hw_addr *ha;
28928c2ecf20Sopenharmony_ci		netdev_for_each_mc_addr(ha, ndev) {
28938c2ecf20Sopenharmony_ci			if (mcast_all && is_multicast_ether_addr(ha->addr))
28948c2ecf20Sopenharmony_ci				continue;
28958c2ecf20Sopenharmony_ci
28968c2ecf20Sopenharmony_ci			if (sh_eth_tsu_add_entry(ndev, ha->addr) < 0) {
28978c2ecf20Sopenharmony_ci				if (!mcast_all) {
28988c2ecf20Sopenharmony_ci					sh_eth_tsu_purge_mcast(ndev);
28998c2ecf20Sopenharmony_ci					ecmr_bits &= ~ECMR_MCT;
29008c2ecf20Sopenharmony_ci					mcast_all = 1;
29018c2ecf20Sopenharmony_ci				}
29028c2ecf20Sopenharmony_ci			}
29038c2ecf20Sopenharmony_ci		}
29048c2ecf20Sopenharmony_ci	}
29058c2ecf20Sopenharmony_ci
29068c2ecf20Sopenharmony_ci	/* update the ethernet mode */
29078c2ecf20Sopenharmony_ci	sh_eth_write(ndev, ecmr_bits, ECMR);
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&mdp->lock, flags);
29108c2ecf20Sopenharmony_ci}
29118c2ecf20Sopenharmony_ci
29128c2ecf20Sopenharmony_cistatic void sh_eth_set_rx_csum(struct net_device *ndev, bool enable)
29138c2ecf20Sopenharmony_ci{
29148c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
29158c2ecf20Sopenharmony_ci	unsigned long flags;
29168c2ecf20Sopenharmony_ci
29178c2ecf20Sopenharmony_ci	spin_lock_irqsave(&mdp->lock, flags);
29188c2ecf20Sopenharmony_ci
29198c2ecf20Sopenharmony_ci	/* Disable TX and RX */
29208c2ecf20Sopenharmony_ci	sh_eth_rcv_snd_disable(ndev);
29218c2ecf20Sopenharmony_ci
29228c2ecf20Sopenharmony_ci	/* Modify RX Checksum setting */
29238c2ecf20Sopenharmony_ci	sh_eth_modify(ndev, ECMR, ECMR_RCSC, enable ? ECMR_RCSC : 0);
29248c2ecf20Sopenharmony_ci
29258c2ecf20Sopenharmony_ci	/* Enable TX and RX */
29268c2ecf20Sopenharmony_ci	sh_eth_rcv_snd_enable(ndev);
29278c2ecf20Sopenharmony_ci
29288c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&mdp->lock, flags);
29298c2ecf20Sopenharmony_ci}
29308c2ecf20Sopenharmony_ci
29318c2ecf20Sopenharmony_cistatic int sh_eth_set_features(struct net_device *ndev,
29328c2ecf20Sopenharmony_ci			       netdev_features_t features)
29338c2ecf20Sopenharmony_ci{
29348c2ecf20Sopenharmony_ci	netdev_features_t changed = ndev->features ^ features;
29358c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
29368c2ecf20Sopenharmony_ci
29378c2ecf20Sopenharmony_ci	if (changed & NETIF_F_RXCSUM && mdp->cd->rx_csum)
29388c2ecf20Sopenharmony_ci		sh_eth_set_rx_csum(ndev, features & NETIF_F_RXCSUM);
29398c2ecf20Sopenharmony_ci
29408c2ecf20Sopenharmony_ci	ndev->features = features;
29418c2ecf20Sopenharmony_ci
29428c2ecf20Sopenharmony_ci	return 0;
29438c2ecf20Sopenharmony_ci}
29448c2ecf20Sopenharmony_ci
29458c2ecf20Sopenharmony_cistatic int sh_eth_get_vtag_index(struct sh_eth_private *mdp)
29468c2ecf20Sopenharmony_ci{
29478c2ecf20Sopenharmony_ci	if (!mdp->port)
29488c2ecf20Sopenharmony_ci		return TSU_VTAG0;
29498c2ecf20Sopenharmony_ci	else
29508c2ecf20Sopenharmony_ci		return TSU_VTAG1;
29518c2ecf20Sopenharmony_ci}
29528c2ecf20Sopenharmony_ci
29538c2ecf20Sopenharmony_cistatic int sh_eth_vlan_rx_add_vid(struct net_device *ndev,
29548c2ecf20Sopenharmony_ci				  __be16 proto, u16 vid)
29558c2ecf20Sopenharmony_ci{
29568c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
29578c2ecf20Sopenharmony_ci	int vtag_reg_index = sh_eth_get_vtag_index(mdp);
29588c2ecf20Sopenharmony_ci
29598c2ecf20Sopenharmony_ci	if (unlikely(!mdp->cd->tsu))
29608c2ecf20Sopenharmony_ci		return -EPERM;
29618c2ecf20Sopenharmony_ci
29628c2ecf20Sopenharmony_ci	/* No filtering if vid = 0 */
29638c2ecf20Sopenharmony_ci	if (!vid)
29648c2ecf20Sopenharmony_ci		return 0;
29658c2ecf20Sopenharmony_ci
29668c2ecf20Sopenharmony_ci	mdp->vlan_num_ids++;
29678c2ecf20Sopenharmony_ci
29688c2ecf20Sopenharmony_ci	/* The controller has one VLAN tag HW filter. So, if the filter is
29698c2ecf20Sopenharmony_ci	 * already enabled, the driver disables it and the filte
29708c2ecf20Sopenharmony_ci	 */
29718c2ecf20Sopenharmony_ci	if (mdp->vlan_num_ids > 1) {
29728c2ecf20Sopenharmony_ci		/* disable VLAN filter */
29738c2ecf20Sopenharmony_ci		sh_eth_tsu_write(mdp, 0, vtag_reg_index);
29748c2ecf20Sopenharmony_ci		return 0;
29758c2ecf20Sopenharmony_ci	}
29768c2ecf20Sopenharmony_ci
29778c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, TSU_VTAG_ENABLE | (vid & TSU_VTAG_VID_MASK),
29788c2ecf20Sopenharmony_ci			 vtag_reg_index);
29798c2ecf20Sopenharmony_ci
29808c2ecf20Sopenharmony_ci	return 0;
29818c2ecf20Sopenharmony_ci}
29828c2ecf20Sopenharmony_ci
29838c2ecf20Sopenharmony_cistatic int sh_eth_vlan_rx_kill_vid(struct net_device *ndev,
29848c2ecf20Sopenharmony_ci				   __be16 proto, u16 vid)
29858c2ecf20Sopenharmony_ci{
29868c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
29878c2ecf20Sopenharmony_ci	int vtag_reg_index = sh_eth_get_vtag_index(mdp);
29888c2ecf20Sopenharmony_ci
29898c2ecf20Sopenharmony_ci	if (unlikely(!mdp->cd->tsu))
29908c2ecf20Sopenharmony_ci		return -EPERM;
29918c2ecf20Sopenharmony_ci
29928c2ecf20Sopenharmony_ci	/* No filtering if vid = 0 */
29938c2ecf20Sopenharmony_ci	if (!vid)
29948c2ecf20Sopenharmony_ci		return 0;
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_ci	mdp->vlan_num_ids--;
29978c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, vtag_reg_index);
29988c2ecf20Sopenharmony_ci
29998c2ecf20Sopenharmony_ci	return 0;
30008c2ecf20Sopenharmony_ci}
30018c2ecf20Sopenharmony_ci
30028c2ecf20Sopenharmony_ci/* SuperH's TSU register init function */
30038c2ecf20Sopenharmony_cistatic void sh_eth_tsu_init(struct sh_eth_private *mdp)
30048c2ecf20Sopenharmony_ci{
30058c2ecf20Sopenharmony_ci	if (!mdp->cd->dual_port) {
30068c2ecf20Sopenharmony_ci		sh_eth_tsu_write(mdp, 0, TSU_TEN); /* Disable all CAM entry */
30078c2ecf20Sopenharmony_ci		sh_eth_tsu_write(mdp, TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL,
30088c2ecf20Sopenharmony_ci				 TSU_FWSLC);	/* Enable POST registers */
30098c2ecf20Sopenharmony_ci		return;
30108c2ecf20Sopenharmony_ci	}
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FWEN0);	/* Disable forward(0->1) */
30138c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FWEN1);	/* Disable forward(1->0) */
30148c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FCM);	/* forward fifo 3k-3k */
30158c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0xc, TSU_BSYSL0);
30168c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0xc, TSU_BSYSL1);
30178c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_PRISL0);
30188c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_PRISL1);
30198c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FWSL0);
30208c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FWSL1);
30218c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, TSU_FWSLC);
30228c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_QTAGM0);	/* Disable QTAG(0->1) */
30238c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_QTAGM1);	/* Disable QTAG(1->0) */
30248c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FWSR);	/* all interrupt status clear */
30258c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FWINMK);	/* Disable all interrupt */
30268c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_TEN);	/* Disable all CAM entry */
30278c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_POST1);	/* Disable CAM entry [ 0- 7] */
30288c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_POST2);	/* Disable CAM entry [ 8-15] */
30298c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_POST3);	/* Disable CAM entry [16-23] */
30308c2ecf20Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_POST4);	/* Disable CAM entry [24-31] */
30318c2ecf20Sopenharmony_ci}
30328c2ecf20Sopenharmony_ci
30338c2ecf20Sopenharmony_ci/* MDIO bus release function */
30348c2ecf20Sopenharmony_cistatic int sh_mdio_release(struct sh_eth_private *mdp)
30358c2ecf20Sopenharmony_ci{
30368c2ecf20Sopenharmony_ci	/* unregister mdio bus */
30378c2ecf20Sopenharmony_ci	mdiobus_unregister(mdp->mii_bus);
30388c2ecf20Sopenharmony_ci
30398c2ecf20Sopenharmony_ci	/* free bitbang info */
30408c2ecf20Sopenharmony_ci	free_mdio_bitbang(mdp->mii_bus);
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci	return 0;
30438c2ecf20Sopenharmony_ci}
30448c2ecf20Sopenharmony_ci
30458c2ecf20Sopenharmony_ci/* MDIO bus init function */
30468c2ecf20Sopenharmony_cistatic int sh_mdio_init(struct sh_eth_private *mdp,
30478c2ecf20Sopenharmony_ci			struct sh_eth_plat_data *pd)
30488c2ecf20Sopenharmony_ci{
30498c2ecf20Sopenharmony_ci	int ret;
30508c2ecf20Sopenharmony_ci	struct bb_info *bitbang;
30518c2ecf20Sopenharmony_ci	struct platform_device *pdev = mdp->pdev;
30528c2ecf20Sopenharmony_ci	struct device *dev = &mdp->pdev->dev;
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_ci	/* create bit control struct for PHY */
30558c2ecf20Sopenharmony_ci	bitbang = devm_kzalloc(dev, sizeof(struct bb_info), GFP_KERNEL);
30568c2ecf20Sopenharmony_ci	if (!bitbang)
30578c2ecf20Sopenharmony_ci		return -ENOMEM;
30588c2ecf20Sopenharmony_ci
30598c2ecf20Sopenharmony_ci	/* bitbang init */
30608c2ecf20Sopenharmony_ci	bitbang->addr = mdp->addr + mdp->reg_offset[PIR];
30618c2ecf20Sopenharmony_ci	bitbang->set_gate = pd->set_mdio_gate;
30628c2ecf20Sopenharmony_ci	bitbang->ctrl.ops = &bb_ops;
30638c2ecf20Sopenharmony_ci
30648c2ecf20Sopenharmony_ci	/* MII controller setting */
30658c2ecf20Sopenharmony_ci	mdp->mii_bus = alloc_mdio_bitbang(&bitbang->ctrl);
30668c2ecf20Sopenharmony_ci	if (!mdp->mii_bus)
30678c2ecf20Sopenharmony_ci		return -ENOMEM;
30688c2ecf20Sopenharmony_ci
30698c2ecf20Sopenharmony_ci	/* Hook up MII support for ethtool */
30708c2ecf20Sopenharmony_ci	mdp->mii_bus->name = "sh_mii";
30718c2ecf20Sopenharmony_ci	mdp->mii_bus->parent = dev;
30728c2ecf20Sopenharmony_ci	snprintf(mdp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
30738c2ecf20Sopenharmony_ci		 pdev->name, pdev->id);
30748c2ecf20Sopenharmony_ci
30758c2ecf20Sopenharmony_ci	/* register MDIO bus */
30768c2ecf20Sopenharmony_ci	if (pd->phy_irq > 0)
30778c2ecf20Sopenharmony_ci		mdp->mii_bus->irq[pd->phy] = pd->phy_irq;
30788c2ecf20Sopenharmony_ci
30798c2ecf20Sopenharmony_ci	ret = of_mdiobus_register(mdp->mii_bus, dev->of_node);
30808c2ecf20Sopenharmony_ci	if (ret)
30818c2ecf20Sopenharmony_ci		goto out_free_bus;
30828c2ecf20Sopenharmony_ci
30838c2ecf20Sopenharmony_ci	return 0;
30848c2ecf20Sopenharmony_ci
30858c2ecf20Sopenharmony_ciout_free_bus:
30868c2ecf20Sopenharmony_ci	free_mdio_bitbang(mdp->mii_bus);
30878c2ecf20Sopenharmony_ci	return ret;
30888c2ecf20Sopenharmony_ci}
30898c2ecf20Sopenharmony_ci
30908c2ecf20Sopenharmony_cistatic const u16 *sh_eth_get_register_offset(int register_type)
30918c2ecf20Sopenharmony_ci{
30928c2ecf20Sopenharmony_ci	const u16 *reg_offset = NULL;
30938c2ecf20Sopenharmony_ci
30948c2ecf20Sopenharmony_ci	switch (register_type) {
30958c2ecf20Sopenharmony_ci	case SH_ETH_REG_GIGABIT:
30968c2ecf20Sopenharmony_ci		reg_offset = sh_eth_offset_gigabit;
30978c2ecf20Sopenharmony_ci		break;
30988c2ecf20Sopenharmony_ci	case SH_ETH_REG_FAST_RCAR:
30998c2ecf20Sopenharmony_ci		reg_offset = sh_eth_offset_fast_rcar;
31008c2ecf20Sopenharmony_ci		break;
31018c2ecf20Sopenharmony_ci	case SH_ETH_REG_FAST_SH4:
31028c2ecf20Sopenharmony_ci		reg_offset = sh_eth_offset_fast_sh4;
31038c2ecf20Sopenharmony_ci		break;
31048c2ecf20Sopenharmony_ci	case SH_ETH_REG_FAST_SH3_SH2:
31058c2ecf20Sopenharmony_ci		reg_offset = sh_eth_offset_fast_sh3_sh2;
31068c2ecf20Sopenharmony_ci		break;
31078c2ecf20Sopenharmony_ci	}
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_ci	return reg_offset;
31108c2ecf20Sopenharmony_ci}
31118c2ecf20Sopenharmony_ci
31128c2ecf20Sopenharmony_cistatic const struct net_device_ops sh_eth_netdev_ops = {
31138c2ecf20Sopenharmony_ci	.ndo_open		= sh_eth_open,
31148c2ecf20Sopenharmony_ci	.ndo_stop		= sh_eth_close,
31158c2ecf20Sopenharmony_ci	.ndo_start_xmit		= sh_eth_start_xmit,
31168c2ecf20Sopenharmony_ci	.ndo_get_stats		= sh_eth_get_stats,
31178c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	= sh_eth_set_rx_mode,
31188c2ecf20Sopenharmony_ci	.ndo_tx_timeout		= sh_eth_tx_timeout,
31198c2ecf20Sopenharmony_ci	.ndo_do_ioctl		= phy_do_ioctl_running,
31208c2ecf20Sopenharmony_ci	.ndo_change_mtu		= sh_eth_change_mtu,
31218c2ecf20Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
31228c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
31238c2ecf20Sopenharmony_ci	.ndo_set_features	= sh_eth_set_features,
31248c2ecf20Sopenharmony_ci};
31258c2ecf20Sopenharmony_ci
31268c2ecf20Sopenharmony_cistatic const struct net_device_ops sh_eth_netdev_ops_tsu = {
31278c2ecf20Sopenharmony_ci	.ndo_open		= sh_eth_open,
31288c2ecf20Sopenharmony_ci	.ndo_stop		= sh_eth_close,
31298c2ecf20Sopenharmony_ci	.ndo_start_xmit		= sh_eth_start_xmit,
31308c2ecf20Sopenharmony_ci	.ndo_get_stats		= sh_eth_get_stats,
31318c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	= sh_eth_set_rx_mode,
31328c2ecf20Sopenharmony_ci	.ndo_vlan_rx_add_vid	= sh_eth_vlan_rx_add_vid,
31338c2ecf20Sopenharmony_ci	.ndo_vlan_rx_kill_vid	= sh_eth_vlan_rx_kill_vid,
31348c2ecf20Sopenharmony_ci	.ndo_tx_timeout		= sh_eth_tx_timeout,
31358c2ecf20Sopenharmony_ci	.ndo_do_ioctl		= phy_do_ioctl_running,
31368c2ecf20Sopenharmony_ci	.ndo_change_mtu		= sh_eth_change_mtu,
31378c2ecf20Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
31388c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
31398c2ecf20Sopenharmony_ci	.ndo_set_features	= sh_eth_set_features,
31408c2ecf20Sopenharmony_ci};
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
31438c2ecf20Sopenharmony_cistatic struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev)
31448c2ecf20Sopenharmony_ci{
31458c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
31468c2ecf20Sopenharmony_ci	struct sh_eth_plat_data *pdata;
31478c2ecf20Sopenharmony_ci	phy_interface_t interface;
31488c2ecf20Sopenharmony_ci	const char *mac_addr;
31498c2ecf20Sopenharmony_ci	int ret;
31508c2ecf20Sopenharmony_ci
31518c2ecf20Sopenharmony_ci	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
31528c2ecf20Sopenharmony_ci	if (!pdata)
31538c2ecf20Sopenharmony_ci		return NULL;
31548c2ecf20Sopenharmony_ci
31558c2ecf20Sopenharmony_ci	ret = of_get_phy_mode(np, &interface);
31568c2ecf20Sopenharmony_ci	if (ret)
31578c2ecf20Sopenharmony_ci		return NULL;
31588c2ecf20Sopenharmony_ci	pdata->phy_interface = interface;
31598c2ecf20Sopenharmony_ci
31608c2ecf20Sopenharmony_ci	mac_addr = of_get_mac_address(np);
31618c2ecf20Sopenharmony_ci	if (!IS_ERR(mac_addr))
31628c2ecf20Sopenharmony_ci		ether_addr_copy(pdata->mac_addr, mac_addr);
31638c2ecf20Sopenharmony_ci
31648c2ecf20Sopenharmony_ci	pdata->no_ether_link =
31658c2ecf20Sopenharmony_ci		of_property_read_bool(np, "renesas,no-ether-link");
31668c2ecf20Sopenharmony_ci	pdata->ether_link_active_low =
31678c2ecf20Sopenharmony_ci		of_property_read_bool(np, "renesas,ether-link-active-low");
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_ci	return pdata;
31708c2ecf20Sopenharmony_ci}
31718c2ecf20Sopenharmony_ci
31728c2ecf20Sopenharmony_cistatic const struct of_device_id sh_eth_match_table[] = {
31738c2ecf20Sopenharmony_ci	{ .compatible = "renesas,gether-r8a7740", .data = &r8a7740_data },
31748c2ecf20Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7743", .data = &rcar_gen2_data },
31758c2ecf20Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7745", .data = &rcar_gen2_data },
31768c2ecf20Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7778", .data = &rcar_gen1_data },
31778c2ecf20Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7779", .data = &rcar_gen1_data },
31788c2ecf20Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7790", .data = &rcar_gen2_data },
31798c2ecf20Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7791", .data = &rcar_gen2_data },
31808c2ecf20Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7793", .data = &rcar_gen2_data },
31818c2ecf20Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7794", .data = &rcar_gen2_data },
31828c2ecf20Sopenharmony_ci	{ .compatible = "renesas,gether-r8a77980", .data = &r8a77980_data },
31838c2ecf20Sopenharmony_ci	{ .compatible = "renesas,ether-r7s72100", .data = &r7s72100_data },
31848c2ecf20Sopenharmony_ci	{ .compatible = "renesas,ether-r7s9210", .data = &r7s9210_data },
31858c2ecf20Sopenharmony_ci	{ .compatible = "renesas,rcar-gen1-ether", .data = &rcar_gen1_data },
31868c2ecf20Sopenharmony_ci	{ .compatible = "renesas,rcar-gen2-ether", .data = &rcar_gen2_data },
31878c2ecf20Sopenharmony_ci	{ }
31888c2ecf20Sopenharmony_ci};
31898c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sh_eth_match_table);
31908c2ecf20Sopenharmony_ci#else
31918c2ecf20Sopenharmony_cistatic inline struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev)
31928c2ecf20Sopenharmony_ci{
31938c2ecf20Sopenharmony_ci	return NULL;
31948c2ecf20Sopenharmony_ci}
31958c2ecf20Sopenharmony_ci#endif
31968c2ecf20Sopenharmony_ci
31978c2ecf20Sopenharmony_cistatic int sh_eth_drv_probe(struct platform_device *pdev)
31988c2ecf20Sopenharmony_ci{
31998c2ecf20Sopenharmony_ci	struct resource *res;
32008c2ecf20Sopenharmony_ci	struct sh_eth_plat_data *pd = dev_get_platdata(&pdev->dev);
32018c2ecf20Sopenharmony_ci	const struct platform_device_id *id = platform_get_device_id(pdev);
32028c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp;
32038c2ecf20Sopenharmony_ci	struct net_device *ndev;
32048c2ecf20Sopenharmony_ci	int ret;
32058c2ecf20Sopenharmony_ci
32068c2ecf20Sopenharmony_ci	/* get base addr */
32078c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
32088c2ecf20Sopenharmony_ci
32098c2ecf20Sopenharmony_ci	ndev = alloc_etherdev(sizeof(struct sh_eth_private));
32108c2ecf20Sopenharmony_ci	if (!ndev)
32118c2ecf20Sopenharmony_ci		return -ENOMEM;
32128c2ecf20Sopenharmony_ci
32138c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
32148c2ecf20Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
32158c2ecf20Sopenharmony_ci
32168c2ecf20Sopenharmony_ci	ret = platform_get_irq(pdev, 0);
32178c2ecf20Sopenharmony_ci	if (ret < 0)
32188c2ecf20Sopenharmony_ci		goto out_release;
32198c2ecf20Sopenharmony_ci	ndev->irq = ret;
32208c2ecf20Sopenharmony_ci
32218c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(ndev, &pdev->dev);
32228c2ecf20Sopenharmony_ci
32238c2ecf20Sopenharmony_ci	mdp = netdev_priv(ndev);
32248c2ecf20Sopenharmony_ci	mdp->num_tx_ring = TX_RING_SIZE;
32258c2ecf20Sopenharmony_ci	mdp->num_rx_ring = RX_RING_SIZE;
32268c2ecf20Sopenharmony_ci	mdp->addr = devm_ioremap_resource(&pdev->dev, res);
32278c2ecf20Sopenharmony_ci	if (IS_ERR(mdp->addr)) {
32288c2ecf20Sopenharmony_ci		ret = PTR_ERR(mdp->addr);
32298c2ecf20Sopenharmony_ci		goto out_release;
32308c2ecf20Sopenharmony_ci	}
32318c2ecf20Sopenharmony_ci
32328c2ecf20Sopenharmony_ci	ndev->base_addr = res->start;
32338c2ecf20Sopenharmony_ci
32348c2ecf20Sopenharmony_ci	spin_lock_init(&mdp->lock);
32358c2ecf20Sopenharmony_ci	mdp->pdev = pdev;
32368c2ecf20Sopenharmony_ci
32378c2ecf20Sopenharmony_ci	if (pdev->dev.of_node)
32388c2ecf20Sopenharmony_ci		pd = sh_eth_parse_dt(&pdev->dev);
32398c2ecf20Sopenharmony_ci	if (!pd) {
32408c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "no platform data\n");
32418c2ecf20Sopenharmony_ci		ret = -EINVAL;
32428c2ecf20Sopenharmony_ci		goto out_release;
32438c2ecf20Sopenharmony_ci	}
32448c2ecf20Sopenharmony_ci
32458c2ecf20Sopenharmony_ci	/* get PHY ID */
32468c2ecf20Sopenharmony_ci	mdp->phy_id = pd->phy;
32478c2ecf20Sopenharmony_ci	mdp->phy_interface = pd->phy_interface;
32488c2ecf20Sopenharmony_ci	mdp->no_ether_link = pd->no_ether_link;
32498c2ecf20Sopenharmony_ci	mdp->ether_link_active_low = pd->ether_link_active_low;
32508c2ecf20Sopenharmony_ci
32518c2ecf20Sopenharmony_ci	/* set cpu data */
32528c2ecf20Sopenharmony_ci	if (id)
32538c2ecf20Sopenharmony_ci		mdp->cd = (struct sh_eth_cpu_data *)id->driver_data;
32548c2ecf20Sopenharmony_ci	else
32558c2ecf20Sopenharmony_ci		mdp->cd = (struct sh_eth_cpu_data *)of_device_get_match_data(&pdev->dev);
32568c2ecf20Sopenharmony_ci
32578c2ecf20Sopenharmony_ci	mdp->reg_offset = sh_eth_get_register_offset(mdp->cd->register_type);
32588c2ecf20Sopenharmony_ci	if (!mdp->reg_offset) {
32598c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Unknown register type (%d)\n",
32608c2ecf20Sopenharmony_ci			mdp->cd->register_type);
32618c2ecf20Sopenharmony_ci		ret = -EINVAL;
32628c2ecf20Sopenharmony_ci		goto out_release;
32638c2ecf20Sopenharmony_ci	}
32648c2ecf20Sopenharmony_ci	sh_eth_set_default_cpu_data(mdp->cd);
32658c2ecf20Sopenharmony_ci
32668c2ecf20Sopenharmony_ci	/* User's manual states max MTU should be 2048 but due to the
32678c2ecf20Sopenharmony_ci	 * alignment calculations in sh_eth_ring_init() the practical
32688c2ecf20Sopenharmony_ci	 * MTU is a bit less. Maybe this can be optimized some more.
32698c2ecf20Sopenharmony_ci	 */
32708c2ecf20Sopenharmony_ci	ndev->max_mtu = 2000 - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
32718c2ecf20Sopenharmony_ci	ndev->min_mtu = ETH_MIN_MTU;
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci	if (mdp->cd->rx_csum) {
32748c2ecf20Sopenharmony_ci		ndev->features = NETIF_F_RXCSUM;
32758c2ecf20Sopenharmony_ci		ndev->hw_features = NETIF_F_RXCSUM;
32768c2ecf20Sopenharmony_ci	}
32778c2ecf20Sopenharmony_ci
32788c2ecf20Sopenharmony_ci	/* set function */
32798c2ecf20Sopenharmony_ci	if (mdp->cd->tsu)
32808c2ecf20Sopenharmony_ci		ndev->netdev_ops = &sh_eth_netdev_ops_tsu;
32818c2ecf20Sopenharmony_ci	else
32828c2ecf20Sopenharmony_ci		ndev->netdev_ops = &sh_eth_netdev_ops;
32838c2ecf20Sopenharmony_ci	ndev->ethtool_ops = &sh_eth_ethtool_ops;
32848c2ecf20Sopenharmony_ci	ndev->watchdog_timeo = TX_TIMEOUT;
32858c2ecf20Sopenharmony_ci
32868c2ecf20Sopenharmony_ci	/* debug message level */
32878c2ecf20Sopenharmony_ci	mdp->msg_enable = SH_ETH_DEF_MSG_ENABLE;
32888c2ecf20Sopenharmony_ci
32898c2ecf20Sopenharmony_ci	/* read and set MAC address */
32908c2ecf20Sopenharmony_ci	read_mac_address(ndev, pd->mac_addr);
32918c2ecf20Sopenharmony_ci	if (!is_valid_ether_addr(ndev->dev_addr)) {
32928c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev,
32938c2ecf20Sopenharmony_ci			 "no valid MAC address supplied, using a random one.\n");
32948c2ecf20Sopenharmony_ci		eth_hw_addr_random(ndev);
32958c2ecf20Sopenharmony_ci	}
32968c2ecf20Sopenharmony_ci
32978c2ecf20Sopenharmony_ci	if (mdp->cd->tsu) {
32988c2ecf20Sopenharmony_ci		int port = pdev->id < 0 ? 0 : pdev->id % 2;
32998c2ecf20Sopenharmony_ci		struct resource *rtsu;
33008c2ecf20Sopenharmony_ci
33018c2ecf20Sopenharmony_ci		rtsu = platform_get_resource(pdev, IORESOURCE_MEM, 1);
33028c2ecf20Sopenharmony_ci		if (!rtsu) {
33038c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "no TSU resource\n");
33048c2ecf20Sopenharmony_ci			ret = -ENODEV;
33058c2ecf20Sopenharmony_ci			goto out_release;
33068c2ecf20Sopenharmony_ci		}
33078c2ecf20Sopenharmony_ci		/* We can only request the  TSU region  for the first port
33088c2ecf20Sopenharmony_ci		 * of the two  sharing this TSU for the probe to succeed...
33098c2ecf20Sopenharmony_ci		 */
33108c2ecf20Sopenharmony_ci		if (port == 0 &&
33118c2ecf20Sopenharmony_ci		    !devm_request_mem_region(&pdev->dev, rtsu->start,
33128c2ecf20Sopenharmony_ci					     resource_size(rtsu),
33138c2ecf20Sopenharmony_ci					     dev_name(&pdev->dev))) {
33148c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "can't request TSU resource.\n");
33158c2ecf20Sopenharmony_ci			ret = -EBUSY;
33168c2ecf20Sopenharmony_ci			goto out_release;
33178c2ecf20Sopenharmony_ci		}
33188c2ecf20Sopenharmony_ci		/* ioremap the TSU registers */
33198c2ecf20Sopenharmony_ci		mdp->tsu_addr = devm_ioremap(&pdev->dev, rtsu->start,
33208c2ecf20Sopenharmony_ci					     resource_size(rtsu));
33218c2ecf20Sopenharmony_ci		if (!mdp->tsu_addr) {
33228c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "TSU region ioremap() failed.\n");
33238c2ecf20Sopenharmony_ci			ret = -ENOMEM;
33248c2ecf20Sopenharmony_ci			goto out_release;
33258c2ecf20Sopenharmony_ci		}
33268c2ecf20Sopenharmony_ci		mdp->port = port;
33278c2ecf20Sopenharmony_ci		ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
33288c2ecf20Sopenharmony_ci
33298c2ecf20Sopenharmony_ci		/* Need to init only the first port of the two sharing a TSU */
33308c2ecf20Sopenharmony_ci		if (port == 0) {
33318c2ecf20Sopenharmony_ci			if (mdp->cd->chip_reset)
33328c2ecf20Sopenharmony_ci				mdp->cd->chip_reset(ndev);
33338c2ecf20Sopenharmony_ci
33348c2ecf20Sopenharmony_ci			/* TSU init (Init only)*/
33358c2ecf20Sopenharmony_ci			sh_eth_tsu_init(mdp);
33368c2ecf20Sopenharmony_ci		}
33378c2ecf20Sopenharmony_ci	}
33388c2ecf20Sopenharmony_ci
33398c2ecf20Sopenharmony_ci	if (mdp->cd->rmiimode)
33408c2ecf20Sopenharmony_ci		sh_eth_write(ndev, 0x1, RMIIMODE);
33418c2ecf20Sopenharmony_ci
33428c2ecf20Sopenharmony_ci	/* MDIO bus init */
33438c2ecf20Sopenharmony_ci	ret = sh_mdio_init(mdp, pd);
33448c2ecf20Sopenharmony_ci	if (ret) {
33458c2ecf20Sopenharmony_ci		if (ret != -EPROBE_DEFER)
33468c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "MDIO init failed: %d\n", ret);
33478c2ecf20Sopenharmony_ci		goto out_release;
33488c2ecf20Sopenharmony_ci	}
33498c2ecf20Sopenharmony_ci
33508c2ecf20Sopenharmony_ci	netif_napi_add(ndev, &mdp->napi, sh_eth_poll, 64);
33518c2ecf20Sopenharmony_ci
33528c2ecf20Sopenharmony_ci	/* network device register */
33538c2ecf20Sopenharmony_ci	ret = register_netdev(ndev);
33548c2ecf20Sopenharmony_ci	if (ret)
33558c2ecf20Sopenharmony_ci		goto out_napi_del;
33568c2ecf20Sopenharmony_ci
33578c2ecf20Sopenharmony_ci	if (mdp->cd->magic)
33588c2ecf20Sopenharmony_ci		device_set_wakeup_capable(&pdev->dev, 1);
33598c2ecf20Sopenharmony_ci
33608c2ecf20Sopenharmony_ci	/* print device information */
33618c2ecf20Sopenharmony_ci	netdev_info(ndev, "Base address at 0x%x, %pM, IRQ %d.\n",
33628c2ecf20Sopenharmony_ci		    (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
33638c2ecf20Sopenharmony_ci
33648c2ecf20Sopenharmony_ci	pm_runtime_put(&pdev->dev);
33658c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, ndev);
33668c2ecf20Sopenharmony_ci
33678c2ecf20Sopenharmony_ci	return ret;
33688c2ecf20Sopenharmony_ci
33698c2ecf20Sopenharmony_ciout_napi_del:
33708c2ecf20Sopenharmony_ci	netif_napi_del(&mdp->napi);
33718c2ecf20Sopenharmony_ci	sh_mdio_release(mdp);
33728c2ecf20Sopenharmony_ci
33738c2ecf20Sopenharmony_ciout_release:
33748c2ecf20Sopenharmony_ci	/* net_dev free */
33758c2ecf20Sopenharmony_ci	free_netdev(ndev);
33768c2ecf20Sopenharmony_ci
33778c2ecf20Sopenharmony_ci	pm_runtime_put(&pdev->dev);
33788c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
33798c2ecf20Sopenharmony_ci	return ret;
33808c2ecf20Sopenharmony_ci}
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_cistatic int sh_eth_drv_remove(struct platform_device *pdev)
33838c2ecf20Sopenharmony_ci{
33848c2ecf20Sopenharmony_ci	struct net_device *ndev = platform_get_drvdata(pdev);
33858c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
33868c2ecf20Sopenharmony_ci
33878c2ecf20Sopenharmony_ci	unregister_netdev(ndev);
33888c2ecf20Sopenharmony_ci	netif_napi_del(&mdp->napi);
33898c2ecf20Sopenharmony_ci	sh_mdio_release(mdp);
33908c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
33918c2ecf20Sopenharmony_ci	free_netdev(ndev);
33928c2ecf20Sopenharmony_ci
33938c2ecf20Sopenharmony_ci	return 0;
33948c2ecf20Sopenharmony_ci}
33958c2ecf20Sopenharmony_ci
33968c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
33978c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
33988c2ecf20Sopenharmony_cistatic int sh_eth_wol_setup(struct net_device *ndev)
33998c2ecf20Sopenharmony_ci{
34008c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
34018c2ecf20Sopenharmony_ci
34028c2ecf20Sopenharmony_ci	/* Only allow ECI interrupts */
34038c2ecf20Sopenharmony_ci	synchronize_irq(ndev->irq);
34048c2ecf20Sopenharmony_ci	napi_disable(&mdp->napi);
34058c2ecf20Sopenharmony_ci	sh_eth_write(ndev, EESIPR_ECIIP, EESIPR);
34068c2ecf20Sopenharmony_ci
34078c2ecf20Sopenharmony_ci	/* Enable MagicPacket */
34088c2ecf20Sopenharmony_ci	sh_eth_modify(ndev, ECMR, ECMR_MPDE, ECMR_MPDE);
34098c2ecf20Sopenharmony_ci
34108c2ecf20Sopenharmony_ci	return enable_irq_wake(ndev->irq);
34118c2ecf20Sopenharmony_ci}
34128c2ecf20Sopenharmony_ci
34138c2ecf20Sopenharmony_cistatic int sh_eth_wol_restore(struct net_device *ndev)
34148c2ecf20Sopenharmony_ci{
34158c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
34168c2ecf20Sopenharmony_ci	int ret;
34178c2ecf20Sopenharmony_ci
34188c2ecf20Sopenharmony_ci	napi_enable(&mdp->napi);
34198c2ecf20Sopenharmony_ci
34208c2ecf20Sopenharmony_ci	/* Disable MagicPacket */
34218c2ecf20Sopenharmony_ci	sh_eth_modify(ndev, ECMR, ECMR_MPDE, 0);
34228c2ecf20Sopenharmony_ci
34238c2ecf20Sopenharmony_ci	/* The device needs to be reset to restore MagicPacket logic
34248c2ecf20Sopenharmony_ci	 * for next wakeup. If we close and open the device it will
34258c2ecf20Sopenharmony_ci	 * both be reset and all registers restored. This is what
34268c2ecf20Sopenharmony_ci	 * happens during suspend and resume without WoL enabled.
34278c2ecf20Sopenharmony_ci	 */
34288c2ecf20Sopenharmony_ci	ret = sh_eth_close(ndev);
34298c2ecf20Sopenharmony_ci	if (ret < 0)
34308c2ecf20Sopenharmony_ci		return ret;
34318c2ecf20Sopenharmony_ci	ret = sh_eth_open(ndev);
34328c2ecf20Sopenharmony_ci	if (ret < 0)
34338c2ecf20Sopenharmony_ci		return ret;
34348c2ecf20Sopenharmony_ci
34358c2ecf20Sopenharmony_ci	return disable_irq_wake(ndev->irq);
34368c2ecf20Sopenharmony_ci}
34378c2ecf20Sopenharmony_ci
34388c2ecf20Sopenharmony_cistatic int sh_eth_suspend(struct device *dev)
34398c2ecf20Sopenharmony_ci{
34408c2ecf20Sopenharmony_ci	struct net_device *ndev = dev_get_drvdata(dev);
34418c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
34428c2ecf20Sopenharmony_ci	int ret = 0;
34438c2ecf20Sopenharmony_ci
34448c2ecf20Sopenharmony_ci	if (!netif_running(ndev))
34458c2ecf20Sopenharmony_ci		return 0;
34468c2ecf20Sopenharmony_ci
34478c2ecf20Sopenharmony_ci	netif_device_detach(ndev);
34488c2ecf20Sopenharmony_ci
34498c2ecf20Sopenharmony_ci	if (mdp->wol_enabled)
34508c2ecf20Sopenharmony_ci		ret = sh_eth_wol_setup(ndev);
34518c2ecf20Sopenharmony_ci	else
34528c2ecf20Sopenharmony_ci		ret = sh_eth_close(ndev);
34538c2ecf20Sopenharmony_ci
34548c2ecf20Sopenharmony_ci	return ret;
34558c2ecf20Sopenharmony_ci}
34568c2ecf20Sopenharmony_ci
34578c2ecf20Sopenharmony_cistatic int sh_eth_resume(struct device *dev)
34588c2ecf20Sopenharmony_ci{
34598c2ecf20Sopenharmony_ci	struct net_device *ndev = dev_get_drvdata(dev);
34608c2ecf20Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
34618c2ecf20Sopenharmony_ci	int ret = 0;
34628c2ecf20Sopenharmony_ci
34638c2ecf20Sopenharmony_ci	if (!netif_running(ndev))
34648c2ecf20Sopenharmony_ci		return 0;
34658c2ecf20Sopenharmony_ci
34668c2ecf20Sopenharmony_ci	if (mdp->wol_enabled)
34678c2ecf20Sopenharmony_ci		ret = sh_eth_wol_restore(ndev);
34688c2ecf20Sopenharmony_ci	else
34698c2ecf20Sopenharmony_ci		ret = sh_eth_open(ndev);
34708c2ecf20Sopenharmony_ci
34718c2ecf20Sopenharmony_ci	if (ret < 0)
34728c2ecf20Sopenharmony_ci		return ret;
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci	netif_device_attach(ndev);
34758c2ecf20Sopenharmony_ci
34768c2ecf20Sopenharmony_ci	return ret;
34778c2ecf20Sopenharmony_ci}
34788c2ecf20Sopenharmony_ci#endif
34798c2ecf20Sopenharmony_ci
34808c2ecf20Sopenharmony_cistatic int sh_eth_runtime_nop(struct device *dev)
34818c2ecf20Sopenharmony_ci{
34828c2ecf20Sopenharmony_ci	/* Runtime PM callback shared between ->runtime_suspend()
34838c2ecf20Sopenharmony_ci	 * and ->runtime_resume(). Simply returns success.
34848c2ecf20Sopenharmony_ci	 *
34858c2ecf20Sopenharmony_ci	 * This driver re-initializes all registers after
34868c2ecf20Sopenharmony_ci	 * pm_runtime_get_sync() anyway so there is no need
34878c2ecf20Sopenharmony_ci	 * to save and restore registers here.
34888c2ecf20Sopenharmony_ci	 */
34898c2ecf20Sopenharmony_ci	return 0;
34908c2ecf20Sopenharmony_ci}
34918c2ecf20Sopenharmony_ci
34928c2ecf20Sopenharmony_cistatic const struct dev_pm_ops sh_eth_dev_pm_ops = {
34938c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(sh_eth_suspend, sh_eth_resume)
34948c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(sh_eth_runtime_nop, sh_eth_runtime_nop, NULL)
34958c2ecf20Sopenharmony_ci};
34968c2ecf20Sopenharmony_ci#define SH_ETH_PM_OPS (&sh_eth_dev_pm_ops)
34978c2ecf20Sopenharmony_ci#else
34988c2ecf20Sopenharmony_ci#define SH_ETH_PM_OPS NULL
34998c2ecf20Sopenharmony_ci#endif
35008c2ecf20Sopenharmony_ci
35018c2ecf20Sopenharmony_cistatic const struct platform_device_id sh_eth_id_table[] = {
35028c2ecf20Sopenharmony_ci	{ "sh7619-ether", (kernel_ulong_t)&sh7619_data },
35038c2ecf20Sopenharmony_ci	{ "sh771x-ether", (kernel_ulong_t)&sh771x_data },
35048c2ecf20Sopenharmony_ci	{ "sh7724-ether", (kernel_ulong_t)&sh7724_data },
35058c2ecf20Sopenharmony_ci	{ "sh7734-gether", (kernel_ulong_t)&sh7734_data },
35068c2ecf20Sopenharmony_ci	{ "sh7757-ether", (kernel_ulong_t)&sh7757_data },
35078c2ecf20Sopenharmony_ci	{ "sh7757-gether", (kernel_ulong_t)&sh7757_data_giga },
35088c2ecf20Sopenharmony_ci	{ "sh7763-gether", (kernel_ulong_t)&sh7763_data },
35098c2ecf20Sopenharmony_ci	{ }
35108c2ecf20Sopenharmony_ci};
35118c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, sh_eth_id_table);
35128c2ecf20Sopenharmony_ci
35138c2ecf20Sopenharmony_cistatic struct platform_driver sh_eth_driver = {
35148c2ecf20Sopenharmony_ci	.probe = sh_eth_drv_probe,
35158c2ecf20Sopenharmony_ci	.remove = sh_eth_drv_remove,
35168c2ecf20Sopenharmony_ci	.id_table = sh_eth_id_table,
35178c2ecf20Sopenharmony_ci	.driver = {
35188c2ecf20Sopenharmony_ci		   .name = CARDNAME,
35198c2ecf20Sopenharmony_ci		   .pm = SH_ETH_PM_OPS,
35208c2ecf20Sopenharmony_ci		   .of_match_table = of_match_ptr(sh_eth_match_table),
35218c2ecf20Sopenharmony_ci	},
35228c2ecf20Sopenharmony_ci};
35238c2ecf20Sopenharmony_ci
35248c2ecf20Sopenharmony_cimodule_platform_driver(sh_eth_driver);
35258c2ecf20Sopenharmony_ci
35268c2ecf20Sopenharmony_ciMODULE_AUTHOR("Nobuhiro Iwamatsu, Yoshihiro Shimoda");
35278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Renesas SuperH Ethernet driver");
35288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
3529