From patchwork Fri Jun 3 09:07:15 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: 629730 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 3rLdYl0CQfz9t5R for ; Fri, 3 Jun 2016 19:08:43 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=altera.onmicrosoft.com header.i=@altera.onmicrosoft.com header.b=LnvpwUzU; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752524AbcFCJH6 (ORCPT ); Fri, 3 Jun 2016 05:07:58 -0400 Received: from mail-bl2on0055.outbound.protection.outlook.com ([65.55.169.55]:57628 "EHLO na01-bl2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751631AbcFCJHx (ORCPT ); Fri, 3 Jun 2016 05:07:53 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=altera.onmicrosoft.com; s=selector1-altera-com; h=From:To:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=O8y86P+Fx0idOM5qXA+wU2at76VnFQ4e4aJ6vjZxoKE=; b=LnvpwUzUJIRQgkg9dqZZesQROVJWgfo8H5S1HZ/bdWs7n+7+FRSQIzBVWJyjcMZ6oa//GstnnewJAmMrFpo/ikegvyNzF+7qmh5IjPjf5Kz1GAx4VlCwOGM1PZ6APotUEEoyEhXemknq4jrVydu24bDp9iVtTa6xS97jXdnjDlA= Received: from BY2PR03CA010.namprd03.prod.outlook.com (10.255.93.27) by SN2PR03MB2383.namprd03.prod.outlook.com (10.166.210.150) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.506.9; Fri, 3 Jun 2016 09:07:50 +0000 Received: from BN1AFFO11FD012.protection.gbl (10.255.93.4) by BY2PR03CA010.outlook.office365.com (10.255.93.27) with Microsoft SMTP Server (TLS) id 15.1.492.11 via Frontend Transport; Fri, 3 Jun 2016 09:07:49 +0000 Authentication-Results: spf=softfail (sender IP is 66.35.236.227) smtp.mailfrom=altera.com; vger.kernel.org; dkim=none (message not signed) header.d=none; vger.kernel.org; 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 BN1AFFO11FD012.mail.protection.outlook.com (10.58.52.72) with Microsoft SMTP Server (TLS) id 15.1.497.8 via Frontend Transport; Fri, 3 Jun 2016 09:07:49 +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; Fri, 3 Jun 2016 02:06:31 -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 u5397dnD017857; Fri, 3 Jun 2016 02:07:40 -0700 (PDT) Received: by ubuntu (sSMTP sendmail emulation); Fri, 03 Jun 2016 02:07:47 -0700 From: To: , , , , , , CC: Tien Hock Loh Subject: [PATCH 1/1] net: ethernet: Add TSE PCS support to dwmac-socfpga Date: Fri, 3 Jun 2016 02:07:15 -0700 Message-ID: <1464944835-21575-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)(2980300002)(189002)(199003)(9170700003)(5008740100001)(8676002)(86362001)(19580395003)(229853001)(575784001)(2906002)(92566002)(81166006)(5003940100001)(33646002)(86152002)(5001770100001)(42186005)(105596002)(6806005)(87936001)(2876002)(4326007)(2201001)(4001430100002)(106466001)(586003)(48376002)(47776003)(11100500001)(50226002)(8936002)(50466002)(50986999)(189998001)(36756003)(107886002)(19580405001)(7099028)(4720700001)(217873001); DIR:OUT; SFP:1101; SCL:1; SRVR:SN2PR03MB2383; H:sj-itexedge03.altera.priv.altera.com; FPR:; SPF:SoftFail; MLV:sfv; MX:1; A:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BN1AFFO11FD012; 1:Q0o9wX/2AYjgluGiqQns+Hv+a7Zf5cv4pKbf3iGJVl4ihWJgP8qwVXXiYfThW+g6rFHw9lgGoFTPHJ9+ejIt+RSjv3GT0sSJJg98uzEjj0kD5XL5UZeQswVF8erO3cC4nhx7xTNj6sJt1V8Hmz+3XZ69RLKPO0INIBu/Hb08nIM5OoTMaD9nuKO5/nh/fymFk8Y//20FCx98gDWDXxcqhPPe+I6KlOUZPGqmHNJwUU++vQu40sdaFt15X//Wp3IfReMAvxbROhcvJummjqx/4KpBDT3m+aKCSfaqreVmg50fTQQZdrHFIYvko4GMuUIKmyvYST9VhM/d97FlSwwdSIJ3iubAeDBaX+AlnhnvjAaXmzcaU3axKMk6rV2OH4SZ1wgBpUm7IMG4k9uKLRMT5UbHONCF9KystCCTwF4prQ0lbvmwts7/emijltnjpSmmg2q8O12iSpAhdRyHaLc0S/6BSLTD2jFJ/FkN9LjZWKojmH0kJTIgPXJ5RJZHATM6 X-MS-Office365-Filtering-Correlation-Id: 76597b15-a6e7-4511-41cf-08d38b8e8996 X-Microsoft-Exchange-Diagnostics: 1; SN2PR03MB2383; 2:6VLA37E/FT6nRrqqUvqm3Q6vzTHU3L1XUHK5AHIJSLlyGrFiFQeYFnbBOwu0sdws5oKK2m+Dr2YO8N3wMHns9UoEhxXCmQas8IpForULLmlMS4gLHLpn8ugESyYY7Kic/HehkrOsocNbxPEZhOPQNWyQ9sWF+Z/kCv0muVKt23KtDKwws5tzJivUWPbcMmOB; 3:FZmMf0FDjHkb8VllEN8FT52ONJw8Nhhbf3ZTXExfDa6yg1BZY6jY5QBImUyT4+qGadD/Zlx2L11Vmo9amEj27MPslwglXCJ2EQe0mavF0HDHE8id3CeHt46YNBakliWC3eglZHino158Z9qdppzQpHerM2IUEeg6pTuMtSn2BhhIhrTfR5S0dq1nl/hoS2bPNXPcJFrhXDhWu11NPraNixXqn1BcY7LEnVhC+tk8rPM=; 25:y75TCD5AbrvTS2hp12fCO0ekllGy0mZVhC5u//+C5fwF3KuekjXVq6bVajf2EvMQ+WBu4xH3zwyN0n1v/Sqp3FHZ7vL4DZ+4lu6+SxJeGewjPJOdWIRwk7mXtKq2ki0dLNJ1bYtAJnPh6lP+5dJ/7NdBkbDdlChIW/0rpXtHlVrDbNxbVs2H4VhwyeRjCySzYZ14+2l9upXhdBb0hXBNWtNRiG4NHXUgo/84ZtM23P3yPeH775Hfa+Gs68a0eNQx8F9L6QR8WZhwP+k0mFfUswb1FWfRhn+x8mrnENQ3zZTNHdoPScXSzoCIWupmyK+mAFdboCz5Wo33CdMzCp7dCwvwINCfUnz3eCkWnv9wMeRcHReGCGkU1FrRiMprDIsV6mx6Tp2eRz/zwsJmqCRHEeeQ1AZhmI5fvDXQBZ1bUfw= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:SN2PR03MB2383; X-Microsoft-Exchange-Diagnostics: 1; SN2PR03MB2383; 20:HxhLboDEpFtwjvqiPRadUvb49n8ggsiTO5wbMg32AR7ObEMY/XRCaOOZmmkv1/Z+2kRvtLIqtbmszi4wS90JGHWifETxNArhWZjR81UNsjnrZDAOnzqUnwP0XiKD9JINytnI25U8wAMjFy/9kZOZasyAqEQiqabIg5E4lrqOkII=; 4:xSHVQtJb0HnzhWY1unmrSDluwaU5PndJWhA5TCB6JVe2MgaoPPLMhUHK3aFSqekRMaIA26BVMtr79SFzbv17bJuaueRPsVkRjvnaWC+e/v5A3NgnVXxKYj56KQApd3731tQsMDTVGV0fpblkIrkga1QvwE3DBKPoAQiJBVugYCxjIu9sRSe0xGLK926Z+qooBxd3Z6jBAu5i1DauDd/LAnsa7FL9T5lI/6zXlpGq6PjBy5Pa+IB8BtOXLPe2jbvD7ss4/4de9sK7vQCEMyMHkwW4EbChpSw05Ist/CLyRZk3PzawJFnEUkqHjOTg22yqFEiWXvJpFOVFVPzD+GttN89v1YTqb8uf7tG8hktjnv7CBGb5lZ6xBahzQ3PYg2kF+gOs9ouamFZRDIN/uFLFPU2OJsNamOyQDK4ToSEgLt9lTOj2ROeCD+Q1Dnj6hET5PwloRohp5HvvzZhTmwktpJd39aCELVehANe11Wr6jS1TPuWijA8LuREkn/fvAmC11u5JBG7QeCtb3xIF9y9wXw== X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(80048183373757); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(8121501046)(13017025)(5005006)(13015025)(13024025)(13023025)(13018025)(10201501046)(3002001)(6055026); SRVR:SN2PR03MB2383; BCL:0; PCL:0; RULEID:; SRVR:SN2PR03MB2383; X-Forefront-PRVS: 0962D394D2 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; SN2PR03MB2383; 23:vOtXAZ8QWpGwKzSze4nKs8+eTtycqLtEjV/EazIc0?= =?us-ascii?Q?t3va0byFt/KDbbna4+h/qeoliU/2nm8f/IH4BxOJHWS3X/sBrfj/2nlrcR+J?= =?us-ascii?Q?YqkWkp/wGRqbH7Ct7vKYRy7L7APGFbK08gP60soc+yL3E+2hvpSjdxWh730R?= =?us-ascii?Q?VxyEAhei/rgWcK24JZ5Ll1Vf17vsBIS7hJKKfO8x9R7kp8zdkMmx4W9X0Fw8?= =?us-ascii?Q?BOksrjX8w5dlPXwQo27wa8eXja4XsVnvI29xPjf5euzEFyXqJVOOXIhw3W7o?= =?us-ascii?Q?8d9bBmpI3nE5+v0Q2TQIY/f+4NAVk4ediTL1BJJRGeaEqO+10Pf63hOBtywS?= =?us-ascii?Q?l4mx43auakcZZ58M3O9dUN/iWvwJTMNOGUr6vPZi/+HQXNEjSyn1PRZq3QqQ?= =?us-ascii?Q?/N7ehPb180gdeSNIc1x3Okw7g9G2UtZJspOrQ5LOYX7GZd9ajWlwpXgbIiJz?= =?us-ascii?Q?31Kulj6NR1U9ATPMb2+Dsv6iHHmWlpnN10ow9/gJJlK/xBx2XE5mtwoaWeTt?= =?us-ascii?Q?zhItgFP0uDCztfgLqlcd7LrJsEnP4320Xa8MamVl45bONN7Z4sq5GVqgE1Dy?= =?us-ascii?Q?qoQ+c6EkwCci4rVi0oUcIXk+MG+uDk/Xw6uqA2UE6x9Mq6hPJfl0C1OryI9b?= =?us-ascii?Q?qoVmDy7FPfU/+JC6R8TASgrIELbmOXXiYku1K2n05wfdXiI8Q27Cytc/Qpq8?= =?us-ascii?Q?NFeyXWKogOh25ohnz8N/h3BALZpVv9vov8wtTvIFNKIP0tBqKNjFkfEHCgpH?= =?us-ascii?Q?jA/SFcHK6l54qIlbnrU5tSY0mfmwUP/CD+jcy0GNx/Zb94Ql4pK6mCCkMU8c?= =?us-ascii?Q?dEXHYGE/qha4cbafNdPpkWuDtbKeHA1kgVZviA5wmPDE9GaEjg197PrppF9l?= =?us-ascii?Q?iy8iJCciZyWcHicTiej21g8f3EWC/L3p2sK7kXGgnZUfWNwx9/xufVS51PG1?= =?us-ascii?Q?yEU/hVyo0EWQ5eqsqH2hnZ1S0kJ9IpZJbYUiksEQS90ytmh4tRlSGndIptE3?= =?us-ascii?Q?whdWp1UxhLYimfcNrqquwk/ZjvdZrlFocE+lx+nkLV9ZL6Yq/kBq/4xPf3mB?= =?us-ascii?Q?spatZjcXXmlX8ozxXI39CrEP+52XU6KhoyltLHT6XdQCKvEKyq0f9tLHojXi?= =?us-ascii?Q?pONJ2dH9cI=3D?= X-Microsoft-Exchange-Diagnostics: 1; SN2PR03MB2383; 5:NTg5JL4BA78upOMbGUNiYOgqncgxyBaRdm4u0gDsh/XsGBuY+/fE3BkLywqdID/2Mc1h93V+h8sXlAgsZYKxi/4v+bngLg219cLE/o7aPHzzYPNiHzw24P73EWinUMDQFyx5QYuxi1Ovl0RfRDE6Tw==; 24:AKUwlmDKt9yaaL+ON3tP0GjFM27T0tYLhBgXpYwAGE5KII2tn2pKSSVd4lxPhyJhe/Nam8ZBIW5ASebdu9CO1v3jYKXFsN5bBbrociOqIOI=; 7:WppKN1Rpb4B3Tj3fhZK9P/WmIyfiv3/UzFJ2YwKSA5e05LHrwa+A9iL9C5OyvAqDcT2itF2YyhvF3FZdQhVSMaH1qoPe1dLS1SsY7blxzmvx7BU4VNIcnPsTXHKb9sBzRIYiuaq7RkoIjx+ozKLfzLSm2O7gDQM5LSU54MCIM3enGgqWzL5jMZXifUxbtbHdeH7Uqdf3v6gwmNRdEUOnunS9eZO8O2ZSvjvmASjmv8U=; 20:o3D6ZY0ObCliOB+e7vKcYMTIDJFH76cfrUIEQMCsxl5SYMmLAIRP3TLKx1ah/54/SvPvbdbJD47hGvncsvG76PHg4jXLk28tOzFEKv6YOmnt1Ggh5P1i823gn8QRNctIH/5rhqvWThUzJmgEIpYsOxzKf4VyxdSoizA2Diyz6Ws= SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: altera.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Jun 2016 09:07:49.5882 (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: SN2PR03MB2383 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 --- v2: - Refactored the TSE PCS out from the dwmac-socfpga.c file - Added binding documentation for TSE PCS sgmii adapter --- .../devicetree/bindings/net/socfpga-dwmac.txt | 4 + drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +- .../net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 141 ++++++++++-- drivers/net/ethernet/stmicro/stmmac/tse_pcs.c | 245 +++++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/tse_pcs.h | 11 + 5 files changed, 379 insertions(+), 24 deletions(-) create mode 100644 drivers/net/ethernet/stmicro/stmmac/tse_pcs.c create mode 100644 drivers/net/ethernet/stmicro/stmmac/tse_pcs.h diff --git a/Documentation/devicetree/bindings/net/socfpga-dwmac.txt b/Documentation/devicetree/bindings/net/socfpga-dwmac.txt index 3a9d679..2bc39f1 100644 --- a/Documentation/devicetree/bindings/net/socfpga-dwmac.txt +++ b/Documentation/devicetree/bindings/net/socfpga-dwmac.txt @@ -15,6 +15,8 @@ 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 Example: @@ -28,4 +30,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 = <&sgmii_1_gmii_to_sgmii_converter_0>; }; diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 73c2715..29c1dee 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o \ - dwmac-sti.o dwmac-socfpga.o dwmac-rk.o + dwmac-sti.o dwmac-socfpga.o dwmac-rk.o tse_pcs.o obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o stmmac-pci-objs:= stmmac_pci.o diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 3f9588e..8d04a90 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -27,6 +27,8 @@ #include "stmmac.h" #include "stmmac_platform.h" +#include "tse_pcs.h" + #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 @@ -47,48 +49,61 @@ struct socfpga_dwmac { struct regmap *sys_mgr_base_addr; struct reset_control *stmmac_rst; void __iomem *splitter_base; + 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 (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) +static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, + struct device *dev) { 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); + 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) @@ -99,6 +114,7 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device * dwmac->interface = of_get_phy_mode(np); sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon"); + if (IS_ERR(sys_mgr_base_addr)) { dev_info(dev, "No sysmgr-syscon node found\n"); return PTR_ERR(sys_mgr_base_addr); @@ -130,6 +146,74 @@ 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; @@ -153,6 +237,7 @@ static int socfpga_dwmac_setup(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: @@ -172,6 +257,10 @@ static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac) ctrl |= val << reg_shift; regmap_write(sys_mgr_base_addr, reg_offset, ctrl); + + if (phymode == PHY_INTERFACE_MODE_SGMII) + tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs); + return 0; } @@ -191,6 +280,12 @@ static void *socfpga_dwmac_probe(struct platform_device *pdev) return ERR_PTR(ret); } + ret = socfpga_dwmac_setup(dwmac); + if (ret) { + dev_err(dev, "couldn't setup SoC glue (%d)\n", ret); + return ERR_PTR(ret); + } + return dwmac; } diff --git a/drivers/net/ethernet/stmicro/stmmac/tse_pcs.c b/drivers/net/ethernet/stmicro/stmmac/tse_pcs.c new file mode 100644 index 0000000..9c37e2f --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/tse_pcs.c @@ -0,0 +1,245 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stmmac.h" +#include "stmmac_platform.h" + +#include "tse_pcs.h" + +#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 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003 + +#define EMAC_SPLITTER_CTRL_REG 0x0 +#define EMAC_SPLITTER_CTRL_SPEED_MASK 0x3 +#define EMAC_SPLITTER_CTRL_SPEED_10 0x2 +#define EMAC_SPLITTER_CTRL_SPEED_100 0x3 +#define EMAC_SPLITTER_CTRL_SPEED_1000 0x0 + +#define TSE_PCS_CONTROL_AN_EN_MASK 0x1000 +#define TSE_PCS_CONTROL_REG 0x00 +#define TSE_PCS_CONTROL_RESTART_AN_MASK 0x0200 +#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 0x0020 +#define TSE_PCS_STATUS_LINK_MASK 0x0004 +#define TSE_PCS_STATUS_REG 0x02 +#define TSE_PCS_SGMII_SPEED_1000 0x8 +#define TSE_PCS_SGMII_SPEED_100 0x4 +#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 0x0c00 +#define TSE_PCS_PARTNER_SPEED_1000 0x0800 +#define TSE_PCS_PARTNER_SPEED_100 0x0400 +#define TSE_PCS_PARTNER_SPEED_10 0x0000 +#define TSE_PCS_PARTNER_SPEED_1000 0x0800 +#define TSE_PCS_PARTNER_SPEED_100 0x0400 +#define TSE_PCS_PARTNER_SPEED_10 0x0000 +#define TSE_PCS_SGMII_SPEED_MASK 0x000C +#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 0x0002 + +#define SGMII_ADAPTER_CTRL_REG 0x00 +#define SGMII_ADAPTER_DISABLE 0x0001 +#define SGMII_ADAPTER_ENABLE 0x0000 +#define LINK_TIMER 20 +#define AUTONEGO_TIMER 20 + +static void config_tx_buffer(u16 data, void __iomem *base) +{ + writew(data, base + SGMII_ADAPTER_CTRL_REG); +} + +static void 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"); +} + +void tse_pcs_init(void __iomem *base, struct tse_pcs *pcs) +{ + writew(0x0001, 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); + + tse_pcs_reset(base, pcs); + config_tx_buffer(SGMII_ADAPTER_ENABLE, + pcs->sgmii_adapter_base); +} + +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"); + config_tx_buffer(SGMII_ADAPTER_ENABLE, sgmii_adapter_base); + } else { + mod_timer(&pcs->link_timer, jiffies + + msecs_to_jiffies(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"); + + config_tx_buffer(SGMII_ADAPTER_ENABLE, sgmii_adapter_base); + } 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->an_timer, jiffies + + msecs_to_jiffies(AUTONEGO_TIMER)); + } +} + +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; + + config_tx_buffer(SGMII_ADAPTER_DISABLE, sgmii_adapter_base); + + 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; + writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); + + tse_pcs_reset(tse_pcs_base, pcs); + + setup_timer(&pcs->an_timer, + auto_nego_timer_callback, + (unsigned long)pcs); + mod_timer(&pcs->an_timer, jiffies + + msecs_to_jiffies(AUTONEGO_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->link_timer, + pcs_link_timer_callback, + (unsigned long)pcs); + mod_timer(&pcs->link_timer, jiffies + + msecs_to_jiffies(LINK_TIMER)); + } +} diff --git a/drivers/net/ethernet/stmicro/stmmac/tse_pcs.h b/drivers/net/ethernet/stmicro/stmmac/tse_pcs.h new file mode 100644 index 0000000..3faa714 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/tse_pcs.h @@ -0,0 +1,11 @@ +struct tse_pcs { + struct device *dev; + void __iomem *tse_pcs_base; + void __iomem *sgmii_adapter_base; + struct timer_list an_timer; + struct timer_list link_timer; +}; + +void 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);