mirror of
https://github.com/hanwckf/immortalwrt-mt798x.git
synced 2025-01-10 03:09:08 +08:00
313 lines
9.0 KiB
Diff
313 lines
9.0 KiB
Diff
From afb123e0f9992d35d0fb28ed875f2b7b7884652f Mon Sep 17 00:00:00 2001
|
|
From: Zhanyong Wang <zhanyong.wang@mediatek.com>
|
|
Date: Mon, 8 Nov 2021 14:51:38 +0800
|
|
Subject: [PATCH 3/5] phy: phy-mtk-tphy: add support efuse setting
|
|
|
|
Due to some SoCs have a bit shift issue that will drop a bit for usb3
|
|
phy or pcie phy, fix it by adding software efuse reading and setting,
|
|
but only support it optionally for versoin.
|
|
|
|
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
|
|
Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
|
|
Change-Id: Ibf88868668b3889f18c7930531981400cac732f1
|
|
---
|
|
drivers/phy/mediatek/phy-mtk-tphy.c | 194 ++++++++++++++++++++++++++++
|
|
1 file changed, 194 insertions(+)
|
|
|
|
diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c
|
|
index cb2ed3b25068..05a1ad4ff334 100644
|
|
--- a/drivers/phy/mediatek/phy-mtk-tphy.c
|
|
+++ b/drivers/phy/mediatek/phy-mtk-tphy.c
|
|
@@ -11,6 +11,7 @@
|
|
#include <linux/io.h>
|
|
#include <linux/iopoll.h>
|
|
#include <linux/module.h>
|
|
+#include <linux/nvmem-consumer.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/phy/phy.h>
|
|
@@ -38,11 +39,16 @@
|
|
#define SSUSB_SIFSLV_V2_U3PHYD 0x200
|
|
#define SSUSB_SIFSLV_V2_U3PHYA 0x400
|
|
|
|
+#define U3P_MISC_REG1 0x04
|
|
+#define MR1_EFUSE_AUTO_LOAD_DIS BIT(6)
|
|
+
|
|
#define U3P_USBPHYACR0 0x000
|
|
#define PA0_RG_U2PLL_FORCE_ON BIT(15)
|
|
#define PA0_RG_USB20_INTR_EN BIT(5)
|
|
|
|
#define U3P_USBPHYACR1 0x004
|
|
+#define PA1_RG_INTR_CAL GENMASK(23, 19)
|
|
+#define PA1_RG_INTR_CAL_VAL(x) ((0x1f & (x)) << 19)
|
|
#define PA1_RG_VRT_SEL GENMASK(14, 12)
|
|
#define PA1_RG_VRT_SEL_VAL(x) ((0x7 & (x)) << 12)
|
|
#define PA1_RG_TERM_SEL GENMASK(10, 8)
|
|
@@ -114,6 +120,8 @@
|
|
#define P3C_RG_SWRST_U3_PHYD_FORCE_EN BIT(24)
|
|
|
|
#define U3P_U3_PHYA_REG0 0x000
|
|
+#define P3A_RG_IEXT_INTR GENMASK(15, 10)
|
|
+#define P3A_RG_IEXT_INTR_VAL(x) ((0x3f & (x)) << 10)
|
|
#define P3A_RG_CLKDRV_OFF GENMASK(3, 2)
|
|
#define P3A_RG_CLKDRV_OFF_VAL(x) ((0x3 & (x)) << 2)
|
|
|
|
@@ -168,6 +176,25 @@
|
|
#define P3D_RG_FWAKE_TH GENMASK(21, 16)
|
|
#define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16)
|
|
|
|
+#define U3P_U3_PHYD_IMPCAL0 0x010
|
|
+#define P3D_RG_FORCE_TX_IMPEL BIT(31)
|
|
+#define P3D_RG_TX_IMPEL GENMASK(28, 24)
|
|
+#define P3D_RG_TX_IMPEL_VAL(x) ((0x1f & (x)) << 24)
|
|
+
|
|
+#define U3P_U3_PHYD_IMPCAL1 0x014
|
|
+#define P3D_RG_FORCE_RX_IMPEL BIT(31)
|
|
+#define P3D_RG_RX_IMPEL GENMASK(28, 24)
|
|
+#define P3D_RG_RX_IMPEL_VAL(x) ((0x1f & (x)) << 24)
|
|
+
|
|
+#define U3P_U3_PHYD_RX0 0x02c
|
|
+
|
|
+#define U3P_U3_PHYD_T2RLB 0x030
|
|
+
|
|
+#define U3P_U3_PHYD_PIPE0 0x040
|
|
+
|
|
+#define U3P_U3_PHYD_RSV 0x054
|
|
+#define P3D_RG_EFUSE_AUTO_LOAD_DIS BIT(12)
|
|
+
|
|
#define U3P_U3_PHYD_CDR1 0x05c
|
|
#define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24)
|
|
#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24)
|
|
@@ -266,11 +293,23 @@
|
|
enum mtk_phy_version {
|
|
MTK_PHY_V1 = 1,
|
|
MTK_PHY_V2,
|
|
+ MTK_PHY_V3,
|
|
};
|
|
|
|
struct mtk_phy_pdata {
|
|
/* avoid RX sensitivity level degradation only for mt8173 */
|
|
bool avoid_rx_sen_degradation;
|
|
+ /*
|
|
+ * u2phy should use integer mode instead of fractional mode of
|
|
+ * 48M PLL, fix it by switching PLL to 26M from default 48M
|
|
+ * for mt8195
|
|
+ */
|
|
+ bool sx_pll_48m_to_26m;
|
|
+ /*
|
|
+ * Some SoCs (e.g. mt8195) drop a bit when use auto load efuse,
|
|
+ * support sw way, also support it for v2/v3 optionally.
|
|
+ */
|
|
+ bool sw_efuse_supported;
|
|
enum mtk_phy_version version;
|
|
};
|
|
|
|
@@ -295,6 +334,10 @@ struct mtk_phy_instance {
|
|
struct u3phy_banks u3_banks;
|
|
};
|
|
struct clk *ref_clk; /* reference clock of anolog phy */
|
|
+ u32 efuse_sw_en;
|
|
+ u32 efuse_intr;
|
|
+ u32 efuse_tx_imp;
|
|
+ u32 efuse_rx_imp;
|
|
u32 index;
|
|
u8 type;
|
|
int eye_src;
|
|
@@ -890,6 +933,138 @@ static void u2_phy_props_set(struct mtk_tphy *tphy,
|
|
}
|
|
}
|
|
|
|
+static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instance)
|
|
+{
|
|
+ struct device *dev = &instance->phy->dev;
|
|
+ int ret = 0;
|
|
+
|
|
+ dev_err(dev, "try to get sw efuse\n");
|
|
+
|
|
+ /* tphy v1 doesn't support sw efuse, skip it */
|
|
+ if (!tphy->pdata->sw_efuse_supported) {
|
|
+ instance->efuse_sw_en = 0;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* software efuse is optional */
|
|
+ instance->efuse_sw_en = device_property_read_bool(dev, "nvmem-cells");
|
|
+ if (!instance->efuse_sw_en)
|
|
+ return 0;
|
|
+
|
|
+ dev_err(dev, "try to get sw efuse+\n");
|
|
+
|
|
+ switch (instance->type) {
|
|
+ case PHY_TYPE_USB2:
|
|
+ ret = nvmem_cell_read_variable_le_u32(dev, "intr", &instance->efuse_intr);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "fail to get u2 intr efuse, %d\n", ret);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* no efuse, ignore it */
|
|
+ if (!instance->efuse_intr) {
|
|
+ dev_warn(dev, "no u2 intr efuse, but dts enable it\n");
|
|
+ instance->efuse_sw_en = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ dev_info(dev, "u2 efuse - intr %x\n", instance->efuse_intr);
|
|
+ break;
|
|
+ case PHY_TYPE_USB3:
|
|
+ case PHY_TYPE_PCIE:
|
|
+ ret = nvmem_cell_read_variable_le_u32(dev, "intr", &instance->efuse_intr);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "fail to get u3 intr efuse, %d\n", ret);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ ret = nvmem_cell_read_variable_le_u32(dev, "rx_imp", &instance->efuse_rx_imp);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "fail to get u3 rx_imp efuse, %d\n", ret);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ ret = nvmem_cell_read_variable_le_u32(dev, "tx_imp", &instance->efuse_tx_imp);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "fail to get u3 tx_imp efuse, %d\n", ret);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* no efuse, ignore it */
|
|
+ if (!instance->efuse_intr &&
|
|
+ !instance->efuse_rx_imp &&
|
|
+ !instance->efuse_tx_imp) {
|
|
+ dev_warn(dev, "no u3 intr efuse, but dts enable it\n");
|
|
+ instance->efuse_sw_en = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ dev_info(dev, "u3 efuse - intr %x, rx_imp %x, tx_imp %x\n",
|
|
+ instance->efuse_intr, instance->efuse_rx_imp,
|
|
+ instance->efuse_tx_imp);
|
|
+ break;
|
|
+ default:
|
|
+ dev_err(dev, "no sw efuse for type %d\n", instance->type);
|
|
+ ret = -EINVAL;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void phy_efuse_set(struct mtk_phy_instance *instance)
|
|
+{
|
|
+ struct device *dev = &instance->phy->dev;
|
|
+ struct u2phy_banks *u2_banks = &instance->u2_banks;
|
|
+ struct u3phy_banks *u3_banks = &instance->u3_banks;
|
|
+ u32 tmp;
|
|
+
|
|
+ if (!instance->efuse_sw_en)
|
|
+ return;
|
|
+
|
|
+ switch (instance->type) {
|
|
+ case PHY_TYPE_USB2:
|
|
+ tmp = readl(u2_banks->misc + U3P_MISC_REG1);
|
|
+ tmp |= MR1_EFUSE_AUTO_LOAD_DIS;
|
|
+ writel(tmp, u2_banks->misc + U3P_MISC_REG1);
|
|
+
|
|
+ tmp = readl(u2_banks->com + U3P_USBPHYACR1);
|
|
+ tmp &= ~PA1_RG_INTR_CAL;
|
|
+ tmp |= PA1_RG_INTR_CAL_VAL(instance->efuse_intr);
|
|
+ writel(tmp, u2_banks->com + U3P_USBPHYACR1);
|
|
+ pr_err("%s set efuse intr %x\n", __func__, instance->efuse_intr);
|
|
+
|
|
+ break;
|
|
+ case PHY_TYPE_USB3:
|
|
+ case PHY_TYPE_PCIE:
|
|
+ tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RSV);
|
|
+ tmp |= P3D_RG_EFUSE_AUTO_LOAD_DIS;
|
|
+ writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RSV);
|
|
+
|
|
+ tmp = readl(u3_banks->phyd + U3P_U3_PHYD_IMPCAL0);
|
|
+ tmp &= ~P3D_RG_TX_IMPEL;
|
|
+ tmp |= P3D_RG_TX_IMPEL_VAL(instance->efuse_tx_imp);
|
|
+ tmp |= P3D_RG_FORCE_TX_IMPEL;
|
|
+ writel(tmp, u3_banks->phyd + U3P_U3_PHYD_IMPCAL0);
|
|
+
|
|
+ tmp = readl(u3_banks->phyd + U3P_U3_PHYD_IMPCAL1);
|
|
+ tmp &= ~P3D_RG_RX_IMPEL;
|
|
+ tmp |= P3D_RG_RX_IMPEL_VAL(instance->efuse_rx_imp);
|
|
+ tmp |= P3D_RG_FORCE_RX_IMPEL;
|
|
+ writel(tmp, u3_banks->phyd + U3P_U3_PHYD_IMPCAL1);
|
|
+
|
|
+ tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG0);
|
|
+ tmp &= ~P3A_RG_IEXT_INTR;
|
|
+ tmp |= P3A_RG_IEXT_INTR_VAL(instance->efuse_intr);
|
|
+ writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG0);
|
|
+ pr_err("%s set efuse, tx_imp %x, rx_imp %x intr %x\n",
|
|
+ __func__, instance->efuse_tx_imp,
|
|
+ instance->efuse_rx_imp, instance->efuse_intr);
|
|
+ break;
|
|
+ default:
|
|
+ dev_warn(dev, "no sw efuse for type %d\n", instance->type);
|
|
+ }
|
|
+}
|
|
+
|
|
static int mtk_phy_init(struct phy *phy)
|
|
{
|
|
struct mtk_phy_instance *instance = phy_get_drvdata(phy);
|
|
@@ -908,6 +1083,8 @@ static int mtk_phy_init(struct phy *phy)
|
|
return ret;
|
|
}
|
|
|
|
+ phy_efuse_set(instance);
|
|
+
|
|
switch (instance->type) {
|
|
case PHY_TYPE_USB2:
|
|
u2_phy_instance_init(tphy, instance);
|
|
@@ -989,6 +1166,7 @@ static struct phy *mtk_phy_xlate(struct device *dev,
|
|
struct mtk_phy_instance *instance = NULL;
|
|
struct device_node *phy_np = args->np;
|
|
int index;
|
|
+ int ret;
|
|
|
|
if (args->args_count != 1) {
|
|
dev_err(dev, "invalid number of cells in 'phy' property\n");
|
|
@@ -1024,6 +1202,10 @@ static struct phy *mtk_phy_xlate(struct device *dev,
|
|
return ERR_PTR(-EINVAL);
|
|
}
|
|
|
|
+ ret = phy_efuse_get(tphy, instance);
|
|
+ if (ret)
|
|
+ return ERR_PTR(ret);
|
|
+
|
|
phy_parse_property(tphy, instance);
|
|
|
|
return instance->phy;
|
|
@@ -1045,14 +1227,26 @@ static const struct mtk_phy_pdata tphy_v1_pdata = {
|
|
|
|
static const struct mtk_phy_pdata tphy_v2_pdata = {
|
|
.avoid_rx_sen_degradation = false,
|
|
+ .sw_efuse_supported = true,
|
|
.version = MTK_PHY_V2,
|
|
};
|
|
|
|
+static const struct mtk_phy_pdata tphy_v3_pdata = {
|
|
+ .sw_efuse_supported = true,
|
|
+ .version = MTK_PHY_V3,
|
|
+};
|
|
+
|
|
static const struct mtk_phy_pdata mt8173_pdata = {
|
|
.avoid_rx_sen_degradation = true,
|
|
.version = MTK_PHY_V1,
|
|
};
|
|
|
|
+static const struct mtk_phy_pdata mt8195_pdata = {
|
|
+ .sx_pll_48m_to_26m = true,
|
|
+ .sw_efuse_supported = true,
|
|
+ .version = MTK_PHY_V3,
|
|
+};
|
|
+
|
|
static const struct of_device_id mtk_tphy_id_table[] = {
|
|
{ .compatible = "mediatek,mt2701-u3phy", .data = &tphy_v1_pdata },
|
|
{ .compatible = "mediatek,mt2712-u3phy", .data = &tphy_v2_pdata },
|
|
--
|
|
2.18.0
|
|
|