From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752128AbcFGDDG (ORCPT ); Mon, 6 Jun 2016 23:03:06 -0400 Received: from mail-by2on0067.outbound.protection.outlook.com ([207.46.100.67]:63520 "EHLO na01-by2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751091AbcFGDDB (ORCPT ); Mon, 6 Jun 2016 23:03:01 -0400 Authentication-Results: spf=softfail (sender IP is 66.35.236.227) smtp.mailfrom=altera.com; arm.com; dkim=none (message not signed) header.d=none;arm.com; dmarc=none action=none header.from=altera.com; From: To: , , , , , , , , CC: Tien Hock Loh Subject: [PATCH v3 1/1] net: ethernet: Add TSE PCS support to dwmac-socfpga Date: Mon, 6 Jun 2016 20:01:56 -0700 Message-ID: <1465268516-31480-1-git-send-email-thloh@altera.com> X-Mailer: git-send-email 1.7.9.5 MIME-Version: 1.0 Content-Type: text/plain X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:66.35.236.227;IPV:NLI;CTRY:US;EFV:NLI;SFV:NSPM;SFS:(10009020)(6009001)(2980300002)(3190300001)(189002)(199003)(81156014)(86362001)(81166006)(2906002)(8936002)(2201001)(586003)(50466002)(50226002)(8676002)(4326007)(47776003)(42186005)(107886002)(229853001)(5008740100001)(19580405001)(36756003)(19580395003)(575784001)(86152002)(33646002)(11100500001)(68736007)(50986999)(106466001)(97736004)(5003940100001)(48376002)(189998001)(6806005)(87936001)(15975445007)(92566002)(2876002)(105596002)(5001770100001)(4001430100002)(7099028)(2004002)(4720700001)(217873001);DIR:OUT;SFP:1101;SCL:1;SRVR:BY2PR03MB109;H:sj-itexedge03.altera.priv.altera.com;FPR:;SPF:SoftFail;PTR:InfoDomainNonexistent;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: 1;BY2FFO11FD024;1:g9SAMojhpP9ps4ALJimdia7rbTpcizjPfoRhcp+Z1FjL/0yZV3NLRwLAluFAiCBneaG404wOSu0c4fOj8q8WL/Vc4LKdAHexsDUpZa4G2DtPuTBvYGV3mi39z6OCriiPKAs+cHc/dnyQWKeK8BFnVsJg3ct8VB+86x5R3hVnda0WigWN9qhTropaGUyD1uurD6DKs5e9es5eKqv5hS/XwsMCC5siIGlvR9VeN5aZhwAsGKeJg9sNKt5mZP4Ht9FYY+5ESi+opqD1Gyn2wVbEi09b8jV9hVWYNNk/4H/qcwN93W3k8DSWzV/SKZ/REEUIEjFcws5BgVZzu+UenuT6QQc9zKD1aJGj/uDI08S6A0fRGU4eY2DiYzM4/N1qb21Ha9kJq6yVGAPnkP8bqY2EArUHKLzl/A+Tu9BuPGsTz9ZwHFTX9fK6oP5K0H0jTg2V9oI6UmvE7PvIZijKHA8zPXkBFwrxRryTzmgkI9maCSrKtyrz/ogi2MLgfTAEp6IIWDLw5agE9wFh0kB/ErpJYgMjKNnYDI/IWafEwG/IopP7gJXEZurp0xTKU6q6hB3c+FATApS4QzXGy3k26nsILw== X-MS-Office365-Filtering-Correlation-Id: 5e3568df-0ebd-4048-3c56-08d38e803abc X-Microsoft-Exchange-Diagnostics: 1;BY2PR03MB109;2:jdgM9OkHbDfVxLa8aDFsSjZZtjbgUZpR4iVjq2QrWf5kLOwJnLueGSYP0PZaeex2IWhSwJmXjZdcodag4P9Xz7guog18APPJfIk3X7wkWhpzBacPZp5Fsf4RWDTVD0DWHGSiV3KsyblFYlVr35o9nR7+U7RHVwJeyWGUxw5Jn2aFDMbrrb37Q7Fu1tmE2e+e;3:+9DJiyVbSQ/YhTYVFgR6x72ssoCbtnBPzsMBhp7jxwFxTgJsbrw4zR0lATzI6qquk7KI89AowbOGN4CJQ9YTIBL2rYM8/OalV++n2J39DkZMAsvvuqQepNvG6hJzG0vUv3BUt6cv/3SY26HSlB8xWMa/4GKSOraoksXXz9eqOkJqSMjTZ+FmZEO2AgveHREF/kKGpr59KdAIk5/BUi8DLdnR2R1jqP/z1ysIWmKOFzY= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY2PR03MB109; X-Microsoft-Exchange-Diagnostics: 1;BY2PR03MB109;25:7CYZcLY7KCRCNFCAFiJdepxSTPoq9HBN6XtpuQezGTC8I+2WUO+3/EjeFbEDDV6cjO2Esp4LwDae4QZMCZ8s53G8JgCk/WgR4DF6jKRGqkAMPtaP9Bx1oPkrAVGglBzBa6Sd++P142rDlieNIdnv3luq5JB8Kase03mXDurPv0IreP7JD7Emimm+L7sLPnCf6UJuDq2j6skmnW0lKzj7xrR0MQ+WpIOKShpUreDUXL7WY1RSMe89BJXLK92dArH8kubTCSDM6b32wPYlz2HGDEaw0A9eJ8vTlpR34UiWcHSUS4TyR/0PHJggRxex6ypbuYPzOyLIINjbUHHq8WCBPGJ0c9GS9EMRPbY+xJ78IG3UnwSS0Pqrt5uZFDVUYhhumbuzil9BdHlLsOug9YTQ9PtTdyRsjBEpHOdTZyvyJC2SCsx+n54poDsEKQVmdYjwVPHhexmmZybelkxOV0PYlZBdRxBpCITbNPIF8aK0kIXazvHge6cr9IvpKfjwEgxSo6jtKsFyTh6D8hYVkqtZNT3bfaTjs4XGtsxoULwHvcvtIfKPZx8IR0ZSrLwXmsvKrQh78w2GC4o+tvMD3yRzbndf6O/n1sgTsJjFs5LpjYjVw9MSpedT0GvWHeEdJMij+9z4gutDEF9JkrLUQ0m/RgkMRM3QY6UllTJbJJoguiwmMcHsF99oE70oEKp5s1gbr5KlRom8BCPI+bibpcqbwZqu38ZlDNzCmwvGHvbWR0X8KbDgO79nrUmssLOugQ3+lQLo26RO1OH90lCfmHlNjwEM9ys8+mDA1nQzRtHR66wnxGLuNpysfKWWnKW5iNFrnMSmKJFDl0TmcQM70DIi5w== X-Microsoft-Exchange-Diagnostics: 1;BY2PR03MB109;20:RR2xRwcKpfnelpSR6PgRGmZBvICUCo1EHn96Gx5e6LAG2qE4EOTKVNLz7VDKKLH+NUptcpFOcA+7h6/lvkXHEtx5tWhyWlufN2/3dKzPlmyyYvrrHwKP2QoKEcCV9ZA0ynaJdf9aZoxuabK7lqmwjg5YWBet8cEhkD5L5VQ5DWg=;4:kXjct3UrFE0rzBXCVCu7H/UXqXlXzTj5HzmwhH7aVdS4t8XUf9KBrXKMpnWCPeK3j+O+b6tZi5o1rIB8C3wDVR4UvxK0ZJ7Y7zeFJNyxfxMiyOURnUjaZqkYFtKtXx6G3P0io6GgTD/BZ9dr+3Dqh6GVNYM8yyf54A5McjDK/5hqhTDCn3ayH4F5D4nOT61jlBiu9nzoENwmW6L2ySlFxvHCrsJIuQDQT0geaShxsBHN0e5DQX5ivVufmBqF8MyzB7aCwT6hP1UiYShq20+lwLePq5wfpoi2408o86Kv/QAYUXoGwNd8LRkUxSA73dsn0xanSovQlnhsq3Yqrl8LZsTDBzDDHLj1FJOhImfbsZwX9X6jG2Asc1Ws53Zab9gYImXN6aKSPFibCbsM8c3Dow42HPWgbY6TIAxClQfxYouiAK0TQr3QFj9JqQUQWtCLg4DJk7Ha7lOSQN18h8AhWDyhyy8eeF3R/3PP5MJ9keqJutHAlq3J7ucFbNnY6zHUo+NAmtvGCiuqqVOsnQNuy111P8/8Yy89vRvomjffsRQ2Vp86sbCpleStIXYjKFaElw/F5a2zzFt2zO+4MHodqw== 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)(13023025)(13018025)(13017025)(13015025)(8121501046)(5005006)(13024025)(10201501046)(3002001)(6055026);SRVR:BY2PR03MB109;BCL:0;PCL:0;RULEID:;SRVR:BY2PR03MB109; X-Forefront-PRVS: 09669DB681 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;BY2PR03MB109;23:A3zia50rbqU72SaAw8gZ1EbQuhS1OkEF+c7KvyPrJI?= =?us-ascii?Q?yQ6FADPqiL9Wm0gNSb4bhFxCgoq3eZWdm7XfnSWUK6x5efxv57SuzF3rPXUI?= =?us-ascii?Q?As9apQDiRozlHpTvYyioR4xvGF1b+AfODnfHYEgPCHxxM/1U9k7OGuHIHcg8?= =?us-ascii?Q?20ZCNh8yXi5hmX+Vc7goGaFci0+259jCw2bftoWyNowVqWCnzH7XGOZDj4og?= =?us-ascii?Q?D8O2sOMp/XO+MlxbQzPzB0ZHUlLF5A3MiGX/PkN2xjZ47y+nUW1adHGzbyQv?= =?us-ascii?Q?8ciYrDYs3pjIEEuQsXyTVo1PlYRGSbOt8xScp1D+gCFf0PI6B5OmKq/h4MtZ?= =?us-ascii?Q?78Ht7t2a6qm/kOGjfWpC0Ww7wwJJjC0Y+AxltTscyeW1psfWhDbg+hiTdcVj?= =?us-ascii?Q?8LsczG9IvYY6V8GQwzMI6mzwgRYZKlrRqk+cp7pY01UoeXugsQj9VR8qo/6F?= =?us-ascii?Q?RNvkFiUOULj397m+R5GXiLkcAetWpLeDTgNu19Gq1cbHL2IISV+ZtPyws7ZB?= =?us-ascii?Q?cbjP2cnym1e6NYrJVj2fId6Ft+gPpN8RNB4u+mjilmC3GePQSWk2CKKbzTPh?= =?us-ascii?Q?rEe9l5KcHXtLGlFQCCRjNm4YHkQmKDJKNoP8FKjGudD4e5xwIb2LHhFx6l2w?= =?us-ascii?Q?AzI4GqJUSc9a4JEwyuLMxl7SbT9ICEmuYUFXXVjp3bfS8mwD9NGNVYKNYWwZ?= =?us-ascii?Q?5UY3xqDv1NKz0DsWRmwH3aeBd1s744pa3Utzc6eZmSJGyMf1NnTkWAi+v/Pr?= =?us-ascii?Q?I8yKHG4twlRF6np9N8oR6LOxgT9JhEDbkpGtwnSFmSbv7Qw+UZEX9eajJnU+?= =?us-ascii?Q?3q1PafYEMi9Ci6fl3x1BU26WmA/IynfYQfTXWVjgznECjfBAQ97d9Vv4prTS?= =?us-ascii?Q?d9tiCLJtP5gdJmOc+6y43vC01QHF1qBAHYcMPpJRy/1oY8C2X6MFRmyyGs6a?= =?us-ascii?Q?0g4mceXJLYMq95gyqCBAtiYWg3Jrk8pRHNG/7eqhEHL1xg02+t30hX8wA6D/?= =?us-ascii?Q?aZpXOwH5IqU/y3ERUA1FyE5DsyJE64xUYkFKSJJCxuGyf83tLpJvo+wbWCDl?= =?us-ascii?Q?nWteeoHeKM3y8urTyU1hyo3LiAo7k1bS0lG4ol7mJKkEsRZnaqHHOMOGmhY3?= =?us-ascii?Q?h42NQ+g4/qNWYSAHWO7paMHERjWzIH39lCcOZEqKKjPaHvXU8JkcVbJ75uxx?= =?us-ascii?Q?G83SALvQMcL4j2UZ+cV6CL1b+L5ahxZ2koh9Ec+kq6kJaSe3iSU4eMjQ=3D?= =?us-ascii?Q?=3D?= X-Microsoft-Exchange-Diagnostics: 1;BY2PR03MB109;5:OC1e9KDxxJ/vZKr1bDI6qvY1HxkHDaTQINvcoqpYgekM/CpBvRS30P6n3qnuJ+hi/KC9wYQfJGe1i2JFMSTj47/vl+hZpg4ib4fQLE0iT2mg+YIf4qr3QeY5OfiPK0RQTc9OlUTCRXFYVxAo4xggJg==;24:eHxzqX68PygKWpE+NYHcIg3CsMnOyA776RbVEaukNE6DB5VLbx2gpNzLd5YSe4O2hRhKY+aiefIFRz3xxJyl97bxmgx2fvbiidPMHtGuwMg=;7:ecCsQ2ishftFCfBacoD1GKDiLHaRdgdfxV6+GYu+0QX2RkTAH+NOBBBYygMDxoHc1aEllpYfQArGG0kj4i03h0tW4okr+EH/r7s2rMVN46GfhPSDP9M2Q8qJk1B6dFAzTQVm2cJkKO3pW8TJ5ZF0GjWj3IFj3bk64KKYoeC+Kaf7I/O7HnA+Rsw7F5tfT81g3LQGARcmHurKy+Zfr7EW5eV2T3QKvJcLDOhGJ7tHPos=;20:t1f5lpzU3D/T36GllxOrlSpBF75AWHiKPrglFSWs08uKlKy9T6AMLjK0ddPFN+nTI0dahT7W6Aj1ntsr0GDi8CmEEr5NooKORBP9QZG/zqSorl2o8zl0RksXEp9QJOWajhoRr8WaPTnNu+RW6eiSMwtrcLZ1CHizURZEKqG7DxQ= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: altera.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 07 Jun 2016 03:02:57.9560 (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: BY2PR03MB109 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@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 v3: - Added missing license header for new source files - Updated tse_pcs.h include headers - Standardize if statements --- .../devicetree/bindings/net/socfpga-dwmac.txt | 4 + drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +- .../net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 140 +++++++++-- drivers/net/ethernet/stmicro/stmmac/tse_pcs.c | 261 +++++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/tse_pcs.h | 36 +++ 5 files changed, 419 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..88fba4e 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,60 @@ 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 +113,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 +145,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 +236,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 +256,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 +279,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..1989bd1 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/tse_pcs.c @@ -0,0 +1,261 @@ +/* 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 "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..e3d4511 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/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 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); + +#endif /* __TSE_PCS_H__ */ -- 1.7.11.GIT