From patchwork Tue Jun 21 08:46:11 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: thloh@altera.com X-Patchwork-Id: 638566 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3rYhDS3VMwz9sxb for ; Tue, 21 Jun 2016 18:47:04 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=altera.onmicrosoft.com header.i=@altera.onmicrosoft.com header.b=WFBZZFRt; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752652AbcFUIq7 (ORCPT ); Tue, 21 Jun 2016 04:46:59 -0400 Received: from mail-bn1bon0056.outbound.protection.outlook.com ([157.56.111.56]:33284 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751539AbcFUIqS (ORCPT ); Tue, 21 Jun 2016 04:46:18 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=altera.onmicrosoft.com; s=selector1-altera-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=n7K2J0JDhp/V22m3leTcoJX0xV5jE2PJkNLflDrU9Zw=; b=WFBZZFRteEF4H11Q0l2wMGmIbSn0TLesgvzmu8MguUX/rmxUxSI8r92l9jMzHjCXt1iL4jle79ECdgDIfyJSkjhS60VcHuGfLJluv4QWPWz82Iis8qse8aHu0gMTqHntIOmoSQAY6jeARdO6K19/NWrKqX7lSTD5gGTtdsRANyU= Received: from BLUPR0301CA0012.namprd03.prod.outlook.com (10.162.113.150) by BN1PR03MB105.namprd03.prod.outlook.com (10.255.201.11) with Microsoft SMTP Server (TLS) id 15.1.492.11; Tue, 21 Jun 2016 08:46:05 +0000 Received: from BL2FFO11OLC006.protection.gbl (2a01:111:f400:7c09::125) by BLUPR0301CA0012.outlook.office365.com (2a01:111:e400:5259::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.523.12 via Frontend Transport; Tue, 21 Jun 2016 08:46:05 +0000 Authentication-Results: spf=softfail (sender IP is 66.35.236.227) smtp.mailfrom=altera.com; st.com; dkim=none (message not signed) header.d=none; st.com; dmarc=none action=none header.from=altera.com; Received-SPF: SoftFail (protection.outlook.com: domain of transitioning altera.com discourages use of 66.35.236.227 as permitted sender) Received: from sj-itexedge03.altera.priv.altera.com (66.35.236.227) by BL2FFO11OLC006.mail.protection.outlook.com (10.173.160.95) with Microsoft SMTP Server (TLS) id 15.1.517.7 via Frontend Transport; Tue, 21 Jun 2016 08:46:05 +0000 Received: from sj-mail01.altera.com (137.57.1.6) by webmail.altera.com (66.35.236.227) with Microsoft SMTP Server (TLS) id 14.3.174.1; Tue, 21 Jun 2016 01:45:46 -0700 Received: from ubuntu (pg-thloh-l.altera.com [10.142.36.106]) by sj-mail01.altera.com (8.13.7+Sun/8.13.7) with SMTP id u5L8jw83025682; Tue, 21 Jun 2016 01:45:59 -0700 (PDT) Received: by ubuntu (sSMTP sendmail emulation); Tue, 21 Jun 2016 01:46:13 -0700 From: To: , , , , , , , , , , , , Subject: [PATCH V4 1/1] net: ethernet: Add TSE PCS support to dwmac-socfpga Date: Tue, 21 Jun 2016 01:46:11 -0700 Message-ID: <1466498771-18971-1-git-send-email-thloh@altera.com> X-Mailer: git-send-email 1.7.9.5 MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:66.35.236.227; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(7916002)(2980300002)(199003)(189002)(19580405001)(7846002)(19580395003)(2876002)(68736007)(586003)(15975445007)(48376002)(189998001)(50226002)(50986999)(2906002)(7049001)(8936002)(87936001)(42186005)(50466002)(81166006)(81156014)(36756003)(8676002)(33646002)(86152002)(356003)(6806005)(92566002)(5001770100001)(107886002)(2201001)(47776003)(575784001)(97736004)(4001450100002)(86362001)(106466001)(229853001)(5003940100001)(105596002)(11100500001)(7099028)(2004002)(921003)(217873001)(4720700001)(1121003); DIR:OUT; SFP:1101; SCL:1; SRVR:BN1PR03MB105; H:sj-itexedge03.altera.priv.altera.com; FPR:; SPF:SoftFail; PTR:InfoDomainNonexistent; A:1; MX:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BL2FFO11OLC006; 1:FYMb0ac6znRnXUt8lLB+4xGnJcpwE/k5IOzLnnSl8luG9ywdIAQUrtIJDsuSGRfsnlVlKDotIWrMOR5niHAu2K/LTbFVXXHO5g2FFSPkwSgqFW7r8qKU5mW3O1mwrYLzKQZsaW9hlhEnFUMoL1I07D+W+lh54GdhsCRiiCUYcYjLtbYpgbUV31wSeeqpVkThLncEvfe9Ib4cXhwhn0B7kKHBrki7dRC65ZbzLi5n0ZaIJY6Wa8OepsQqeBSIPfUjsyGZm06EjpKyEJqEeHecRz9hFDZbMrNCaWtdBaAWBL6xVHevJVL4/e3FfFv91EaY3mw8ERdut9YJaL3/gBVn7KMY6WEBar6PvE2tTv3uGxQwcK/T4M9ndiLnd9T/CwtcTTJ4/fQhqZ2Vg5nrpfdapsq3DlkmjOJv7CdzIeHm1iDVzUZ/HOB3DpkvooeX/Hjnks5UDetHzNJSVArl0gvfaQ39qXwE7Clz+PTDVuaotBaMoi5FQ8T6ckAaULetr8eJGv6GEG6SPzibLoKlzKSdvnrMnl8Y7eglpTETC9qdYHQ9awStE0q6tSx/+/2Xg7YA X-MS-Office365-Filtering-Correlation-Id: afe058d3-dc4f-4861-92a5-08d399b07b7b X-Microsoft-Exchange-Diagnostics: 1; BN1PR03MB105; 2:eTcOEunxyis+8oZQrTXAYzz4InV1mE9S18cxFXoNHq0LpgAO7UEU60QojQVl/ozu9Q7vBVx1VoBln3KWl2oYmFrq3clLHBgH5agchlhGHhpY4sNB6MJ/5hgQt3ZYYaTXnFT1oIINl7dqg/Q+VAn02MkkftHYBzW8p2EuSlQBoa3FjMi94DrGQjZ5q79jhOuB; 3:eYEY0rBEFGsLPLf2mBV4vV9DC5qVh8vQbp7rCantXbqFWYN7kARpbDdgC9KvhIj5SiUgWLQJirOmrgZpgS6qNin6VK/agqeoz+phaahZmMzAKDE8IvGIalrpi9iRUvtC8uWsyz5+pX2I3gDMPQZ0IpoDaX6OWVftNvd7jvakjubMny2RAmpjHoIyk/Ti/ycOk2cmPYvPC8/KZn4R19oL9nCn719rBTCuQJqbDsPXNPk= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BN1PR03MB105; X-Microsoft-Exchange-Diagnostics: 1; BN1PR03MB105; 25:AzZ8x7EeetBQbYVSJ7iISp8XoVzYmTRWDTer06wxP+63UfWj9qIH/MvmFcaaZd4kNqG4s0qFYF50zTaH2G3CjC5nh8oSpBRsZ/iQCA1DkrAns5KOzj5wVLvFSXRK2CSRHVheSLg3ByuTSUvM3aiwyZGF2CASK3zrq2q9jrhNA0VNmanLctBAm4/+g0yr7QpVgo2JS81N/cmOLKa8qmDvn+2Kv8CPzMed+HfUURvd5ZeK/zDqAHBpaLmjWZ09aanGYlqW3clxHIHIlivRlDGTmv4bz0SgDjwfuYyu4eJI+TqwlloHOz93mN+ih3iF056VoSBYZauWKat5SnWJZKyDcIGk5MeQmzLTlYWBRxq5zGY2jejSFKahdpHcVHuHP1yQ8SFm4c/EnmXSxTqf7lhAYFpVl/a/Vr7RlBw7P45Sua+etUMhvQ9kfPer/ryOhKgAvgyJft9DAOxx3yFURbrzfn4BlPH4CbQXELBYBr6UO+0xlCOAuPxQPDWovUbEJ5bbDx2fotvoDhthyh9LbcgWahAQM2QQq1YJzCNNSfG/HiiALP6kEdDT7Mzam2ooDmi6Va4debLYAu5ClR9mABEf/Q8kSPjr/QqOPIHhYMjdVbWK2TUI0Kjgx3OUPnuS8kvm1wkt1OdAeM//y1VkGSufvZQ8vT4Vyga0Uwn77NtkzuzkpPbwFK1N7X8ek3JS7V/MIXHqBg8Z+iWsGvS2QrVtpQtfPDlNCKkugdgtBqtOfnOMEb1m+DSpxepqsLSySj9ULxZuEBFXGQibFNaSAObRF6zcBDT3B19PO1F49kU063mQN4D/noJC4Rl9EbubWey9Hc3638DriW7rTNvZI33mGg== X-Microsoft-Exchange-Diagnostics: 1; BN1PR03MB105; 20:tj/d2zw+WTVHvfVLv37TpSxQJAqqSIhB334je261zJJLCV4T2px/CTyp+O24mQGfAtVKmww0D/y6gwQvy80s6tNIYYH4FF9wp4QaagzQA3Kv2i+ht2hCaPkzrV6j5q2SWKakJDKNTUZFE42nCf7/HuqNBYCGlbq5f8L0JOejKBc=; 4:mneW2uOP/R826FuUPDbXuNmj+sHyJuEzXbHMV8o3atY23Aakt8tgKIJATDVFXQtxDBl3qX4wLxaYlVcwk9mtu7p/EhpJbcRlTTf+DMTu1bN2EKLqxCfrfHKeWpdtVPDxvB5JMCZQQ/xmQu593dLbkIVvGkkovmY1gjdDSXMhTMYQcIoI64O8U8GK5jvLHzoQphb5pWatk32B/ODncpkaN2pb7+WLM/ouyR+3tWHARraCnVUwxDVrZV84TO60lDNpwyqKIsHE2F4A9Kwcsi+uBfH6givnSTP9c/6ZO65unZMI66Cszq2UEUxEJzZSGlLdBy/lf6KQ5qX1v1ayOy1kdYR6+7p/SldOSGPl5r2P7xbaYbY5sJeLigQQh2taxjppF8tbd2sRdUns6HviYCriHZhIyd0C5EVc1TiE5pnfKvg6jJ0HaFsRZDELBsnSvX1CvyRcErhDWi+pCZ1HJUlTPNoQkjTtkevalfYzS6YmU/RzdEtT0vCk5scs7ABwGlX18/8SGSmlro59ZAvNpDIjxohOF4nrR762kU3DA2+qFJjMbNpQ+YsabAKBSUObS3H3fjmXT7Z7E884kvBUcJEO8w== X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(250305191791016)(22074186197030)(80048183373757); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(13018025)(13017025)(13024025)(13023025)(13015025)(5005006)(8121501046)(10201501046)(3002001)(6055026); SRVR:BN1PR03MB105; BCL:0; PCL:0; RULEID:; SRVR:BN1PR03MB105; X-Forefront-PRVS: 098076C36C X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BN1PR03MB105; 23:1NO4orAAfk87oLpJ2rSB7/q8u4H6UXyf66GJxw+B+d?= =?us-ascii?Q?Ue2APKjcMZWubQwJVq7ymLjYwSVSBbkyUepaYfYW9wpbGHYgm34V/Wyx3WpD?= =?us-ascii?Q?NFBE1pQgmOPKrzVv1wqNhw/MGYfM+WvDwlQFTpGYEV8p1F2I+/ehXTO7S4V1?= =?us-ascii?Q?dtXoW7TdzPJxAg7ZUuH8cggRKibYV6SeCUpxtDu/boUqHkhUXd3Bj/A3HVH4?= =?us-ascii?Q?gG1AWCXzHBmHW5S61+au1u3kfcl4XNlmHxNqdFQEJIo2JFa+WkOzuohEUTbr?= =?us-ascii?Q?4VYR0n6X7uhpmxakrnTr7uXyulZ/Idz8lM0OQyLH0Yv6bwT3b4ZK7de2p9Jt?= =?us-ascii?Q?PDRvs1O1ND3zkAgEZxhS8TuiQ6y8TKf8vDBxhxuMBCTKe8JCZVEyrd+tkNhV?= =?us-ascii?Q?FI9Q79TLjEIiIa1hLJb8du1G6OqCmDORl2aPu6pwbO958XqlJamQF6G8EExX?= =?us-ascii?Q?ZP8eQKkIfdpqWnamjd9A8tXO2O4nI0sxr9Km2DxCRheOfzXoYNuM/4JmkPkx?= =?us-ascii?Q?8QomSpq4btjHU/8c01mf+q10CpQ7h44F0Q5L4x9eTRI82x7wNHX1bbA8BEmR?= =?us-ascii?Q?+gnE1v3i0aWo/AAmrfVPPOo+dNUSCHmKu3DXydmgVt7u4ThYd9OcuN5sRVC+?= =?us-ascii?Q?tV0/gHwrf9ASNMuJsSEQ9nu1C5+YEZE28yJuWTTxKnQO6WQEo6wedsrUW29I?= =?us-ascii?Q?zwqx3ejYA2cbBox1OnDOWNbyWua1bAb3LCOzWCiOvmclnMePbm75RZ7yDUgK?= =?us-ascii?Q?T2Yu6/Wdv4GFakG9XUGAyDXpOwSOHWSmLc0SvFNNXiYFItqvDJ+O+quPi0GJ?= =?us-ascii?Q?rCCos4D2ZRtu7jOoPP6f9LRVLoJUOmFf7HPNh3yF6ravJqlvLSJTLKOVG7c6?= =?us-ascii?Q?LpIzLBw4z8rPJdbd5Dc5hku5DdY2rObACIpik/R3FlICobfP8U6WcJgEkRbO?= =?us-ascii?Q?AbpaZ1cjvjNJfQHefKywMiZ0NQ9bKtpTJNXq0TsTNIfKqN7iR4xt+YIFVw7Z?= =?us-ascii?Q?9qyn5/PquB7b1cl5uTYERi/qXE53cdj8lOAFgeK3odBiX4Tz3DG/nE213GMN?= =?us-ascii?Q?aogkCcB/TmcmM5oz1Zl/RkXGEizjpNVWWW0L/1WLSVUmnU1OrfAAO4vp+ufs?= =?us-ascii?Q?+67Nu8gp552Oo1/UPICguRG0KGCehynLQYE9yDaanBzBy6jz4XqP/bsbVQBP?= =?us-ascii?Q?eosm8tqssG0IU+ssEJekcJ4wunoZRYZlc/7o9LwZ4TaZU7NOesVK0ea5IKSN?= =?us-ascii?Q?xYlU1p4AnENAuewVs=3D?= X-Microsoft-Exchange-Diagnostics: 1; BN1PR03MB105; 5:2mGqErABM5BwI59QyUf7yMukpgzm204zfr5WXYbIl6fyuLjwZsZjT9GzShukKfBBlrPvDhfcbJpW7DFqwnZxAY7ngyZmmr4zj0AXkr+WC9hZ/H6rYtwXLSA3wE25I+1x5Q6CoWE2nkcFkup7bzYtcg==; 24:rrSuwxKDQiayogQJ9UmTAEyho5HWgADnYdhCc3gd2JZOgEJzql5pB2esmoqcYk6/Bs1MjC33KGpWDUOVkEFGnIdjl0keUnATzBjN1fc9LfQ=; 7:t2KFsVDicyuTMkd+RHpI7V48jmzbmTbunSSofTjCq9IbRovV6sQQMytq9MpNjwPTJBVwLzS0Bdg+8rH3tvUS+dTyOeyY583gyLQLhiS9H7NErNgVqPFWv39vLJ8+QJL4wZGhLc7Tx2+/8FOdnSt7Vnnu1W0fa0DA8x60PGd2X2cPrH5ACrjFTP2E+0DkVTNnQgXWX3zOWRadToOsxMnE8w==; 20:6F6qWLx4hPchcuIvHJ8534mjKP4YJm42qukyKqFprsn8yxTfyXyWmXVJJ2feqOmxdbPwiYwhfebEv43Y5Ubg7d9wijvmlWR9sCfZM3ZzLmdeUZETUUtI5ikjU7pC+Cie30Dmr/diPw0nE2wcntY7ba2rJx9kpxeONVdwFyie1wY= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: altera.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Jun 2016 08:46:05.0305 (UTC) X-MS-Exchange-CrossTenant-Id: fbd72e03-d4a5-4110-adce-614d51f2077a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=fbd72e03-d4a5-4110-adce-614d51f2077a; Ip=[66.35.236.227]; Helo=[sj-itexedge03.altera.priv.altera.com] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN1PR03MB105 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Tien Hock Loh This adds support for TSE PCS that uses SGMII adapter when the phy-mode of the dwmac is set to sgmii Signed-off-by: Tien Hock Loh Acked-by: Giuseppe Cavallaro --- v2: - Refactored the TSE PCS out from the dwmac-socfpga.c file - Added binding documentation for TSE PCS sgmii adapter v3: - Added missing license header for new source files - Updated tse_pcs.h include headers - Standardize if statements v4: - Reset SGMII adapter on speed change - Do not enable SGMII adapter if speed is not supported - On init, if PCS reset fails, do not enable adapter 123 --- .../devicetree/bindings/net/socfpga-dwmac.txt | 19 ++ drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +- drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c | 276 +++++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h | 36 +++ .../net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 149 +++++++++-- 5 files changed, 460 insertions(+), 22 deletions(-) create mode 100644 drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c create mode 100644 drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h diff --git a/Documentation/devicetree/bindings/net/socfpga-dwmac.txt b/Documentation/devicetree/bindings/net/socfpga-dwmac.txt index 72d82d6..dd10f2f 100644 --- a/Documentation/devicetree/bindings/net/socfpga-dwmac.txt +++ b/Documentation/devicetree/bindings/net/socfpga-dwmac.txt @@ -17,9 +17,26 @@ Required properties: Optional properties: altr,emac-splitter: Should be the phandle to the emac splitter soft IP node if DWMAC controller is connected emac splitter. +phy-mode: The phy mode the ethernet operates in +altr,sgmii_to_sgmii_converter: phandle to the TSE SGMII converter + +This device node has additional phandle dependency, the sgmii converter: + +Required properties: + - compatible : Should be altr,gmii-to-sgmii-2.0 + - reg-names : Should be "eth_tse_control_port" Example: +gmii_to_sgmii_converter: phy@0x100000240 { + compatible = "altr,gmii-to-sgmii-2.0"; + reg = <0x00000001 0x00000240 0x00000008>, + <0x00000001 0x00000200 0x00000040>; + reg-names = "eth_tse_control_port"; + clocks = <&sgmii_1_clk_0 &emac1 1 &sgmii_clk_125 &sgmii_clk_125>; + clock-names = "tse_pcs_ref_clk_clock_connection", "tse_rx_cdr_refclk"; +}; + gmac0: ethernet@ff700000 { compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac"; altr,sysmgr-syscon = <&sysmgr 0x60 0>; @@ -30,4 +47,6 @@ gmac0: ethernet@ff700000 { mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ clocks = <&emac_0_clk>; clock-names = "stmmaceth"; + phy-mode = "sgmii"; + altr,gmii-to-sgmii-converter = <&gmii_to_sgmii_converter>; }; diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 0fb362d..0ff76e8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -11,7 +11,7 @@ obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o -obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o +obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o altr_tse_pcs.o obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c new file mode 100644 index 0000000..40bfaac --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c @@ -0,0 +1,276 @@ +/* Copyright Altera Corporation (C) 2016. 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, + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Author: Tien Hock Loh + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stmmac.h" +#include "stmmac_platform.h" +#include "altr_tse_pcs.h" + +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII BIT(1) +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII BIT(2) +#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK GENMASK(1, 0) + +#define TSE_PCS_CONTROL_AN_EN_MASK BIT(12) +#define TSE_PCS_CONTROL_REG 0x00 +#define TSE_PCS_CONTROL_RESTART_AN_MASK BIT(9) +#define TSE_PCS_IF_MODE_REG 0x28 +#define TSE_PCS_LINK_TIMER_0_REG 0x24 +#define TSE_PCS_LINK_TIMER_1_REG 0x26 +#define TSE_PCS_SIZE 0x40 +#define TSE_PCS_STATUS_AN_COMPLETED_MASK BIT(5) +#define TSE_PCS_STATUS_LINK_MASK 0x0004 +#define TSE_PCS_STATUS_REG 0x02 +#define TSE_PCS_SGMII_SPEED_1000 BIT(3) +#define TSE_PCS_SGMII_SPEED_100 BIT(2) +#define TSE_PCS_SGMII_SPEED_10 0x0 +#define TSE_PCS_SW_RST_MASK 0x8000 +#define TSE_PCS_PARTNER_ABILITY_REG 0x0A +#define TSE_PCS_PARTNER_DUPLEX_FULL 0x1000 +#define TSE_PCS_PARTNER_DUPLEX_HALF 0x0000 +#define TSE_PCS_PARTNER_DUPLEX_MASK 0x1000 +#define TSE_PCS_PARTNER_SPEED_MASK GENMASK(11, 10) +#define TSE_PCS_PARTNER_SPEED_1000 BIT(11) +#define TSE_PCS_PARTNER_SPEED_100 BIT(10) +#define TSE_PCS_PARTNER_SPEED_10 0x0000 +#define TSE_PCS_PARTNER_SPEED_1000 BIT(11) +#define TSE_PCS_PARTNER_SPEED_100 BIT(10) +#define TSE_PCS_PARTNER_SPEED_10 0x0000 +#define TSE_PCS_SGMII_SPEED_MASK GENMASK(3, 2) +#define TSE_PCS_SGMII_LINK_TIMER_0 0x0D40 +#define TSE_PCS_SGMII_LINK_TIMER_1 0x0003 +#define TSE_PCS_SW_RESET_TIMEOUT 100 +#define TSE_PCS_USE_SGMII_AN_MASK BIT(2) +#define TSE_PCS_USE_SGMII_ENA BIT(1) + +#define SGMII_ADAPTER_CTRL_REG 0x00 +#define SGMII_ADAPTER_DISABLE 0x0001 +#define SGMII_ADAPTER_ENABLE 0x0000 + +#define AUTONEGO_LINK_TIMER 20 + +static int tse_pcs_reset(void __iomem *base, struct tse_pcs *pcs) +{ + int counter = 0; + u16 val; + + val = readw(base + TSE_PCS_CONTROL_REG); + val |= TSE_PCS_SW_RST_MASK; + writew(val, base + TSE_PCS_CONTROL_REG); + + while (counter < TSE_PCS_SW_RESET_TIMEOUT) { + val = readw(base + TSE_PCS_CONTROL_REG); + val &= TSE_PCS_SW_RST_MASK; + if (val == 0) + break; + counter++; + udelay(1); + } + if (counter >= TSE_PCS_SW_RESET_TIMEOUT) { + dev_err(pcs->dev, "PCS could not get out of sw reset\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs) +{ + int ret = 0; + + writew(TSE_PCS_USE_SGMII_ENA, base + TSE_PCS_IF_MODE_REG); + + writew(TSE_PCS_SGMII_LINK_TIMER_0, base + TSE_PCS_LINK_TIMER_0_REG); + writew(TSE_PCS_SGMII_LINK_TIMER_1, base + TSE_PCS_LINK_TIMER_1_REG); + + ret = tse_pcs_reset(base, pcs); + if (ret == 0) + writew(SGMII_ADAPTER_ENABLE, + pcs->sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); + + return ret; +} + +static void pcs_link_timer_callback(unsigned long data) +{ + u16 val = 0; + + struct tse_pcs *pcs = (struct tse_pcs *)data; + void __iomem *tse_pcs_base = pcs->tse_pcs_base; + void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base; + + val = readw(tse_pcs_base + TSE_PCS_STATUS_REG); + val &= TSE_PCS_STATUS_LINK_MASK; + + if (val != 0) { + dev_dbg(pcs->dev, "Adapter: Link is established\n"); + writew(SGMII_ADAPTER_ENABLE, + sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); + } else { + mod_timer(&pcs->aneg_link_timer, jiffies + + msecs_to_jiffies(AUTONEGO_LINK_TIMER)); + } +} + +static void auto_nego_timer_callback(unsigned long data) +{ + u16 val = 0; + u16 speed = 0; + u16 duplex = 0; + + struct tse_pcs *pcs = (struct tse_pcs *)data; + void __iomem *tse_pcs_base = pcs->tse_pcs_base; + void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base; + + val = readw(tse_pcs_base + TSE_PCS_STATUS_REG); + val &= TSE_PCS_STATUS_AN_COMPLETED_MASK; + + if (val != 0) { + dev_dbg(pcs->dev, "Adapter: Auto Negotiation is completed\n"); + val = readw(tse_pcs_base + TSE_PCS_PARTNER_ABILITY_REG); + speed = val & TSE_PCS_PARTNER_SPEED_MASK; + duplex = val & TSE_PCS_PARTNER_DUPLEX_MASK; + + if (speed == TSE_PCS_PARTNER_SPEED_10 && + duplex == TSE_PCS_PARTNER_DUPLEX_FULL) + dev_dbg(pcs->dev, + "Adapter: Link Partner is Up - 10/Full\n"); + else if (speed == TSE_PCS_PARTNER_SPEED_100 && + duplex == TSE_PCS_PARTNER_DUPLEX_FULL) + dev_dbg(pcs->dev, + "Adapter: Link Partner is Up - 100/Full\n"); + else if (speed == TSE_PCS_PARTNER_SPEED_1000 && + duplex == TSE_PCS_PARTNER_DUPLEX_FULL) + dev_dbg(pcs->dev, + "Adapter: Link Partner is Up - 1000/Full\n"); + else if (speed == TSE_PCS_PARTNER_SPEED_10 && + duplex == TSE_PCS_PARTNER_DUPLEX_HALF) + dev_err(pcs->dev, + "Adapter does not support Half Duplex\n"); + else if (speed == TSE_PCS_PARTNER_SPEED_100 && + duplex == TSE_PCS_PARTNER_DUPLEX_HALF) + dev_err(pcs->dev, + "Adapter does not support Half Duplex\n"); + else if (speed == TSE_PCS_PARTNER_SPEED_1000 && + duplex == TSE_PCS_PARTNER_DUPLEX_HALF) + dev_err(pcs->dev, + "Adapter does not support Half Duplex\n"); + else + dev_err(pcs->dev, + "Adapter: Invalid Partner Speed and Duplex\n"); + + if (duplex == TSE_PCS_PARTNER_DUPLEX_FULL && + (speed == TSE_PCS_PARTNER_SPEED_10 || + speed == TSE_PCS_PARTNER_SPEED_100 || + speed == TSE_PCS_PARTNER_SPEED_1000)) + writew(SGMII_ADAPTER_ENABLE, + sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); + } else { + val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); + val |= TSE_PCS_CONTROL_RESTART_AN_MASK; + writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); + + tse_pcs_reset(tse_pcs_base, pcs); + mod_timer(&pcs->aneg_link_timer, jiffies + + msecs_to_jiffies(AUTONEGO_LINK_TIMER)); + } +} + +static void aneg_link_timer_callback(unsigned long data) +{ + struct tse_pcs *pcs = (struct tse_pcs *)data; + + if (pcs->autoneg == AUTONEG_ENABLE) + auto_nego_timer_callback(data); + else if (pcs->autoneg == AUTONEG_DISABLE) + pcs_link_timer_callback(data); +} + +void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev, + unsigned int speed) +{ + void __iomem *tse_pcs_base = pcs->tse_pcs_base; + void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base; + u32 val; + + writew(SGMII_ADAPTER_ENABLE, + sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); + + pcs->autoneg = phy_dev->autoneg; + + if (phy_dev->autoneg == AUTONEG_ENABLE) { + val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); + val |= TSE_PCS_CONTROL_AN_EN_MASK; + writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); + + val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); + val |= TSE_PCS_USE_SGMII_AN_MASK; + writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); + + val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); + val |= TSE_PCS_CONTROL_RESTART_AN_MASK; + + tse_pcs_reset(tse_pcs_base, pcs); + + setup_timer(&pcs->aneg_link_timer, + aneg_link_timer_callback, (unsigned long)pcs); + mod_timer(&pcs->aneg_link_timer, jiffies + + msecs_to_jiffies(AUTONEGO_LINK_TIMER)); + } else if (phy_dev->autoneg == AUTONEG_DISABLE) { + val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); + val &= ~TSE_PCS_CONTROL_AN_EN_MASK; + writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); + + val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); + val &= ~TSE_PCS_USE_SGMII_AN_MASK; + writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); + + val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); + val &= ~TSE_PCS_SGMII_SPEED_MASK; + + switch (speed) { + case 1000: + val |= TSE_PCS_SGMII_SPEED_1000; + break; + case 100: + val |= TSE_PCS_SGMII_SPEED_100; + break; + case 10: + val |= TSE_PCS_SGMII_SPEED_10; + break; + default: + return; + } + writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); + + tse_pcs_reset(tse_pcs_base, pcs); + + setup_timer(&pcs->aneg_link_timer, + aneg_link_timer_callback, (unsigned long)pcs); + mod_timer(&pcs->aneg_link_timer, jiffies + + msecs_to_jiffies(AUTONEGO_LINK_TIMER)); + } +} diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h new file mode 100644 index 0000000..2f58824 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h @@ -0,0 +1,36 @@ +/* Copyright Altera Corporation (C) 2016. 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, + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Author: Tien Hock Loh + */ + +#ifndef __TSE_PCS_H__ +#define __TSE_PCS_H__ + +#include +#include + +struct tse_pcs { + struct device *dev; + void __iomem *tse_pcs_base; + void __iomem *sgmii_adapter_base; + struct timer_list aneg_link_timer; + int autoneg; +}; + +int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs); +void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev, + unsigned int speed); + +#endif /* __TSE_PCS_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index f13499f..bd4008b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -27,6 +27,11 @@ #include "stmmac.h" #include "stmmac_platform.h" +#include "altr_tse_pcs.h" + +#define SGMII_ADAPTER_CTRL_REG 0x00 +#define SGMII_ADAPTER_DISABLE 0x0001 + #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 @@ -52,35 +57,46 @@ struct socfpga_dwmac { struct reset_control *stmmac_rst; void __iomem *splitter_base; bool f2h_ptp_ref_clk; + struct tse_pcs pcs; }; static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed) { struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv; void __iomem *splitter_base = dwmac->splitter_base; + void __iomem *tse_pcs_base = dwmac->pcs.tse_pcs_base; + void __iomem *sgmii_adapter_base = dwmac->pcs.sgmii_adapter_base; + struct device *dev = dwmac->dev; + struct net_device *ndev = dev_get_drvdata(dev); + struct phy_device *phy_dev = ndev->phydev; u32 val; - if (!splitter_base) - return; - - val = readl(splitter_base + EMAC_SPLITTER_CTRL_REG); - val &= ~EMAC_SPLITTER_CTRL_SPEED_MASK; - - switch (speed) { - case 1000: - val |= EMAC_SPLITTER_CTRL_SPEED_1000; - break; - case 100: - val |= EMAC_SPLITTER_CTRL_SPEED_100; - break; - case 10: - val |= EMAC_SPLITTER_CTRL_SPEED_10; - break; - default: - return; + if ((tse_pcs_base) && (sgmii_adapter_base)) + writew(SGMII_ADAPTER_DISABLE, + sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); + + if (splitter_base) { + val = readl(splitter_base + EMAC_SPLITTER_CTRL_REG); + val &= ~EMAC_SPLITTER_CTRL_SPEED_MASK; + + switch (speed) { + case 1000: + val |= EMAC_SPLITTER_CTRL_SPEED_1000; + break; + case 100: + val |= EMAC_SPLITTER_CTRL_SPEED_100; + break; + case 10: + val |= EMAC_SPLITTER_CTRL_SPEED_10; + break; + default: + return; + } + writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG); } - writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG); + if ((tse_pcs_base) && (sgmii_adapter_base)) + tse_pcs_fix_mac_speed(&dwmac->pcs, phy_dev, speed); } static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) @@ -88,9 +104,22 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device * struct device_node *np = dev->of_node; struct regmap *sys_mgr_base_addr; u32 reg_offset, reg_shift; - int ret; - struct device_node *np_splitter; + int ret, index; + struct device_node *np_splitter = NULL; + struct device_node *np_sgmii_adapter = NULL; + struct resource res_splitter; + struct resource res_tse_pcs; + struct resource res_sgmii_adapter; + + dwmac->stmmac_rst = devm_reset_control_get(dev, + STMMAC_RESOURCE_NAME); + if (IS_ERR(dwmac->stmmac_rst)) { + dev_info(dev, "Could not get reset control!\n"); + if (PTR_ERR(dwmac->stmmac_rst) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dwmac->stmmac_rst = NULL; + } dwmac->interface = of_get_phy_mode(np); @@ -128,6 +157,77 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device * } } + np_sgmii_adapter = of_parse_phandle(np, + "altr,gmii_to_sgmii_converter", 0); + if (np_sgmii_adapter) { + index = of_property_match_string(np_sgmii_adapter, "reg-names", + "hps_emac_interface_splitter_avalon_slave"); + + if (index >= 0) { + if (of_address_to_resource(np_sgmii_adapter, index, + &res_splitter)) { + dev_err(dev, + "%s: ERROR: missing emac splitter address\n", + __func__); + return -EINVAL; + } + + dwmac->splitter_base = + devm_ioremap_resource(dev, &res_splitter); + + if (IS_ERR(dwmac->splitter_base)) { + dev_err(dev, + "%s: ERROR: failed mapping emac splitter\n", + __func__); + return PTR_ERR(dwmac->splitter_base); + } + } + + index = of_property_match_string(np_sgmii_adapter, "reg-names", + "gmii_to_sgmii_adapter_avalon_slave"); + + if (index >= 0) { + if (of_address_to_resource(np_sgmii_adapter, index, + &res_sgmii_adapter)) { + dev_err(dev, + "%s: ERROR: failed mapping adapter\n", + __func__); + return -EINVAL; + } + + dwmac->pcs.sgmii_adapter_base = + devm_ioremap_resource(dev, &res_sgmii_adapter); + + if (IS_ERR(dwmac->pcs.sgmii_adapter_base)) { + dev_err(dev, "%s: failed to mapping adapter\n", + __func__); + return PTR_ERR(dwmac->pcs.sgmii_adapter_base); + } + } + + index = of_property_match_string(np_sgmii_adapter, "reg-names", + "eth_tse_control_port"); + + if (index >= 0) { + if (of_address_to_resource(np_sgmii_adapter, index, + &res_tse_pcs)) { + dev_err(dev, + "%s: ERROR: failed mapping tse control port\n", + __func__); + return -EINVAL; + } + + dwmac->pcs.tse_pcs_base = + devm_ioremap_resource(dev, &res_tse_pcs); + + if (IS_ERR(dwmac->pcs.tse_pcs_base)) { + dev_err(dev, + "%s: ERROR: failed mapping tse control port\n", + __func__); + return PTR_ERR(dwmac->pcs.sgmii_adapter_base); + } + } + } dwmac->reg_offset = reg_offset; dwmac->reg_shift = reg_shift; dwmac->sys_mgr_base_addr = sys_mgr_base_addr; @@ -151,6 +251,7 @@ static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac) break; case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_GMII: + case PHY_INTERFACE_MODE_SGMII: val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; break; default: @@ -191,6 +292,12 @@ static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac) */ if (dwmac->stmmac_rst) reset_control_deassert(dwmac->stmmac_rst); + if (phymode == PHY_INTERFACE_MODE_SGMII) { + if (tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs) != 0) { + dev_err(dwmac->dev, "Unable to initialize TSE PCS"); + return -EINVAL; + } + } return 0; }