| From 34687407776d46f08926b91f118adc484c4ac231 Mon Sep 17 00:00:00 2001 |
| From: Zhanyong Wang <zhanyong.wang@mediatek.com> |
| Date: Fri, 17 Sep 2021 15:56:53 +0800 |
| Subject: [PATCH 1/8] phy: phy-mtk-tphy: support type switch by pericfg |
| |
| Add support type switch between USB3, PCIe, SATA and SGMII by |
| pericfg register, this is used to take the place of efuse or |
| jumper. |
| |
| Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com> |
| Signed-off-by: Vinod Koul <vkoul@kernel.org> |
| Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com> |
| --- |
| drivers/phy/mediatek/phy-mtk-tphy.c | 83 ++++++++++++++++++++++++++++- |
| 1 file changed, 81 insertions(+), 2 deletions(-) |
| |
| diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c |
| index cb2ed3b25068..a59fe65f69e5 100644 |
| --- a/drivers/phy/mediatek/phy-mtk-tphy.c |
| +++ b/drivers/phy/mediatek/phy-mtk-tphy.c |
| @@ -10,6 +10,7 @@ |
| #include <linux/delay.h> |
| #include <linux/io.h> |
| #include <linux/iopoll.h> |
| +#include <linux/mfd/syscon.h> |
| #include <linux/module.h> |
| #include <linux/of_address.h> |
| #include <linux/of_device.h> |
| @@ -263,6 +264,14 @@ |
| #define RG_CDR_BIRLTD0_GEN3_MSK GENMASK(4, 0) |
| #define RG_CDR_BIRLTD0_GEN3_VAL(x) (0x1f & (x)) |
| |
| +/* PHY switch between pcie/usb3/sgmii/sata */ |
| +#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 |
| +#define RG_PHY_SW_SATA 0x3 |
| + |
| enum mtk_phy_version { |
| MTK_PHY_V1 = 1, |
| MTK_PHY_V2, |
| @@ -296,7 +305,10 @@ struct mtk_phy_instance { |
| }; |
| struct clk *ref_clk; /* reference clock of anolog phy */ |
| u32 index; |
| - u8 type; |
| + u32 type; |
| + struct regmap *type_sw; |
| + u32 type_sw_reg; |
| + u32 type_sw_index; |
| int eye_src; |
| int eye_vrt; |
| int eye_term; |
| @@ -890,6 +902,64 @@ static void u2_phy_props_set(struct mtk_tphy *tphy, |
| } |
| } |
| |
| +/* type switch for usb3/pcie/sgmii/sata */ |
| +static int phy_type_syscon_get(struct mtk_phy_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 mtk_phy_instance *instance) |
| +{ |
| + int type; |
| + u32 mask; |
| + |
| + 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_SATA: |
| + type = RG_PHY_SW_SATA; |
| + break; |
| + case PHY_TYPE_USB2: |
| + default: |
| + return 0; |
| + } |
| + |
| + mask = RG_PHY_SW_TYPE << (instance->type_sw_index * BITS_PER_BYTE); |
| + regmap_update_bits(instance->type_sw, instance->type_sw_reg, mask, type); |
| + |
| + return 0; |
| +} |
| + |
| static int mtk_phy_init(struct phy *phy) |
| { |
| struct mtk_phy_instance *instance = phy_get_drvdata(phy); |
| @@ -922,6 +992,9 @@ static int mtk_phy_init(struct phy *phy) |
| case PHY_TYPE_SATA: |
| sata_phy_instance_init(tphy, instance); |
| break; |
| + case PHY_TYPE_SGMII: |
| + /* nothing to do, only used to set type */ |
| + break; |
| default: |
| dev_err(tphy->dev, "incompatible PHY type\n"); |
| return -EINVAL; |
| @@ -1010,7 +1083,8 @@ static struct phy *mtk_phy_xlate(struct device *dev, |
| if (!(instance->type == PHY_TYPE_USB2 || |
| instance->type == PHY_TYPE_USB3 || |
| instance->type == PHY_TYPE_PCIE || |
| - instance->type == PHY_TYPE_SATA)) { |
| + instance->type == PHY_TYPE_SATA || |
| + instance->type == PHY_TYPE_SGMII)) { |
| dev_err(dev, "unsupported device type: %d\n", instance->type); |
| return ERR_PTR(-EINVAL); |
| } |
| @@ -1025,6 +1099,7 @@ static struct phy *mtk_phy_xlate(struct device *dev, |
| } |
| |
| phy_parse_property(tphy, instance); |
| + phy_type_set(instance); |
| |
| return instance->phy; |
| } |
| @@ -1163,6 +1238,10 @@ static int mtk_tphy_probe(struct platform_device *pdev) |
| retval = PTR_ERR(instance->ref_clk); |
| goto put_child; |
| } |
| + |
| + retval = phy_type_syscon_get(instance, child_np); |
| + if (retval) |
| + goto put_child; |
| } |
| |
| provider = devm_of_phy_provider_register(dev, mtk_phy_xlate); |
| -- |
| 2.18.0 |
| |