// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2010 ASIX Electronics Corporation
* Copyright (c) 2020 Samsung Electronics Co., Ltd.
*
* ASIX AX88796C SPI Fast Ethernet Linux driver
*/
#define pr_fmt(fmt) "ax88796c: " fmt
#include "ax88796c_main.h"
#include "ax88796c_ioctl.h"
#include <linux/bitmap.h>
#include <linux/etherdevice.h>
#include <linux/iopoll.h>
#include <linux/lockdep.h>
#include <linux/mdio.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/skbuff.h>
#include <linux/spi/spi.h>
static int comp = IS_ENABLED(CONFIG_SPI_AX88796C_COMPRESSION);
static int msg_enable = NETIF_MSG_PROBE |
NETIF_MSG_LINK |
NETIF_MSG_RX_ERR |
NETIF_MSG_TX_ERR;
static const char *no_regs_list = "80018001,e1918001,8001a001,fc0d0000";
unsigned long ax88796c_no_regs_mask[AX88796C_REGDUMP_LEN / (sizeof(unsigned long) * 8)];
module_param(msg_enable, int, 0444);
MODULE_PARM_DESC(msg_enable, "Message mask (see linux/netdevice.h for bitmap)");
static int ax88796c_soft_reset(struct ax88796c_device *ax_local)
{
u16 temp;
int ret;
lockdep_assert_held(&ax_local->spi_lock);
AX_WRITE(&ax_local->ax_spi, PSR_RESET, P0_PSR);
AX_WRITE(&ax_local->ax_spi, PSR_RESET_CLR, P0_PSR);
ret = read_poll_timeout(AX_READ, ret,
(ret & PSR_DEV_READY),
0, jiffies_to_usecs(160 * HZ / 1000), false,
&ax_local->ax_spi, P0_PSR);
if (ret)
return ret;
temp = AX_READ(&ax_local->ax_spi, P4_SPICR);
if (ax_local->priv_flags & AX_CAP_COMP) {
AX_WRITE(&ax_local->ax_spi,
(temp | SPICR_RCEN | SPICR_QCEN), P4_SPICR);
ax_local->ax_spi.comp = 1;
} else {
AX_WRITE(&ax_local->ax_spi,
(temp & ~(SPICR_RCEN | SPICR_QCEN)), P4_SPICR);
ax_local->ax_spi.comp = 0;
}
return 0;
}
static int ax88796c_reload_eeprom(struct ax88796c_device *ax_local)
{
int ret;
lockdep_assert_held(&ax_local->spi_lock);
AX_WRITE(&ax_local->ax_spi, EECR_RELOAD, P3_EECR);
ret = read_poll_timeout(AX_READ, ret,
(ret & PSR_DEV_READY),
0, jiffies_to_usecs(2 * HZ / 1000), false,
&ax_local->ax_spi, P0_PSR);
if (ret) {
dev_err(&ax_local->spi->dev,
"timeout waiting for reload eeprom\n");
return ret;
}
return 0;
}
static void ax88796c_set_hw_multicast(struct net_device *ndev)
{
struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
int mc_count = netdev_mc_count(ndev);
u16 rx_ctl = RXCR_AB;
lockdep_assert_held(&ax_local->spi_lock);
memset(ax_local->multi_filter, 0, AX_MCAST_FILTER_SIZE);
if (ndev->flags & IFF_PROMISC) {
rx_ctl |= RXCR_PRO;
} else if (ndev->flags & IFF_ALLMULTI || mc_count > AX_MAX_MCAST) {
rx_ctl |= RXCR_AMALL;
} else if (mc_count == 0) {
/* just broadcast and directed */
} else {
u32 crc_bits;
int i;
struct netdev_hw_addr *ha;
netdev_for_each_mc_addr(ha, ndev) {
crc_bits = ether_crc(ETH_ALEN, ha->addr);
ax_local->multi_filter[crc_bits >> 29] |=
(1 << ((crc_bits >> 26) & 7));
}
for (i = 0; i < 4; i++) {
AX_WRITE(&ax_local->ax_spi,
((ax_local->multi_filter[i * 2 + 1] << 8) |
ax_local->multi_filter[i * 2]), P3_MFAR(i));
}
}
AX_WRITE(&ax_local->ax_spi, rx_ctl, P2_RXCR);
}
static void ax88796c_set_mac_addr(struct net_device<