From patchwork Sat May 8 00:29:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Marangi X-Patchwork-Id: 432993 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EDE7FC433B4 for ; Sat, 8 May 2021 00:32:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C861161154 for ; Sat, 8 May 2021 00:32:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230452AbhEHAdX (ORCPT ); Fri, 7 May 2021 20:33:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47760 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230352AbhEHAdC (ORCPT ); Fri, 7 May 2021 20:33:02 -0400 Received: from mail-wm1-x32a.google.com (mail-wm1-x32a.google.com [IPv6:2a00:1450:4864:20::32a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1103FC06138B; Fri, 7 May 2021 17:30:06 -0700 (PDT) Received: by mail-wm1-x32a.google.com with SMTP id y124-20020a1c32820000b029010c93864955so8035135wmy.5; Fri, 07 May 2021 17:30:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=qcblg99dKtUzLmP9mbJXQAISMB0uNfwt/9mCJ1r1c3U=; b=etIGs1jthj7TT3R3upyK1KJK/meiSJ/3xzDUsWPWzZfiC7je/C4T70+esGB1sqd/b2 ab+2+DqrTxCGhdOgKrs2h8rYxrzazKtdANaB6pYxwzmGNTZKbT68BE7PE0CuHuBrk3ej ppAlNioGZMxW1rJbd8clItMTwUyWK1jwwBx1iHZrsGtpABgfVlqmPVgO3SQLIp5vK0OT AMpPQuYXOitb3LyXClYxnyrQgpcUgoJ5Ae6NpU6f3rhV1VOoxGkhQQ1fI1WwuSb0NX8/ b54NV/G9f7cOsEtojWLpGK8fM/JXqlDlrHCjzxSNTUiDwL34StnLksXfA8nX6zAU1iqC xX1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=qcblg99dKtUzLmP9mbJXQAISMB0uNfwt/9mCJ1r1c3U=; b=IeeeL7og55ZkxeLNTsgDPRUa0Xz5jMd5peICPv6uld+a0zBsV8N+1+6jSgreUdHuF/ z96wSOd3Qq7hLClbo8Kpzak9/I32qiqBSgNzh+1srtPto8ycxia887bxJRXw6ATPALf6 gBnZjbkaXal7ZS4nqgIvis5P/MVcaVPJ+yuzTG3XMeguhWIOn9lHoN8sL8OBbCdKmK1N +7ia2DBRBcwD+A7HmDZb4xkN5HDCKc1bBh89VEVuLliP1rOBHfxV8Uv1efq5z/x48XGe 3gJPEVYYNguQHL9elmWWiei86ZaBzZrdgruxFqh1/O8nJQATjJ9GBVeklyGZ5pYOAA1j jy+g== X-Gm-Message-State: AOAM530rli312ufZ+C64Y+PV9Eji3+1hyigu6QeFYYtPVD5RbY9evxLr XyyiUd2nJRoI2gjjO6CJgtA= X-Google-Smtp-Source: ABdhPJxA4mWVt96aVWdM3JrX/XlR3pFVe3a0oxDkqFUAQL1JUD98eNCjYiMTyTznve5LaPn67o04Dw== X-Received: by 2002:a1c:2097:: with SMTP id g145mr23480081wmg.33.1620433804651; Fri, 07 May 2021 17:30:04 -0700 (PDT) Received: from Ansuel-xps.localdomain (93-35-189-2.ip56.fastwebnet.it. [93.35.189.2]) by smtp.googlemail.com with ESMTPSA id f4sm10967597wrz.33.2021.05.07.17.30.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 May 2021 17:30:04 -0700 (PDT) From: Ansuel Smith To: Florian Fainelli Cc: Ansuel Smith , Andrew Lunn , Heiner Kallweit , Russell King , "David S. Miller" , Jakub Kicinski , linux-kernel@vger.kernel.org, netdev@vger.kernel.org Subject: [RFC PATCH net-next v4 28/28] net: phy: add qca8k driver for qca8k switch internal PHY Date: Sat, 8 May 2021 02:29:18 +0200 Message-Id: <20210508002920.19945-28-ansuelsmth@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210508002920.19945-1-ansuelsmth@gmail.com> References: <20210508002920.19945-1-ansuelsmth@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add initial support for qca8k internal PHYs. The internal PHYs requires special mmd and debug values to be set based on the switch revision passwd using the dev_flags. Supports output of idle, receive and eee_wake errors stats. Some debug values sets can't be translated as the documentation lacks any reference about them. Signed-off-by: Ansuel Smith --- drivers/net/phy/Kconfig | 7 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/qca8k.c | 172 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 drivers/net/phy/qca8k.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 698bea312adc..cdf01613eb37 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -245,6 +245,13 @@ config QSEMI_PHY help Currently supports the qs6612 +config QCA8K_PHY + tristate "Qualcomm Atheros AR833x Internal PHYs" + help + This PHY is for the internal PHYs present on the QCA833x switch. + + Currently supports the AR8334, AR8337 model + config REALTEK_PHY tristate "Realtek PHYs" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index a13e402074cf..5f3cfd5606bb 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_MICROSEMI_PHY) += mscc/ obj-$(CONFIG_NATIONAL_PHY) += national.o obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o obj-$(CONFIG_QSEMI_PHY) += qsemi.o +obj-$(CONFIG_QCA8K_PHY) += qca8k.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_RENESAS_PHY) += uPD60620.o obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o diff --git a/drivers/net/phy/qca8k.c b/drivers/net/phy/qca8k.c new file mode 100644 index 000000000000..53bbd506d184 --- /dev/null +++ b/drivers/net/phy/qca8k.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include +#include +#include +#include +#include +#include +#include + +#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0) + +#define QCA8K_PHY_ID_MASK 0xffffffff +#define QCA8K_PHY_ID_QCA8327 0x004dd034 +#define QCA8K_PHY_ID_QCA8337 0x004dd036 + +#define MDIO_AZ_DEBUG 0x800d + +#define MDIO_DBG_ANALOG_TEST 0x0 +#define MDIO_DBG_SYSTEM_CONTROL_MODE 0x5 +#define MDIO_DBG_CONTROL_FEATURE_CONF 0x3d + +/* QCA specific MII registers */ +#define MII_ATH_DBG_ADDR 0x1d +#define MII_ATH_DBG_DATA 0x1e + +/* QCA specific MII registers access function */ +static void qca8k_phy_dbg_write(struct mii_bus *bus, int phy_addr, u16 dbg_addr, u16 dbg_data) +{ + bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr); + bus->write(bus, phy_addr, MII_ATH_DBG_DATA, dbg_data); +} + +enum stat_access_type { + PHY, + MMD +}; + +struct qca8k_hw_stat { + const char *string; + u8 reg; + u32 mask; + enum stat_access_type access_type; +}; + +static struct qca8k_hw_stat qca8k_hw_stats[] = { + { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY}, + { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY}, + { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD}, +}; + +struct qca8k_phy_priv { + u8 switch_revision; + u64 stats[ARRAY_SIZE(qca8k_hw_stats)]; +}; + +static int qca8k_get_sset_count(struct phy_device *phydev) +{ + return ARRAY_SIZE(qca8k_hw_stats); +} + +static void qca8k_get_strings(struct phy_device *phydev, u8 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(qca8k_hw_stats); i++) { + strscpy(data + i * ETH_GSTRING_LEN, + qca8k_hw_stats[i].string, ETH_GSTRING_LEN); + } +} + +static u64 qca8k_get_stat(struct phy_device *phydev, int i) +{ + struct qca8k_hw_stat stat = qca8k_hw_stats[i]; + struct qca8k_phy_priv *priv = phydev->priv; + int val; + u64 ret; + + if (stat.access_type == MMD) + val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg); + else + val = phy_read(phydev, stat.reg); + + if (val < 0) { + ret = U64_MAX; + } else { + val = val & stat.mask; + priv->stats[i] += val; + ret = priv->stats[i]; + } + + return ret; +} + +static void qca8k_get_stats(struct phy_device *phydev, + struct ethtool_stats *stats, u64 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(qca8k_hw_stats); i++) + data[i] = qca8k_get_stat(phydev, i); +} + +static int qca8k_config_init(struct phy_device *phydev) +{ + struct qca8k_phy_priv *priv = phydev->priv; + struct mii_bus *bus = phydev->mdio.bus; + int phy_addr = phydev->mdio.addr; + + priv->switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK; + + switch (priv->switch_revision) { + case 1: + /* For 100M waveform */ + qca8k_phy_dbg_write(bus, phy_addr, MDIO_DBG_ANALOG_TEST, 0x02ea); + /* Turn on Gigabit clock */ + qca8k_phy_dbg_write(bus, phy_addr, MDIO_DBG_CONTROL_FEATURE_CONF, 0x68a0); + break; + + case 2: + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0); + fallthrough; + case 4: + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f); + qca8k_phy_dbg_write(bus, phy_addr, MDIO_DBG_CONTROL_FEATURE_CONF, 0x6860); + qca8k_phy_dbg_write(bus, phy_addr, MDIO_DBG_SYSTEM_CONTROL_MODE, 0x2c46); + qca8k_phy_dbg_write(bus, phy_addr, 0x3c, 0x6000); + break; + } + + return 0; +} + +static int qca8k_probe(struct phy_device *phydev) +{ + struct qca8k_phy_priv *priv; + + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + phydev->priv = priv; + + return 0; +} + +static struct phy_driver qca8k_drivers[] = { + { + .phy_id = QCA8K_PHY_ID_QCA8337, + .phy_id_mask = QCA8K_PHY_ID_MASK, + .name = "QCA PHY 8337", + /* PHY_GBIT_FEATURES */ + .probe = qca8k_probe, + .flags = PHY_IS_INTERNAL, + .config_init = qca8k_config_init, + .soft_reset = genphy_soft_reset, + .get_sset_count = qca8k_get_sset_count, + .get_strings = qca8k_get_strings, + .get_stats = qca8k_get_stats, + }, +}; + +module_phy_driver(qca8k_drivers); + +static struct mdio_device_id __maybe_unused qca8k_tbl[] = { + { QCA8K_PHY_ID_QCA8337, QCA8K_PHY_ID_MASK }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, qca8k_tbl); +MODULE_DESCRIPTION("Qualcomm QCA8k PHY driver"); +MODULE_AUTHOR("Ansuel Smith"); +MODULE_LICENSE("GPL");