From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751420AbcEMHRb (ORCPT ); Fri, 13 May 2016 03:17:31 -0400 Received: from mail-bl2on0069.outbound.protection.outlook.com ([65.55.169.69]:8944 "EHLO na01-bl2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751104AbcEMHR3 (ORCPT ); Fri, 13 May 2016 03:17:29 -0400 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: Fri, 13 May 2016 00:01:12 -0700 Message-ID: <1463122872-31309-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)(199003)(189002)(9170700003)(4001450100002)(5008740100001)(47776003)(4001430100002)(33646002)(5003940100001)(105596002)(92566002)(36756003)(1220700001)(50226002)(8936002)(2201001)(106466001)(2876002)(86152002)(229853001)(5001770100001)(107886002)(87936001)(19580405001)(19580395003)(189998001)(48376002)(42186005)(50466002)(6806005)(81166006)(86362001)(575784001)(50986999)(2906002)(4326007)(8676002)(586003)(7099028)(4720700001);DIR:OUT;SFP:1101;SCL:1;SRVR:BLUPR03MB518;H:sj-itexedge03.altera.priv.altera.com;FPR:;SPF:SoftFail;MLV:sfv;A:1;MX:1;LANG:en; X-Microsoft-Exchange-Diagnostics: 1;BN1AFFO11FD039;1:pDpVsjlxkCN3RiiNox6JSapB9YY5LKVgE4TguNagspA1oc0iMizvgHKDFNPkZpTVa0FDT8hKAnWlT0L513f4+W1zytCL0xx9JKMZkwGTQEIWb1ZuQz9DWYKAH3g4AtWGWTTG5rb8LottC0SqEWXdvwhmLUpSipsIidO1R4ap28V0c5n76Njz2c/r5MRzt1FRDjJUiGp6e5D2LEDL2CTpPiwm/wvcs4bgIiZ183AgoPAOD66qWpdZDtN5ZC5Fnr58K2kOwqRLxgX6ZFYbfKUF1hfCeMC+W3u//aUougDc/FLdsl7WTouuaUYHOzVFIwJOQkh30IumyDWJGN+DWlpGwyFwp+g/VC+PLma9m7y0xWmn+E5f8UQyvygPaAN5EBqZBORvjj6wqGKREz04T1Xd6HdppdbtqA2ebP4zNqxdCw14ex514B+NdDClqoRAp6JHAss3TFBR0F3FLJ5rA6i53JUTcnhdXDEnEWdyKlJD/5LRJUDYc/qnMLUwwr/ytWhucXnW6a4vg9bbtU3iamlevw== X-MS-Office365-Filtering-Correlation-Id: 1efd8073-7ae2-4018-550f-08d37afc6ca3 X-Microsoft-Exchange-Diagnostics: 1;BLUPR03MB518;2:MdD4ljsZLU73SNEU/p4cWBDRzToRpIfDJoZC8Zs2FAg+QUlixF95kBj2dEJzRSU1SkXvQI68sWyemtazLbhD21cRS+SoKF4S3kOy8lpFdX1y2XLSGDaXdt8qIiKWeGDzERmviz68mlv98/l+5ZzApxp8415azQ/8ffJBdD9fpGgHIjA9QEfy01oIOzLMR07X;3:6PZp9+1XRoO6qhrPvdUlaRbLMOgGON1z243ePgkYnwh75C3P2wK9H3XEjreU23oWbdu4J06yM09T6M7XDTWLfHivyyyroQ0vuCWBMlvI08ffmtKbVS7HfAOv3dK2JHEUBQtSVmeHWcunM0NIc7HxVp7Ew/QXCXrNanpeU6T+pwLINuHSJSru2/nqskVdq0S9SSlrthRulPKsYskgmPqUQrkdeuF19+kEbidkxWCVRJQ=;25:k54QzFNkvWN3adQiLmNQxyVI7MI26IH7bjX1h4apZUd3h44yrM/tSGIU+d+WCmKkaCXnKLQSrSvFcYJGkONftUHfY/n5iLF4fCuNfuGqXL3QVPIdaDi6KxMJe75F8zdjlcPOaLqJ11rsmgIyHvrP8vKKzcLYI24HLttLABJKUw1dXNULh2XpLZ/rN7YhzB18vWXJx8ZDDV3RXt+umuXhpG7XJLxsyl8UUOqWwfeIyXX+k2vktlxsBmoJRlny3VAYV1YyU6KIRYHzM/0PNa5CLizOdbh+tC3z3MwQSiA00OO8r3y8Ty9W5aPDJOL5CmVwMk580h3h8dbjxi10PHFvJPlwVYGIKaGsEdE95xCYqkGvTZJQPWMsGP/+iIEdEc6Rq3iKRITuozAkNU5erzPoPSNyrxLdYFyDpI7bf/6/0FY= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BLUPR03MB518; X-Microsoft-Exchange-Diagnostics: 1;BLUPR03MB518;20:+utxSextaXlQrpdevH02AB2D8KOu4LHn+CIi+bnoEam1dSZ/VtW4ueVJ3ggwT5k2h8fAXGOtZ+SGuZfZlPB1x8rWk5x9TElNzZzaq1ke63bjxx3FHZBs0f/R359g6MuTO9AgGFrGT1NZX0nASPHMa24ts+5bi/Y58qJTEl8C8z4=;4:p9Ko7KhIbeZ5kYFMjdoKXUiNhFSW5X8wYCTKMVTAhmcxo3iMBGtzxHavM4dOU5RuGsBTI5LBeZxFhEhYcvWQEFYRx6KrNKIoICU0AE2BLKJo6AgPh/nRSyWMGnMbLD52Pa6YzAVquGOGpyNWpeS6SgApvlBt/MbaJOMtTeKtwkVgevrqd31DV4UtzT38ZJNHm4Obx3S15KVWu3Eay9tXUPJTCn7x7vLodFz6bSsDbDC6Tlv/yCfHk8lyuDrkvZEPLosgXJEGIioNJRJmwjP5+Huh7AP0UGk1NAGfSK1s4VivmnvGASwPLf9KYfEQcgqkwZm49NhdpnSfLRujVwNut0zt6FK3OGMjw488pmLC761+NyYgBL713kRqOpUGrs1/pbRESj+5flik38X/mr8A0XcGupB5R9LXuebLXgY/A/FD/YI63vjE2coKW+DSqqJ481lMQUqfAb1lKxuGw/5TM6BBo8+9KbS6tO3DraDFz1A= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(13018025)(13017025)(13015025)(13023025)(13024025)(8121501046)(5005006)(3002001)(10201501046)(6055026);SRVR:BLUPR03MB518;BCL:0;PCL:0;RULEID:;SRVR:BLUPR03MB518; X-Forefront-PRVS: 0941B96580 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;BLUPR03MB518;23:2wiOZsQlzwa1IzoQgIVD7ekQTUypdK43hLaGTg2xFv?= =?us-ascii?Q?7wvsMMFTW3cyIK7XqvibxZQuqDkK0N5rDSFlSPaUg1INFvFizws/Ib7EjBty?= =?us-ascii?Q?h6+1HUneZA49o9B1IDxSwsdRQItsgzf4TWCg7LPKcKvZDdCz/k2wLaD0Pto+?= =?us-ascii?Q?TtPZDjLDPBMkXIgo3wYeG6qGdPqNB7LO3q5lIy2uFdQpqUNjf6YrJfiTC60/?= =?us-ascii?Q?YsmnglrCQl8H0N5jc3BtHGlcrul4Z+Go27aQJdHELJ8XZqebvVt57LCtuW5e?= =?us-ascii?Q?zRXnE/nAnKK8Ig0UbZX2lWZsI0PUGmplrsTc6pJv+a699+NlspVIiBsocKjd?= =?us-ascii?Q?GgqRekmgvCOSQnXbp7W30zQlbvdxE68Vxp/PYAC1kNN910IEZ/MyrLi12blC?= =?us-ascii?Q?WP8Rtv8dxdSgA/8bcvRXJwohRS1lvc9+T9JLBEnGltgKBNFAb77E9ulMIbG7?= =?us-ascii?Q?nWxXNIkW5Q3qk7A/PWdFKHpJLSZE5Cf7Y9Xagx0EpzRyEmBaxlf0+3rQJwWD?= =?us-ascii?Q?Sh6BUsjevAfMk/xA2tNMAUg0upPJSj6oPQjcFoatB2hMeXb6rFNiOeduA+71?= =?us-ascii?Q?w7Z/YP3D9nKGi6yNqtCmjAG5LHu6n1MfZw9vO26OVRHiuEPiOXPclSpZEHb/?= =?us-ascii?Q?ddyptNYAsMus0VPcRoHdxA2HzxR/ks8qdxhuZPTvvczsP5tRLYzF+aaglnWl?= =?us-ascii?Q?0G8Cd2PEAAzJayCQkBujJvvCXMS5PZs9xabtyz08saeWBee2yIFWkcl9XSke?= =?us-ascii?Q?klEvvycrD3j0B/TjM8l29ifwqM5Y0YAbpcoGuc7bIYLWVSKQBUKDrOalP6Ii?= =?us-ascii?Q?PS/q2w3UrAF7IBjFHGVp1k+YhUtZDgRNnRREfIQzjOeqcuVCKqo/BhLWwwXp?= =?us-ascii?Q?cdpgD5SRX5yv8KUwHOMDYCdbLtfCxIfTeoWCJb9Gb8pQ7M8Ubl8Hk+DUTPKj?= =?us-ascii?Q?xyyJw/BR41daH8Azg8Q6cUdyP2Zq82i4Zc7j9vflD+LvHbgyemBs/SD6UdXM?= =?us-ascii?Q?bmn9PqrV4oKmPH5jVu16Scumv8DUT/bNxVbgElTQH2T2FYXEXgptYsWb+cXQ?= =?us-ascii?Q?GvKsUfFOT35CMD3wimMbPnOLfdcJtZEym3vfWq5CzxJ6tEgfHpgoc/sFodTB?= =?us-ascii?Q?fiDONpKiI=3D?= X-Microsoft-Exchange-Diagnostics: 1;BLUPR03MB518;5:Y9DzMTMJ21anZLnu4M4fpT4R+kzuWVb28c9A0RAGULkpdo1Q8aH4MLgDUQUS720o8Gue2oJl+pe3nDZH5rWCVNUi+q9bHtDn4CyMqg7RePG5n8yeYVxz4SLVEC/2By7c8XcC5UitBgsimo20migE6Q==;24:sMrhPzRJROWB8E00qDMRduJ+mFZBolmpubbNHKabTcRDdfLg7owt6LctGx1YE3wIKlKKxCwkPTqsEKjw8kFbrO2z+Hy2N995Iib5A9Fidss=;7:mS/kkdpw0uQaGqts+4k75kHhhe2Fa6YH7ybCQ4D5uBjBB5IfQBY/oxyk3lq7Bb8hF6fwaufup1NYNDEtvXwIpWGaG6MNT7LtkqxJacUOut3iCWG2qLmrHlnN06Ku8+VE+ABLiryNYuMdGVcEB5+iFy5tk+5gnmcQ395T30nE602uWcUHxeHB3vfD+QHYCf1y;20:00ydnXMrQ4SC7qadml5oxc+oporiyEMT3gvF6xmIIWYNUnAhbyMwHmjzzVFok9sblVMr/GlsbFNHzASMCBlzA2EcFjKprmzD9EKsut08EJGs4qlwKQ990qFICQJTGqj8nNuLU2frM3zu+PVROWQzV8Otf8ae+TgF7/FzRHVSD9M= SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: altera.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 13 May 2016 07:01:35.8774 (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: BLUPR03MB518 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 | 339 ++++++++++++++++++++- 1 file changed, 329 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..a59d590 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -40,6 +40,43 @@ #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 + struct socfpga_dwmac { int interface; u32 reg_offset; @@ -49,18 +86,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 +112,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); +} + +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; - writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG); + 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 +327,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 +380,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 +469,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 +494,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