117364b80SDmitry Bezrukov // SPDX-License-Identifier: GPL-2.0-or-later 217364b80SDmitry Bezrukov /* Aquantia Corp. Aquantia AQtion USB to 5GbE Controller 317364b80SDmitry Bezrukov * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> 417364b80SDmitry Bezrukov * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> 517364b80SDmitry Bezrukov * Copyright (C) 2002-2003 TiVo Inc. 617364b80SDmitry Bezrukov * Copyright (C) 2017-2018 ASIX 717364b80SDmitry Bezrukov * Copyright (C) 2018 Aquantia Corp. 817364b80SDmitry Bezrukov */ 917364b80SDmitry Bezrukov 1017364b80SDmitry Bezrukov #include <linux/module.h> 1117364b80SDmitry Bezrukov #include <linux/netdevice.h> 1217364b80SDmitry Bezrukov #include <linux/mii.h> 1317364b80SDmitry Bezrukov #include <linux/usb.h> 1417364b80SDmitry Bezrukov #include <linux/usb/cdc.h> 1517364b80SDmitry Bezrukov #include <linux/usb/usbnet.h> 1617364b80SDmitry Bezrukov 17619fcb44SDmitry Bezrukov #include "aqc111.h" 18619fcb44SDmitry Bezrukov 19619fcb44SDmitry Bezrukov static int aqc111_read_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 20619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 21619fcb44SDmitry Bezrukov { 22619fcb44SDmitry Bezrukov int ret; 23619fcb44SDmitry Bezrukov 24619fcb44SDmitry Bezrukov ret = usbnet_read_cmd_nopm(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | 25619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, data, size); 26619fcb44SDmitry Bezrukov 27619fcb44SDmitry Bezrukov if (unlikely(ret < 0)) 28619fcb44SDmitry Bezrukov netdev_warn(dev->net, 29619fcb44SDmitry Bezrukov "Failed to read(0x%x) reg index 0x%04x: %d\n", 30619fcb44SDmitry Bezrukov cmd, index, ret); 31619fcb44SDmitry Bezrukov 32619fcb44SDmitry Bezrukov return ret; 33619fcb44SDmitry Bezrukov } 34619fcb44SDmitry Bezrukov 35619fcb44SDmitry Bezrukov static int aqc111_read_cmd(struct usbnet *dev, u8 cmd, u16 value, 36619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 37619fcb44SDmitry Bezrukov { 38619fcb44SDmitry Bezrukov int ret; 39619fcb44SDmitry Bezrukov 40619fcb44SDmitry Bezrukov ret = usbnet_read_cmd(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | 41619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, data, size); 42619fcb44SDmitry Bezrukov 43619fcb44SDmitry Bezrukov if (unlikely(ret < 0)) 44619fcb44SDmitry Bezrukov netdev_warn(dev->net, 45619fcb44SDmitry Bezrukov "Failed to read(0x%x) reg index 0x%04x: %d\n", 46619fcb44SDmitry Bezrukov cmd, index, ret); 47619fcb44SDmitry Bezrukov 48619fcb44SDmitry Bezrukov return ret; 49619fcb44SDmitry Bezrukov } 50619fcb44SDmitry Bezrukov 51f3aa095aSDmitry Bezrukov static int aqc111_read16_cmd(struct usbnet *dev, u8 cmd, u16 value, 52f3aa095aSDmitry Bezrukov u16 index, u16 *data) 53f3aa095aSDmitry Bezrukov { 54f3aa095aSDmitry Bezrukov int ret = 0; 55f3aa095aSDmitry Bezrukov 56f3aa095aSDmitry Bezrukov ret = aqc111_read_cmd(dev, cmd, value, index, sizeof(*data), data); 57f3aa095aSDmitry Bezrukov le16_to_cpus(data); 58f3aa095aSDmitry Bezrukov 59f3aa095aSDmitry Bezrukov return ret; 60f3aa095aSDmitry Bezrukov } 61f3aa095aSDmitry Bezrukov 62619fcb44SDmitry Bezrukov static int __aqc111_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, 63619fcb44SDmitry Bezrukov u16 value, u16 index, u16 size, const void *data) 64619fcb44SDmitry Bezrukov { 65619fcb44SDmitry Bezrukov int err = -ENOMEM; 66619fcb44SDmitry Bezrukov void *buf = NULL; 67619fcb44SDmitry Bezrukov 68619fcb44SDmitry Bezrukov netdev_dbg(dev->net, 69619fcb44SDmitry Bezrukov "%s cmd=%#x reqtype=%#x value=%#x index=%#x size=%d\n", 70619fcb44SDmitry Bezrukov __func__, cmd, reqtype, value, index, size); 71619fcb44SDmitry Bezrukov 72619fcb44SDmitry Bezrukov if (data) { 73619fcb44SDmitry Bezrukov buf = kmemdup(data, size, GFP_KERNEL); 74619fcb44SDmitry Bezrukov if (!buf) 75619fcb44SDmitry Bezrukov goto out; 76619fcb44SDmitry Bezrukov } 77619fcb44SDmitry Bezrukov 78619fcb44SDmitry Bezrukov err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), 79619fcb44SDmitry Bezrukov cmd, reqtype, value, index, buf, size, 80619fcb44SDmitry Bezrukov (cmd == AQ_PHY_POWER) ? AQ_USB_PHY_SET_TIMEOUT : 81619fcb44SDmitry Bezrukov AQ_USB_SET_TIMEOUT); 82619fcb44SDmitry Bezrukov 83619fcb44SDmitry Bezrukov if (unlikely(err < 0)) 84619fcb44SDmitry Bezrukov netdev_warn(dev->net, 85619fcb44SDmitry Bezrukov "Failed to write(0x%x) reg index 0x%04x: %d\n", 86619fcb44SDmitry Bezrukov cmd, index, err); 87619fcb44SDmitry Bezrukov kfree(buf); 88619fcb44SDmitry Bezrukov 89619fcb44SDmitry Bezrukov out: 90619fcb44SDmitry Bezrukov return err; 91619fcb44SDmitry Bezrukov } 92619fcb44SDmitry Bezrukov 93619fcb44SDmitry Bezrukov static int aqc111_write_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 94619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 95619fcb44SDmitry Bezrukov { 96619fcb44SDmitry Bezrukov int ret; 97619fcb44SDmitry Bezrukov 98619fcb44SDmitry Bezrukov ret = __aqc111_write_cmd(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | 99619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, size, data); 100619fcb44SDmitry Bezrukov 101619fcb44SDmitry Bezrukov return ret; 102619fcb44SDmitry Bezrukov } 103619fcb44SDmitry Bezrukov 104619fcb44SDmitry Bezrukov static int aqc111_write_cmd(struct usbnet *dev, u8 cmd, u16 value, 105619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 106619fcb44SDmitry Bezrukov { 107619fcb44SDmitry Bezrukov int ret; 108619fcb44SDmitry Bezrukov 109619fcb44SDmitry Bezrukov if (usb_autopm_get_interface(dev->intf) < 0) 110619fcb44SDmitry Bezrukov return -ENODEV; 111619fcb44SDmitry Bezrukov 112619fcb44SDmitry Bezrukov ret = __aqc111_write_cmd(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | 113619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, size, data); 114619fcb44SDmitry Bezrukov 115619fcb44SDmitry Bezrukov usb_autopm_put_interface(dev->intf); 116619fcb44SDmitry Bezrukov 117619fcb44SDmitry Bezrukov return ret; 118619fcb44SDmitry Bezrukov } 119619fcb44SDmitry Bezrukov 120f3aa095aSDmitry Bezrukov static int aqc111_write16_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 121f3aa095aSDmitry Bezrukov u16 index, u16 *data) 122f3aa095aSDmitry Bezrukov { 123f3aa095aSDmitry Bezrukov u16 tmp = *data; 124f3aa095aSDmitry Bezrukov 125f3aa095aSDmitry Bezrukov cpu_to_le16s(&tmp); 126f3aa095aSDmitry Bezrukov 127f3aa095aSDmitry Bezrukov return aqc111_write_cmd_nopm(dev, cmd, value, index, sizeof(tmp), &tmp); 128f3aa095aSDmitry Bezrukov } 129f3aa095aSDmitry Bezrukov 130f3aa095aSDmitry Bezrukov static int aqc111_write16_cmd(struct usbnet *dev, u8 cmd, u16 value, 131f3aa095aSDmitry Bezrukov u16 index, u16 *data) 132f3aa095aSDmitry Bezrukov { 133f3aa095aSDmitry Bezrukov u16 tmp = *data; 134f3aa095aSDmitry Bezrukov 135f3aa095aSDmitry Bezrukov cpu_to_le16s(&tmp); 136f3aa095aSDmitry Bezrukov 137f3aa095aSDmitry Bezrukov return aqc111_write_cmd(dev, cmd, value, index, sizeof(tmp), &tmp); 138f3aa095aSDmitry Bezrukov } 139f3aa095aSDmitry Bezrukov 14033cd597fSDmitry Bezrukov static int aqc111_write32_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 14133cd597fSDmitry Bezrukov u16 index, u32 *data) 14233cd597fSDmitry Bezrukov { 14333cd597fSDmitry Bezrukov u32 tmp = *data; 14433cd597fSDmitry Bezrukov 14533cd597fSDmitry Bezrukov cpu_to_le32s(&tmp); 14633cd597fSDmitry Bezrukov 14733cd597fSDmitry Bezrukov return aqc111_write_cmd_nopm(dev, cmd, value, index, sizeof(tmp), &tmp); 14833cd597fSDmitry Bezrukov } 14933cd597fSDmitry Bezrukov 15033cd597fSDmitry Bezrukov static int aqc111_write32_cmd(struct usbnet *dev, u8 cmd, u16 value, 15133cd597fSDmitry Bezrukov u16 index, u32 *data) 15233cd597fSDmitry Bezrukov { 15333cd597fSDmitry Bezrukov u32 tmp = *data; 15433cd597fSDmitry Bezrukov 15533cd597fSDmitry Bezrukov cpu_to_le32s(&tmp); 15633cd597fSDmitry Bezrukov 15733cd597fSDmitry Bezrukov return aqc111_write_cmd(dev, cmd, value, index, sizeof(tmp), &tmp); 15833cd597fSDmitry Bezrukov } 15933cd597fSDmitry Bezrukov 160*7b8b0654SDmitry Bezrukov static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed) 161*7b8b0654SDmitry Bezrukov { 162*7b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 163*7b8b0654SDmitry Bezrukov 164*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_ADV_MASK; 165*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_PAUSE; 166*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ASYM_PAUSE; 167*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_DOWNSHIFT; 168*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_DSH_RETRIES_MASK; 169*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= (3 << AQ_DSH_RETRIES_SHIFT) & 170*7b8b0654SDmitry Bezrukov AQ_DSH_RETRIES_MASK; 171*7b8b0654SDmitry Bezrukov 172*7b8b0654SDmitry Bezrukov if (autoneg == AUTONEG_ENABLE) { 173*7b8b0654SDmitry Bezrukov switch (speed) { 174*7b8b0654SDmitry Bezrukov case SPEED_5000: 175*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_5G; 176*7b8b0654SDmitry Bezrukov /* fall-through */ 177*7b8b0654SDmitry Bezrukov case SPEED_2500: 178*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_2G5; 179*7b8b0654SDmitry Bezrukov /* fall-through */ 180*7b8b0654SDmitry Bezrukov case SPEED_1000: 181*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_1G; 182*7b8b0654SDmitry Bezrukov /* fall-through */ 183*7b8b0654SDmitry Bezrukov case SPEED_100: 184*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_100M; 185*7b8b0654SDmitry Bezrukov /* fall-through */ 186*7b8b0654SDmitry Bezrukov } 187*7b8b0654SDmitry Bezrukov } else { 188*7b8b0654SDmitry Bezrukov switch (speed) { 189*7b8b0654SDmitry Bezrukov case SPEED_5000: 190*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_5G; 191*7b8b0654SDmitry Bezrukov break; 192*7b8b0654SDmitry Bezrukov case SPEED_2500: 193*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_2G5; 194*7b8b0654SDmitry Bezrukov break; 195*7b8b0654SDmitry Bezrukov case SPEED_1000: 196*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_1G; 197*7b8b0654SDmitry Bezrukov break; 198*7b8b0654SDmitry Bezrukov case SPEED_100: 199*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_100M; 200*7b8b0654SDmitry Bezrukov break; 201*7b8b0654SDmitry Bezrukov } 202*7b8b0654SDmitry Bezrukov } 203*7b8b0654SDmitry Bezrukov 204*7b8b0654SDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, &aqc111_data->phy_cfg); 205*7b8b0654SDmitry Bezrukov } 206*7b8b0654SDmitry Bezrukov 2077cea2d40SDmitry Bezrukov static const struct net_device_ops aqc111_netdev_ops = { 2087cea2d40SDmitry Bezrukov .ndo_open = usbnet_open, 2097cea2d40SDmitry Bezrukov .ndo_stop = usbnet_stop, 2107cea2d40SDmitry Bezrukov }; 2117cea2d40SDmitry Bezrukov 21233cd597fSDmitry Bezrukov static void aqc111_read_fw_version(struct usbnet *dev, 21333cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data) 21433cd597fSDmitry Bezrukov { 21533cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MAJOR, 21633cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.major); 21733cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MINOR, 21833cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.minor); 21933cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_REV, 22033cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.rev); 22133cd597fSDmitry Bezrukov 22233cd597fSDmitry Bezrukov if (aqc111_data->fw_ver.major & 0x80) 22333cd597fSDmitry Bezrukov aqc111_data->fw_ver.major &= ~0x80; 22433cd597fSDmitry Bezrukov } 22533cd597fSDmitry Bezrukov 2267cea2d40SDmitry Bezrukov static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) 2277cea2d40SDmitry Bezrukov { 2287cea2d40SDmitry Bezrukov struct usb_device *udev = interface_to_usbdev(intf); 229*7b8b0654SDmitry Bezrukov enum usb_device_speed usb_speed = udev->speed; 23033cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data; 2317cea2d40SDmitry Bezrukov int ret; 2327cea2d40SDmitry Bezrukov 2337cea2d40SDmitry Bezrukov /* Check if vendor configuration */ 2347cea2d40SDmitry Bezrukov if (udev->actconfig->desc.bConfigurationValue != 1) { 2357cea2d40SDmitry Bezrukov usb_driver_set_configuration(udev, 1); 2367cea2d40SDmitry Bezrukov return -ENODEV; 2377cea2d40SDmitry Bezrukov } 2387cea2d40SDmitry Bezrukov 2397cea2d40SDmitry Bezrukov usb_reset_configuration(dev->udev); 2407cea2d40SDmitry Bezrukov 2417cea2d40SDmitry Bezrukov ret = usbnet_get_endpoints(dev, intf); 2427cea2d40SDmitry Bezrukov if (ret < 0) { 2437cea2d40SDmitry Bezrukov netdev_dbg(dev->net, "usbnet_get_endpoints failed"); 2447cea2d40SDmitry Bezrukov return ret; 2457cea2d40SDmitry Bezrukov } 2467cea2d40SDmitry Bezrukov 24733cd597fSDmitry Bezrukov aqc111_data = kzalloc(sizeof(*aqc111_data), GFP_KERNEL); 24833cd597fSDmitry Bezrukov if (!aqc111_data) 24933cd597fSDmitry Bezrukov return -ENOMEM; 25033cd597fSDmitry Bezrukov 25133cd597fSDmitry Bezrukov /* store aqc111_data pointer in device data field */ 25233cd597fSDmitry Bezrukov dev->driver_priv = aqc111_data; 25333cd597fSDmitry Bezrukov 2547cea2d40SDmitry Bezrukov dev->net->netdev_ops = &aqc111_netdev_ops; 2557cea2d40SDmitry Bezrukov 25633cd597fSDmitry Bezrukov aqc111_read_fw_version(dev, aqc111_data); 257*7b8b0654SDmitry Bezrukov aqc111_data->autoneg = AUTONEG_ENABLE; 258*7b8b0654SDmitry Bezrukov aqc111_data->advertised_speed = (usb_speed == USB_SPEED_SUPER) ? 259*7b8b0654SDmitry Bezrukov SPEED_5000 : SPEED_1000; 26033cd597fSDmitry Bezrukov 2617cea2d40SDmitry Bezrukov return 0; 2627cea2d40SDmitry Bezrukov } 2637cea2d40SDmitry Bezrukov 2647cea2d40SDmitry Bezrukov static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf) 2657cea2d40SDmitry Bezrukov { 26633cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 267f3aa095aSDmitry Bezrukov u16 reg16; 268f3aa095aSDmitry Bezrukov 269f3aa095aSDmitry Bezrukov /* Force bz */ 270f3aa095aSDmitry Bezrukov reg16 = SFR_PHYPWR_RSTCTL_BZ; 271f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 272f3aa095aSDmitry Bezrukov 2, ®16); 273f3aa095aSDmitry Bezrukov reg16 = 0; 274f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 275f3aa095aSDmitry Bezrukov 2, ®16); 27633cd597fSDmitry Bezrukov 27733cd597fSDmitry Bezrukov /* Power down ethernet PHY */ 278*7b8b0654SDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_ADV_MASK; 27933cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 28033cd597fSDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_PHY_POWER_EN; 28133cd597fSDmitry Bezrukov aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0, 28233cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 28333cd597fSDmitry Bezrukov 28433cd597fSDmitry Bezrukov kfree(aqc111_data); 285f3aa095aSDmitry Bezrukov } 286f3aa095aSDmitry Bezrukov 287*7b8b0654SDmitry Bezrukov static void aqc111_status(struct usbnet *dev, struct urb *urb) 288*7b8b0654SDmitry Bezrukov { 289*7b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 290*7b8b0654SDmitry Bezrukov u64 *event_data = NULL; 291*7b8b0654SDmitry Bezrukov int link = 0; 292*7b8b0654SDmitry Bezrukov 293*7b8b0654SDmitry Bezrukov if (urb->actual_length < sizeof(*event_data)) 294*7b8b0654SDmitry Bezrukov return; 295*7b8b0654SDmitry Bezrukov 296*7b8b0654SDmitry Bezrukov event_data = urb->transfer_buffer; 297*7b8b0654SDmitry Bezrukov le64_to_cpus(event_data); 298*7b8b0654SDmitry Bezrukov 299*7b8b0654SDmitry Bezrukov if (*event_data & AQ_LS_MASK) 300*7b8b0654SDmitry Bezrukov link = 1; 301*7b8b0654SDmitry Bezrukov else 302*7b8b0654SDmitry Bezrukov link = 0; 303*7b8b0654SDmitry Bezrukov 304*7b8b0654SDmitry Bezrukov aqc111_data->link_speed = (*event_data & AQ_SPEED_MASK) >> 305*7b8b0654SDmitry Bezrukov AQ_SPEED_SHIFT; 306*7b8b0654SDmitry Bezrukov aqc111_data->link = link; 307*7b8b0654SDmitry Bezrukov 308*7b8b0654SDmitry Bezrukov if (netif_carrier_ok(dev->net) != link) 309*7b8b0654SDmitry Bezrukov usbnet_defer_kevent(dev, EVENT_LINK_RESET); 310*7b8b0654SDmitry Bezrukov } 311*7b8b0654SDmitry Bezrukov 312*7b8b0654SDmitry Bezrukov static void aqc111_configure_rx(struct usbnet *dev, 313*7b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data) 314*7b8b0654SDmitry Bezrukov { 315*7b8b0654SDmitry Bezrukov enum usb_device_speed usb_speed = dev->udev->speed; 316*7b8b0654SDmitry Bezrukov u16 link_speed = 0, usb_host = 0; 317*7b8b0654SDmitry Bezrukov u8 buf[5] = { 0 }; 318*7b8b0654SDmitry Bezrukov u8 queue_num = 0; 319*7b8b0654SDmitry Bezrukov u16 reg16 = 0; 320*7b8b0654SDmitry Bezrukov u8 reg8 = 0; 321*7b8b0654SDmitry Bezrukov 322*7b8b0654SDmitry Bezrukov buf[0] = 0x00; 323*7b8b0654SDmitry Bezrukov buf[1] = 0xF8; 324*7b8b0654SDmitry Bezrukov buf[2] = 0x07; 325*7b8b0654SDmitry Bezrukov switch (aqc111_data->link_speed) { 326*7b8b0654SDmitry Bezrukov case AQ_INT_SPEED_5G: 327*7b8b0654SDmitry Bezrukov link_speed = 5000; 328*7b8b0654SDmitry Bezrukov reg8 = 0x05; 329*7b8b0654SDmitry Bezrukov reg16 = 0x001F; 330*7b8b0654SDmitry Bezrukov break; 331*7b8b0654SDmitry Bezrukov case AQ_INT_SPEED_2_5G: 332*7b8b0654SDmitry Bezrukov link_speed = 2500; 333*7b8b0654SDmitry Bezrukov reg16 = 0x003F; 334*7b8b0654SDmitry Bezrukov break; 335*7b8b0654SDmitry Bezrukov case AQ_INT_SPEED_1G: 336*7b8b0654SDmitry Bezrukov link_speed = 1000; 337*7b8b0654SDmitry Bezrukov reg16 = 0x009F; 338*7b8b0654SDmitry Bezrukov break; 339*7b8b0654SDmitry Bezrukov case AQ_INT_SPEED_100M: 340*7b8b0654SDmitry Bezrukov link_speed = 100; 341*7b8b0654SDmitry Bezrukov queue_num = 1; 342*7b8b0654SDmitry Bezrukov reg16 = 0x063F; 343*7b8b0654SDmitry Bezrukov buf[1] = 0xFB; 344*7b8b0654SDmitry Bezrukov buf[2] = 0x4; 345*7b8b0654SDmitry Bezrukov break; 346*7b8b0654SDmitry Bezrukov } 347*7b8b0654SDmitry Bezrukov 348*7b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_INTER_PACKET_GAP_0, 349*7b8b0654SDmitry Bezrukov 1, 1, ®8); 350*7b8b0654SDmitry Bezrukov 351*7b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TX_PAUSE_RESEND_T, 3, 3, buf); 352*7b8b0654SDmitry Bezrukov 353*7b8b0654SDmitry Bezrukov switch (usb_speed) { 354*7b8b0654SDmitry Bezrukov case USB_SPEED_SUPER: 355*7b8b0654SDmitry Bezrukov usb_host = 3; 356*7b8b0654SDmitry Bezrukov break; 357*7b8b0654SDmitry Bezrukov case USB_SPEED_HIGH: 358*7b8b0654SDmitry Bezrukov usb_host = 2; 359*7b8b0654SDmitry Bezrukov break; 360*7b8b0654SDmitry Bezrukov case USB_SPEED_FULL: 361*7b8b0654SDmitry Bezrukov case USB_SPEED_LOW: 362*7b8b0654SDmitry Bezrukov usb_host = 1; 363*7b8b0654SDmitry Bezrukov queue_num = 0; 364*7b8b0654SDmitry Bezrukov break; 365*7b8b0654SDmitry Bezrukov default: 366*7b8b0654SDmitry Bezrukov usb_host = 0; 367*7b8b0654SDmitry Bezrukov break; 368*7b8b0654SDmitry Bezrukov } 369*7b8b0654SDmitry Bezrukov 370*7b8b0654SDmitry Bezrukov memcpy(buf, &AQC111_BULKIN_SIZE[queue_num], 5); 371*7b8b0654SDmitry Bezrukov /* RX bulk configuration */ 372*7b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 5, 5, buf); 373*7b8b0654SDmitry Bezrukov 374*7b8b0654SDmitry Bezrukov /* Set high low water level */ 375*7b8b0654SDmitry Bezrukov reg16 = 0x0810; 376*7b8b0654SDmitry Bezrukov 377*7b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW, 378*7b8b0654SDmitry Bezrukov 2, ®16); 379*7b8b0654SDmitry Bezrukov netdev_info(dev->net, "Link Speed %d, USB %d", link_speed, usb_host); 380*7b8b0654SDmitry Bezrukov } 381*7b8b0654SDmitry Bezrukov 382*7b8b0654SDmitry Bezrukov static int aqc111_link_reset(struct usbnet *dev) 383*7b8b0654SDmitry Bezrukov { 384*7b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 385*7b8b0654SDmitry Bezrukov u16 reg16 = 0; 386*7b8b0654SDmitry Bezrukov u8 reg8 = 0; 387*7b8b0654SDmitry Bezrukov 388*7b8b0654SDmitry Bezrukov if (aqc111_data->link == 1) { /* Link up */ 389*7b8b0654SDmitry Bezrukov aqc111_configure_rx(dev, aqc111_data); 390*7b8b0654SDmitry Bezrukov 391*7b8b0654SDmitry Bezrukov /* Vlan Tag Filter */ 392*7b8b0654SDmitry Bezrukov reg8 = SFR_VLAN_CONTROL_VSO; 393*7b8b0654SDmitry Bezrukov 394*7b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 395*7b8b0654SDmitry Bezrukov 1, 1, ®8); 396*7b8b0654SDmitry Bezrukov 397*7b8b0654SDmitry Bezrukov reg8 = 0x0; 398*7b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL, 399*7b8b0654SDmitry Bezrukov 1, 1, ®8); 400*7b8b0654SDmitry Bezrukov 401*7b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMTX_DMA_CONTROL, 402*7b8b0654SDmitry Bezrukov 1, 1, ®8); 403*7b8b0654SDmitry Bezrukov 404*7b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ARC_CTRL, 1, 1, ®8); 405*7b8b0654SDmitry Bezrukov 406*7b8b0654SDmitry Bezrukov reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB; 407*7b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 408*7b8b0654SDmitry Bezrukov 409*7b8b0654SDmitry Bezrukov reg8 = SFR_RX_PATH_READY; 410*7b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH, 411*7b8b0654SDmitry Bezrukov 1, 1, ®8); 412*7b8b0654SDmitry Bezrukov 413*7b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_EFF_EN; 414*7b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 415*7b8b0654SDmitry Bezrukov 1, 1, ®8); 416*7b8b0654SDmitry Bezrukov 417*7b8b0654SDmitry Bezrukov reg16 = 0; 418*7b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 419*7b8b0654SDmitry Bezrukov 2, ®16); 420*7b8b0654SDmitry Bezrukov 421*7b8b0654SDmitry Bezrukov reg16 = SFR_MEDIUM_XGMIIMODE | SFR_MEDIUM_FULL_DUPLEX; 422*7b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 423*7b8b0654SDmitry Bezrukov 2, ®16); 424*7b8b0654SDmitry Bezrukov 425*7b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 426*7b8b0654SDmitry Bezrukov 2, ®16); 427*7b8b0654SDmitry Bezrukov 428*7b8b0654SDmitry Bezrukov reg16 |= SFR_MEDIUM_RECEIVE_EN | SFR_MEDIUM_RXFLOW_CTRLEN | 429*7b8b0654SDmitry Bezrukov SFR_MEDIUM_TXFLOW_CTRLEN; 430*7b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 431*7b8b0654SDmitry Bezrukov 2, ®16); 432*7b8b0654SDmitry Bezrukov 433*7b8b0654SDmitry Bezrukov reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB | SFR_RX_CTL_START; 434*7b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 435*7b8b0654SDmitry Bezrukov 436*7b8b0654SDmitry Bezrukov netif_carrier_on(dev->net); 437*7b8b0654SDmitry Bezrukov } else { 438*7b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 439*7b8b0654SDmitry Bezrukov 2, ®16); 440*7b8b0654SDmitry Bezrukov reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 441*7b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 442*7b8b0654SDmitry Bezrukov 2, ®16); 443*7b8b0654SDmitry Bezrukov 444*7b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 445*7b8b0654SDmitry Bezrukov reg16 &= ~SFR_RX_CTL_START; 446*7b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 447*7b8b0654SDmitry Bezrukov 448*7b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_FLUSH_EN | SFR_BULK_OUT_EFF_EN; 449*7b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 450*7b8b0654SDmitry Bezrukov 1, 1, ®8); 451*7b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_EFF_EN; 452*7b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 453*7b8b0654SDmitry Bezrukov 1, 1, ®8); 454*7b8b0654SDmitry Bezrukov 455*7b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 456*7b8b0654SDmitry Bezrukov } 457*7b8b0654SDmitry Bezrukov return 0; 458*7b8b0654SDmitry Bezrukov } 459*7b8b0654SDmitry Bezrukov 460f3aa095aSDmitry Bezrukov static int aqc111_reset(struct usbnet *dev) 461f3aa095aSDmitry Bezrukov { 46233cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 463f3aa095aSDmitry Bezrukov u8 reg8 = 0; 464f3aa095aSDmitry Bezrukov 46533cd597fSDmitry Bezrukov /* Power up ethernet PHY */ 46633cd597fSDmitry Bezrukov aqc111_data->phy_cfg = AQ_PHY_POWER_EN; 46733cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 46833cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 46933cd597fSDmitry Bezrukov 470f3aa095aSDmitry Bezrukov reg8 = 0xFF; 471f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK, 1, 1, ®8); 472f3aa095aSDmitry Bezrukov 473f3aa095aSDmitry Bezrukov reg8 = 0x0; 474f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_SWP_CTRL, 1, 1, ®8); 475f3aa095aSDmitry Bezrukov 476f3aa095aSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 477f3aa095aSDmitry Bezrukov reg8 &= ~(SFR_MONITOR_MODE_EPHYRW | SFR_MONITOR_MODE_RWLC | 478f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RWMP | SFR_MONITOR_MODE_RWWF | 479f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RW_FLAG); 480f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 481f3aa095aSDmitry Bezrukov 482*7b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 483*7b8b0654SDmitry Bezrukov 484*7b8b0654SDmitry Bezrukov /* Phy advertise */ 485*7b8b0654SDmitry Bezrukov aqc111_set_phy_speed(dev, aqc111_data->autoneg, 486*7b8b0654SDmitry Bezrukov aqc111_data->advertised_speed); 487*7b8b0654SDmitry Bezrukov 488f3aa095aSDmitry Bezrukov return 0; 489f3aa095aSDmitry Bezrukov } 490f3aa095aSDmitry Bezrukov 491f3aa095aSDmitry Bezrukov static int aqc111_stop(struct usbnet *dev) 492f3aa095aSDmitry Bezrukov { 49333cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 494f3aa095aSDmitry Bezrukov u16 reg16 = 0; 495f3aa095aSDmitry Bezrukov 496f3aa095aSDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 497f3aa095aSDmitry Bezrukov 2, ®16); 498f3aa095aSDmitry Bezrukov reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 499f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 500f3aa095aSDmitry Bezrukov 2, ®16); 501f3aa095aSDmitry Bezrukov reg16 = 0; 502f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 503f3aa095aSDmitry Bezrukov 50433cd597fSDmitry Bezrukov /* Put PHY to low power*/ 50533cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 50633cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 50733cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 50833cd597fSDmitry Bezrukov 509*7b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 510*7b8b0654SDmitry Bezrukov 511f3aa095aSDmitry Bezrukov return 0; 5127cea2d40SDmitry Bezrukov } 5137cea2d40SDmitry Bezrukov 51417364b80SDmitry Bezrukov static const struct driver_info aqc111_info = { 51517364b80SDmitry Bezrukov .description = "Aquantia AQtion USB to 5GbE Controller", 5167cea2d40SDmitry Bezrukov .bind = aqc111_bind, 5177cea2d40SDmitry Bezrukov .unbind = aqc111_unbind, 518*7b8b0654SDmitry Bezrukov .status = aqc111_status, 519*7b8b0654SDmitry Bezrukov .link_reset = aqc111_link_reset, 520f3aa095aSDmitry Bezrukov .reset = aqc111_reset, 521f3aa095aSDmitry Bezrukov .stop = aqc111_stop, 52217364b80SDmitry Bezrukov }; 52317364b80SDmitry Bezrukov 52417364b80SDmitry Bezrukov #define AQC111_USB_ETH_DEV(vid, pid, table) \ 52517364b80SDmitry Bezrukov USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_VENDOR_SPEC), \ 52617364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table) \ 52717364b80SDmitry Bezrukov }, \ 52817364b80SDmitry Bezrukov { \ 52917364b80SDmitry Bezrukov USB_DEVICE_AND_INTERFACE_INFO((vid), (pid), \ 53017364b80SDmitry Bezrukov USB_CLASS_COMM, \ 53117364b80SDmitry Bezrukov USB_CDC_SUBCLASS_ETHERNET, \ 53217364b80SDmitry Bezrukov USB_CDC_PROTO_NONE), \ 53317364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table), 53417364b80SDmitry Bezrukov 53517364b80SDmitry Bezrukov static const struct usb_device_id products[] = { 53617364b80SDmitry Bezrukov {AQC111_USB_ETH_DEV(0x2eca, 0xc101, aqc111_info)}, 53717364b80SDmitry Bezrukov { },/* END */ 53817364b80SDmitry Bezrukov }; 53917364b80SDmitry Bezrukov MODULE_DEVICE_TABLE(usb, products); 54017364b80SDmitry Bezrukov 54117364b80SDmitry Bezrukov static struct usb_driver aq_driver = { 54217364b80SDmitry Bezrukov .name = "aqc111", 54317364b80SDmitry Bezrukov .id_table = products, 54417364b80SDmitry Bezrukov .probe = usbnet_probe, 54517364b80SDmitry Bezrukov .disconnect = usbnet_disconnect, 54617364b80SDmitry Bezrukov }; 54717364b80SDmitry Bezrukov 54817364b80SDmitry Bezrukov module_usb_driver(aq_driver); 54917364b80SDmitry Bezrukov 55017364b80SDmitry Bezrukov MODULE_DESCRIPTION("Aquantia AQtion USB to 5/2.5GbE Controllers"); 55117364b80SDmitry Bezrukov MODULE_LICENSE("GPL"); 552