From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751839AbcF2JKr (ORCPT ); Wed, 29 Jun 2016 05:10:47 -0400 Received: from mail-bl2on0094.outbound.protection.outlook.com ([65.55.169.94]:34400 "EHLO na01-bl2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751334AbcF2JKm (ORCPT ); Wed, 29 Jun 2016 05:10:42 -0400 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; From: To: , , , , , , , , , , , CC: Tien Hock Loh Subject: [PATCH V6 1/1] net: ethernet: Add TSE PCS support to dwmac-socfpga Date: Wed, 29 Jun 2016 02:10:13 -0700 Message-ID: <1467191413-16715-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-MS-Office365-Filtering-HT: Tenant X-Forefront-Antispam-Report: CIP:66.35.236.227;IPV:NLI;CTRY:US;EFV:NLI;SFV:NSPM;SFS:(10009020)(6009001)(7916002)(2980300002)(189002)(199003)(47776003)(50986999)(15975445007)(189998001)(2876002)(356003)(87936001)(4326007)(86362001)(2201001)(2906002)(586003)(107886002)(68736007)(7846002)(19580395003)(92566002)(575784001)(81156014)(81166006)(19580405001)(8676002)(86152002)(48376002)(8936002)(6806005)(50226002)(4001450100002)(5003940100001)(11100500001)(229853001)(33646002)(36756003)(105596002)(106466001)(42186005)(4001430100002)(97736004)(5001770100001)(305945005)(50466002)(7099028)(921003)(2004002)(217873001)(1121003)(4720700001);DIR:OUT;SFP:1101;SCL:1;SRVR:BLUPR03MB360;H:sj-itexedge03.altera.priv.altera.com;FPR:;SPF:SoftFail;PTR:InfoDomainNonexistent;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: 1;BL2FFO11FD046;1:/lPVRTbJVJsU0FvWXfC57ta3ofdgvf8sRzkeZNMkaODdDQVHM5eFFJy5G6UsC9oy0kvXLZGzfJ//HnUMkjb24M27G2XEZtlwdT6XSrRyv45cgXT33QvkI+jyh8cExwz7FaYlwJpUa8JnxHpvzBGj4PV3752ZYakFdyqKfhhSjuEojI81cyVvJ8funRmTAi9FfIV4dW0KIwYLOb9FwUhCF9NgU3DizvmrC5gssVGl3ENR0SEEWH71RJKqO18yO5iiuOgYYksZfz3+CwpJf7jQ4Bp80ORcy/PSYzoK/1ptuvj5wcb9VeYpIttyyPLdZoRr2n4Ydw7i6FPChXW0VIFiZq7SWgDLnK8Kiey8OseKl/sNK5wnHDi9uqXXRdFZoQ6CcNRFRqaWClZu0vyGFd+9ovJTuCyaYNQM222YlMq7z6RbsB18GU64J5P/obo+veVu3+lBZRWTKSZn6P3kfxjVztKG+lgg4v7GcDPBUDtfnUYeJM2LNAicNG7Y+uqHCUJUuiA64hIn0zaAQYRhHkUF0bpLxm5oPUyHhMNZxmSXAAlrv7v66R8z6jcESafJ4y5wOXGFeIutbgtJKMFxUBLZ+55gdVKuAA7v1Jxfnc1IKBc= X-MS-Office365-Filtering-Correlation-Id: ca8b8e4a-961e-43a5-2922-08d39ffd3ce6 X-Microsoft-Exchange-Diagnostics: 1;BLUPR03MB360;2:QDmhezMYfYoeDe4SR5XBbQkcy+2T5GP3yoHBjDsKR2KpBDSi5wXVMLiS9Aecw0HNZ/nP/qf2xHoUxyJwRkucZtTBrX51YiNyKXe2niXUiPCy9hs6wc0oZJWxMJEx4OQYje4pNuoz4FzbqushqJQq2wqlhQQrfPDyGhigk4+wf/Ulxqs8NnOO47XgXtaz3M5K;3:drqLnE1eAWXOVhwIDzKxtxnyRajhrxkh9bXMhVgSUO8FVX6MmrNlKiCR7EDeA+Rj9AESYZSN6kPCvdJjB1bg0/8VTeuxUckmQOPhy7vm1/XhmtlyXIMJPDegUO867A2oiZ44Jwa/MLJjrAGJX/P0K8n6VctQcgRQhzi0FJ2jOZV0fhnUrNtQPDSH2X/1cgX77zYn3cbhnZwfW8vIuV0Qi4Mr/hZzeUbSxEvKwpshfVo=;25:z4t263nhguZ75nB6ucfkLCDlATu1hupk9C9GFyKLzIT3gEJS7u0geLftSJg0nVfTtAvn3DlExWVHNXS5BwSO2wDWY4S4a5/GlnvUmUzANo5JWqRiPs0TM7rQmT8hYltvnvEgK8WD2209QLkCFPpfh9jRs9SJdiYnYaYDIyRam8TaLPE8p4nVocdmzWePoxeeGre8ty0JAOz8CIZHXU/y7okYrTsf678f/RKoqdjj9T9C7X5iEK60393OROWjXSrLyoyOz0xMdyYzCXs7cnJv3kvO+agSvTprof+U05HNvwQl8k46VLS7IYzT3vSbvaKzlU5UA0WQ2xTO5b4NZh3yeShPR37TvKNm0HTHpqxJoO/8WVtzJ5keS8QuszLJIx7b4L4NMi17/iCS2Fa9C7DaVVGcGMIH38Z/XAXg7JDopvA= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BLUPR03MB360; X-Microsoft-Exchange-Diagnostics: 1;BLUPR03MB360;20:iOegJfK8404LxFlNiCYsVcp92eMiMq5S5hRHPh8RFLRE+tv+i3WUOARxZpQimUTRS6uCKc9QihAgBoMRKNPN5x+n637YXyRNS45F0kzLmwhPmQlpNIt4g4YCowjMflVFkT63A4ux4yEMKfnNHenvzKgSB1uz18AA1wWu963x4Uk=;4:sjSKVTYfUzk9yUxsviWR3ReCqYqWjL49rJ0QiF4f3WNmtzxC9ZFtglfkvLiN7vWJUB9AcJl2/XvG32LkXLhv/D3OnnHv4WbbK9UvJPsOLwyjq9U+Rvm2HaOjn98w1KvGXe9JTlgldMbAPdbubRcPAhdR05T6pE47KKu5OuerWk+Q31oLkixehF9OUbyuNmZXGGgdzEh502JyMalRhebayVartyLWU++I7BZCA8UR+I0awopWxYYFvG9udkCU54JoRJgngEwR/LjrV7uRCdUuBIGrXam38FLiUjtbjLXYf+YWyL+PrGCAFJFjzxzzfQwM9F4vJYMxdJFZ0W0w4QWf13Muyka0/tNWmDq9lwBNlZWw7MA4WdCvIL2qBlOHS6kQoi3QQnbsDYSm48GFCTM6fiQcCGKRGv7+9m2w7BkS7xvoO8l9AtXy4J41geZDkgwf+lijaLOsmsGQIcNWAO7ttyv9vcrJIj2PGmqSgXK0x6eoqKLxRWR4Gu1Lye0FFsDz3kr/F4HPasdlr8HqGhCF1LnY/d8Ej5EFTpTUsoAUKBHAKN6+KohCmS6Vvd7IjAcykYUdNgDE7f62wxQbT40ndg== 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)(13015025)(8121501046)(13017025)(5005006)(13024025)(13023025)(13018025)(3002001)(10201501046)(6055026);SRVR:BLUPR03MB360;BCL:0;PCL:0;RULEID:;SRVR:BLUPR03MB360; X-Forefront-PRVS: 09888BC01D X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;BLUPR03MB360;23:+wbtWChgun9R7ZRK9vzgUxfAr7qO68Mo0eyvODh8XY?= =?us-ascii?Q?wd1SPGgo7vmBw3XGkqzp2Tw08OSxTPaZRl5YEpkdaoeGQavUloAOEEdNUC9A?= =?us-ascii?Q?i1H9wvCWWp9wqRC1oqSsJTrModKnz0A/HP0LJ8M6yd7KKE7ZpbSUirDXsJQh?= =?us-ascii?Q?+8fPi8rWL+RZb2wmHSuIIzhIVCrF5CrkXUfGKcnL6ycHKef3aTBQepUltJSp?= =?us-ascii?Q?m2SGXZGEfSKtZDnP8damIqMrnSRWPmFcyywzGF4wX15/wO6YZuhhXrqxuZcz?= =?us-ascii?Q?kpg3cwsuk5t3flmofrdL8yD5IZ8oxHiX4vrCq3wn29OjddbJkL7wfhR4xT1u?= =?us-ascii?Q?cjL4h6b5VLgswjXOH/Tco0RAhfs8lyhBgf+sX5THncM3DBHAMKAmzrnHLerN?= =?us-ascii?Q?v+DlVgGllP1DixoF+viObo+BZkvZhwaX+K6BP7UUQ/OX31VaCazwnlxjVGi7?= =?us-ascii?Q?HHTjjY2g4JgajMZ6jN48AbcsxtANyOqxzapNhhquI8sNhYP/BqVsdaMZ/I45?= =?us-ascii?Q?yTV2AehrKICGIjxdiDX21eJwxKrb6nUtm0Kv/dnk8jX0hSbVwHYlywF6Qx5l?= =?us-ascii?Q?Kfmxj7T1QtGS6lydLV2SdxqR+XdM24fh89qx5XIHPPIh6VJlHnd+lN8KRHhu?= =?us-ascii?Q?8ywo64yakkJ8R9eeZLWjZlwHKy2DqQCj8yazsTe78a1qip8I9VwplbFmK6Jt?= =?us-ascii?Q?9/tTXLqRwpjEyVMsrOiXNjHYE5ZldWZWReeLLAx/f5KI/u8tftEEgkUy7yJB?= =?us-ascii?Q?GDCGqQDXeq69vw7RzT/zpfOUU2fkUfiknA5JqX7UnENRRxuo0Z3FzuxtM0tT?= =?us-ascii?Q?BR3m59n9Jnm/6pjLBoUHLMNH9WP5FmpvCm8hCtV/ZjzhmOzKbfnGzdkJOyko?= =?us-ascii?Q?vlOobmBsiKLjRgKqTAXyI+IxX3J+PXNqwtepSN7jsoqnERehm6sQlhDva45k?= =?us-ascii?Q?S6z7bUnBTgsYTyG801U2IvogpkaQ/xODqjq6ZydAqJ5YLqOfa2BO2hvw3MJG?= =?us-ascii?Q?PNpzWIvZbLKJSEdl47tG7AroAxKXw6HqhNkJbVRm+bCuJwhaOdNWlv8lu8hJ?= =?us-ascii?Q?p6nQQS3EEkA2ecYXum3oRZkvX3s2+7Qol7Uoi6+0b8pnMUVZdRGR1MkGdWDw?= =?us-ascii?Q?BJfPWsu/dg/RgsEsC3X1av6/EYo180FtePK7B8w2L9Jwy3ur4oS40+/AGeKW?= =?us-ascii?Q?evPI+r5Ih1sJx1pt9iPafTEvXUoBfEBbo2pwq+ZKIloE3Y3LndednL9/vbyv?= =?us-ascii?Q?dxrBibf+npfYDKaAraGS9AMV/PLixoT1OMwSyB?= X-Microsoft-Exchange-Diagnostics: 1;BLUPR03MB360;6:CHcK4UMZHSJqD7LqzcVJYgmzzG13QcAAp+ey8Se9gGf/DsUtTHvQ7KI8s8bYmly2x68Sz5OIWBQsRWxEWH5CvF0sVek9h3YCN81Pe4VNHNv6mLL0EOuuLxk9wsY1nMDgjwiavp3at3V2umZUDTgiQpTQGdkZJN2wWCZZd0dRQAgNcn0YvPc6dOF7mvTGoWw9oer2UhEaSsVoRbjERV7d8xpo9fIVYmTT7SlcgX4zuRVPWYBe/qafRvQ1TzaHgVCzVhgYfBSAeAKceICoenbMbmF1DAZ4nlmLvXd1Qpfv/6ZQAXQ7jw42MAf8tKgaaV7wAAo98DwKR7Cbp2rFG6osYPa3N6TEpi3TXrPsjx5pkcA=;5:6ulDc9MdytbUfm6v7JjpOTRNWsNWm8S7trvlcT5mbAhtarTzlymqtIlgS7NMYKnvirNurZZi9CtkSje4bOpNzjaBNpyDClKnQdCi3v9cDCincpMbKLffstFG7vDryIFQnrPbdXai8vTNq2qmuSHOvw==;24:ZykzS4YjHtsIn/+I2TUxmAasl2KeekgfndqtS7cs1v8rPigLer2/hOdvFXi+JaLXeusx5/WSr9K+EejPzOeU1vaYH/qTEPGqptuuptw0kpY=;7:30OqtTDPnrqwmTrU7ZOplGOFV8e0NF0feL4A9Zvjvyw1SrigqtFveo3ij09ffCh1bMAM98BljMXZ7aOIeDVu2Rww/bFMMmxIuM1CeKB7xrEaOcOR0eMyM+B5LP+D0w2bHkL4wWzievxPJBq4Rmmg7wAv/2dQLDcytjmV9QgH72vg6+J53jo78KrsHP6zTXiPGG8/qBGdOf6HueBRfglZwNYMrUt27VnijPs1mdUVg2j4iXTxCEcYhrfi93oIeHcArf8CygwZUlXtniBnUvPgjw== SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;BLUPR03MB360;20:Jt8Av1GIvqMwmlGg8/aD4B4zmerFMoAfjVhhIQDqt6izCUZvxfN13s7qh0Yo5sRrbiHseUYVKGC7Jd04JnQNhSnUzZX3q17OPR9uY7BkhU7jN1jfwcZbg3XThhxvdM02u50UeIfXib1hEZnU+LfnUBJXdPdEB3mhBrpqL2J9Wko= X-OriginatorOrg: altera.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 29 Jun 2016 09:10:38.2574 (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: BLUPR03MB360 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 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 v5: - Fixed devicetree binding property name using _ instead of - v6: - Fixed a problem where driver build broken if driver is set as module --- .../devicetree/bindings/net/socfpga-dwmac.txt | 19 ++ drivers/net/ethernet/stmicro/stmmac/Makefile | 3 +- 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 | 141 +++++++++-- 5 files changed, 453 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..2e68a3c 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..44b630c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -11,11 +11,12 @@ 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-altr-socfpga.o obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o stmmac-platform-objs:= stmmac_platform.o +dwmac-altr-socfpga-objs := altr_tse_pcs.o dwmac-socfpga.o obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o stmmac-pci-objs:= stmmac_pci.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..5c96216 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,13 @@ 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->interface = of_get_phy_mode(np); @@ -128,6 +148,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 +242,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 +283,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; } @@ -225,6 +323,7 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed; ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + if (!ret) { struct net_device *ndev = platform_get_drvdata(pdev); struct stmmac_priv *stpriv = netdev_priv(ndev); -- 1.7.11.GIT