[PATCH v3 07/16] phy: qcom-qusb2: Add support for different register layouts
From: Manu Gautam
Date: Tue Nov 21 2017 - 04:24:44 EST
New version of QUSB2 PHY has some registers offset changed.
Add support to have register layout for a target and update
the same in phy_configuration.
Signed-off-by: Manu Gautam <mgautam@xxxxxxxxxxxxxx>
---
drivers/phy/qualcomm/phy-qcom-qusb2.c | 131 ++++++++++++++++++++++++----------
1 file changed, 95 insertions(+), 36 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 4a5b2a1..c0c5358 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -37,17 +37,10 @@
#define QUSB2PHY_PLL_AUTOPGM_CTL1 0x1c
#define QUSB2PHY_PLL_PWR_CTRL 0x18
-#define QUSB2PHY_PLL_STATUS 0x38
+/* QUSB2PHY_PLL_STATUS register bits */
#define PLL_LOCKED BIT(5)
-#define QUSB2PHY_PORT_TUNE1 0x80
-#define QUSB2PHY_PORT_TUNE2 0x84
-#define QUSB2PHY_PORT_TUNE3 0x88
-#define QUSB2PHY_PORT_TUNE4 0x8c
-#define QUSB2PHY_PORT_TUNE5 0x90
-#define QUSB2PHY_PORT_TEST2 0x9c
-
-#define QUSB2PHY_PORT_POWERDOWN 0xb4
+/* QUSB2PHY_PORT_POWERDOWN register bits */
#define CLAMP_N_EN BIT(5)
#define FREEZIO_N BIT(1)
#define POWER_DOWN BIT(0)
@@ -59,6 +52,11 @@
struct qusb2_phy_init_tbl {
unsigned int offset;
unsigned int val;
+ /*
+ * register part of layout ?
+ * if yes, then offset gives index in the reg-layout
+ */
+ int in_layout;
};
#define QUSB2_PHY_INIT_CFG(o, v) \
@@ -67,15 +65,50 @@ struct qusb2_phy_init_tbl {
.val = v, \
}
+#define QUSB2_PHY_INIT_CFG_L(o, v) \
+ { \
+ .offset = o, \
+ .val = v, \
+ .in_layout = 1, \
+ }
+
+/* set of registers with offsets different per-PHY */
+enum qusb2phy_reg_layout {
+ QUSB2PHY_PLL_STATUS,
+ QUSB2PHY_PORT_TUNE1,
+ QUSB2PHY_PORT_TUNE2,
+ QUSB2PHY_PORT_TUNE3,
+ QUSB2PHY_PORT_TUNE4,
+ QUSB2PHY_PORT_TUNE5,
+ QUSB2PHY_PORT_TEST1,
+ QUSB2PHY_PORT_TEST2,
+ QUSB2PHY_PORT_POWERDOWN,
+ QUSB2PHY_INTR_CTRL,
+};
+
+static const unsigned int msm8996_regs_layout[] = {
+ [QUSB2PHY_PLL_STATUS] = 0x38,
+ [QUSB2PHY_PORT_TUNE1] = 0x80,
+ [QUSB2PHY_PORT_TUNE2] = 0x84,
+ [QUSB2PHY_PORT_TUNE3] = 0x88,
+ [QUSB2PHY_PORT_TUNE4] = 0x8c,
+ [QUSB2PHY_PORT_TUNE5] = 0x90,
+ [QUSB2PHY_PORT_TEST2] = 0x9c,
+ [QUSB2PHY_PORT_POWERDOWN] = 0xb4,
+};
+
static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
- QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE1, 0xf8),
- QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE2, 0xb3),
- QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE3, 0x83),
- QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE4, 0xc0),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xf8),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0xb3),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0x83),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0xc0),
+
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
- QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TEST2, 0x14),
+
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TEST2, 0x14),
+
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
};
@@ -86,11 +119,24 @@ struct qusb2_phy_cfg {
unsigned int tbl_num;
/* offset to PHY_CLK_SCHEME register in TCSR map */
unsigned int clk_scheme_offset;
+
+ /* array of registers with different offsets */
+ const unsigned int *regs;
+ unsigned int mask_core_ready;
+ unsigned int disable_ctrl;
+
+ /* true if PHY has PLL_TEST register to select clk_scheme */
+ bool has_pll_test;
};
static const struct qusb2_phy_cfg msm8996_phy_cfg = {
- .tbl = msm8996_init_tbl,
- .tbl_num = ARRAY_SIZE(msm8996_init_tbl),
+ .tbl = msm8996_init_tbl,
+ .tbl_num = ARRAY_SIZE(msm8996_init_tbl),
+ .regs = msm8996_regs_layout,
+
+ .has_pll_test = true,
+ .disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
+ .mask_core_ready = PLL_LOCKED,
};
static const char * const qusb2_phy_vreg_names[] = {
@@ -160,12 +206,17 @@ static inline void qusb2_clrbits(void __iomem *base, u32 offset, u32 val)
static inline
void qcom_qusb2_phy_configure(void __iomem *base,
+ const unsigned int *regs,
const struct qusb2_phy_init_tbl tbl[], int num)
{
int i;
- for (i = 0; i < num; i++)
- writel(tbl[i].val, base + tbl[i].offset);
+ for (i = 0; i < num; i++) {
+ if (tbl[i].in_layout)
+ writel(tbl[i].val, base + regs[tbl[i].offset]);
+ else
+ writel(tbl[i].val, base + tbl[i].offset);
+ }
}
/*
@@ -198,7 +249,8 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy *qphy)
static int qusb2_phy_init(struct phy *phy)
{
struct qusb2_phy *qphy = phy_get_drvdata(phy);
- unsigned int val;
+ const struct qusb2_phy_cfg *cfg = qphy->cfg;
+ unsigned int val = 0;
unsigned int clk_scheme;
int ret;
@@ -239,20 +291,23 @@ static int qusb2_phy_init(struct phy *phy)
}
/* Disable the PHY */
- qusb2_setbits(qphy->base, QUSB2PHY_PORT_POWERDOWN,
- CLAMP_N_EN | FREEZIO_N | POWER_DOWN);
+ qusb2_setbits(qphy->base, cfg->regs[QUSB2PHY_PORT_POWERDOWN],
+ qphy->cfg->disable_ctrl);
- /* save reset value to override reference clock scheme later */
- val = readl(qphy->base + QUSB2PHY_PLL_TEST);
+ if (cfg->has_pll_test) {
+ /* save reset value to override reference clock scheme later */
+ val = readl(qphy->base + QUSB2PHY_PLL_TEST);
+ }
- qcom_qusb2_phy_configure(qphy->base, qphy->cfg->tbl,
- qphy->cfg->tbl_num);
+ qcom_qusb2_phy_configure(qphy->base, cfg->regs, cfg->tbl,
+ cfg->tbl_num);
/* Set efuse value for tuning the PHY */
qusb2_phy_set_tune2_param(qphy);
/* Enable the PHY */
- qusb2_clrbits(qphy->base, QUSB2PHY_PORT_POWERDOWN, POWER_DOWN);
+ qusb2_clrbits(qphy->base, cfg->regs[QUSB2PHY_PORT_POWERDOWN],
+ POWER_DOWN);
/* Required to get phy pll lock successfully */
usleep_range(150, 160);
@@ -285,27 +340,31 @@ static int qusb2_phy_init(struct phy *phy)
}
if (!qphy->has_se_clk_scheme) {
- val &= ~CLK_REF_SEL;
ret = clk_prepare_enable(qphy->ref_clk);
if (ret) {
dev_err(&phy->dev, "failed to enable ref clk, %d\n",
ret);
goto assert_phy_reset;
}
- } else {
- val |= CLK_REF_SEL;
}
- writel(val, qphy->base + QUSB2PHY_PLL_TEST);
+ if (cfg->has_pll_test) {
+ if (!qphy->has_se_clk_scheme)
+ val &= ~CLK_REF_SEL;
+ else
+ val |= CLK_REF_SEL;
+
+ writel(val, qphy->base + QUSB2PHY_PLL_TEST);
- /* ensure above write is through */
- readl(qphy->base + QUSB2PHY_PLL_TEST);
+ /* ensure above write is through */
+ readl(qphy->base + QUSB2PHY_PLL_TEST);
+ }
/* Required to get phy pll lock successfully */
usleep_range(100, 110);
- val = readb(qphy->base + QUSB2PHY_PLL_STATUS);
- if (!(val & PLL_LOCKED)) {
+ val = readb(qphy->base + cfg->regs[QUSB2PHY_PLL_STATUS]);
+ if (!(val & cfg->mask_core_ready)) {
dev_err(&phy->dev,
"QUSB2PHY pll lock failed: status reg = %x\n", val);
ret = -EBUSY;
@@ -334,8 +393,8 @@ static int qusb2_phy_exit(struct phy *phy)
struct qusb2_phy *qphy = phy_get_drvdata(phy);
/* Disable the PHY */
- qusb2_setbits(qphy->base, QUSB2PHY_PORT_POWERDOWN,
- CLAMP_N_EN | FREEZIO_N | POWER_DOWN);
+ qusb2_setbits(qphy->base, qphy->cfg->regs[QUSB2PHY_PORT_POWERDOWN],
+ qphy->cfg->disable_ctrl);
if (!qphy->has_se_clk_scheme)
clk_disable_unprepare(qphy->ref_clk);
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project