From patchwork Wed Feb 10 12:55:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Robert Marko X-Patchwork-Id: 12080823 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=-13.9 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable 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 7997DC433E6 for ; Wed, 10 Feb 2021 12:57:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 43C6F64E65 for ; Wed, 10 Feb 2021 12:57:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230267AbhBJM5g (ORCPT ); Wed, 10 Feb 2021 07:57:36 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49636 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231363AbhBJM4O (ORCPT ); Wed, 10 Feb 2021 07:56:14 -0500 Received: from mail-ej1-x62a.google.com (mail-ej1-x62a.google.com [IPv6:2a00:1450:4864:20::62a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1FB70C06178A for ; Wed, 10 Feb 2021 04:55:33 -0800 (PST) Received: by mail-ej1-x62a.google.com with SMTP id jj19so4010792ejc.4 for ; Wed, 10 Feb 2021 04:55:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sartura-hr.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=QP3xask6OD7k8KSQ5tVVcC2So9/tpald+pKQ9QG/+P8=; b=HjJ6Lp/AhwITcJlB6qLHzWAJY/BrcnEYgKc4a+8TzLCZ5CCXAWI50E7ZohLrJGmbNh vJrTk3rv9gio+BQgS8wQLCxK71fcPm4j7kUztMMCdcVx/oTZX9NlArdOQaVP7cWrf4O9 GwQ0TONto3hfchlvQ64hAmFR9JDfWwa/PSQobPThflThTbPoWGazrjdNbtRIidAB3yRg nxZgEs+dFWA85wunPG6kzc023yG4EgtDXPtOazdvsunr0wY4BaDYGMfNUx4VVEuuRKhH uVE2hurMQquNBrpsxDYaWpM95IBONWC3y795H39kYzccBfOuawpXw9sIVli4PaGufh6n l54w== 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=QP3xask6OD7k8KSQ5tVVcC2So9/tpald+pKQ9QG/+P8=; b=BgwxcXU602Ept9etpVN+xGTLHPF2PsVGLuHvtIuaT1dxc9bqrBlPsDfWo2i/j226Vt pgYfmIugYO8SYmUcfiFgAhQwOVdUs7vjSx2w/y5HDT9vVtrlQAONXhjiRc1JMuuVwscZ jWPuZ2DlxdGf5gb2ic9d8m7D95rcx48P5ttWcC/mzEidWVP0hc+bEhiznccqUo7RU8tJ lVqhGcMSruk8aaVmQFIO2v6Hfsp8jmRD7BNNzajGCRC6ZyCVhJu3/X3Smf1/48Nt41Aw YaYS47OQ/lsYiRogNcWiSGEOP9w80uZDREK421Eov2KJHCHhJDis9hg50TRO5RUtyDM7 eRmA== X-Gm-Message-State: AOAM531i0NdE1gJS2c2KMiaj5NVPEGIlhE/0JZokLxu7aGYdFIZhOW+e ALZnFSLjAuSg3qdUZPJDP00DBA== X-Google-Smtp-Source: ABdhPJySVHbEy7cRf3FVEZU38MkaaqoQGA40nPFPDQevnBQvfDLbeE2YY+LPPPi8oagsbkMesjJCnQ== X-Received: by 2002:a17:906:2b16:: with SMTP id a22mr2792396ejg.291.1612961731916; Wed, 10 Feb 2021 04:55:31 -0800 (PST) Received: from localhost.localdomain (dh207-97-164.xnet.hr. [88.207.97.164]) by smtp.googlemail.com with ESMTPSA id u5sm1084900edc.29.2021.02.10.04.55.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Feb 2021 04:55:31 -0800 (PST) From: Robert Marko To: agross@kernel.org, bjorn.andersson@linaro.org, robh+dt@kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, davem@davemloft.net, kuba@kernel.org, netdev@vger.kernel.org, andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk Cc: Robert Marko , Luka Perkov Subject: [PATCH v2 net-next 1/4] dt-bindings: net: Add QCA807x PHY Date: Wed, 10 Feb 2021 13:55:20 +0100 Message-Id: <20210210125523.2146352-2-robert.marko@sartura.hr> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210210125523.2146352-1-robert.marko@sartura.hr> References: <20210210125523.2146352-1-robert.marko@sartura.hr> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org Add DT bindings for Qualcomm QCA807x PHY series. Signed-off-by: Robert Marko Cc: Luka Perkov --- Changes in v2: * Drop PSGMII/QSGMII TX driver defines include/dt-bindings/net/qcom-qca807x.h | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 include/dt-bindings/net/qcom-qca807x.h diff --git a/include/dt-bindings/net/qcom-qca807x.h b/include/dt-bindings/net/qcom-qca807x.h new file mode 100644 index 000000000000..a5ac12777c2b --- /dev/null +++ b/include/dt-bindings/net/qcom-qca807x.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Device Tree constants for the Qualcomm QCA807X PHYs + */ + +#ifndef _DT_BINDINGS_QCOM_QCA807X_H +#define _DT_BINDINGS_QCOM_QCA807X_H + +/* Full amplitude, full bias current */ +#define QCA807X_CONTROL_DAC_FULL_VOLT_BIAS 0 +/* Amplitude follow DSP (amplitude is adjusted based on cable length), half bias current */ +#define QCA807X_CONTROL_DAC_DSP_VOLT_HALF_BIAS 1 +/* Full amplitude, bias current follow DSP (bias current is adjusted based on cable length) */ +#define QCA807X_CONTROL_DAC_FULL_VOLT_DSP_BIAS 2 +/* Both amplitude and bias current follow DSP */ +#define QCA807X_CONTROL_DAC_DSP_VOLT_BIAS 3 +/* Full amplitude, half bias current */ +#define QCA807X_CONTROL_DAC_FULL_VOLT_HALF_BIAS 4 +/* Amplitude follow DSP setting; 1/4 bias current when cable<10m, + * otherwise half bias current + */ +#define QCA807X_CONTROL_DAC_DSP_VOLT_QUARTER_BIAS 5 +/* Full amplitude; same bias current setting with “010” and “011”, + * but half more bias is reduced when cable <10m + */ +#define QCA807X_CONTROL_DAC_FULL_VOLT_HALF_BIAS_SHORT 6 +/* Amplitude follow DSP; same bias current setting with “110”, default value */ +#define QCA807X_CONTROL_DAC_DSP_VOLT_HALF_BIAS_SHORT 7 + +#endif From patchwork Wed Feb 10 12:55:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robert Marko X-Patchwork-Id: 12080819 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=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 E47E6C433DB for ; Wed, 10 Feb 2021 12:56:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9D0BE64E3B for ; Wed, 10 Feb 2021 12:56:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230388AbhBJM4Y (ORCPT ); Wed, 10 Feb 2021 07:56:24 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49540 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230192AbhBJM4K (ORCPT ); Wed, 10 Feb 2021 07:56:10 -0500 Received: from mail-ej1-x636.google.com (mail-ej1-x636.google.com [IPv6:2a00:1450:4864:20::636]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E66C7C061794 for ; Wed, 10 Feb 2021 04:55:34 -0800 (PST) Received: by mail-ej1-x636.google.com with SMTP id jj19so4011006ejc.4 for ; Wed, 10 Feb 2021 04:55:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sartura-hr.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=j2pR7GHtK2D/n+G2R92gU7IY+vciRBprFSrIu2y8jqQ=; b=WslFAuX+r5eNLy3aXOBoL0GU98/EoUPq2zxD0CU3YakcUF4V+Dbh+rIM8LT+Y/NZFt r30eVO8OkS/PnaMN0+P+D/7LGo0bQ64S6U72ik4nmpZ8z3G9calBQfksAriS+kBWD6Be Vkijvz/G+ZkA8oNACGzE95SROw/+WhW8QOYcQC0R/MzHvL2JvGLfS80AVFDM79XaFOun 8ewt8EMwnR3BiEyNEp5hGKkPiQqIznAGA6PN42f+9Qm7o6MeZAxJxcTfgyDCuCtv6hkj pRr2Rby2Tpd45ghShLBKoyvERynA+JIVS+VhBiECqaCk03ucGxqAJafW3zuY1CCmqHY2 JoYg== 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=j2pR7GHtK2D/n+G2R92gU7IY+vciRBprFSrIu2y8jqQ=; b=sOIjyrv/SPLeNVdj3QVWi6U7GhAFALP+rzjr8ghw1DEwp0Q3vIGYKI1kReZ8pqzYD5 aY96tKbCAPmm8opwMZt4GxvatyhHA7U8ob74JT4eS2wSrhKRL5sq3QptTrs13/99HIvf u+lOhyiw3I/kjAf4bGXcpmJMp4R2po1p3Td2vKH0cmdATAHeOcbg2x2jBczuQ1ruvBYM kwA2Bi0P162H4kkx9dYX+gzO8QMjCTnUlJtGof/kfa4FKaa+CJSSq7BvKhqDkjoZ/xhT cvNsVgfu8UiFPUqHsR3CeXX9k4QL0dposy771oXhVP5Z8mxOmtyCNruRyPR8B40jdnaw RB+w== X-Gm-Message-State: AOAM533ckB2skUXdHnGroNOZNHRQi5jRNRqya+YB8oTjfyzaG7NYoixr BqvlptnvO1q6NzIGJdn8/CHgLQ== X-Google-Smtp-Source: ABdhPJx+cbffJtH/oYQNj2WBZy9er7kIC5vD6i5EoJcwf8fbm03n2PHzuHv1N5sFqvqdWOJGYNCDPQ== X-Received: by 2002:a17:906:4013:: with SMTP id v19mr2822228ejj.5.1612961733706; Wed, 10 Feb 2021 04:55:33 -0800 (PST) Received: from localhost.localdomain (dh207-97-164.xnet.hr. [88.207.97.164]) by smtp.googlemail.com with ESMTPSA id u5sm1084900edc.29.2021.02.10.04.55.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Feb 2021 04:55:33 -0800 (PST) From: Robert Marko To: agross@kernel.org, bjorn.andersson@linaro.org, robh+dt@kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, davem@davemloft.net, kuba@kernel.org, netdev@vger.kernel.org, andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk Cc: Robert Marko , Luka Perkov Subject: [PATCH v2 net-next 2/4] dt-bindings: net: Add bindings for Qualcomm QCA807x Date: Wed, 10 Feb 2021 13:55:21 +0100 Message-Id: <20210210125523.2146352-3-robert.marko@sartura.hr> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210210125523.2146352-1-robert.marko@sartura.hr> References: <20210210125523.2146352-1-robert.marko@sartura.hr> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org Add DT bindings for Qualcomm QCA807x PHYs. Signed-off-by: Robert Marko Cc: Luka Perkov --- Changes in v2: * Drop LED properties * Directly define PSGMII/QSGMII SerDes driver values .../devicetree/bindings/net/qcom,qca807x.yaml | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/qcom,qca807x.yaml diff --git a/Documentation/devicetree/bindings/net/qcom,qca807x.yaml b/Documentation/devicetree/bindings/net/qcom,qca807x.yaml new file mode 100644 index 000000000000..0867f5e698cd --- /dev/null +++ b/Documentation/devicetree/bindings/net/qcom,qca807x.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/qcom,qca807x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QCA807x PHY + +maintainers: + - Robert Marko + +description: | + Bindings for Qualcomm QCA807x PHYs + +allOf: + - $ref: ethernet-phy.yaml# + +properties: + reg: + maxItems: 1 + + qcom,fiber-enable: + description: | + If present, then PHYs combo port is configured to operate in combo + mode. In combo mode autodetection of copper and fiber media is + used in order to support both of them. + Combo mode can be strapped as well, if not strapped this property + will set combo support anyway. + type: boolean + + qcom,psgmii-az: + description: | + If present, then PSMGII PHY will advertise 802.3-az support to + the MAC. + type: boolean + + gpio-controller: true + "#gpio-cells": + const: 2 + + qcom,tx-driver-strength: + description: PSGMII/QSGMII SerDes TX driver strength control in mV. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [140, 160, 180, 200, 220, 240, 260, 280, 300, 320, 400, 500, 600] + + qcom,control-dac: + description: Analog MDI driver amplitude and bias current. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3, 4, 5, 6, 7] + +required: + - reg + +unevaluatedProperties: false + +examples: + - | + #include + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + + qcom,control-dac = ; + }; + }; From patchwork Wed Feb 10 12:55:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robert Marko X-Patchwork-Id: 12080827 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=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable 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 DFAF1C433DB for ; Wed, 10 Feb 2021 12:59:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7F6C764E3B for ; Wed, 10 Feb 2021 12:59:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230231AbhBJM7q (ORCPT ); Wed, 10 Feb 2021 07:59:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49990 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231362AbhBJM5x (ORCPT ); Wed, 10 Feb 2021 07:57:53 -0500 Received: from mail-ej1-x636.google.com (mail-ej1-x636.google.com [IPv6:2a00:1450:4864:20::636]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E3F40C06121C for ; Wed, 10 Feb 2021 04:55:36 -0800 (PST) Received: by mail-ej1-x636.google.com with SMTP id f14so3970747ejc.8 for ; Wed, 10 Feb 2021 04:55:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sartura-hr.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=HDhx1OrccLP05rzbGCjbEnMgA7nn+nxTwfnrw5Gec3c=; b=LoVVxam1bjAedMVMKx9y8liB/ey+FZ6aFUjfamVauDQVnytC+PoNi9Ew8WwMjyf7uJ mSaFqkCo0JwxOnXjgZ1pi53K6sbC/YF0ismwmUgdb0fDZ8CI6l8V0EUrifM9ZIxm4uYN /I3VN2SVgOk+S8dCYV5wfyByUgM/cgAWbhdzsMfcsjex4j0v5nxklNrJ3xILFAA0/VP0 CVCqtffxoT7L+ZGnY3UI/FbQHuii0T/NMIAUHc2eIdHsCn1jZV/o38Qu0q8Lo6czSRNi kLlqjGowmam1DWbwggZEm4oyHGxxdIvLpwRuCvvenJaqdN+c19qYWkkhG4qhJTiidrPW Fcrg== 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=HDhx1OrccLP05rzbGCjbEnMgA7nn+nxTwfnrw5Gec3c=; b=hYuIIV50tRGZ+40eLF9Tjaz6OOMKP/fC1LwIoaqgf4KF9gD+RTh93Ycbi/u/h4VVB3 rkScTT0WKnkJkwQ1F7Wh3fPkms6WLlwwG/2xrfRVHEtSmhZdWokKz1x1vC5hOJ1ekiJP AiXGsCZ0BpUDM6un4C9bFlDoHcqNzOCxIvfI+2iCQXHZH1mHThL3mU0sikCL/m1XHwsu yZrTRUzMf+ptdH1E8KbdxYgkB0pz7eaxblWJYQ/thmb5hfmpFB+FQLbWn2XBqxvgXZ5K gbS9SAfajpTrS3nFq2l0Nh4ov9o0eDae98u4ZFqilBmgHjyQcnCQdV+Js8EVkYcS6gCx wNpQ== X-Gm-Message-State: AOAM530VeJ7WM4ykRy6sTYtfA5YCgo3a8nj/Z1VWaoQS4/Wmj3arJpql DOIpCrki0ZD/Ik8YDSlYhCBJbQ== X-Google-Smtp-Source: ABdhPJzkbQnQFq8WWq608sMjqkj73b1HRORpWADcPWvkuhZ319b2apSgIH6q460D6woZR1xooOARvg== X-Received: by 2002:a17:907:98d7:: with SMTP id kd23mr2779373ejc.283.1612961735518; Wed, 10 Feb 2021 04:55:35 -0800 (PST) Received: from localhost.localdomain (dh207-97-164.xnet.hr. [88.207.97.164]) by smtp.googlemail.com with ESMTPSA id u5sm1084900edc.29.2021.02.10.04.55.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Feb 2021 04:55:35 -0800 (PST) From: Robert Marko To: agross@kernel.org, bjorn.andersson@linaro.org, robh+dt@kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, davem@davemloft.net, kuba@kernel.org, netdev@vger.kernel.org, andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk Cc: Robert Marko , Luka Perkov Subject: [PATCH v2 net-next 3/4] net: phy: Add Qualcomm QCA807x driver Date: Wed, 10 Feb 2021 13:55:22 +0100 Message-Id: <20210210125523.2146352-4-robert.marko@sartura.hr> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210210125523.2146352-1-robert.marko@sartura.hr> References: <20210210125523.2146352-1-robert.marko@sartura.hr> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org This adds driver for the Qualcomm QCA8072 and QCA8075 PHY-s. They are 2 or 5 port IEEE 802.3 clause 22 compliant 10BASE-Te, 100BASE-TX and 1000BASE-T PHY-s. They feature 2 SerDes, one for PSGMII or QSGMII connection with MAC, while second one is SGMII for connection to MAC or fiber. Both models have a combo port that supports 1000BASE-X and 100BASE-FX fiber. Each PHY inside of QCA807x series has 2 digitally controlled output only pins that natively drive LED-s. But some vendors used these to driver generic LED-s controlled by user space, so lets enable registering each PHY as GPIO controller and add driver for it. This also adds the ability to specify DT properties so that 1000 Base-T LED will also be lit up for 100 and 10 Base connections. This is usually done by U-boot, but boards running mainline U-boot are not configuring this yet. These PHY-s are commonly used in Qualcomm IPQ40xx, IPQ60xx and IPQ807x boards. Signed-off-by: Robert Marko Cc: Luka Perkov --- Changes in v2: * Drop LED related code * Fix ordering in KConfig and Makefile * Add SFP module validation upon instert * Rework IRQ code * Convert values for PSGMII/QSGMII SerDes driver into register values instead of using defines in dt-bindings * Fill phydev->port with correct port type drivers/net/phy/Kconfig | 10 + drivers/net/phy/Makefile | 1 + drivers/net/phy/qca807x.c | 855 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 866 insertions(+) create mode 100644 drivers/net/phy/qca807x.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 92164e7b7f60..f0725d8acd4a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -259,6 +259,16 @@ config AT803X_PHY help Currently supports the AR8030, AR8031, AR8033 and AR8035 model +config QCA807X_PHY + tristate "Qualcomm QCA807X PHYs" + depends on OF_MDIO + help + Adds support for the Qualcomm QCA807x PHYs. + These are 802.3 Clause 22 compliant PHYs supporting gigabit + ethernet as well as 100Base-FX and 1000Base-X fibre. + + Currently supports the QCA8072 and QCA8075 models. + config QSEMI_PHY tristate "Quality Semiconductor PHYs" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index ca0a313423b9..25530057950e 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_MICROCHIP_T1_PHY) += microchip_t1.o obj-$(CONFIG_MICROSEMI_PHY) += mscc/ obj-$(CONFIG_NATIONAL_PHY) += national.o obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o +obj-$(CONFIG_QCA807X_PHY) += qca807x.o obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_RENESAS_PHY) += uPD60620.o diff --git a/drivers/net/phy/qca807x.c b/drivers/net/phy/qca807x.c new file mode 100644 index 000000000000..9126035853e4 --- /dev/null +++ b/drivers/net/phy/qca807x.c @@ -0,0 +1,855 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020 Sartura Ltd. + * + * Author: Robert Marko + * + * Qualcomm QCA8072 and QCA8075 PHY driver + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PHY_ID_QCA8072 0x004dd0b2 +#define PHY_ID_QCA8075 0x004dd0b1 +#define PHY_ID_QCA807X_PSGMII 0x06820805 + +/* Downshift */ +#define QCA807X_SMARTSPEED_EN BIT(5) +#define QCA807X_SMARTSPEED_RETRY_LIMIT_MASK GENMASK(4, 2) +#define QCA807X_SMARTSPEED_RETRY_LIMIT_DEFAULT 5 +#define QCA807X_SMARTSPEED_RETRY_LIMIT_MIN 2 +#define QCA807X_SMARTSPEED_RETRY_LIMIT_MAX 9 + +/* Cable diagnostic test (CDT) */ +#define QCA807X_CDT 0x16 +#define QCA807X_CDT_ENABLE BIT(15) +#define QCA807X_CDT_ENABLE_INTER_PAIR_SHORT BIT(13) +#define QCA807X_CDT_STATUS BIT(11) +#define QCA807X_CDT_MMD3_STATUS 0x8064 +#define QCA807X_CDT_MDI0_STATUS_MASK GENMASK(15, 12) +#define QCA807X_CDT_MDI1_STATUS_MASK GENMASK(11, 8) +#define QCA807X_CDT_MDI2_STATUS_MASK GENMASK(7, 4) +#define QCA807X_CDT_MDI3_STATUS_MASK GENMASK(3, 0) +#define QCA807X_CDT_RESULTS_INVALID 0x0 +#define QCA807X_CDT_RESULTS_OK 0x1 +#define QCA807X_CDT_RESULTS_OPEN 0x2 +#define QCA807X_CDT_RESULTS_SAME_SHORT 0x3 +#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OK 0x4 +#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OK 0x8 +#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OK 0xc +#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OPEN 0x6 +#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OPEN 0xa +#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OPEN 0xe +#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_SHORT 0x7 +#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_SHORT 0xb +#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_SHORT 0xf +#define QCA807X_CDT_RESULTS_BUSY 0x9 +#define QCA807X_CDT_MMD3_MDI0_LENGTH 0x8065 +#define QCA807X_CDT_MMD3_MDI1_LENGTH 0x8066 +#define QCA807X_CDT_MMD3_MDI2_LENGTH 0x8067 +#define QCA807X_CDT_MMD3_MDI3_LENGTH 0x8068 +#define QCA807X_CDT_SAME_SHORT_LENGTH_MASK GENMASK(15, 8) +#define QCA807X_CDT_CROSS_SHORT_LENGTH_MASK GENMASK(7, 0) + +#define QCA807X_CHIP_CONFIGURATION 0x1f +#define QCA807X_BT_BX_REG_SEL BIT(15) +#define QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK GENMASK(3, 0) +#define QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII 4 +#define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER 3 +#define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER 0 + +#define QCA807X_MEDIA_SELECT_STATUS 0x1a +#define QCA807X_MEDIA_DETECTED_COPPER BIT(5) +#define QCA807X_MEDIA_DETECTED_1000_BASE_X BIT(4) +#define QCA807X_MEDIA_DETECTED_100_BASE_FX BIT(3) + +#define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION 0x807e +#define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN BIT(0) + +#define QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH 0x801a +#define QCA807X_CONTROL_DAC_MASK GENMASK(2, 0) + +#define QCA807X_MMD7_LED_100N_1 0x8074 +#define QCA807X_MMD7_LED_100N_2 0x8075 +#define QCA807X_MMD7_LED_1000N_1 0x8076 +#define QCA807X_MMD7_LED_1000N_2 0x8077 +#define QCA807X_GPIO_FORCE_EN BIT(15) +#define QCA807X_GPIO_FORCE_MODE_MASK GENMASK(14, 13) + +#define QCA807X_INTR_ENABLE 0x12 +#define QCA807X_INTR_STATUS 0x13 +#define QCA807X_INTR_ENABLE_AUTONEG_ERR BIT(15) +#define QCA807X_INTR_ENABLE_SPEED_CHANGED BIT(14) +#define QCA807X_INTR_ENABLE_DUPLEX_CHANGED BIT(13) +#define QCA807X_INTR_ENABLE_LINK_FAIL BIT(11) +#define QCA807X_INTR_ENABLE_LINK_SUCCESS BIT(10) + +#define QCA807X_FUNCTION_CONTROL 0x10 +#define QCA807X_FC_MDI_CROSSOVER_MODE_MASK GENMASK(6, 5) +#define QCA807X_FC_MDI_CROSSOVER_AUTO 3 +#define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDIX 1 +#define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDI 0 + +#define QCA807X_PHY_SPECIFIC_STATUS 0x11 +#define QCA807X_SS_SPEED_AND_DUPLEX_RESOLVED BIT(11) +#define QCA807X_SS_SPEED_MASK GENMASK(15, 14) +#define QCA807X_SS_SPEED_1000 2 +#define QCA807X_SS_SPEED_100 1 +#define QCA807X_SS_SPEED_10 0 +#define QCA807X_SS_DUPLEX BIT(13) +#define QCA807X_SS_MDIX BIT(6) + +/* PSGMII PHY specific */ +#define PSGMII_QSGMII_DRIVE_CONTROL_1 0xb +#define PSGMII_QSGMII_TX_DRIVER_MASK GENMASK(7, 4) +#define PSGMII_MODE_CTRL 0x6d +#define PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK GENMASK(3, 0) +#define PSGMII_MMD3_SERDES_CONTROL 0x805a + +struct qca807x_gpio_priv { + struct phy_device *phy; +}; + +static int qca807x_get_downshift(struct phy_device *phydev, u8 *data) +{ + int val, cnt, enable; + + val = phy_read(phydev, MII_NWAYTEST); + if (val < 0) + return val; + + enable = FIELD_GET(QCA807X_SMARTSPEED_EN, val); + cnt = FIELD_GET(QCA807X_SMARTSPEED_RETRY_LIMIT_MASK, val) + 2; + + *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE; + + return 0; +} + +static int qca807x_set_downshift(struct phy_device *phydev, u8 cnt) +{ + int ret, val; + + if (cnt > QCA807X_SMARTSPEED_RETRY_LIMIT_MAX || + (cnt < QCA807X_SMARTSPEED_RETRY_LIMIT_MIN && cnt != DOWNSHIFT_DEV_DISABLE)) + return -EINVAL; + + if (!cnt) { + ret = phy_clear_bits(phydev, MII_NWAYTEST, QCA807X_SMARTSPEED_EN); + } else { + val = QCA807X_SMARTSPEED_EN; + val |= FIELD_PREP(QCA807X_SMARTSPEED_RETRY_LIMIT_MASK, cnt - 2); + + phy_modify(phydev, MII_NWAYTEST, + QCA807X_SMARTSPEED_EN | + QCA807X_SMARTSPEED_RETRY_LIMIT_MASK, + val); + } + + ret = genphy_soft_reset(phydev); + + return ret; +} + +static int qca807x_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return qca807x_get_downshift(phydev, data); + default: + return -EOPNOTSUPP; + } +} + +static int qca807x_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return qca807x_set_downshift(phydev, *(const u8 *)data); + default: + return -EOPNOTSUPP; + } +} + +static bool qca807x_distance_valid(int result) +{ + switch (result) { + case QCA807X_CDT_RESULTS_OPEN: + case QCA807X_CDT_RESULTS_SAME_SHORT: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OK: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OK: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OK: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OPEN: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OPEN: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OPEN: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_SHORT: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_SHORT: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_SHORT: + return true; + } + return false; +} + +static int qca807x_report_length(struct phy_device *phydev, + int pair, int result) +{ + int length; + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA807X_CDT_MMD3_MDI0_LENGTH + pair); + if (ret < 0) + return ret; + + switch (result) { + case ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT: + length = (FIELD_GET(QCA807X_CDT_SAME_SHORT_LENGTH_MASK, ret) * 800) / 10; + break; + case ETHTOOL_A_CABLE_RESULT_CODE_OPEN: + case ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT: + length = (FIELD_GET(QCA807X_CDT_CROSS_SHORT_LENGTH_MASK, ret) * 800) / 10; + break; + } + + ethnl_cable_test_fault_length(phydev, pair, length); + + return 0; +} + +static int qca807x_cable_test_report_trans(int result) +{ + switch (result) { + case QCA807X_CDT_RESULTS_OK: + return ETHTOOL_A_CABLE_RESULT_CODE_OK; + case QCA807X_CDT_RESULTS_OPEN: + return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; + case QCA807X_CDT_RESULTS_SAME_SHORT: + return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OK: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OK: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OK: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OPEN: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OPEN: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OPEN: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_SHORT: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_SHORT: + case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_SHORT: + return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; + default: + return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; + } +} + +static int qca807x_cable_test_report(struct phy_device *phydev) +{ + int pair0, pair1, pair2, pair3; + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA807X_CDT_MMD3_STATUS); + if (ret < 0) + return ret; + + pair0 = FIELD_GET(QCA807X_CDT_MDI0_STATUS_MASK, ret); + pair1 = FIELD_GET(QCA807X_CDT_MDI1_STATUS_MASK, ret); + pair2 = FIELD_GET(QCA807X_CDT_MDI2_STATUS_MASK, ret); + pair3 = FIELD_GET(QCA807X_CDT_MDI3_STATUS_MASK, ret); + + ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, + qca807x_cable_test_report_trans(pair0)); + ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B, + qca807x_cable_test_report_trans(pair1)); + ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C, + qca807x_cable_test_report_trans(pair2)); + ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D, + qca807x_cable_test_report_trans(pair3)); + + if (qca807x_distance_valid(pair0)) + qca807x_report_length(phydev, 0, qca807x_cable_test_report_trans(pair0)); + if (qca807x_distance_valid(pair1)) + qca807x_report_length(phydev, 1, qca807x_cable_test_report_trans(pair1)); + if (qca807x_distance_valid(pair2)) + qca807x_report_length(phydev, 2, qca807x_cable_test_report_trans(pair2)); + if (qca807x_distance_valid(pair3)) + qca807x_report_length(phydev, 3, qca807x_cable_test_report_trans(pair3)); + + return 0; +} + +static int qca807x_cable_test_get_status(struct phy_device *phydev, + bool *finished) +{ + int val; + + *finished = false; + + val = phy_read(phydev, QCA807X_CDT); + if (!((val & QCA807X_CDT_ENABLE) && (val & QCA807X_CDT_STATUS))) { + *finished = true; + + return qca807x_cable_test_report(phydev); + } + + return 0; +} + +static int qca807x_cable_test_start(struct phy_device *phydev) +{ + int val, ret; + + /* Check if fiber is being used in the combo port, + * as we cant cable test fiber modules. + */ + if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) { + if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) { + val = phy_read(phydev, QCA807X_MEDIA_SELECT_STATUS); + if ((val & QCA807X_MEDIA_DETECTED_1000_BASE_X) || + (val & QCA807X_MEDIA_DETECTED_100_BASE_FX)) + return -EOPNOTSUPP; + } + } + + val = phy_read(phydev, QCA807X_CDT); + /* Enable inter-pair short check as well */ + val &= ~QCA807X_CDT_ENABLE_INTER_PAIR_SHORT; + val |= QCA807X_CDT_ENABLE; + ret = phy_write(phydev, QCA807X_CDT, val); + + return ret; +} + +#ifdef CONFIG_GPIOLIB +static int qca807x_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + return GPIO_LINE_DIRECTION_OUT; +} + +static int qca807x_gpio_get_reg(unsigned int offset) +{ + return QCA807X_MMD7_LED_100N_2 + (offset % 2) * 2; +} + +static int qca807x_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct qca807x_gpio_priv *priv = gpiochip_get_data(gc); + int val; + + val = phy_read_mmd(priv->phy, MDIO_MMD_AN, qca807x_gpio_get_reg(offset)); + + return FIELD_GET(QCA807X_GPIO_FORCE_MODE_MASK, val); +} + +static void qca807x_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) +{ + struct qca807x_gpio_priv *priv = gpiochip_get_data(gc); + int val; + + val = phy_read_mmd(priv->phy, MDIO_MMD_AN, qca807x_gpio_get_reg(offset)); + val &= ~QCA807X_GPIO_FORCE_MODE_MASK; + val |= FIELD_PREP(QCA807X_GPIO_FORCE_MODE_MASK, value); + + phy_write_mmd(priv->phy, MDIO_MMD_AN, qca807x_gpio_get_reg(offset), val); +} + +static int qca807x_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int value) +{ + qca807x_gpio_set(gc, offset, value); + + return 0; +} + +static int qca807x_gpio(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct qca807x_gpio_priv *priv; + struct gpio_chip *gc; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->phy = phydev; + + gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL); + if (!gc) + return -ENOMEM; + + gc->label = dev_name(dev); + gc->base = -1; + gc->ngpio = 2; + gc->parent = dev; + gc->owner = THIS_MODULE; + gc->can_sleep = true; + gc->get_direction = qca807x_gpio_get_direction; + gc->direction_output = qca807x_gpio_dir_out; + gc->get = qca807x_gpio_get; + gc->set = qca807x_gpio_set; + + return devm_gpiochip_add_data(dev, gc, priv); +} +#endif + +static int qca807x_read_copper_status(struct phy_device *phydev, bool combo_port) +{ + int ss, err, page, old_link = phydev->link; + + if (phydev->port != PORT_TP) + phydev->port = PORT_TP; + + /* Only combo port has dual pages */ + if (combo_port) { + /* Check whether copper page is set and set if needed */ + page = phy_read(phydev, QCA807X_CHIP_CONFIGURATION); + if (!(page & QCA807X_BT_BX_REG_SEL)) { + page |= QCA807X_BT_BX_REG_SEL; + phy_write(phydev, QCA807X_CHIP_CONFIGURATION, page); + } + } + + /* Update the link, but return if there was an error */ + err = genphy_update_link(phydev); + if (err) + return err; + + /* why bother the PHY if nothing can have changed */ + if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) + return 0; + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; + + err = genphy_read_lpa(phydev); + if (err < 0) + return err; + + /* Read the QCA807x PHY-Specific Status register copper page, + * which indicates the speed and duplex that the PHY is actually + * using, irrespective of whether we are in autoneg mode or not. + */ + ss = phy_read(phydev, QCA807X_PHY_SPECIFIC_STATUS); + if (ss < 0) + return ss; + + if (ss & QCA807X_SS_SPEED_AND_DUPLEX_RESOLVED) { + int sfc; + + sfc = phy_read(phydev, QCA807X_FUNCTION_CONTROL); + if (sfc < 0) + return sfc; + + switch (FIELD_GET(QCA807X_SS_SPEED_MASK, ss)) { + case QCA807X_SS_SPEED_10: + phydev->speed = SPEED_10; + break; + case QCA807X_SS_SPEED_100: + phydev->speed = SPEED_100; + break; + case QCA807X_SS_SPEED_1000: + phydev->speed = SPEED_1000; + break; + } + if (ss & QCA807X_SS_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + if (ss & QCA807X_SS_MDIX) + phydev->mdix = ETH_TP_MDI_X; + else + phydev->mdix = ETH_TP_MDI; + + switch (FIELD_GET(QCA807X_FC_MDI_CROSSOVER_MODE_MASK, sfc)) { + case QCA807X_FC_MDI_CROSSOVER_MANUAL_MDI: + phydev->mdix_ctrl = ETH_TP_MDI; + break; + case QCA807X_FC_MDI_CROSSOVER_MANUAL_MDIX: + phydev->mdix_ctrl = ETH_TP_MDI_X; + break; + case QCA807X_FC_MDI_CROSSOVER_AUTO: + phydev->mdix_ctrl = ETH_TP_MDI_AUTO; + break; + } + } + + if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) + phy_resolve_aneg_pause(phydev); + + return 0; +} + +static int qca807x_read_fiber_status(struct phy_device *phydev, bool combo_port) +{ + int ss, err, page; + + if (phydev->port != PORT_FIBRE) + phydev->port = PORT_FIBRE; + + /* Check whether fiber page is set and set if needed */ + page = phy_read(phydev, QCA807X_CHIP_CONFIGURATION); + if (page & QCA807X_BT_BX_REG_SEL) { + page &= ~QCA807X_BT_BX_REG_SEL; + phy_write(phydev, QCA807X_CHIP_CONFIGURATION, page); + } + + err = genphy_c37_read_status(phydev); + if (err) + return err; + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + + /* Read the QCA807x PHY-Specific Status register fiber page, + * which indicates the speed and duplex that the PHY is actually + * using, irrespective of whether we are in autoneg mode or not. + */ + ss = phy_read(phydev, QCA807X_PHY_SPECIFIC_STATUS); + if (ss < 0) + return ss; + + if (ss & QCA807X_SS_SPEED_AND_DUPLEX_RESOLVED) { + switch (FIELD_GET(QCA807X_SS_SPEED_MASK, ss)) { + case QCA807X_SS_SPEED_100: + phydev->speed = SPEED_100; + break; + case QCA807X_SS_SPEED_1000: + phydev->speed = SPEED_1000; + break; + } + + if (ss & QCA807X_SS_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + } + + return 0; +} + +static int qca807x_read_status(struct phy_device *phydev) +{ + int val; + + /* Check for Combo port */ + if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) { + /* Check for fiber mode first */ + if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) { + /* Check for actual detected media */ + val = phy_read(phydev, QCA807X_MEDIA_SELECT_STATUS); + if (val & QCA807X_MEDIA_DETECTED_COPPER) { + qca807x_read_copper_status(phydev, true); + } else if ((val & QCA807X_MEDIA_DETECTED_1000_BASE_X) || + (val & QCA807X_MEDIA_DETECTED_100_BASE_FX)) { + qca807x_read_fiber_status(phydev, true); + } + } else { + qca807x_read_copper_status(phydev, true); + } + } else { + qca807x_read_copper_status(phydev, false); + } + + return 0; +} + +static int qca807x_ack_intr(struct phy_device *phydev) +{ + int ret; + + ret = phy_read(phydev, QCA807X_INTR_STATUS); + + return (ret < 0) ? ret : 0; +} + +static int qca807x_config_intr(struct phy_device *phydev) +{ + int ret, val; + + val = phy_read(phydev, QCA807X_INTR_ENABLE); + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* Clear any pending interrupts */ + ret = qca807x_ack_intr(phydev); + if (ret) + return ret; + /* Check for combo port as it has fewer interrupts */ + if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) { + val |= QCA807X_INTR_ENABLE_SPEED_CHANGED; + val |= QCA807X_INTR_ENABLE_LINK_FAIL; + val |= QCA807X_INTR_ENABLE_LINK_SUCCESS; + } else { + val |= QCA807X_INTR_ENABLE_AUTONEG_ERR; + val |= QCA807X_INTR_ENABLE_SPEED_CHANGED; + val |= QCA807X_INTR_ENABLE_DUPLEX_CHANGED; + val |= QCA807X_INTR_ENABLE_LINK_FAIL; + val |= QCA807X_INTR_ENABLE_LINK_SUCCESS; + } + ret = phy_write(phydev, QCA807X_INTR_ENABLE, val); + } else { + ret = phy_write(phydev, QCA807X_INTR_ENABLE, 0); + if (ret) + return ret; + + /* Clear any pending interrupts */ + ret = qca807x_ack_intr(phydev); + } + + return ret; +} + +static irqreturn_t qca807x_handle_interrupt(struct phy_device *phydev) +{ + int irq_status, int_enabled; + + irq_status = phy_read(phydev, QCA807X_INTR_STATUS); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* Read the current enabled interrupts */ + int_enabled = phy_read(phydev, QCA807X_INTR_ENABLE); + if (int_enabled < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* See if this was one of our enabled interrupts */ + if (!(irq_status & int_enabled)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + +static int qca807x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) +{ + struct phy_device *phydev = upstream; + __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; + phy_interface_t iface; + + sfp_parse_support(phydev->sfp_bus, id, support); + iface = sfp_select_interface(phydev->sfp_bus, support); + + if (iface != PHY_INTERFACE_MODE_1000BASEX && + iface != PHY_INTERFACE_MODE_SGMII) { + dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); + return -EINVAL; + } + + return 0; +} + +static const struct sfp_upstream_ops qca807x_sfp_ops = { + .attach = phy_sfp_attach, + .detach = phy_sfp_detach, + .module_insert = qca807x_sfp_insert, +}; + +static int qca807x_config(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + int control_dac, ret = 0; + u32 of_control_dac; + + /* Check for Combo port */ + if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) { + int fiber_mode_autodect; + int psgmii_serdes; + int chip_config; + + if (of_property_read_bool(node, "qcom,fiber-enable")) { + /* Enable fiber mode autodection (1000Base-X or 100Base-FX) */ + fiber_mode_autodect = phy_read_mmd(phydev, MDIO_MMD_AN, + QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION); + fiber_mode_autodect |= QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN; + phy_write_mmd(phydev, MDIO_MMD_AN, QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION, + fiber_mode_autodect); + + /* Enable 4 copper + combo port mode */ + chip_config = phy_read(phydev, QCA807X_CHIP_CONFIGURATION); + chip_config &= ~QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK; + chip_config |= FIELD_PREP(QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK, + QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER); + phy_write(phydev, QCA807X_CHIP_CONFIGURATION, chip_config); + + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising); + } + + /* Prevent PSGMII going into hibernation via PSGMII self test */ + psgmii_serdes = phy_read_mmd(phydev, MDIO_MMD_PCS, PSGMII_MMD3_SERDES_CONTROL); + psgmii_serdes &= ~BIT(1); + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, + PSGMII_MMD3_SERDES_CONTROL, + psgmii_serdes); + } + + if (!of_property_read_u32(node, "qcom,control-dac", &of_control_dac)) { + control_dac = phy_read_mmd(phydev, MDIO_MMD_AN, + QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH); + control_dac &= ~QCA807X_CONTROL_DAC_MASK; + control_dac |= FIELD_PREP(QCA807X_CONTROL_DAC_MASK, of_control_dac); + ret = phy_write_mmd(phydev, MDIO_MMD_AN, + QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH, + control_dac); + } + + return ret; +} + +static int qca807x_probe(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + int ret = 0; + + if (IS_ENABLED(CONFIG_GPIOLIB)) { + /* Do not register a GPIO controller unless flagged for it */ + if (of_property_read_bool(node, "gpio-controller")) + ret = qca807x_gpio(phydev); + } + + /* Attach SFP bus on combo port*/ + if (of_property_read_bool(node, "qcom,fiber-enable")) { + if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) + ret = phy_sfp_probe(phydev, &qca807x_sfp_ops); + } + + return ret; +} + +static int qca807x_psgmii_config(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + int psgmii_az, tx_amp, ret = 0; + u32 tx_driver_strength_dt; + + /* Workaround to enable AZ transmitting ability */ + if (of_property_read_bool(node, "qcom,psgmii-az")) { + psgmii_az = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, PSGMII_MODE_CTRL); + psgmii_az &= ~PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK; + psgmii_az |= FIELD_PREP(PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK, 0xc); + ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, PSGMII_MODE_CTRL, psgmii_az); + psgmii_az = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, PSGMII_MODE_CTRL); + } + + /* PSGMII/QSGMII TX amp set to DT defined value instead of default 600mV */ + if (!of_property_read_u32(node, "qcom,tx-driver-strength", &tx_driver_strength_dt)) { + int tx_driver_strength; + + switch (tx_driver_strength_dt) { + case 140: + tx_driver_strength = 0; + break; + case 160: + tx_driver_strength = 1; + break; + case 180: + tx_driver_strength = 2; + break; + case 200: + tx_driver_strength = 3; + break; + case 220: + tx_driver_strength = 4; + break; + case 240: + tx_driver_strength = 5; + break; + case 260: + tx_driver_strength = 6; + break; + case 280: + tx_driver_strength = 7; + break; + case 300: + tx_driver_strength = 8; + break; + case 320: + tx_driver_strength = 9; + break; + case 400: + tx_driver_strength = 10; + break; + case 500: + tx_driver_strength = 11; + break; + case 600: + tx_driver_strength = 12; + break; + default: + tx_driver_strength = 12; + break; + } + + tx_amp = phy_read(phydev, PSGMII_QSGMII_DRIVE_CONTROL_1); + tx_amp &= ~PSGMII_QSGMII_TX_DRIVER_MASK; + tx_amp |= FIELD_PREP(PSGMII_QSGMII_TX_DRIVER_MASK, tx_driver_strength); + ret = phy_write(phydev, PSGMII_QSGMII_DRIVE_CONTROL_1, tx_amp); + } + + return ret; +} + +static struct phy_driver qca807x_drivers[] = { + { + PHY_ID_MATCH_EXACT(PHY_ID_QCA8072), + .name = "Qualcomm QCA8072", + .flags = PHY_POLL_CABLE_TEST, + /* PHY_GBIT_FEATURES */ + .probe = qca807x_probe, + .config_init = qca807x_config, + .read_status = qca807x_read_status, + .config_intr = qca807x_config_intr, + .handle_interrupt = qca807x_handle_interrupt, + .soft_reset = genphy_soft_reset, + .get_tunable = qca807x_get_tunable, + .set_tunable = qca807x_set_tunable, + .cable_test_start = qca807x_cable_test_start, + .cable_test_get_status = qca807x_cable_test_get_status, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_QCA8075), + .name = "Qualcomm QCA8075", + .flags = PHY_POLL_CABLE_TEST, + /* PHY_GBIT_FEATURES */ + .probe = qca807x_probe, + .config_init = qca807x_config, + .read_status = qca807x_read_status, + .config_intr = qca807x_config_intr, + .handle_interrupt = qca807x_handle_interrupt, + .soft_reset = genphy_soft_reset, + .get_tunable = qca807x_get_tunable, + .set_tunable = qca807x_set_tunable, + .cable_test_start = qca807x_cable_test_start, + .cable_test_get_status = qca807x_cable_test_get_status, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_QCA807X_PSGMII), + .name = "Qualcomm QCA807x PSGMII", + .probe = qca807x_psgmii_config, + }, +}; +module_phy_driver(qca807x_drivers); + +static struct mdio_device_id __maybe_unused qca807x_tbl[] = { + { PHY_ID_MATCH_EXACT(PHY_ID_QCA8072) }, + { PHY_ID_MATCH_EXACT(PHY_ID_QCA8075) }, + { PHY_ID_MATCH_MODEL(PHY_ID_QCA807X_PSGMII) }, + { } +}; + +MODULE_AUTHOR("Robert Marko"); +MODULE_DESCRIPTION("Qualcomm QCA807x PHY driver"); +MODULE_DEVICE_TABLE(mdio, qca807x_tbl); +MODULE_LICENSE("GPL"); From patchwork Wed Feb 10 12:55:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robert Marko X-Patchwork-Id: 12080825 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=-13.9 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED,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 23F47C4332B for ; Wed, 10 Feb 2021 12:58:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EA41B64E66 for ; Wed, 10 Feb 2021 12:58:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231732AbhBJM6W (ORCPT ); Wed, 10 Feb 2021 07:58:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49618 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231511AbhBJM51 (ORCPT ); Wed, 10 Feb 2021 07:57:27 -0500 Received: from mail-ej1-x636.google.com (mail-ej1-x636.google.com [IPv6:2a00:1450:4864:20::636]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 832B4C06121D for ; Wed, 10 Feb 2021 04:55:38 -0800 (PST) Received: by mail-ej1-x636.google.com with SMTP id l25so3965468eja.9 for ; Wed, 10 Feb 2021 04:55:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sartura-hr.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=6HSMvuiMGiIfphZU4Vo/CX2mIjsqBu8/UXWK69Lqxos=; b=zT46NYVFSrGggVIbyOEEogHPPkm1SqFJytRsLCRtmsrCeYHkABUo1c5aMMeLk3xMa0 fHNyLS1B8zkjBA3HKJYal0l77ch2d06q6LGLz0UajkbyRjvFvWIbwouMu+wRkX9w6oJ1 tDrDzQXXmo+zKFy5eevThg3/xqW8r35rad3/6B43Pm4PoLlxg410b8se0Osm2U4w1da/ ijfiN/Mh+SKwaBBV6X7Pq4a20EOzkQ3wONJrOi+h2Fa01GT80AGeq0F/W95cbOKKzqM6 +ohEjIsLMZA/iCYluvXPIPbTgANGOlVI+6ttA2dSLowAaivIwkEivFfbqgfuWY4wGt5B 1JQw== 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=6HSMvuiMGiIfphZU4Vo/CX2mIjsqBu8/UXWK69Lqxos=; b=g8rQ6W//wANwHWjRAaEto8FYkMp/glOrAaMy1pNAqd2q5CKznklAIIHkIhJi0EGoEO frC+Iz7dazKUzspVz3fD8mXQ5aBY8auoXzg7qt+twCLMy7qnVo+5vkesiDaPi8M+zKDO m0cdk/JYrisi8GdJpoBeh/LHGG8hBjFKG3jMX90kS3UeFZGSBzbU2cIsv431qVzlftHf naYWZYZbaZJZdzcikg9lscBXMYAefejRHwF1tfo6M8CxIEsWjiPsgqYflDGhfFf6ZhkD HQgfzwfqi2tPFj/be05FDYUtSxo4T4aID4pIainCX0yM43F9pRbA+BIrI627mn3GtQ7k 8Kpg== X-Gm-Message-State: AOAM531R7K9DPG2ja30P2KstGNQFWKXG4oOiABHutG4Bs5mmV0niSgO2 n23q9jiJj2gJg6edo1mCD38gP0U6FdD0QHZq X-Google-Smtp-Source: ABdhPJw2tDiJeYgQ037lzOwHWXvaUdM+6n6I0eYa1cOOaAGbTOYbsnhNFTTPb9Guc0Dz/JYnVxmMmQ== X-Received: by 2002:a17:906:719:: with SMTP id y25mr2781547ejb.180.1612961737261; Wed, 10 Feb 2021 04:55:37 -0800 (PST) Received: from localhost.localdomain (dh207-97-164.xnet.hr. [88.207.97.164]) by smtp.googlemail.com with ESMTPSA id u5sm1084900edc.29.2021.02.10.04.55.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Feb 2021 04:55:36 -0800 (PST) From: Robert Marko To: agross@kernel.org, bjorn.andersson@linaro.org, robh+dt@kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, davem@davemloft.net, kuba@kernel.org, netdev@vger.kernel.org, andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk Cc: Robert Marko , Luka Perkov Subject: [PATCH v2 net-next 4/4] MAINTAINERS: Add entry for Qualcomm QCA807x PHY driver Date: Wed, 10 Feb 2021 13:55:23 +0100 Message-Id: <20210210125523.2146352-5-robert.marko@sartura.hr> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210210125523.2146352-1-robert.marko@sartura.hr> References: <20210210125523.2146352-1-robert.marko@sartura.hr> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org Add maintainers entry for the Qualcomm QCA807x PHY driver. Signed-off-by: Robert Marko Cc: Luka Perkov --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 667d03852191..48f32ef108d5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14775,6 +14775,15 @@ S: Maintained F: Documentation/devicetree/bindings/regulator/vqmmc-ipq4019-regulator.yaml F: drivers/regulator/vqmmc-ipq4019-regulator.c +QUALCOMM QCA807X PHY DRIVER +M: Robert Marko +M: Luka Perkov +L: linux-arm-msm@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/net/qcom,qca807x.yaml +F: drivers/net/phy/qca807x.c +F: include/dt-bindings/net/qcom-qca807x.h + QUALCOMM RMNET DRIVER M: Subash Abhinov Kasiviswanathan M: Sean Tranchetti