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

Unverified Commit 5e5bcb1d authored by derfelot's avatar derfelot
Browse files

usb: phy: Add Sony modifications to USB physical layer

Taken from Sony 47.2.A.10.107 stock kernel
parent bfd25ca9
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -13,6 +13,11 @@
 * GNU General Public License for more details.
 *
 */
/*
 * NOTE: This file has been modified by Sony Mobile Communications Inc.
 * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc,
 * and licensed under the license of the file.
 */

#include <linux/ctype.h>
#include <linux/device.h>
@@ -413,7 +418,7 @@ static umode_t dual_role_attr_is_visible(struct kobject *kobj,
			if (dual_role->desc->property_is_writeable &&
			    dual_role_property_is_writeable(dual_role, property)
			    > 0)
				mode |= S_IWUSR;
				mode |= S_IWUSR | S_IWGRP;

			return mode;
		}
+180 −11
Original line number Diff line number Diff line
@@ -10,6 +10,11 @@
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
/*
 * NOTE: This file has been modified by Sony Mobile Communications Inc.
 * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc,
 * and licensed under the license of the file.
 */

#include <linux/module.h>
#include <linux/kernel.h>
@@ -51,6 +56,9 @@

#define QUSB2PHY_PORT_TUNE1		0x23c
#define QUSB2PHY_TEST1			0x24C
#define QUSB2PHY_PORT_TUNE2		0x240
#define QUSB2PHY_PORT_TUNE3		0x244
#define QUSB2PHY_PORT_TUNE4		0x248

#define QUSB2PHY_1P2_VOL_MIN           1200000 /* uV */
#define QUSB2PHY_1P2_VOL_MAX           1200000 /* uV */
@@ -70,9 +78,39 @@
#define QUSB2PHY_PLL_ANALOG_CONTROLS_ONE	0x0
#define QUSB2PHY_PLL_ANALOG_CONTROLS_TWO	0x4

#define USB_PHY_HSTX_TRIM		0xF0	/* TUNE1 7:4 */
#define USB_PHY_HSTX_SR			0x0C	/* TUNE1 3:2 */
#define USB_PHY_HSTX_SR_BIAS		0x03	/* TUNE1 1:0 */
#define USB_PHY_SEL_EMPH_HALF_WIDTH	0x10	/* TUNE2   4 */
#define USB_PHY_EN_EMPHASIS		0x0C	/* TUNE2 3:2 */
#define USB_PHY_HS_DISCON_TRIM		0x03	/* TUNE2 1:0 */
#define USB_PHY_CDR_WIDE		0x80	/* TUNE3   7 */
#define USB_PHY_CDR_PULSE_SMPL		0x40	/* TUNE3   6 */
#define USB_PHY_TX2RX_DLY		0x3F	/* TUNE3 5:0 */
#define USB_PHY_HANDOFF_PHSEL		0xE0	/* TUNE4 7:5 */
#define USB_PHY_FORCE_HSRX_ALWAYS_ON	0x10	/* TUNE4   4 */
#define USB_PHY_SQ_FILTER_DIS		0x08	/* TUNE4   3 */
#define USB_PHY_SQ_LEVEL		0x07	/* TUNE4 2:0 */

unsigned int phy_tune1;
unsigned int phy_tune2;
unsigned int phy_tune3;
unsigned int phy_tune4;
unsigned int phy_host_tune1;
unsigned int phy_host_tune2;
module_param(phy_tune1, uint, S_IRUGO | S_IWUSR);
module_param(phy_tune2, uint, S_IRUGO | S_IWUSR);
module_param(phy_tune3, uint, S_IRUGO | S_IWUSR);
module_param(phy_tune4, uint, S_IRUGO | S_IWUSR);
module_param(phy_host_tune1, uint, S_IRUGO | S_IWUSR);
module_param(phy_host_tune2, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(phy_tune1, "QUSB PHY v2 TUNE1");
MODULE_PARM_DESC(phy_tune2, "QUSB PHY v2 TUNE2");
MODULE_PARM_DESC(phy_tune3, "QUSB PHY v2 TUNE3");
MODULE_PARM_DESC(phy_tune4, "QUSB PHY v2 TUNE4");
MODULE_PARM_DESC(phy_host_tune1, "QUSB PHY HOST v2 TUNE1");
MODULE_PARM_DESC(phy_host_tune2, "QUSB PHY HOST v2 TUNE2");


struct qusb_phy {
	struct usb_phy		phy;
@@ -98,8 +136,10 @@ struct qusb_phy {
	int			*qusb_phy_host_init_seq;

	u32			tune_val;
	u32			host_tune_val;
	int			efuse_bit_pos;
	int			efuse_num_of_bits;
	u32			efuse_offset;

	int			power_enabled_ref;
	bool			clocks_enabled;
@@ -380,14 +420,16 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value)
	return ret;
}

static void qusb_phy_get_tune1_param(struct qusb_phy *qphy)
static u32 qusb_phy_get_tune1_param(struct qusb_phy *qphy)
{
	u8 reg;
	u32 bit_mask = 1;
	u32 tune_val;

	pr_debug("%s(): num_of_bits:%d bit_pos:%d\n", __func__,
	pr_debug("%s(): num_of_bits:%d bit_pos:%d offset:%d\n", __func__,
				qphy->efuse_num_of_bits,
				qphy->efuse_bit_pos);
				qphy->efuse_bit_pos,
				qphy->efuse_offset);

	/* get bit mask based on number of bits to use with efuse reg */
	bit_mask = (bit_mask << qphy->efuse_num_of_bits) - 1;
@@ -396,18 +438,22 @@ static void qusb_phy_get_tune1_param(struct qusb_phy *qphy)
	 * if efuse reg is updated (i.e non-zero) then use it to program
	 * tune parameters
	 */
	qphy->tune_val = readl_relaxed(qphy->efuse_reg);
	tune_val = readl_relaxed(qphy->efuse_reg);
	pr_debug("%s(): bit_mask:%d efuse based tune1 value:%d\n",
				__func__, bit_mask, qphy->tune_val);
				__func__, bit_mask, tune_val);

	qphy->tune_val = TUNE_VAL_MASK(qphy->tune_val,
				qphy->efuse_bit_pos, bit_mask);
	tune_val = TUNE_VAL_MASK(tune_val, qphy->efuse_bit_pos, bit_mask);
	reg = readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE1);
	if (qphy->tune_val) {
	if (tune_val) {
		tune_val += qphy->efuse_offset;
		if ((s32)tune_val < 0)
			tune_val = 0x00;
		else if ((s32)tune_val > 0x0f)
			tune_val = 0x0f;
		reg = reg & 0x0f;
		reg |= (qphy->tune_val << 4);
		reg |= (tune_val << 4);
	}
	qphy->tune_val = reg;
	return reg;
}

static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt,
@@ -424,6 +470,75 @@ static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt,
	}
}

static inline u32 msm_usb_read_reg_field(void *base, u32 offset, const u32 mask)
{
	u32 shift = find_first_bit((void *)&mask, 32);
	u32 val = readb_relaxed(base + offset);
	val &= mask;		/* clear other bits */
	val >>= shift;
	return val;
}

static void msm_qphy_param_output(struct usb_phy *phy)
{
	struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);

	/* PORT_TUNE1 */
	dev_dbg(phy->dev, "PORT_TUNE1:0x%02x\n",
		readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE1));
	dev_dbg(phy->dev, "  :HSTX_TRIM     \t0x%02x\n",
		msm_usb_read_reg_field(qphy->base,
			QUSB2PHY_PORT_TUNE1, USB_PHY_HSTX_TRIM));
	dev_dbg(phy->dev, "  :HSTX_SR      \t0x%02x\n",
		msm_usb_read_reg_field(qphy->base,
			QUSB2PHY_PORT_TUNE1, USB_PHY_HSTX_SR));
	dev_dbg(phy->dev, "  :HSTX_SR_BIAS      \t0x%02x\n",
		msm_usb_read_reg_field(qphy->base,
			QUSB2PHY_PORT_TUNE1, USB_PHY_HSTX_SR_BIAS));

	/* PORT_TUNE2 */
	dev_dbg(phy->dev, "PORT_TUNE2:0x%02x\n",
		readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE2));
	dev_dbg(phy->dev, "  :SEL_EMPH_HALF_WIDTH    \t0x%02x\n",
		msm_usb_read_reg_field(qphy->base,
			QUSB2PHY_PORT_TUNE2, USB_PHY_SEL_EMPH_HALF_WIDTH));
	dev_dbg(phy->dev, "  :EN_EMPHASIS       \t0x%02x\n",
		msm_usb_read_reg_field(qphy->base,
			QUSB2PHY_PORT_TUNE2, USB_PHY_EN_EMPHASIS));
	dev_dbg(phy->dev, "  :HS_DISCON_TRIM      \t0x%02x\n",
		msm_usb_read_reg_field(qphy->base,
			QUSB2PHY_PORT_TUNE2, USB_PHY_HS_DISCON_TRIM));

	/* PORT_TUNE3 */
	dev_dbg(phy->dev, "PORT_TUNE3:0x%02x\n",
		readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE3));
	dev_dbg(phy->dev, "  :CDR_WIDE            \t0x%02x\n",
		msm_usb_read_reg_field(qphy->base,
			QUSB2PHY_PORT_TUNE3, USB_PHY_CDR_WIDE));
	dev_dbg(phy->dev, "  :CDR_PULSE_SMPL            \t0x%02x\n",
		msm_usb_read_reg_field(qphy->base,
			QUSB2PHY_PORT_TUNE3, USB_PHY_CDR_PULSE_SMPL));
	dev_dbg(phy->dev, "  :TX2RX_DLY            \t0x%02x\n",
		msm_usb_read_reg_field(qphy->base,
			QUSB2PHY_PORT_TUNE3, USB_PHY_TX2RX_DLY));

	/* PORT_TUNE4 */
	dev_dbg(phy->dev, "PORT_TUNE4:0x%02x\n",
		readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE4));
	dev_dbg(phy->dev, "  :HANDOFF_PHSEL      \t0x%02x\n",
		msm_usb_read_reg_field(qphy->base,
			QUSB2PHY_PORT_TUNE4, USB_PHY_HANDOFF_PHSEL));
	dev_dbg(phy->dev, "  :FORCE_HSRX_ALWAYS_ON    \t0x%02x\n",
		msm_usb_read_reg_field(qphy->base,
			QUSB2PHY_PORT_TUNE4, USB_PHY_FORCE_HSRX_ALWAYS_ON));
	dev_dbg(phy->dev, "  :SQ_FILTER_DIS     \t0x%02x\n",
		msm_usb_read_reg_field(qphy->base,
			QUSB2PHY_PORT_TUNE4, USB_PHY_SQ_FILTER_DIS));
	dev_dbg(phy->dev, "  :SQ_LEVEL       \t0x%02x\n",
		msm_usb_read_reg_field(qphy->base,
			QUSB2PHY_PORT_TUNE4, USB_PHY_SQ_LEVEL));
}

static void qusb_phy_host_init(struct usb_phy *phy)
{
	u8 reg;
@@ -444,6 +559,32 @@ static void qusb_phy_host_init(struct usb_phy *phy)
	qusb_phy_write_seq(qphy->base, qphy->qusb_phy_host_init_seq,
			qphy->host_init_seq_len, 0);

	if (qphy->efuse_reg) {
		if (!qphy->host_tune_val)
			qphy->host_tune_val = qusb_phy_get_tune1_param(qphy);

		pr_debug("%s(): Programming host TUNE1 parameter as:%x\n",
				__func__, qphy->host_tune_val);
		writel_relaxed(qphy->host_tune_val,
				qphy->base + QUSB2PHY_PORT_TUNE1);
	}

	/* If phy_tune1 modparam set, override tune1 value */
	if (phy_host_tune1) {
		pr_debug("%s(): (modparam) HOST_TUNE1 val:0x%02x\n",
						__func__, phy_host_tune1);
		writel_relaxed(phy_host_tune1,
				qphy->base + QUSB2PHY_PORT_TUNE1);
	}
	/* If phy_tune2 modparam set, override tune2 value */
	if (phy_host_tune2) {
		pr_debug("%s(): (modparam) HOST TUNE2 val:0x%02x\n",
						__func__, phy_host_tune2);
		writel_relaxed(phy_host_tune2,
				qphy->base + QUSB2PHY_PORT_TUNE2);
	}
	msm_qphy_param_output(phy);

	/* Ensure above write is completed before turning ON ref clk */
	wmb();

@@ -520,7 +661,7 @@ static int qusb_phy_init(struct usb_phy *phy)
				qphy->init_seq_len, 0);
	if (qphy->efuse_reg) {
		if (!qphy->tune_val)
			qusb_phy_get_tune1_param(qphy);
			qphy->tune_val = qusb_phy_get_tune1_param(qphy);

		pr_debug("%s(): Programming TUNE1 parameter as:%x\n", __func__,
				qphy->tune_val);
@@ -535,6 +676,28 @@ static int qusb_phy_init(struct usb_phy *phy)
		writel_relaxed(phy_tune1,
				qphy->base + QUSB2PHY_PORT_TUNE1);
	}
	/* If phy_tune2 modparam set, override tune2 value */
	if (phy_tune2) {
		pr_debug("%s(): (modparam) TUNE2 val:0x%02x\n",
						__func__, phy_tune2);
		writel_relaxed(phy_tune2,
				qphy->base + QUSB2PHY_PORT_TUNE2);
	}
	/* If phy_tune3 modparam set, override tune3 value */
	if (phy_tune3) {
		pr_debug("%s(): (modparam) TUNE3 val:0x%02x\n",
						__func__, phy_tune3);
		writel_relaxed(phy_tune3,
				qphy->base + QUSB2PHY_PORT_TUNE3);
	}
	/* If phy_tune4 modparam set, override tune4 value */
	if (phy_tune4) {
		pr_debug("%s(): (modparam) TUNE4 val:0x%02x\n",
						__func__, phy_tune4);
		writel_relaxed(phy_tune4,
				qphy->base + QUSB2PHY_PORT_TUNE4);
	}
	msm_qphy_param_output(phy);

	/* ensure above writes are completed before re-enabling PHY */
	wmb();
@@ -886,6 +1049,12 @@ static int qusb_phy_probe(struct platform_device *pdev)
						&qphy->efuse_num_of_bits);
			}

			if (!ret) {
				ret = of_property_read_u32(dev->of_node,
						"qcom,efuse-offset",
						&qphy->efuse_offset);
			}

			if (ret) {
				dev_err(dev,
				"DT Value for efuse is invalid.\n");
+55 −0
Original line number Diff line number Diff line
@@ -11,6 +11,11 @@
 * GNU General Public License for more details.
 *
 */
/*
 * NOTE: This file has been modified by Sony Mobile Communications Inc.
 * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc,
 * and licensed under the license of the file.
 */

#include <linux/module.h>
#include <linux/kernel.h>
@@ -57,6 +62,24 @@ enum ldo_levels {
/* port select mux: 1 - sw control. 0 - HW control*/
#define SW_PORTSELECT_MX	BIT(1)

#define SSUSB3PHY_TXA_DRV_LVL		0x21c
#define SSUSB3PHY_TXB_DRV_LVL		0x61c
#define SSUSB3PHY_TXA_EMP_POST1_LVL	0x20c
#define SSUSB3PHY_TXB_EMP_POST1_LVL	0x60c

unsigned int ssphy_txa_drv_lvl;
unsigned int ssphy_txb_drv_lvl;
unsigned int ssphy_txa_emp_post1_lvl;
unsigned int ssphy_txb_emp_post1_lvl;
module_param(ssphy_txa_drv_lvl, uint, S_IRUGO | S_IWUSR);
module_param(ssphy_txb_drv_lvl, uint, S_IRUGO | S_IWUSR);
module_param(ssphy_txa_emp_post1_lvl, uint, S_IRUGO | S_IWUSR);
module_param(ssphy_txb_emp_post1_lvl, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ssphy_txa_drv_lvl, "SSUSB3PHY QSERDES TXA DRV LVL");
MODULE_PARM_DESC(ssphy_txb_drv_lvl, "SSUSB3PHY QSERDES TXB DRV LVL");
MODULE_PARM_DESC(ssphy_txa_emp_post1_lvl, "SSUSB3PHY QSERDES TXA EMP POST1 LVL");
MODULE_PARM_DESC(ssphy_txb_emp_post1_lvl, "SSUSB3PHY QSERDES TXB EMP POST1 LVL");

enum qmp_phy_rev_reg {
	USB3_PHY_PCS_STATUS,
	USB3_PHY_AUTONOMOUS_MODE_CTRL,
@@ -263,6 +286,21 @@ disable_fpc_redrive:
	return rc < 0 ? rc : 0;
}

static void msm_ssphy_param_output(struct usb_phy *uphy)
{
	struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp,
					phy);

	dev_dbg(uphy->dev, "SS_USB3PHY_QSERDES_TXA_TX_DEV_LVL:0x%02x\n",
		readb_relaxed(phy->base + SSUSB3PHY_TXA_DRV_LVL));
	dev_dbg(uphy->dev, "SS_USB3PHY_QSERDES_TXB_TX_DEV_LVL:0x%02x\n",
		readb_relaxed(phy->base + SSUSB3PHY_TXB_DRV_LVL));
	dev_dbg(uphy->dev, "SS_USB3PHY_QSERDES_TXA_TX_EMP_POST1_LVL:0x%02x\n",
		readb_relaxed(phy->base + SSUSB3PHY_TXA_EMP_POST1_LVL));
	dev_dbg(uphy->dev, "SS_USB3PHY_QSERDES_TXB_TX_EMP_POST1_LVL:0x%02x\n",
		readb_relaxed(phy->base + SSUSB3PHY_TXB_EMP_POST1_LVL));
}

static int configure_phy_regs(struct usb_phy *uphy,
				const struct qmp_reg_val *reg)
{
@@ -280,6 +318,23 @@ static int configure_phy_regs(struct usb_phy *uphy,
			usleep_range(reg->delay, reg->delay + 10);
		reg++;
	}

	/* ssusb phy dynamic set */
	if (ssphy_txa_drv_lvl)
		writel_relaxed(ssphy_txa_drv_lvl,
				phy->base + SSUSB3PHY_TXA_DRV_LVL);
	if (ssphy_txb_drv_lvl)
		writel_relaxed(ssphy_txb_drv_lvl,
				phy->base + SSUSB3PHY_TXB_DRV_LVL);
	if (ssphy_txa_emp_post1_lvl)
		writel_relaxed(ssphy_txa_emp_post1_lvl,
				phy->base + SSUSB3PHY_TXA_EMP_POST1_LVL);
	if (ssphy_txb_emp_post1_lvl)
		writel_relaxed(ssphy_txb_emp_post1_lvl,
				phy->base + SSUSB3PHY_TXB_EMP_POST1_LVL);

	/* parameter output */
	msm_ssphy_param_output(uphy);
	return 0;
}