diff options
author | Casey Piper <cpiper@codeaurora.org> | 2015-07-24 11:40:35 -0700 |
---|---|---|
committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:43:01 -0700 |
commit | 45ebb6f6ed03acaf98959d09bdc8f1f4ae8ee228 (patch) | |
tree | 1c60ffe9d288624e39207c605988ad5b9ca3f1cc /drivers/clk/msm | |
parent | c41b5b1cc5b623af22a8ac3c775a90d331c13019 (diff) |
clk: mdss: hdmi: enable PLL value calculations for MSM8996V3
In the V3 revision of MSM8996, there is a different
recommended power on sequence. Update this sequence for
MSM8996V3 only with the new sequence and calculations.
Change-Id: I29612a3a4c9d148df61169c091015079ada6b41c
Signed-off-by: Casey Piper <cpiper@codeaurora.org>
Diffstat (limited to 'drivers/clk/msm')
-rw-r--r-- | drivers/clk/msm/mdss/mdss-hdmi-pll-8996.c | 487 | ||||
-rw-r--r-- | drivers/clk/msm/mdss/mdss-hdmi-pll.h | 3 | ||||
-rw-r--r-- | drivers/clk/msm/mdss/mdss-pll.c | 6 | ||||
-rw-r--r-- | drivers/clk/msm/mdss/mdss-pll.h | 1 |
4 files changed, 471 insertions, 26 deletions
diff --git a/drivers/clk/msm/mdss/mdss-hdmi-pll-8996.c b/drivers/clk/msm/mdss/mdss-hdmi-pll-8996.c index 682586a53526..f720b4e07eb5 100644 --- a/drivers/clk/msm/mdss/mdss-hdmi-pll-8996.c +++ b/drivers/clk/msm/mdss/mdss-hdmi-pll-8996.c @@ -34,7 +34,10 @@ #define HDMI_64B_ERR_VAL 0xFFFFFFFFFFFFFFFF #define HDMI_VERSION_8996_V1 1 #define HDMI_VERSION_8996_V2 2 +#define HDMI_VERSION_8996_V3 3 +#define HDMI_VCO_MAX_FREQ 12000000000 +#define HDMI_VCO_MIN_FREQ 8000000000 #define HDMI_2400MHZ_BIT_CLK_HZ 2400000000 #define HDMI_2250MHZ_BIT_CLK_HZ 2250000000 #define HDMI_2000MHZ_BIT_CLK_HZ 2000000000 @@ -79,23 +82,30 @@ #define QSERDES_COM_LOCK_CMP2_MODE1 (0x05C) #define QSERDES_COM_LOCK_CMP3_MODE1 (0x060) #define QSERDES_COM_LOCK_CMP1_MODE2 (0x064) +#define QSERDES_COM_CMN_RSVD0 (0x064) #define QSERDES_COM_LOCK_CMP2_MODE2 (0x068) +#define QSERDES_COM_EP_CLOCK_DETECT_CTRL (0x068) #define QSERDES_COM_LOCK_CMP3_MODE2 (0x06C) +#define QSERDES_COM_SYSCLK_DET_COMP_STATUS (0x06C) #define QSERDES_COM_BG_TRIM (0x070) #define QSERDES_COM_CLK_EP_DIV (0x074) #define QSERDES_COM_CP_CTRL_MODE0 (0x078) #define QSERDES_COM_CP_CTRL_MODE1 (0x07C) #define QSERDES_COM_CP_CTRL_MODE2 (0x080) +#define QSERDES_COM_CMN_RSVD1 (0x080) #define QSERDES_COM_PLL_RCTRL_MODE0 (0x084) #define QSERDES_COM_PLL_RCTRL_MODE1 (0x088) #define QSERDES_COM_PLL_RCTRL_MODE2 (0x08C) +#define QSERDES_COM_CMN_RSVD2 (0x08C) #define QSERDES_COM_PLL_CCTRL_MODE0 (0x090) #define QSERDES_COM_PLL_CCTRL_MODE1 (0x094) #define QSERDES_COM_PLL_CCTRL_MODE2 (0x098) +#define QSERDES_COM_CMN_RSVD3 (0x098) #define QSERDES_COM_PLL_CNTRL (0x09C) #define QSERDES_COM_PHASE_SEL_CTRL (0x0A0) #define QSERDES_COM_PHASE_SEL_DC (0x0A4) #define QSERDES_COM_CORE_CLK_IN_SYNC_SEL (0x0A8) +#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM (0x0A8) #define QSERDES_COM_SYSCLK_EN_SEL (0x0AC) #define QSERDES_COM_CML_SYSCLK_SEL (0x0B0) #define QSERDES_COM_RESETSM_CNTRL (0x0B4) @@ -108,6 +118,7 @@ #define QSERDES_COM_DEC_START_MODE0 (0x0D0) #define QSERDES_COM_DEC_START_MODE1 (0x0D4) #define QSERDES_COM_DEC_START_MODE2 (0x0D8) +#define QSERDES_COM_VCOCAL_DEADMAN_CTRL (0x0D8) #define QSERDES_COM_DIV_FRAC_START1_MODE0 (0x0DC) #define QSERDES_COM_DIV_FRAC_START2_MODE0 (0x0E0) #define QSERDES_COM_DIV_FRAC_START3_MODE0 (0x0E4) @@ -115,8 +126,11 @@ #define QSERDES_COM_DIV_FRAC_START2_MODE1 (0x0EC) #define QSERDES_COM_DIV_FRAC_START3_MODE1 (0x0F0) #define QSERDES_COM_DIV_FRAC_START1_MODE2 (0x0F4) +#define QSERDES_COM_VCO_TUNE_MINVAL1 (0x0F4) #define QSERDES_COM_DIV_FRAC_START2_MODE2 (0x0F8) +#define QSERDES_COM_VCO_TUNE_MINVAL2 (0x0F8) #define QSERDES_COM_DIV_FRAC_START3_MODE2 (0x0FC) +#define QSERDES_COM_CMN_RSVD4 (0x0FC) #define QSERDES_COM_INTEGLOOP_INITVAL (0x100) #define QSERDES_COM_INTEGLOOP_EN (0x104) #define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 (0x108) @@ -124,7 +138,9 @@ #define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 (0x110) #define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 (0x114) #define QSERDES_COM_INTEGLOOP_GAIN0_MODE2 (0x118) +#define QSERDES_COM_VCO_TUNE_MAXVAL1 (0x118) #define QSERDES_COM_INTEGLOOP_GAIN1_MODE2 (0x11C) +#define QSERDES_COM_VCO_TUNE_MAXVAL2 (0x11C) #define QSERDES_COM_RES_TRIM_CONTROL2 (0x120) #define QSERDES_COM_VCO_TUNE_CTRL (0x124) #define QSERDES_COM_VCO_TUNE_MAP (0x128) @@ -133,7 +149,9 @@ #define QSERDES_COM_VCO_TUNE1_MODE1 (0x134) #define QSERDES_COM_VCO_TUNE2_MODE1 (0x138) #define QSERDES_COM_VCO_TUNE1_MODE2 (0x13C) +#define QSERDES_COM_VCO_TUNE_INITVAL1 (0x13C) #define QSERDES_COM_VCO_TUNE2_MODE2 (0x140) +#define QSERDES_COM_VCO_TUNE_INITVAL2 (0x140) #define QSERDES_COM_VCO_TUNE_TIMER1 (0x144) #define QSERDES_COM_VCO_TUNE_TIMER2 (0x148) #define QSERDES_COM_SAR (0x14C) @@ -166,6 +184,7 @@ #define QSERDES_COM_CMN_MISC2 (0x1B8) #define QSERDES_COM_CORECLK_DIV_MODE1 (0x1BC) #define QSERDES_COM_CORECLK_DIV_MODE2 (0x1C0) +#define QSERDES_COM_CMN_RSVD5 (0x1C0) /* Tx Channel base addresses */ #define HDMI_TX_L0_BASE_OFFSET (0x400) @@ -315,6 +334,8 @@ enum hdmi_pll_freqs { }; struct hdmi_8996_phy_pll_reg_cfg { + u32 tx_l0_lane_mode; + u32 tx_l2_lane_mode; u32 tx_l0_tx_band; u32 tx_l1_tx_band; u32 tx_l2_tx_band; @@ -363,6 +384,14 @@ struct hdmi_8996_phy_pll_reg_cfg { u32 phy_mode; }; +struct hdmi_8996_v3_post_divider { + u64 vco_freq; + u64 hsclk_divsel; + u64 vco_ratio; + u64 tx_band_sel; + u64 half_rate_mode; +}; + static inline struct hdmi_pll_vco_clk *to_hdmi_8996_vco_clk(struct clk *clk) { return container_of(clk, struct hdmi_pll_vco_clk, c); @@ -587,6 +616,17 @@ static inline u64 hdmi_8996_get_integloop_gain(u64 frac_start, bool gen_ssc) return 0xC4; } +static inline u64 hdmi_8996_v3_get_integloop_gain(u64 frac_start, u64 bclk, + bool gen_ssc) +{ + u64 digclk_divsel = bclk >= HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2; + u64 base = ((frac_start != 0) || (gen_ssc == true)) ? 0x40 : 0xC4; + + base <<= digclk_divsel; + + return (base <= 2046 ? base : 0x7FE); +} + static inline u64 hdmi_8996_get_vco_tune(u64 fdata, u64 div) { u64 vco_tune; @@ -612,6 +652,117 @@ static inline u64 hdmi_8996_get_pll_cmp(u64 pll_cmp_cnt, u64 core_clk) return pll_cmp; } +static inline u64 hdmi_8996_v3_get_pll_cmp(u64 pll_cmp_cnt, u64 fdata) +{ + u64 dividend = pll_cmp_cnt * fdata; + u64 divisor = HDMI_REF_CLOCK * 10; + u64 rem; + + rem = do_div(dividend, divisor); + if (rem > (divisor >> 1)) + dividend++; + + return dividend - 1; +} + +static int hdmi_8996_v3_get_post_div(struct hdmi_8996_v3_post_divider *pd, + u64 bclk) +{ + u32 ratio[] = {2, 3, 4, 5, 6, 9, 10, 12, 14, 15, 20, 21, 25, 28, 35}; + u32 tx_band_sel[] = {0, 1, 2, 3}; + u64 vco_freq[60]; + u64 vco, vco_optimal, half_rate_mode = 0; + int vco_optimal_index, vco_freq_index; + int i, j, k, x; + + for (i = 0; i <= 1; i++) { + vco_optimal = HDMI_VCO_MAX_FREQ; + vco_optimal_index = -1; + vco_freq_index = 0; + for (j = 0; j < 15; j++) { + for (k = 0; k < 4; k++) { + u64 ratio_mult = ratio[j] << tx_band_sel[k]; + + vco = bclk >> half_rate_mode; + vco *= ratio_mult; + vco_freq[vco_freq_index++] = vco; + } + } + + for (x = 0; x < 60; x++) { + u64 vco_tmp = vco_freq[x]; + + if ((vco_tmp >= HDMI_VCO_MIN_FREQ) && + (vco_tmp <= vco_optimal)) { + vco_optimal = vco_tmp; + vco_optimal_index = x; + } + } + + if (vco_optimal_index == -1) { + if (!half_rate_mode) + half_rate_mode++; + else + return -EINVAL; + } else { + pd->vco_freq = vco_optimal; + pd->tx_band_sel = tx_band_sel[vco_optimal_index % 4]; + pd->vco_ratio = ratio[vco_optimal_index / 4]; + break; + } + } + + switch (pd->vco_ratio) { + case 2: + pd->hsclk_divsel = 0; + break; + case 3: + pd->hsclk_divsel = 4; + break; + case 4: + pd->hsclk_divsel = 8; + break; + case 5: + pd->hsclk_divsel = 12; + break; + case 6: + pd->hsclk_divsel = 1; + break; + case 9: + pd->hsclk_divsel = 5; + break; + case 10: + pd->hsclk_divsel = 2; + break; + case 12: + pd->hsclk_divsel = 9; + break; + case 14: + pd->hsclk_divsel = 3; + break; + case 15: + pd->hsclk_divsel = 13; + break; + case 20: + pd->hsclk_divsel = 10; + break; + case 21: + pd->hsclk_divsel = 7; + break; + case 25: + pd->hsclk_divsel = 14; + break; + case 28: + pd->hsclk_divsel = 11; + break; + case 35: + pd->hsclk_divsel = 15; + break; + }; + + return 0; +} + static int hdmi_8996_v1_calculate(u32 pix_clk, struct hdmi_8996_phy_pll_reg_cfg *cfg) { @@ -727,6 +878,8 @@ static int hdmi_8996_v1_calculate(u32 pix_clk, DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp); /* Convert these values to register specific values */ + cfg->tx_l0_lane_mode = 0x3; + cfg->tx_l2_lane_mode = 0x3; cfg->tx_l0_tx_band = tx_band + 4; cfg->tx_l1_tx_band = tx_band + 4; cfg->tx_l2_tx_band = tx_band + 4; @@ -814,6 +967,8 @@ static int hdmi_8996_v1_calculate(u32 pix_clk, cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0; DEV_DBG("HDMI 8996 PLL: PLL Settings\n"); + DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode); + DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode); DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band); DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band); DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band); @@ -989,6 +1144,8 @@ static int hdmi_8996_v2_calculate(u32 pix_clk, DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp); /* Convert these values to register specific values */ + cfg->tx_l0_lane_mode = 0x3; + cfg->tx_l2_lane_mode = 0x3; cfg->tx_l0_tx_band = tx_band + 4; cfg->tx_l1_tx_band = tx_band + 4; cfg->tx_l2_tx_band = tx_band + 4; @@ -1086,6 +1243,8 @@ static int hdmi_8996_v2_calculate(u32 pix_clk, cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0; DEV_DBG("HDMI 8996 PLL: PLL Settings\n"); + DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode); + DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode); DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band); DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band); DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band); @@ -1160,10 +1319,232 @@ fail: return rc; } +static int hdmi_8996_v3_calculate(u32 pix_clk, + struct hdmi_8996_phy_pll_reg_cfg *cfg) +{ + int rc = -EINVAL; + struct hdmi_8996_v3_post_divider pd; + u64 fdata, tmds_clk; + u64 bclk; + u64 pll_cmp; + u64 tx_band; + u64 hsclk; + u64 dec_start; + u64 frac_start; + u64 pll_divisor = 4 * HDMI_REF_CLOCK; + u64 cpctrl; + u64 rctrl; + u64 cctrl; + u64 integloop_gain; + u64 vco_freq; + u64 rem; + + /* FDATA, HSCLK, PIXEL_CLK, TMDS_CLK */ + bclk = ((u64)pix_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO; + + if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) + tmds_clk = pix_clk >> 2; + else + tmds_clk = pix_clk; + + if (hdmi_8996_v3_get_post_div(&pd, bclk) || pd.vco_ratio <= 0 || + pd.vco_freq <= 0) + goto fail; + + vco_freq = pd.vco_freq; + fdata = pd.vco_freq; + do_div(fdata, pd.vco_ratio); + + hsclk = pd.hsclk_divsel; + dec_start = vco_freq; + do_div(dec_start, pll_divisor); + + frac_start = vco_freq * (1 << 20); + rem = do_div(frac_start, pll_divisor); + frac_start -= dec_start * (1 << 20); + if (rem > (pll_divisor >> 1)) + frac_start++; + + cpctrl = hdmi_8996_get_cpctrl(frac_start, false); + rctrl = hdmi_8996_get_rctrl(frac_start, false); + cctrl = hdmi_8996_get_cctrl(frac_start, false); + integloop_gain = hdmi_8996_v3_get_integloop_gain(frac_start, bclk, + false); + pll_cmp = hdmi_8996_v3_get_pll_cmp(1024, fdata); + tx_band = pd.tx_band_sel; + + /* Debug dump */ + DEV_DBG("%s: VCO freq: %llu\n", __func__, vco_freq); + DEV_DBG("%s: fdata: %llu\n", __func__, fdata); + DEV_DBG("%s: pix_clk: %d\n", __func__, pix_clk); + DEV_DBG("%s: tmds clk: %llu\n", __func__, tmds_clk); + DEV_DBG("%s: HSCLK_SEL: %llu\n", __func__, hsclk); + DEV_DBG("%s: DEC_START: %llu\n", __func__, dec_start); + DEV_DBG("%s: DIV_FRAC_START: %llu\n", __func__, frac_start); + DEV_DBG("%s: PLL_CPCTRL: %llu\n", __func__, cpctrl); + DEV_DBG("%s: PLL_RCTRL: %llu\n", __func__, rctrl); + DEV_DBG("%s: PLL_CCTRL: %llu\n", __func__, cctrl); + DEV_DBG("%s: INTEGLOOP_GAIN: %llu\n", __func__, integloop_gain); + DEV_DBG("%s: TX_BAND: %llu\n", __func__, tx_band); + DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp); + + /* Convert these values to register specific values */ + cfg->tx_l0_tx_band = tx_band + 4; + cfg->tx_l1_tx_band = tx_band + 4; + cfg->tx_l2_tx_band = tx_band + 4; + cfg->tx_l3_tx_band = tx_band + 4; + + if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) + cfg->com_svs_mode_clk_sel = 1; + else + cfg->com_svs_mode_clk_sel = 2; + + cfg->com_hsclk_sel = (0x20 | hsclk); + cfg->com_pll_cctrl_mode0 = cctrl; + cfg->com_pll_rctrl_mode0 = rctrl; + cfg->com_cp_ctrl_mode0 = cpctrl; + cfg->com_dec_start_mode0 = dec_start; + cfg->com_div_frac_start1_mode0 = (frac_start & 0xFF); + cfg->com_div_frac_start2_mode0 = ((frac_start & 0xFF00) >> 8); + cfg->com_div_frac_start3_mode0 = ((frac_start & 0xF0000) >> 16); + cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xFF); + cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xF00) >> 8); + cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xFF); + cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8); + cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16); + cfg->com_lock_cmp_en = 0x0; + cfg->com_core_clk_en = 0x2C; + cfg->com_coreclk_div = HDMI_CORECLK_DIV; + cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0; + cfg->com_vco_tune_ctrl = 0x0; + + cfg->tx_l0_lane_mode = (pd.half_rate_mode ? 0x7 : 0x3); + cfg->tx_l2_lane_mode = (pd.half_rate_mode ? 0x7 : 0x3); + + if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) { + cfg->tx_l0_tx_drv_lvl = 0x25; + cfg->tx_l0_tx_emp_post1_lvl = 0x23; + cfg->tx_l1_tx_drv_lvl = 0x25; + cfg->tx_l1_tx_emp_post1_lvl = 0x23; + cfg->tx_l2_tx_drv_lvl = 0x25; + cfg->tx_l2_tx_emp_post1_lvl = 0x23; + cfg->tx_l3_tx_drv_lvl = 0x22; + cfg->tx_l3_tx_emp_post1_lvl = 0x27; + cfg->tx_l0_vmode_ctrl1 = 0x00; + cfg->tx_l0_vmode_ctrl2 = 0x0D; + cfg->tx_l1_vmode_ctrl1 = 0x00; + cfg->tx_l1_vmode_ctrl2 = 0x0D; + cfg->tx_l2_vmode_ctrl1 = 0x00; + cfg->tx_l2_vmode_ctrl2 = 0x0D; + cfg->tx_l3_vmode_ctrl1 = 0x00; + cfg->tx_l3_vmode_ctrl2 = 0x00; + } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) { + cfg->tx_l0_tx_drv_lvl = 0x25; + cfg->tx_l0_tx_emp_post1_lvl = 0x23; + cfg->tx_l1_tx_drv_lvl = 0x25; + cfg->tx_l1_tx_emp_post1_lvl = 0x23; + cfg->tx_l2_tx_drv_lvl = 0x25; + cfg->tx_l2_tx_emp_post1_lvl = 0x23; + cfg->tx_l3_tx_drv_lvl = 0x25; + cfg->tx_l3_tx_emp_post1_lvl = 0x23; + cfg->tx_l0_vmode_ctrl1 = 0x00; + cfg->tx_l0_vmode_ctrl2 = 0x0D; + cfg->tx_l1_vmode_ctrl1 = 0x00; + cfg->tx_l1_vmode_ctrl2 = 0x0D; + cfg->tx_l2_vmode_ctrl1 = 0x00; + cfg->tx_l2_vmode_ctrl2 = 0x0D; + cfg->tx_l3_vmode_ctrl1 = 0x00; + cfg->tx_l3_vmode_ctrl2 = 0x00; + } else { + cfg->tx_l0_tx_drv_lvl = 0x20; + cfg->tx_l0_tx_emp_post1_lvl = 0x20; + cfg->tx_l1_tx_drv_lvl = 0x20; + cfg->tx_l1_tx_emp_post1_lvl = 0x20; + cfg->tx_l2_tx_drv_lvl = 0x20; + cfg->tx_l2_tx_emp_post1_lvl = 0x20; + cfg->tx_l3_tx_drv_lvl = 0x20; + cfg->tx_l3_tx_emp_post1_lvl = 0x20; + cfg->tx_l0_vmode_ctrl1 = 0x00; + cfg->tx_l0_vmode_ctrl2 = 0x0E; + cfg->tx_l1_vmode_ctrl1 = 0x00; + cfg->tx_l1_vmode_ctrl2 = 0x0E; + cfg->tx_l2_vmode_ctrl1 = 0x00; + cfg->tx_l2_vmode_ctrl2 = 0x0E; + cfg->tx_l3_vmode_ctrl1 = 0x00; + cfg->tx_l3_vmode_ctrl2 = 0x0E; + } + + DEV_DBG("HDMI 8996 PLL: PLL Settings\n"); + DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band); + DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band); + DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band); + DEV_DBG("PLL PARAM: tx_l3_tx_band = 0x%x\n", cfg->tx_l3_tx_band); + DEV_DBG("PLL PARAM: com_svs_mode_clk_sel = 0x%x\n", + cfg->com_svs_mode_clk_sel); + DEV_DBG("PLL PARAM: com_hsclk_sel = 0x%x\n", cfg->com_hsclk_sel); + DEV_DBG("PLL PARAM: com_lock_cmp_en = 0x%x\n", cfg->com_lock_cmp_en); + DEV_DBG("PLL PARAM: com_pll_cctrl_mode0 = 0x%x\n", + cfg->com_pll_cctrl_mode0); + DEV_DBG("PLL PARAM: com_pll_rctrl_mode0 = 0x%x\n", + cfg->com_pll_rctrl_mode0); + DEV_DBG("PLL PARAM: com_cp_ctrl_mode0 = 0x%x\n", + cfg->com_cp_ctrl_mode0); + DEV_DBG("PLL PARAM: com_dec_start_mode0 = 0x%x\n", + cfg->com_dec_start_mode0); + DEV_DBG("PLL PARAM: com_div_frac_start1_mode0 = 0x%x\n", + cfg->com_div_frac_start1_mode0); + DEV_DBG("PLL PARAM: com_div_frac_start2_mode0 = 0x%x\n", + cfg->com_div_frac_start2_mode0); + DEV_DBG("PLL PARAM: com_div_frac_start3_mode0 = 0x%x\n", + cfg->com_div_frac_start3_mode0); + DEV_DBG("PLL PARAM: com_integloop_gain0_mode0 = 0x%x\n", + cfg->com_integloop_gain0_mode0); + DEV_DBG("PLL PARAM: com_integloop_gain1_mode0 = 0x%x\n", + cfg->com_integloop_gain1_mode0); + DEV_DBG("PLL PARAM: com_lock_cmp1_mode0 = 0x%x\n", + cfg->com_lock_cmp1_mode0); + DEV_DBG("PLL PARAM: com_lock_cmp2_mode0 = 0x%x\n", + cfg->com_lock_cmp2_mode0); + DEV_DBG("PLL PARAM: com_lock_cmp3_mode0 = 0x%x\n", + cfg->com_lock_cmp3_mode0); + DEV_DBG("PLL PARAM: com_core_clk_en = 0x%x\n", cfg->com_core_clk_en); + DEV_DBG("PLL PARAM: com_coreclk_div = 0x%x\n", cfg->com_coreclk_div); + DEV_DBG("PLL PARAM: phy_mode = 0x%x\n", cfg->phy_mode); + + DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode); + DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode); + DEV_DBG("PLL PARAM: l0_tx_drv_lvl = 0x%x\n", cfg->tx_l0_tx_drv_lvl); + DEV_DBG("PLL PARAM: l0_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l0_tx_emp_post1_lvl); + DEV_DBG("PLL PARAM: l1_tx_drv_lvl = 0x%x\n", cfg->tx_l1_tx_drv_lvl); + DEV_DBG("PLL PARAM: l1_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l1_tx_emp_post1_lvl); + DEV_DBG("PLL PARAM: l2_tx_drv_lvl = 0x%x\n", cfg->tx_l2_tx_drv_lvl); + DEV_DBG("PLL PARAM: l2_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l2_tx_emp_post1_lvl); + DEV_DBG("PLL PARAM: l3_tx_drv_lvl = 0x%x\n", cfg->tx_l3_tx_drv_lvl); + DEV_DBG("PLL PARAM: l3_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l3_tx_emp_post1_lvl); + + DEV_DBG("PLL PARAM: l0_vmode_ctrl1 = 0x%x\n", cfg->tx_l0_vmode_ctrl1); + DEV_DBG("PLL PARAM: l0_vmode_ctrl2 = 0x%x\n", cfg->tx_l0_vmode_ctrl2); + DEV_DBG("PLL PARAM: l1_vmode_ctrl1 = 0x%x\n", cfg->tx_l1_vmode_ctrl1); + DEV_DBG("PLL PARAM: l1_vmode_ctrl2 = 0x%x\n", cfg->tx_l1_vmode_ctrl2); + DEV_DBG("PLL PARAM: l2_vmode_ctrl1 = 0x%x\n", cfg->tx_l2_vmode_ctrl1); + DEV_DBG("PLL PARAM: l2_vmode_ctrl2 = 0x%x\n", cfg->tx_l2_vmode_ctrl2); + DEV_DBG("PLL PARAM: l3_vmode_ctrl1 = 0x%x\n", cfg->tx_l3_vmode_ctrl1); + DEV_DBG("PLL PARAM: l3_vmode_ctrl2 = 0x%x\n", cfg->tx_l3_vmode_ctrl2); + rc = 0; +fail: + return rc; +} + static int hdmi_8996_calculate(u32 pix_clk, struct hdmi_8996_phy_pll_reg_cfg *cfg, u32 ver) { switch (ver) { + case HDMI_VERSION_8996_V3: + return hdmi_8996_v3_calculate(pix_clk, cfg); case HDMI_VERSION_8996_V2: return hdmi_8996_v2_calculate(pix_clk, cfg); default: @@ -1190,8 +1571,12 @@ static int hdmi_8996_phy_pll_set_clk_rate(struct clk *c, u32 tmds_clk, u32 ver) udelay(500); /* Power up sequence */ - if (ver == HDMI_VERSION_8996_V2) + switch (ver) { + case HDMI_VERSION_8996_V2: + case HDMI_VERSION_8996_V3: MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x04); + break; + }; MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x1); MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESETSM_CNTRL, 0x20); @@ -1205,10 +1590,11 @@ static int hdmi_8996_phy_pll_set_clk_rate(struct clk *c, u32 tmds_clk, u32 ver) QSERDES_TX_L0_CLKBUF_ENABLE, 0x03); MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, QSERDES_TX_L0_CLKBUF_ENABLE, 0x03); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, - QSERDES_TX_L0_LANE_MODE, 0x03); + QSERDES_TX_L0_LANE_MODE, cfg.tx_l0_lane_mode); MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, - QSERDES_TX_L0_LANE_MODE, 0x03); + QSERDES_TX_L0_LANE_MODE, cfg.tx_l2_lane_mode); MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, QSERDES_TX_L0_TX_BAND, cfg.tx_l0_tx_band); @@ -1245,12 +1631,14 @@ static int hdmi_8996_phy_pll_set_clk_rate(struct clk *c, u32 tmds_clk, u32 ver) MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE_CTRL, cfg.com_vco_tune_ctrl); - if (ver == HDMI_VERSION_8996_V1) + switch (ver) { + case HDMI_VERSION_8996_V1: MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL, cfg.com_svs_mode_clk_sel); - - if (ver == HDMI_VERSION_8996_V2) + break; + default: MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x06); + } MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CLK_SELECT, 0x30); MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_HSCLK_SEL, @@ -1292,6 +1680,9 @@ static int hdmi_8996_phy_pll_set_clk_rate(struct clk *c, u32 tmds_clk, u32 ver) cfg.com_coreclk_div); MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_CONFIG, 0x02); + if (ver == HDMI_VERSION_8996_V3) + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESCODE_DIV_NUM, 0x15); + /* TX lanes setup (TX 0/1/2/3) */ MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, QSERDES_TX_L0_TX_DRV_LVL, @@ -1367,23 +1758,25 @@ static int hdmi_8996_phy_pll_set_clk_rate(struct clk *c, u32 tmds_clk, u32 ver) MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00); - MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, - QSERDES_TX_L0_RES_CODE_LANE_TX, - cfg.tx_l0_res_code_lane_tx); - MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, - QSERDES_TX_L0_RES_CODE_LANE_TX, - cfg.tx_l1_res_code_lane_tx); - MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, - QSERDES_TX_L0_RES_CODE_LANE_TX, - cfg.tx_l2_res_code_lane_tx); - MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, - QSERDES_TX_L0_RES_CODE_LANE_TX, - cfg.tx_l3_res_code_lane_tx); - MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESTRIM_CTRL, - cfg.com_restrim_ctrl); - - MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TXCAL_CFG0, 0x00); - MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TXCAL_CFG1, 0x05); + if (ver < HDMI_VERSION_8996_V3) { + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_RES_CODE_LANE_TX, + cfg.tx_l0_res_code_lane_tx); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_RES_CODE_LANE_TX, + cfg.tx_l1_res_code_lane_tx); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_RES_CODE_LANE_TX, + cfg.tx_l2_res_code_lane_tx); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_RES_CODE_LANE_TX, + cfg.tx_l3_res_code_lane_tx); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESTRIM_CTRL, + cfg.com_restrim_ctrl); + + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TXCAL_CFG0, 0x00); + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TXCAL_CFG1, 0x05); + } MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_MODE, cfg.phy_mode); MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x1F); @@ -1678,11 +2071,12 @@ static int hdmi_8996_v2_perform_sw_calibration(struct clk *c) static int hdmi_8996_perform_sw_calibration(struct clk *c, u32 ver) { switch (ver) { + case HDMI_VERSION_8996_V1: + return hdmi_8996_v1_perform_sw_calibration(c); case HDMI_VERSION_8996_V2: return hdmi_8996_v2_perform_sw_calibration(c); - default: - return hdmi_8996_v1_perform_sw_calibration(c); } + return 0; } static int hdmi_8996_vco_enable(struct clk *c, u32 ver) @@ -1754,6 +2148,11 @@ static int hdmi_8996_v2_vco_enable(struct clk *c) return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V2); } +static int hdmi_8996_v3_vco_enable(struct clk *c) +{ + return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V3); +} + static int hdmi_8996_vco_set_rate(struct clk *c, unsigned long rate, u32 ver) { struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); @@ -1802,6 +2201,11 @@ static int hdmi_8996_v2_vco_set_rate(struct clk *c, unsigned long rate) return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V2); } +static int hdmi_8996_v3_vco_set_rate(struct clk *c, unsigned long rate) +{ + return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V3); +} + static unsigned long hdmi_8996_vco_get_rate(struct clk *c) { unsigned long freq = 0; @@ -1848,6 +2252,11 @@ static int hdmi_8996_v2_vco_prepare(struct clk *c) return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V2); } +static int hdmi_8996_v3_vco_prepare(struct clk *c) +{ + return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V3); +} + static void hdmi_8996_vco_unprepare(struct clk *c) { struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); @@ -1927,6 +2336,16 @@ static struct clk_ops hdmi_8996_v2_vco_clk_ops = { .handoff = hdmi_8996_vco_handoff, }; +static struct clk_ops hdmi_8996_v3_vco_clk_ops = { + .enable = hdmi_8996_v3_vco_enable, + .set_rate = hdmi_8996_v3_vco_set_rate, + .get_rate = hdmi_8996_vco_get_rate, + .round_rate = hdmi_8996_vco_round_rate, + .prepare = hdmi_8996_v3_vco_prepare, + .unprepare = hdmi_8996_vco_unprepare, + .handoff = hdmi_8996_vco_handoff, +}; + static struct hdmi_pll_vco_clk hdmi_vco_clk = { .c = { .dbg_name = "hdmi_8996_vco_clk", @@ -1951,8 +2370,17 @@ int hdmi_8996_pll_clock_register(struct platform_device *pdev, /* Set client data for vco, mux and div clocks */ hdmi_vco_clk.priv = pll_res; - if (ver == HDMI_VERSION_8996_V2) + switch (ver) { + case HDMI_VERSION_8996_V2: hdmi_vco_clk.c.ops = &hdmi_8996_v2_vco_clk_ops; + break; + case HDMI_VERSION_8996_V3: + hdmi_vco_clk.c.ops = &hdmi_8996_v3_vco_clk_ops; + break; + default: + hdmi_vco_clk.c.ops = &hdmi_8996_v1_vco_clk_ops; + break; + }; rc = of_msm_clock_register(pdev->dev.of_node, hdmipllcc_8996, ARRAY_SIZE(hdmipllcc_8996)); @@ -1979,3 +2407,10 @@ int hdmi_8996_v2_pll_clock_register(struct platform_device *pdev, return hdmi_8996_pll_clock_register(pdev, pll_res, HDMI_VERSION_8996_V2); } + +int hdmi_8996_v3_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + return hdmi_8996_pll_clock_register(pdev, pll_res, + HDMI_VERSION_8996_V3); +} diff --git a/drivers/clk/msm/mdss/mdss-hdmi-pll.h b/drivers/clk/msm/mdss/mdss-hdmi-pll.h index 340b0e7a436d..f281ce761ce0 100644 --- a/drivers/clk/msm/mdss/mdss-hdmi-pll.h +++ b/drivers/clk/msm/mdss/mdss-hdmi-pll.h @@ -44,4 +44,7 @@ int hdmi_8996_v1_pll_clock_register(struct platform_device *pdev, int hdmi_8996_v2_pll_clock_register(struct platform_device *pdev, struct mdss_pll_resources *pll_res); + +int hdmi_8996_v3_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); #endif diff --git a/drivers/clk/msm/mdss/mdss-pll.c b/drivers/clk/msm/mdss/mdss-pll.c index 81ae1defd29c..dfa7af3ba78e 100644 --- a/drivers/clk/msm/mdss/mdss-pll.c +++ b/drivers/clk/msm/mdss/mdss-pll.c @@ -138,6 +138,8 @@ static int mdss_pll_resource_parse(struct platform_device *pdev, pll_res->pll_interface_type = MDSS_HDMI_PLL_8996; } else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996_v2")) { pll_res->pll_interface_type = MDSS_HDMI_PLL_8996_V2; + } else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996_v3")) { + pll_res->pll_interface_type = MDSS_HDMI_PLL_8996_V3; } else { goto err; } @@ -170,6 +172,9 @@ static int mdss_pll_clock_register(struct platform_device *pdev, case MDSS_HDMI_PLL_8996_V2: rc = hdmi_8996_v2_pll_clock_register(pdev, pll_res); break; + case MDSS_HDMI_PLL_8996_V3: + rc = hdmi_8996_v3_pll_clock_register(pdev, pll_res); + break; case MDSS_UNKNOWN_PLL: default: rc = -EINVAL; @@ -359,6 +364,7 @@ static const struct of_device_id mdss_pll_dt_match[] = { {.compatible = "qcom,mdss_dsi_pll_8996_v2"}, {.compatible = "qcom,mdss_hdmi_pll_8996"}, {.compatible = "qcom,mdss_hdmi_pll_8996_v2"}, + {.compatible = "qcom,mdss_hdmi_pll_8996_v3"}, {} }; diff --git a/drivers/clk/msm/mdss/mdss-pll.h b/drivers/clk/msm/mdss/mdss-pll.h index 79eb5abeaa83..e30db3af5ac4 100644 --- a/drivers/clk/msm/mdss/mdss-pll.h +++ b/drivers/clk/msm/mdss/mdss-pll.h @@ -31,6 +31,7 @@ enum { MDSS_DSI_PLL_8996, MDSS_HDMI_PLL_8996, MDSS_HDMI_PLL_8996_V2, + MDSS_HDMI_PLL_8996_V3, MDSS_UNKNOWN_PLL, }; |