[][nvmem: porting newest upstream source code 1/5]

[Description]
Add newest upstream source code on nvmem relations.

[Release-log]
N/A

Change-Id: I999e439f6706a00593c385e7adb5367c973d644b
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/5579214
diff --git a/target/linux/mediatek/patches-5.4/8004-nvmem-core-Add-functions-to-make-number-reading-easy.patch b/target/linux/mediatek/patches-5.4/8004-nvmem-core-Add-functions-to-make-number-reading-easy.patch
new file mode 100644
index 0000000..969ec3f
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/8004-nvmem-core-Add-functions-to-make-number-reading-easy.patch
@@ -0,0 +1,307 @@
+From 8dc0b1158dcffd78ea2b3a5604b82ee826de687b Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Mon, 8 Nov 2021 13:58:51 +0800
+Subject: [PATCH 1/5] nvmem: core: Add functions to make number reading easy
+
+Sometimes the clients of nvmem just want to get a number out of
+nvmem. They don't want to think about exactly how many bytes the nvmem
+cell took up. They just want the number. Let's make it easy.
+
+In general this concept is useful because nvmem space is precious and
+usually the fewest bits are allocated that will hold a given value on
+a given system. However, even though small numbers might be fine on
+one system that doesn't mean that logically the number couldn't be
+bigger. Imagine nvmem containing a max frequency for a component. On
+one system perhaps that fits in 16 bits. On another system it might
+fit in 32 bits. The code reading this number doesn't care--it just
+wants the number.
+
+We'll provide two functions: nvmem_cell_read_variable_le_u32() and
+nvmem_cell_read_variable_le_u64().
+
+Comparing these to the existing functions like nvmem_cell_read_u32():
+* These new functions have no problems if the value was stored in
+  nvmem in fewer bytes. It's OK to use these function as long as the
+  value stored will fit in 32-bits (or 64-bits).
+* These functions avoid problems that the earlier APIs had with bit
+  offsets. For instance, you can't use nvmem_cell_read_u32() to read a
+  value has nbits=32 and bit_offset=4 because the nvmem cell must be
+  at least 5 bytes big to hold this value. The new API accounts for
+  this and works fine.
+* These functions make it very explicit that they assume that the
+  number was stored in little endian format. The old functions made
+  this assumption whenever bit_offset was non-zero (see
+  nvmem_shift_read_buffer_in_place()) but didn't whenever the
+  bit_offset was zero.
+
+NOTE: it's assumed that we don't need an 8-bit or 16-bit version of
+this function. The 32-bit version of the function can be used to read
+8-bit or 16-bit data.
+
+At the moment, I'm only adding the "unsigned" versions of these
+functions, but if it ends up being useful someone could add a "signed"
+version that did 2's complement sign extension.
+
+At the moment, I'm only adding the "little endian" versions of these
+functions. Adding the "big endian" version would require adding "big
+endian" support to nvmem_shift_read_buffer_in_place().
+
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210330111241.19401-7-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Change-Id: I3e1d96ec1680812d5e24681c79852c9b36899559
+---
+ drivers/nvmem/core.c           | 161 +++++++++++++++++++++++++++------
+ include/linux/nvmem-consumer.h |  15 +++
+ 2 files changed, 150 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
+index c0f4324d8f7c..e26b25b5c288 100644
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -1102,16 +1102,8 @@ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len)
+ }
+ EXPORT_SYMBOL_GPL(nvmem_cell_write);
+ 
+-/**
+- * nvmem_cell_read_u16() - Read a cell value as an u16
+- *
+- * @dev: Device that requests the nvmem cell.
+- * @cell_id: Name of nvmem cell to read.
+- * @val: pointer to output value.
+- *
+- * Return: 0 on success or negative errno.
+- */
+-int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val)
++static int nvmem_cell_read_common(struct device *dev, const char *cell_id,
++				  void *val, size_t count)
+ {
+ 	struct nvmem_cell *cell;
+ 	void *buf;
+@@ -1126,21 +1118,50 @@ int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val)
+ 		nvmem_cell_put(cell);
+ 		return PTR_ERR(buf);
+ 	}
+-	if (len != sizeof(*val)) {
++	if (len != count) {
+ 		kfree(buf);
+ 		nvmem_cell_put(cell);
+ 		return -EINVAL;
+ 	}
+-	memcpy(val, buf, sizeof(*val));
++	memcpy(val, buf, count);
+ 	kfree(buf);
+ 	nvmem_cell_put(cell);
+ 
+ 	return 0;
+ }
++
++/**
++ * nvmem_cell_read_u8() - Read a cell value as a u8
++ *
++ * @dev: Device that requests the nvmem cell.
++ * @cell_id: Name of nvmem cell to read.
++ * @val: pointer to output value.
++ *
++ * Return: 0 on success or negative errno.
++ */
++int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val)
++{
++	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
++}
++EXPORT_SYMBOL_GPL(nvmem_cell_read_u8);
++
++/**
++ * nvmem_cell_read_u16() - Read a cell value as a u16
++ *
++ * @dev: Device that requests the nvmem cell.
++ * @cell_id: Name of nvmem cell to read.
++ * @val: pointer to output value.
++ *
++ * Return: 0 on success or negative errno.
++ */
++int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val)
++{
++	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
++}
+ EXPORT_SYMBOL_GPL(nvmem_cell_read_u16);
+ 
+ /**
+- * nvmem_cell_read_u32() - Read a cell value as an u32
++ * nvmem_cell_read_u32() - Read a cell value as a u32
+  *
+  * @dev: Device that requests the nvmem cell.
+  * @cell_id: Name of nvmem cell to read.
+@@ -1149,32 +1170,120 @@ EXPORT_SYMBOL_GPL(nvmem_cell_read_u16);
+  * Return: 0 on success or negative errno.
+  */
+ int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val)
++{
++	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
++}
++EXPORT_SYMBOL_GPL(nvmem_cell_read_u32);
++
++/**
++ * nvmem_cell_read_u64() - Read a cell value as a u64
++ *
++ * @dev: Device that requests the nvmem cell.
++ * @cell_id: Name of nvmem cell to read.
++ * @val: pointer to output value.
++ *
++ * Return: 0 on success or negative errno.
++ */
++int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val)
++{
++	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
++}
++EXPORT_SYMBOL_GPL(nvmem_cell_read_u64);
++
++static const void *nvmem_cell_read_variable_common(struct device *dev,
++						   const char *cell_id,
++						   size_t max_len, size_t *len)
+ {
+ 	struct nvmem_cell *cell;
++	int nbits;
+ 	void *buf;
+-	size_t len;
+ 
+ 	cell = nvmem_cell_get(dev, cell_id);
+ 	if (IS_ERR(cell))
+-		return PTR_ERR(cell);
++		return cell;
+ 
+-	buf = nvmem_cell_read(cell, &len);
+-	if (IS_ERR(buf)) {
+-		nvmem_cell_put(cell);
+-		return PTR_ERR(buf);
+-	}
+-	if (len != sizeof(*val)) {
++	nbits = cell->nbits;
++	buf = nvmem_cell_read(cell, len);
++	nvmem_cell_put(cell);
++	if (IS_ERR(buf))
++		return buf;
++
++	/*
++	 * If nbits is set then nvmem_cell_read() can significantly exaggerate
++	 * the length of the real data. Throw away the extra junk.
++	 */
++	if (nbits)
++		*len = DIV_ROUND_UP(nbits, 8);
++
++	if (*len > max_len) {
+ 		kfree(buf);
+-		nvmem_cell_put(cell);
+-		return -EINVAL;
++		return ERR_PTR(-ERANGE);
+ 	}
+-	memcpy(val, buf, sizeof(*val));
++
++	return buf;
++}
++
++/**
++ * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number.
++ *
++ * @dev: Device that requests the nvmem cell.
++ * @cell_id: Name of nvmem cell to read.
++ * @val: pointer to output value.
++ *
++ * Return: 0 on success or negative errno.
++ */
++int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id,
++				    u32 *val)
++{
++	size_t len;
++	const u8 *buf;
++	int i;
++
++	buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
++	if (IS_ERR(buf))
++		return PTR_ERR(buf);
++
++	/* Copy w/ implicit endian conversion */
++	*val = 0;
++	for (i = 0; i < len; i++)
++		*val |= buf[i] << (8 * i);
+ 
+ 	kfree(buf);
+-	nvmem_cell_put(cell);
++
+ 	return 0;
+ }
+-EXPORT_SYMBOL_GPL(nvmem_cell_read_u32);
++EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32);
++
++/**
++ * nvmem_cell_read_variable_le_u64() - Read up to 64-bits of data as a little endian number.
++ *
++ * @dev: Device that requests the nvmem cell.
++ * @cell_id: Name of nvmem cell to read.
++ * @val: pointer to output value.
++ *
++ * Return: 0 on success or negative errno.
++ */
++int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id,
++				    u64 *val)
++{
++	size_t len;
++	const u8 *buf;
++	int i;
++
++	buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
++	if (IS_ERR(buf))
++		return PTR_ERR(buf);
++
++	/* Copy w/ implicit endian conversion */
++	*val = 0;
++	for (i = 0; i < len; i++)
++		*val |= (uint64_t)buf[i] << (8 * i);
++
++	kfree(buf);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u64);
+ 
+ /**
+  * nvmem_device_cell_read() - Read a given nvmem device and cell
+diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
+index 5c17cb733224..e328c0f7eef3 100644
+--- a/include/linux/nvmem-consumer.h
++++ b/include/linux/nvmem-consumer.h
+@@ -63,6 +63,10 @@ void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len);
+ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len);
+ int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val);
+ int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val);
++int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id,
++				    u32 *val);
++int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id,
++				    u64 *val);
+ 
+ /* direct nvmem device read/write interface */
+ struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
+@@ -134,6 +138,17 @@ static inline int nvmem_cell_read_u32(struct device *dev,
+ {
+ 	return -EOPNOTSUPP;
+ }
++static inline int nvmem_cell_read_variable_le_u32(struct device *dev,
++						const char *cell_id, u32 *val)
++{
++	return -ENOSYS;
++}
++
++static inline int nvmem_cell_read_variable_le_u64(struct device *dev,
++						const char *cell_id, u64 *val);
++{
++	return -ENOSYS;
++}
+ 
+ static inline struct nvmem_device *nvmem_device_get(struct device *dev,
+ 						    const char *name)
+-- 
+2.18.0
+
diff --git a/target/linux/mediatek/patches-5.4/8005-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch b/target/linux/mediatek/patches-5.4/8005-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch
new file mode 100644
index 0000000..8de4c2a
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/8005-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch
@@ -0,0 +1,51 @@
+From 44ae4ed142265a6d50a9d3e6f4c395f97b6849ab Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Sat, 6 Nov 2021 20:06:30 +0800
+Subject: [PATCH 2/5] nvmem: mtk-efuse: support minimum one byte access stride
+ and granularity
+
+In order to support nvmem bits property, should support minimum 1 byte
+read stride and minimum 1 byte read granularity at the same time.
+
+Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Change-Id: Iafe1ebf195d58a3e9e3518913f795d14a01dfd3b
+---
+ drivers/nvmem/mtk-efuse.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c
+index 856d9c3fc38e..2e728fed0b49 100644
+--- a/drivers/nvmem/mtk-efuse.c
++++ b/drivers/nvmem/mtk-efuse.c
+@@ -19,11 +19,12 @@ static int mtk_reg_read(void *context,
+ 			unsigned int reg, void *_val, size_t bytes)
+ {
+ 	struct mtk_efuse_priv *priv = context;
+-	u32 *val = _val;
+-	int i = 0, words = bytes / 4;
++	void __iomem *addr = priv->base + reg;
++	u8 *val = _val;
++	int i;
+ 
+-	while (words--)
+-		*val++ = readl(priv->base + reg + (i++ * 4));
++	for (i = 0; i < bytes; i++, val++)
++		*val = readb(addr + i);
+ 
+ 	return 0;
+ }
+@@ -58,8 +59,8 @@ static int mtk_efuse_probe(struct platform_device *pdev)
+ 	if (IS_ERR(priv->base))
+ 		return PTR_ERR(priv->base);
+ 
+-	econfig.stride = 4;
+-	econfig.word_size = 4;
++	econfig.stride = 1;
++	econfig.word_size = 1;
+ 	econfig.reg_read = mtk_reg_read;
+ 	econfig.reg_write = mtk_reg_write;
+ 	econfig.size = resource_size(res);
+-- 
+2.18.0
+
diff --git a/target/linux/mediatek/patches-5.4/8006-phy-phy-mtk-tphy-add-support-efuse-setting.patch b/target/linux/mediatek/patches-5.4/8006-phy-phy-mtk-tphy-add-support-efuse-setting.patch
new file mode 100644
index 0000000..5cc8a65
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/8006-phy-phy-mtk-tphy-add-support-efuse-setting.patch
@@ -0,0 +1,312 @@
+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
+
diff --git a/target/linux/mediatek/patches-5.4/8007-phy-phy-mtk-tphy-Add-PCIe-2-lane-efuse-support.patch b/target/linux/mediatek/patches-5.4/8007-phy-phy-mtk-tphy-Add-PCIe-2-lane-efuse-support.patch
new file mode 100644
index 0000000..b710695
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/8007-phy-phy-mtk-tphy-Add-PCIe-2-lane-efuse-support.patch
@@ -0,0 +1,229 @@
+From 41ffe32e7ec23f592e21c508b5108899ad393059 Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Tue, 25 Jan 2022 16:50:47 +0800
+Subject: [PATCH 4/5] phy: phy-mtk-tphy: Add PCIe 2 lane efuse support
+
+Add PCIe 2 lane efuse support in tphy driver.
+
+Signed-off-by: Jie Yang <jieyy.yang@mediatek.com>
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+---
+ drivers/phy/mediatek/phy-mtk-tphy.c | 140 ++++++++++++++++++++++++++++
+ 1 file changed, 140 insertions(+)
+
+diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c
+index 05a1ad4..59d6ac3 100644
+--- a/drivers/phy/mediatek/phy-mtk-tphy.c
++++ b/drivers/phy/mediatek/phy-mtk-tphy.c
+@@ -39,6 +39,15 @@
+ #define SSUSB_SIFSLV_V2_U3PHYD		0x200
+ #define SSUSB_SIFSLV_V2_U3PHYA		0x400
+ 
++/* version V4 sub-banks offset base address */
++/* pcie phy banks */
++#define SSUSB_SIFSLV_V4_SPLLC		0x000
++#define SSUSB_SIFSLV_V4_CHIP		0x100
++#define SSUSB_SIFSLV_V4_U3PHYD		0x900
++#define SSUSB_SIFSLV_V4_U3PHYA		0xb00
++
++#define SSUSB_LN1_OFFSET		0x10000
++
+ #define U3P_MISC_REG1		0x04
+ #define MR1_EFUSE_AUTO_LOAD_DIS		BIT(6)
+ 
+@@ -294,6 +303,7 @@ enum mtk_phy_version {
+ 	MTK_PHY_V1 = 1,
+ 	MTK_PHY_V2,
+ 	MTK_PHY_V3,
++	MTK_PHY_V4,
+ };
+ 
+ struct mtk_phy_pdata {
+@@ -338,6 +348,9 @@ struct mtk_phy_instance {
+ 	u32 efuse_intr;
+ 	u32 efuse_tx_imp;
+ 	u32 efuse_rx_imp;
++	u32 efuse_intr_ln1;
++	u32 efuse_tx_imp_ln1;
++	u32 efuse_rx_imp_ln1;
+ 	u32 index;
+ 	u8 type;
+ 	int eye_src;
+@@ -878,6 +891,36 @@ static void phy_v2_banks_init(struct mtk_tphy *tphy,
+ 	}
+ }
+ 
++static void phy_v4_banks_init(struct mtk_tphy *tphy,
++			      struct mtk_phy_instance *instance)
++{
++	struct u2phy_banks *u2_banks = &instance->u2_banks;
++	struct u3phy_banks *u3_banks = &instance->u3_banks;
++
++	switch (instance->type) {
++	case PHY_TYPE_USB2:
++		u2_banks->misc = instance->port_base + SSUSB_SIFSLV_V2_MISC;
++		u2_banks->fmreg = instance->port_base + SSUSB_SIFSLV_V2_U2FREQ;
++		u2_banks->com = instance->port_base + SSUSB_SIFSLV_V2_U2PHY_COM;
++		break;
++	case PHY_TYPE_USB3:
++		u3_banks->spllc = instance->port_base + SSUSB_SIFSLV_V2_SPLLC;
++		u3_banks->chip = instance->port_base + SSUSB_SIFSLV_V2_CHIP;
++		u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V2_U3PHYD;
++		u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V2_U3PHYA;
++		break;
++	case PHY_TYPE_PCIE:
++		u3_banks->spllc = instance->port_base + SSUSB_SIFSLV_V4_SPLLC;
++		u3_banks->chip = instance->port_base + SSUSB_SIFSLV_V4_CHIP;
++		u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V4_U3PHYD;
++		u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V4_U3PHYA;
++		break;
++	default:
++		dev_err(tphy->dev, "incompatible PHY type\n");
++		return;
++	}
++}
++
+ static void phy_parse_property(struct mtk_tphy *tphy,
+ 				struct mtk_phy_instance *instance)
+ {
+@@ -1002,6 +1045,40 @@ static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instanc
+ 		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);
++
++		if (tphy->pdata->version != MTK_PHY_V4)
++			break;
++
++		ret = nvmem_cell_read_variable_le_u32(dev, "intr_ln1", &instance->efuse_intr_ln1);
++		if (ret) {
++			dev_err(dev, "fail to get u3 lane1 intr efuse, %d\n", ret);
++			break;
++		}
++
++		ret = nvmem_cell_read_variable_le_u32(dev, "rx_imp_ln1", &instance->efuse_rx_imp_ln1);
++		if (ret) {
++			dev_err(dev, "fail to get u3 lane1 rx_imp efuse, %d\n", ret);
++			break;
++		}
++
++		ret = nvmem_cell_read_variable_le_u32(dev, "tx_imp_ln1", &instance->efuse_tx_imp_ln1);
++		if (ret) {
++			dev_err(dev, "fail to get u3 lane1 tx_imp efuse, %d\n", ret);
++			break;
++		}
++
++		/* no efuse, ignore it */
++		if (!instance->efuse_intr_ln1 &&
++		    !instance->efuse_rx_imp_ln1 &&
++		    !instance->efuse_tx_imp_ln1) {
++			dev_warn(dev, "no u3 lane1 efuse, but dts enable it\n");
++			instance->efuse_sw_en = 0;
++			break;
++		}
++
++		dev_info(dev, "u3 lane1 efuse - intr %x, rx_imp %x, tx_imp %x\n",
++			 instance->efuse_intr_ln1, instance->efuse_rx_imp_ln1,
++			 instance->efuse_tx_imp_ln1);
+ 		break;
+ 	default:
+ 		dev_err(dev, "no sw efuse for type %d\n", instance->type);
+@@ -1035,6 +1112,31 @@ static void phy_efuse_set(struct mtk_phy_instance *instance)
+ 
+ 		break;
+ 	case PHY_TYPE_USB3:
++		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;
+ 	case PHY_TYPE_PCIE:
+ 		tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RSV);
+ 		tmp |= P3D_RG_EFUSE_AUTO_LOAD_DIS;
+@@ -1059,6 +1161,35 @@ static void phy_efuse_set(struct mtk_phy_instance *instance)
+ 		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);
++
++		if (!instance->efuse_intr_ln1 &&
++		    !instance->efuse_rx_imp_ln1 &&
++		    !instance->efuse_tx_imp_ln1)
++			break;
++
++		tmp = readl(u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_RSV);
++		tmp |= P3D_RG_EFUSE_AUTO_LOAD_DIS;
++		writel(tmp, u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_RSV);
++
++		tmp = readl(u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_IMPCAL0);
++		tmp &= ~P3D_RG_TX_IMPEL;
++		tmp |= P3D_RG_TX_IMPEL_VAL(instance->efuse_tx_imp_ln1);
++		tmp |= P3D_RG_FORCE_TX_IMPEL;
++		writel(tmp, u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_IMPCAL0);
++
++		tmp = readl(u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_IMPCAL1);
++		tmp &= ~P3D_RG_RX_IMPEL;
++		tmp |= P3D_RG_RX_IMPEL_VAL(instance->efuse_rx_imp_ln1);
++		tmp |= P3D_RG_FORCE_RX_IMPEL;
++		writel(tmp, u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_IMPCAL1);
++
++		tmp = readl(u3_banks->phya + SSUSB_LN1_OFFSET + U3P_U3_PHYA_REG0);
++		tmp &= ~P3A_RG_IEXT_INTR;
++		tmp |= P3A_RG_IEXT_INTR_VAL(instance->efuse_intr_ln1);
++		writel(tmp, u3_banks->phya + SSUSB_LN1_OFFSET + U3P_U3_PHYA_REG0);
++		pr_err("%s set LN1 efuse, tx_imp %x, rx_imp %x intr %x\n",
++			__func__, instance->efuse_tx_imp_ln1,
++			instance->efuse_rx_imp_ln1, instance->efuse_intr_ln1);
+ 		break;
+ 	default:
+ 		dev_warn(dev, "no sw efuse for type %d\n", instance->type);
+@@ -1197,6 +1328,8 @@ static struct phy *mtk_phy_xlate(struct device *dev,
+ 		phy_v1_banks_init(tphy, instance);
+ 	} else if (tphy->pdata->version == MTK_PHY_V2) {
+ 		phy_v2_banks_init(tphy, instance);
++	} else if (tphy->pdata->version == MTK_PHY_V4) {
++		phy_v4_banks_init(tphy, instance);
+ 	} else {
+ 		dev_err(dev, "phy version is not supported\n");
+ 		return ERR_PTR(-EINVAL);
+@@ -1247,12 +1380,19 @@ static const struct mtk_phy_pdata mt8195_pdata = {
+ 	.version = MTK_PHY_V3,
+ };
+ 
++static const struct mtk_phy_pdata tphy_v4_pdata = {
++	.avoid_rx_sen_degradation = false,
++	.sw_efuse_supported = true,
++	.version = MTK_PHY_V4,
++};
++
+ 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 },
+ 	{ .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata },
+ 	{ .compatible = "mediatek,generic-tphy-v1", .data = &tphy_v1_pdata },
+ 	{ .compatible = "mediatek,generic-tphy-v2", .data = &tphy_v2_pdata },
++	{ .compatible = "mediatek,generic-tphy-v4", .data = &tphy_v4_pdata },
+ 	{ },
+ };
+ MODULE_DEVICE_TABLE(of, mtk_tphy_id_table);
+-- 
+2.18.0
+
diff --git a/target/linux/mediatek/patches-5.4/8008-phy-phy-mtk-tphy-add-auto-load-valid-check-mechanism.patch b/target/linux/mediatek/patches-5.4/8008-phy-phy-mtk-tphy-add-auto-load-valid-check-mechanism.patch
new file mode 100644
index 0000000..1223fb6
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/8008-phy-phy-mtk-tphy-add-auto-load-valid-check-mechanism.patch
@@ -0,0 +1,153 @@
+From 1d5819e90f2ef6dead11809744372a9863227a92 Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Tue, 25 Jan 2022 19:03:34 +0800
+Subject: [PATCH 5/5] phy: phy-mtk-tphy: add auto-load-valid check mechanism
+ support
+
+add auto-load-valid check mechanism support
+
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+---
+ drivers/phy/mediatek/phy-mtk-tphy.c | 67 +++++++++++++++++++++++++++--
+ 1 file changed, 64 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c
+index 59d6ac3..4adc505 100644
+--- a/drivers/phy/mediatek/phy-mtk-tphy.c
++++ b/drivers/phy/mediatek/phy-mtk-tphy.c
+@@ -345,9 +345,13 @@ struct mtk_phy_instance {
+ 	};
+ 	struct clk *ref_clk;	/* reference clock of anolog phy */
+ 	u32 efuse_sw_en;
++	bool efuse_alv_en;
++	u32 efuse_autoloadvalid;
+ 	u32 efuse_intr;
+ 	u32 efuse_tx_imp;
+ 	u32 efuse_rx_imp;
++	bool efuse_alv_ln1_en;
++	u32 efuse_ln1_autoloadvalid;
+ 	u32 efuse_intr_ln1;
+ 	u32 efuse_tx_imp_ln1;
+ 	u32 efuse_rx_imp_ln1;
+@@ -980,6 +984,7 @@ static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instanc
+ {
+ 	struct device *dev = &instance->phy->dev;
+ 	int ret = 0;
++	bool alv = false;
+ 
+ 	dev_err(dev, "try to get sw efuse\n");
+ 
+@@ -998,6 +1003,20 @@ static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instanc
+ 
+ 	switch (instance->type) {
+ 	case PHY_TYPE_USB2:
++		alv = of_property_read_bool(dev->of_node, "auto_load_valid");
++		if (alv) {
++			instance->efuse_alv_en = alv;
++			ret = nvmem_cell_read_variable_le_u32(dev, "auto_load_valid",
++							&instance->efuse_autoloadvalid);
++			if (ret) {
++				dev_err(dev, "fail to get u2 alv efuse, %d\n", ret);
++				break;
++			}
++			dev_info(dev,
++				"u2 auto load valid efuse: ENABLE with value: %u\n",
++				instance->efuse_autoloadvalid);
++		}
++
+ 		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);
+@@ -1015,6 +1034,20 @@ static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instanc
+ 		break;
+ 	case PHY_TYPE_USB3:
+ 	case PHY_TYPE_PCIE:
++		alv = of_property_read_bool(dev->of_node, "auto_load_valid");
++		if (alv) {
++			instance->efuse_alv_en = alv;
++			ret = nvmem_cell_read_variable_le_u32(dev, "auto_load_valid",
++							&instance->efuse_autoloadvalid);
++			if (ret) {
++				dev_err(dev, "fail to get u3(pcei) alv efuse, %d\n", ret);
++				break;
++			}
++			dev_info(dev,
++				"u3 auto load valid efuse: ENABLE with value: %u\n",
++				instance->efuse_autoloadvalid);
++		}
++
+ 		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);
+@@ -1049,6 +1082,20 @@ static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instanc
+ 		if (tphy->pdata->version != MTK_PHY_V4)
+ 			break;
+ 
++		alv = of_property_read_bool(dev->of_node, "auto_load_valid_ln1");
++		if (alv) {
++			instance->efuse_alv_ln1_en = alv;
++			ret = nvmem_cell_read_variable_le_u32(dev, "auto_load_valid_ln1",
++							&instance->efuse_ln1_autoloadvalid);
++			if (ret) {
++				dev_err(dev, "fail to get pcie auto_load_valid efuse, %d\n", ret);
++				break;
++			}
++			dev_info(dev,
++				"pcie auto load valid efuse: ENABLE with value: %u\n",
++				instance->efuse_ln1_autoloadvalid);
++		}
++
+ 		ret = nvmem_cell_read_variable_le_u32(dev, "intr_ln1", &instance->efuse_intr_ln1);
+ 		if (ret) {
+ 			dev_err(dev, "fail to get u3 lane1 intr efuse, %d\n", ret);
+@@ -1100,6 +1147,10 @@ static void phy_efuse_set(struct mtk_phy_instance *instance)
+ 
+ 	switch (instance->type) {
+ 	case PHY_TYPE_USB2:
++		if (instance->efuse_alv_en &&
++		    instance->efuse_autoloadvalid == 1)
++			break;
++
+ 		tmp = readl(u2_banks->misc + U3P_MISC_REG1);
+ 		tmp |= MR1_EFUSE_AUTO_LOAD_DIS;
+ 		writel(tmp, u2_banks->misc + U3P_MISC_REG1);
+@@ -1112,6 +1163,10 @@ static void phy_efuse_set(struct mtk_phy_instance *instance)
+ 
+ 		break;
+ 	case PHY_TYPE_USB3:
++		if (instance->efuse_alv_en &&
++		    instance->efuse_autoloadvalid == 1)
++			break;
++
+ 		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);
+@@ -1138,6 +1193,10 @@ static void phy_efuse_set(struct mtk_phy_instance *instance)
+ 
+ 		break;
+ 	case PHY_TYPE_PCIE:
++		if (instance->efuse_alv_en &&
++		    instance->efuse_autoloadvalid == 1)
++			break;
++
+ 		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);
+@@ -1162,9 +1221,11 @@ static void phy_efuse_set(struct mtk_phy_instance *instance)
+ 			__func__, instance->efuse_tx_imp,
+ 			instance->efuse_rx_imp, instance->efuse_intr);
+ 
+-		if (!instance->efuse_intr_ln1 &&
+-		    !instance->efuse_rx_imp_ln1 &&
+-		    !instance->efuse_tx_imp_ln1)
++		if ((!instance->efuse_intr_ln1 &&
++		     !instance->efuse_rx_imp_ln1 &&
++		     !instance->efuse_tx_imp_ln1) ||
++		    (instance->efuse_alv_ln1_en &&
++		     instance->efuse_ln1_autoloadvalid == 1))
+ 			break;
+ 
+ 		tmp = readl(u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_RSV);
+-- 
+2.18.0
+