msm: mdss: add support of dsi pll SSC for 8996

DSI SSC enabled through dtsi. Both down spread and
center spread are supported. Default is down spread
when SSC enabled.

Change-Id: I4c5ef632e5442ef610444ea5439d4bb78541791b
Signed-off-by: Kuogee Hsieh <khsieh@codeaurora.org>
This commit is contained in:
Kuogee Hsieh 2015-05-29 09:38:54 -07:00 committed by David Keitel
parent fc534490e0
commit f1f853212f
5 changed files with 132 additions and 16 deletions

View file

@ -27,6 +27,11 @@ Optional properties:
- label: A string used to describe the driver used.
- vcca-supply: Phandle for vcca regulator device node.
- qcom,dsi-pll-ssc-en: Boolean property to indicate that ssc is enabled.
- qcom,dsi-pll-ssc-mode: Spread-spectrum clocking. It can be either "down-spread"
or "center-spread". Default is "down-spread" if it is not specified.
- qcom,platform-supply-entries: A node that lists the elements of the supply. There
can be more than one instance of this binding,
in which case the entry would be appended with
@ -64,6 +69,8 @@ Example:
clock-rate = <0>, <0>, <0>;
qcom,dsi-pll-slave;
qcom,dsi-pll-ssc-en:
qcom,dsi-pll-ssc-mode = "down-spread";
qcom,platform-supply-entries {
#address-cells = <1>;

View file

@ -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(pdb, pll);
pll_8996_dec_frac_calc(pll, pdb);
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);

View file

@ -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 */

View file

@ -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) {

View file

@ -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;
/*