Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/807486/?format=api
{ "id": 807486, "url": "http://patchwork.ozlabs.org/api/patches/807486/?format=api", "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/20170830082924.3180-3-antoine.tenart@free-electrons.com/", "project": { "id": 7, "url": "http://patchwork.ozlabs.org/api/projects/7/?format=api", "name": "Linux network development", "link_name": "netdev", "list_id": "netdev.vger.kernel.org", "list_email": "netdev@vger.kernel.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20170830082924.3180-3-antoine.tenart@free-electrons.com>", "list_archive_url": null, "date": "2017-08-30T08:29:13", "name": "[net-next,v4,02/13] phy: add the mvebu cp110 comphy driver", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": true, "hash": "4e9963e19738299138340ea12d37d689da74130d", "submitter": { "id": 61603, "url": "http://patchwork.ozlabs.org/api/people/61603/?format=api", "name": "Antoine Tenart", "email": "antoine.tenart@free-electrons.com" }, "delegate": { "id": 34, "url": "http://patchwork.ozlabs.org/api/users/34/?format=api", "username": "davem", "first_name": "David", "last_name": "Miller", "email": "davem@davemloft.net" }, "mbox": "http://patchwork.ozlabs.org/project/netdev/patch/20170830082924.3180-3-antoine.tenart@free-electrons.com/mbox/", "series": [ { "id": 550, "url": "http://patchwork.ozlabs.org/api/series/550/?format=api", "web_url": "http://patchwork.ozlabs.org/project/netdev/list/?series=550", "date": "2017-08-30T08:29:24", "name": "net: mvpp2: comphy configuration", "version": 4, "mbox": "http://patchwork.ozlabs.org/series/550/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/807486/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/807486/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<netdev-owner@vger.kernel.org>", "X-Original-To": "patchwork-incoming@ozlabs.org", "Delivered-To": "patchwork-incoming@ozlabs.org", "Authentication-Results": "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=netdev-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)", "Received": [ "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xhzMM2WyJz9t2Q\n\tfor <patchwork-incoming@ozlabs.org>;\n\tWed, 30 Aug 2017 18:34:39 +1000 (AEST)", "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1751399AbdH3I3m (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tWed, 30 Aug 2017 04:29:42 -0400", "from mail.free-electrons.com ([62.4.15.54]:58090 \"EHLO\n\tmail.free-electrons.com\" rhost-flags-OK-OK-OK-OK) by vger.kernel.org\n\twith ESMTP id S1751298AbdH3I3k (ORCPT\n\t<rfc822;netdev@vger.kernel.org>); Wed, 30 Aug 2017 04:29:40 -0400", "by mail.free-electrons.com (Postfix, from userid 110)\n\tid 140E021FCE; Wed, 30 Aug 2017 10:29:38 +0200 (CEST)", "from localhost (LStLambert-657-1-97-87.w90-63.abo.wanadoo.fr\n\t[90.63.216.87])\n\tby mail.free-electrons.com (Postfix) with ESMTPSA id CFC8C21F49;\n\tWed, 30 Aug 2017 10:29:27 +0200 (CEST)" ], "X-Spam-Checker-Version": "SpamAssassin 3.4.0 (2014-02-07) on\n\tmail.free-electrons.com", "X-Spam-Level": "", "X-Spam-Status": "No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT,\n\tURIBL_BLOCKED shortcircuit=ham autolearn=disabled version=3.4.0", "From": "Antoine Tenart <antoine.tenart@free-electrons.com>", "To": "davem@davemloft.net, kishon@ti.com, andrew@lunn.ch,\n\tjason@lakedaemon.net, sebastian.hesselbarth@gmail.com,\n\tgregory.clement@free-electrons.com", "Cc": "Antoine Tenart <antoine.tenart@free-electrons.com>,\n\tthomas.petazzoni@free-electrons.com, nadavh@marvell.com,\n\tlinux@armlinux.org.uk, linux-kernel@vger.kernel.org,\n\tmw@semihalf.com, stefanc@marvell.com,\n\tmiquel.raynal@free-electrons.com, netdev@vger.kernel.org", "Subject": "[PATCH net-next v4 02/13] phy: add the mvebu cp110 comphy driver", "Date": "Wed, 30 Aug 2017 10:29:13 +0200", "Message-Id": "<20170830082924.3180-3-antoine.tenart@free-electrons.com>", "X-Mailer": "git-send-email 2.13.5", "In-Reply-To": "<20170830082924.3180-1-antoine.tenart@free-electrons.com>", "References": "<20170830082924.3180-1-antoine.tenart@free-electrons.com>", "Sender": "netdev-owner@vger.kernel.org", "Precedence": "bulk", "List-ID": "<netdev.vger.kernel.org>", "X-Mailing-List": "netdev@vger.kernel.org" }, "content": "On the CP110 unit, which can be found on various Marvell platforms such\nas the 7k and 8k (currently), a comphy (common PHYs) hardware block can\nbe found. This block provides a number of PHYs which can be used in\nvarious modes by other controllers (network, SATA ...). These common\nPHYs must be configured for the controllers using them to work correctly\neither at boot time, or when the system runs to switch the mode used.\nThis patch adds a driver for this comphy hardware block, providing\ncallbacks for the its PHYs so that consumers can configure the modes\nused.\n\nAs of this commit, two modes are supported by the comphy driver: sgmii\nand 10gkr.\n\nSigned-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>\n---\n drivers/phy/marvell/Kconfig | 11 +\n drivers/phy/marvell/Makefile | 1 +\n drivers/phy/marvell/phy-mvebu-cp110-comphy.c | 644 +++++++++++++++++++++++++++\n 3 files changed, 656 insertions(+)\n create mode 100644 drivers/phy/marvell/phy-mvebu-cp110-comphy.c", "diff": "diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig\nindex 048d8893bc2e..68e321225400 100644\n--- a/drivers/phy/marvell/Kconfig\n+++ b/drivers/phy/marvell/Kconfig\n@@ -21,6 +21,17 @@ config PHY_BERLIN_USB\n \thelp\n \t Enable this to support the USB PHY on Marvell Berlin SoCs.\n \n+config PHY_MVEBU_CP110_COMPHY\n+\ttristate \"Marvell CP110 comphy driver\"\n+\tdepends on ARCH_MVEBU || COMPILE_TEST\n+\tdepends on OF\n+\tselect GENERIC_PHY\n+\thelp\n+\t This driver allows to control the comphy, an hardware block providing\n+\t shared serdes PHYs on Marvell Armada 7k/8k (in the CP110). Its serdes\n+\t lanes can be used by various controllers (Ethernet, sata, usb,\n+\t PCIe...).\n+\n config PHY_MVEBU_SATA\n \tdef_bool y\n \tdepends on ARCH_DOVE || MACH_DOVE || MACH_KIRKWOOD\ndiff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile\nindex 3fc188f59118..0cf6a7cbaf9f 100644\n--- a/drivers/phy/marvell/Makefile\n+++ b/drivers/phy/marvell/Makefile\n@@ -1,6 +1,7 @@\n obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY)\t+= phy-armada375-usb2.o\n obj-$(CONFIG_PHY_BERLIN_SATA)\t\t+= phy-berlin-sata.o\n obj-$(CONFIG_PHY_BERLIN_USB)\t\t+= phy-berlin-usb.o\n+obj-$(CONFIG_PHY_MVEBU_CP110_COMPHY)\t+= phy-mvebu-cp110-comphy.o\n obj-$(CONFIG_PHY_MVEBU_SATA)\t\t+= phy-mvebu-sata.o\n obj-$(CONFIG_PHY_PXA_28NM_HSIC)\t\t+= phy-pxa-28nm-hsic.o\n obj-$(CONFIG_PHY_PXA_28NM_USB2)\t\t+= phy-pxa-28nm-usb2.o\ndiff --git a/drivers/phy/marvell/phy-mvebu-cp110-comphy.c b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c\nnew file mode 100644\nindex 000000000000..73ebad6634a7\n--- /dev/null\n+++ b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c\n@@ -0,0 +1,644 @@\n+/*\n+ * Copyright (C) 2017 Marvell\n+ *\n+ * Antoine Tenart <antoine.tenart@free-electrons.com>\n+ *\n+ * This file is licensed under the terms of the GNU General Public\n+ * License version 2. This program is licensed \"as is\" without any\n+ * warranty of any kind, whether express or implied.\n+ */\n+\n+#include <linux/io.h>\n+#include <linux/iopoll.h>\n+#include <linux/mfd/syscon.h>\n+#include <linux/module.h>\n+#include <linux/phy/phy.h>\n+#include <linux/platform_device.h>\n+#include <linux/regmap.h>\n+\n+/* Relative to priv->base */\n+#define MVEBU_COMPHY_SERDES_CFG0(n)\t\t(0x0 + (n) * 0x1000)\n+#define MVEBU_COMPHY_SERDES_CFG0_PU_PLL\tBIT(1)\n+#define MVEBU_COMPHY_SERDES_CFG0_GEN_RX(n)\t((n) << 3)\n+#define MVEBU_COMPHY_SERDES_CFG0_GEN_TX(n)\t((n) << 7)\n+#define MVEBU_COMPHY_SERDES_CFG0_PU_RX\tBIT(11)\n+#define MVEBU_COMPHY_SERDES_CFG0_PU_TX\tBIT(12)\n+#define MVEBU_COMPHY_SERDES_CFG0_HALF_BUS\tBIT(14)\n+#define MVEBU_COMPHY_SERDES_CFG1(n)\t\t(0x4 + (n) * 0x1000)\n+#define MVEBU_COMPHY_SERDES_CFG1_RESET\tBIT(3)\n+#define MVEBU_COMPHY_SERDES_CFG1_RX_INIT\tBIT(4)\n+#define MVEBU_COMPHY_SERDES_CFG1_CORE_RESET\tBIT(5)\n+#define MVEBU_COMPHY_SERDES_CFG1_RF_RESET\tBIT(6)\n+#define MVEBU_COMPHY_SERDES_CFG2(n)\t\t(0x8 + (n) * 0x1000)\n+#define MVEBU_COMPHY_SERDES_CFG2_DFE_EN\tBIT(4)\n+#define MVEBU_COMPHY_SERDES_STATUS0(n)\t\t(0x18 + (n) * 0x1000)\n+#define MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY\tBIT(2)\n+#define MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY\tBIT(3)\n+#define MVEBU_COMPHY_SERDES_STATUS0_RX_INIT\t\tBIT(4)\n+#define MVEBU_COMPHY_PWRPLL_CTRL(n)\t\t(0x804 + (n) * 0x1000)\n+#define MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(n)\t((n) << 0)\n+#define MVEBU_COMPHY_PWRPLL_PHY_MODE(n)\t((n) << 5)\n+#define MVEBU_COMPHY_IMP_CAL(n)\t\t\t(0x80c + (n) * 0x1000)\n+#define MVEBU_COMPHY_IMP_CAL_TX_EXT(n)\t((n) << 10)\n+#define MVEBU_COMPHY_IMP_CAL_TX_EXT_EN\tBIT(15)\n+#define MVEBU_COMPHY_DFE_RES(n)\t\t\t(0x81c + (n) * 0x1000)\n+#define MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL\tBIT(15)\n+#define MVEBU_COMPHY_COEF(n)\t\t\t(0x828 + (n) * 0x1000)\n+#define MVEBU_COMPHY_COEF_DFE_EN\t\tBIT(14)\n+#define MVEBU_COMPHY_COEF_DFE_CTRL\t\tBIT(15)\n+#define MVEBU_COMPHY_GEN1_S0(n)\t\t\t(0x834 + (n) * 0x1000)\n+#define MVEBU_COMPHY_GEN1_S0_TX_AMP(n)\t((n) << 1)\n+#define MVEBU_COMPHY_GEN1_S0_TX_EMPH(n)\t((n) << 7)\n+#define MVEBU_COMPHY_GEN1_S1(n)\t\t\t(0x838 + (n) * 0x1000)\n+#define MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(n)\t((n) << 0)\n+#define MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(n)\t((n) << 3)\n+#define MVEBU_COMPHY_GEN1_S1_RX_MUL_FI(n)\t((n) << 6)\n+#define MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(n)\t((n) << 8)\n+#define MVEBU_COMPHY_GEN1_S1_RX_DFE_EN\tBIT(10)\n+#define MVEBU_COMPHY_GEN1_S1_RX_DIV(n)\t((n) << 11)\n+#define MVEBU_COMPHY_GEN1_S2(n)\t\t\t(0x8f4 + (n) * 0x1000)\n+#define MVEBU_COMPHY_GEN1_S2_TX_EMPH(n)\t((n) << 0)\n+#define MVEBU_COMPHY_GEN1_S2_TX_EMPH_EN\tBIT(4)\n+#define MVEBU_COMPHY_LOOPBACK(n)\t\t(0x88c + (n) * 0x1000)\n+#define MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(n)\t((n) << 1)\n+#define MVEBU_COMPHY_VDD_CAL0(n)\t\t(0x908 + (n) * 0x1000)\n+#define MVEBU_COMPHY_VDD_CAL0_CONT_MODE\tBIT(15)\n+#define MVEBU_COMPHY_EXT_SELV(n)\t\t(0x914 + (n) * 0x1000)\n+#define MVEBU_COMPHY_EXT_SELV_RX_SAMPL(n)\t((n) << 5)\n+#define MVEBU_COMPHY_MISC_CTRL0(n)\t\t(0x93c + (n) * 0x1000)\n+#define MVEBU_COMPHY_MISC_CTRL0_ICP_FORCE\tBIT(5)\n+#define MVEBU_COMPHY_MISC_CTRL0_REFCLK_SEL\tBIT(10)\n+#define MVEBU_COMPHY_RX_CTRL1(n)\t\t(0x940 + (n) * 0x1000)\n+#define MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL\tBIT(11)\n+#define MVEBU_COMPHY_RX_CTRL1_CLK8T_EN\tBIT(12)\n+#define MVEBU_COMPHY_SPEED_DIV(n)\t\t(0x954 + (n) * 0x1000)\n+#define MVEBU_COMPHY_SPEED_DIV_TX_FORCE\tBIT(7)\n+#define MVEBU_SP_CALIB(n)\t\t\t(0x96c + (n) * 0x1000)\n+#define MVEBU_SP_CALIB_SAMPLER(n)\t\t((n) << 8)\n+#define MVEBU_SP_CALIB_SAMPLER_EN\t\tBIT(12)\n+#define MVEBU_COMPHY_TX_SLEW_RATE(n)\t\t(0x974 + (n) * 0x1000)\n+#define MVEBU_COMPHY_TX_SLEW_RATE_EMPH(n)\t((n) << 5)\n+#define MVEBU_COMPHY_TX_SLEW_RATE_SLC(n)\t((n) << 10)\n+#define MVEBU_COMPHY_DLT_CTRL(n)\t\t(0x984 + (n) * 0x1000)\n+#define MVEBU_COMPHY_DLT_CTRL_DTL_FLOOP_EN\tBIT(2)\n+#define MVEBU_COMPHY_FRAME_DETECT0(n)\t\t(0xa14 + (n) * 0x1000)\n+#define MVEBU_COMPHY_FRAME_DETECT0_PATN(n)\t((n) << 7)\n+#define MVEBU_COMPHY_FRAME_DETECT3(n)\t\t(0xa20 + (n) * 0x1000)\n+#define MVEBU_COMPHY_FRAME_DETECT3_LOST_TIMEOUT_EN\tBIT(12)\n+#define MVEBU_COMPHY_DME(n)\t\t\t(0xa28 + (n) * 0x1000)\n+#define MVEBU_COMPHY_DME_ETH_MODE\t\tBIT(7)\n+#define MVEBU_COMPHY_TRAINING0(n)\t\t(0xa68 + (n) * 0x1000)\n+#define MVEBU_COMPHY_TRAINING0_P2P_HOLD\tBIT(15)\n+#define MVEBU_COMPHY_TRAINING5(n)\t\t(0xaa4 + (n) * 0x1000)\n+#define\t MVEBU_COMPHY_TRAINING5_RX_TIMER(n)\t((n) << 0)\n+#define MVEBU_COMPHY_TX_TRAIN_PRESET(n)\t\t(0xb1c + (n) * 0x1000)\n+#define MVEBU_COMPHY_TX_TRAIN_PRESET_16B_AUTO_EN\tBIT(8)\n+#define MVEBU_COMPHY_TX_TRAIN_PRESET_PRBS11\t\tBIT(9)\n+#define MVEBU_COMPHY_GEN1_S3(n)\t\t\t(0xc40 + (n) * 0x1000)\n+#define MVEBU_COMPHY_GEN1_S3_FBCK_SEL\tBIT(9)\n+#define MVEBU_COMPHY_GEN1_S4(n)\t\t\t(0xc44 + (n) * 0x1000)\n+#define\t MVEBU_COMPHY_GEN1_S4_DFE_RES(n)\t((n) << 8)\n+#define MVEBU_COMPHY_TX_PRESET(n)\t\t(0xc68 + (n) * 0x1000)\n+#define MVEBU_COMPHY_TX_PRESET_INDEX(n)\t((n) << 0)\n+#define MVEBU_COMPHY_GEN1_S5(n)\t\t\t(0xd38 + (n) * 0x1000)\n+#define MVEBU_COMPHY_GEN1_S5_ICP(n)\t\t((n) << 0)\n+\n+/* Relative to priv->regmap */\n+#define MVEBU_COMPHY_CONF1(n)\t\t\t(0x1000 + (n) * 0x28)\n+#define MVEBU_COMPHY_CONF1_PWRUP\t\tBIT(1)\n+#define MVEBU_COMPHY_CONF1_USB_PCIE\t\tBIT(2)\t/* 0: Ethernet/SATA */\n+#define MVEBU_COMPHY_CONF6(n)\t\t\t(0x1014 + (n) * 0x28)\n+#define MVEBU_COMPHY_CONF6_40B\t\tBIT(18)\n+#define MVEBU_COMPHY_SELECTOR\t\t\t0x1140\n+#define MVEBU_COMPHY_SELECTOR_PHY(n)\t((n) * 0x4)\n+\n+#define MVEBU_COMPHY_LANES\t6\n+#define MVEBU_COMPHY_PORTS\t3\n+\n+struct mvebu_comhy_conf {\n+\tenum phy_mode mode;\n+\tunsigned lane;\n+\tunsigned port;\n+\tu32 mux;\n+};\n+\n+#define MVEBU_COMPHY_CONF(_lane, _port, _mode, _mux)\t\\\n+\t{\t\t\t\t\t\t\\\n+\t\t.lane = _lane,\t\t\t\t\\\n+\t\t.port = _port,\t\t\t\t\\\n+\t\t.mode = _mode,\t\t\t\t\\\n+\t\t.mux = _mux,\t\t\t\t\\\n+\t}\n+\n+static const struct mvebu_comhy_conf mvebu_comphy_cp110_modes[] = {\n+\t/* lane 0 */\n+\tMVEBU_COMPHY_CONF(0, 1, PHY_MODE_SGMII, 0x1),\n+\t/* lane 1 */\n+\tMVEBU_COMPHY_CONF(1, 2, PHY_MODE_SGMII, 0x1),\n+\t/* lane 2 */\n+\tMVEBU_COMPHY_CONF(2, 0, PHY_MODE_SGMII, 0x1),\n+\tMVEBU_COMPHY_CONF(2, 0, PHY_MODE_10GKR, 0x1),\n+\t/* lane 3 */\n+\tMVEBU_COMPHY_CONF(3, 1, PHY_MODE_SGMII, 0x2),\n+\t/* lane 4 */\n+\tMVEBU_COMPHY_CONF(4, 0, PHY_MODE_SGMII, 0x2),\n+\tMVEBU_COMPHY_CONF(4, 0, PHY_MODE_10GKR, 0x2),\n+\tMVEBU_COMPHY_CONF(4, 1, PHY_MODE_SGMII, 0x1),\n+\t/* lane 5 */\n+\tMVEBU_COMPHY_CONF(5, 2, PHY_MODE_SGMII, 0x1),\n+};\n+\n+struct mvebu_comphy_priv {\n+\tvoid __iomem *base;\n+\tstruct regmap *regmap;\n+\tstruct device *dev;\n+\tint modes[MVEBU_COMPHY_LANES];\n+};\n+\n+struct mvebu_comphy_lane {\n+\tstruct mvebu_comphy_priv *priv;\n+\tunsigned id;\n+\tenum phy_mode mode;\n+\tint port;\n+};\n+\n+static int mvebu_comphy_get_mux(int lane, int port, enum phy_mode mode)\n+{\n+\tint i, n = ARRAY_SIZE(mvebu_comphy_cp110_modes);\n+\n+\t/* Unused PHY mux value is 0x0 */\n+\tif (mode == PHY_MODE_INVALID)\n+\t\treturn 0;\n+\n+\tfor (i = 0; i < n; i++) {\n+\t\tif (mvebu_comphy_cp110_modes[i].lane == lane &&\n+\t\t mvebu_comphy_cp110_modes[i].port == port &&\n+\t\t mvebu_comphy_cp110_modes[i].mode == mode)\n+\t\t\tbreak;\n+\t}\n+\n+\tif (i == n)\n+\t\treturn -EINVAL;\n+\n+\treturn mvebu_comphy_cp110_modes[i].mux;\n+}\n+\n+static void mvebu_comphy_ethernet_init_reset(struct mvebu_comphy_lane *lane,\n+\t\t\t\t\t enum phy_mode mode)\n+{\n+\tstruct mvebu_comphy_priv *priv = lane->priv;\n+\tu32 val;\n+\n+\tregmap_read(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), &val);\n+\tval &= ~MVEBU_COMPHY_CONF1_USB_PCIE;\n+\tval |= MVEBU_COMPHY_CONF1_PWRUP;\n+\tregmap_write(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), val);\n+\n+\t/* Select baud rates and PLLs */\n+\tval = readl(priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));\n+\tval &= ~(MVEBU_COMPHY_SERDES_CFG0_PU_PLL |\n+\t\t MVEBU_COMPHY_SERDES_CFG0_PU_RX |\n+\t\t MVEBU_COMPHY_SERDES_CFG0_PU_TX |\n+\t\t MVEBU_COMPHY_SERDES_CFG0_HALF_BUS |\n+\t\t MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xf) |\n+\t\t MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xf));\n+\tif (mode == PHY_MODE_10GKR)\n+\t\tval |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xe) |\n+\t\t MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xe);\n+\telse if (mode == PHY_MODE_SGMII)\n+\t\tval |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0x6) |\n+\t\t MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0x6) |\n+\t\t MVEBU_COMPHY_SERDES_CFG0_HALF_BUS;\n+\twritel(val, priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));\n+\n+\t/* reset */\n+\tval = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));\n+\tval &= ~(MVEBU_COMPHY_SERDES_CFG1_RESET |\n+\t\t MVEBU_COMPHY_SERDES_CFG1_CORE_RESET |\n+\t\t MVEBU_COMPHY_SERDES_CFG1_RF_RESET);\n+\twritel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));\n+\n+\t/* de-assert reset */\n+\tval = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));\n+\tval |= MVEBU_COMPHY_SERDES_CFG1_RESET |\n+\t MVEBU_COMPHY_SERDES_CFG1_CORE_RESET;\n+\twritel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));\n+\n+\t/* wait until clocks are ready */\n+\tmdelay(1);\n+\n+\t/* exlicitly disable 40B, the bits isn't clear on reset */\n+\tregmap_read(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), &val);\n+\tval &= ~MVEBU_COMPHY_CONF6_40B;\n+\tregmap_write(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), val);\n+\n+\t/* refclk selection */\n+\tval = readl(priv->base + MVEBU_COMPHY_MISC_CTRL0(lane->id));\n+\tval &= ~MVEBU_COMPHY_MISC_CTRL0_REFCLK_SEL;\n+\tif (mode == PHY_MODE_10GKR)\n+\t\tval |= MVEBU_COMPHY_MISC_CTRL0_ICP_FORCE;\n+\twritel(val, priv->base + MVEBU_COMPHY_MISC_CTRL0(lane->id));\n+\n+\t/* power and pll selection */\n+\tval = readl(priv->base + MVEBU_COMPHY_PWRPLL_CTRL(lane->id));\n+\tval &= ~(MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(0x1f) |\n+\t\t MVEBU_COMPHY_PWRPLL_PHY_MODE(0x7));\n+\tval |= MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(0x1) |\n+\t MVEBU_COMPHY_PWRPLL_PHY_MODE(0x4);\n+\twritel(val, priv->base + MVEBU_COMPHY_PWRPLL_CTRL(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_LOOPBACK(lane->id));\n+\tval &= ~MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(0x7);\n+\tval |= MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(0x1);\n+\twritel(val, priv->base + MVEBU_COMPHY_LOOPBACK(lane->id));\n+}\n+\n+static int mvebu_comphy_init_plls(struct mvebu_comphy_lane *lane,\n+\t\t\t\t enum phy_mode mode)\n+{\n+\tstruct mvebu_comphy_priv *priv = lane->priv;\n+\tu32 val;\n+\n+\t/* SERDES external config */\n+\tval = readl(priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));\n+\tval |= MVEBU_COMPHY_SERDES_CFG0_PU_PLL |\n+\t MVEBU_COMPHY_SERDES_CFG0_PU_RX |\n+\t MVEBU_COMPHY_SERDES_CFG0_PU_TX;\n+\twritel(val, priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));\n+\n+\t/* check rx/tx pll */\n+\treadl_poll_timeout(priv->base + MVEBU_COMPHY_SERDES_STATUS0(lane->id),\n+\t\t\t val,\n+\t\t\t val & (MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY |\n+\t\t\t\t MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY),\n+\t\t\t 1000, 150000);\n+\tif (!(val & (MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY |\n+\t\t MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY)))\n+\t\treturn -ETIMEDOUT;\n+\n+\t/* rx init */\n+\tval = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));\n+\tval |= MVEBU_COMPHY_SERDES_CFG1_RX_INIT;\n+\twritel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));\n+\n+\t/* check rx */\n+\treadl_poll_timeout(priv->base + MVEBU_COMPHY_SERDES_STATUS0(lane->id),\n+\t\t\t val, val & MVEBU_COMPHY_SERDES_STATUS0_RX_INIT,\n+\t\t\t 1000, 10000);\n+\tif (!(val & MVEBU_COMPHY_SERDES_STATUS0_RX_INIT))\n+\t\treturn -ETIMEDOUT;\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));\n+\tval &= ~MVEBU_COMPHY_SERDES_CFG1_RX_INIT;\n+\twritel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));\n+\n+\treturn 0;\n+}\n+\n+static int mvebu_comphy_set_mode_sgmii(struct phy *phy)\n+{\n+\tstruct mvebu_comphy_lane *lane = phy_get_drvdata(phy);\n+\tstruct mvebu_comphy_priv *priv = lane->priv;\n+\tu32 val;\n+\n+\tmvebu_comphy_ethernet_init_reset(lane, PHY_MODE_SGMII);\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));\n+\tval &= ~MVEBU_COMPHY_RX_CTRL1_CLK8T_EN;\n+\tval |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL;\n+\twritel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_DLT_CTRL(lane->id));\n+\tval &= ~MVEBU_COMPHY_DLT_CTRL_DTL_FLOOP_EN;\n+\twritel(val, priv->base + MVEBU_COMPHY_DLT_CTRL(lane->id));\n+\n+\tregmap_read(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), &val);\n+\tval &= ~MVEBU_COMPHY_CONF1_USB_PCIE;\n+\tval |= MVEBU_COMPHY_CONF1_PWRUP;\n+\tregmap_write(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), val);\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));\n+\tval &= ~MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf);\n+\tval |= MVEBU_COMPHY_GEN1_S0_TX_EMPH(0x1);\n+\twritel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));\n+\n+\treturn mvebu_comphy_init_plls(lane, PHY_MODE_SGMII);\n+}\n+\n+static int mvebu_comphy_set_mode_10gkr(struct phy *phy)\n+{\n+\tstruct mvebu_comphy_lane *lane = phy_get_drvdata(phy);\n+\tstruct mvebu_comphy_priv *priv = lane->priv;\n+\tu32 val;\n+\n+\tmvebu_comphy_ethernet_init_reset(lane, PHY_MODE_10GKR);\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));\n+\tval |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL |\n+\t MVEBU_COMPHY_RX_CTRL1_CLK8T_EN;\n+\twritel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_DLT_CTRL(lane->id));\n+\tval |= MVEBU_COMPHY_DLT_CTRL_DTL_FLOOP_EN;\n+\twritel(val, priv->base + MVEBU_COMPHY_DLT_CTRL(lane->id));\n+\n+\t/* Speed divider */\n+\tval = readl(priv->base + MVEBU_COMPHY_SPEED_DIV(lane->id));\n+\tval |= MVEBU_COMPHY_SPEED_DIV_TX_FORCE;\n+\twritel(val, priv->base + MVEBU_COMPHY_SPEED_DIV(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));\n+\tval |= MVEBU_COMPHY_SERDES_CFG2_DFE_EN;\n+\twritel(val, priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));\n+\n+\t/* DFE resolution */\n+\tval = readl(priv->base + MVEBU_COMPHY_DFE_RES(lane->id));\n+\tval |= MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL;\n+\twritel(val, priv->base + MVEBU_COMPHY_DFE_RES(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));\n+\tval &= ~(MVEBU_COMPHY_GEN1_S0_TX_AMP(0x1f) |\n+\t\t MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf));\n+\tval |= MVEBU_COMPHY_GEN1_S0_TX_AMP(0x1c) |\n+\t MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xe);\n+\twritel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_GEN1_S2(lane->id));\n+\tval &= ~MVEBU_COMPHY_GEN1_S2_TX_EMPH(0xf);\n+\tval |= MVEBU_COMPHY_GEN1_S2_TX_EMPH_EN;\n+\twritel(val, priv->base + MVEBU_COMPHY_GEN1_S2(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_TX_SLEW_RATE(lane->id));\n+\tval |= MVEBU_COMPHY_TX_SLEW_RATE_EMPH(0x3) |\n+\t MVEBU_COMPHY_TX_SLEW_RATE_SLC(0x3f);\n+\twritel(val, priv->base + MVEBU_COMPHY_TX_SLEW_RATE(lane->id));\n+\n+\t/* Impedance calibration */\n+\tval = readl(priv->base + MVEBU_COMPHY_IMP_CAL(lane->id));\n+\tval &= ~MVEBU_COMPHY_IMP_CAL_TX_EXT(0x1f);\n+\tval |= MVEBU_COMPHY_IMP_CAL_TX_EXT(0xe) |\n+\t MVEBU_COMPHY_IMP_CAL_TX_EXT_EN;\n+\twritel(val, priv->base + MVEBU_COMPHY_IMP_CAL(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_GEN1_S5(lane->id));\n+\tval &= ~MVEBU_COMPHY_GEN1_S5_ICP(0xf);\n+\twritel(val, priv->base + MVEBU_COMPHY_GEN1_S5(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));\n+\tval &= ~(MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x7) |\n+\t\t MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x7) |\n+\t\t MVEBU_COMPHY_GEN1_S1_RX_MUL_FI(0x3) |\n+\t\t MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(0x3));\n+\tval |= MVEBU_COMPHY_GEN1_S1_RX_DFE_EN |\n+\t MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x2) |\n+\t MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x2) |\n+\t MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(0x1) |\n+\t MVEBU_COMPHY_GEN1_S1_RX_DIV(0x3);\n+\twritel(val, priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_COEF(lane->id));\n+\tval &= ~(MVEBU_COMPHY_COEF_DFE_EN | MVEBU_COMPHY_COEF_DFE_CTRL);\n+\twritel(val, priv->base + MVEBU_COMPHY_COEF(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));\n+\tval &= ~MVEBU_COMPHY_GEN1_S4_DFE_RES(0x3);\n+\tval |= MVEBU_COMPHY_GEN1_S4_DFE_RES(0x1);\n+\twritel(val, priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_GEN1_S3(lane->id));\n+\tval |= MVEBU_COMPHY_GEN1_S3_FBCK_SEL;\n+\twritel(val, priv->base + MVEBU_COMPHY_GEN1_S3(lane->id));\n+\n+\t/* rx training timer */\n+\tval = readl(priv->base + MVEBU_COMPHY_TRAINING5(lane->id));\n+\tval &= ~MVEBU_COMPHY_TRAINING5_RX_TIMER(0x3ff);\n+\tval |= MVEBU_COMPHY_TRAINING5_RX_TIMER(0x13);\n+\twritel(val, priv->base + MVEBU_COMPHY_TRAINING5(lane->id));\n+\n+\t/* tx train peak to peak hold */\n+\tval = readl(priv->base + MVEBU_COMPHY_TRAINING0(lane->id));\n+\tval |= MVEBU_COMPHY_TRAINING0_P2P_HOLD;\n+\twritel(val, priv->base + MVEBU_COMPHY_TRAINING0(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_TX_PRESET(lane->id));\n+\tval &= ~MVEBU_COMPHY_TX_PRESET_INDEX(0xf);\n+\tval |= MVEBU_COMPHY_TX_PRESET_INDEX(0x2);\t/* preset coeff */\n+\twritel(val, priv->base + MVEBU_COMPHY_TX_PRESET(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_FRAME_DETECT3(lane->id));\n+\tval &= ~MVEBU_COMPHY_FRAME_DETECT3_LOST_TIMEOUT_EN;\n+\twritel(val, priv->base + MVEBU_COMPHY_FRAME_DETECT3(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_TX_TRAIN_PRESET(lane->id));\n+\tval |= MVEBU_COMPHY_TX_TRAIN_PRESET_16B_AUTO_EN |\n+\t MVEBU_COMPHY_TX_TRAIN_PRESET_PRBS11;\n+\twritel(val, priv->base + MVEBU_COMPHY_TX_TRAIN_PRESET(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_FRAME_DETECT0(lane->id));\n+\tval &= ~MVEBU_COMPHY_FRAME_DETECT0_PATN(0x1ff);\n+\tval |= MVEBU_COMPHY_FRAME_DETECT0_PATN(0x88);\n+\twritel(val, priv->base + MVEBU_COMPHY_FRAME_DETECT0(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_DME(lane->id));\n+\tval |= MVEBU_COMPHY_DME_ETH_MODE;\n+\twritel(val, priv->base + MVEBU_COMPHY_DME(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_VDD_CAL0(lane->id));\n+\tval |= MVEBU_COMPHY_VDD_CAL0_CONT_MODE;\n+\twritel(val, priv->base + MVEBU_COMPHY_VDD_CAL0(lane->id));\n+\n+\tval = readl(priv->base + MVEBU_SP_CALIB(lane->id));\n+\tval &= ~MVEBU_SP_CALIB_SAMPLER(0x3);\n+\tval |= MVEBU_SP_CALIB_SAMPLER(0x3) |\n+\t MVEBU_SP_CALIB_SAMPLER_EN;\n+\twritel(val, priv->base + MVEBU_SP_CALIB(lane->id));\n+\tval &= ~MVEBU_SP_CALIB_SAMPLER_EN;\n+\twritel(val, priv->base + MVEBU_SP_CALIB(lane->id));\n+\n+\t/* External rx regulator */\n+\tval = readl(priv->base + MVEBU_COMPHY_EXT_SELV(lane->id));\n+\tval &= ~MVEBU_COMPHY_EXT_SELV_RX_SAMPL(0x1f);\n+\tval |= MVEBU_COMPHY_EXT_SELV_RX_SAMPL(0x1a);\n+\twritel(val, priv->base + MVEBU_COMPHY_EXT_SELV(lane->id));\n+\n+\treturn mvebu_comphy_init_plls(lane, PHY_MODE_10GKR);\n+}\n+\n+static int mvebu_comphy_power_on(struct phy *phy)\n+{\n+\tstruct mvebu_comphy_lane *lane = phy_get_drvdata(phy);\n+\tstruct mvebu_comphy_priv *priv = lane->priv;\n+\tint ret;\n+\tu32 mux, val;\n+\n+\tmux = mvebu_comphy_get_mux(lane->id, lane->port, lane->mode);\n+\tif (mux < 0)\n+\t\treturn -ENOTSUPP;\n+\n+\tregmap_read(priv->regmap, MVEBU_COMPHY_SELECTOR, &val);\n+\tval &= ~(0xf << MVEBU_COMPHY_SELECTOR_PHY(lane->id));\n+\tval |= mux << MVEBU_COMPHY_SELECTOR_PHY(lane->id);\n+\tregmap_write(priv->regmap, MVEBU_COMPHY_SELECTOR, val);\n+\n+\tswitch (lane->mode) {\n+\tcase PHY_MODE_SGMII:\n+\t\tret = mvebu_comphy_set_mode_sgmii(phy);\n+\t\tbreak;\n+\tcase PHY_MODE_10GKR:\n+\t\tret = mvebu_comphy_set_mode_10gkr(phy);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -ENOTSUPP;\n+\t}\n+\n+\t/* digital reset */\n+\tval = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));\n+\tval |= MVEBU_COMPHY_SERDES_CFG1_RF_RESET;\n+\twritel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));\n+\n+\treturn ret;\n+}\n+\n+static int mvebu_comphy_set_mode(struct phy *phy, enum phy_mode mode)\n+{\n+\tstruct mvebu_comphy_lane *lane = phy_get_drvdata(phy);\n+\n+\tif (mvebu_comphy_get_mux(lane->id, lane->port, mode) < 0)\n+\t\treturn -EINVAL;\n+\n+\tlane->mode = mode;\n+\treturn 0;\n+}\n+\n+static int mvebu_comphy_power_off(struct phy *phy)\n+{\n+\tstruct mvebu_comphy_lane *lane = phy_get_drvdata(phy);\n+\tstruct mvebu_comphy_priv *priv = lane->priv;\n+\tu32 val;\n+\n+\tval = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));\n+\tval &= ~(MVEBU_COMPHY_SERDES_CFG1_RESET |\n+\t\t MVEBU_COMPHY_SERDES_CFG1_CORE_RESET |\n+\t\t MVEBU_COMPHY_SERDES_CFG1_RF_RESET);\n+\twritel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));\n+\n+\tregmap_read(priv->regmap, MVEBU_COMPHY_SELECTOR, &val);\n+\tval &= ~(0xf << MVEBU_COMPHY_SELECTOR_PHY(lane->id));\n+\tregmap_write(priv->regmap, MVEBU_COMPHY_SELECTOR, val);\n+\n+\treturn 0;\n+}\n+\n+static const struct phy_ops mvebu_comphy_ops = {\n+\t.power_on\t= mvebu_comphy_power_on,\n+\t.power_off\t= mvebu_comphy_power_off,\n+\t.set_mode\t= mvebu_comphy_set_mode,\n+\t.owner\t\t= THIS_MODULE,\n+};\n+\n+static struct phy *mvebu_comphy_xlate(struct device *dev,\n+\t\t\t\t struct of_phandle_args *args)\n+{\n+\tstruct mvebu_comphy_lane *lane;\n+\tstruct phy *phy;\n+\n+\tif (WARN_ON(args->args[0] >= MVEBU_COMPHY_PORTS))\n+\t\treturn ERR_PTR(-EINVAL);\n+\n+\tphy = of_phy_simple_xlate(dev, args);\n+\tif (IS_ERR(phy))\n+\t\treturn phy;\n+\n+\tlane = phy_get_drvdata(phy);\n+\tif (lane->port >= 0)\n+\t\treturn ERR_PTR(-EBUSY);\n+\tlane->port = args->args[0];\n+\n+\treturn phy;\n+}\n+\n+static int mvebu_comphy_probe(struct platform_device *pdev)\n+{\n+\tstruct mvebu_comphy_priv *priv;\n+\tstruct phy_provider *provider;\n+\tstruct device_node *child;\n+\tstruct resource *res;\n+\n+\tpriv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);\n+\tif (!priv)\n+\t\treturn -ENOMEM;\n+\n+\tpriv->dev = &pdev->dev;\n+\tpriv->regmap =\n+\t\tsyscon_regmap_lookup_by_phandle(pdev->dev.of_node,\n+\t\t\t\t\t\t\"marvell,system-controller\");\n+\tif (IS_ERR(priv->regmap))\n+\t\treturn PTR_ERR(priv->regmap);\n+\tres = platform_get_resource(pdev, IORESOURCE_MEM, 0);\n+\tpriv->base = devm_ioremap_resource(&pdev->dev, res);\n+\tif (!priv->base)\n+\t\treturn -ENOMEM;\n+\n+\tfor_each_available_child_of_node(pdev->dev.of_node, child) {\n+\t\tstruct mvebu_comphy_lane *lane;\n+\t\tstruct phy *phy;\n+\t\tint ret;\n+\t\tu32 val;\n+\n+\t\tret = of_property_read_u32(child, \"reg\", &val);\n+\t\tif (ret < 0) {\n+\t\t\tdev_err(&pdev->dev, \"missing 'reg' property (%d)\\n\",\n+\t\t\t\tret);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (val >= MVEBU_COMPHY_LANES) {\n+\t\t\tdev_err(&pdev->dev, \"invalid 'reg' property\\n\");\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tlane = devm_kzalloc(&pdev->dev, sizeof(*lane), GFP_KERNEL);\n+\t\tif (!lane)\n+\t\t\treturn -ENOMEM;\n+\n+\t\tphy = devm_phy_create(&pdev->dev, child, &mvebu_comphy_ops);\n+\t\tif (IS_ERR(phy))\n+\t\t\treturn PTR_ERR(phy);\n+\n+\t\tlane->priv = priv;\n+\t\tlane->mode = PHY_MODE_INVALID;\n+\t\tlane->id = val;\n+\t\tlane->port = -1;\n+\t\tphy_set_drvdata(phy, lane);\n+\n+\t\t/*\n+\t\t * Once all modes are supported in this driver we should call\n+\t\t * mvebu_comphy_power_off(phy) here to avoid relying on the\n+\t\t * bootloader/firmware configuration.\n+\t\t */\n+\t}\n+\n+\tdev_set_drvdata(&pdev->dev, priv);\n+\tprovider = devm_of_phy_provider_register(&pdev->dev,\n+\t\t\t\t\t\t mvebu_comphy_xlate);\n+\treturn PTR_ERR_OR_ZERO(provider);\n+}\n+\n+static const struct of_device_id mvebu_comphy_of_match_table[] = {\n+\t{ .compatible = \"marvell,comphy-cp110\" },\n+\t{ },\n+};\n+MODULE_DEVICE_TABLE(of, mvebu_comphy_of_match_table);\n+\n+static struct platform_driver mvebu_comphy_driver = {\n+\t.probe\t= mvebu_comphy_probe,\n+\t.driver\t= {\n+\t\t.name = \"mvebu-comphy\",\n+\t\t.of_match_table = mvebu_comphy_of_match_table,\n+\t},\n+};\n+module_platform_driver(mvebu_comphy_driver);\n+\n+MODULE_AUTHOR(\"Antoine Tenart <antoine.tenart@free-electrons.com>\");\n+MODULE_DESCRIPTION(\"Common PHY driver for mvebu SoCs\");\n+MODULE_LICENSE(\"GPL v2\");\n", "prefixes": [ "net-next", "v4", "02/13" ] }