Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a11489df authored by Mayank Rana's avatar Mayank Rana Committed by Matt Wagantall
Browse files

usb: phy: qusb: Add support to read TUNE2 using EFUSE register



QUSB_PHY_TUNE2 parameter's high nibble value may vary across
different devices. It needs to be read through EFUSE based
register. This change adds support which reads EFUSE based register,
and calculate TUNE2 parameter's high nibble value. It also requires
number of bits to use and starting position of bit with EFUSE
register to calculate this value. In case, EFUSE register based
value is zero, it uses 0xB as default high nibble value with low
nibble value (0x3 which always default value).

CRs-Fixed: 705188
Change-Id: I1a530e34342ea3a897e7f6cb80957af9c1fe3bf5
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent 7197f1f1
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -149,6 +149,8 @@ Required properties:

Optional properties:
 - reg: Address and length register set to control QUSB2 PHY
   "qscratch_base" : QSCRATCH base register set.
   "tune2_efuse_addr": EFUSE based register address to read TUNE2 parameter.
   via the QSCRATCH interface.
 - reg-names: Should be "qscratch_base". The qscratch register bank
   allows us to manipulate QUSB PHY bits eg. to enable D+ pull-up using s/w
@@ -158,6 +160,8 @@ Optional properties:
   are passed in as 4 bytes packed into a single 32-bit value. The parameters control
   On-chip Rout Term, TX Output Level, RX Sensitivity and TX Pre-emphasis respectively.
 - qcom,qusb-phy-init-seq: QUSB PHY initialization sequence with value,reg pair.
 - qcom,tune2-efuse-bit-pos: TUNE2 parameter related start bit position with EFUSE register
 - qcom,tune2-efuse-num-bits: Number of bits based value to use for TUNE2 high nibble

Example:
	qusb_phy: qusb@f9b39000 {
@@ -170,6 +174,8 @@ Example:
		vdda18-supply = <&pm8994_l6>;
		vdda33-supply = <&pm8994_l24>;
		qcom,vdd-voltage-level = <1 5 7>;
		qcom,tune2-efuse-bit-pos = <21>;
		qcom,tune2-efuse-num-bits = <3>;

		clocks = <&clock_rpm clk_ln_bb_clk>,
			 <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>,
+85 −0
Original line number Diff line number Diff line
@@ -35,6 +35,13 @@
#define QUSB2PHY_PORT_TUNE3             0x88
#define QUSB2PHY_PORT_TUNE4             0x8C

/* In case Efuse register shows zero, use this value */
#define TUNE2_DEFAULT_HIGH_NIBBLE	0xB
#define TUNE2_DEFAULT_LOW_NIBBLE	0x3

/* Get TUNE2's high nibble value read from efuse */
#define TUNE2_HIGH_NIBBLE_VAL(val, pos, mask)	((val >> pos) & mask)

#define QUSB2PHY_PORT_INTR_CTRL         0xBC
#define CHG_DET_INTR_EN                 BIT(4)
#define DMSE_INTR_HIGH_SEL              BIT(3)
@@ -63,6 +70,7 @@ struct qusb_phy {
	struct usb_phy		phy;
	void __iomem		*base;
	void __iomem		*qscratch_base;
	void __iomem		*tune2_efuse_reg;

	struct clk		*ref_clk;
	struct clk		*cfg_ahb_clk;
@@ -76,6 +84,10 @@ struct qusb_phy {
	int			init_seq_len;
	int			*qusb_phy_init_seq;

	u32			tune2_val;
	int			tune2_efuse_bit_pos;
	int			tune2_efuse_num_of_bits;

	bool			power_enabled;
	bool			clocks_enabled;
	bool			cable_connected;
@@ -232,6 +244,42 @@ err_vdd:
	return ret;
}

static void qusb_phy_get_tune2_param(struct qusb_phy *qphy)
{
	u8 num_of_bits;
	u32 bit_mask = 1;

	pr_debug("%s(): num_of_bits:%d bit_pos:%d\n", __func__,
				qphy->tune2_efuse_num_of_bits,
				qphy->tune2_efuse_bit_pos);

	/* get bit mask based on number of bits to use with efuse reg */
	if (qphy->tune2_efuse_num_of_bits) {
		num_of_bits = qphy->tune2_efuse_num_of_bits;
		bit_mask = (bit_mask << num_of_bits) - 1;
	}

	/*
	 * Read EFUSE register having TUNE2 parameter's high nibble.
	 * If efuse register shows value as 0x0, then use default value
	 * as 0xB as high nibble. Otherwise use efuse register based
	 * value for this purpose.
	 */
	qphy->tune2_val = readl_relaxed(qphy->tune2_efuse_reg);
	pr_debug("%s(): bit_mask:%d efuse based tune2 value:%d\n",
				__func__, bit_mask, qphy->tune2_val);

	qphy->tune2_val = TUNE2_HIGH_NIBBLE_VAL(qphy->tune2_val,
				qphy->tune2_efuse_bit_pos, bit_mask);

	if (!qphy->tune2_val)
		qphy->tune2_val = TUNE2_DEFAULT_HIGH_NIBBLE;

	/* Get TUNE2 byte value using high and low nibble value */
	qphy->tune2_val = ((qphy->tune2_val << 0x4) |
					TUNE2_DEFAULT_LOW_NIBBLE);
}

static int qusb_phy_init(struct usb_phy *phy)
{
	struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
@@ -283,6 +331,20 @@ static int qusb_phy_init(struct usb_phy *phy)
		}
	}

	/*
	 * Check for EFUSE value only if tune2_efuse_reg is available
	 * and try to read EFUSE value only once i.e. not every USB
	 * cable connect case.
	 */
	if (qphy->tune2_efuse_reg) {
		if (!qphy->tune2_val)
			qusb_phy_get_tune2_param(qphy);

		pr_debug("%s(): Programming TUNE2 parameter as:%x\n",
					__func__, qphy->tune2_val);
		writel_relaxed(qphy->tune2_val,
				qphy->base + QUSB2PHY_PORT_TUNE2);
	}
	/* ensure above writes are completed before re-enabling PHY */
	wmb();

@@ -483,6 +545,29 @@ static int qusb_phy_probe(struct platform_device *pdev)
	if (IS_ERR(qphy->qscratch_base))
		qphy->qscratch_base = NULL;

	qphy->tune2_efuse_reg = NULL;
	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
							"tune2_efuse_addr");
	if (res) {
		qphy->tune2_efuse_reg = devm_ioremap_nocache(dev, res->start,
							resource_size(res));
		if (!IS_ERR_OR_NULL(qphy->tune2_efuse_reg)) {
			ret = of_property_read_u32(dev->of_node,
					"qcom,tune2-efuse-bit-pos",
					&qphy->tune2_efuse_bit_pos);
			if (!ret) {
				ret = of_property_read_u32(dev->of_node,
						"qcom,tune2-efuse-num-bits",
						&qphy->tune2_efuse_num_of_bits);
			}

			if (ret) {
				dev_err(dev, "DT Value for tune2 efuse is invalid.\n");
				return -EINVAL;
			}
		}
	}

	qphy->ref_clk = devm_clk_get(dev, "ref_clk");
	if (IS_ERR(qphy->ref_clk))
		return PTR_ERR(qphy->ref_clk);