aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/qualcomm
diff options
context:
space:
mode:
authorMark Brown2017-04-25 16:35:35 +0100
committerMark Brown2017-04-25 16:35:35 +0100
commit9095bf25ea08135a5b74875dd0e3eeaddc4218a0 (patch)
treea4e6976eab0e7a5b6258281077cd5853c7e69514 /drivers/net/ethernet/qualcomm
parentcdf4275e957c6bad3756e98942341667f1d7de7d (diff)
parentc1ae3cfa0e89fa1a7ecc4c99031f5e9ae99d9201 (diff)
Merge tag 'v4.11-rc1' into regulator-arizona
Linux 4.11-rc1
Diffstat (limited to 'drivers/net/ethernet/qualcomm')
-rw-r--r--drivers/net/ethernet/qualcomm/emac/Makefile4
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-ethtool.c261
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-mac.c114
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-mac.h1
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-phy.c12
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-phy.h13
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-sgmii-fsm9900.c245
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c217
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c210
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-sgmii.c714
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-sgmii.h31
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac.c118
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac.h126
-rw-r--r--drivers/net/ethernet/qualcomm/qca_debug.c18
-rw-r--r--drivers/net/ethernet/qualcomm/qca_framing.h6
-rw-r--r--drivers/net/ethernet/qualcomm/qca_spi.c16
16 files changed, 1345 insertions, 761 deletions
diff --git a/drivers/net/ethernet/qualcomm/emac/Makefile b/drivers/net/ethernet/qualcomm/emac/Makefile
index 01ee144c6386..fc57cedf4c0c 100644
--- a/drivers/net/ethernet/qualcomm/emac/Makefile
+++ b/drivers/net/ethernet/qualcomm/emac/Makefile
@@ -4,4 +4,6 @@
obj-$(CONFIG_QCOM_EMAC) += qcom-emac.o
-qcom-emac-objs := emac.o emac-mac.o emac-phy.o emac-sgmii.o
+qcom-emac-objs := emac.o emac-mac.o emac-phy.o emac-sgmii.o emac-ethtool.o \
+ emac-sgmii-fsm9900.o emac-sgmii-qdf2432.o \
+ emac-sgmii-qdf2400.o
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-ethtool.c b/drivers/net/ethernet/qualcomm/emac/emac-ethtool.c
new file mode 100644
index 000000000000..bbe24639aa5a
--- /dev/null
+++ b/drivers/net/ethernet/qualcomm/emac/emac-ethtool.c
@@ -0,0 +1,261 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include "emac.h"
+
+static const char * const emac_ethtool_stat_strings[] = {
+ "rx_ok",
+ "rx_bcast",
+ "rx_mcast",
+ "rx_pause",
+ "rx_ctrl",
+ "rx_fcs_err",
+ "rx_len_err",
+ "rx_byte_cnt",
+ "rx_runt",
+ "rx_frag",
+ "rx_sz_64",
+ "rx_sz_65_127",
+ "rx_sz_128_255",
+ "rx_sz_256_511",
+ "rx_sz_512_1023",
+ "rx_sz_1024_1518",
+ "rx_sz_1519_max",
+ "rx_sz_ov",
+ "rx_rxf_ov",
+ "rx_align_err",
+ "rx_bcast_byte_cnt",
+ "rx_mcast_byte_cnt",
+ "rx_err_addr",
+ "rx_crc_align",
+ "rx_jabbers",
+ "tx_ok",
+ "tx_bcast",
+ "tx_mcast",
+ "tx_pause",
+ "tx_exc_defer",
+ "tx_ctrl",
+ "tx_defer",
+ "tx_byte_cnt",
+ "tx_sz_64",
+ "tx_sz_65_127",
+ "tx_sz_128_255",
+ "tx_sz_256_511",
+ "tx_sz_512_1023",
+ "tx_sz_1024_1518",
+ "tx_sz_1519_max",
+ "tx_1_col",
+ "tx_2_col",
+ "tx_late_col",
+ "tx_abort_col",
+ "tx_underrun",
+ "tx_rd_eop",
+ "tx_len_err",
+ "tx_trunc",
+ "tx_bcast_byte",
+ "tx_mcast_byte",
+ "tx_col",
+};
+
+#define EMAC_STATS_LEN ARRAY_SIZE(emac_ethtool_stat_strings)
+
+static u32 emac_get_msglevel(struct net_device *netdev)
+{
+ struct emac_adapter *adpt = netdev_priv(netdev);
+
+ return adpt->msg_enable;
+}
+
+static void emac_set_msglevel(struct net_device *netdev, u32 data)
+{
+ struct emac_adapter *adpt = netdev_priv(netdev);
+
+ adpt->msg_enable = data;
+}
+
+static int emac_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return EMAC_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void emac_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+ unsigned int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < EMAC_STATS_LEN; i++) {
+ strlcpy(data, emac_ethtool_stat_strings[i],
+ ETH_GSTRING_LEN);
+ data += ETH_GSTRING_LEN;
+ }
+ break;
+ }
+}
+
+static void emac_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct emac_adapter *adpt = netdev_priv(netdev);
+
+ spin_lock(&adpt->stats.lock);
+
+ emac_update_hw_stats(adpt);
+ memcpy(data, &adpt->stats, EMAC_STATS_LEN * sizeof(u64));
+
+ spin_unlock(&adpt->stats.lock);
+}
+
+static int emac_nway_reset(struct net_device *netdev)
+{
+ struct phy_device *phydev = netdev->phydev;
+
+ if (!phydev)
+ return -ENODEV;
+
+ return genphy_restart_aneg(phydev);
+}
+
+static void emac_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct emac_adapter *adpt = netdev_priv(netdev);
+
+ ring->rx_max_pending = EMAC_MAX_RX_DESCS;
+ ring->tx_max_pending = EMAC_MAX_TX_DESCS;
+ ring->rx_pending = adpt->rx_desc_cnt;
+ ring->tx_pending = adpt->tx_desc_cnt;
+}
+
+static int emac_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct emac_adapter *adpt = netdev_priv(netdev);
+
+ /* We don't have separate queues/rings for small/large frames, so
+ * reject any attempt to specify those values separately.
+ */
+ if (ring->rx_mini_pending || ring->rx_jumbo_pending)
+ return -EINVAL;
+
+ adpt->tx_desc_cnt =
+ clamp_val(ring->tx_pending, EMAC_MIN_TX_DESCS, EMAC_MAX_TX_DESCS);
+
+ adpt->rx_desc_cnt =
+ clamp_val(ring->rx_pending, EMAC_MIN_RX_DESCS, EMAC_MAX_RX_DESCS);
+
+ if (netif_running(netdev))
+ return emac_reinit_locked(adpt);
+
+ return 0;
+}
+
+static void emac_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct emac_adapter *adpt = netdev_priv(netdev);
+
+ pause->autoneg = adpt->automatic ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+ pause->rx_pause = adpt->rx_flow_control ? 1 : 0;
+ pause->tx_pause = adpt->tx_flow_control ? 1 : 0;
+}
+
+static int emac_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct emac_adapter *adpt = netdev_priv(netdev);
+
+ adpt->automatic = pause->autoneg == AUTONEG_ENABLE;
+ adpt->rx_flow_control = pause->rx_pause != 0;
+ adpt->tx_flow_control = pause->tx_pause != 0;
+
+ if (netif_running(netdev))
+ return emac_reinit_locked(adpt);
+
+ return 0;
+}
+
+/* Selected registers that might want to track during runtime. */
+static const u16 emac_regs[] = {
+ EMAC_DMA_MAS_CTRL,
+ EMAC_MAC_CTRL,
+ EMAC_TXQ_CTRL_0,
+ EMAC_RXQ_CTRL_0,
+ EMAC_DMA_CTRL,
+ EMAC_INT_MASK,
+ EMAC_AXI_MAST_CTRL,
+ EMAC_CORE_HW_VERSION,
+ EMAC_MISC_CTRL,
+};
+
+/* Every time emac_regs[] above is changed, increase this version number. */
+#define EMAC_REGS_VERSION 0
+
+#define EMAC_MAX_REG_SIZE ARRAY_SIZE(emac_regs)
+
+static void emac_get_regs(struct net_device *netdev,
+ struct ethtool_regs *regs, void *buff)
+{
+ struct emac_adapter *adpt = netdev_priv(netdev);
+ u32 *val = buff;
+ unsigned int i;
+
+ regs->version = EMAC_REGS_VERSION;
+ regs->len = EMAC_MAX_REG_SIZE * sizeof(u32);
+
+ for (i = 0; i < EMAC_MAX_REG_SIZE; i++)
+ val[i] = readl(adpt->base + emac_regs[i]);
+}
+
+static int emac_get_regs_len(struct net_device *netdev)
+{
+ return EMAC_MAX_REG_SIZE * sizeof(u32);
+}
+
+static const struct ethtool_ops emac_ethtool_ops = {
+ .get_link_ksettings = phy_ethtool_get_link_ksettings,
+ .set_link_ksettings = phy_ethtool_set_link_ksettings,
+
+ .get_msglevel = emac_get_msglevel,
+ .set_msglevel = emac_set_msglevel,
+
+ .get_sset_count = emac_get_sset_count,
+ .get_strings = emac_get_strings,
+ .get_ethtool_stats = emac_get_ethtool_stats,
+
+ .get_ringparam = emac_get_ringparam,
+ .set_ringparam = emac_set_ringparam,
+
+ .get_pauseparam = emac_get_pauseparam,
+ .set_pauseparam = emac_set_pauseparam,
+
+ .nway_reset = emac_nway_reset,
+
+ .get_link = ethtool_op_get_link,
+
+ .get_regs_len = emac_get_regs_len,
+ .get_regs = emac_get_regs,
+};
+
+void emac_set_ethtool_ops(struct net_device *netdev)
+{
+ netdev->ethtool_ops = &emac_ethtool_ops;
+}
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-mac.c b/drivers/net/ethernet/qualcomm/emac/emac-mac.c
index 0b4deb31e742..cc065ffbe4b5 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-mac.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac-mac.c
@@ -25,58 +25,6 @@
#include "emac.h"
#include "emac-sgmii.h"
-/* EMAC base register offsets */
-#define EMAC_MAC_CTRL 0x001480
-#define EMAC_WOL_CTRL0 0x0014a0
-#define EMAC_RSS_KEY0 0x0014b0
-#define EMAC_H1TPD_BASE_ADDR_LO 0x0014e0
-#define EMAC_H2TPD_BASE_ADDR_LO 0x0014e4
-#define EMAC_H3TPD_BASE_ADDR_LO 0x0014e8
-#define EMAC_INTER_SRAM_PART9 0x001534
-#define EMAC_DESC_CTRL_0 0x001540
-#define EMAC_DESC_CTRL_1 0x001544
-#define EMAC_DESC_CTRL_2 0x001550
-#define EMAC_DESC_CTRL_10 0x001554
-#define EMAC_DESC_CTRL_12 0x001558
-#define EMAC_DESC_CTRL_13 0x00155c
-#define EMAC_DESC_CTRL_3 0x001560
-#define EMAC_DESC_CTRL_4 0x001564
-#define EMAC_DESC_CTRL_5 0x001568
-#define EMAC_DESC_CTRL_14 0x00156c
-#define EMAC_DESC_CTRL_15 0x001570
-#define EMAC_DESC_CTRL_16 0x001574
-#define EMAC_DESC_CTRL_6 0x001578
-#define EMAC_DESC_CTRL_8 0x001580
-#define EMAC_DESC_CTRL_9 0x001584
-#define EMAC_DESC_CTRL_11 0x001588
-#define EMAC_TXQ_CTRL_0 0x001590
-#define EMAC_TXQ_CTRL_1 0x001594
-#define EMAC_TXQ_CTRL_2 0x001598
-#define EMAC_RXQ_CTRL_0 0x0015a0
-#define EMAC_RXQ_CTRL_1 0x0015a4
-#define EMAC_RXQ_CTRL_2 0x0015a8
-#define EMAC_RXQ_CTRL_3 0x0015ac
-#define EMAC_BASE_CPU_NUMBER 0x0015b8
-#define EMAC_DMA_CTRL 0x0015c0
-#define EMAC_MAILBOX_0 0x0015e0
-#define EMAC_MAILBOX_5 0x0015e4
-#define EMAC_MAILBOX_6 0x0015e8
-#define EMAC_MAILBOX_13 0x0015ec
-#define EMAC_MAILBOX_2 0x0015f4
-#define EMAC_MAILBOX_3 0x0015f8
-#define EMAC_MAILBOX_11 0x00160c
-#define EMAC_AXI_MAST_CTRL 0x001610
-#define EMAC_MAILBOX_12 0x001614
-#define EMAC_MAILBOX_9 0x001618
-#define EMAC_MAILBOX_10 0x00161c
-#define EMAC_ATHR_HEADER_CTRL 0x001620
-#define EMAC_CLK_GATE_CTRL 0x001814
-#define EMAC_MISC_CTRL 0x001990
-#define EMAC_MAILBOX_7 0x0019e0
-#define EMAC_MAILBOX_8 0x0019e4
-#define EMAC_MAILBOX_15 0x001bd4
-#define EMAC_MAILBOX_16 0x001bd8
-
/* EMAC_MAC_CTRL */
#define SINGLE_PAUSE_MODE 0x10000000
#define DEBUG_MODE 0x08000000
@@ -103,14 +51,6 @@
#define RXEN 0x00000002
#define TXEN 0x00000001
-
-/* EMAC_WOL_CTRL0 */
-#define LK_CHG_PME 0x20
-#define LK_CHG_EN 0x10
-#define MG_FRAME_PME 0x8
-#define MG_FRAME_EN 0x4
-#define WK_FRAME_EN 0x1
-
/* EMAC_DESC_CTRL_3 */
#define RFD_RING_SIZE_BMSK 0xfff
@@ -314,8 +254,6 @@ struct emac_skb_cb {
RX_PKT_INT2 |\
RX_PKT_INT3)
-#define EMAC_MAC_IRQ_RES "core0"
-
void emac_mac_multicast_addr_set(struct emac_adapter *adpt, u8 *addr)
{
u32 crc32, bit, reg, mta;
@@ -558,7 +496,7 @@ void emac_mac_reset(struct emac_adapter *adpt)
emac_reg_update32(adpt->base + EMAC_DMA_MAS_CTRL, 0, INT_RD_CLR_EN);
}
-void emac_mac_start(struct emac_adapter *adpt)
+static void emac_mac_start(struct emac_adapter *adpt)
{
struct phy_device *phydev = adpt->phydev;
u32 mac, csr1;
@@ -575,11 +513,19 @@ void emac_mac_start(struct emac_adapter *adpt)
mac |= TXEN | RXEN; /* enable RX/TX */
- /* Configure MAC flow control to match the PHY's settings. */
- if (phydev->pause)
- mac |= RXFC;
- if (phydev->pause != phydev->asym_pause)
- mac |= TXFC;
+ /* Configure MAC flow control. If set to automatic, then match
+ * whatever the PHY does. Otherwise, enable or disable it, depending
+ * on what the user configured via ethtool.
+ */
+ mac &= ~(RXFC | TXFC);
+
+ if (adpt->automatic) {
+ /* If it's set to automatic, then update our local values */
+ adpt->rx_flow_control = phydev->pause;
+ adpt->tx_flow_control = phydev->pause != phydev->asym_pause;
+ }
+ mac |= adpt->rx_flow_control ? RXFC : 0;
+ mac |= adpt->tx_flow_control ? TXFC : 0;
/* setup link speed */
mac &= ~SPEED_MASK;
@@ -621,8 +567,6 @@ void emac_mac_start(struct emac_adapter *adpt)
emac_reg_update32(adpt->base + EMAC_ATHR_HEADER_CTRL,
(HEADER_ENABLE | HEADER_CNT_EN), 0);
-
- emac_reg_update32(adpt->csr + EMAC_EMAC_WRAPPER_CSR2, 0, WOL_EN);
}
void emac_mac_stop(struct emac_adapter *adpt)
@@ -963,12 +907,16 @@ static void emac_mac_rx_descs_refill(struct emac_adapter *adpt,
static void emac_adjust_link(struct net_device *netdev)
{
struct emac_adapter *adpt = netdev_priv(netdev);
+ struct emac_sgmii *sgmii = &adpt->phy;
struct phy_device *phydev = netdev->phydev;
- if (phydev->link)
+ if (phydev->link) {
emac_mac_start(adpt);
- else
+ sgmii->link_up(adpt);
+ } else {
+ sgmii->link_down(adpt);
emac_mac_stop(adpt);
+ }
phy_print_status(phydev);
}
@@ -977,40 +925,26 @@ static void emac_adjust_link(struct net_device *netdev)
int emac_mac_up(struct emac_adapter *adpt)
{
struct net_device *netdev = adpt->netdev;
- struct emac_irq *irq = &adpt->irq;
int ret;
emac_mac_rx_tx_ring_reset_all(adpt);
emac_mac_config(adpt);
-
- ret = request_irq(irq->irq, emac_isr, 0, EMAC_MAC_IRQ_RES, irq);
- if (ret) {
- netdev_err(adpt->netdev, "could not request %s irq\n",
- EMAC_MAC_IRQ_RES);
- return ret;
- }
-
emac_mac_rx_descs_refill(adpt, &adpt->rx_q);
+ adpt->phydev->irq = PHY_IGNORE_INTERRUPT;
ret = phy_connect_direct(netdev, adpt->phydev, emac_adjust_link,
PHY_INTERFACE_MODE_SGMII);
if (ret) {
netdev_err(adpt->netdev, "could not connect phy\n");
- free_irq(irq->irq, irq);
return ret;
}
+ phy_attached_print(adpt->phydev, NULL);
+
/* enable mac irq */
writel((u32)~DIS_INT, adpt->base + EMAC_INT_STATUS);
writel(adpt->irq.mask, adpt->base + EMAC_INT_MASK);
- /* Enable pause frames. Without this feature, the EMAC has been shown
- * to receive (and drop) frames with FCS errors at gigabit connections.
- */
- adpt->phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
- adpt->phydev->advertising |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-
- adpt->phydev->irq = PHY_IGNORE_INTERRUPT;
phy_start(adpt->phydev);
napi_enable(&adpt->rx_q.napi);
@@ -1036,7 +970,6 @@ void emac_mac_down(struct emac_adapter *adpt)
writel(DIS_INT, adpt->base + EMAC_INT_STATUS);
writel(0, adpt->base + EMAC_INT_MASK);
synchronize_irq(adpt->irq.irq);
- free_irq(adpt->irq.irq, &adpt->irq);
phy_disconnect(adpt->phydev);
@@ -1213,7 +1146,6 @@ void emac_mac_rx_process(struct emac_adapter *adpt, struct emac_rx_queue *rx_q,
emac_receive_skb(rx_q, skb, (u16)RRD_CVALN_TAG(&rrd),
(bool)RRD_CVTAG(&rrd));
- netdev->last_rx = jiffies;
(*num_pkts)++;
} while (*num_pkts < max_pkts);
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-mac.h b/drivers/net/ethernet/qualcomm/emac/emac-mac.h
index f3aa24dc4a29..5028fb4bec2b 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-mac.h
+++ b/drivers/net/ethernet/qualcomm/emac/emac-mac.h
@@ -230,7 +230,6 @@ struct emac_adapter;
int emac_mac_up(struct emac_adapter *adpt);
void emac_mac_down(struct emac_adapter *adpt);
void emac_mac_reset(struct emac_adapter *adpt);
-void emac_mac_start(struct emac_adapter *adpt);
void emac_mac_stop(struct emac_adapter *adpt);
void emac_mac_mode_config(struct emac_adapter *adpt);
void emac_mac_rx_process(struct emac_adapter *adpt, struct emac_rx_queue *rx_q,
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-phy.c b/drivers/net/ethernet/qualcomm/emac/emac-phy.c
index 99a14df28b96..441c19366489 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-phy.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac-phy.c
@@ -22,8 +22,6 @@
#include <linux/acpi.h>
#include "emac.h"
#include "emac-mac.h"
-#include "emac-phy.h"
-#include "emac-sgmii.h"
/* EMAC base register offsets */
#define EMAC_MDIO_CTRL 0x001414
@@ -201,6 +199,13 @@ int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt)
else
adpt->phydev = mdiobus_get_phy(mii_bus, phy_addr);
+ /* of_phy_find_device() claims a reference to the phydev,
+ * so we do that here manually as well. When the driver
+ * later unloads, it can unilaterally drop the reference
+ * without worrying about ACPI vs DT.
+ */
+ if (adpt->phydev)
+ get_device(&adpt->phydev->mdio.dev);
} else {
struct device_node *phy_np;
@@ -221,8 +226,5 @@ int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt)
return -ENODEV;
}
- if (adpt->phydev->drv)
- phy_attached_print(adpt->phydev, NULL);
-
return 0;
}
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-phy.h b/drivers/net/ethernet/qualcomm/emac/emac-phy.h
index 49f3701a6dd7..c0c301c72129 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-phy.h
+++ b/drivers/net/ethernet/qualcomm/emac/emac-phy.h
@@ -13,19 +13,6 @@
#ifndef _EMAC_PHY_H_
#define _EMAC_PHY_H_
-typedef int (*emac_sgmii_initialize)(struct emac_adapter *adpt);
-
-/** emac_phy - internal emac phy
- * @base base address
- * @digital per-lane digital block
- * @initialize initialization function
- */
-struct emac_phy {
- void __iomem *base;
- void __iomem *digital;
- emac_sgmii_initialize initialize;
-};
-
struct emac_adapter;
int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt);
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-fsm9900.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-fsm9900.c
new file mode 100644
index 000000000000..10de8d0d9a56
--- /dev/null
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-fsm9900.c
@@ -0,0 +1,245 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* Qualcomm Technologies, Inc. FSM9900 EMAC SGMII Controller driver.
+ */
+
+#include <linux/iopoll.h>
+#include "emac.h"
+
+/* EMAC_QSERDES register offsets */
+#define EMAC_QSERDES_COM_SYS_CLK_CTRL 0x0000
+#define EMAC_QSERDES_COM_PLL_CNTRL 0x0014
+#define EMAC_QSERDES_COM_PLL_IP_SETI 0x0018
+#define EMAC_QSERDES_COM_PLL_CP_SETI 0x0024
+#define EMAC_QSERDES_COM_PLL_IP_SETP 0x0028
+#define EMAC_QSERDES_COM_PLL_CP_SETP 0x002c
+#define EMAC_QSERDES_COM_SYSCLK_EN_SEL 0x0038
+#define EMAC_QSERDES_COM_RESETSM_CNTRL 0x0040
+#define EMAC_QSERDES_COM_PLLLOCK_CMP1 0x0044
+#define EMAC_QSERDES_COM_PLLLOCK_CMP2 0x0048
+#define EMAC_QSERDES_COM_PLLLOCK_CMP3 0x004c
+#define EMAC_QSERDES_COM_PLLLOCK_CMP_EN 0x0050
+#define EMAC_QSERDES_COM_DEC_START1 0x0064
+#define EMAC_QSERDES_COM_DIV_FRAC_START1 0x0098
+#define EMAC_QSERDES_COM_DIV_FRAC_START2 0x009c
+#define EMAC_QSERDES_COM_DIV_FRAC_START3 0x00a0
+#define EMAC_QSERDES_COM_DEC_START2 0x00a4
+#define EMAC_QSERDES_COM_PLL_CRCTRL 0x00ac
+#define EMAC_QSERDES_COM_RESET_SM 0x00bc
+#define EMAC_QSERDES_TX_BIST_MODE_LANENO 0x0100
+#define EMAC_QSERDES_TX_TX_EMP_POST1_LVL 0x0108
+#define EMAC_QSERDES_TX_TX_DRV_LVL 0x010c
+#define EMAC_QSERDES_TX_LANE_MODE 0x0150
+#define EMAC_QSERDES_TX_TRAN_DRVR_EMP_EN 0x0170
+#define EMAC_QSERDES_RX_CDR_CONTROL 0x0200
+#define EMAC_QSERDES_RX_CDR_CONTROL2 0x0210
+#define EMAC_QSERDES_RX_RX_EQ_GAIN12 0x0230
+
+/* EMAC_SGMII register offsets */
+#define EMAC_SGMII_PHY_SERDES_START 0x0000
+#define EMAC_SGMII_PHY_CMN_PWR_CTRL 0x0004
+#define EMAC_SGMII_PHY_RX_PWR_CTRL 0x0008
+#define EMAC_SGMII_PHY_TX_PWR_CTRL 0x000C
+#define EMAC_SGMII_PHY_LANE_CTRL1 0x0018
+#define EMAC_SGMII_PHY_CDR_CTRL0 0x0058
+#define EMAC_SGMII_PHY_POW_DWN_CTRL0 0x0080
+#define EMAC_SGMII_PHY_INTERRUPT_MASK 0x00b4
+
+#define PLL_IPSETI(x) ((x) & 0x3f)
+
+#define PLL_CPSETI(x) ((x) & 0xff)
+
+#define PLL_IPSETP(x) ((x) & 0x3f)
+
+#define PLL_CPSETP(x) ((x) & 0x1f)
+
+#define PLL_RCTRL(x) (((x) & 0xf) << 4)
+#define PLL_CCTRL(x) ((x) & 0xf)
+
+#define LANE_MODE(x) ((x) & 0x1f)
+
+#define SYSCLK_CM BIT(4)
+#define SYSCLK_AC_COUPLE BIT(3)
+
+#define OCP_EN BIT(5)
+#define PLL_DIV_FFEN BIT(2)
+#define PLL_DIV_ORD BIT(1)
+
+#define SYSCLK_SEL_CMOS BIT(3)
+
+#define FRQ_TUNE_MODE BIT(4)
+
+#define PLLLOCK_CMP_EN BIT(0)
+
+#define DEC_START1_MUX BIT(7)
+#define DEC_START1(x) ((x) & 0x7f)
+
+#define DIV_FRAC_START_MUX BIT(7)
+#define DIV_FRAC_START(x) ((x) & 0x7f)
+
+#define DIV_FRAC_START3_MUX BIT(4)
+#define DIV_FRAC_START3(x) ((x) & 0xf)
+
+#define DEC_START2_MUX BIT(1)
+#define DEC_START2 BIT(0)
+
+#define READY BIT(5)
+
+#define TX_EMP_POST1_LVL_MUX BIT(5)
+#define TX_EMP_POST1_LVL(x) ((x) & 0x1f)
+
+#define TX_DRV_LVL_MUX BIT(4)
+#define TX_DRV_LVL(x) ((x) & 0xf)
+
+#define EMP_EN_MUX BIT(1)
+#define EMP_EN BIT(0)
+
+#define SECONDORDERENABLE BIT(6)
+#define FIRSTORDER_THRESH(x) (((x) & 0x7) << 3)
+#define SECONDORDERGAIN(x) ((x) & 0x7)
+
+#define RX_EQ_GAIN2(x) (((x) & 0xf) << 4)
+#define RX_EQ_GAIN1(x) ((x) & 0xf)
+
+#define SERDES_START BIT(0)
+
+#define BIAS_EN BIT(6)
+#define PLL_EN BIT(5)
+#define SYSCLK_EN BIT(4)
+#define CLKBUF_L_EN BIT(3)
+#define PLL_TXCLK_EN BIT(1)
+#define PLL_RXCLK_EN BIT(0)
+
+#define L0_RX_SIGDET_EN BIT(7)
+#define L0_RX_TERM_MODE(x) (((x) & 3) << 4)
+#define L0_RX_I_EN BIT(1)
+
+#define L0_TX_EN BIT(5)
+#define L0_CLKBUF_EN BIT(4)
+#define L0_TRAN_BIAS_EN BIT(1)
+
+#define L0_RX_EQUALIZE_ENABLE BIT(6)
+#define L0_RESET_TSYNC_EN BIT(4)
+#define L0_DRV_LVL(x) ((x) & 0xf)
+
+#define PWRDN_B BIT(0)
+#define CDR_MAX_CNT(x) ((x) & 0xff)
+
+#define PLLLOCK_CMP(x) ((x) & 0xff)
+
+#define SERDES_START_WAIT_TIMES 100
+
+struct emac_reg_write {
+ unsigned int offset;
+ u32 val;
+};
+
+static void emac_reg_write_all(void __iomem *base,
+ const struct emac_reg_write *itr, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; ++itr, ++i)
+ writel(itr->val, base + itr->offset);
+}
+
+static const struct emac_reg_write physical_coding_sublayer_programming[] = {
+ {EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
+ {EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
+ {EMAC_SGMII_PHY_CMN_PWR_CTRL,
+ BIAS_EN | SYSCLK_EN | CLKBUF_L_EN | PLL_TXCLK_EN | PLL_RXCLK_EN},
+ {EMAC_SGMII_PHY_TX_PWR_CTRL, L0_TX_EN | L0_CLKBUF_EN | L0_TRAN_BIAS_EN},
+ {EMAC_SGMII_PHY_RX_PWR_CTRL,
+ L0_RX_SIGDET_EN | L0_RX_TERM_MODE(1) | L0_RX_I_EN},
+ {EMAC_SGMII_PHY_CMN_PWR_CTRL,
+ BIAS_EN | PLL_EN | SYSCLK_EN | CLKBUF_L_EN | PLL_TXCLK_EN |
+ PLL_RXCLK_EN},
+ {EMAC_SGMII_PHY_LANE_CTRL1,
+ L0_RX_EQUALIZE_ENABLE | L0_RESET_TSYNC_EN | L0_DRV_LVL(15)},
+};
+
+static const struct emac_reg_write sysclk_refclk_setting[] = {
+ {EMAC_QSERDES_COM_SYSCLK_EN_SEL, SYSCLK_SEL_CMOS},
+ {EMAC_QSERDES_COM_SYS_CLK_CTRL, SYSCLK_CM | SYSCLK_AC_COUPLE},
+};
+
+static const struct emac_reg_write pll_setting[] = {
+ {EMAC_QSERDES_COM_PLL_IP_SETI, PLL_IPSETI(1)},
+ {EMAC_QSERDES_COM_PLL_CP_SETI, PLL_CPSETI(59)},
+ {EMAC_QSERDES_COM_PLL_IP_SETP, PLL_IPSETP(10)},
+ {EMAC_QSERDES_COM_PLL_CP_SETP, PLL_CPSETP(9)},
+ {EMAC_QSERDES_COM_PLL_CRCTRL, PLL_RCTRL(15) | PLL_CCTRL(11)},
+ {EMAC_QSERDES_COM_PLL_CNTRL, OCP_EN | PLL_DIV_FFEN | PLL_DIV_ORD},
+ {EMAC_QSERDES_COM_DEC_START1, DEC_START1_MUX | DEC_START1(2)},
+ {EMAC_QSERDES_COM_DEC_START2, DEC_START2_MUX | DEC_START2},
+ {EMAC_QSERDES_COM_DIV_FRAC_START1,
+ DIV_FRAC_START_MUX | DIV_FRAC_START(85)},
+ {EMAC_QSERDES_COM_DIV_FRAC_START2,
+ DIV_FRAC_START_MUX | DIV_FRAC_START(42)},
+ {EMAC_QSERDES_COM_DIV_FRAC_START3,
+ DIV_FRAC_START3_MUX | DIV_FRAC_START3(3)},
+ {EMAC_QSERDES_COM_PLLLOCK_CMP1, PLLLOCK_CMP(43)},
+ {EMAC_QSERDES_COM_PLLLOCK_CMP2, PLLLOCK_CMP(104)},
+ {EMAC_QSERDES_COM_PLLLOCK_CMP3, PLLLOCK_CMP(0)},
+ {EMAC_QSERDES_COM_PLLLOCK_CMP_EN, PLLLOCK_CMP_EN},
+ {EMAC_QSERDES_COM_RESETSM_CNTRL, FRQ_TUNE_MODE},
+};
+
+static const struct emac_reg_write cdr_setting[] = {
+ {EMAC_QSERDES_RX_CDR_CONTROL,
+ SECONDORDERENABLE | FIRSTORDER_THRESH(3) | SECONDORDERGAIN(2)},
+ {EMAC_QSERDES_RX_CDR_CONTROL2,
+ SECONDORDERENABLE | FIRSTORDER_THRESH(3) | SECONDORDERGAIN(4)},
+};
+
+static const struct emac_reg_write tx_rx_setting[] = {
+ {EMAC_QSERDES_TX_BIST_MODE_LANENO, 0},
+ {EMAC_QSERDES_TX_TX_DRV_LVL, TX_DRV_LVL_MUX | TX_DRV_LVL(15)},
+ {EMAC_QSERDES_TX_TRAN_DRVR_EMP_EN, EMP_EN_MUX | EMP_EN},
+ {EMAC_QSERDES_TX_TX_EMP_POST1_LVL,
+ TX_EMP_POST1_LVL_MUX | TX_EMP_POST1_LVL(1)},
+ {EMAC_QSERDES_RX_RX_EQ_GAIN12, RX_EQ_GAIN2(15) | RX_EQ_GAIN1(15)},
+ {EMAC_QSERDES_TX_LANE_MODE, LANE_MODE(8)},
+};
+
+int emac_sgmii_init_fsm9900(struct emac_adapter *adpt)
+{
+ struct emac_sgmii *phy = &adpt->phy;
+ unsigned int i;
+
+ emac_reg_write_all(phy->base, physical_coding_sublayer_programming,
+ ARRAY_SIZE(physical_coding_sublayer_programming));
+ emac_reg_write_all(phy->base, sysclk_refclk_setting,
+ ARRAY_SIZE(sysclk_refclk_setting));
+ emac_reg_write_all(phy->base, pll_setting, ARRAY_SIZE(pll_setting));
+ emac_reg_write_all(phy->base, cdr_setting, ARRAY_SIZE(cdr_setting));
+ emac_reg_write_all(phy->base, tx_rx_setting, ARRAY_SIZE(tx_rx_setting));
+
+ /* Power up the Ser/Des engine */
+ writel(SERDES_START, phy->base + EMAC_SGMII_PHY_SERDES_START);
+
+ for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
+ if (readl(phy->base + EMAC_QSERDES_COM_RESET_SM) & READY)
+ break;
+ usleep_range(100, 200);
+ }
+
+ if (i == SERDES_START_WAIT_TIMES) {
+ netdev_err(adpt->netdev, "error: ser/des failed to start\n");
+ return -EIO;
+ }
+ /* Mask out all the SGMII Interrupt */
+ writel(0, phy->base + EMAC_SGMII_PHY_INTERRUPT_MASK);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c
new file mode 100644
index 000000000000..f62c215be779
--- /dev/null
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c
@@ -0,0 +1,217 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* Qualcomm Technologies, Inc. QDF2400 EMAC SGMII Controller driver.
+ */
+
+#include <linux/iopoll.h>
+#include "emac.h"
+
+/* EMAC_SGMII register offsets */
+#define EMAC_SGMII_PHY_TX_PWR_CTRL 0x000C
+#define EMAC_SGMII_PHY_LANE_CTRL1 0x0018
+#define EMAC_SGMII_PHY_CDR_CTRL0 0x0058
+#define EMAC_SGMII_PHY_POW_DWN_CTRL0 0x0080
+#define EMAC_SGMII_PHY_RESET_CTRL 0x00a8
+#define EMAC_SGMII_PHY_INTERRUPT_MASK 0x00b4
+
+/* SGMII digital lane registers */
+#define EMAC_SGMII_LN_DRVR_CTRL0 0x000C
+#define EMAC_SGMII_LN_DRVR_TAP_EN 0x0018
+#define EMAC_SGMII_LN_TX_MARGINING 0x001C
+#define EMAC_SGMII_LN_TX_PRE 0x0020
+#define EMAC_SGMII_LN_TX_POST 0x0024
+#define EMAC_SGMII_LN_TX_BAND_MODE 0x0060
+#define EMAC_SGMII_LN_LANE_MODE 0x0064
+#define EMAC_SGMII_LN_PARALLEL_RATE 0x007C
+#define EMAC_SGMII_LN_CML_CTRL_MODE0 0x00C0
+#define EMAC_SGMII_LN_MIXER_CTRL_MODE0 0x00D8
+#define EMAC_SGMII_LN_VGA_INITVAL 0x013C
+#define EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0 0x0184
+#define EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0 0x0190
+#define EMAC_SGMII_LN_UCDR_SO_CONFIG 0x019C
+#define EMAC_SGMII_LN_RX_BAND 0x01A4
+#define EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0 0x01C0
+#define EMAC_SGMII_LN_RSM_CONFIG 0x01F8
+#define EMAC_SGMII_LN_SIGDET_ENABLES 0x0230
+#define EMAC_SGMII_LN_SIGDET_CNTRL 0x0234
+#define EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL 0x0238
+#define EMAC_SGMII_LN_RX_EN_SIGNAL 0x02AC
+#define EMAC_SGMII_LN_RX_MISC_CNTRL0 0x02B8
+#define EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV 0x02C8
+
+/* SGMII digital lane register values */
+#define UCDR_STEP_BY_TWO_MODE0 BIT(7)
+#define UCDR_xO_GAIN_MODE(x) ((x) & 0x7f)
+#define UCDR_ENABLE BIT(6)
+#define UCDR_SO_SATURATION(x) ((x) & 0x3f)
+
+#define SIGDET_LP_BYP_PS4 BIT(7)
+#define SIGDET_EN_PS0_TO_PS2 BIT(6)
+
+#define TXVAL_VALID_INIT BIT(4)
+#define KR_PCIGEN3_MODE BIT(0)
+
+#define MAIN_EN BIT(0)
+
+#define TX_MARGINING_MUX BIT(6)
+#define TX_MARGINING(x) ((x) & 0x3f)
+
+#define TX_PRE_MUX BIT(6)
+
+#define TX_POST_MUX BIT(6)
+
+#define CML_GEAR_MODE(x) (((x) & 7) << 3)
+#define CML2CMOS_IBOOST_MODE(x) ((x) & 7)
+
+#define MIXER_LOADB_MODE(x) (((x) & 0xf) << 2)
+#define MIXER_DATARATE_MODE(x) ((x) & 3)
+
+#define VGA_THRESH_DFE(x) ((x) & 0x3f)
+
+#define SIGDET_LP_BYP_PS0_TO_PS2 BIT(5)
+#define SIGDET_FLT_BYP BIT(0)
+
+#define SIGDET_LVL(x) (((x) & 0xf) << 4)
+
+#define SIGDET_DEGLITCH_CTRL(x) (((x) & 0xf) << 1)
+
+#define INVERT_PCS_RX_CLK BIT(7)
+
+#define DRVR_LOGIC_CLK_EN BIT(4)
+#define DRVR_LOGIC_CLK_DIV(x) ((x) & 0xf)
+
+#define PARALLEL_RATE_MODE0(x) ((x) & 0x3)
+
+#define BAND_MODE0(x) ((x) & 0x3)
+
+#define LANE_MODE(x) ((x) & 0x1f)
+
+#define CDR_PD_SEL_MODE0(x) (((x) & 0x3) << 5)
+#define EN_DLL_MODE0 BIT(4)
+#define EN_IQ_DCC_MODE0 BIT(3)
+#define EN_IQCAL_MODE0 BIT(2)
+
+#define BYPASS_RSM_SAMP_CAL BIT(1)
+#define BYPASS_RSM_DLL_CAL BIT(0)
+
+#define L0_RX_EQUALIZE_ENABLE BIT(6)
+
+#define PWRDN_B BIT(0)
+
+#define CDR_MAX_CNT(x) ((x) & 0xff)
+
+#define SERDES_START_WAIT_TIMES 100
+
+struct emac_reg_write {
+ unsigned int offset;
+ u32 val;
+};
+
+static void emac_reg_write_all(void __iomem *base,
+ const struct emac_reg_write *itr, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; ++itr, ++i)
+ writel(itr->val, base + itr->offset);
+}
+
+static const struct emac_reg_write sgmii_laned[] = {
+ /* CDR Settings */
+ {EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0,
+ UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)},
+ {EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(0)},
+ {EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)},
+
+ /* TX/RX Settings */
+ {EMAC_SGMII_LN_RX_EN_SIGNAL, SIGDET_LP_BYP_PS4 | SIGDET_EN_PS0_TO_PS2},
+
+ {EMAC_SGMII_LN_DRVR_CTRL0, TXVAL_VALID_INIT | KR_PCIGEN3_MODE},
+ {EMAC_SGMII_LN_DRVR_TAP_EN, MAIN_EN},
+ {EMAC_SGMII_LN_TX_MARGINING, TX_MARGINING_MUX | TX_MARGINING(25)},
+ {EMAC_SGMII_LN_TX_PRE, TX_PRE_MUX},
+ {EMAC_SGMII_LN_TX_POST, TX_POST_MUX},
+
+ {EMAC_SGMII_LN_CML_CTRL_MODE0,
+ CML_GEAR_MODE(1) | CML2CMOS_IBOOST_MODE(1)},
+ {EMAC_SGMII_LN_MIXER_CTRL_MODE0,
+ MIXER_LOADB_MODE(12) | MIXER_DATARATE_MODE(1)},
+ {EMAC_SGMII_LN_VGA_INITVAL, VGA_THRESH_DFE(31)},
+ {EMAC_SGMII_LN_SIGDET_ENABLES,
+ SIGDET_LP_BYP_PS0_TO_PS2 | SIGDET_FLT_BYP},
+ {EMAC_SGMII_LN_SIGDET_CNTRL, SIGDET_LVL(8)},
+
+ {EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL, SIGDET_DEGLITCH_CTRL(4)},
+ {EMAC_SGMII_LN_RX_MISC_CNTRL0, INVERT_PCS_RX_CLK},
+ {EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV,
+ DRVR_LOGIC_CLK_EN | DRVR_LOGIC_CLK_DIV(4)},
+
+ {EMAC_SGMII_LN_PARALLEL_RATE, PARALLEL_RATE_MODE0(1)},
+ {EMAC_SGMII_LN_TX_BAND_MODE, BAND_MODE0(1)},
+ {EMAC_SGMII_LN_RX_BAND, BAND_MODE0(2)},
+ {EMAC_SGMII_LN_LANE_MODE, LANE_MODE(26)},
+ {EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0, CDR_PD_SEL_MODE0(2) |
+ EN_DLL_MODE0 | EN_IQ_DCC_MODE0 | EN_IQCAL_MODE0},
+ {EMAC_SGMII_LN_RSM_CONFIG, BYPASS_RSM_SAMP_CAL | BYPASS_RSM_DLL_CAL},
+};
+
+static const struct emac_reg_write physical_coding_sublayer_programming[] = {
+ {EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
+ {EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
+ {EMAC_SGMII_PHY_TX_PWR_CTRL, 0},
+ {EMAC_SGMII_PHY_LANE_CTRL1, L0_RX_EQUALIZE_ENABLE},
+};
+
+int emac_sgmii_init_qdf2400(struct emac_adapter *adpt)
+{
+ struct emac_sgmii *phy = &adpt->phy;
+ void __iomem *phy_regs = phy->base;
+ void __iomem *laned = phy->digital;
+ unsigned int i;
+ u32 lnstatus;
+
+ /* PCS lane-x init */
+ emac_reg_write_all(phy->base, physical_coding_sublayer_programming,
+ ARRAY_SIZE(physical_coding_sublayer_programming));
+
+ /* SGMII lane-x init */
+ emac_reg_write_all(phy->digital, sgmii_laned, ARRAY_SIZE(sgmii_laned));
+
+ /* Power up PCS and start reset lane state machine */
+
+ writel(0, phy_regs + EMAC_SGMII_PHY_RESET_CTRL);
+ writel(1, laned + SGMII_LN_RSM_START);
+
+ /* Wait for c_ready assertion */
+ for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
+ lnstatus = readl(phy_regs + SGMII_PHY_LN_LANE_STATUS);
+ if (lnstatus & BIT(1))
+ break;
+ usleep_range(100, 200);
+ }
+
+ if (i == SERDES_START_WAIT_TIMES) {
+ netdev_err(adpt->netdev, "SGMII failed to start\n");
+ return -EIO;
+ }
+
+ /* Disable digital and SERDES loopback */
+ writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN0);
+ writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN2);
+ writel(0, phy_regs + SGMII_PHY_LN_CDR_CTRL1);
+
+ /* Mask out all the SGMII Interrupt */
+ writel(0, phy_regs + EMAC_SGMII_PHY_INTERRUPT_MASK);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c
new file mode 100644
index 000000000000..b9c0df7bdd15
--- /dev/null
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c
@@ -0,0 +1,210 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* Qualcomm Technologies, Inc. QDF2432 EMAC SGMII Controller driver.
+ */
+
+#include <linux/iopoll.h>
+#include "emac.h"
+
+/* EMAC_SGMII register offsets */
+#define EMAC_SGMII_PHY_TX_PWR_CTRL 0x000C
+#define EMAC_SGMII_PHY_LANE_CTRL1 0x0018
+#define EMAC_SGMII_PHY_CDR_CTRL0 0x0058
+#define EMAC_SGMII_PHY_POW_DWN_CTRL0 0x0080
+#define EMAC_SGMII_PHY_RESET_CTRL 0x00a8
+#define EMAC_SGMII_PHY_INTERRUPT_MASK 0x00b4
+
+/* SGMII digital lane registers */
+#define EMAC_SGMII_LN_DRVR_CTRL0 0x000C
+#define EMAC_SGMII_LN_DRVR_TAP_EN 0x0018
+#define EMAC_SGMII_LN_TX_MARGINING 0x001C
+#define EMAC_SGMII_LN_TX_PRE 0x0020
+#define EMAC_SGMII_LN_TX_POST 0x0024
+#define EMAC_SGMII_LN_TX_BAND_MODE 0x0060
+#define EMAC_SGMII_LN_LANE_MODE 0x0064
+#define EMAC_SGMII_LN_PARALLEL_RATE 0x0078
+#define EMAC_SGMII_LN_CML_CTRL_MODE0 0x00B8
+#define EMAC_SGMII_LN_MIXER_CTRL_MODE0 0x00D0
+#define EMAC_SGMII_LN_VGA_INITVAL 0x0134
+#define EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0 0x017C
+#define EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0 0x0188
+#define EMAC_SGMII_LN_UCDR_SO_CONFIG 0x0194
+#define EMAC_SGMII_LN_RX_BAND 0x019C
+#define EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0 0x01B8
+#define EMAC_SGMII_LN_RSM_CONFIG 0x01F0
+#define EMAC_SGMII_LN_SIGDET_ENABLES 0x0224
+#define EMAC_SGMII_LN_SIGDET_CNTRL 0x0228
+#define EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL 0x022C
+#define EMAC_SGMII_LN_RX_EN_SIGNAL 0x02A0
+#define EMAC_SGMII_LN_RX_MISC_CNTRL0 0x02AC
+#define EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV 0x02BC
+
+/* SGMII digital lane register values */
+#define UCDR_STEP_BY_TWO_MODE0 BIT(7)
+#define UCDR_xO_GAIN_MODE(x) ((x) & 0x7f)
+#define UCDR_ENABLE BIT(6)
+#define UCDR_SO_SATURATION(x) ((x) & 0x3f)
+
+#define SIGDET_LP_BYP_PS4 BIT(7)
+#define SIGDET_EN_PS0_TO_PS2 BIT(6)
+
+#define TXVAL_VALID_INIT BIT(4)
+#define KR_PCIGEN3_MODE BIT(0)
+
+#define MAIN_EN BIT(0)
+
+#define TX_MARGINING_MUX BIT(6)
+#define TX_MARGINING(x) ((x) & 0x3f)
+
+#define TX_PRE_MUX BIT(6)
+
+#define TX_POST_MUX BIT(6)
+
+#define CML_GEAR_MODE(x) (((x) & 7) << 3)
+#define CML2CMOS_IBOOST_MODE(x) ((x) & 7)
+
+#define MIXER_LOADB_MODE(x) (((x) & 0xf) << 2)
+#define MIXER_DATARATE_MODE(x) ((x) & 3)
+
+#define VGA_THRESH_DFE(x) ((x) & 0x3f)
+
+#define SIGDET_LP_BYP_PS0_TO_PS2 BIT(5)
+#define SIGDET_FLT_BYP BIT(0)
+
+#define SIGDET_LVL(x) (((x) & 0xf) << 4)
+
+#define SIGDET_DEGLITCH_CTRL(x) (((x) & 0xf) << 1)
+
+#define DRVR_LOGIC_CLK_EN BIT(4)
+#define DRVR_LOGIC_CLK_DIV(x) ((x) & 0xf)
+
+#define PARALLEL_RATE_MODE0(x) ((x) & 0x3)
+
+#define BAND_MODE0(x) ((x) & 0x3)
+
+#define LANE_MODE(x) ((x) & 0x1f)
+
+#define CDR_PD_SEL_MODE0(x) (((x) & 0x3) << 5)
+#define BYPASS_RSM_SAMP_CAL BIT(1)
+#define BYPASS_RSM_DLL_CAL BIT(0)
+
+#define L0_RX_EQUALIZE_ENABLE BIT(6)
+
+#define PWRDN_B BIT(0)
+
+#define CDR_MAX_CNT(x) ((x) & 0xff)
+
+#define SERDES_START_WAIT_TIMES 100
+
+struct emac_reg_write {
+ unsigned int offset;
+ u32 val;
+};
+
+static void emac_reg_write_all(void __iomem *base,
+ const struct emac_reg_write *itr, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; ++itr, ++i)
+ writel(itr->val, base + itr->offset);
+}
+
+static const struct emac_reg_write sgmii_laned[] = {
+ /* CDR Settings */
+ {EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0,
+ UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)},
+ {EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(0)},
+ {EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)},
+
+ /* TX/RX Settings */
+ {EMAC_SGMII_LN_RX_EN_SIGNAL, SIGDET_LP_BYP_PS4 | SIGDET_EN_PS0_TO_PS2},
+
+ {EMAC_SGMII_LN_DRVR_CTRL0, TXVAL_VALID_INIT | KR_PCIGEN3_MODE},
+ {EMAC_SGMII_LN_DRVR_TAP_EN, MAIN_EN},
+ {EMAC_SGMII_LN_TX_MARGINING, TX_MARGINING_MUX | TX_MARGINING(25)},
+ {EMAC_SGMII_LN_TX_PRE, TX_PRE_MUX},
+ {EMAC_SGMII_LN_TX_POST, TX_POST_MUX},
+
+ {EMAC_SGMII_LN_CML_CTRL_MODE0,
+ CML_GEAR_MODE(1) | CML2CMOS_IBOOST_MODE(1)},
+ {EMAC_SGMII_LN_MIXER_CTRL_MODE0,
+ MIXER_LOADB_MODE(12) | MIXER_DATARATE_MODE(1)},
+ {EMAC_SGMII_LN_VGA_INITVAL, VGA_THRESH_DFE(31)},
+ {EMAC_SGMII_LN_SIGDET_ENABLES,
+ SIGDET_LP_BYP_PS0_TO_PS2 | SIGDET_FLT_BYP},
+ {EMAC_SGMII_LN_SIGDET_CNTRL, SIGDET_LVL(8)},
+
+ {EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL, SIGDET_DEGLITCH_CTRL(4)},
+ {EMAC_SGMII_LN_RX_MISC_CNTRL0, 0},
+ {EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV,
+ DRVR_LOGIC_CLK_EN | DRVR_LOGIC_CLK_DIV(4)},
+
+ {EMAC_SGMII_LN_PARALLEL_RATE, PARALLEL_RATE_MODE0(1)},
+ {EMAC_SGMII_LN_TX_BAND_MODE, BAND_MODE0(2)},
+ {EMAC_SGMII_LN_RX_BAND, BAND_MODE0(3)},
+ {EMAC_SGMII_LN_LANE_MODE, LANE_MODE(26)},
+ {EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0, CDR_PD_SEL_MODE0(3)},
+ {EMAC_SGMII_LN_RSM_CONFIG, BYPASS_RSM_SAMP_CAL | BYPASS_RSM_DLL_CAL},
+};
+
+static const struct emac_reg_write physical_coding_sublayer_programming[] = {
+ {EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
+ {EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
+ {EMAC_SGMII_PHY_TX_PWR_CTRL, 0},
+ {EMAC_SGMII_PHY_LANE_CTRL1, L0_RX_EQUALIZE_ENABLE},
+};
+
+int emac_sgmii_init_qdf2432(struct emac_adapter *adpt)
+{
+ struct emac_sgmii *phy = &adpt->phy;
+ void __iomem *phy_regs = phy->base;
+ void __iomem *laned = phy->digital;
+ unsigned int i;
+ u32 lnstatus;
+
+ /* PCS lane-x init */
+ emac_reg_write_all(phy->base, physical_coding_sublayer_programming,
+ ARRAY_SIZE(physical_coding_sublayer_programming));
+
+ /* SGMII lane-x init */
+ emac_reg_write_all(phy->digital, sgmii_laned, ARRAY_SIZE(sgmii_laned));
+
+ /* Power up PCS and start reset lane state machine */
+
+ writel(0, phy_regs + EMAC_SGMII_PHY_RESET_CTRL);
+ writel(1, laned + SGMII_LN_RSM_START);
+
+ /* Wait for c_ready assertion */
+ for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
+ lnstatus = readl(phy_regs + SGMII_PHY_LN_LANE_STATUS);
+ if (lnstatus & BIT(1))
+ break;
+ usleep_range(100, 200);
+ }
+
+ if (i == SERDES_START_WAIT_TIMES) {
+ netdev_err(adpt->netdev, "SGMII failed to start\n");
+ return -EIO;
+ }
+
+ /* Disable digital and SERDES loopback */
+ writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN0);
+ writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN2);
+ writel(0, phy_regs + SGMII_PHY_LN_CDR_CTRL1);
+
+ /* Mask out all the SGMII Interrupt */
+ writel(0, phy_regs + EMAC_SGMII_PHY_INTERRUPT_MASK);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
index 72fe343c7a36..040b28977ee7 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
@@ -20,491 +20,56 @@
#include "emac-mac.h"
#include "emac-sgmii.h"
-/* EMAC_QSERDES register offsets */
-#define EMAC_QSERDES_COM_SYS_CLK_CTRL 0x000000
-#define EMAC_QSERDES_COM_PLL_CNTRL 0x000014
-#define EMAC_QSERDES_COM_PLL_IP_SETI 0x000018
-#define EMAC_QSERDES_COM_PLL_CP_SETI 0x000024
-#define EMAC_QSERDES_COM_PLL_IP_SETP 0x000028
-#define EMAC_QSERDES_COM_PLL_CP_SETP 0x00002c
-#define EMAC_QSERDES_COM_SYSCLK_EN_SEL 0x000038
-#define EMAC_QSERDES_COM_RESETSM_CNTRL 0x000040
-#define EMAC_QSERDES_COM_PLLLOCK_CMP1 0x000044
-#define EMAC_QSERDES_COM_PLLLOCK_CMP2 0x000048
-#define EMAC_QSERDES_COM_PLLLOCK_CMP3 0x00004c
-#define EMAC_QSERDES_COM_PLLLOCK_CMP_EN 0x000050
-#define EMAC_QSERDES_COM_DEC_START1 0x000064
-#define EMAC_QSERDES_COM_DIV_FRAC_START1 0x000098
-#define EMAC_QSERDES_COM_DIV_FRAC_START2 0x00009c
-#define EMAC_QSERDES_COM_DIV_FRAC_START3 0x0000a0
-#define EMAC_QSERDES_COM_DEC_START2 0x0000a4
-#define EMAC_QSERDES_COM_PLL_CRCTRL 0x0000ac
-#define EMAC_QSERDES_COM_RESET_SM 0x0000bc
-#define EMAC_QSERDES_TX_BIST_MODE_LANENO 0x000100
-#define EMAC_QSERDES_TX_TX_EMP_POST1_LVL 0x000108
-#define EMAC_QSERDES_TX_TX_DRV_LVL 0x00010c
-#define EMAC_QSERDES_TX_LANE_MODE 0x000150
-#define EMAC_QSERDES_TX_TRAN_DRVR_EMP_EN 0x000170
-#define EMAC_QSERDES_RX_CDR_CONTROL 0x000200
-#define EMAC_QSERDES_RX_CDR_CONTROL2 0x000210
-#define EMAC_QSERDES_RX_RX_EQ_GAIN12 0x000230
-
/* EMAC_SGMII register offsets */
-#define EMAC_SGMII_PHY_SERDES_START 0x000000
-#define EMAC_SGMII_PHY_CMN_PWR_CTRL 0x000004
-#define EMAC_SGMII_PHY_RX_PWR_CTRL 0x000008
-#define EMAC_SGMII_PHY_TX_PWR_CTRL 0x00000C
-#define EMAC_SGMII_PHY_LANE_CTRL1 0x000018
-#define EMAC_SGMII_PHY_AUTONEG_CFG2 0x000048
-#define EMAC_SGMII_PHY_CDR_CTRL0 0x000058
-#define EMAC_SGMII_PHY_SPEED_CFG1 0x000074
-#define EMAC_SGMII_PHY_POW_DWN_CTRL0 0x000080
-#define EMAC_SGMII_PHY_RESET_CTRL 0x0000a8
-#define EMAC_SGMII_PHY_IRQ_CMD 0x0000ac
-#define EMAC_SGMII_PHY_INTERRUPT_CLEAR 0x0000b0
-#define EMAC_SGMII_PHY_INTERRUPT_MASK 0x0000b4
-#define EMAC_SGMII_PHY_INTERRUPT_STATUS 0x0000b8
-#define EMAC_SGMII_PHY_RX_CHK_STATUS 0x0000d4
-#define EMAC_SGMII_PHY_AUTONEG0_STATUS 0x0000e0
-#define EMAC_SGMII_PHY_AUTONEG1_STATUS 0x0000e4
-
-/* EMAC_QSERDES_COM_PLL_IP_SETI */
-#define PLL_IPSETI(x) ((x) & 0x3f)
-
-/* EMAC_QSERDES_COM_PLL_CP_SETI */
-#define PLL_CPSETI(x) ((x) & 0xff)
-
-/* EMAC_QSERDES_COM_PLL_IP_SETP */
-#define PLL_IPSETP(x) ((x) & 0x3f)
-
-/* EMAC_QSERDES_COM_PLL_CP_SETP */
-#define PLL_CPSETP(x) ((x) & 0x1f)
-
-/* EMAC_QSERDES_COM_PLL_CRCTRL */
-#define PLL_RCTRL(x) (((x) & 0xf) << 4)
-#define PLL_CCTRL(x) ((x) & 0xf)
-
-/* SGMII v2 PHY registers per lane */
-#define EMAC_SGMII_PHY_LN_OFFSET 0x0400
-
-/* SGMII v2 digital lane registers */
-#define EMAC_SGMII_LN_DRVR_CTRL0 0x00C
-#define EMAC_SGMII_LN_DRVR_TAP_EN 0x018
-#define EMAC_SGMII_LN_TX_MARGINING 0x01C
-#define EMAC_SGMII_LN_TX_PRE 0x020
-#define EMAC_SGMII_LN_TX_POST 0x024
-#define EMAC_SGMII_LN_TX_BAND_MODE 0x060
-#define EMAC_SGMII_LN_LANE_MODE 0x064
-#define EMAC_SGMII_LN_PARALLEL_RATE 0x078
-#define EMAC_SGMII_LN_CML_CTRL_MODE0 0x0B8
-#define EMAC_SGMII_LN_MIXER_CTRL_MODE0 0x0D0
-#define EMAC_SGMII_LN_VGA_INITVAL 0x134
-#define EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0 0x17C
-#define EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0 0x188
-#define EMAC_SGMII_LN_UCDR_SO_CONFIG 0x194
-#define EMAC_SGMII_LN_RX_BAND 0x19C
-#define EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0 0x1B8
-#define EMAC_SGMII_LN_RSM_CONFIG 0x1F0
-#define EMAC_SGMII_LN_SIGDET_ENABLES 0x224
-#define EMAC_SGMII_LN_SIGDET_CNTRL 0x228
-#define EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL 0x22C
-#define EMAC_SGMII_LN_RX_EN_SIGNAL 0x2A0
-#define EMAC_SGMII_LN_RX_MISC_CNTRL0 0x2AC
-#define EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV 0x2BC
-
-/* SGMII v2 digital lane register values */
-#define UCDR_STEP_BY_TWO_MODE0 BIT(7)
-#define UCDR_xO_GAIN_MODE(x) ((x) & 0x7f)
-#define UCDR_ENABLE BIT(6)
-#define UCDR_SO_SATURATION(x) ((x) & 0x3f)
-#define SIGDET_LP_BYP_PS4 BIT(7)
-#define SIGDET_EN_PS0_TO_PS2 BIT(6)
-#define EN_ACCOUPLEVCM_SW_MUX BIT(5)
-#define EN_ACCOUPLEVCM_SW BIT(4)
-#define RX_SYNC_EN BIT(3)
-#define RXTERM_HIGHZ_PS5 BIT(2)
-#define SIGDET_EN_PS3 BIT(1)
-#define EN_ACCOUPLE_VCM_PS3 BIT(0)
-#define UFS_MODE BIT(5)
-#define TXVAL_VALID_INIT BIT(4)
-#define TXVAL_VALID_MUX BIT(3)
-#define TXVAL_VALID BIT(2)
-#define USB3P1_MODE BIT(1)
-#define KR_PCIGEN3_MODE BIT(0)
-#define PRE_EN BIT(3)
-#define POST_EN BIT(2)
-#define MAIN_EN_MUX BIT(1)
-#define MAIN_EN BIT(0)
-#define TX_MARGINING_MUX BIT(6)
-#define TX_MARGINING(x) ((x) & 0x3f)
-#define TX_PRE_MUX BIT(6)
-#define TX_PRE(x) ((x) & 0x3f)
-#define TX_POST_MUX BIT(6)
-#define TX_POST(x) ((x) & 0x3f)
-#define CML_GEAR_MODE(x) (((x) & 7) << 3)
-#define CML2CMOS_IBOOST_MODE(x) ((x) & 7)
-#define MIXER_LOADB_MODE(x) (((x) & 0xf) << 2)
-#define MIXER_DATARATE_MODE(x) ((x) & 3)
-#define VGA_THRESH_DFE(x) ((x) & 0x3f)
-#define SIGDET_LP_BYP_PS0_TO_PS2 BIT(5)
-#define SIGDET_LP_BYP_MUX BIT(4)
-#define SIGDET_LP_BYP BIT(3)
-#define SIGDET_EN_MUX BIT(2)
-#define SIGDET_EN BIT(1)
-#define SIGDET_FLT_BYP BIT(0)
-#define SIGDET_LVL(x) (((x) & 0xf) << 4)
-#define SIGDET_BW_CTRL(x) ((x) & 0xf)
-#define SIGDET_DEGLITCH_CTRL(x) (((x) & 0xf) << 1)
-#define SIGDET_DEGLITCH_BYP BIT(0)
-#define INVERT_PCS_RX_CLK BIT(7)
-#define PWM_EN BIT(6)
-#define RXBIAS_SEL(x) (((x) & 0x3) << 4)
-#define EBDAC_SIGN BIT(3)
-#define EDAC_SIGN BIT(2)
-#define EN_AUXTAP1SIGN_INVERT BIT(1)
-#define EN_DAC_CHOPPING BIT(0)
-#define DRVR_LOGIC_CLK_EN BIT(4)
-#define DRVR_LOGIC_CLK_DIV(x) ((x) & 0xf)
-#define PARALLEL_RATE_MODE2(x) (((x) & 0x3) << 4)
-#define PARALLEL_RATE_MODE1(x) (((x) & 0x3) << 2)
-#define PARALLEL_RATE_MODE0(x) ((x) & 0x3)
-#define BAND_MODE2(x) (((x) & 0x3) << 4)
-#define BAND_MODE1(x) (((x) & 0x3) << 2)
-#define BAND_MODE0(x) ((x) & 0x3)
-#define LANE_SYNC_MODE BIT(5)
-#define LANE_MODE(x) ((x) & 0x1f)
-#define CDR_PD_SEL_MODE0(x) (((x) & 0x3) << 5)
-#define EN_DLL_MODE0 BIT(4)
-#define EN_IQ_DCC_MODE0 BIT(3)
-#define EN_IQCAL_MODE0 BIT(2)
-#define EN_QPATH_MODE0 BIT(1)
-#define EN_EPATH_MODE0 BIT(0)
-#define FORCE_TSYNC_ACK BIT(7)
-#define FORCE_CMN_ACK BIT(6)
-#define FORCE_CMN_READY BIT(5)
-#define EN_RCLK_DEGLITCH BIT(4)
-#define BYPASS_RSM_CDR_RESET BIT(3)
-#define BYPASS_RSM_TSYNC BIT(2)
-#define BYPASS_RSM_SAMP_CAL BIT(1)
-#define BYPASS_RSM_DLL_CAL BIT(0)
-
-/* EMAC_QSERDES_COM_SYS_CLK_CTRL */
-#define SYSCLK_CM BIT(4)
-#define SYSCLK_AC_COUPLE BIT(3)
-
-/* EMAC_QSERDES_COM_PLL_CNTRL */
-#define OCP_EN BIT(5)
-#define PLL_DIV_FFEN BIT(2)
-#define PLL_DIV_ORD BIT(1)
-
-/* EMAC_QSERDES_COM_SYSCLK_EN_SEL */
-#define SYSCLK_SEL_CMOS BIT(3)
-
-/* EMAC_QSERDES_COM_RESETSM_CNTRL */
-#define FRQ_TUNE_MODE BIT(4)
-
-/* EMAC_QSERDES_COM_PLLLOCK_CMP_EN */
-#define PLLLOCK_CMP_EN BIT(0)
-
-/* EMAC_QSERDES_COM_DEC_START1 */
-#define DEC_START1_MUX BIT(7)
-#define DEC_START1(x) ((x) & 0x7f)
-
-/* EMAC_QSERDES_COM_DIV_FRAC_START1 * EMAC_QSERDES_COM_DIV_FRAC_START2 */
-#define DIV_FRAC_START_MUX BIT(7)
-#define DIV_FRAC_START(x) ((x) & 0x7f)
-
-/* EMAC_QSERDES_COM_DIV_FRAC_START3 */
-#define DIV_FRAC_START3_MUX BIT(4)
-#define DIV_FRAC_START3(x) ((x) & 0xf)
-
-/* EMAC_QSERDES_COM_DEC_START2 */
-#define DEC_START2_MUX BIT(1)
-#define DEC_START2 BIT(0)
-
-/* EMAC_QSERDES_COM_RESET_SM */
-#define READY BIT(5)
-
-/* EMAC_QSERDES_TX_TX_EMP_POST1_LVL */
-#define TX_EMP_POST1_LVL_MUX BIT(5)
-#define TX_EMP_POST1_LVL(x) ((x) & 0x1f)
-#define TX_EMP_POST1_LVL_BMSK 0x1f
-#define TX_EMP_POST1_LVL_SHFT 0
-
-/* EMAC_QSERDES_TX_TX_DRV_LVL */
-#define TX_DRV_LVL_MUX BIT(4)
-#define TX_DRV_LVL(x) ((x) & 0xf)
-
-/* EMAC_QSERDES_TX_TRAN_DRVR_EMP_EN */
-#define EMP_EN_MUX BIT(1)
-#define EMP_EN BIT(0)
-
-/* EMAC_QSERDES_RX_CDR_CONTROL & EMAC_QSERDES_RX_CDR_CONTROL2 */
-#define HBW_PD_EN BIT(7)
-#define SECONDORDERENABLE BIT(6)
-#define FIRSTORDER_THRESH(x) (((x) & 0x7) << 3)
-#define SECONDORDERGAIN(x) ((x) & 0x7)
-
-/* EMAC_QSERDES_RX_RX_EQ_GAIN12 */
-#define RX_EQ_GAIN2(x) (((x) & 0xf) << 4)
-#define RX_EQ_GAIN1(x) ((x) & 0xf)
-
-/* EMAC_SGMII_PHY_SERDES_START */
-#define SERDES_START BIT(0)
-
-/* EMAC_SGMII_PHY_CMN_PWR_CTRL */
-#define BIAS_EN BIT(6)
-#define PLL_EN BIT(5)
-#define SYSCLK_EN BIT(4)
-#define CLKBUF_L_EN BIT(3)
-#define PLL_TXCLK_EN BIT(1)
-#define PLL_RXCLK_EN BIT(0)
-
-/* EMAC_SGMII_PHY_RX_PWR_CTRL */
-#define L0_RX_SIGDET_EN BIT(7)
-#define L0_RX_TERM_MODE(x) (((x) & 3) << 4)
-#define L0_RX_I_EN BIT(1)
-
-/* EMAC_SGMII_PHY_TX_PWR_CTRL */
-#define L0_TX_EN BIT(5)
-#define L0_CLKBUF_EN BIT(4)
-#define L0_TRAN_BIAS_EN BIT(1)
-
-/* EMAC_SGMII_PHY_LANE_CTRL1 */
-#define L0_RX_EQUALIZE_ENABLE BIT(6)
-#define L0_RESET_TSYNC_EN BIT(4)
-#define L0_DRV_LVL(x) ((x) & 0xf)
-
-/* EMAC_SGMII_PHY_AUTONEG_CFG2 */
+#define EMAC_SGMII_PHY_AUTONEG_CFG2 0x0048
+#define EMAC_SGMII_PHY_SPEED_CFG1 0x0074
+#define EMAC_SGMII_PHY_IRQ_CMD 0x00ac
+#define EMAC_SGMII_PHY_INTERRUPT_CLEAR 0x00b0
+#define EMAC_SGMII_PHY_INTERRUPT_MASK 0x00b4
+#define EMAC_SGMII_PHY_INTERRUPT_STATUS 0x00b8
+#define EMAC_SGMII_PHY_RX_CHK_STATUS 0x00d4
+
#define FORCE_AN_TX_CFG BIT(5)
#define FORCE_AN_RX_CFG BIT(4)
#define AN_ENABLE BIT(0)
-/* EMAC_SGMII_PHY_SPEED_CFG1 */
#define DUPLEX_MODE BIT(4)
#define SPDMODE_1000 BIT(1)
#define SPDMODE_100 BIT(0)
#define SPDMODE_10 0
-#define SPDMODE_BMSK 3
-#define SPDMODE_SHFT 0
-
-/* EMAC_SGMII_PHY_POW_DWN_CTRL0 */
-#define PWRDN_B BIT(0)
-#define CDR_MAX_CNT(x) ((x) & 0xff)
-
-/* EMAC_QSERDES_TX_BIST_MODE_LANENO */
-#define BIST_LANE_NUMBER(x) (((x) & 3) << 5)
-#define BISTMODE(x) ((x) & 0x1f)
-/* EMAC_QSERDES_COM_PLLLOCK_CMPx */
-#define PLLLOCK_CMP(x) ((x) & 0xff)
+#define CDR_ALIGN_DET BIT(6)
-/* EMAC_SGMII_PHY_RESET_CTRL */
-#define PHY_SW_RESET BIT(0)
-
-/* EMAC_SGMII_PHY_IRQ_CMD */
#define IRQ_GLOBAL_CLEAR BIT(0)
-/* EMAC_SGMII_PHY_INTERRUPT_MASK */
#define DECODE_CODE_ERR BIT(7)
#define DECODE_DISP_ERR BIT(6)
-#define PLL_UNLOCK BIT(5)
-#define AN_ILLEGAL_TERM BIT(4)
-#define SYNC_FAIL BIT(3)
-#define AN_START BIT(2)
-#define AN_END BIT(1)
-#define AN_REQUEST BIT(0)
#define SGMII_PHY_IRQ_CLR_WAIT_TIME 10
-#define SGMII_PHY_INTERRUPT_ERR (\
- DECODE_CODE_ERR |\
- DECODE_DISP_ERR)
-
-#define SGMII_ISR_AN_MASK (\
- AN_REQUEST |\
- AN_START |\
- AN_END |\
- AN_ILLEGAL_TERM |\
- PLL_UNLOCK |\
- SYNC_FAIL)
-
-#define SGMII_ISR_MASK (\
- SGMII_PHY_INTERRUPT_ERR |\
- SGMII_ISR_AN_MASK)
-
-/* SGMII TX_CONFIG */
-#define TXCFG_LINK 0x8000
-#define TXCFG_MODE_BMSK 0x1c00
-#define TXCFG_1000_FULL 0x1800
-#define TXCFG_100_FULL 0x1400
-#define TXCFG_100_HALF 0x0400
-#define TXCFG_10_FULL 0x1000
-#define TXCFG_10_HALF 0x0000
+#define SGMII_PHY_INTERRUPT_ERR (DECODE_CODE_ERR | DECODE_DISP_ERR)
+#define SGMII_ISR_MASK (SGMII_PHY_INTERRUPT_ERR)
#define SERDES_START_WAIT_TIMES 100
-struct emac_reg_write {
- unsigned int offset;
- u32 val;
-};
-
-static void emac_reg_write_all(void __iomem *base,
- const struct emac_reg_write *itr, size_t size)
-{
- size_t i;
-
- for (i = 0; i < size; ++itr, ++i)
- writel(itr->val, base + itr->offset);
-}
-
-static const struct emac_reg_write physical_coding_sublayer_programming_v1[] = {
- {EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
- {EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
- {EMAC_SGMII_PHY_CMN_PWR_CTRL,
- BIAS_EN | SYSCLK_EN | CLKBUF_L_EN | PLL_TXCLK_EN | PLL_RXCLK_EN},
- {EMAC_SGMII_PHY_TX_PWR_CTRL, L0_TX_EN | L0_CLKBUF_EN | L0_TRAN_BIAS_EN},
- {EMAC_SGMII_PHY_RX_PWR_CTRL,
- L0_RX_SIGDET_EN | L0_RX_TERM_MODE(1) | L0_RX_I_EN},
- {EMAC_SGMII_PHY_CMN_PWR_CTRL,
- BIAS_EN | PLL_EN | SYSCLK_EN | CLKBUF_L_EN | PLL_TXCLK_EN |
- PLL_RXCLK_EN},
- {EMAC_SGMII_PHY_LANE_CTRL1,
- L0_RX_EQUALIZE_ENABLE | L0_RESET_TSYNC_EN | L0_DRV_LVL(15)},
-};
-
-static const struct emac_reg_write sysclk_refclk_setting[] = {
- {EMAC_QSERDES_COM_SYSCLK_EN_SEL, SYSCLK_SEL_CMOS},
- {EMAC_QSERDES_COM_SYS_CLK_CTRL, SYSCLK_CM | SYSCLK_AC_COUPLE},
-};
-
-static const struct emac_reg_write pll_setting[] = {
- {EMAC_QSERDES_COM_PLL_IP_SETI, PLL_IPSETI(1)},
- {EMAC_QSERDES_COM_PLL_CP_SETI, PLL_CPSETI(59)},
- {EMAC_QSERDES_COM_PLL_IP_SETP, PLL_IPSETP(10)},
- {EMAC_QSERDES_COM_PLL_CP_SETP, PLL_CPSETP(9)},
- {EMAC_QSERDES_COM_PLL_CRCTRL, PLL_RCTRL(15) | PLL_CCTRL(11)},
- {EMAC_QSERDES_COM_PLL_CNTRL, OCP_EN | PLL_DIV_FFEN | PLL_DIV_ORD},
- {EMAC_QSERDES_COM_DEC_START1, DEC_START1_MUX | DEC_START1(2)},
- {EMAC_QSERDES_COM_DEC_START2, DEC_START2_MUX | DEC_START2},
- {EMAC_QSERDES_COM_DIV_FRAC_START1,
- DIV_FRAC_START_MUX | DIV_FRAC_START(85)},
- {EMAC_QSERDES_COM_DIV_FRAC_START2,
- DIV_FRAC_START_MUX | DIV_FRAC_START(42)},
- {EMAC_QSERDES_COM_DIV_FRAC_START3,
- DIV_FRAC_START3_MUX | DIV_FRAC_START3(3)},
- {EMAC_QSERDES_COM_PLLLOCK_CMP1, PLLLOCK_CMP(43)},
- {EMAC_QSERDES_COM_PLLLOCK_CMP2, PLLLOCK_CMP(104)},
- {EMAC_QSERDES_COM_PLLLOCK_CMP3, PLLLOCK_CMP(0)},
- {EMAC_QSERDES_COM_PLLLOCK_CMP_EN, PLLLOCK_CMP_EN},
- {EMAC_QSERDES_COM_RESETSM_CNTRL, FRQ_TUNE_MODE},
-};
-
-static const struct emac_reg_write cdr_setting[] = {
- {EMAC_QSERDES_RX_CDR_CONTROL,
- SECONDORDERENABLE | FIRSTORDER_THRESH(3) | SECONDORDERGAIN(2)},
- {EMAC_QSERDES_RX_CDR_CONTROL2,
- SECONDORDERENABLE | FIRSTORDER_THRESH(3) | SECONDORDERGAIN(4)},
-};
-
-static const struct emac_reg_write tx_rx_setting[] = {
- {EMAC_QSERDES_TX_BIST_MODE_LANENO, 0},
- {EMAC_QSERDES_TX_TX_DRV_LVL, TX_DRV_LVL_MUX | TX_DRV_LVL(15)},
- {EMAC_QSERDES_TX_TRAN_DRVR_EMP_EN, EMP_EN_MUX | EMP_EN},
- {EMAC_QSERDES_TX_TX_EMP_POST1_LVL,
- TX_EMP_POST1_LVL_MUX | TX_EMP_POST1_LVL(1)},
- {EMAC_QSERDES_RX_RX_EQ_GAIN12, RX_EQ_GAIN2(15) | RX_EQ_GAIN1(15)},
- {EMAC_QSERDES_TX_LANE_MODE, LANE_MODE(8)},
-};
-
-static const struct emac_reg_write sgmii_v2_laned[] = {
- /* CDR Settings */
- {EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0,
- UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)},
- {EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(0)},
- {EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)},
-
- /* TX/RX Settings */
- {EMAC_SGMII_LN_RX_EN_SIGNAL, SIGDET_LP_BYP_PS4 | SIGDET_EN_PS0_TO_PS2},
-
- {EMAC_SGMII_LN_DRVR_CTRL0, TXVAL_VALID_INIT | KR_PCIGEN3_MODE},
- {EMAC_SGMII_LN_DRVR_TAP_EN, MAIN_EN},
- {EMAC_SGMII_LN_TX_MARGINING, TX_MARGINING_MUX | TX_MARGINING(25)},
- {EMAC_SGMII_LN_TX_PRE, TX_PRE_MUX},
- {EMAC_SGMII_LN_TX_POST, TX_POST_MUX},
-
- {EMAC_SGMII_LN_CML_CTRL_MODE0,
- CML_GEAR_MODE(1) | CML2CMOS_IBOOST_MODE(1)},
- {EMAC_SGMII_LN_MIXER_CTRL_MODE0,
- MIXER_LOADB_MODE(12) | MIXER_DATARATE_MODE(1)},
- {EMAC_SGMII_LN_VGA_INITVAL, VGA_THRESH_DFE(31)},
- {EMAC_SGMII_LN_SIGDET_ENABLES,
- SIGDET_LP_BYP_PS0_TO_PS2 | SIGDET_FLT_BYP},
- {EMAC_SGMII_LN_SIGDET_CNTRL, SIGDET_LVL(8)},
-
- {EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL, SIGDET_DEGLITCH_CTRL(4)},
- {EMAC_SGMII_LN_RX_MISC_CNTRL0, 0},
- {EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV,
- DRVR_LOGIC_CLK_EN | DRVR_LOGIC_CLK_DIV(4)},
-
- {EMAC_SGMII_LN_PARALLEL_RATE, PARALLEL_RATE_MODE0(1)},
- {EMAC_SGMII_LN_TX_BAND_MODE, BAND_MODE0(2)},
- {EMAC_SGMII_LN_RX_BAND, BAND_MODE0(3)},
- {EMAC_SGMII_LN_LANE_MODE, LANE_MODE(26)},
- {EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0, CDR_PD_SEL_MODE0(3)},
- {EMAC_SGMII_LN_RSM_CONFIG, BYPASS_RSM_SAMP_CAL | BYPASS_RSM_DLL_CAL},
-};
-
-static const struct emac_reg_write physical_coding_sublayer_programming_v2[] = {
- {EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
- {EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
- {EMAC_SGMII_PHY_TX_PWR_CTRL, 0},
- {EMAC_SGMII_PHY_LANE_CTRL1, L0_RX_EQUALIZE_ENABLE},
-};
-
-static int emac_sgmii_link_init(struct emac_adapter *adpt)
+/* Initialize the SGMII link between the internal and external PHYs. */
+static void emac_sgmii_link_init(struct emac_adapter *adpt)
{
- struct phy_device *phydev = adpt->phydev;
- struct emac_phy *phy = &adpt->phy;
+ struct emac_sgmii *phy = &adpt->phy;
u32 val;
+ /* Always use autonegotiation. It works no matter how the external
+ * PHY is configured.
+ */
val = readl(phy->base + EMAC_SGMII_PHY_AUTONEG_CFG2);
-
- if (phydev->autoneg == AUTONEG_ENABLE) {
- val &= ~(FORCE_AN_RX_CFG | FORCE_AN_TX_CFG);
- val |= AN_ENABLE;
- writel(val, phy->base + EMAC_SGMII_PHY_AUTONEG_CFG2);
- } else {
- u32 speed_cfg;
-
- switch (phydev->speed) {
- case SPEED_10:
- speed_cfg = SPDMODE_10;
- break;
- case SPEED_100:
- speed_cfg = SPDMODE_100;
- break;
- case SPEED_1000:
- speed_cfg = SPDMODE_1000;
- break;
- default:
- return -EINVAL;
- }
-
- if (phydev->duplex == DUPLEX_FULL)
- speed_cfg |= DUPLEX_MODE;
-
- val &= ~AN_ENABLE;
- writel(speed_cfg, phy->base + EMAC_SGMII_PHY_SPEED_CFG1);
- writel(val, phy->base + EMAC_SGMII_PHY_AUTONEG_CFG2);
- }
-
- return 0;
+ val &= ~(FORCE_AN_RX_CFG | FORCE_AN_TX_CFG);
+ val |= AN_ENABLE;
+ writel(val, phy->base + EMAC_SGMII_PHY_AUTONEG_CFG2);
}
static int emac_sgmii_irq_clear(struct emac_adapter *adpt, u32 irq_bits)
{
- struct emac_phy *phy = &adpt->phy;
+ struct emac_sgmii *phy = &adpt->phy;
u32 status;
writel_relaxed(irq_bits, phy->base + EMAC_SGMII_PHY_INTERRUPT_CLEAR);
@@ -536,101 +101,54 @@ static int emac_sgmii_irq_clear(struct emac_adapter *adpt, u32 irq_bits)
return 0;
}
-int emac_sgmii_init_v1(struct emac_adapter *adpt)
-{
- struct emac_phy *phy = &adpt->phy;
- unsigned int i;
- int ret;
+/* The number of decode errors that triggers a reset */
+#define DECODE_ERROR_LIMIT 2
- ret = emac_sgmii_link_init(adpt);
- if (ret)
- return ret;
-
- emac_reg_write_all(phy->base, physical_coding_sublayer_programming_v1,
- ARRAY_SIZE(physical_coding_sublayer_programming_v1));
- emac_reg_write_all(phy->base, sysclk_refclk_setting,
- ARRAY_SIZE(sysclk_refclk_setting));
- emac_reg_write_all(phy->base, pll_setting, ARRAY_SIZE(pll_setting));
- emac_reg_write_all(phy->base, cdr_setting, ARRAY_SIZE(cdr_setting));
- emac_reg_write_all(phy->base, tx_rx_setting,
- ARRAY_SIZE(tx_rx_setting));
-
- /* Power up the Ser/Des engine */
- writel(SERDES_START, phy->base + EMAC_SGMII_PHY_SERDES_START);
-
- for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
- if (readl(phy->base + EMAC_QSERDES_COM_RESET_SM) & READY)
- break;
- usleep_range(100, 200);
- }
-
- if (i == SERDES_START_WAIT_TIMES) {
- netdev_err(adpt->netdev, "error: ser/des failed to start\n");
- return -EIO;
- }
- /* Mask out all the SGMII Interrupt */
- writel(0, phy->base + EMAC_SGMII_PHY_INTERRUPT_MASK);
-
- emac_sgmii_irq_clear(adpt, SGMII_PHY_INTERRUPT_ERR);
-
- return 0;
-}
-
-int emac_sgmii_init_v2(struct emac_adapter *adpt)
+static irqreturn_t emac_sgmii_interrupt(int irq, void *data)
{
- struct emac_phy *phy = &adpt->phy;
- void __iomem *phy_regs = phy->base;
- void __iomem *laned = phy->digital;
- unsigned int i;
- u32 lnstatus;
- int ret;
-
- ret = emac_sgmii_link_init(adpt);
- if (ret)
- return ret;
-
- /* PCS lane-x init */
- emac_reg_write_all(phy->base, physical_coding_sublayer_programming_v2,
- ARRAY_SIZE(physical_coding_sublayer_programming_v2));
-
- /* SGMII lane-x init */
- emac_reg_write_all(phy->digital,
- sgmii_v2_laned, ARRAY_SIZE(sgmii_v2_laned));
-
- /* Power up PCS and start reset lane state machine */
+ struct emac_adapter *adpt = data;
+ struct emac_sgmii *phy = &adpt->phy;
+ u32 status;
- writel(0, phy_regs + EMAC_SGMII_PHY_RESET_CTRL);
- writel(1, laned + SGMII_LN_RSM_START);
+ status = readl(phy->base + EMAC_SGMII_PHY_INTERRUPT_STATUS);
+ status &= SGMII_ISR_MASK;
+ if (!status)
+ return IRQ_HANDLED;
- /* Wait for c_ready assertion */
- for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
- lnstatus = readl(phy_regs + SGMII_PHY_LN_LANE_STATUS);
- if (lnstatus & BIT(1))
- break;
- usleep_range(100, 200);
+ /* If we get a decoding error and CDR is not locked, then try
+ * resetting the internal PHY. The internal PHY uses an embedded
+ * clock with Clock and Data Recovery (CDR) to recover the
+ * clock and data.
+ */
+ if (status & SGMII_PHY_INTERRUPT_ERR) {
+ int count;
+
+ /* The SGMII is capable of recovering from some decode
+ * errors automatically. However, if we get multiple
+ * decode errors in a row, then assume that something
+ * is wrong and reset the interface.
+ */
+ count = atomic_inc_return(&phy->decode_error_count);
+ if (count == DECODE_ERROR_LIMIT) {
+ schedule_work(&adpt->work_thread);
+ atomic_set(&phy->decode_error_count, 0);
+ }
+ } else {
+ /* We only care about consecutive decode errors. */
+ atomic_set(&phy->decode_error_count, 0);
}
- if (i == SERDES_START_WAIT_TIMES) {
- netdev_err(adpt->netdev, "SGMII failed to start\n");
- return -EIO;
+ if (emac_sgmii_irq_clear(adpt, status)) {
+ netdev_warn(adpt->netdev, "failed to clear SGMII interrupt\n");
+ schedule_work(&adpt->work_thread);
}
- /* Disable digital and SERDES loopback */
- writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN0);
- writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN2);
- writel(0, phy_regs + SGMII_PHY_LN_CDR_CTRL1);
-
- /* Mask out all the SGMII Interrupt */
- writel(0, phy_regs + EMAC_SGMII_PHY_INTERRUPT_MASK);
-
- emac_sgmii_irq_clear(adpt, SGMII_PHY_INTERRUPT_ERR);
-
- return 0;
+ return IRQ_HANDLED;
}
static void emac_sgmii_reset_prepare(struct emac_adapter *adpt)
{
- struct emac_phy *phy = &adpt->phy;
+ struct emac_sgmii *phy = &adpt->phy;
u32 val;
/* Reset PHY */
@@ -651,44 +169,129 @@ void emac_sgmii_reset(struct emac_adapter *adpt)
{
int ret;
- clk_set_rate(adpt->clk[EMAC_CLK_HIGH_SPEED], 19200000);
emac_sgmii_reset_prepare(adpt);
+ emac_sgmii_link_init(adpt);
ret = adpt->phy.initialize(adpt);
if (ret)
netdev_err(adpt->netdev,
"could not reinitialize internal PHY (error=%i)\n",
ret);
+}
- clk_set_rate(adpt->clk[EMAC_CLK_HIGH_SPEED], 125000000);
+static int emac_sgmii_open(struct emac_adapter *adpt)
+{
+ struct emac_sgmii *sgmii = &adpt->phy;
+ int ret;
+
+ if (sgmii->irq) {
+ /* Make sure interrupts are cleared and disabled first */
+ ret = emac_sgmii_irq_clear(adpt, 0xff);
+ if (ret)
+ return ret;
+ writel(0, sgmii->base + EMAC_SGMII_PHY_INTERRUPT_MASK);
+
+ ret = request_irq(sgmii->irq, emac_sgmii_interrupt, 0,
+ "emac-sgmii", adpt);
+ if (ret) {
+ netdev_err(adpt->netdev,
+ "could not register handler for internal PHY\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int emac_sgmii_close(struct emac_adapter *adpt)
+{
+ struct emac_sgmii *sgmii = &adpt->phy;
+
+ /* Make sure interrupts are disabled */
+ writel(0, sgmii->base + EMAC_SGMII_PHY_INTERRUPT_MASK);
+ free_irq(sgmii->irq, adpt);
+
+ return 0;
+}
+
+/* The error interrupts are only valid after the link is up */
+static int emac_sgmii_link_up(struct emac_adapter *adpt)
+{
+ struct emac_sgmii *sgmii = &adpt->phy;
+ int ret;
+
+ /* Clear and enable interrupts */
+ ret = emac_sgmii_irq_clear(adpt, 0xff);
+ if (ret)
+ return ret;
+
+ writel(SGMII_ISR_MASK, sgmii->base + EMAC_SGMII_PHY_INTERRUPT_MASK);
+
+ return 0;
+}
+
+static int emac_sgmii_link_down(struct emac_adapter *adpt)
+{
+ struct emac_sgmii *sgmii = &adpt->phy;
+
+ /* Disable interrupts */
+ writel(0, sgmii->base + EMAC_SGMII_PHY_INTERRUPT_MASK);
+ synchronize_irq(sgmii->irq);
+
+ return 0;
}
static int emac_sgmii_acpi_match(struct device *dev, void *data)
{
+#ifdef CONFIG_ACPI
static const struct acpi_device_id match_table[] = {
{
.id = "QCOM8071",
- .driver_data = (kernel_ulong_t)emac_sgmii_init_v2,
},
{}
};
const struct acpi_device_id *id = acpi_match_device(match_table, dev);
- emac_sgmii_initialize *initialize = data;
+ emac_sgmii_function *initialize = data;
+
+ if (id) {
+ acpi_handle handle = ACPI_HANDLE(dev);
+ unsigned long long hrv;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(handle, "_HRV", NULL, &hrv);
+ if (status) {
+ if (status == AE_NOT_FOUND)
+ /* Older versions of the QDF2432 ACPI tables do
+ * not have an _HRV property.
+ */
+ hrv = 1;
+ else
+ /* Something is wrong with the tables */
+ return 0;
+ }
- if (id)
- *initialize = (emac_sgmii_initialize)id->driver_data;
+ switch (hrv) {
+ case 1:
+ *initialize = emac_sgmii_init_qdf2432;
+ return 1;
+ case 2:
+ *initialize = emac_sgmii_init_qdf2400;
+ return 1;
+ }
+ }
+#endif
- return !!id;
+ return 0;
}
static const struct of_device_id emac_sgmii_dt_match[] = {
{
.compatible = "qcom,fsm9900-emac-sgmii",
- .data = emac_sgmii_init_v1,
+ .data = emac_sgmii_init_fsm9900,
},
{
.compatible = "qcom,qdf2432-emac-sgmii",
- .data = emac_sgmii_init_v2,
+ .data = emac_sgmii_init_qdf2432,
},
{}
};
@@ -696,7 +299,7 @@ static const struct of_device_id emac_sgmii_dt_match[] = {
int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt)
{
struct platform_device *sgmii_pdev = NULL;
- struct emac_phy *phy = &adpt->phy;
+ struct emac_sgmii *phy = &adpt->phy;
struct resource *res;
int ret;
@@ -735,9 +338,14 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt)
goto error_put_device;
}
- phy->initialize = (emac_sgmii_initialize)match->data;
+ phy->initialize = (emac_sgmii_function)match->data;
}
+ phy->open = emac_sgmii_open;
+ phy->close = emac_sgmii_close;
+ phy->link_up = emac_sgmii_link_up;
+ phy->link_down = emac_sgmii_link_down;
+
/* Base address is the first address */
res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -765,6 +373,12 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt)
if (ret)
goto error;
+ emac_sgmii_link_init(adpt);
+
+ ret = platform_get_irq(sgmii_pdev, 0);
+ if (ret > 0)
+ phy->irq = ret;
+
/* We've remapped the addresses, so we don't need the device any
* more. of_find_device_by_node() says we should release it.
*/
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h
index ce79212ff403..e7c0c3b2baa4 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h
@@ -16,9 +16,36 @@
struct emac_adapter;
struct platform_device;
-int emac_sgmii_init_v1(struct emac_adapter *adpt);
-int emac_sgmii_init_v2(struct emac_adapter *adpt);
+typedef int (*emac_sgmii_function)(struct emac_adapter *adpt);
+
+/** emac_sgmii - internal emac phy
+ * @base base address
+ * @digital per-lane digital block
+ * @irq the interrupt number
+ * @decode_error_count reference count of consecutive decode errors
+ * @initialize initialization function
+ * @open called when the driver is opened
+ * @close called when the driver is closed
+ * @link_up called when the link comes up
+ * @link_down called when the link comes down
+ */
+struct emac_sgmii {
+ void __iomem *base;
+ void __iomem *digital;
+ unsigned int irq;
+ atomic_t decode_error_count;
+ emac_sgmii_function initialize;
+ emac_sgmii_function open;
+ emac_sgmii_function close;
+ emac_sgmii_function link_up;
+ emac_sgmii_function link_down;
+};
+
int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt);
void emac_sgmii_reset(struct emac_adapter *adpt);
+int emac_sgmii_init_fsm9900(struct emac_adapter *adpt);
+int emac_sgmii_init_qdf2432(struct emac_adapter *adpt);
+int emac_sgmii_init_qdf2400(struct emac_adapter *adpt);
+
#endif
diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c
index 57b35aeac51a..28a8cdc36485 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac.c
@@ -129,7 +129,7 @@ static int emac_napi_rtx(struct napi_struct *napi, int budget)
emac_mac_rx_process(adpt, rx_q, &work_done, budget);
if (work_done < budget) {
- napi_complete(napi);
+ napi_complete_done(napi, work_done);
irq->mask |= rx_q->intr;
writel(irq->mask, adpt->base + EMAC_INT_MASK);
@@ -239,15 +239,8 @@ static void emac_rx_mode_set(struct net_device *netdev)
/* Change the Maximum Transfer Unit (MTU) */
static int emac_change_mtu(struct net_device *netdev, int new_mtu)
{
- unsigned int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
struct emac_adapter *adpt = netdev_priv(netdev);
- if ((max_frame < EMAC_MIN_ETH_FRAME_SIZE) ||
- (max_frame > EMAC_MAX_ETH_FRAME_SIZE)) {
- netdev_err(adpt->netdev, "error: invalid MTU setting\n");
- return -EINVAL;
- }
-
netif_info(adpt, hw, adpt->netdev,
"changing MTU from %d to %d\n", netdev->mtu,
new_mtu);
@@ -263,22 +256,37 @@ static int emac_change_mtu(struct net_device *netdev, int new_mtu)
static int emac_open(struct net_device *netdev)
{
struct emac_adapter *adpt = netdev_priv(netdev);
+ struct emac_irq *irq = &adpt->irq;
int ret;
+ ret = request_irq(irq->irq, emac_isr, 0, "emac-core0", irq);
+ if (ret) {
+ netdev_err(adpt->netdev, "could not request emac-core0 irq\n");
+ return ret;
+ }
+
/* allocate rx/tx dma buffer & descriptors */
ret = emac_mac_rx_tx_rings_alloc_all(adpt);
if (ret) {
netdev_err(adpt->netdev, "error allocating rx/tx rings\n");
+ free_irq(irq->irq, irq);
return ret;
}
ret = emac_mac_up(adpt);
if (ret) {
emac_mac_rx_tx_rings_free_all(adpt);
+ free_irq(irq->irq, irq);
return ret;
}
- emac_mac_start(adpt);
+ ret = adpt->phy.open(adpt);
+ if (ret) {
+ emac_mac_down(adpt);
+ emac_mac_rx_tx_rings_free_all(adpt);
+ free_irq(irq->irq, irq);
+ return ret;
+ }
return 0;
}
@@ -290,9 +298,12 @@ static int emac_close(struct net_device *netdev)
mutex_lock(&adpt->reset_lock);
+ adpt->phy.close(adpt);
emac_mac_down(adpt);
emac_mac_rx_tx_rings_free_all(adpt);
+ free_irq(adpt->irq.irq, &adpt->irq);
+
mutex_unlock(&adpt->reset_lock);
return 0;
@@ -318,45 +329,56 @@ static int emac_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
return phy_mii_ioctl(netdev->phydev, ifr, cmd);
}
-/* Provide network statistics info for the interface */
-static struct rtnl_link_stats64 *emac_get_stats64(struct net_device *netdev,
- struct rtnl_link_stats64 *net_stats)
+/**
+ * emac_update_hw_stats - read the EMAC stat registers
+ *
+ * Reads the stats registers and write the values to adpt->stats.
+ *
+ * adpt->stats.lock must be held while calling this function,
+ * and while reading from adpt->stats.
+ */
+void emac_update_hw_stats(struct emac_adapter *adpt)
{
- struct emac_adapter *adpt = netdev_priv(netdev);
- unsigned int addr = REG_MAC_RX_STATUS_BIN;
struct emac_stats *stats = &adpt->stats;
u64 *stats_itr = &adpt->stats.rx_ok;
- u32 val;
-
- spin_lock(&stats->lock);
+ void __iomem *base = adpt->base;
+ unsigned int addr;
+ addr = REG_MAC_RX_STATUS_BIN;
while (addr <= REG_MAC_RX_STATUS_END) {
- val = readl_relaxed(adpt->base + addr);
- *stats_itr += val;
+ *stats_itr += readl_relaxed(base + addr);
stats_itr++;
addr += sizeof(u32);
}
/* additional rx status */
- val = readl_relaxed(adpt->base + EMAC_RXMAC_STATC_REG23);
- adpt->stats.rx_crc_align += val;
- val = readl_relaxed(adpt->base + EMAC_RXMAC_STATC_REG24);
- adpt->stats.rx_jabbers += val;
+ stats->rx_crc_align += readl_relaxed(base + EMAC_RXMAC_STATC_REG23);
+ stats->rx_jabbers += readl_relaxed(base + EMAC_RXMAC_STATC_REG24);
/* update tx status */
addr = REG_MAC_TX_STATUS_BIN;
- stats_itr = &adpt->stats.tx_ok;
+ stats_itr = &stats->tx_ok;
while (addr <= REG_MAC_TX_STATUS_END) {
- val = readl_relaxed(adpt->base + addr);
- *stats_itr += val;
- ++stats_itr;
+ *stats_itr += readl_relaxed(base + addr);
+ stats_itr++;
addr += sizeof(u32);
}
/* additional tx status */
- val = readl_relaxed(adpt->base + EMAC_TXMAC_STATC_REG25);
- adpt->stats.tx_col += val;
+ stats->tx_col += readl_relaxed(base + EMAC_TXMAC_STATC_REG25);
+}
+
+/* Provide network statistics info for the interface */
+static void emac_get_stats64(struct net_device *netdev,
+ struct rtnl_link_stats64 *net_stats)
+{
+ struct emac_adapter *adpt = netdev_priv(netdev);
+ struct emac_stats *stats = &adpt->stats;
+
+ spin_lock(&stats->lock);
+
+ emac_update_hw_stats(adpt);
/* return parsed statistics */
net_stats->rx_packets = stats->rx_ok;
@@ -384,8 +406,6 @@ static struct rtnl_link_stats64 *emac_get_stats64(struct net_device *netdev,
net_stats->tx_window_errors = stats->tx_late_col;
spin_unlock(&stats->lock);
-
- return net_stats;
}
static const struct net_device_ops emac_netdev_ops = {
@@ -416,6 +436,10 @@ static void emac_init_adapter(struct emac_adapter *adpt)
{
u32 reg;
+ adpt->rrd_size = EMAC_RRD_SIZE;
+ adpt->tpd_size = EMAC_TPD_SIZE;
+ adpt->rfd_size = EMAC_RFD_SIZE;
+
/* descriptors */
adpt->tx_desc_cnt = EMAC_DEF_TX_DESCS;
adpt->rx_desc_cnt = EMAC_DEF_RX_DESCS;
@@ -436,6 +460,9 @@ static void emac_init_adapter(struct emac_adapter *adpt)
/* others */
adpt->preamble = EMAC_PREAMBLE_DEF;
+
+ /* default to automatic flow control */
+ adpt->automatic = true;
}
/* Get the clock */
@@ -467,6 +494,12 @@ static int emac_clks_phase1_init(struct platform_device *pdev,
{
int ret;
+ /* On ACPI platforms, clocks are controlled by firmware and/or
+ * ACPI, not by drivers.
+ */
+ if (has_acpi_companion(&pdev->dev))
+ return 0;
+
ret = emac_clks_get(pdev, adpt);
if (ret)
return ret;
@@ -492,6 +525,9 @@ static int emac_clks_phase2_init(struct platform_device *pdev,
{
int ret;
+ if (has_acpi_companion(&pdev->dev))
+ return 0;
+
ret = clk_set_rate(adpt->clk[EMAC_CLK_TX], 125000000);
if (ret)
return ret;
@@ -591,7 +627,7 @@ static int emac_probe(struct platform_device *pdev)
{
struct net_device *netdev;
struct emac_adapter *adpt;
- struct emac_phy *phy;
+ struct emac_sgmii *phy;
u16 devid, revid;
u32 reg;
int ret;
@@ -618,12 +654,14 @@ static int emac_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
+ emac_set_ethtool_ops(netdev);
adpt = netdev_priv(netdev);
adpt->netdev = netdev;
adpt->msg_enable = EMAC_MSG_DEFAULT;
phy = &adpt->phy;
+ atomic_set(&phy->decode_error_count, 0);
mutex_init(&adpt->reset_lock);
spin_lock_init(&adpt->stats.lock);
@@ -644,10 +682,6 @@ static int emac_probe(struct platform_device *pdev)
netdev->watchdog_timeo = EMAC_WATCHDOG_TIME;
netdev->irq = adpt->irq.irq;
- adpt->rrd_size = EMAC_RRD_SIZE;
- adpt->tpd_size = EMAC_TPD_SIZE;
- adpt->rfd_size = EMAC_RFD_SIZE;
-
netdev->netdev_ops = &emac_netdev_ops;
emac_init_adapter(adpt);
@@ -680,6 +714,12 @@ static int emac_probe(struct platform_device *pdev)
netdev->vlan_features |= NETIF_F_SG | NETIF_F_HW_CSUM |
NETIF_F_TSO | NETIF_F_TSO6;
+ /* MTU range: 46 - 9194 */
+ netdev->min_mtu = EMAC_MIN_ETH_FRAME_SIZE -
+ (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
+ netdev->max_mtu = EMAC_MAX_ETH_FRAME_SIZE -
+ (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
+
INIT_WORK(&adpt->work_thread, emac_work_thread);
/* Initialize queues */
@@ -711,8 +751,7 @@ static int emac_probe(struct platform_device *pdev)
err_undo_napi:
netif_napi_del(&adpt->rx_q.napi);
err_undo_mdiobus:
- if (!has_acpi_companion(&pdev->dev))
- put_device(&adpt->phydev->mdio.dev);
+ put_device(&adpt->phydev->mdio.dev);
mdiobus_unregister(adpt->mii_bus);
err_undo_clocks:
emac_clks_teardown(adpt);
@@ -732,8 +771,7 @@ static int emac_remove(struct platform_device *pdev)
emac_clks_teardown(adpt);
- if (!has_acpi_companion(&pdev->dev))
- put_device(&adpt->phydev->mdio.dev);
+ put_device(&adpt->phydev->mdio.dev);
mdiobus_unregister(adpt->mii_bus);
free_netdev(netdev);
diff --git a/drivers/net/ethernet/qualcomm/emac/emac.h b/drivers/net/ethernet/qualcomm/emac/emac.h
index 0c76e6cb8c9e..8ee4ec6aef2e 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac.h
+++ b/drivers/net/ethernet/qualcomm/emac/emac.h
@@ -19,37 +19,88 @@
#include <linux/platform_device.h>
#include "emac-mac.h"
#include "emac-phy.h"
+#include "emac-sgmii.h"
/* EMAC base register offsets */
-#define EMAC_DMA_MAS_CTRL 0x001400
-#define EMAC_IRQ_MOD_TIM_INIT 0x001408
-#define EMAC_BLK_IDLE_STS 0x00140c
-#define EMAC_PHY_LINK_DELAY 0x00141c
-#define EMAC_SYS_ALIV_CTRL 0x001434
-#define EMAC_MAC_IPGIFG_CTRL 0x001484
-#define EMAC_MAC_STA_ADDR0 0x001488
-#define EMAC_MAC_STA_ADDR1 0x00148c
-#define EMAC_HASH_TAB_REG0 0x001490
-#define EMAC_HASH_TAB_REG1 0x001494
-#define EMAC_MAC_HALF_DPLX_CTRL 0x001498
-#define EMAC_MAX_FRAM_LEN_CTRL 0x00149c
-#define EMAC_INT_STATUS 0x001600
-#define EMAC_INT_MASK 0x001604
-#define EMAC_RXMAC_STATC_REG0 0x001700
-#define EMAC_RXMAC_STATC_REG22 0x001758
-#define EMAC_TXMAC_STATC_REG0 0x001760
-#define EMAC_TXMAC_STATC_REG24 0x0017c0
-#define EMAC_CORE_HW_VERSION 0x001974
-#define EMAC_IDT_TABLE0 0x001b00
-#define EMAC_RXMAC_STATC_REG23 0x001bc8
-#define EMAC_RXMAC_STATC_REG24 0x001bcc
-#define EMAC_TXMAC_STATC_REG25 0x001bd0
-#define EMAC_INT1_MASK 0x001bf0
-#define EMAC_INT1_STATUS 0x001bf4
-#define EMAC_INT2_MASK 0x001bf8
-#define EMAC_INT2_STATUS 0x001bfc
-#define EMAC_INT3_MASK 0x001c00
-#define EMAC_INT3_STATUS 0x001c04
+#define EMAC_DMA_MAS_CTRL 0x1400
+#define EMAC_IRQ_MOD_TIM_INIT 0x1408
+#define EMAC_BLK_IDLE_STS 0x140c
+#define EMAC_PHY_LINK_DELAY 0x141c
+#define EMAC_SYS_ALIV_CTRL 0x1434
+#define EMAC_MAC_CTRL 0x1480
+#define EMAC_MAC_IPGIFG_CTRL 0x1484
+#define EMAC_MAC_STA_ADDR0 0x1488
+#define EMAC_MAC_STA_ADDR1 0x148c
+#define EMAC_HASH_TAB_REG0 0x1490
+#define EMAC_HASH_TAB_REG1 0x1494
+#define EMAC_MAC_HALF_DPLX_CTRL 0x1498
+#define EMAC_MAX_FRAM_LEN_CTRL 0x149c
+#define EMAC_WOL_CTRL0 0x14a0
+#define EMAC_RSS_KEY0 0x14b0
+#define EMAC_H1TPD_BASE_ADDR_LO 0x14e0
+#define EMAC_H2TPD_BASE_ADDR_LO 0x14e4
+#define EMAC_H3TPD_BASE_ADDR_LO 0x14e8
+#define EMAC_INTER_SRAM_PART9 0x1534
+#define EMAC_DESC_CTRL_0 0x1540
+#define EMAC_DESC_CTRL_1 0x1544
+#define EMAC_DESC_CTRL_2 0x1550
+#define EMAC_DESC_CTRL_10 0x1554
+#define EMAC_DESC_CTRL_12 0x1558
+#define EMAC_DESC_CTRL_13 0x155c
+#define EMAC_DESC_CTRL_3 0x1560
+#define EMAC_DESC_CTRL_4 0x1564
+#define EMAC_DESC_CTRL_5 0x1568
+#define EMAC_DESC_CTRL_14 0x156c
+#define EMAC_DESC_CTRL_15 0x1570
+#define EMAC_DESC_CTRL_16 0x1574
+#define EMAC_DESC_CTRL_6 0x1578
+#define EMAC_DESC_CTRL_8 0x1580
+#define EMAC_DESC_CTRL_9 0x1584
+#define EMAC_DESC_CTRL_11 0x1588
+#define EMAC_TXQ_CTRL_0 0x1590
+#define EMAC_TXQ_CTRL_1 0x1594
+#define EMAC_TXQ_CTRL_2 0x1598
+#define EMAC_RXQ_CTRL_0 0x15a0
+#define EMAC_RXQ_CTRL_1 0x15a4
+#define EMAC_RXQ_CTRL_2 0x15a8
+#define EMAC_RXQ_CTRL_3 0x15ac
+#define EMAC_BASE_CPU_NUMBER 0x15b8
+#define EMAC_DMA_CTRL 0x15c0
+#define EMAC_MAILBOX_0 0x15e0
+#define EMAC_MAILBOX_5 0x15e4
+#define EMAC_MAILBOX_6 0x15e8
+#define EMAC_MAILBOX_13 0x15ec
+#define EMAC_MAILBOX_2 0x15f4
+#define EMAC_MAILBOX_3 0x15f8
+#define EMAC_INT_STATUS 0x1600
+#define EMAC_INT_MASK 0x1604
+#define EMAC_MAILBOX_11 0x160c
+#define EMAC_AXI_MAST_CTRL 0x1610
+#define EMAC_MAILBOX_12 0x1614
+#define EMAC_MAILBOX_9 0x1618
+#define EMAC_MAILBOX_10 0x161c
+#define EMAC_ATHR_HEADER_CTRL 0x1620
+#define EMAC_RXMAC_STATC_REG0 0x1700
+#define EMAC_RXMAC_STATC_REG22 0x1758
+#define EMAC_TXMAC_STATC_REG0 0x1760
+#define EMAC_TXMAC_STATC_REG24 0x17c0
+#define EMAC_CLK_GATE_CTRL 0x1814
+#define EMAC_CORE_HW_VERSION 0x1974
+#define EMAC_MISC_CTRL 0x1990
+#define EMAC_MAILBOX_7 0x19e0
+#define EMAC_MAILBOX_8 0x19e4
+#define EMAC_IDT_TABLE0 0x1b00
+#define EMAC_RXMAC_STATC_REG23 0x1bc8
+#define EMAC_RXMAC_STATC_REG24 0x1bcc
+#define EMAC_TXMAC_STATC_REG25 0x1bd0
+#define EMAC_MAILBOX_15 0x1bd4
+#define EMAC_MAILBOX_16 0x1bd8
+#define EMAC_INT1_MASK 0x1bf0
+#define EMAC_INT1_STATUS 0x1bf4
+#define EMAC_INT2_MASK 0x1bf8
+#define EMAC_INT2_STATUS 0x1bfc
+#define EMAC_INT3_MASK 0x1c00
+#define EMAC_INT3_STATUS 0x1c04
/* EMAC_DMA_MAS_CTRL */
#define DEV_ID_NUM_BMSK 0x7f000000
@@ -166,10 +217,6 @@ enum emac_clk_id {
#define EMAC_MAX_SETUP_LNK_CYCLE 100
-/* Wake On Lan */
-#define EMAC_WOL_PHY 0x00000001 /* PHY Status Change */
-#define EMAC_WOL_MAGIC 0x00000002 /* Magic Packet */
-
struct emac_stats {
/* rx */
u64 rx_ok; /* good packets */
@@ -291,7 +338,7 @@ struct emac_adapter {
void __iomem *base;
void __iomem *csr;
- struct emac_phy phy;
+ struct emac_sgmii phy;
struct emac_stats stats;
struct emac_irq irq;
@@ -309,6 +356,13 @@ struct emac_adapter {
unsigned int rxbuf_size;
+ /* Flow control / pause frames support. If automatic=True, do whatever
+ * the PHY does. Otherwise, use tx_flow_control and rx_flow_control.
+ */
+ bool automatic;
+ bool tx_flow_control;
+ bool rx_flow_control;
+
/* Ring parameter */
u8 tpd_burst;
u8 rfd_burst;
@@ -330,6 +384,8 @@ struct emac_adapter {
int emac_reinit_locked(struct emac_adapter *adpt);
void emac_reg_update32(void __iomem *addr, u32 mask, u32 val);
-irqreturn_t emac_isr(int irq, void *data);
+
+void emac_set_ethtool_ops(struct net_device *netdev);
+void emac_update_hw_stats(struct emac_adapter *adpt);
#endif /* _EMAC_H_ */
diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c
index 8e28234dddad..d145df98feff 100644
--- a/drivers/net/ethernet/qualcomm/qca_debug.c
+++ b/drivers/net/ethernet/qualcomm/qca_debug.c
@@ -188,14 +188,16 @@ qcaspi_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *p)
}
static int
-qcaspi_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+qcaspi_get_link_ksettings(struct net_device *dev,
+ struct ethtool_link_ksettings *cmd)
{
- cmd->transceiver = XCVR_INTERNAL;
- cmd->supported = SUPPORTED_10baseT_Half;
- ethtool_cmd_speed_set(cmd, SPEED_10);
- cmd->duplex = DUPLEX_HALF;
- cmd->port = PORT_OTHER;
- cmd->autoneg = AUTONEG_DISABLE;
+ ethtool_link_ksettings_zero_link_mode(cmd, supported);
+ ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Half);
+
+ cmd->base.speed = SPEED_10;
+ cmd->base.duplex = DUPLEX_HALF;
+ cmd->base.port = PORT_OTHER;
+ cmd->base.autoneg = AUTONEG_DISABLE;
return 0;
}
@@ -295,7 +297,6 @@ qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
static const struct ethtool_ops qcaspi_ethtool_ops = {
.get_drvinfo = qcaspi_get_drvinfo,
.get_link = ethtool_op_get_link,
- .get_settings = qcaspi_get_settings,
.get_ethtool_stats = qcaspi_get_ethtool_stats,
.get_strings = qcaspi_get_strings,
.get_sset_count = qcaspi_get_sset_count,
@@ -303,6 +304,7 @@ static const struct ethtool_ops qcaspi_ethtool_ops = {
.get_regs = qcaspi_get_regs,
.get_ringparam = qcaspi_get_ringparam,
.set_ringparam = qcaspi_set_ringparam,
+ .get_link_ksettings = qcaspi_get_link_ksettings,
};
void qcaspi_set_ethtool_ops(struct net_device *dev)
diff --git a/drivers/net/ethernet/qualcomm/qca_framing.h b/drivers/net/ethernet/qualcomm/qca_framing.h
index 5d965959c978..d5e795dcdf47 100644
--- a/drivers/net/ethernet/qualcomm/qca_framing.h
+++ b/drivers/net/ethernet/qualcomm/qca_framing.h
@@ -43,9 +43,9 @@
/* Frame length is invalid */
#define QCAFRM_INVFRAME (QCAFRM_ERR_BASE - 4)
-/* Min/Max Ethernet MTU */
-#define QCAFRM_ETHMINMTU 46
-#define QCAFRM_ETHMAXMTU 1500
+/* Min/Max Ethernet MTU: 46/1500 */
+#define QCAFRM_ETHMINMTU (ETH_ZLEN - ETH_HLEN)
+#define QCAFRM_ETHMAXMTU ETH_DATA_LEN
/* Min/Max frame lengths */
#define QCAFRM_ETHMINLEN (QCAFRM_ETHMINMTU + ETH_HLEN)
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 6e2add979471..513e6c74e199 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -780,24 +780,12 @@ qcaspi_netdev_uninit(struct net_device *dev)
dev_kfree_skb(qca->rx_skb);
}
-static int
-qcaspi_netdev_change_mtu(struct net_device *dev, int new_mtu)
-{
- if ((new_mtu < QCAFRM_ETHMINMTU) || (new_mtu > QCAFRM_ETHMAXMTU))
- return -EINVAL;
-
- dev->mtu = new_mtu;
-
- return 0;
-}
-
static const struct net_device_ops qcaspi_netdev_ops = {
.ndo_init = qcaspi_netdev_init,
.ndo_uninit = qcaspi_netdev_uninit,
.ndo_open = qcaspi_netdev_open,
.ndo_stop = qcaspi_netdev_close,
.ndo_start_xmit = qcaspi_netdev_xmit,
- .ndo_change_mtu = qcaspi_netdev_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_tx_timeout = qcaspi_netdev_tx_timeout,
.ndo_validate_addr = eth_validate_addr,
@@ -814,6 +802,10 @@ qcaspi_netdev_setup(struct net_device *dev)
dev->priv_flags &= ~IFF_TX_SKB_SHARING;
dev->tx_queue_len = 100;
+ /* MTU range: 46 - 1500 */
+ dev->min_mtu = QCAFRM_ETHMINMTU;
+ dev->max_mtu = QCAFRM_ETHMAXMTU;
+
qca = netdev_priv(dev);
memset(qca, 0, sizeof(struct qcaspi));