Re: [PATCH 5/6] phy: phy-mtk-tphy: add support efuse setting
From: Chunfeng Yun <chunfeng.yun@mediatek.com>
Date: 2021-12-02 08:48:55
Also in:
linux-arm-kernel, linux-devicetree, linux-mediatek, lkml
On Thu, 2021-11-25 at 10:42 +0530, Vinod Koul wrote:
On 24-11-21, 14:54, Chunfeng Yun wrote:quoted
On Mon, 2021-11-22 at 17:05 +0530, Vinod Koul wrote:quoted
On 07-11-21, 15:56, Chunfeng Yun wrote:quoted
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 2/3.s/versoin/versionOkquoted
quoted
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com> --- drivers/phy/mediatek/phy-mtk-tphy.c | 162 ++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+)diff --git a/drivers/phy/mediatek/phy-mtk-tphy.cb/drivers/phy/mediatek/phy-mtk-tphy.c index cdcef865fe9e..3b5b1c266595 100644--- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c@@ -12,6 +12,7 @@ #include <linux/iopoll.h> #include <linux/mfd/syscon.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>@@ -41,6 +42,9 @@ #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_USB20_PLL_PREDIV GENMASK(7, 6)@@ -133,6 +137,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)@@ -187,6 +193,19 @@ #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_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)@@ -307,6 +326,11 @@ struct mtk_phy_pdata { * 48M PLL, fix it by switching PLL to 26M from default48M */ bool sw_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; };@@ -336,6 +360,10 @@ struct mtk_phy_instance { struct regmap *type_sw; u32 type_sw_reg; u32 type_sw_index; + u32 efuse_sw_en; + u32 efuse_intr; + u32 efuse_tx_imp; + u32 efuse_rx_imp; int eye_src; int eye_vrt; int eye_term;@@ -1040,6 +1068,130 @@ static int phy_type_set(structmtk_phy_instance *instance) return 0; } +static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instance) +{ + struct device *dev = &instance->phy->dev; + int ret = 0; + + /* 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; + + 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; + }What does this check do...? so a zero value is not valid..?Yes, because it's also zero for SoC without efuse, prefer to use default value instead.quoted
quoted
+ + dev_info(dev, "u2 efuse - intr %x\n", instance-quoted
efuse_intr);dev_dbg()?We usually use HW auto load way, print this log can help to point out that it's specific SoC.You can enable this print thru dynamic debug or enable debug prints when debugging, let us not spam message log
Ok, will use dev_dbg()
quoted
quoted
quoted
+ break;empty line after break improves readability, pls addOkquoted
quoted
+ 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; + }This seems to be common, why not read this before switch?It's not used for SGMII or SATA, but not applied until nowquoted
quoted
+ + 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_rx_imp) { + dev_warn(dev, "no u3 intr efuse, but dts enable it\n"); + instance->efuse_sw_en = 0; + break; + }again, zero values are not valid?It's also zero for SoC without efuse, treat it as invalid valuequoted
quoted
+ + dev_info(dev, "u3 efuse - intr %x, rx_imp %x, tx_imp %x\n", + instance->efuse_intr, instance-quoted
efuse_rx_imp,+ instance->efuse_tx_imp);dbg plsOkquoted
quoted
+ break; + default: + dev_err(dev, "no sw efuse for type %d\n", instance-quoted
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-quoted
efuse_intr);+ writel(tmp, u2_banks->com + U3P_USBPHYACR1); + 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);add a updatel() macro and use this here and other places?You mean add macro to set/clear bits? If so, I need prepare another patch for this purposeSure, that would be nice
Ok
-- linux-phy mailing list linux-phy@lists.infradead.org https://lists.infradead.org/mailman/listinfo/linux-phy