diff options
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c | 115 | ||||
-rw-r--r-- | drivers/clk/msm/mdss/mdss-dsi-pll-8996.h | 13 | ||||
-rw-r--r-- | drivers/clk/msm/mdss/mdss-pll.c | 10 | ||||
-rw-r--r-- | drivers/clk/msm/mdss/mdss-pll.h | 3 |
4 files changed, 125 insertions, 16 deletions
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c index 10aa2bd16928..438bed4f7c03 100644 --- a/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c +++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c @@ -26,6 +26,8 @@ #define DSI_PLL_POLL_TIMEOUT_US 1000 #define MSM8996_DSI_PLL_REVISION_2 2 +#define CEIL(x, y) (((x) + ((y)-1)) / (y)) + int set_mdss_byte_mux_sel_8996(struct mux_clk *clk, int sel) { return 0; @@ -303,12 +305,13 @@ static void dsi_pll_disable(struct clk *c) return; } -static void mdss_dsi_pll_8996_input_init(struct dsi_pll_db *pdb) +static void mdss_dsi_pll_8996_input_init(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) { pdb->in.fref = 19200000; /* 19.2 Mhz*/ pdb->in.fdata = 0; /* bit clock rate */ pdb->in.dsiclk_sel = 1; /* 1, reg: 0x0014 */ - pdb->in.ssc_en = 0; /* 1, reg: 0x0494, bit 0 */ + pdb->in.ssc_en = pll->ssc_en; /* 1, reg: 0x0494, bit 0 */ pdb->in.ldo_en = 0; /* 0, reg: 0x004c, bit 0 */ /* fixed input */ @@ -319,8 +322,8 @@ static void mdss_dsi_pll_8996_input_init(struct dsi_pll_db *pdb) pdb->in.pll_wakeup_timer = 5; /* 5, reg: 0x043c, bit 0 - 2 */ pdb->in.plllock_cnt = 1; /* 1, reg: 0x0488, bit 1 - 2 */ pdb->in.plllock_rng = 0; /* 0, reg: 0x0488, bit 3 - 4 */ - pdb->in.ssc_center_spread = 0; /* 0, reg: 0x0494, bit 1 */ - pdb->in.ssc_adj_per = 37; /* 37, reg: 0x498, bit 0 - 9 */ + pdb->in.ssc_center = pll->ssc_center;/* 0, reg: 0x0494, bit 1 */ + pdb->in.ssc_adj_period = 37; /* 37, reg: 0x498, bit 0 - 9 */ pdb->in.ssc_spread = 5; /* 0.005, 5kppm */ pdb->in.ssc_freq = 31500; /* 31.5 khz */ @@ -342,8 +345,49 @@ static void mdss_dsi_pll_8996_input_init(struct dsi_pll_db *pdb) pdb->in.pll_r3ctrl = 1; /* 1 */ } -static void pll_8996_dec_frac_calc(struct dsi_pll_db *pdb, - struct mdss_pll_resources *pll) +static void pll_8996_ssc_calc(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + u32 period, ssc_period; + u32 ref, rem; + s64 step_size; + + pr_debug("%s: vco=%lld ref=%lld\n", __func__, + pll->vco_current_rate, pll->vco_ref_clk_rate); + + ssc_period = pdb->in.ssc_freq / 500; + period = pll->vco_ref_clk_rate / 1000; + ssc_period = CEIL(period, ssc_period); + ssc_period -= 1; + pdb->out.ssc_period = ssc_period; + + pr_debug("%s: ssc, freq=%d spread=%d period=%d\n", __func__, + pdb->in.ssc_freq, pdb->in.ssc_spread, pdb->out.ssc_period); + + step_size = (u32)pll->vco_current_rate; + ref = pll->vco_ref_clk_rate; + ref /= 1000; + step_size = div_s64(step_size, ref); + step_size <<= 20; + step_size = div_s64(step_size, 1000); + step_size *= pdb->in.ssc_spread; + step_size = div_s64(step_size, 1000); + step_size *= (pdb->in.ssc_adj_period + 1); + + rem = 0; + step_size = div_s64_rem(step_size, ssc_period + 1, &rem); + if (rem) + step_size++; + + pr_debug("%s: step_size=%lld\n", __func__, step_size); + + step_size &= 0x0ffff; /* take lower 16 bits */ + + pdb->out.ssc_step_size = step_size; +} + +static void pll_8996_dec_frac_calc(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) { struct dsi_pll_input *pin = &pdb->in; struct dsi_pll_output *pout = &pdb->out; @@ -438,9 +482,47 @@ static void pll_8996_calc_vco_count(struct dsi_pll_db *pdb, pout->pll_kvco_code = 0; } -static void pll_db_commit_common(void __iomem *pll_base, +static void pll_db_commit_ssc(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + void __iomem *pll_base = pll->pll_base; + struct dsi_pll_input *pin = &pdb->in; + struct dsi_pll_output *pout = &pdb->out; + char data; + + data = pin->ssc_adj_period; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_ADJ_PER1, data); + data = (pin->ssc_adj_period >> 8); + data &= 0x03; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_ADJ_PER2, data); + + data = pout->ssc_period; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_PER1, data); + data = (pout->ssc_period >> 8); + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_PER2, data); + + data = pout->ssc_step_size; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_STEP_SIZE1, data); + data = (pout->ssc_step_size >> 8); + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_STEP_SIZE2, data); + + data = (pin->ssc_center & 0x01); + data <<= 1; + data |= 0x01; /* enable */ + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_EN_CENTER, data); + + wmb(); /* make sure register committed */ +} + +static void pll_db_commit_common(struct mdss_pll_resources *pll, struct dsi_pll_db *pdb) { + void __iomem *pll_base = pll->pll_base; struct dsi_pll_input *pin = &pdb->in; struct dsi_pll_output *pout = &pdb->out; char data; @@ -506,9 +588,10 @@ static void pll_db_commit_common(void __iomem *pll_base, MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_CRCTRL, data); } -static void pll_db_commit_8996(void __iomem *pll_base, +static void pll_db_commit_8996(struct mdss_pll_resources *pll, struct dsi_pll_db *pdb) { + void __iomem *pll_base = pll->pll_base; struct dsi_pll_input *pin = &pdb->in; struct dsi_pll_output *pout = &pdb->out; char data; @@ -516,7 +599,7 @@ static void pll_db_commit_8996(void __iomem *pll_base, data = pout->cmn_ldo_cntrl; MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_LDO_CNTRL, data); - pll_db_commit_common(pll_base, pdb); + pll_db_commit_common(pll, pdb); /* de assert pll start and apply pll sw reset */ /* stop pll */ @@ -590,6 +673,9 @@ static void pll_db_commit_8996(void __iomem *pll_base, data = (pout->pll_n1div | (pout->pll_n2div << 4)); MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CLK_CFG0, data); + if (pll->ssc_en) + pll_db_commit_ssc(pll, pdb); + wmb(); /* make sure register committed */ } @@ -691,9 +777,12 @@ int pll_vco_set_rate_8996(struct clk *c, unsigned long rate) pll->vco_current_rate = rate; pll->vco_ref_clk_rate = vco->ref_clk_rate; - mdss_dsi_pll_8996_input_init(pdb); + mdss_dsi_pll_8996_input_init(pll, pdb); + + pll_8996_dec_frac_calc(pll, pdb); - pll_8996_dec_frac_calc(pdb, pll); + if (pll->ssc_en) + pll_8996_ssc_calc(pll, pdb); pll_8996_calc_vco_count(pdb, pll->vco_current_rate, pll->vco_ref_clk_rate); @@ -701,10 +790,10 @@ int pll_vco_set_rate_8996(struct clk *c, unsigned long rate) /* commit slave if split display is enabled */ slave = pll->slave; if (slave) - pll_db_commit_8996(slave->pll_base, pdb); + pll_db_commit_8996(slave, pdb); /* commit master itself */ - pll_db_commit_8996(pll->pll_base, pdb); + pll_db_commit_8996(pll, pdb); mdss_pll_resource_enable(pll, false); diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8996.h b/drivers/clk/msm/mdss/mdss-dsi-pll-8996.h index 94c50acfb771..e78184376cc4 100644 --- a/drivers/clk/msm/mdss/mdss-dsi-pll-8996.h +++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8996.h @@ -52,6 +52,13 @@ #define DSIPHY_PLL_PLLLOCK_CMP_EN 0x0488 #define DSIPHY_PLL_DEC_START 0x0490 +#define DSIPHY_PLL_SSC_EN_CENTER 0x0494 +#define DSIPHY_PLL_SSC_ADJ_PER1 0x0498 +#define DSIPHY_PLL_SSC_ADJ_PER2 0x049c +#define DSIPHY_PLL_SSC_PER1 0x04a0 +#define DSIPHY_PLL_SSC_PER2 0x04a4 +#define DSIPHY_PLL_SSC_STEP_SIZE1 0x04a8 +#define DSIPHY_PLL_SSC_STEP_SIZE2 0x04ac #define DSIPHY_PLL_DIV_FRAC_START1 0x04b4 #define DSIPHY_PLL_DIV_FRAC_START2 0x04b8 #define DSIPHY_PLL_DIV_FRAC_START3 0x04bc @@ -85,8 +92,8 @@ struct dsi_pll_input { u32 pll_wakeup_timer; /* 5, reg: 0x043c, bit 0 - 2 */ u32 plllock_cnt; /* 1, reg: 0x0488, bit 1 - 2 */ u32 plllock_rng; /* 1, reg: 0x0488, bit 3 - 4 */ - u32 ssc_center_spread; /* 0, reg: 0x0494, bit 1 */ - u32 ssc_adj_per; /* 37, reg: 0x498, bit 0 - 9 */ + u32 ssc_center; /* 0, reg: 0x0494, bit 1 */ + u32 ssc_adj_period; /* 37, reg: 0x498, bit 0 - 9 */ u32 ssc_spread; /* 0.005 */ u32 ssc_freq; /* unknown */ u32 pll_ie_trim; /* 4, reg: 0x0400 */ @@ -115,7 +122,7 @@ struct dsi_pll_output { u32 pll_txclk_en; /* reg: 0x04c0 */ u32 dec_start; /* reg: 0x0490 */ u32 div_frac_start; /* reg: 0x04b4, 0x4b8, 0x04bc */ - u32 ssc_per; /* reg: 0x04a0, 0x04a4 */ + u32 ssc_period; /* reg: 0x04a0, 0x04a4 */ u32 ssc_step_size; /* reg: 0x04a8, 0x04ac */ u32 plllock_cmp; /* reg: 0x047c, 0x0480, 0x0484 */ u32 pll_vco_div_ref; /* reg: 0x046c, 0x0470 */ diff --git a/drivers/clk/msm/mdss/mdss-pll.c b/drivers/clk/msm/mdss/mdss-pll.c index bf118be406cb..81ae1defd29c 100644 --- a/drivers/clk/msm/mdss/mdss-pll.c +++ b/drivers/clk/msm/mdss/mdss-pll.c @@ -222,6 +222,16 @@ static int mdss_pll_probe(struct platform_device *pdev) pll_res->index = 0; } + pll_res->ssc_en = of_property_read_bool(pdev->dev.of_node, + "qcom,dsi-pll-ssc-en"); + + pll_res->ssc_center = false; + + label = of_get_property(pdev->dev.of_node, + "qcom,dsi-pll-ssc-mode", NULL); + if (label && !strcmp(label, "center-spread")) + pll_res->ssc_center = true; + pll_base_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_base"); if (!pll_base_reg) { diff --git a/drivers/clk/msm/mdss/mdss-pll.h b/drivers/clk/msm/mdss/mdss-pll.h index 365c21d3f0ca..79eb5abeaa83 100644 --- a/drivers/clk/msm/mdss/mdss-pll.h +++ b/drivers/clk/msm/mdss/mdss-pll.h @@ -124,6 +124,9 @@ struct mdss_pll_resources { */ uint32_t index; + bool ssc_en; /* share pll with master */ + bool ssc_center; /* default is down spread */ + struct mdss_pll_resources *slave; /* |