Skip to content

Commit f85eb65

Browse files
dangowrtvinodkoul
authored andcommitted
phy: mediatek: xsphy: support type switch by pericfg
Patch from Sam Shih <[email protected]> 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 <[email protected]> Signed-off-by: Frank Wunderlich <[email protected]> Reviewed-by: AngeloGioacchino Del Regno <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent b484b25 commit f85eb65

File tree

1 file changed

+84
-1
lines changed

1 file changed

+84
-1
lines changed

drivers/phy/mediatek/phy-mtk-xsphy.c

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
#include <linux/clk.h>
1212
#include <linux/delay.h>
1313
#include <linux/iopoll.h>
14+
#include <linux/mfd/syscon.h>
1415
#include <linux/module.h>
1516
#include <linux/of_address.h>
1617
#include <linux/phy/phy.h>
1718
#include <linux/platform_device.h>
19+
#include <linux/regmap.h>
1820

1921
#include "phy-mtk-io.h"
2022

@@ -81,12 +83,22 @@
8183
#define XSP_SR_COEF_DIVISOR 1000
8284
#define XSP_FM_DET_CYCLE_CNT 1024
8385

86+
/* PHY switch between pcie/usb3/sgmii */
87+
#define USB_PHY_SWITCH_CTRL 0x0
88+
#define RG_PHY_SW_TYPE GENMASK(3, 0)
89+
#define RG_PHY_SW_PCIE 0x0
90+
#define RG_PHY_SW_USB3 0x1
91+
#define RG_PHY_SW_SGMII 0x2
92+
8493
struct xsphy_instance {
8594
struct phy *phy;
8695
void __iomem *port_base;
8796
struct clk *ref_clk; /* reference clock of anolog phy */
8897
u32 index;
8998
u32 type;
99+
struct regmap *type_sw;
100+
u32 type_sw_reg;
101+
u32 type_sw_index;
90102
/* only for HQA test */
91103
int efuse_intr;
92104
int efuse_tx_imp;
@@ -259,6 +271,10 @@ static void phy_parse_property(struct mtk_xsphy *xsphy,
259271
inst->efuse_intr, inst->efuse_tx_imp,
260272
inst->efuse_rx_imp);
261273
break;
274+
case PHY_TYPE_PCIE:
275+
case PHY_TYPE_SGMII:
276+
/* nothing to do */
277+
break;
262278
default:
263279
dev_err(xsphy->dev, "incompatible phy type\n");
264280
return;
@@ -305,6 +321,62 @@ static void u3_phy_props_set(struct mtk_xsphy *xsphy,
305321
RG_XTP_LN0_RX_IMPSEL, inst->efuse_rx_imp);
306322
}
307323

324+
/* type switch for usb3/pcie/sgmii */
325+
static int phy_type_syscon_get(struct xsphy_instance *instance,
326+
struct device_node *dn)
327+
{
328+
struct of_phandle_args args;
329+
int ret;
330+
331+
/* type switch function is optional */
332+
if (!of_property_present(dn, "mediatek,syscon-type"))
333+
return 0;
334+
335+
ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type",
336+
2, 0, &args);
337+
if (ret)
338+
return ret;
339+
340+
instance->type_sw_reg = args.args[0];
341+
instance->type_sw_index = args.args[1] & 0x3; /* <=3 */
342+
instance->type_sw = syscon_node_to_regmap(args.np);
343+
of_node_put(args.np);
344+
dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n",
345+
instance->type_sw_reg, instance->type_sw_index);
346+
347+
return PTR_ERR_OR_ZERO(instance->type_sw);
348+
}
349+
350+
static int phy_type_set(struct xsphy_instance *instance)
351+
{
352+
int type;
353+
u32 offset;
354+
355+
if (!instance->type_sw)
356+
return 0;
357+
358+
switch (instance->type) {
359+
case PHY_TYPE_USB3:
360+
type = RG_PHY_SW_USB3;
361+
break;
362+
case PHY_TYPE_PCIE:
363+
type = RG_PHY_SW_PCIE;
364+
break;
365+
case PHY_TYPE_SGMII:
366+
type = RG_PHY_SW_SGMII;
367+
break;
368+
case PHY_TYPE_USB2:
369+
default:
370+
return 0;
371+
}
372+
373+
offset = instance->type_sw_index * BITS_PER_BYTE;
374+
regmap_update_bits(instance->type_sw, instance->type_sw_reg,
375+
RG_PHY_SW_TYPE << offset, type << offset);
376+
377+
return 0;
378+
}
379+
308380
static int mtk_phy_init(struct phy *phy)
309381
{
310382
struct xsphy_instance *inst = phy_get_drvdata(phy);
@@ -325,6 +397,10 @@ static int mtk_phy_init(struct phy *phy)
325397
case PHY_TYPE_USB3:
326398
u3_phy_props_set(xsphy, inst);
327399
break;
400+
case PHY_TYPE_PCIE:
401+
case PHY_TYPE_SGMII:
402+
/* nothing to do, only used to set type */
403+
break;
328404
default:
329405
dev_err(xsphy->dev, "incompatible phy type\n");
330406
clk_disable_unprepare(inst->ref_clk);
@@ -403,12 +479,15 @@ static struct phy *mtk_phy_xlate(struct device *dev,
403479

404480
inst->type = args->args[0];
405481
if (!(inst->type == PHY_TYPE_USB2 ||
406-
inst->type == PHY_TYPE_USB3)) {
482+
inst->type == PHY_TYPE_USB3 ||
483+
inst->type == PHY_TYPE_PCIE ||
484+
inst->type == PHY_TYPE_SGMII)) {
407485
dev_err(dev, "unsupported phy type: %d\n", inst->type);
408486
return ERR_PTR(-EINVAL);
409487
}
410488

411489
phy_parse_property(xsphy, inst);
490+
phy_type_set(inst);
412491

413492
return inst->phy;
414493
}
@@ -510,6 +589,10 @@ static int mtk_xsphy_probe(struct platform_device *pdev)
510589
dev_err(dev, "failed to get ref_clk(id-%d)\n", port);
511590
return PTR_ERR(inst->ref_clk);
512591
}
592+
593+
retval = phy_type_syscon_get(inst, child_np);
594+
if (retval)
595+
return retval;
513596
}
514597

515598
provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);

0 commit comments

Comments
 (0)