All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Marek Behún" <marek.behun@nic.cz>
To: u-boot@lists.denx.de
Subject: [PATCH u-boot-marvell 03/11] phy: port Armada 37xx COMPHY from Linux
Date: Sun, 19 Apr 2020 17:48:42 +0200	[thread overview]
Message-ID: <20200419154850.25868-4-marek.behun@nic.cz> (raw)
In-Reply-To: <20200419154850.25868-1-marek.behun@nic.cz>

This patch ports the A3700 COMPHY driver from Linux.

Signed-off-by: Marek Beh?n <marek.behun@nic.cz>
---
 drivers/phy/Kconfig                  |   8 +
 drivers/phy/Makefile                 |   1 +
 drivers/phy/phy-mvebu-a3700-comphy.c | 315 +++++++++++++++++++++++++++
 3 files changed, 324 insertions(+)
 create mode 100644 drivers/phy/phy-mvebu-a3700-comphy.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index f655f1af3c..04307c5876 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -217,6 +217,14 @@ config PHY_MTK_TPHY
 	  multi-ports is first version, otherwise is second veriosn,
 	  so you can easily distinguish them by banks layout.
 
+config PHY_MVEBU_A3700_COMPHY
+	tristate "Marvell A3700 comphy driver"
+	depends on PHY && ARMADA_3700
+	help
+	  This driver allows to control the comphy, a hardware block providing
+	  shared serdes PHYs on Marvell Armada 3700. Its serdes lanes can be
+	  used by various controllers: Ethernet, SATA, USB3, PCIe.
+
 config PHY_MVEBU_A3700_UTMI
 	bool "Marvell A3700 UTMI driver"
 	depends on PHY && ARMADA_3700
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index d76e26dd83..0ee88b1251 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -24,4 +24,5 @@ obj-$(CONFIG_KEYSTONE_USB_PHY) += keystone-usb-phy.o
 obj-$(CONFIG_MT76X8_USB_PHY) += mt76x8-usb-phy.o
 obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
 obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
+obj-$(CONFIG_PHY_MVEBU_A3700_COMPHY) += phy-mvebu-a3700-comphy.o
 obj-$(CONFIG_PHY_MVEBU_A3700_UTMI) += phy-mvebu-a3700-utmi.o
diff --git a/drivers/phy/phy-mvebu-a3700-comphy.c b/drivers/phy/phy-mvebu-a3700-comphy.c
new file mode 100644
index 0000000000..f657626f65
--- /dev/null
+++ b/drivers/phy/phy-mvebu-a3700-comphy.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Marvell
+ *
+ * Authors:
+ *   Evan Wang <xswang@marvell.com>
+ *   Miqu?l Raynal <miquel.raynal@bootlin.com>
+ *
+ * Structure inspired from phy-mvebu-cp110-comphy.c written by Antoine Tenart.
+ * SMC call initial support done by Grzegorz Jaszczyk.
+ *
+ * Ported from Linux to U-Boot by Marek Behun <marek.behun@nic.cz>
+ */
+
+#include <common.h>
+#include <asm/system.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <linux/bug.h>
+#include <linux/compat.h>
+#include <phy_interface.h>
+
+#define MVEBU_A3700_COMPHY_LANES		3
+#define MVEBU_A3700_COMPHY_PORTS		2
+
+/* COMPHY Fast SMC function identifiers */
+#define COMPHY_SIP_POWER_ON			0x82000001
+#define COMPHY_SIP_POWER_OFF			0x82000002
+#define COMPHY_SIP_PLL_LOCK			0x82000003
+#define COMPHY_FW_NOT_SUPPORTED			(-1)
+
+#define COMPHY_FW_MODE_SATA			0x1
+#define COMPHY_FW_MODE_SGMII			0x2
+#define COMPHY_FW_MODE_HS_SGMII			0x3
+#define COMPHY_FW_MODE_USB3H			0x4
+#define COMPHY_FW_MODE_USB3D			0x5
+#define COMPHY_FW_MODE_PCIE			0x6
+#define COMPHY_FW_MODE_RXAUI			0x7
+#define COMPHY_FW_MODE_XFI			0x8
+#define COMPHY_FW_MODE_SFI			0x9
+#define COMPHY_FW_MODE_USB3			0xa
+
+#define COMPHY_FW_SPEED_1_25G			0 /* SGMII 1G */
+#define COMPHY_FW_SPEED_2_5G			1
+#define COMPHY_FW_SPEED_3_125G			2 /* SGMII 2.5G */
+#define COMPHY_FW_SPEED_5G			3
+#define COMPHY_FW_SPEED_5_15625G		4 /* XFI 5G */
+#define COMPHY_FW_SPEED_6G			5
+#define COMPHY_FW_SPEED_10_3125G		6 /* XFI 10G */
+#define COMPHY_FW_SPEED_MAX			0x3F
+
+#define COMPHY_FW_MODE(mode)			((mode) << 12)
+#define COMPHY_FW_NET(mode, idx, speed)		(COMPHY_FW_MODE(mode) | \
+						 ((idx) << 8) |	\
+						 ((speed) << 2))
+#define COMPHY_FW_PCIE(mode, idx, speed)	(COMPHY_FW_NET(mode, idx, speed))
+
+struct mvebu_a3700_comphy_conf {
+	unsigned int lane;
+	enum phy_mode mode;
+	int submode;
+	unsigned int port;
+	u32 fw_mode;
+};
+
+#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _port, _fw)	\
+	{								\
+		.lane = _lane,						\
+		.mode = _mode,						\
+		.submode = _smode,					\
+		.port = _port,						\
+		.fw_mode = _fw,						\
+	}
+
+#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _port, _fw) \
+	MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NONE, _port, _fw)
+
+#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _port, _fw) \
+	MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _port, _fw)
+
+static const struct mvebu_a3700_comphy_conf mvebu_a3700_comphy_modes[] = {
+	/* lane 0 */
+	MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, 0,
+				    COMPHY_FW_MODE_USB3H),
+	MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, 1,
+				    COMPHY_FW_MODE_SGMII),
+	MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII_2500, 1,
+				    COMPHY_FW_MODE_HS_SGMII),
+	/* lane 1 */
+	MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, 0,
+				    COMPHY_FW_MODE_PCIE),
+	MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, 0,
+				    COMPHY_FW_MODE_SGMII),
+	MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII_2500, 0,
+				    COMPHY_FW_MODE_HS_SGMII),
+	/* lane 2 */
+	MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, 0,
+				    COMPHY_FW_MODE_SATA),
+	MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, 0,
+				    COMPHY_FW_MODE_USB3H),
+};
+
+struct mvebu_a3700_comphy_lane {
+	unsigned int id;
+	enum phy_mode mode;
+	int submode;
+	int port;
+};
+
+struct mvebu_a3700_comphy {
+	struct mvebu_a3700_comphy_lane lanes[MVEBU_A3700_COMPHY_LANES];
+};
+
+static int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane,
+				  unsigned long mode)
+{
+	struct pt_regs regs;
+
+	regs.regs[0] = function;
+	regs.regs[1] = lane;
+	regs.regs[2] = mode;
+
+	smc_call(&regs);
+
+	return regs.regs[0];
+}
+
+static int mvebu_a3700_comphy_get_fw_mode(int lane, int port,
+					  enum phy_mode mode,
+					  int submode)
+{
+	int i, n = ARRAY_SIZE(mvebu_a3700_comphy_modes);
+
+	/* Unused PHY mux value is 0x0 */
+	if (mode == PHY_MODE_INVALID)
+		return -EINVAL;
+
+	for (i = 0; i < n; i++) {
+		if (mvebu_a3700_comphy_modes[i].lane == lane &&
+		    mvebu_a3700_comphy_modes[i].port == port &&
+		    mvebu_a3700_comphy_modes[i].mode == mode &&
+		    (mode != PHY_MODE_ETHERNET ||
+		     mvebu_a3700_comphy_modes[i].submode == submode))
+			break;
+	}
+
+	if (i == n)
+		return -EINVAL;
+
+	return mvebu_a3700_comphy_modes[i].fw_mode;
+}
+
+static inline struct mvebu_a3700_comphy_lane *phy_to_lane(struct phy *phy)
+{
+	struct mvebu_a3700_comphy *priv = dev_get_priv(phy->dev);
+
+	return &priv->lanes[phy->id];
+}
+
+static int mvebu_a3700_comphy_set_mode(struct phy *phy, enum phy_mode mode,
+				       int submode)
+{
+	struct mvebu_a3700_comphy_lane *lane = phy_to_lane(phy);
+	int fw_mode;
+
+	fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, mode,
+						 submode);
+	if (fw_mode < 0) {
+		dev_err(lane->dev, "invalid COMPHY mode\n");
+		return fw_mode;
+	}
+
+	/* Just remember the mode, ->power_on() will do the real setup */
+	lane->mode = mode;
+	lane->submode = submode;
+
+	return 0;
+}
+
+static int mvebu_a3700_comphy_power_on(struct phy *phy)
+{
+	struct mvebu_a3700_comphy_lane *lane = phy_to_lane(phy);
+	u32 fw_param;
+	int fw_mode;
+	int ret;
+
+	fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port,
+						 lane->mode, lane->submode);
+	if (fw_mode < 0) {
+		dev_err(lane->dev, "invalid COMPHY mode\n");
+		return fw_mode;
+	}
+
+	switch (lane->mode) {
+	case PHY_MODE_USB_HOST_SS:
+		dev_dbg(lane->dev, "set lane %d to USB3 host mode\n", lane->id);
+		fw_param = COMPHY_FW_MODE(fw_mode);
+		break;
+	case PHY_MODE_SATA:
+		dev_dbg(lane->dev, "set lane %d to SATA mode\n", lane->id);
+		fw_param = COMPHY_FW_MODE(fw_mode);
+		break;
+	case PHY_MODE_ETHERNET:
+		switch (lane->submode) {
+		case PHY_INTERFACE_MODE_SGMII:
+			dev_dbg(lane->dev, "set lane %d to SGMII mode\n",
+				lane->id);
+			fw_param = COMPHY_FW_NET(fw_mode, lane->port,
+						 COMPHY_FW_SPEED_1_25G);
+			break;
+		case PHY_INTERFACE_MODE_SGMII_2500:
+			dev_dbg(lane->dev, "set lane %d to HS SGMII mode\n",
+				lane->id);
+			fw_param = COMPHY_FW_NET(fw_mode, lane->port,
+						 COMPHY_FW_SPEED_3_125G);
+			break;
+		default:
+			dev_err(lane->dev, "unsupported PHY submode (%d)\n",
+				lane->submode);
+			return -ENOTSUPP;
+		}
+		break;
+	case PHY_MODE_PCIE:
+		dev_dbg(lane->dev, "set lane %d to PCIe mode\n", lane->id);
+		fw_param = COMPHY_FW_PCIE(fw_mode, lane->port,
+					  COMPHY_FW_SPEED_5G);
+		break;
+	default:
+		dev_err(lane->dev, "unsupported PHY mode (%d)\n", lane->mode);
+		return -ENOTSUPP;
+	}
+
+	ret = mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_ON, lane->id, fw_param);
+	if (ret == COMPHY_FW_NOT_SUPPORTED)
+		dev_err(lane->dev,
+			"unsupported SMC call, try updating your firmware\n");
+
+	return ret;
+}
+
+static int mvebu_a3700_comphy_power_off(struct phy *phy)
+{
+	struct mvebu_a3700_comphy_lane *lane = phy_to_lane(phy);
+
+	return mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_OFF, lane->id, 0);
+}
+
+static int mvebu_a3700_comphy_xlate(struct phy *phy,
+				    struct ofnode_phandle_args *args)
+{
+	struct mvebu_a3700_comphy_lane *lane;
+
+	if (WARN_ON(args->args_count > 2 ||
+		    args->args[0] >= MVEBU_A3700_COMPHY_LANES ||
+		    args->args[1] >= MVEBU_A3700_COMPHY_PORTS))
+		return -EINVAL;
+
+	phy->id = args->args[0];
+	lane = phy_to_lane(phy);
+	lane->port = args->args[1];
+
+	return 0;
+}
+
+static const struct phy_ops mvebu_a3700_comphy_ops = {
+	.power_on	= mvebu_a3700_comphy_power_on,
+	.power_off	= mvebu_a3700_comphy_power_off,
+	.set_mode	= mvebu_a3700_comphy_set_mode,
+	.of_xlate	= mvebu_a3700_comphy_xlate,
+};
+
+static int mvebu_a3700_comphy_probe(struct udevice *dev)
+{
+	struct mvebu_a3700_comphy *priv = dev_get_priv(dev);
+	ofnode child;
+
+	dev_for_each_subnode(child, dev) {
+		struct mvebu_a3700_comphy_lane *lane;
+		u32 lane_id;
+		int ret;
+
+		ret = ofnode_read_u32(child, "reg", &lane_id);
+		if (ret < 0) {
+			dev_err(parent, "missing 'reg' property (%d)\n", ret);
+			continue;
+		}
+
+		if (lane_id >= MVEBU_A3700_COMPHY_LANES) {
+			dev_err(parent, "invalid 'reg' property\n");
+			continue;
+		}
+
+		lane = &priv->lanes[lane_id];
+		lane->mode = PHY_MODE_INVALID;
+		lane->submode = PHY_INTERFACE_MODE_NONE;
+		lane->id = lane_id;
+		lane->port = -1;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id mvebu_a3700_comphy_of_match_table[] = {
+	{ .compatible = "marvell,comphy-a3700" },
+	{ },
+};
+
+U_BOOT_DRIVER(mvebu_a3700_comphy) = {
+	.name = "mvebu-a3700-comphy",
+	.id = UCLASS_PHY,
+	.of_match = mvebu_a3700_comphy_of_match_table,
+	.ops = &mvebu_a3700_comphy_ops,
+	.probe = mvebu_a3700_comphy_probe,
+	.priv_auto_alloc_size = sizeof(struct mvebu_a3700_comphy),
+};
-- 
2.24.1

  parent reply	other threads:[~2020-04-19 15:48 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-19 15:48 [PATCH u-boot-marvell 00/11] Armada 37xx: port comphy to generic-phys (PLEASE TEST) Marek Behún
2020-04-19 15:48 ` [PATCH u-boot-marvell 01/11] phy: add support for setting phy mode Marek Behún
2020-04-19 15:48 ` [PATCH u-boot-marvell 02/11] phy: port Armada 37xx UTMI PHY from Linux Marek Behún
2020-04-19 15:48 ` Marek Behún [this message]
2020-04-19 15:48 ` [PATCH u-boot-marvell 04/11] usb: host: make PHY handling more generic Marek Behún
2020-04-20  1:41   ` Marek Vasut
2020-04-20  9:27     ` Marek Behun
2020-04-20 10:20       ` Marek Vasut
2020-04-20 10:40         ` Marek Behun
2020-04-19 15:48 ` [PATCH u-boot-marvell 05/11] usb: ehci-marvell: call generic-phy initialization Marek Behún
2020-04-19 15:48 ` [PATCH u-boot-marvell 06/11] usb: xhci-mvebu: " Marek Behún
2020-04-19 15:48 ` [PATCH u-boot-marvell 07/11] pci: aardvark: add PHY support Marek Behún
2020-04-19 15:48 ` [PATCH u-boot-marvell 08/11] ata: ahci_mvebu: " Marek Behún
2020-04-19 15:48 ` [PATCH u-boot-marvell 09/11] net: mvneta: " Marek Behún
2020-04-20  9:36   ` Marek Behun
2020-04-19 15:48 ` [PATCH u-boot-marvell 10/11] arm64: mvebu: armada-37xx: convert to use new generic-phy drivers Marek Behún
2020-04-19 20:06   ` [PATCH u-boot-marvell 10/11 fix] " Marek Behún
2020-04-19 15:48 ` [PATCH u-boot-marvell 11/11] phy: marvell: remove comphy_a3700 driver Marek Behún
2020-05-08 13:05 ` [PATCH u-boot-marvell 00/11] Armada 37xx: port comphy to generic-phys (PLEASE TEST) Tomasz Maciej Nowak

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200419154850.25868-4-marek.behun@nic.cz \
    --to=marek.behun@nic.cz \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.