Add clock tree and their corresponding clock operations. Add corresponding devicetree bindings. Change-Id: I042067a1ac5317edbdc73c8a64ae127ce6f5ff08 Signed-off-by: Venkata Prahlad Valluru <vvalluru@codeaurora.org>tirimbino
parent
e078309580
commit
1bc0f5d76d
@ -0,0 +1,988 @@ |
||||
/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 and |
||||
* only version 2 as published by the Free Software Foundation. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
*/ |
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__ |
||||
|
||||
#include <linux/kernel.h> |
||||
#include <linux/err.h> |
||||
#include <linux/iopoll.h> |
||||
#include <linux/delay.h> |
||||
|
||||
#include "mdss-pll.h" |
||||
#include "mdss-dsi-pll.h" |
||||
#include "mdss-dsi-pll-12nm.h" |
||||
|
||||
#define DSI_PLL_POLL_MAX_READS 15 |
||||
#define DSI_PLL_POLL_TIMEOUT_US 1000 |
||||
|
||||
int pixel_div_set_div(void *context, unsigned int reg, |
||||
unsigned int div) |
||||
{ |
||||
struct mdss_pll_resources *pll = context; |
||||
struct dsi_pll_db *pdb; |
||||
|
||||
pdb = (struct dsi_pll_db *)pll->priv; |
||||
|
||||
/* Programming during vco_prepare. Keep this value */ |
||||
pdb->param.pixel_divhf = (div - 1); |
||||
|
||||
pr_debug("ndx=%d div=%d divhf=%d\n", |
||||
pll->index, div, pdb->param.pixel_divhf); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int pixel_div_get_div(void *context, unsigned int reg, |
||||
unsigned int *div) |
||||
{ |
||||
int rc; |
||||
struct mdss_pll_resources *pll = context; |
||||
|
||||
if (is_gdsc_disabled(pll)) |
||||
return 0; |
||||
|
||||
rc = mdss_pll_resource_enable(pll, true); |
||||
if (rc) { |
||||
pr_err("Failed to enable mdss dsi pll resources\n"); |
||||
return rc; |
||||
} |
||||
|
||||
*div = (MDSS_PLL_REG_R(pll->pll_base, DSIPHY_SSC9) & 0x7F); |
||||
pr_debug("pixel_div = %d\n", (*div+1)); |
||||
|
||||
mdss_pll_resource_enable(pll, false); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int set_post_div_mux_sel(void *context, unsigned int reg, |
||||
unsigned int sel) |
||||
{ |
||||
struct mdss_pll_resources *pll = context; |
||||
struct dsi_pll_db *pdb; |
||||
|
||||
pdb = (struct dsi_pll_db *)pll->priv; |
||||
|
||||
/* Programming during vco_prepare. Keep this value */ |
||||
pdb->param.post_div_mux = sel; |
||||
|
||||
pr_debug("ndx=%d post_div_mux_sel=%d p_div=%d\n", |
||||
pll->index, sel, (u32) BIT(sel)); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int get_post_div_mux_sel(void *context, unsigned int reg, |
||||
unsigned int *sel) |
||||
{ |
||||
u32 vco_cntrl = 0, cpbias_cntrl = 0; |
||||
int rc; |
||||
struct mdss_pll_resources *pll = context; |
||||
|
||||
if (is_gdsc_disabled(pll)) |
||||
return 0; |
||||
|
||||
rc = mdss_pll_resource_enable(pll, true); |
||||
if (rc) { |
||||
pr_err("Failed to enable mdss dsi pll resources\n"); |
||||
return rc; |
||||
} |
||||
|
||||
vco_cntrl = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_PLL_VCO_CTRL); |
||||
vco_cntrl &= 0x30; |
||||
|
||||
cpbias_cntrl = MDSS_PLL_REG_R(pll->pll_base, |
||||
DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL); |
||||
cpbias_cntrl = ((cpbias_cntrl >> 6) & 0x1); |
||||
|
||||
if (cpbias_cntrl == 0) { |
||||
if (vco_cntrl == 0x00) |
||||
*sel = 0; |
||||
else if (vco_cntrl == 0x10) |
||||
*sel = 2; |
||||
else if (vco_cntrl == 0x20) |
||||
*sel = 3; |
||||
else if (vco_cntrl == 0x30) |
||||
*sel = 4; |
||||
} else if (cpbias_cntrl == 1) { |
||||
if (vco_cntrl == 0x30) |
||||
*sel = 2; |
||||
else if (vco_cntrl == 0x00) |
||||
*sel = 5; |
||||
} |
||||
|
||||
mdss_pll_resource_enable(pll, false); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int set_gp_mux_sel(void *context, unsigned int reg, |
||||
unsigned int sel) |
||||
{ |
||||
struct mdss_pll_resources *pll = context; |
||||
struct dsi_pll_db *pdb; |
||||
|
||||
pdb = (struct dsi_pll_db *)pll->priv; |
||||
|
||||
/* Programming during vco_prepare. Keep this value */ |
||||
pdb->param.gp_div_mux = sel; |
||||
|
||||
pr_debug("ndx=%d gp_div_mux_sel=%d gp_cntrl=%d\n", |
||||
pll->index, sel, (u32) BIT(sel)); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int get_gp_mux_sel(void *context, unsigned int reg, |
||||
unsigned int *sel) |
||||
{ |
||||
int rc; |
||||
struct mdss_pll_resources *pll = context; |
||||
u32 reg_val; |
||||
|
||||
if (is_gdsc_disabled(pll)) |
||||
return 0; |
||||
|
||||
rc = mdss_pll_resource_enable(pll, true); |
||||
if (rc) { |
||||
pr_err("Failed to enable mdss dsi pll resources\n"); |
||||
return rc; |
||||
} |
||||
|
||||
reg_val = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_PLL_CTRL); |
||||
*sel = (reg_val >> 5) & 0x7; |
||||
pr_debug("gp_cntrl = %d\n", *sel); |
||||
|
||||
mdss_pll_resource_enable(pll, false); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static bool pll_is_pll_locked_12nm(struct mdss_pll_resources *pll, |
||||
bool is_handoff) |
||||
{ |
||||
u32 status; |
||||
bool pll_locked; |
||||
|
||||
/* poll for PLL ready status */ |
||||
if (readl_poll_timeout_atomic((pll->pll_base + |
||||
DSIPHY_STAT0), |
||||
status, |
||||
((status & BIT(1)) > 0), |
||||
DSI_PLL_POLL_MAX_READS, |
||||
DSI_PLL_POLL_TIMEOUT_US)) { |
||||
if (!is_handoff) |
||||
pr_err("DSI PLL ndx=%d status=%x failed to Lock\n", |
||||
pll->index, status); |
||||
pll_locked = false; |
||||
} else { |
||||
pll_locked = true; |
||||
} |
||||
|
||||
return pll_locked; |
||||
} |
||||
|
||||
int dsi_pll_enable_seq_12nm(struct mdss_pll_resources *pll) |
||||
{ |
||||
int rc = 0; |
||||
struct dsi_pll_db *pdb; |
||||
void __iomem *pll_base; |
||||
|
||||
if (!pll) { |
||||
pr_err("Invalid PLL resources\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
pdb = (struct dsi_pll_db *)pll->priv; |
||||
if (!pdb) { |
||||
pr_err("No priv found\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
pll_base = pll->pll_base; |
||||
|
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SYS_CTRL, 0x49); |
||||
wmb(); /* make sure register committed before enabling branch clocks */ |
||||
udelay(5); /* h/w recommended delay */ |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SYS_CTRL, 0xc9); |
||||
wmb(); /* make sure register committed before enabling branch clocks */ |
||||
udelay(50); /* h/w recommended delay */ |
||||
|
||||
if (!pll_is_pll_locked_12nm(pll, false)) { |
||||
pr_err("DSI PLL ndx=%d lock failed!\n", |
||||
pll->index); |
||||
rc = -EINVAL; |
||||
goto init_lock_err; |
||||
} |
||||
|
||||
pr_debug("DSI PLL ndx:%d Locked!\n", pll->index); |
||||
|
||||
init_lock_err: |
||||
return rc; |
||||
} |
||||
|
||||
static int dsi_pll_enable(struct clk_hw *hw) |
||||
{ |
||||
int i, rc = 0; |
||||
struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); |
||||
struct mdss_pll_resources *pll = vco->priv; |
||||
|
||||
/* Try all enable sequences until one succeeds */ |
||||
for (i = 0; i < vco->pll_en_seq_cnt; i++) { |
||||
rc = vco->pll_enable_seqs[i](pll); |
||||
pr_debug("DSI PLL %s after sequence #%d\n", |
||||
rc ? "unlocked" : "locked", i + 1); |
||||
if (!rc) |
||||
break; |
||||
} |
||||
|
||||
if (rc) |
||||
pr_err("ndx=%d DSI PLL failed to lock\n", pll->index); |
||||
else |
||||
pll->pll_on = true; |
||||
|
||||
return rc; |
||||
} |
||||
|
||||
static int dsi_pll_relock(struct mdss_pll_resources *pll) |
||||
{ |
||||
void __iomem *pll_base = pll->pll_base; |
||||
u32 data = 0; |
||||
int rc = 0; |
||||
|
||||
data = MDSS_PLL_REG_R(pll_base, DSIPHY_PLL_POWERUP_CTRL); |
||||
data &= ~BIT(1); /* remove ONPLL_OVR_EN bit */ |
||||
data |= 0x1; /* set ONPLL_OVN to 0x1 */ |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_POWERUP_CTRL, data); |
||||
ndelay(500); /* h/w recommended delay */ |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SYS_CTRL, 0x49); |
||||
wmb(); /* make sure register committed before enabling branch clocks */ |
||||
udelay(5); /* h/w recommended delay */ |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SYS_CTRL, 0xc9); |
||||
wmb(); /* make sure register committed before enabling branch clocks */ |
||||
udelay(50); /* h/w recommended delay */ |
||||
|
||||
if (!pll_is_pll_locked_12nm(pll, false)) { |
||||
pr_err("DSI PLL ndx=%d lock failed!\n", |
||||
pll->index); |
||||
rc = -EINVAL; |
||||
goto relock_err; |
||||
} |
||||
ndelay(50); /* h/w recommended delay */ |
||||
|
||||
data = MDSS_PLL_REG_R(pll_base, DSIPHY_PLL_CTRL); |
||||
data |= 0x01; /* set CLK_SEL bits to 0x1 */ |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CTRL, data); |
||||
ndelay(500); /* h/w recommended delay */ |
||||
wmb(); /* make sure register committed before enabling branch clocks */ |
||||
pll->pll_on = true; |
||||
relock_err: |
||||
return rc; |
||||
} |
||||
|
||||
static void dsi_pll_disable(struct clk_hw *hw) |
||||
{ |
||||
struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); |
||||
struct mdss_pll_resources *pll = vco->priv; |
||||
void __iomem *pll_base = pll->pll_base; |
||||
u32 data = 0; |
||||
|
||||
if (!pll->pll_on && |
||||
mdss_pll_resource_enable(pll, true)) { |
||||
pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); |
||||
return; |
||||
} |
||||
|
||||
data = MDSS_PLL_REG_R(pll_base, DSIPHY_SSC0); |
||||
data &= ~BIT(6); /* disable GP_CLK_EN */ |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC0, data); |
||||
ndelay(500); /* h/w recommended delay */ |
||||
|
||||
data = MDSS_PLL_REG_R(pll_base, DSIPHY_PLL_CTRL); |
||||
data &= ~0x03; /* remove CLK_SEL bits */ |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CTRL, data); |
||||
ndelay(500); /* h/w recommended delay */ |
||||
|
||||
data = MDSS_PLL_REG_R(pll_base, DSIPHY_PLL_POWERUP_CTRL); |
||||
data &= ~0x1; /* remove ONPLL_OVR bit */ |
||||
data |= BIT(1); /* set ONPLL_OVR_EN to 0x1 */ |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_POWERUP_CTRL, data); |
||||
ndelay(500); /* h/w recommended delay */ |
||||
wmb(); /* make sure register committed before disabling branch clocks */ |
||||
pll->handoff_resources = false; |
||||
|
||||
mdss_pll_resource_enable(pll, false); |
||||
|
||||
pll->pll_on = false; |
||||
|
||||
pr_debug("DSI PLL ndx=%d Disabled\n", pll->index); |
||||
} |
||||
|
||||
static u32 __mdss_dsi_get_hsfreqrange(u64 target_freq) |
||||
{ |
||||
u64 bitclk_rate_mhz = div_u64((target_freq * 2), 1000000); |
||||
|
||||
if (bitclk_rate_mhz >= 80 && bitclk_rate_mhz < 90) |
||||
return 0x00; |
||||
else if (bitclk_rate_mhz >= 90 && bitclk_rate_mhz < 100) |
||||
return 0x10; |
||||
else if (bitclk_rate_mhz >= 100 && bitclk_rate_mhz < 110) |
||||
return 0x20; |
||||
else if (bitclk_rate_mhz >= 110 && bitclk_rate_mhz < 120) |
||||
return 0x30; |
||||
else if (bitclk_rate_mhz >= 120 && bitclk_rate_mhz < 130) |
||||
return 0x01; |
||||
else if (bitclk_rate_mhz >= 130 && bitclk_rate_mhz < 140) |
||||
return 0x11; |
||||
else if (bitclk_rate_mhz >= 140 && bitclk_rate_mhz < 150) |
||||
return 0x21; |
||||
else if (bitclk_rate_mhz >= 150 && bitclk_rate_mhz < 160) |
||||
return 0x31; |
||||
else if (bitclk_rate_mhz >= 160 && bitclk_rate_mhz < 170) |
||||
return 0x02; |
||||
else if (bitclk_rate_mhz >= 170 && bitclk_rate_mhz < 180) |
||||
return 0x12; |
||||
else if (bitclk_rate_mhz >= 180 && bitclk_rate_mhz < 190) |
||||
return 0x22; |
||||
else if (bitclk_rate_mhz >= 190 && bitclk_rate_mhz < 205) |
||||
return 0x32; |
||||
else if (bitclk_rate_mhz >= 205 && bitclk_rate_mhz < 220) |
||||
return 0x03; |
||||
else if (bitclk_rate_mhz >= 220 && bitclk_rate_mhz < 235) |
||||
return 0x13; |
||||
else if (bitclk_rate_mhz >= 235 && bitclk_rate_mhz < 250) |
||||
return 0x23; |
||||
else if (bitclk_rate_mhz >= 250 && bitclk_rate_mhz < 275) |
||||
return 0x33; |
||||
else if (bitclk_rate_mhz >= 275 && bitclk_rate_mhz < 300) |
||||
return 0x04; |
||||
else if (bitclk_rate_mhz >= 300 && bitclk_rate_mhz < 325) |
||||
return 0x14; |
||||
else if (bitclk_rate_mhz >= 325 && bitclk_rate_mhz < 350) |
||||
return 0x25; |
||||
else if (bitclk_rate_mhz >= 350 && bitclk_rate_mhz < 400) |
||||
return 0x35; |
||||
else if (bitclk_rate_mhz >= 400 && bitclk_rate_mhz < 450) |
||||
return 0x05; |
||||
else if (bitclk_rate_mhz >= 450 && bitclk_rate_mhz < 500) |
||||
return 0x16; |
||||
else if (bitclk_rate_mhz >= 500 && bitclk_rate_mhz < 550) |
||||
return 0x26; |
||||
else if (bitclk_rate_mhz >= 550 && bitclk_rate_mhz < 600) |
||||
return 0x37; |
||||
else if (bitclk_rate_mhz >= 600 && bitclk_rate_mhz < 650) |
||||
return 0x07; |
||||
else if (bitclk_rate_mhz >= 650 && bitclk_rate_mhz < 700) |
||||
return 0x18; |
||||
else if (bitclk_rate_mhz >= 700 && bitclk_rate_mhz < 750) |
||||
return 0x28; |
||||
else if (bitclk_rate_mhz >= 750 && bitclk_rate_mhz < 800) |
||||
return 0x39; |
||||
else if (bitclk_rate_mhz >= 800 && bitclk_rate_mhz < 850) |
||||
return 0x09; |
||||
else if (bitclk_rate_mhz >= 850 && bitclk_rate_mhz < 900) |
||||
return 0x19; |
||||
else if (bitclk_rate_mhz >= 900 && bitclk_rate_mhz < 950) |
||||
return 0x29; |
||||
else if (bitclk_rate_mhz >= 950 && bitclk_rate_mhz < 1000) |
||||
return 0x3a; |
||||
else if (bitclk_rate_mhz >= 1000 && bitclk_rate_mhz < 1050) |
||||
return 0x0a; |
||||
else if (bitclk_rate_mhz >= 1050 && bitclk_rate_mhz < 1100) |
||||
return 0x1a; |
||||
else if (bitclk_rate_mhz >= 1100 && bitclk_rate_mhz < 1150) |
||||
return 0x2a; |
||||
else if (bitclk_rate_mhz >= 1150 && bitclk_rate_mhz < 1200) |
||||
return 0x3b; |
||||
else if (bitclk_rate_mhz >= 1200 && bitclk_rate_mhz < 1250) |
||||
return 0x0b; |
||||
else if (bitclk_rate_mhz >= 1250 && bitclk_rate_mhz < 1300) |
||||
return 0x1b; |
||||
else if (bitclk_rate_mhz >= 1300 && bitclk_rate_mhz < 1350) |
||||
return 0x2b; |
||||
else if (bitclk_rate_mhz >= 1350 && bitclk_rate_mhz < 1400) |
||||
return 0x3c; |
||||
else if (bitclk_rate_mhz >= 1400 && bitclk_rate_mhz < 1450) |
||||
return 0x0c; |
||||
else if (bitclk_rate_mhz >= 1450 && bitclk_rate_mhz < 1500) |
||||
return 0x1c; |
||||
else if (bitclk_rate_mhz >= 1500 && bitclk_rate_mhz < 1550) |
||||
return 0x2c; |
||||
else if (bitclk_rate_mhz >= 1550 && bitclk_rate_mhz < 1600) |
||||
return 0x3d; |
||||
else if (bitclk_rate_mhz >= 1600 && bitclk_rate_mhz < 1650) |
||||
return 0x0d; |
||||
else if (bitclk_rate_mhz >= 1650 && bitclk_rate_mhz < 1700) |
||||
return 0x1d; |
||||
else if (bitclk_rate_mhz >= 1700 && bitclk_rate_mhz < 1750) |
||||
return 0x2e; |
||||
else if (bitclk_rate_mhz >= 1750 && bitclk_rate_mhz < 1800) |
||||
return 0x3e; |
||||
else if (bitclk_rate_mhz >= 1800 && bitclk_rate_mhz < 1850) |
||||
return 0x0e; |
||||
else if (bitclk_rate_mhz >= 1850 && bitclk_rate_mhz < 1900) |
||||
return 0x1e; |
||||
else if (bitclk_rate_mhz >= 1900 && bitclk_rate_mhz < 1950) |
||||
return 0x2f; |
||||
else if (bitclk_rate_mhz >= 1950 && bitclk_rate_mhz < 2000) |
||||
return 0x3f; |
||||
else if (bitclk_rate_mhz >= 2000 && bitclk_rate_mhz < 2050) |
||||
return 0x0f; |
||||
else if (bitclk_rate_mhz >= 2050 && bitclk_rate_mhz < 2100) |
||||
return 0x40; |
||||
else if (bitclk_rate_mhz >= 2100 && bitclk_rate_mhz < 2150) |
||||
return 0x41; |
||||
else if (bitclk_rate_mhz >= 2150 && bitclk_rate_mhz < 2200) |
||||
return 0x42; |
||||
else if (bitclk_rate_mhz >= 2200 && bitclk_rate_mhz < 2250) |
||||
return 0x43; |
||||
else if (bitclk_rate_mhz >= 2250 && bitclk_rate_mhz < 2300) |
||||
return 0x44; |
||||
else if (bitclk_rate_mhz >= 2300 && bitclk_rate_mhz < 2350) |
||||
return 0x45; |
||||
else if (bitclk_rate_mhz >= 2350 && bitclk_rate_mhz < 2400) |
||||
return 0x46; |
||||
else if (bitclk_rate_mhz >= 2400 && bitclk_rate_mhz < 2450) |
||||
return 0x47; |
||||
else if (bitclk_rate_mhz >= 2450 && bitclk_rate_mhz < 2500) |
||||
return 0x48; |
||||
else |
||||
return 0x49; |
||||
} |
||||
|
||||
static void __mdss_dsi_get_pll_vco_cntrl(u64 target_freq, u32 post_div_mux, |
||||
u32 *vco_cntrl, u32 *cpbias_cntrl) |
||||
{ |
||||
u64 target_freq_mhz = div_u64(target_freq, 1000000); |
||||
u32 p_div = BIT(post_div_mux); |
||||
|
||||
if (p_div == 1) { |
||||
*vco_cntrl = 0x00; |
||||
*cpbias_cntrl = 0; |
||||
} else if (p_div == 2) { |
||||
*vco_cntrl = 0x30; |
||||
*cpbias_cntrl = 1; |
||||
} else if (p_div == 4) { |
||||
*vco_cntrl = 0x10; |
||||
*cpbias_cntrl = 0; |
||||
} else if (p_div == 8) { |
||||
*vco_cntrl = 0x20; |
||||
*cpbias_cntrl = 0; |
||||
} else if (p_div == 16) { |
||||
*vco_cntrl = 0x30; |
||||
*cpbias_cntrl = 0; |
||||
} else { |
||||
*vco_cntrl = 0x00; |
||||
*cpbias_cntrl = 1; |
||||
} |
||||
|
||||
if (target_freq_mhz <= 1250 && target_freq_mhz >= 1092) |
||||
*vco_cntrl = *vco_cntrl | 2; |
||||
else if (target_freq_mhz < 1092 && target_freq_mhz >= 950) |
||||
*vco_cntrl = *vco_cntrl | 3; |
||||
else if (target_freq_mhz < 950 && target_freq_mhz >= 712) |
||||
*vco_cntrl = *vco_cntrl | 1; |
||||
else if (target_freq_mhz < 712 && target_freq_mhz >= 546) |
||||
*vco_cntrl = *vco_cntrl | 2; |
||||
else if (target_freq_mhz < 546 && target_freq_mhz >= 475) |
||||
*vco_cntrl = *vco_cntrl | 3; |
||||
else if (target_freq_mhz < 475 && target_freq_mhz >= 356) |
||||
*vco_cntrl = *vco_cntrl | 1; |
||||
else if (target_freq_mhz < 356 && target_freq_mhz >= 273) |
||||
*vco_cntrl = *vco_cntrl | 2; |
||||
else if (target_freq_mhz < 273 && target_freq_mhz >= 237) |
||||
*vco_cntrl = *vco_cntrl | 3; |
||||
else if (target_freq_mhz < 237 && target_freq_mhz >= 178) |
||||
*vco_cntrl = *vco_cntrl | 1; |
||||
else if (target_freq_mhz < 178 && target_freq_mhz >= 136) |
||||
*vco_cntrl = *vco_cntrl | 2; |
||||
else if (target_freq_mhz < 136 && target_freq_mhz >= 118) |
||||
*vco_cntrl = *vco_cntrl | 3; |
||||
else if (target_freq_mhz < 118 && target_freq_mhz >= 89) |
||||
*vco_cntrl = *vco_cntrl | 1; |
||||
else if (target_freq_mhz < 89 && target_freq_mhz >= 68) |
||||
*vco_cntrl = *vco_cntrl | 2; |
||||
else if (target_freq_mhz < 68 && target_freq_mhz >= 57) |
||||
*vco_cntrl = *vco_cntrl | 3; |
||||
else if (target_freq_mhz < 57 && target_freq_mhz >= 44) |
||||
*vco_cntrl = *vco_cntrl | 1; |
||||
else |
||||
*vco_cntrl = *vco_cntrl | 2; |
||||
} |
||||
|
||||
static u32 __mdss_dsi_get_osc_freq_target(u64 target_freq) |
||||
{ |
||||
u64 target_freq_mhz = div_u64(target_freq, 1000000); |
||||
|
||||
if (target_freq_mhz <= 1000) |
||||
return 1315; |
||||
else if (target_freq_mhz > 1000 && target_freq_mhz <= 1500) |
||||
return 1839; |
||||
else |
||||
return 0; |
||||
} |
||||
|
||||
static u64 __mdss_dsi_pll_get_m_div(u64 vco_rate) |
||||
{ |
||||
return div_u64((vco_rate * 4), 19200000); |
||||
} |
||||
|
||||
static u32 __mdss_dsi_get_fsm_ovr_ctrl(u64 target_freq) |
||||
{ |
||||
u64 bitclk_rate_mhz = div_u64((target_freq * 2), 1000000); |
||||
|
||||
if (bitclk_rate_mhz > 1500 && bitclk_rate_mhz <= 2500) |
||||
return 0; |
||||
else |
||||
return BIT(6); |
||||
} |
||||
|
||||
static void mdss_dsi_pll_12nm_calc_reg(struct mdss_pll_resources *pll, |
||||
struct dsi_pll_db *pdb) |
||||
{ |
||||
struct dsi_pll_param *param = &pdb->param; |
||||
u64 target_freq = 0; |
||||
|
||||
target_freq = div_u64(pll->vco_current_rate, |
||||
BIT(pdb->param.post_div_mux)); |
||||
|
||||
param->hsfreqrange = __mdss_dsi_get_hsfreqrange(target_freq); |
||||
__mdss_dsi_get_pll_vco_cntrl(target_freq, param->post_div_mux, |
||||
¶m->vco_cntrl, ¶m->cpbias_cntrl); |
||||
param->osc_freq_target = __mdss_dsi_get_osc_freq_target(target_freq); |
||||
param->m_div = (u32) __mdss_dsi_pll_get_m_div(pll->vco_current_rate); |
||||
param->fsm_ovr_ctrl = __mdss_dsi_get_fsm_ovr_ctrl(target_freq); |
||||
param->prop_cntrl = 0x05; |
||||
param->int_cntrl = 0x00; |
||||
param->gmp_cntrl = 0x1; |
||||
} |
||||
|
||||
static u32 __mdss_dsi_get_multi_intX100(u64 vco_rate, u32 *rem) |
||||
{ |
||||
u32 reminder = 0; |
||||
u64 temp = 0; |
||||
const u32 ref_clk_rate = 19200000, quarterX100 = 25; |
||||
|
||||
temp = div_u64_rem(vco_rate, ref_clk_rate, &reminder); |
||||
temp *= 100; |
||||
|
||||
/*
|
||||
* Multiplication integer needs to be floored in steps of 0.25 |
||||
* Hence multi_intX100 needs to be rounded off in steps of 25 |
||||
*/ |
||||
if (reminder < (ref_clk_rate / 4)) { |
||||
*rem = reminder; |
||||
return temp; |
||||
} else if ((reminder >= (ref_clk_rate / 4)) && |
||||
reminder < (ref_clk_rate / 2)) { |
||||
*rem = (reminder - (ref_clk_rate / 4)); |
||||
return (temp + quarterX100); |
||||
} else if ((reminder >= (ref_clk_rate / 2)) && |
||||
(reminder < ((3 * ref_clk_rate) / 4))) { |
||||
*rem = (reminder - (ref_clk_rate / 2)); |
||||
return (temp + (quarterX100 * 2)); |
||||
} |
||||
|
||||
*rem = (reminder - ((3 * ref_clk_rate) / 4)); |
||||
return (temp + (quarterX100 * 3)); |
||||
} |
||||
|
||||
static u32 __calc_gcd(u32 num1, u32 num2) |
||||
{ |
||||
if (num2 != 0) |
||||
return __calc_gcd(num2, (num1 % num2)); |
||||
else |
||||
return num1; |
||||
} |
||||
|
||||
static void mdss_dsi_pll_12nm_calc_ssc(struct mdss_pll_resources *pll, |
||||
struct dsi_pll_db *pdb) |
||||
{ |
||||
struct dsi_pll_param *param = &pdb->param; |
||||
u64 multi_intX100 = 0, temp = 0; |
||||
u32 temp_rem1 = 0, temp_rem2 = 0; |
||||
const u64 power_2_17 = 131072, power_2_10 = 1024; |
||||
const u32 ref_clk_rate = 19200000; |
||||
|
||||
multi_intX100 = __mdss_dsi_get_multi_intX100(pll->vco_current_rate, |
||||
&temp_rem1); |
||||
|
||||
/* Calculation for mpll_ssc_peak_i */ |
||||
temp = (multi_intX100 * pll->ssc_ppm * power_2_17); |
||||
temp = div_u64(temp, 100); /* 100 div for multi_intX100 */ |
||||
param->mpll_ssc_peak_i = |
||||
(u32) div_u64(temp, 1000000); /*10^6 for SSC PPM */ |
||||
|
||||
/* Calculation for mpll_stepsize_i */ |
||||
param->mpll_stepsize_i = (u32) div_u64((param->mpll_ssc_peak_i * |
||||
pll->ssc_freq * power_2_10), ref_clk_rate); |
||||
|
||||
/* Calculation for mpll_mint_i */ |
||||
param->mpll_mint_i = (u32) (div_u64((multi_intX100 * 4), 100) - 32); |
||||
|
||||
/* Calculation for mpll_frac_den */ |
||||
param->mpll_frac_den = (u32) div_u64(ref_clk_rate, |
||||
__calc_gcd((u32)pll->vco_current_rate, ref_clk_rate)); |
||||
|
||||
/* Calculation for mpll_frac_quot_i */ |
||||
temp = (temp_rem1 * power_2_17); |
||||
param->mpll_frac_quot_i = |
||||
(u32) div_u64_rem(temp, ref_clk_rate, &temp_rem2); |
||||
|
||||
/* Calculation for mpll_frac_rem */ |
||||
param->mpll_frac_rem = (u32) div_u64(((u64)temp_rem2 * |
||||
param->mpll_frac_den), ref_clk_rate); |
||||
|
||||
pr_debug("mpll_ssc_peak_i=%d mpll_stepsize_i=%d mpll_mint_i=%d\n", |
||||
param->mpll_ssc_peak_i, param->mpll_stepsize_i, |
||||
param->mpll_mint_i); |
||||
pr_debug("mpll_frac_den=%d mpll_frac_quot_i=%d mpll_frac_rem=%d", |
||||
param->mpll_frac_den, param->mpll_frac_quot_i, |
||||
param->mpll_frac_rem); |
||||
} |
||||
|
||||
static void pll_db_commit_12nm_ssc(struct mdss_pll_resources *pll, |
||||
struct dsi_pll_db *pdb) |
||||
{ |
||||
void __iomem *pll_base = pll->pll_base; |
||||
struct dsi_pll_param *param = &pdb->param; |
||||
char data = 0; |
||||
|
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC0, 0x27); |
||||
|
||||
data = (param->mpll_mint_i & 0xff); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC7, data); |
||||
|
||||
data = ((param->mpll_mint_i & 0xff00) >> 8); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC8, data); |
||||
|
||||
data = (param->mpll_ssc_peak_i & 0xff); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC1, data); |
||||
|
||||
data = ((param->mpll_ssc_peak_i & 0xff00) >> 8); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC2, data); |
||||
|
||||
data = ((param->mpll_ssc_peak_i & 0xf0000) >> 16); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC3, data); |
||||
|
||||
data = (param->mpll_stepsize_i & 0xff); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC4, data); |
||||
|
||||
data = ((param->mpll_stepsize_i & 0xff00) >> 8); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC5, data); |
||||
|
||||
data = ((param->mpll_stepsize_i & 0x1f0000) >> 16); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC6, data); |
||||
|
||||
data = (param->mpll_frac_quot_i & 0xff); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC10, data); |
||||
|
||||
data = ((param->mpll_frac_quot_i & 0xff00) >> 8); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC11, data); |
||||
|
||||
data = (param->mpll_frac_rem & 0xff); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC12, data); |
||||
|
||||
data = ((param->mpll_frac_rem & 0xff00) >> 8); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC13, data); |
||||
|
||||
data = (param->mpll_frac_den & 0xff); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC14, data); |
||||
|
||||
data = ((param->mpll_frac_den & 0xff00) >> 8); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC15, data); |
||||
} |
||||
|
||||
static void pll_db_commit_12nm(struct mdss_pll_resources *pll, |
||||
struct dsi_pll_db *pdb) |
||||
{ |
||||
void __iomem *pll_base = pll->pll_base; |
||||
struct dsi_pll_param *param = &pdb->param; |
||||
char data = 0; |
||||
|
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_CTRL0, 0x01); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CTRL, 0x05); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SLEWRATE_DDL_LOOP_CTRL, 0x01); |
||||
|
||||
data = ((param->hsfreqrange & 0x7f) | BIT(7)); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_HS_FREQ_RAN_SEL, data); |
||||
|
||||
data = ((param->vco_cntrl & 0x3f) | BIT(6)); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_CTRL, data); |
||||
|
||||
data = (param->osc_freq_target & 0x7f); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_0, data); |
||||
|
||||
data = ((param->osc_freq_target & 0xf80) >> 7); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_1, data); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_INPUT_LOOP_DIV_RAT_CTRL, 0x30); |
||||
|
||||
data = (param->m_div & 0x3f); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_LOOP_DIV_RATIO_0, data); |
||||
|
||||
data = ((param->m_div & 0xfc0) >> 6); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_LOOP_DIV_RATIO_1, data); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_INPUT_DIV_PLL_OVR, 0x60); |
||||
|
||||
data = (param->prop_cntrl & 0x3f); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PROP_CHRG_PUMP_CTRL, data); |
||||
|
||||
data = (param->int_cntrl & 0x3f); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_INTEG_CHRG_PUMP_CTRL, data); |
||||
|
||||
data = ((param->gmp_cntrl & 0x3) << 4); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_GMP_CTRL_DIG_TST, data); |
||||
|
||||
data = ((param->cpbias_cntrl & 0x1) << 6) | BIT(4); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL, data); |
||||
|
||||
data = ((param->gp_div_mux & 0x7) << 5) | 0x5; |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CTRL, data); |
||||
|
||||
data = (param->pixel_divhf & 0x7f); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_SSC9, data); |
||||
|
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_ANA_PROG_CTRL, 0x03); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_ANA_TST_LOCK_ST_OVR_CTRL, 0x50); |
||||
MDSS_PLL_REG_W(pll_base, |
||||
DSIPHY_SLEWRATE_FSM_OVR_CTRL, param->fsm_ovr_ctrl); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PHA_ERR_CTRL_0, 0x01); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PHA_ERR_CTRL_1, 0x00); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_LOCK_FILTER, 0xff); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_UNLOCK_FILTER, 0x03); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PRO_DLY_RELOCK, 0x0c); |
||||
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_LOCK_DET_MODE_SEL, 0x02); |
||||
|
||||
if (pll->ssc_en) |
||||
pll_db_commit_12nm_ssc(pll, pdb); |
||||
|
||||
pr_debug("pll:%d\n", pll->index); |
||||
wmb(); /* make sure register committed before preparing the clocks */ |
||||
} |
||||
|
||||
int pll_vco_set_rate_12nm(struct clk_hw *hw, unsigned long rate, |
||||
unsigned long parent_rate) |
||||
{ |
||||
int rc = 0; |
||||
struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); |
||||
struct mdss_pll_resources *pll = vco->priv; |
||||
struct dsi_pll_db *pdb; |
||||
|
||||
pdb = (struct dsi_pll_db *)pll->priv; |
||||
if (!pdb) { |
||||
pr_err("pll pdb not found\n"); |
||||
rc = -EINVAL; |
||||
goto error; |
||||
} |
||||
|
||||
pr_debug("%s: ndx=%d rate=%lu\n", __func__, pll->index, rate); |
||||
|
||||
pll->vco_current_rate = rate; |
||||
pll->vco_ref_clk_rate = vco->ref_clk_rate; |
||||
error: |
||||
return rc; |
||||
} |
||||
|
||||
static unsigned long pll_vco_get_rate_12nm(struct clk_hw *hw) |
||||
{ |
||||
u64 vco_rate = 0; |
||||
u32 m_div_5_0 = 0, m_div_11_6 = 0, m_div = 0; |
||||
struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); |
||||
u64 ref_clk = vco->ref_clk_rate; |
||||
int rc; |
||||
struct mdss_pll_resources *pll = vco->priv; |
||||
|
||||
if (is_gdsc_disabled(pll)) |
||||
return 0; |
||||
|
||||
rc = mdss_pll_resource_enable(pll, true); |
||||
if (rc) { |
||||
pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); |
||||
return rc; |
||||
} |
||||
|
||||
m_div_5_0 = MDSS_PLL_REG_R(pll->pll_base, |
||||
DSIPHY_PLL_LOOP_DIV_RATIO_0); |
||||
m_div_5_0 &= 0x3f; |
||||
pr_debug("m_div_5_0 = 0x%x\n", m_div_5_0); |
||||
|
||||
m_div_11_6 = MDSS_PLL_REG_R(pll->pll_base, |
||||
DSIPHY_PLL_LOOP_DIV_RATIO_1); |
||||
m_div_11_6 &= 0x3f; |
||||
pr_debug("m_div_11_6 = 0x%x\n", m_div_11_6); |
||||
|
||||
m_div = ((m_div_11_6 << 6) | (m_div_5_0)); |
||||
|
||||
vco_rate = div_u64((ref_clk * m_div), 4); |
||||
|
||||
pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); |
||||
|
||||
mdss_pll_resource_enable(pll, false); |
||||
|
||||
return (unsigned long)vco_rate; |
||||
} |
||||
|
||||
long pll_vco_round_rate_12nm(struct clk_hw *hw, unsigned long rate, |
||||
unsigned long *parent_rate) |
||||
{ |
||||
unsigned long rrate = rate; |
||||
struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); |
||||
|
||||
if (rate < vco->min_rate) |
||||
rrate = vco->min_rate; |
||||
if (rate > vco->max_rate) |
||||
rrate = vco->max_rate; |
||||
|
||||
*parent_rate = rrate; |
||||
|
||||
return rrate; |
||||
} |
||||
|
||||
unsigned long vco_12nm_recalc_rate(struct clk_hw *hw, |
||||
unsigned long parent_rate) |
||||
{ |
||||
struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); |
||||
struct mdss_pll_resources *pll = vco->priv; |
||||
unsigned long rate = 0; |
||||
int rc; |
||||
|
||||
if (!pll && is_gdsc_disabled(pll)) { |
||||
pr_err("gdsc disabled\n"); |
||||
return 0; |
||||
} |
||||
|
||||
rc = mdss_pll_resource_enable(pll, true); |
||||
if (rc) { |
||||
pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); |
||||
return 0; |
||||
} |
||||
|
||||
if (pll_is_pll_locked_12nm(pll, true)) { |
||||
pll->handoff_resources = true; |
||||
pll->pll_on = true; |
||||
rate = pll_vco_get_rate_12nm(hw); |
||||
} else { |
||||
mdss_pll_resource_enable(pll, false); |
||||
} |
||||
|
||||
return rate; |
||||
} |
||||
|
||||
int pll_vco_prepare_12nm(struct clk_hw *hw) |
||||
{ |
||||
int rc = 0; |
||||
struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); |
||||
struct mdss_pll_resources *pll = vco->priv; |
||||
struct dsi_pll_db *pdb; |
||||
u32 data = 0; |
||||
|
||||
if (!pll) { |
||||
pr_err("Dsi pll resources are not available\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
pdb = (struct dsi_pll_db *)pll->priv; |
||||
if (!pdb) { |
||||
pr_err("No prov found\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
rc = mdss_pll_resource_enable(pll, true); |
||||
if (rc) { |
||||
pr_err("ndx=%d Failed to enable mdss dsi pll resources\n", |
||||
pll->index); |
||||
return rc; |
||||
} |
||||
|
||||
if ((pll->vco_cached_rate != 0) |
||||
&& (pll->vco_cached_rate == clk_hw_get_rate(hw))) { |
||||
rc = hw->init->ops->set_rate(hw, pll->vco_cached_rate, |
||||
pll->vco_cached_rate); |
||||
if (rc) { |
||||
pr_err("index=%d vco_set_rate failed. rc=%d\n", |
||||
pll->index, rc); |
||||
goto error; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* For cases where DSI PHY is already enabled like: |
||||
* 1.) LP-11 during static screen |
||||
* 2.) ULPS during static screen |
||||
* 3.) Boot up with cont splash enabled where PHY is programmed in LK |
||||
* Execute the Re-lock sequence to enable the DSI PLL. |
||||
*/ |
||||
data = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_SYS_CTRL); |
||||
if (data & BIT(7)) { |
||||
rc = dsi_pll_relock(pll); |
||||
if (rc) |
||||
goto error; |
||||
else |
||||
goto end; |
||||
} |
||||
|
||||
mdss_dsi_pll_12nm_calc_reg(pll, pdb); |
||||
if (pll->ssc_en) |
||||
mdss_dsi_pll_12nm_calc_ssc(pll, pdb); |
||||
|
||||
/* commit DSI vco */ |
||||
pll_db_commit_12nm(pll, pdb); |
||||
|
||||
rc = dsi_pll_enable(hw); |
||||
|
||||
error: |
||||
if (rc) { |
||||
mdss_pll_resource_enable(pll, false); |
||||
pr_err("ndx=%d failed to enable dsi pll\n", pll->index); |
||||
} |
||||
|
||||
end: |
||||
return rc; |
||||
} |
||||
|
||||
void pll_vco_unprepare_12nm(struct clk_hw *hw) |
||||
{ |
||||
struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); |
||||
struct mdss_pll_resources *pll = vco->priv; |
||||
|
||||
if (!pll) { |
||||
pr_err("Dsi pll resources are not available\n"); |
||||
return; |
||||
} |
||||
|
||||
pll->vco_cached_rate = clk_hw_get_rate(hw); |
||||
dsi_pll_disable(hw); |
||||
} |
||||
|
||||
int pll_vco_enable_12nm(struct clk_hw *hw) |
||||
{ |
||||
struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); |
||||
struct mdss_pll_resources *pll = vco->priv; |
||||
u32 data = 0; |
||||
|
||||
if (!pll) { |
||||
pr_err("Dsi pll resources are not available\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
if (!pll->pll_on) { |
||||
pr_err("DSI PLL not enabled, return\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
data = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_SSC0); |
||||
data |= BIT(6); /* enable GP_CLK_EN */ |
||||
MDSS_PLL_REG_W(pll->pll_base, DSIPHY_SSC0, data); |
||||
wmb(); /* make sure register committed before enabling branch clocks */ |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,723 @@ |
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 and |
||||
* only version 2 as published by the Free Software Foundation. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
*/ |
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__ |
||||
|
||||
#include <linux/kernel.h> |
||||
#include <linux/err.h> |
||||
#include <linux/iopoll.h> |
||||
#include <linux/delay.h> |
||||
#include "mdss-dsi-pll.h" |
||||
#include "mdss-pll.h" |
||||
#include <dt-bindings/clock/mdss-12nm-pll-clk.h> |
||||
#include "mdss-dsi-pll-12nm.h" |
||||
|
||||
#define VCO_DELAY_USEC 1 |
||||
|
||||
static struct regmap_config dsi_pll_12nm_config = { |
||||
.reg_bits = 32, |
||||
.reg_stride = 4, |
||||
.val_bits = 32, |
||||
.max_register = 0x800, |
||||
}; |
||||
|
||||
static const struct clk_ops clk_ops_vco_12nm = { |
||||
.recalc_rate = vco_12nm_recalc_rate, |
||||
.set_rate = pll_vco_set_rate_12nm, |
||||
.round_rate = pll_vco_round_rate_12nm, |
||||
.prepare = pll_vco_prepare_12nm, |
||||
.unprepare = pll_vco_unprepare_12nm, |
||||
}; |
||||
|
||||
static struct regmap_bus pclk_div_regmap_bus = { |
||||
.reg_write = pixel_div_set_div, |
||||
.reg_read = pixel_div_get_div, |
||||
}; |
||||
|
||||
static struct regmap_bus post_div_mux_regmap_bus = { |
||||
.reg_write = set_post_div_mux_sel, |
||||
.reg_read = get_post_div_mux_sel, |
||||
}; |
||||
|
||||
static struct regmap_bus gp_div_mux_regmap_bus = { |
||||
.reg_write = set_gp_mux_sel, |
||||
.reg_read = get_gp_mux_sel, |
||||
}; |
||||
|
||||
/*
|
||||
* Clock tree model for generating DSI byte clock and pclk for 12nm DSI PLL |
||||
* |
||||
* |
||||
* +---------------+ |
||||
* +----------| vco_clk |----------+ |
||||
* | +---------------+ | |
||||
* | | |
||||
* | | |
||||
* | | |
||||
* +---------+---------+----+----+---------+---------+ | |
||||
* | | | | | | | |
||||
* | | | | | | | |
||||
* | | | | | | | |
||||
* +---v---+ +---v---+ +---v---+ +---v---+ +---v---+ +---v---+ | |
||||
* | DIV(1)| | DIV(2)| | DIV(4)| | DIV(8)| |DIV(16)| |DIV(32)| | |
||||
* +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ | |
||||
* | | | | | | | |
||||
* | | +---+ +---+ | | | |
||||
* | +-----------+ | | +-----------+ | | |
||||
* +-------------------+ | | | | +-------------------+ | |
||||
* | | | | | | | |
||||
* +--v-v-v-v-v-v---+ | |
||||
* \ post_div_mux / | |
||||
* \ / | |
||||
* +-----+----+ +---------------------+ |
||||
* | | |
||||
* +------------------------+ | |
||||
* | | |
||||
* +----v----+ +---------+---------+----+----+---------+---------+ |
||||
* | DIV-4 | | | | | | | |
||||
* +----+----+ | | | | | | |
||||
* | +---v---+ +---v---+ +---v---+ +---v---+ +---v---+ +---v---+ |
||||
* | | DIV(1)| | DIV(2)| | DIV(4)| | DIV(8)| |DIV(16)| |DIV(32)| |
||||
* | +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ |
||||
* | | | | | | | |
||||
* v | | +---+ +---+ | | |
||||
* byte_clk_src | +-----------+ | | +-----------+ | |
||||
* +-------------------+ | | | | +-------------------+ |
||||
* | | | | | | |
||||
* +--v-v-v-v-v-v---+ |
||||
* \ gp_cntrl_mux / |
||||
* \ / |
||||
* +-----+----+ |
||||
* | |
||||
* | |
||||
* +-------v-------+ |
||||
* | (DIV + 1) | |
||||
* | DIV = 0...127 | |
||||
* +-------+-------+ |
||||
* | |
||||
* | |
||||
* v |
||||
* dsi_pclk input to Clock Controller MND |
||||
*/ |
||||
|
||||
static struct dsi_pll_db pll_db[DSI_PLL_MAX]; |
||||
|
||||
static struct dsi_pll_vco_clk dsi0pll_vco_clk = { |
||||
.ref_clk_rate = 19200000UL, |
||||
.min_rate = 1000000000UL, |
||||
.max_rate = 2000000000UL, |
||||
.pll_en_seq_cnt = 1, |
||||
.pll_enable_seqs[0] = dsi_pll_enable_seq_12nm, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_vco_clk", |
||||
.parent_names = (const char *[]){"bi_tcxo"}, |
||||
.num_parents = 1, |
||||
.ops = &clk_ops_vco_12nm, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
}, |
||||
}; |
||||
|
||||
static struct dsi_pll_vco_clk dsi1pll_vco_clk = { |
||||
.ref_clk_rate = 19200000UL, |
||||
.min_rate = 1000000000UL, |
||||
.max_rate = 2000000000UL, |
||||
.pll_en_seq_cnt = 1, |
||||
.pll_enable_seqs[0] = dsi_pll_enable_seq_12nm, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_vco_clk", |
||||
.parent_names = (const char *[]){"bi_tcxo"}, |
||||
.num_parents = 1, |
||||
.ops = &clk_ops_vco_12nm, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi0pll_post_div1 = { |
||||
.div = 1, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_post_div1", |
||||
.parent_names = (const char *[]){"dsi0pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi0pll_post_div2 = { |
||||
.div = 2, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_post_div2", |
||||
.parent_names = (const char *[]){"dsi0pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi0pll_post_div4 = { |
||||
.div = 4, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_post_div4", |
||||
.parent_names = (const char *[]){"dsi0pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi0pll_post_div8 = { |
||||
.div = 8, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_post_div8", |
||||
.parent_names = (const char *[]){"dsi0pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi0pll_post_div16 = { |
||||
.div = 16, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_post_div16", |
||||
.parent_names = (const char *[]){"dsi0pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi0pll_post_div32 = { |
||||
.div = 32, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_post_div32", |
||||
.parent_names = (const char *[]){"dsi0pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_regmap_mux dsi0pll_post_div_mux = { |
||||
.reg = DSIPHY_PLL_VCO_CTRL, |
||||
.shift = 4, |
||||
.width = 2, |
||||
.clkr = { |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_post_div_mux", |
||||
.parent_names = (const char *[]){"dsi0pll_post_div1", |
||||
"dsi0pll_post_div2", |
||||
"dsi0pll_post_div4", |
||||
"dsi0pll_post_div8", |
||||
"dsi0pll_post_div16", |
||||
"dsi0pll_post_div32"}, |
||||
.num_parents = 6, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_regmap_mux_closest_ops, |
||||
}, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi1pll_post_div1 = { |
||||
.div = 1, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_post_div1", |
||||
.parent_names = (const char *[]){"dsi1pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi1pll_post_div2 = { |
||||
.div = 2, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_post_div2", |
||||
.parent_names = (const char *[]){"dsi1pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi1pll_post_div4 = { |
||||
.div = 4, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_post_div4", |
||||
.parent_names = (const char *[]){"dsi1pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi1pll_post_div8 = { |
||||
.div = 8, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_post_div8", |
||||
.parent_names = (const char *[]){"dsi1pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi1pll_post_div16 = { |
||||
.div = 16, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_post_div16", |
||||
.parent_names = (const char *[]){"dsi1pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi1pll_post_div32 = { |
||||
.div = 32, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_post_div32", |
||||
.parent_names = (const char *[]){"dsi1pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_regmap_mux dsi1pll_post_div_mux = { |
||||
.reg = DSIPHY_PLL_VCO_CTRL, |
||||
.shift = 4, |
||||
.width = 2, |
||||
.clkr = { |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_post_div_mux", |
||||
.parent_names = (const char *[]){"dsi1pll_post_div1", |
||||
"dsi1pll_post_div2", |
||||
"dsi1pll_post_div4", |
||||
"dsi1pll_post_div8", |
||||
"dsi1pll_post_div16", |
||||
"dsi1pll_post_div32"}, |
||||
.num_parents = 6, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_regmap_mux_closest_ops, |
||||
}, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi0pll_gp_div1 = { |
||||
.div = 1, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_gp_div1", |
||||
.parent_names = (const char *[]){"dsi0pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi0pll_gp_div2 = { |
||||
.div = 2, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_gp_div2", |
||||
.parent_names = (const char *[]){"dsi0pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi0pll_gp_div4 = { |
||||
.div = 4, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_gp_div4", |
||||
.parent_names = (const char *[]){"dsi0pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi0pll_gp_div8 = { |
||||
.div = 8, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_gp_div8", |
||||
.parent_names = (const char *[]){"dsi0pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi0pll_gp_div16 = { |
||||
.div = 16, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_gp_div16", |
||||
.parent_names = (const char *[]){"dsi0pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi0pll_gp_div32 = { |
||||
.div = 32, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_gp_div32", |
||||
.parent_names = (const char *[]){"dsi0pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_regmap_mux dsi0pll_gp_div_mux = { |
||||
.reg = DSIPHY_PLL_CTRL, |
||||
.shift = 5, |
||||
.width = 3, |
||||
.clkr = { |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_gp_div_mux", |
||||
.parent_names = (const char *[]){"dsi0pll_gp_div1", |
||||
"dsi0pll_gp_div2", |
||||
"dsi0pll_gp_div4", |
||||
"dsi0pll_gp_div8", |
||||
"dsi0pll_gp_div16", |
||||
"dsi0pll_gp_div32"}, |
||||
.num_parents = 6, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_regmap_mux_closest_ops, |
||||
}, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi1pll_gp_div1 = { |
||||
.div = 1, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_gp_div1", |
||||
.parent_names = (const char *[]){"dsi1pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi1pll_gp_div2 = { |
||||
.div = 2, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_gp_div2", |
||||
.parent_names = (const char *[]){"dsi1pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi1pll_gp_div4 = { |
||||
.div = 4, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_gp_div4", |
||||
.parent_names = (const char *[]){"dsi1pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi1pll_gp_div8 = { |
||||
.div = 8, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_gp_div8", |
||||
.parent_names = (const char *[]){"dsi1pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi1pll_gp_div16 = { |
||||
.div = 16, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_gp_div16", |
||||
.parent_names = (const char *[]){"dsi1pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi1pll_gp_div32 = { |
||||
.div = 32, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_gp_div32", |
||||
.parent_names = (const char *[]){"dsi1pll_vco_clk"}, |
||||
.num_parents = 1, |
||||
.flags = CLK_GET_RATE_NOCACHE, |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_regmap_mux dsi1pll_gp_div_mux = { |
||||
.reg = DSIPHY_PLL_CTRL, |
||||
.shift = 5, |
||||
.width = 3, |
||||
.clkr = { |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_gp_div_mux", |
||||
.parent_names = (const char *[]){"dsi1pll_gp_div1", |
||||
"dsi1pll_gp_div2", |
||||
"dsi1pll_gp_div4", |
||||
"dsi1pll_gp_div8", |
||||
"dsi1pll_gp_div16", |
||||
"dsi1pll_gp_div32"}, |
||||
.num_parents = 6, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_regmap_mux_closest_ops, |
||||
}, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_regmap_div dsi0pll_pclk_src = { |
||||
.reg = DSIPHY_SSC9, |
||||
.shift = 0, |
||||
.width = 6, |
||||
.clkr = { |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_pclk_src", |
||||
.parent_names = (const char *[]){ |
||||
"dsi0pll_gp_div_mux"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_regmap_div_ops, |
||||
}, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_regmap_div dsi1pll_pclk_src = { |
||||
.reg = DSIPHY_SSC9, |
||||
.shift = 0, |
||||
.width = 6, |
||||
.clkr = { |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_pclk_src", |
||||
.parent_names = (const char *[]){ |
||||
"dsi1pll_gp_div_mux"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_regmap_div_ops, |
||||
}, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi0pll_byte_clk_src = { |
||||
.div = 4, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi0pll_byte_clk_src", |
||||
.parent_names = (const char *[]){"dsi0pll_post_div_mux"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
static struct clk_fixed_factor dsi1pll_byte_clk_src = { |
||||
.div = 4, |
||||
.mult = 1, |
||||
.hw.init = &(struct clk_init_data){ |
||||
.name = "dsi1pll_byte_clk_src", |
||||
.parent_names = (const char *[]){"dsi1pll_post_div_mux"}, |
||||
.num_parents = 1, |
||||
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), |
||||
.ops = &clk_fixed_factor_ops, |
||||
}, |
||||
}; |
||||
|
||||
|
||||
static struct clk_hw *mdss_dsi_pllcc_12nm[] = { |
||||
[VCO_CLK_0] = &dsi0pll_vco_clk.hw, |
||||
[POST_DIV1_0_CLK] = &dsi0pll_post_div1.hw, |
||||
[POST_DIV2_0_CLK] = &dsi0pll_post_div2.hw, |
||||
[POST_DIV4_0_CLK] = &dsi0pll_post_div4.hw, |
||||
[POST_DIV8_0_CLK] = &dsi0pll_post_div8.hw, |
||||
[POST_DIV16_0_CLK] = &dsi0pll_post_div16.hw, |
||||
[POST_DIV32_0_CLK] = &dsi0pll_post_div32.hw, |
||||
[POST_DIV_MUX_0_CLK] = &dsi0pll_post_div_mux.clkr.hw, |
||||
[GP_DIV1_0_CLK] = &dsi0pll_gp_div1.hw, |
||||
[GP_DIV2_0_CLK] = &dsi0pll_gp_div2.hw, |
||||
[GP_DIV4_0_CLK] = &dsi0pll_gp_div4.hw, |
||||
[GP_DIV8_0_CLK] = &dsi0pll_gp_div8.hw, |
||||
[GP_DIV16_0_CLK] = &dsi0pll_gp_div16.hw, |
||||
[GP_DIV32_0_CLK] = &dsi0pll_gp_div32.hw, |
||||
[GP_DIV_MUX_0_CLK] = &dsi0pll_gp_div_mux.clkr.hw, |
||||
[PCLK_SRC_MUX_0_CLK] = &dsi0pll_pclk_src.clkr.hw, |
||||
[BYTE_CLK_SRC_0_CLK] = &dsi0pll_byte_clk_src.hw, |
||||
[VCO_CLK_1] = &dsi1pll_vco_clk.hw, |
||||
[POST_DIV1_1_CLK] = &dsi1pll_post_div1.hw, |
||||
[POST_DIV2_1_CLK] = &dsi1pll_post_div2.hw, |
||||
[POST_DIV4_1_CLK] = &dsi1pll_post_div4.hw, |
||||
[POST_DIV8_1_CLK] = &dsi1pll_post_div8.hw, |
||||
[POST_DIV16_1_CLK] = &dsi1pll_post_div16.hw, |
||||
[POST_DIV32_1_CLK] = &dsi1pll_post_div32.hw, |
||||
[POST_DIV_MUX_1_CLK] = &dsi1pll_post_div_mux.clkr.hw, |
||||
[GP_DIV1_1_CLK] = &dsi1pll_gp_div1.hw, |
||||
[GP_DIV2_1_CLK] = &dsi1pll_gp_div2.hw, |
||||
[GP_DIV4_1_CLK] = &dsi1pll_gp_div4.hw, |
||||
[GP_DIV8_1_CLK] = &dsi1pll_gp_div8.hw, |
||||
[GP_DIV16_1_CLK] = &dsi1pll_gp_div16.hw, |
||||
[GP_DIV32_1_CLK] = &dsi1pll_gp_div32.hw, |
||||
[GP_DIV_MUX_1_CLK] = &dsi1pll_gp_div_mux.clkr.hw, |
||||
[PCLK_SRC_MUX_1_CLK] = &dsi1pll_pclk_src.clkr.hw, |
||||
[BYTE_CLK_SRC_1_CLK] = &dsi1pll_byte_clk_src.hw, |
||||
}; |
||||
|
||||
int dsi_pll_clock_register_12nm(struct platform_device *pdev, |
||||
struct mdss_pll_resources *pll_res) |
||||
{ |
||||
int rc = 0, ndx, i; |
||||
struct clk *clk; |
||||
struct clk_onecell_data *clk_data; |
||||
int num_clks = ARRAY_SIZE(mdss_dsi_pllcc_12nm); |
||||
struct regmap *rmap; |
||||
struct dsi_pll_db *pdb; |
||||
|
||||
if (!pdev || !pdev->dev.of_node || |
||||
!pll_res || !pll_res->pll_base || !pll_res->phy_base) { |
||||
pr_err("Invalid params\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
ndx = pll_res->index; |
||||
|
||||
if (ndx >= DSI_PLL_MAX) { |
||||
pr_err("pll index(%d) NOT supported\n", ndx); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
pdb = &pll_db[ndx]; |
||||
pll_res->priv = pdb; |
||||
pll_res->vco_delay = VCO_DELAY_USEC; |
||||
pdb->pll = pll_res; |
||||
ndx++; |
||||
ndx %= DSI_PLL_MAX; |
||||
pdb->next = &pll_db[ndx]; |
||||
|
||||
clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), |
||||
GFP_KERNEL); |
||||
if (!clk_data) |
||||
return -ENOMEM; |
||||
|
||||
clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks * |
||||
sizeof(struct clk *)), GFP_KERNEL); |
||||
if (!clk_data->clks) { |
||||
devm_kfree(&pdev->dev, clk_data); |
||||
return -ENOMEM; |
||||
} |
||||
clk_data->clk_num = num_clks; |
||||
|
||||
/* Establish client data */ |
||||
if (ndx == 0) { |
||||
rmap = devm_regmap_init(&pdev->dev, &post_div_mux_regmap_bus, |
||||
pll_res, &dsi_pll_12nm_config); |
||||
dsi0pll_post_div_mux.clkr.regmap = rmap; |
||||
|
||||
rmap = devm_regmap_init(&pdev->dev, &gp_div_mux_regmap_bus, |
||||
pll_res, &dsi_pll_12nm_config); |
||||
dsi0pll_gp_div_mux.clkr.regmap = rmap; |
||||
|
||||
rmap = devm_regmap_init(&pdev->dev, &pclk_div_regmap_bus, |
||||
pll_res, &dsi_pll_12nm_config); |
||||
dsi0pll_pclk_src.clkr.regmap = rmap; |
||||
|
||||
dsi0pll_vco_clk.priv = pll_res; |
||||
for (i = VCO_CLK_0; i <= BYTE_CLK_SRC_0_CLK; i++) { |
||||
clk = devm_clk_register(&pdev->dev, |
||||
mdss_dsi_pllcc_12nm[i]); |
||||
if (IS_ERR(clk)) { |
||||
pr_err("clk registration failed for DSI clock:%d\n", |
||||
pll_res->index); |
||||
rc = -EINVAL; |
||||
goto clk_register_fail; |
||||
} |
||||
clk_data->clks[i] = clk; |
||||
|
||||
} |
||||
|
||||
rc = of_clk_add_provider(pdev->dev.of_node, |
||||
of_clk_src_onecell_get, clk_data); |
||||
|
||||
|
||||
} else { |
||||
rmap = devm_regmap_init(&pdev->dev, &post_div_mux_regmap_bus, |
||||
pll_res, &dsi_pll_12nm_config); |
||||
dsi1pll_post_div_mux.clkr.regmap = rmap; |
||||
|
||||
rmap = devm_regmap_init(&pdev->dev, &gp_div_mux_regmap_bus, |
||||
pll_res, &dsi_pll_12nm_config); |
||||
dsi1pll_gp_div_mux.clkr.regmap = rmap; |
||||
|
||||
rmap = devm_regmap_init(&pdev->dev, &pclk_div_regmap_bus, |
||||
pll_res, &dsi_pll_12nm_config); |
||||
dsi1pll_pclk_src.clkr.regmap = rmap; |
||||
|
||||
dsi1pll_vco_clk.priv = pll_res; |
||||
|
||||
for (i = VCO_CLK_1; i <= BYTE_CLK_SRC_1_CLK; i++) { |
||||
clk = devm_clk_register(&pdev->dev, |
||||
mdss_dsi_pllcc_12nm[i]); |
||||
if (IS_ERR(clk)) { |
||||
pr_err("clk registration failed for DSI clock:%d\n", |
||||
pll_res->index); |
||||
rc = -EINVAL; |
||||
goto clk_register_fail; |
||||
} |
||||
clk_data->clks[i] = clk; |
||||
|
||||
} |
||||
|
||||
rc = of_clk_add_provider(pdev->dev.of_node, |
||||
of_clk_src_onecell_get, clk_data); |
||||
} |
||||
if (!rc) { |
||||
pr_info("Registered DSI PLL ndx=%d, clocks successfully", ndx); |
||||
|
||||
return rc; |
||||
} |
||||
clk_register_fail: |
||||
devm_kfree(&pdev->dev, clk_data->clks); |
||||
devm_kfree(&pdev->dev, clk_data); |
||||
return rc; |
||||
} |
@ -0,0 +1,122 @@ |
||||
/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 and |
||||
* only version 2 as published by the Free Software Foundation. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
*/ |
||||
|
||||
#ifndef MDSS_DSI_PLL_12NM_H |
||||
#define MDSS_DSI_PLL_12NM_H |
||||
|
||||
#define DSIPHY_PLL_POWERUP_CTRL 0x034 |
||||
#define DSIPHY_PLL_PROP_CHRG_PUMP_CTRL 0x038 |
||||
#define DSIPHY_PLL_INTEG_CHRG_PUMP_CTRL 0x03c |
||||
#define DSIPHY_PLL_ANA_TST_LOCK_ST_OVR_CTRL 0x044 |
||||
#define DSIPHY_PLL_VCO_CTRL 0x048 |
||||
#define DSIPHY_PLL_GMP_CTRL_DIG_TST 0x04c |
||||
#define DSIPHY_PLL_PHA_ERR_CTRL_0 0x050 |
||||
#define DSIPHY_PLL_LOCK_FILTER 0x054 |
||||
#define DSIPHY_PLL_UNLOCK_FILTER 0x058 |
||||
#define DSIPHY_PLL_INPUT_DIV_PLL_OVR 0x05c |
||||
#define DSIPHY_PLL_LOOP_DIV_RATIO_0 0x060 |
||||
#define DSIPHY_PLL_INPUT_LOOP_DIV_RAT_CTRL 0x064 |
||||
#define DSIPHY_PLL_PRO_DLY_RELOCK 0x06c |
||||
#define DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL 0x070 |
||||
#define DSIPHY_PLL_LOCK_DET_MODE_SEL 0x074 |
||||
#define DSIPHY_PLL_ANA_PROG_CTRL 0x07c |
||||
#define DSIPHY_HS_FREQ_RAN_SEL 0x110 |
||||
#define DSIPHY_SLEWRATE_FSM_OVR_CTRL 0x280 |
||||
#define DSIPHY_SLEWRATE_DDL_LOOP_CTRL 0x28c |
||||
#define DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_0 0x290 |
||||
#define DSIPHY_PLL_PHA_ERR_CTRL_1 0x2e4 |
||||
#define DSIPHY_PLL_LOOP_DIV_RATIO_1 0x2e8 |
||||
#define DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_1 0x328 |
||||
#define DSIPHY_SSC0 0x394 |
||||
#define DSIPHY_SSC7 0x3b0 |
||||
#define DSIPHY_SSC8 0x3b4 |
||||
#define DSIPHY_SSC1 0x398 |
||||
#define DSIPHY_SSC2 0x39c |
||||
#define DSIPHY_SSC3 0x3a0 |
||||
#define DSIPHY_SSC4 0x3a4 |
||||
#define DSIPHY_SSC5 0x3a8 |
||||
#define DSIPHY_SSC6 0x3ac |
||||
#define DSIPHY_SSC10 0x360 |
||||
#define DSIPHY_SSC11 0x364 |
||||
#define DSIPHY_SSC12 0x368 |
||||
#define DSIPHY_SSC13 0x36c |
||||
#define DSIPHY_SSC14 0x370 |
||||
#define DSIPHY_SSC15 0x374 |
||||
#define DSIPHY_SSC7 0x3b0 |
||||
#define DSIPHY_SSC8 0x3b4 |
||||
#define DSIPHY_SSC9 0x3b8 |
||||
#define DSIPHY_STAT0 0x3e0 |
||||
#define DSIPHY_CTRL0 0x3e8 |
||||
#define DSIPHY_SYS_CTRL 0x3f0 |
||||
#define DSIPHY_PLL_CTRL 0x3f8 |
||||
|
||||
struct dsi_pll_param { |
||||
u32 hsfreqrange; |
||||
u32 vco_cntrl; |
||||
u32 osc_freq_target; |
||||
u32 m_div; |
||||
u32 prop_cntrl; |
||||
u32 int_cntrl; |
||||
u32 gmp_cntrl; |
||||
u32 cpbias_cntrl; |
||||
|
||||
/* mux and dividers */ |
||||
u32 gp_div_mux; |
||||
u32 post_div_mux; |
||||
u32 pixel_divhf; |
||||
u32 fsm_ovr_ctrl; |
||||
|
||||
/* ssc_params */ |
||||
u32 mpll_ssc_peak_i; |
||||
u32 mpll_stepsize_i; |
||||
u32 mpll_mint_i; |
||||
u32 mpll_frac_den; |
||||
u32 mpll_frac_quot_i; |
||||
u32 mpll_frac_rem; |
||||
}; |
||||
|
||||
enum { |
||||
DSI_PLL_0, |
||||
DSI_PLL_1, |
||||
DSI_PLL_MAX |
||||
}; |
||||
|
||||
struct dsi_pll_db { |
||||
struct dsi_pll_db *next; |
||||
struct mdss_pll_resources *pll; |
||||
struct dsi_pll_param param; |
||||
}; |
||||
|
||||
int pll_vco_set_rate_12nm(struct clk_hw *hw, unsigned long rate, |
||||
unsigned long parent_rate); |
||||
long pll_vco_round_rate_12nm(struct clk_hw *hw, unsigned long rate, |
||||
unsigned long *parent_rate); |
||||
unsigned long vco_12nm_recalc_rate(struct clk_hw *hw, |
||||
unsigned long parent_rate); |
||||
int pll_vco_prepare_12nm(struct clk_hw *hw); |
||||
void pll_vco_unprepare_12nm(struct clk_hw *hw); |
||||
int pll_vco_enable_12nm(struct clk_hw *hw); |
||||
int pixel_div_set_div(void *context, unsigned int reg, |
||||
unsigned int div); |
||||
int pixel_div_get_div(void *context, unsigned int reg, |
||||
unsigned int *div); |
||||
int set_post_div_mux_sel(void *context, unsigned int reg, |
||||
unsigned int sel); |
||||
int get_post_div_mux_sel(void *context, unsigned int reg, |
||||
unsigned int *sel); |
||||
int set_gp_mux_sel(void *context, unsigned int reg, |
||||
unsigned int sel); |
||||
int get_gp_mux_sel(void *context, unsigned int reg, |
||||
unsigned int *sel); |
||||
int dsi_pll_enable_seq_12nm(struct mdss_pll_resources *pll); |
||||
|
||||
#endif /* MDSS_DSI_PLL_12NM_H */ |
@ -0,0 +1,54 @@ |
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 and |
||||
* only version 2 as published by the Free Software Foundation. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
*/ |
||||
|
||||
#ifndef __MDSS_10NM_PLL_CLK_H |
||||
#define __MDSS_10NM_PLL_CLK_H |
||||
|
||||
/* DSI PLL clocks */ |
||||
#define VCO_CLK_0 0 |
||||
#define POST_DIV1_0_CLK 1 |
||||
#define POST_DIV2_0_CLK 2 |
||||
#define POST_DIV4_0_CLK 3 |
||||
#define POST_DIV8_0_CLK 4 |
||||
#define POST_DIV16_0_CLK 5 |
||||
#define POST_DIV32_0_CLK 6 |
||||
#define POST_DIV_MUX_0_CLK 7 |
||||
#define GP_DIV1_0_CLK 8 |
||||
#define GP_DIV2_0_CLK 9 |
||||
#define GP_DIV4_0_CLK 10 |
||||
#define GP_DIV8_0_CLK 11 |
||||
#define GP_DIV16_0_CLK 12 |
||||
#define GP_DIV32_0_CLK 13 |
||||
#define GP_DIV_MUX_0_CLK 14 |
||||
#define PCLK_SRC_MUX_0_CLK 15 |
||||
#define BYTE_CLK_SRC_0_CLK 16 |
||||
|
||||
#define VCO_CLK_1 17 |
||||
#define POST_DIV1_1_CLK 18 |
||||
#define POST_DIV2_1_CLK 19 |
||||
#define POST_DIV4_1_CLK 20 |
||||
#define POST_DIV8_1_CLK 21 |
||||
#define POST_DIV16_1_CLK 22 |
||||
#define POST_DIV32_1_CLK 23 |
||||
#define POST_DIV_MUX_1_CLK 24 |
||||
#define GP_DIV1_1_CLK 25 |
||||
#define GP_DIV2_1_CLK 26 |
||||
#define GP_DIV4_1_CLK 27 |
||||
#define GP_DIV8_1_CLK 28 |
||||
#define GP_DIV16_1_CLK 29 |
||||
#define GP_DIV32_1_CLK 30 |
||||
#define GP_DIV_MUX_1_CLK 31 |
||||
#define PCLK_SRC_MUX_1_CLK 32 |
||||
#define BYTE_CLK_SRC_1_CLK 33 |
||||
|
||||
#endif |
Loading…
Reference in new issue