diff options
Diffstat (limited to 'drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c')
| -rw-r--r-- | drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c | 536 |
1 files changed, 303 insertions, 233 deletions
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c index d8128f50b0dd..ec486ff02c9b 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c @@ -3,6 +3,7 @@ * Copyright (c) 2018, The Linux Foundation */ +#include <dt-bindings/clock/qcom,dsi-phy-28nm.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/iopoll.h> @@ -83,6 +84,18 @@ struct dsi_pll_10nm { #define to_pll_10nm(x) container_of(x, struct dsi_pll_10nm, clk_hw) +/** + * struct dsi_phy_10nm_tuning_cfg - Holds 10nm PHY tuning config parameters. + * @rescode_offset_top: Offset for pull-up legs rescode. + * @rescode_offset_bot: Offset for pull-down legs rescode. + * @vreg_ctrl: vreg ctrl to drive LDO level + */ +struct dsi_phy_10nm_tuning_cfg { + u8 rescode_offset_top[DSI_LANE_MAX]; + u8 rescode_offset_bot[DSI_LANE_MAX]; + u8 vreg_ctrl; +}; + /* * Global list of private DSI PLL struct pointers. We need this for bonded DSI * mode, where the master PLL's clk_ops needs access the slave's private data @@ -175,20 +188,20 @@ static void dsi_pll_ssc_commit(struct dsi_pll_10nm *pll, struct dsi_pll_config * if (config->enable_ssc) { pr_debug("SSC is enabled\n"); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1, - config->ssc_stepsize & 0xff); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1, - config->ssc_stepsize >> 8); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1, - config->ssc_div_per & 0xff); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1, - config->ssc_div_per >> 8); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1, - config->ssc_adj_per & 0xff); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1, - config->ssc_adj_per >> 8); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_CONTROL, - SSC_EN | (config->ssc_center ? SSC_CENTER : 0)); + writel(config->ssc_stepsize & 0xff, + base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1); + writel(config->ssc_stepsize >> 8, + base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1); + writel(config->ssc_div_per & 0xff, + base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1); + writel(config->ssc_div_per >> 8, + base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1); + writel(config->ssc_adj_per & 0xff, + base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1); + writel(config->ssc_adj_per >> 8, + base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1); + writel(SSC_EN | (config->ssc_center ? SSC_CENTER : 0), + base + REG_DSI_10nm_PHY_PLL_SSC_CONTROL); } } @@ -196,46 +209,43 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll) { void __iomem *base = pll->phy->pll_base; - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE, 0x80); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_DSM_DIVIDER, 0x00); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE, - 0xba); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_OUTDIV, 0x00); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE, 0x00); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x08); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1, 0xc0); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, 0xfa); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, - 0x4c); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PFILT, 0x29); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_IFILT, 0x3f); + writel(0x80, base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE); + writel(0x03, base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO); + writel(0x00, base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE); + writel(0x00, base + REG_DSI_10nm_PHY_PLL_DSM_DIVIDER); + writel(0x4e, base + REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER); + writel(0x40, base + REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS); + writel(0xba, base + REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE); + writel(0x0c, base + REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE); + writel(0x00, base + REG_DSI_10nm_PHY_PLL_OUTDIV); + writel(0x00, base + REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE); + writel(0x08, base + REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO); + writel(0x08, base + REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1); + writel(0xc0, base + REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1); + writel(0xfa, base + REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1); + writel(0x4c, base + REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1); + writel(0x80, base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE); + writel(0x29, base + REG_DSI_10nm_PHY_PLL_PFILT); + writel(0x3f, base + REG_DSI_10nm_PHY_PLL_IFILT); } static void dsi_pll_commit(struct dsi_pll_10nm *pll, struct dsi_pll_config *config) { void __iomem *base = pll->phy->pll_base; - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1, - config->decimal_div_start); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1, - config->frac_div_start & 0xff); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1, - (config->frac_div_start & 0xff00) >> 8); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1, - (config->frac_div_start & 0x30000) >> 16); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1, 64); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY, 0x06); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CMODE, 0x10); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS, - config->pll_clock_inverters); + writel(0x12, base + REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE); + writel(config->decimal_div_start, + base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1); + writel(config->frac_div_start & 0xff, + base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1); + writel((config->frac_div_start & 0xff00) >> 8, + base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1); + writel((config->frac_div_start & 0x30000) >> 16, + base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1); + writel(64, base + REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1); + writel(0x06, base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY); + writel(0x10, base + REG_DSI_10nm_PHY_PLL_CMODE); + writel(config->pll_clock_inverters, base + REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS); } static int dsi_pll_10nm_vco_set_rate(struct clk_hw *hw, unsigned long rate, @@ -290,21 +300,19 @@ static int dsi_pll_10nm_lock_status(struct dsi_pll_10nm *pll) static void dsi_pll_disable_pll_bias(struct dsi_pll_10nm *pll) { - u32 data = dsi_phy_read(pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0); + u32 data = readl(pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0); - dsi_phy_write(pll->phy->pll_base + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0); - dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0, - data & ~BIT(5)); + writel(0, pll->phy->pll_base + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES); + writel(data & ~BIT(5), pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0); ndelay(250); } static void dsi_pll_enable_pll_bias(struct dsi_pll_10nm *pll) { - u32 data = dsi_phy_read(pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0); + u32 data = readl(pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0); - dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0, - data | BIT(5)); - dsi_phy_write(pll->phy->pll_base + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0xc0); + writel(data | BIT(5), pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0); + writel(0xc0, pll->phy->pll_base + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES); ndelay(250); } @@ -312,18 +320,16 @@ static void dsi_pll_disable_global_clk(struct dsi_pll_10nm *pll) { u32 data; - data = dsi_phy_read(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); - dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, - data & ~BIT(5)); + data = readl(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); + writel(data & ~BIT(5), pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); } static void dsi_pll_enable_global_clk(struct dsi_pll_10nm *pll) { u32 data; - data = dsi_phy_read(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); - dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, - data | BIT(5)); + data = readl(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); + writel(data | BIT(5), pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); } static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw) @@ -343,8 +349,7 @@ static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw) } /* Start PLL */ - dsi_phy_write(pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, - 0x01); + writel(0x01, pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL); /* * ensure all PLL configurations are written prior to checking @@ -365,11 +370,9 @@ static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw) if (pll_10nm->slave) dsi_pll_enable_global_clk(pll_10nm->slave); - dsi_phy_write(pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, - 0x01); + writel(0x01, pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL); if (pll_10nm->slave) - dsi_phy_write(pll_10nm->slave->phy->base + - REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x01); + writel(0x01, pll_10nm->slave->phy->base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL); error: return rc; @@ -377,7 +380,7 @@ error: static void dsi_pll_disable_sub(struct dsi_pll_10nm *pll) { - dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0); + writel(0, pll->phy->base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL); dsi_pll_disable_pll_bias(pll); } @@ -391,7 +394,7 @@ static void dsi_pll_10nm_vco_unprepare(struct clk_hw *hw) * powering down the PLL */ dsi_pll_disable_global_clk(pll_10nm); - dsi_phy_write(pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0); + writel(0, pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL); dsi_pll_disable_sub(pll_10nm); if (pll_10nm->slave) { dsi_pll_disable_global_clk(pll_10nm->slave); @@ -414,13 +417,13 @@ static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw, u32 dec; u64 pll_freq, tmp64; - dec = dsi_phy_read(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1); + dec = readl(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1); dec &= 0xff; - frac = dsi_phy_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1); - frac |= ((dsi_phy_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1) & + frac = readl(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1); + frac |= ((readl(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1) & 0xff) << 8); - frac |= ((dsi_phy_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1) & + frac |= ((readl(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1) & 0x3) << 16); /* @@ -441,21 +444,19 @@ static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw, return (unsigned long)vco_rate; } -static long dsi_pll_10nm_clk_round_rate(struct clk_hw *hw, - unsigned long rate, unsigned long *parent_rate) +static int dsi_pll_10nm_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct dsi_pll_10nm *pll_10nm = to_pll_10nm(hw); - if (rate < pll_10nm->phy->cfg->min_pll_rate) - return pll_10nm->phy->cfg->min_pll_rate; - else if (rate > pll_10nm->phy->cfg->max_pll_rate) - return pll_10nm->phy->cfg->max_pll_rate; - else - return rate; + req->rate = clamp_t(unsigned long, req->rate, + pll_10nm->phy->cfg->min_pll_rate, pll_10nm->phy->cfg->max_pll_rate); + + return 0; } static const struct clk_ops clk_ops_dsi_pll_10nm_vco = { - .round_rate = dsi_pll_10nm_clk_round_rate, + .determine_rate = dsi_pll_10nm_clk_determine_rate, .set_rate = dsi_pll_10nm_vco_set_rate, .recalc_rate = dsi_pll_10nm_vco_recalc_rate, .prepare = dsi_pll_10nm_vco_prepare, @@ -473,15 +474,15 @@ static void dsi_10nm_pll_save_state(struct msm_dsi_phy *phy) void __iomem *phy_base = pll_10nm->phy->base; u32 cmn_clk_cfg0, cmn_clk_cfg1; - cached->pll_out_div = dsi_phy_read(pll_10nm->phy->pll_base + - REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); + cached->pll_out_div = readl(pll_10nm->phy->pll_base + + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); cached->pll_out_div &= 0x3; - cmn_clk_cfg0 = dsi_phy_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0); + cmn_clk_cfg0 = readl(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0); cached->bit_clk_div = cmn_clk_cfg0 & 0xf; cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4; - cmn_clk_cfg1 = dsi_phy_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); + cmn_clk_cfg1 = readl(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); cached->pll_mux = cmn_clk_cfg1 & 0x3; DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x", @@ -497,18 +498,18 @@ static int dsi_10nm_pll_restore_state(struct msm_dsi_phy *phy) u32 val; int ret; - val = dsi_phy_read(pll_10nm->phy->pll_base + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); + val = readl(pll_10nm->phy->pll_base + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); val &= ~0x3; val |= cached->pll_out_div; - dsi_phy_write(pll_10nm->phy->pll_base + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, val); + writel(val, pll_10nm->phy->pll_base + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); - dsi_phy_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0, - cached->bit_clk_div | (cached->pix_clk_div << 4)); + writel(cached->bit_clk_div | (cached->pix_clk_div << 4), + phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0); - val = dsi_phy_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); + val = readl(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); val &= ~0x3; val |= cached->pll_mux; - dsi_phy_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, val); + writel(val, phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); ret = dsi_pll_10nm_vco_set_rate(phy->vco_hw, pll_10nm->vco_current_rate, @@ -546,7 +547,7 @@ static int dsi_10nm_set_usecase(struct msm_dsi_phy *phy) } /* set PLL src */ - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, (data << 2)); + writel(data << 2, base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); return 0; } @@ -559,62 +560,59 @@ static int dsi_10nm_set_usecase(struct msm_dsi_phy *phy) */ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm, struct clk_hw **provided_clocks) { - char clk_name[32], parent[32], vco_name[32]; - char parent2[32], parent3[32], parent4[32]; + char clk_name[32]; struct clk_init_data vco_init = { - .parent_names = (const char *[]){ "xo" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "ref", + }, .num_parents = 1, - .name = vco_name, + .name = clk_name, .flags = CLK_IGNORE_UNUSED, .ops = &clk_ops_dsi_pll_10nm_vco, }; struct device *dev = &pll_10nm->phy->pdev->dev; - struct clk_hw *hw; + struct clk_hw *hw, *pll_out_div, *pll_bit, *pll_by_2_bit; + struct clk_hw *pll_post_out_div, *pclk_mux; int ret; DBG("DSI%d", pll_10nm->phy->id); - snprintf(vco_name, 32, "dsi%dvco_clk", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%dvco_clk", pll_10nm->phy->id); pll_10nm->clk_hw.init = &vco_init; ret = devm_clk_hw_register(dev, &pll_10nm->clk_hw); if (ret) return ret; - snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%dvco_clk", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pll_out_div_clk", pll_10nm->phy->id); - hw = devm_clk_hw_register_divider(dev, clk_name, - parent, CLK_SET_RATE_PARENT, - pll_10nm->phy->pll_base + - REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, - 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + pll_out_div = devm_clk_hw_register_divider_parent_hw(dev, clk_name, + &pll_10nm->clk_hw, CLK_SET_RATE_PARENT, + pll_10nm->phy->pll_base + + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, + 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); + if (IS_ERR(pll_out_div)) { + ret = PTR_ERR(pll_out_div); goto fail; } - snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pll_bit_clk", pll_10nm->phy->id); /* BIT CLK: DIV_CTRL_3_0 */ - hw = devm_clk_hw_register_divider(dev, clk_name, parent, - CLK_SET_RATE_PARENT, - pll_10nm->phy->base + - REG_DSI_10nm_PHY_CMN_CLK_CFG0, - 0, 4, CLK_DIVIDER_ONE_BASED, - &pll_10nm->postdiv_lock); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + pll_bit = devm_clk_hw_register_divider_parent_hw(dev, clk_name, + pll_out_div, CLK_SET_RATE_PARENT, + pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG0, + 0, 4, CLK_DIVIDER_ONE_BASED, &pll_10nm->postdiv_lock); + if (IS_ERR(pll_bit)) { + ret = PTR_ERR(pll_bit); goto fail; } - snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_phy_pll_out_byteclk", pll_10nm->phy->id); /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */ - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent, - CLK_SET_RATE_PARENT, 1, 8); + hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, clk_name, + pll_bit, CLK_SET_RATE_PARENT, 1, 8); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail; @@ -622,52 +620,45 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm, struct clk_hw **prov provided_clocks[DSI_BYTE_PLL_CLK] = hw; - snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pll_by_2_bit_clk", pll_10nm->phy->id); - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent, - 0, 1, 2); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + pll_by_2_bit = devm_clk_hw_register_fixed_factor_parent_hw(dev, + clk_name, pll_bit, 0, 1, 2); + if (IS_ERR(pll_by_2_bit)) { + ret = PTR_ERR(pll_by_2_bit); goto fail; } - snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pll_post_out_div_clk", pll_10nm->phy->id); - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent, - 0, 1, 4); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + pll_post_out_div = devm_clk_hw_register_fixed_factor_parent_hw(dev, + clk_name, pll_out_div, 0, 1, 4); + if (IS_ERR(pll_post_out_div)) { + ret = PTR_ERR(pll_post_out_div); goto fail; } - snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->phy->id); - snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->phy->id); - snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_10nm->phy->id); - snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->phy->id); - - hw = devm_clk_hw_register_mux(dev, clk_name, - ((const char *[]){ - parent, parent2, parent3, parent4 - }), 4, 0, pll_10nm->phy->base + - REG_DSI_10nm_PHY_CMN_CLK_CFG1, - 0, 2, 0, NULL); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pclk_mux", pll_10nm->phy->id); + + pclk_mux = devm_clk_hw_register_mux_parent_hws(dev, clk_name, + ((const struct clk_hw *[]){ + pll_bit, + pll_by_2_bit, + pll_out_div, + pll_post_out_div, + }), 4, 0, pll_10nm->phy->base + + REG_DSI_10nm_PHY_CMN_CLK_CFG1, 0, 2, 0, NULL); + if (IS_ERR(pclk_mux)) { + ret = PTR_ERR(pclk_mux); goto fail; } - snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_phy_pll_out_dsiclk", pll_10nm->phy->id); /* PIX CLK DIV : DIV_CTRL_7_4*/ - hw = devm_clk_hw_register_divider(dev, clk_name, parent, - 0, pll_10nm->phy->base + - REG_DSI_10nm_PHY_CMN_CLK_CFG0, - 4, 4, CLK_DIVIDER_ONE_BASED, - &pll_10nm->postdiv_lock); + hw = devm_clk_hw_register_divider_parent_hw(dev, clk_name, pclk_mux, + 0, pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG0, + 4, 4, CLK_DIVIDER_ONE_BASED, &pll_10nm->postdiv_lock); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail; @@ -711,6 +702,13 @@ static int dsi_pll_10nm_init(struct msm_dsi_phy *phy) /* TODO: Remove this when we have proper display handover support */ msm_dsi_phy_pll_save_state(phy); + /* + * Store also proper vco_current_rate, because its value will be used in + * dsi_10nm_pll_restore_state(). + */ + if (!dsi_pll_10nm_vco_recalc_rate(&pll_10nm->clk_hw, VCO_REF_CLK_RATE)) + pll_10nm->vco_current_rate = pll_10nm->phy->cfg->min_pll_rate; + return 0; } @@ -719,7 +717,7 @@ static int dsi_phy_hw_v3_0_is_pll_on(struct msm_dsi_phy *phy) void __iomem *base = phy->base; u32 data = 0; - data = dsi_phy_read(base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL); + data = readl(base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL); mb(); /* make sure read happened */ return (data & BIT(0)); @@ -735,11 +733,9 @@ static void dsi_phy_hw_v3_0_config_lpcdrx(struct msm_dsi_phy *phy, bool enable) * corresponding to the logical data lane 0 */ if (enable) - dsi_phy_write(lane_base + - REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0), 0x3); + writel(0x3, lane_base + REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0)); else - dsi_phy_write(lane_base + - REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0), 0); + writel(0, lane_base + REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0)); } static void dsi_phy_hw_v3_0_lane_settings(struct msm_dsi_phy *phy) @@ -747,46 +743,47 @@ static void dsi_phy_hw_v3_0_lane_settings(struct msm_dsi_phy *phy) int i; u8 tx_dctrl[] = { 0x00, 0x00, 0x00, 0x04, 0x01 }; void __iomem *lane_base = phy->lane_base; + struct dsi_phy_10nm_tuning_cfg *tuning_cfg = phy->tuning_cfg; if (phy->cfg->quirks & DSI_PHY_10NM_QUIRK_OLD_TIMINGS) tx_dctrl[3] = 0x02; /* Strength ctrl settings */ for (i = 0; i < 5; i++) { - dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPTX_STR_CTRL(i), - 0x55); + writel(0x55, lane_base + REG_DSI_10nm_PHY_LN_LPTX_STR_CTRL(i)); /* * Disable LPRX and CDRX for all lanes. And later on, it will * be only enabled for the physical data lane corresponding * to the logical data lane 0 */ - dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPRX_CTRL(i), 0); - dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_PIN_SWAP(i), 0x0); - dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_HSTX_STR_CTRL(i), - 0x88); + writel(0, lane_base + REG_DSI_10nm_PHY_LN_LPRX_CTRL(i)); + writel(0x0, lane_base + REG_DSI_10nm_PHY_LN_PIN_SWAP(i)); + writel(0x88, lane_base + REG_DSI_10nm_PHY_LN_HSTX_STR_CTRL(i)); } dsi_phy_hw_v3_0_config_lpcdrx(phy, true); /* other settings */ for (i = 0; i < 5; i++) { - dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG0(i), 0x0); - dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG1(i), 0x0); - dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG2(i), 0x0); - dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG3(i), - i == 4 ? 0x80 : 0x0); - dsi_phy_write(lane_base + - REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(i), 0x0); - dsi_phy_write(lane_base + - REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(i), 0x0); - dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(i), - tx_dctrl[i]); + writel(0, lane_base + REG_DSI_10nm_PHY_LN_CFG0(i)); + writel(0, lane_base + REG_DSI_10nm_PHY_LN_CFG1(i)); + writel(0, lane_base + REG_DSI_10nm_PHY_LN_CFG2(i)); + writel(i == 4 ? 0x80 : 0x0, lane_base + REG_DSI_10nm_PHY_LN_CFG3(i)); + + /* platform specific dsi phy drive strength adjustment */ + writel(tuning_cfg->rescode_offset_top[i], + lane_base + REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(i)); + writel(tuning_cfg->rescode_offset_bot[i], + lane_base + REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(i)); + + writel(tx_dctrl[i], + lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(i)); } if (!(phy->cfg->quirks & DSI_PHY_10NM_QUIRK_OLD_TIMINGS)) { /* Toggle BIT 0 to release freeze I/0 */ - dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x05); - dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x04); + writel(0x05, lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3)); + writel(0x04, lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3)); } } @@ -799,6 +796,7 @@ static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, u32 const timeout_us = 1000; struct msm_dsi_dphy_timing *timing = &phy->timing; void __iomem *base = phy->base; + struct dsi_phy_10nm_tuning_cfg *tuning_cfg = phy->tuning_cfg; u32 data; DBG(""); @@ -823,63 +821,51 @@ static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, /* de-assert digital and pll power down */ data = BIT(6) | BIT(5); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, data); + writel(data, base + REG_DSI_10nm_PHY_CMN_CTRL_0); /* Assert PLL core reset */ - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0x00); + writel(0x00, base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL); /* turn off resync FIFO */ - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x00); + writel(0x00, base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL); /* Select MS1 byte-clk */ - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_GLBL_CTRL, 0x10); + writel(0x10, base + REG_DSI_10nm_PHY_CMN_GLBL_CTRL); - /* Enable LDO */ - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_VREG_CTRL, 0x59); + /* Enable LDO with platform specific drive level/amplitude adjustment */ + writel(tuning_cfg->vreg_ctrl, base + REG_DSI_10nm_PHY_CMN_VREG_CTRL); /* Configure PHY lane swap (TODO: we need to calculate this) */ - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG0, 0x21); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG1, 0x84); + writel(0x21, base + REG_DSI_10nm_PHY_CMN_LANE_CFG0); + writel(0x84, base + REG_DSI_10nm_PHY_CMN_LANE_CFG1); /* DSI PHY timings */ - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_0, - timing->hs_halfbyte_en); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_1, - timing->clk_zero); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_2, - timing->clk_prepare); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_3, - timing->clk_trail); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_4, - timing->hs_exit); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_5, - timing->hs_zero); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_6, - timing->hs_prepare); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_7, - timing->hs_trail); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_8, - timing->hs_rqst); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_9, - timing->ta_go | (timing->ta_sure << 3)); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_10, - timing->ta_get); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_11, - 0x00); + writel(timing->hs_halfbyte_en, base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_0); + writel(timing->clk_zero, base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_1); + writel(timing->clk_prepare, base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_2); + writel(timing->clk_trail, base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_3); + writel(timing->hs_exit, base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_4); + writel(timing->hs_zero, base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_5); + writel(timing->hs_prepare, base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_6); + writel(timing->hs_trail, base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_7); + writel(timing->hs_rqst, base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_8); + writel(timing->ta_go | (timing->ta_sure << 3), base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_9); + writel(timing->ta_get, base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_10); + writel(0x00, base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_11); /* Remove power down from all blocks */ - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, 0x7f); + writel(0x7f, base + REG_DSI_10nm_PHY_CMN_CTRL_0); /* power up lanes */ - data = dsi_phy_read(base + REG_DSI_10nm_PHY_CMN_CTRL_0); + data = readl(base + REG_DSI_10nm_PHY_CMN_CTRL_0); /* TODO: only power up lanes that are used */ data |= 0x1F; - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, data); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CTRL0, 0x1F); + writel(data, base + REG_DSI_10nm_PHY_CMN_CTRL_0); + writel(0x1F, base + REG_DSI_10nm_PHY_CMN_LANE_CTRL0); /* Select full-rate mode */ - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_2, 0x40); + writel(0x40, base + REG_DSI_10nm_PHY_CMN_CTRL_2); ret = dsi_10nm_set_usecase(phy); if (ret) { @@ -907,35 +893,122 @@ static void dsi_10nm_phy_disable(struct msm_dsi_phy *phy) pr_warn("Turning OFF PHY while PLL is on\n"); dsi_phy_hw_v3_0_config_lpcdrx(phy, false); - data = dsi_phy_read(base + REG_DSI_10nm_PHY_CMN_CTRL_0); + data = readl(base + REG_DSI_10nm_PHY_CMN_CTRL_0); /* disable all lanes */ data &= ~0x1F; - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, data); - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CTRL0, 0); + writel(data, base + REG_DSI_10nm_PHY_CMN_CTRL_0); + writel(0, base + REG_DSI_10nm_PHY_CMN_LANE_CTRL0); /* Turn off all PHY blocks */ - dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, 0x00); + writel(0x00, base + REG_DSI_10nm_PHY_CMN_CTRL_0); /* make sure phy is turned off */ wmb(); DBG("DSI%d PHY disabled", phy->id); } +static int dsi_10nm_phy_parse_dt(struct msm_dsi_phy *phy) +{ + struct device *dev = &phy->pdev->dev; + struct dsi_phy_10nm_tuning_cfg *tuning_cfg; + s8 offset_top[DSI_LANE_MAX] = { 0 }; /* No offset */ + s8 offset_bot[DSI_LANE_MAX] = { 0 }; /* No offset */ + u32 ldo_level = 400; /* 400mV */ + u8 level; + int ret, i; + + tuning_cfg = devm_kzalloc(dev, sizeof(*tuning_cfg), GFP_KERNEL); + if (!tuning_cfg) + return -ENOMEM; + + /* Drive strength adjustment parameters */ + ret = of_property_read_u8_array(dev->of_node, "qcom,phy-rescode-offset-top", + offset_top, DSI_LANE_MAX); + if (ret && ret != -EINVAL) { + DRM_DEV_ERROR(dev, "failed to parse qcom,phy-rescode-offset-top, %d\n", ret); + return ret; + } + + for (i = 0; i < DSI_LANE_MAX; i++) { + if (offset_top[i] < -32 || offset_top[i] > 31) { + DRM_DEV_ERROR(dev, + "qcom,phy-rescode-offset-top value %d is not in range [-32..31]\n", + offset_top[i]); + return -EINVAL; + } + tuning_cfg->rescode_offset_top[i] = 0x3f & offset_top[i]; + } + + ret = of_property_read_u8_array(dev->of_node, "qcom,phy-rescode-offset-bot", + offset_bot, DSI_LANE_MAX); + if (ret && ret != -EINVAL) { + DRM_DEV_ERROR(dev, "failed to parse qcom,phy-rescode-offset-bot, %d\n", ret); + return ret; + } + + for (i = 0; i < DSI_LANE_MAX; i++) { + if (offset_bot[i] < -32 || offset_bot[i] > 31) { + DRM_DEV_ERROR(dev, + "qcom,phy-rescode-offset-bot value %d is not in range [-32..31]\n", + offset_bot[i]); + return -EINVAL; + } + tuning_cfg->rescode_offset_bot[i] = 0x3f & offset_bot[i]; + } + + /* Drive level/amplitude adjustment parameters */ + ret = of_property_read_u32(dev->of_node, "qcom,phy-drive-ldo-level", &ldo_level); + if (ret && ret != -EINVAL) { + DRM_DEV_ERROR(dev, "failed to parse qcom,phy-drive-ldo-level, %d\n", ret); + return ret; + } + + switch (ldo_level) { + case 375: + level = 0; + break; + case 400: + level = 1; + break; + case 425: + level = 2; + break; + case 450: + level = 3; + break; + case 475: + level = 4; + break; + case 500: + level = 5; + break; + default: + DRM_DEV_ERROR(dev, "qcom,phy-drive-ldo-level %d is not supported\n", ldo_level); + return -EINVAL; + } + tuning_cfg->vreg_ctrl = 0x58 | (0x7 & level); + + phy->tuning_cfg = tuning_cfg; + + return 0; +} + +static const struct regulator_bulk_data dsi_phy_10nm_regulators[] = { + { .supply = "vdds", .init_load_uA = 36000 }, +}; + const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs = { .has_phy_lane = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vdds", 36000, 32}, - }, - }, + .regulator_data = dsi_phy_10nm_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_10nm_regulators), .ops = { .enable = dsi_10nm_phy_enable, .disable = dsi_10nm_phy_disable, .pll_init = dsi_pll_10nm_init, .save_pll_state = dsi_10nm_pll_save_state, .restore_pll_state = dsi_10nm_pll_restore_state, + .parse_dt_properties = dsi_10nm_phy_parse_dt, }, .min_pll_rate = 1000000000UL, .max_pll_rate = 3500000000UL, @@ -945,18 +1018,15 @@ const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs = { const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs = { .has_phy_lane = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vdds", 36000, 32}, - }, - }, + .regulator_data = dsi_phy_10nm_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_10nm_regulators), .ops = { .enable = dsi_10nm_phy_enable, .disable = dsi_10nm_phy_disable, .pll_init = dsi_pll_10nm_init, .save_pll_state = dsi_10nm_pll_save_state, .restore_pll_state = dsi_10nm_pll_restore_state, + .parse_dt_properties = dsi_10nm_phy_parse_dt, }, .min_pll_rate = 1000000000UL, .max_pll_rate = 3500000000UL, |
