mediatek: add patch for xsphy driver to support pcie2 on MT7988

Import patch from MediaTek SDK which allows using the third
PCIe host controller of the MT7988 SoC.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
Daniel Golle 2023-12-08 01:04:39 +00:00
parent bbd49326c5
commit 6d76f1c733
1 changed files with 167 additions and 0 deletions

View File

@ -0,0 +1,167 @@
From 50cefacc6c001eea1d9b1c78ba27304566f304f1 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Fri, 2 Jun 2023 13:06:26 +0800
Subject: [PATCH] phy: mediatek: xsphy: support type switch by pericfg
Patch from Sam Shih <sam.shih@mediatek.com> found in MediaTek SDK
released under GPL.
Get syscon and use it to set the PHY type.
Extend support to PCIe and SGMII mode in addition to USB2 and USB3.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/phy/mediatek/phy-mtk-xsphy.c | 81 +++++++++++++++++++++++++++-
1 file changed, 80 insertions(+), 1 deletion(-)
--- a/drivers/phy/mediatek/phy-mtk-xsphy.c
+++ b/drivers/phy/mediatek/phy-mtk-xsphy.c
@@ -11,10 +11,12 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include "phy-mtk-io.h"
@@ -81,12 +83,22 @@
#define XSP_SR_COEF_DIVISOR 1000
#define XSP_FM_DET_CYCLE_CNT 1024
+/* PHY switch between pcie/usb3/sgmii */
+#define USB_PHY_SWITCH_CTRL 0x0
+#define RG_PHY_SW_TYPE GENMASK(3, 0)
+#define RG_PHY_SW_PCIE 0x0
+#define RG_PHY_SW_USB3 0x1
+#define RG_PHY_SW_SGMII 0x2
+
struct xsphy_instance {
struct phy *phy;
void __iomem *port_base;
struct clk *ref_clk; /* reference clock of anolog phy */
u32 index;
u32 type;
+ struct regmap *type_sw;
+ u32 type_sw_reg;
+ u32 type_sw_index;
/* only for HQA test */
int efuse_intr;
int efuse_tx_imp;
@@ -259,6 +271,10 @@ static void phy_parse_property(struct mt
inst->efuse_intr, inst->efuse_tx_imp,
inst->efuse_rx_imp);
break;
+ case PHY_TYPE_PCIE:
+ case PHY_TYPE_SGMII:
+ /* nothing to do */
+ break;
default:
dev_err(xsphy->dev, "incompatible phy type\n");
return;
@@ -305,6 +321,62 @@ static void u3_phy_props_set(struct mtk_
RG_XTP_LN0_RX_IMPSEL, inst->efuse_rx_imp);
}
+/* type switch for usb3/pcie/sgmii */
+static int phy_type_syscon_get(struct xsphy_instance *instance,
+ struct device_node *dn)
+{
+ struct of_phandle_args args;
+ int ret;
+
+ /* type switch function is optional */
+ if (!of_property_read_bool(dn, "mediatek,syscon-type"))
+ return 0;
+
+ ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type",
+ 2, 0, &args);
+ if (ret)
+ return ret;
+
+ instance->type_sw_reg = args.args[0];
+ instance->type_sw_index = args.args[1] & 0x3; /* <=3 */
+ instance->type_sw = syscon_node_to_regmap(args.np);
+ of_node_put(args.np);
+ dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n",
+ instance->type_sw_reg, instance->type_sw_index);
+
+ return PTR_ERR_OR_ZERO(instance->type_sw);
+}
+
+static int phy_type_set(struct xsphy_instance *instance)
+{
+ int type;
+ u32 offset;
+
+ if (!instance->type_sw)
+ return 0;
+
+ switch (instance->type) {
+ case PHY_TYPE_USB3:
+ type = RG_PHY_SW_USB3;
+ break;
+ case PHY_TYPE_PCIE:
+ type = RG_PHY_SW_PCIE;
+ break;
+ case PHY_TYPE_SGMII:
+ type = RG_PHY_SW_SGMII;
+ break;
+ case PHY_TYPE_USB2:
+ default:
+ return 0;
+ }
+
+ offset = instance->type_sw_index * BITS_PER_BYTE;
+ regmap_update_bits(instance->type_sw, instance->type_sw_reg,
+ RG_PHY_SW_TYPE << offset, type << offset);
+
+ return 0;
+}
+
static int mtk_phy_init(struct phy *phy)
{
struct xsphy_instance *inst = phy_get_drvdata(phy);
@@ -325,6 +397,10 @@ static int mtk_phy_init(struct phy *phy)
case PHY_TYPE_USB3:
u3_phy_props_set(xsphy, inst);
break;
+ case PHY_TYPE_PCIE:
+ case PHY_TYPE_SGMII:
+ /* nothing to do, only used to set type */
+ break;
default:
dev_err(xsphy->dev, "incompatible phy type\n");
clk_disable_unprepare(inst->ref_clk);
@@ -403,12 +479,15 @@ static struct phy *mtk_phy_xlate(struct
inst->type = args->args[0];
if (!(inst->type == PHY_TYPE_USB2 ||
- inst->type == PHY_TYPE_USB3)) {
+ inst->type == PHY_TYPE_USB3 ||
+ inst->type == PHY_TYPE_PCIE ||
+ inst->type == PHY_TYPE_SGMII)) {
dev_err(dev, "unsupported phy type: %d\n", inst->type);
return ERR_PTR(-EINVAL);
}
phy_parse_property(xsphy, inst);
+ phy_type_set(inst);
return inst->phy;
}
@@ -515,6 +594,10 @@ static int mtk_xsphy_probe(struct platfo
retval = PTR_ERR(inst->ref_clk);
goto put_child;
}
+
+ retval = phy_type_syscon_get(inst, child_np);
+ if (retval)
+ goto put_child;
}
provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);