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. - label: A string used to describe the driver used.
- vcca-supply: Phandle for vcca regulator device node. - 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 - qcom,platform-supply-entries: A node that lists the elements of the supply. There
can be more than one instance of this binding, can be more than one instance of this binding,
in which case the entry would be appended with in which case the entry would be appended with
@ -64,6 +69,8 @@ Example:
clock-rate = <0>, <0>, <0>; clock-rate = <0>, <0>, <0>;
qcom,dsi-pll-slave; qcom,dsi-pll-slave;
qcom,dsi-pll-ssc-en:
qcom,dsi-pll-ssc-mode = "down-spread";
qcom,platform-supply-entries { qcom,platform-supply-entries {
#address-cells = <1>; #address-cells = <1>;

View file

@ -26,6 +26,8 @@
#define DSI_PLL_POLL_TIMEOUT_US 1000 #define DSI_PLL_POLL_TIMEOUT_US 1000
#define MSM8996_DSI_PLL_REVISION_2 2 #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) int set_mdss_byte_mux_sel_8996(struct mux_clk *clk, int sel)
{ {
return 0; return 0;
@ -303,12 +305,13 @@ static void dsi_pll_disable(struct clk *c)
return; 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.fref = 19200000; /* 19.2 Mhz*/
pdb->in.fdata = 0; /* bit clock rate */ pdb->in.fdata = 0; /* bit clock rate */
pdb->in.dsiclk_sel = 1; /* 1, reg: 0x0014 */ 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 */ pdb->in.ldo_en = 0; /* 0, reg: 0x004c, bit 0 */
/* fixed input */ /* 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.pll_wakeup_timer = 5; /* 5, reg: 0x043c, bit 0 - 2 */
pdb->in.plllock_cnt = 1; /* 1, reg: 0x0488, bit 1 - 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.plllock_rng = 0; /* 0, reg: 0x0488, bit 3 - 4 */
pdb->in.ssc_center_spread = 0; /* 0, reg: 0x0494, bit 1 */ pdb->in.ssc_center = pll->ssc_center;/* 0, reg: 0x0494, bit 1 */
pdb->in.ssc_adj_per = 37; /* 37, reg: 0x498, bit 0 - 9 */ pdb->in.ssc_adj_period = 37; /* 37, reg: 0x498, bit 0 - 9 */
pdb->in.ssc_spread = 5; /* 0.005, 5kppm */ pdb->in.ssc_spread = 5; /* 0.005, 5kppm */
pdb->in.ssc_freq = 31500; /* 31.5 khz */ 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 */ pdb->in.pll_r3ctrl = 1; /* 1 */
} }
static void pll_8996_dec_frac_calc(struct dsi_pll_db *pdb, static void pll_8996_ssc_calc(struct mdss_pll_resources *pll,
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_input *pin = &pdb->in;
struct dsi_pll_output *pout = &pdb->out; 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; 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) 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_input *pin = &pdb->in;
struct dsi_pll_output *pout = &pdb->out; struct dsi_pll_output *pout = &pdb->out;
char data; 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); 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) struct dsi_pll_db *pdb)
{ {
void __iomem *pll_base = pll->pll_base;
struct dsi_pll_input *pin = &pdb->in; struct dsi_pll_input *pin = &pdb->in;
struct dsi_pll_output *pout = &pdb->out; struct dsi_pll_output *pout = &pdb->out;
char data; char data;
@ -516,7 +599,7 @@ static void pll_db_commit_8996(void __iomem *pll_base,
data = pout->cmn_ldo_cntrl; data = pout->cmn_ldo_cntrl;
MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_LDO_CNTRL, data); 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 */ /* de assert pll start and apply pll sw reset */
/* stop pll */ /* stop pll */
@ -590,6 +673,9 @@ static void pll_db_commit_8996(void __iomem *pll_base,
data = (pout->pll_n1div | (pout->pll_n2div << 4)); data = (pout->pll_n1div | (pout->pll_n2div << 4));
MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CLK_CFG0, data); 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 */ 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_current_rate = rate;
pll->vco_ref_clk_rate = vco->ref_clk_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_8996_calc_vco_count(pdb, pll->vco_current_rate,
pll->vco_ref_clk_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 */ /* commit slave if split display is enabled */
slave = pll->slave; slave = pll->slave;
if (slave) if (slave)
pll_db_commit_8996(slave->pll_base, pdb); pll_db_commit_8996(slave, pdb);
/* commit master itself */ /* commit master itself */
pll_db_commit_8996(pll->pll_base, pdb); pll_db_commit_8996(pll, pdb);
mdss_pll_resource_enable(pll, false); mdss_pll_resource_enable(pll, false);

View file

@ -52,6 +52,13 @@
#define DSIPHY_PLL_PLLLOCK_CMP_EN 0x0488 #define DSIPHY_PLL_PLLLOCK_CMP_EN 0x0488
#define DSIPHY_PLL_DEC_START 0x0490 #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_START1 0x04b4
#define DSIPHY_PLL_DIV_FRAC_START2 0x04b8 #define DSIPHY_PLL_DIV_FRAC_START2 0x04b8
#define DSIPHY_PLL_DIV_FRAC_START3 0x04bc #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 pll_wakeup_timer; /* 5, reg: 0x043c, bit 0 - 2 */
u32 plllock_cnt; /* 1, reg: 0x0488, bit 1 - 2 */ u32 plllock_cnt; /* 1, reg: 0x0488, bit 1 - 2 */
u32 plllock_rng; /* 1, reg: 0x0488, bit 3 - 4 */ u32 plllock_rng; /* 1, reg: 0x0488, bit 3 - 4 */
u32 ssc_center_spread; /* 0, reg: 0x0494, bit 1 */ u32 ssc_center; /* 0, reg: 0x0494, bit 1 */
u32 ssc_adj_per; /* 37, reg: 0x498, bit 0 - 9 */ u32 ssc_adj_period; /* 37, reg: 0x498, bit 0 - 9 */
u32 ssc_spread; /* 0.005 */ u32 ssc_spread; /* 0.005 */
u32 ssc_freq; /* unknown */ u32 ssc_freq; /* unknown */
u32 pll_ie_trim; /* 4, reg: 0x0400 */ u32 pll_ie_trim; /* 4, reg: 0x0400 */
@ -115,7 +122,7 @@ struct dsi_pll_output {
u32 pll_txclk_en; /* reg: 0x04c0 */ u32 pll_txclk_en; /* reg: 0x04c0 */
u32 dec_start; /* reg: 0x0490 */ u32 dec_start; /* reg: 0x0490 */
u32 div_frac_start; /* reg: 0x04b4, 0x4b8, 0x04bc */ 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 ssc_step_size; /* reg: 0x04a8, 0x04ac */
u32 plllock_cmp; /* reg: 0x047c, 0x0480, 0x0484 */ u32 plllock_cmp; /* reg: 0x047c, 0x0480, 0x0484 */
u32 pll_vco_div_ref; /* reg: 0x046c, 0x0470 */ 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->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, pll_base_reg = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "pll_base"); IORESOURCE_MEM, "pll_base");
if (!pll_base_reg) { if (!pll_base_reg) {

View file

@ -124,6 +124,9 @@ struct mdss_pll_resources {
*/ */
uint32_t index; uint32_t index;
bool ssc_en; /* share pll with master */
bool ssc_center; /* default is down spread */
struct mdss_pll_resources *slave; struct mdss_pll_resources *slave;
/* /*