From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751549AbcEMGnF (ORCPT ); Fri, 13 May 2016 02:43:05 -0400 Received: from mail-bn1on0074.outbound.protection.outlook.com ([157.56.110.74]:59136 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750889AbcEMGnD (ORCPT ); Fri, 13 May 2016 02:43:03 -0400 X-Greylist: delayed 916 seconds by postgrey-1.27 at vger.kernel.org; Fri, 13 May 2016 02:43:02 EDT 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; From: To: , , , , , CC: Tien Hock Loh Subject: [PATCH 1/1] net: ethernet: Add SGMII support to dwmac-socfpga Date: Thu, 12 May 2016 23:27:21 -0700 Message-ID: <1463120841-31043-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)(189002)(199003)(9170700003)(4001430100002)(8936002)(33646002)(42186005)(4001450100002)(36756003)(1220700001)(105596002)(5001770100001)(47776003)(50986999)(50466002)(11100500001)(8676002)(48376002)(107886002)(92566002)(2906002)(86152002)(4326007)(19580395003)(189998001)(50226002)(86362001)(87936001)(19580405001)(586003)(6806005)(2201001)(5008740100001)(229853001)(106466001)(81166006)(2876002)(5003940100001)(575784001)(7099028)(4720700001);DIR:OUT;SFP:1101;SCL:1;SRVR:BY2PR03MB522;H:sj-itexedge03.altera.priv.altera.com;FPR:;SPF:SoftFail;MLV:sfv;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: 1;BN1AFFO11FD007;1:6KQVv6CXBuJij0u4LtTlNEuM8wVqXQQIO5U5gLt0P8W/VG9HNEqHk9pkkkcJAkQ9QEAaIh/2WOAFwItUJBGrBN9rGJ8ijRQ6RBql8uK9BqtUGoqdqyHs744BwcJBGIAAVrpo3XNOYZYRr6CkJwHMo0+LB5omjrmpUUWKCujfTnBU7dpt1Y9uaiplGcJ51TfIdk4osfb2kl7KYigJTqWqILWYURBy/um+j83ieml1+ECwudcT3iA+KAmE+sx+zXEIDcKxk1ccqgPn1kLXSJo4i5uK+H4nBlu1aYzSI3x0IR6Y9VjCXPNOQdfY4fbXvmqvcyGIoN1f8LFt4WZkdj/XwAPaKMdRLdiC1Ho9dVFnHsDfYeRT2yHwW2gfqS+39nCyTs64DyUnemk+bI5624Vnv/F5xF/nmTIT0sU3uE+ovpC686W7yyoYYbTUL7R6JJrMIJfiNaSLU0XNk7JH1ca3eW0Ebu4rTVhDlTxK5e/6HtZIHhOn15Khp1UUDz9DFv4t2ng+Vws8gKAEp6wXZOiWbw== X-MS-Office365-Filtering-Correlation-Id: 096adc97-4685-49af-f0d9-08d37af7b04f X-Microsoft-Exchange-Diagnostics: 1;BY2PR03MB522;2:exkIE4rPzqUPosZA97+R8/eNHIVxOzeH7p/0z82tXDvAbqpmM69XFQ/URsPdAPUag3kpNlI6y8pOmE4cXIwENX0siCBIi9xkyuYYoCkTSUrQ+znukQKpWJVFWl+vqnHR5OXZME5vfC5e8fLZOp6d7OozzNU/Y4N1ti0Eq82SOWFxccRfNSFGqqjmjrAcw+5E;3:19h0ZaoV9MPQtQEJWQ4XphfhWrNqDsm5DeTCgCCEtC3nPA4cOTq2bWSAnvUsuF0QPjPPZw1z8P07gdqVsBk/nkB1A1dsFnJfv8QRPGxtIuHfu2ZDMJKJ4RAX3AJMlEvq9FSgWxrkRbN0Fg9BLmqLUzM/b84/JkkWTk3vo6UyesW8UuVTMQYIBgCT8VlZZ9qTjQi1liMNztOPuSugbSGZ6jT0PSvcnCvEkdUnJc7JugU=;25:ExBXDM7Ye70stIOxRsz66hWeqMtodwf+EsH3iZTc2j5FYBEX3hGW3ReM2C3GzpLN7v5ENQiU2N5JLyu0qvCq02GYSquzNIBrdIiGsnLAsvH/rze6+IXA88rGivhFgWmAJV31X7aR4uCJOAXtbqVWpUD01ATu+rzLXYh9rrXSrpOVYb4CK5G3W7FwEj9Z7nAFmdoFm3yfYJCVZm6kg1OL+OwQDA1V/wd+LcnoWR0Zs/JCffwxgXYTDGTsMUUMt3Pvr/Iskx706pdKorqJ1c85mBR3VAKRrGhXgJsRdlnRR9JLYHMZEZNkJ9od4JA2uh8Z7iLqbsIDgZorIypHjCoqb1Lzf7EJJYOlj2obmbnw6IVTlaTapWNo6CNKrOKxKDbMQgq/ghw+I3TkrTzN24nFks5m2VuJlItBwCa/Cyub+kg= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY2PR03MB522; X-Microsoft-Exchange-Diagnostics: 1;BY2PR03MB522;20:L8P0T7MhH+a//wsFg+bDdPVXWdtG7kGLCenePnFQ+ubNHw1a8jWxsONFUS1xJo0m7W55zU1K1uAAPIiUQsWv/HxxgAFYfsOWwIilIXoZXSYb+qwn3BOV1sQZYP/fBruckxUwmJzMyRVV4VM6EpcPzmGBiiHzXqL6d6SLO+SsHw8=;4:0oM9lvElXWmJSPs6Ef/74AFC9cUO3WfOEb7ASLPc+IROOeFhMQuLb+Ou2XVGAGQ1K/klzJdQ58lZLVBsiD3ddbBkYXvga8GkDrPDdMYDxGjgBSUqq3K/85u1X2s0FTNXbEHmHJOqLxqoaYzlGp8UJhMdPjXuqo+nEB+UZMhIAYEu9REBw581sl9+2+WDGYS5WvqSIQ57fyjOuB//hhkgiLmqDh01qMv2lKaEOFl3JS0vg8sG15Twtc8t5q9oLNjFkWxxs0B6RhD62GCYm85SVISRBznAoQxvL1OmpUpB/Xe4vjx5DG9F/JPmA9Ikvr+VLk+Rv8C7VZMoOLrTaW6tRDH4Ujrlm/1pqN/E037pu9y6NlPm93bxruGxQN72RYy1fMiKv84Yk8G18qy91ak0jxrJKJiFS1xq8bPYv3P7lBv8dVopbOYOxPWQ9a7KPLx3MFYTxFwiAyYiYZcOnmTZWdt6eEFaj+qhN0JbiH/6J1c= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(8121501046)(5005006)(13024025)(13023025)(13015025)(13018025)(13017025)(10201501046)(3002001)(6055026);SRVR:BY2PR03MB522;BCL:0;PCL:0;RULEID:;SRVR:BY2PR03MB522; X-Forefront-PRVS: 0941B96580 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;BY2PR03MB522;23:KgewZRlIhF1hvqLpilXBI/UE1iPZc3KTp2IwcW3Qz0?= =?us-ascii?Q?ODvxEsdBWC5oCdFWEWU2I6s2OpsbJuPVXj/kFYLi1Y9caG/CEw3EdABdwGLG?= =?us-ascii?Q?GtCmQqpv/Rv9BboW4DxdiO0iU6VnWWS1HZr1Pwy1UUrTrT//HbqAPd8ceBgp?= =?us-ascii?Q?8d7Gc2R8MAQ4EtBZCbvDnyW9IEsgRh2BOxX/psmFR6vLWP32WDueoc+TsJpl?= =?us-ascii?Q?MTFvvHZGyBItXX5lUdaVlCj/E3Aj8H58h2/j7uC7h01gDOtiHGZRubPjRWv4?= =?us-ascii?Q?288u/22VcDmDE6C8tk37Ml0QN7ag65KCA3QfVAZ79f1Tu8QyWuFMC9PBODLq?= =?us-ascii?Q?n4ZChG/dG+TPvwGG9336TmGtBGgPVes4tqTmOqdgxmtWYfo8uYia89Lk9sYS?= =?us-ascii?Q?wEvqgACBtw1jJWHRPZio/g7KhymOV3XaSSeqymF8MvFMi6h+XcsVyyNxQdrf?= =?us-ascii?Q?quFsZIZD/fOnAKfXCD6nwuceEtSIjO0dhBu16iyDL1xwfZCHYhjv9Jcf2D1h?= =?us-ascii?Q?VKrZckGKbsuNbRTls2rA637TxUa+zRR4FmFz31OTulbZlRncZgrL1ujX0MIb?= =?us-ascii?Q?tKl6+pxym3m6FrKTnik+/dCKYpgLqOR73by1r2kunfz+4Uc2RO5f7247DyvI?= =?us-ascii?Q?VOuiARmSCwKbblK3J0eTDLaF/GSt6K4NmObsyVbuTOxC2ne66TCrUl3aQF+d?= =?us-ascii?Q?ibtKTwG4v3E4yYR3Mbcd5YT8ImGWzihHPYK+6Hm6SytKkU/eL/E1lm3uBhO9?= =?us-ascii?Q?YcPX9Ux5dOUD4dVkyLQ6tFR29jox1Bcdx0HQP74UXT5ne0wT4TtUlZEGiSVu?= =?us-ascii?Q?t0UO1Hxf0cCJnWFeM5aqShgIuaa1ygHlAYO1dpbR7V4oVo8O8H+ahpiNN8Rt?= =?us-ascii?Q?uAEEdL/9j8wE01iU7pgPjtU1Vs3ibiRgyHHROvQZI7Fiu9Y5TghTjZshRf7K?= =?us-ascii?Q?50gmoy6TQDTMNrGMMuZEEYEooSUd1em+o3ar/ZZRZnAk7yeb6NeojSr6BCmS?= =?us-ascii?Q?XbzD/72EfeibiaxTe4XduiTNb5XC9S+/Zwnquu5yr66oCLQJVN+8zJJuaX+q?= =?us-ascii?Q?pF4bf4HWWE8lsyKBoRlSXXmDHzxivBKIYu0gDpzZMt2arfkanl/wxgHPMret?= =?us-ascii?Q?1FNsFbNuveItTBMyBEPl5Bi08ZhU9W?= X-Microsoft-Exchange-Diagnostics: 1;BY2PR03MB522;5:if5nYKazJ0Y4Tg8qjAM+pyXuEhRfrTuTjUq+nBHtEOd+eFkZIGPPZr3Ut5LnjmfZs9QUfFmMG744tT8zDpNqtpy8mKRaJ9d4Cy1pEO8d3rbCB+wgmQx0vTVObHvgmuBerMWiTp92igkART0YtASn8A==;24:qRxhRuG6sh6FGqrZhL9PJgFdk6OoBkt2tfUX4pk297h36GCOR1x/jioDnl40d9b/G7Rd7WZVe7YJQkOCwQoIVOQOXZ5LmVsVkw7sZnbZBmg=;7:F6KVFoQSunTbA6JXekAkNx8gZeQB7493sFh82ZUdjcEBzdqqZQGKXeqCV2c6QMDwz/6CW2WDdqknc+xiHQa2ZfptD3TT77qlXJLjlwbsGoEVMgE0L/Hl/8Ra691yesn88SsvMpdZYTKIKvn/M66dsH/X1yBDjPQK3p0NtfYq/iv/47qcZhiWyfnYbGL7OyuV;20:ZTAJM0tStbm84hqqykuE12vTIVZWyrl9qWyDYOBa7ZxwnS8vAGxk7Tg3wioHk+RMUgU6tYLQzc2N5zTCqlmy4u1hj+5wr+mwaZulZSyitATFbNrAqRffHOOcxibGL7c07b3pPxl1Zwe6hljDSDW+pjL/zTjxAWLN8nGcO95eZZA= SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: altera.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 13 May 2016 06:27:41.8231 (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: BY2PR03MB522 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Tien Hock Loh Adds SGMII support for dwmac-socfpga to enable the SGMII PHY when phy-mode of the dwmac is set to sgmii. Signed-off-by: Tien Hock Loh --- .../net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 340 ++++++++++++++++++++- 1 file changed, 330 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 41f4c58..fe826f1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -40,6 +40,44 @@ #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 + +thloh struct socfpga_dwmac { int interface; u32 reg_offset; @@ -49,18 +87,17 @@ struct socfpga_dwmac { struct reset_control *stmmac_rst; void __iomem *splitter_base; bool f2h_ptp_ref_clk; + void __iomem *tse_pcs_base; + void __iomem *sgmii_adapter_base; + struct timer_list an_timer; + struct timer_list link_timer; }; -static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed) +static void config_emac_splitter_speed(void __iomem *base, unsigned int speed) { - struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv; - void __iomem *splitter_base = dwmac->splitter_base; u32 val; - if (!splitter_base) - return; - - val = readl(splitter_base + EMAC_SPLITTER_CTRL_REG); + val = readl(base + EMAC_SPLITTER_CTRL_REG); val &= ~EMAC_SPLITTER_CTRL_SPEED_MASK; switch (speed) { @@ -76,8 +113,214 @@ static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed) default: return; } + writel(val, base + EMAC_SPLITTER_CTRL_REG); +} + +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 socfpga_dwmac *dwmac) +{ + 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(dwmac->dev, "PCS could not get out of sw reset\n"); +} + +static void tse_pcs_init(void __iomem *base, struct socfpga_dwmac *dwmac) +{ + 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, dwmac); +} - writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG); +static void pcs_link_timer_callback(unsigned long data) +{ + u16 val = 0; + + struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)data; + void __iomem *tse_pcs_base = dwmac->tse_pcs_base; + void __iomem *sgmii_adapter_base = dwmac->sgmii_adapter_base; + + val = readw(tse_pcs_base + TSE_PCS_STATUS_REG); + val &= TSE_PCS_STATUS_LINK_MASK; + + if (val != 0) { + dev_dbg(dwmac->dev, "Adapter: Link is established\n"); + config_tx_buffer(SGMII_ADAPTER_ENABLE, sgmii_adapter_base); + } else { + mod_timer(&dwmac->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 socfpga_dwmac *dwmac = (struct socfpga_dwmac *)data; + void __iomem *tse_pcs_base = dwmac->tse_pcs_base; + void __iomem *sgmii_adapter_base = dwmac->sgmii_adapter_base; + + val = readw(tse_pcs_base + TSE_PCS_STATUS_REG); + val &= TSE_PCS_STATUS_AN_COMPLETED_MASK; + + if (val != 0) { + dev_dbg(dwmac->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(dwmac->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(dwmac->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(dwmac->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(dwmac->dev, + "Adapter does not support Half Duplex\n"); + else if (speed == TSE_PCS_PARTNER_SPEED_100 && + duplex == TSE_PCS_PARTNER_DUPLEX_HALF) + dev_err(dwmac->dev, + "Adapter does not support Half Duplex\n"); + else if (speed == TSE_PCS_PARTNER_SPEED_1000 && + duplex == TSE_PCS_PARTNER_DUPLEX_HALF) + dev_err(dwmac->dev, + "Adapter does not support Half Duplex\n"); + else + dev_err(dwmac->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, dwmac); + mod_timer(&dwmac->an_timer, jiffies + + msecs_to_jiffies(AUTONEGO_TIMER)); + } +} + +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->tse_pcs_base; + void __iomem *sgmii_adapter_base = dwmac->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 ((tse_pcs_base) && (sgmii_adapter_base)) { + config_tx_buffer(SGMII_ADAPTER_DISABLE, sgmii_adapter_base); + if (splitter_base) + config_emac_splitter_speed(splitter_base, speed); + + 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, dwmac); + + setup_timer(&dwmac->an_timer, + auto_nego_timer_callback, + (unsigned long)dwmac); + mod_timer(&dwmac->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, dwmac); + + setup_timer(&dwmac->link_timer, + pcs_link_timer_callback, + (unsigned long)dwmac); + mod_timer(&dwmac->link_timer, jiffies + + msecs_to_jiffies(LINK_TIMER)); + } + } else 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); + } } static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) @@ -85,9 +328,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->stmmac_rst = devm_reset_control_get(dev, STMMAC_RESOURCE_NAME); @@ -134,6 +381,72 @@ 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 to 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 to mapping adapter\n", + __func__); + return -EINVAL; + } + + dwmac->sgmii_adapter_base = devm_ioremap_resource( + dev, &res_sgmii_adapter); + + if (IS_ERR(dwmac->sgmii_adapter_base)) { + dev_err(dev, "%s: failed to mapping adapter\n", + __func__); + return PTR_ERR(dwmac->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->tse_pcs_base = devm_ioremap_resource( + dev, &res_tse_pcs); + + if (IS_ERR(dwmac->tse_pcs_base)) { + dev_err(dev, "%s: failed to mapping tse control port\n", + __func__); + return PTR_ERR(dwmac->sgmii_adapter_base); + } + } + } dwmac->reg_offset = reg_offset; dwmac->reg_shift = reg_shift; dwmac->sys_mgr_base_addr = sys_mgr_base_addr; @@ -157,6 +470,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: @@ -181,6 +495,12 @@ static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac) ctrl &= ~(SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK << (reg_shift / 2)); regmap_write(sys_mgr_base_addr, reg_offset, ctrl); + + if (phymode == PHY_INTERFACE_MODE_SGMII) { + tse_pcs_init(dwmac->tse_pcs_base, dwmac); + config_tx_buffer(SGMII_ADAPTER_ENABLE, + dwmac->sgmii_adapter_base); + } return 0; } -- 1.7.11.GIT