/* * Private struct for N1/N2 post-divider clocks. These clocks are similar to * the generic clk_divider class of clocks. The only difference is that it * also sets the slave DSI PLL's post-dividers if in bonded DSI mode
*/ struct dsi_pll_14nm_postdiv { struct clk_hw hw;
/* divider params */
u8 shift;
u8 width;
u8 flags; /* same flags as used by clk_divider struct */
/* * Global list of private DSI PLL struct pointers. We need this for bonded DSI * mode, where the master PLL's clk_ops needs access the slave's private data
*/ staticstruct dsi_pll_14nm *pll_14nm_list[DSI_MAX];
data = pconf->ssc_adj_period;
data &= 0x0ff;
writel(data, base + REG_DSI_14nm_PHY_PLL_SSC_ADJ_PER1);
data = (pconf->ssc_adj_period >> 8);
data &= 0x03;
writel(data, base + REG_DSI_14nm_PHY_PLL_SSC_ADJ_PER2);
data = pconf->ssc_period;
data &= 0x0ff;
writel(data, base + REG_DSI_14nm_PHY_PLL_SSC_PER1);
data = (pconf->ssc_period >> 8);
data &= 0x0ff;
writel(data, base + REG_DSI_14nm_PHY_PLL_SSC_PER2);
data = pconf->ssc_step_size;
data &= 0x0ff;
writel(data, base + REG_DSI_14nm_PHY_PLL_SSC_STEP_SIZE1);
data = (pconf->ssc_step_size >> 8);
data &= 0x0ff;
writel(data, base + REG_DSI_14nm_PHY_PLL_SSC_STEP_SIZE2);
data = (pconf->ssc_center & 0x01);
data <<= 1;
data |= 0x01; /* enable */
writel(data, base + REG_DSI_14nm_PHY_PLL_SSC_EN_CENTER);
/* confgiure the non frequency dependent pll registers */
data = 0;
writel(data, base + REG_DSI_14nm_PHY_PLL_SYSCLK_EN_RESET);
writel(1, base + REG_DSI_14nm_PHY_PLL_TXCLK_EN);
writel(48, base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL); /* bandgap_timer */
writel(4 << 3, base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL2); /* pll_wakeup_timer */
writel(5, base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL5);
data = pconf->pll_vco_div_ref & 0xff;
writel(data, base + REG_DSI_14nm_PHY_PLL_VCO_DIV_REF1);
data = (pconf->pll_vco_div_ref >> 8) & 0x3;
writel(data, base + REG_DSI_14nm_PHY_PLL_VCO_DIV_REF2);
data = pconf->pll_kvco_div_ref & 0xff;
writel(data, base + REG_DSI_14nm_PHY_PLL_KVCO_DIV_REF1);
data = (pconf->pll_kvco_div_ref >> 8) & 0x3;
writel(data, base + REG_DSI_14nm_PHY_PLL_KVCO_DIV_REF2);
writel(16, base + REG_DSI_14nm_PHY_PLL_PLL_MISC1);
writel(4, base + REG_DSI_14nm_PHY_PLL_IE_TRIM);
writel(4, base + REG_DSI_14nm_PHY_PLL_IP_TRIM);
writel(1 << 3 | 1, base + REG_DSI_14nm_PHY_PLL_CP_SET_CUR);
writel(0 << 3 | 0, base + REG_DSI_14nm_PHY_PLL_PLL_ICPCSET);
writel(0 << 3 | 0, base + REG_DSI_14nm_PHY_PLL_PLL_ICPMSET);
writel(4 << 3 | 4, base + REG_DSI_14nm_PHY_PLL_PLL_ICP_SET);
writel(1 << 4 | 11, base + REG_DSI_14nm_PHY_PLL_PLL_LPF1);
writel(7, base + REG_DSI_14nm_PHY_PLL_IPTAT_TRIM);
writel(1 << 4 | 2, base + REG_DSI_14nm_PHY_PLL_PLL_CRCTRL);
}
/* Use the /2 path in Mux */
writel(1, cmn_base + REG_DSI_14nm_PHY_CMN_CLK_CFG1);
data = 0xff; /* data, clk, pll normal operation */
writel(data, cmn_base + REG_DSI_14nm_PHY_CMN_CTRL_0);
/* configure the frequency dependent pll registers */
data = pconf->dec_start;
writel(data, base + REG_DSI_14nm_PHY_PLL_DEC_START);
data = pconf->div_frac_start & 0xff;
writel(data, base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START1);
data = (pconf->div_frac_start >> 8) & 0xff;
writel(data, base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START2);
data = (pconf->div_frac_start >> 16) & 0xf;
writel(data, base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START3);
data = pconf->plllock_cmp & 0xff;
writel(data, base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP1);
data = (pconf->plllock_cmp >> 8) & 0xff;
writel(data, base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP2);
data = (pconf->plllock_cmp >> 16) & 0x3;
writel(data, base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP3);
data = pconf->plllock_cnt << 1 | 0 << 3; /* plllock_rng */
writel(data, base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP_EN);
data = pconf->pll_vco_count & 0xff;
writel(data, base + REG_DSI_14nm_PHY_PLL_VCO_COUNT1);
data = (pconf->pll_vco_count >> 8) & 0xff;
writel(data, base + REG_DSI_14nm_PHY_PLL_VCO_COUNT2);
data = pconf->pll_kvco_count & 0xff;
writel(data, base + REG_DSI_14nm_PHY_PLL_KVCO_COUNT1);
data = (pconf->pll_kvco_count >> 8) & 0x3;
writel(data, base + REG_DSI_14nm_PHY_PLL_KVCO_COUNT2);
/* * High nibble configures the post divider internal to the VCO. It's * fixed to divide by 1 for now. * * 0: divided by 1 * 1: divided by 2 * 2: divided by 4 * 3: divided by 8
*/
writel(0 << 4 | 3, base + REG_DSI_14nm_PHY_PLL_PLL_LPF2_POSTDIV);
if (conf.ssc_en)
pll_14nm_ssc_calc(pll_14nm, &conf);
pll_14nm_calc_vco_count(pll_14nm, &conf);
/* commit the slave DSI PLL registers if we're master. Note that we * don't lock the slave PLL. We just ensure that the PLL/PHY registers * of the master and slave are identical
*/ if (pll_14nm->phy->usecase == MSM_DSI_PHY_MASTER) { struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave;
/* * Recalculating the rate from dec_start and frac_start doesn't end up * the rate we originally set. Convert the freq to KHz, round it up and * convert it back to MHz.
*/
vco_rate = DIV_ROUND_UP_ULL(vco_rate, 1000) * 1000;
value = divider_get_val(rate, parent_rate, NULL, postdiv->width,
postdiv->flags);
spin_lock_irqsave(lock, flags);
val = readl(base + REG_DSI_14nm_PHY_CMN_CLK_CFG0);
val &= ~(div_mask(width) << shift);
val |= value << shift;
writel(val, base + REG_DSI_14nm_PHY_CMN_CLK_CFG0);
/* If we're master in bonded DSI mode, then the slave PLL's post-dividers * follow the master's post dividers
*/ if (pll_14nm->phy->usecase == MSM_DSI_PHY_MASTER) { struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave; void __iomem *slave_base = pll_14nm_slave->phy->base;
pll_postdiv = devm_kzalloc(dev, sizeof(*pll_postdiv), GFP_KERNEL); if (!pll_postdiv) return ERR_PTR(-ENOMEM);
pll_postdiv->pll = pll_14nm;
pll_postdiv->shift = shift; /* both N1 and N2 postdividers are 4 bits wide */
pll_postdiv->width = 4; /* range of each divider is from 1 to 15 */
pll_postdiv->flags = CLK_DIVIDER_ONE_BASED;
pll_postdiv->hw.init = &postdiv_init;
ret = devm_clk_hw_register(dev, &pll_postdiv->hw); if (ret) return ERR_PTR(ret);
/* * Skip the mux for now, force DSICLK_SEL to 1, Add a /2 divider * on the way. Don't let it set parent.
*/
n1_postdivby2 = devm_clk_hw_register_fixed_factor_parent_hw(dev,
clk_name, n1_postdiv, 0, 1, 2); if (IS_ERR(n1_postdivby2)) return PTR_ERR(n1_postdivby2);
/* DSI pixel clock = VCO_CLK / N1 / 2 / N2 * This is the output of N2 post-divider, bits 4-7 in * REG_DSI_14nm_PHY_CMN_CLK_CFG0. Don't let it set parent.
*/
hw = pll_14nm_postdiv_register(pll_14nm, clk_name, n1_postdivby2,
0, 4); if (IS_ERR(hw)) return PTR_ERR(hw);
writel(DSI_14nm_PHY_LN_TIMING_CTRL_4_HS_EXIT(timing->hs_exit),
base + REG_DSI_14nm_PHY_LN_TIMING_CTRL_4(lane_idx));
writel(DSI_14nm_PHY_LN_TIMING_CTRL_5_HS_ZERO(zero),
base + REG_DSI_14nm_PHY_LN_TIMING_CTRL_5(lane_idx));
writel(DSI_14nm_PHY_LN_TIMING_CTRL_6_HS_PREPARE(prepare),
base + REG_DSI_14nm_PHY_LN_TIMING_CTRL_6(lane_idx));
writel(DSI_14nm_PHY_LN_TIMING_CTRL_7_HS_TRAIL(trail),
base + REG_DSI_14nm_PHY_LN_TIMING_CTRL_7(lane_idx));
writel(DSI_14nm_PHY_LN_TIMING_CTRL_8_HS_RQST(rqst),
base + REG_DSI_14nm_PHY_LN_TIMING_CTRL_8(lane_idx));
writel(DSI_14nm_PHY_LN_CFG0_PREPARE_DLY(prep_dly),
base + REG_DSI_14nm_PHY_LN_CFG0(lane_idx));
writel(halfbyte_en ? DSI_14nm_PHY_LN_CFG1_HALFBYTECLK_EN : 0,
base + REG_DSI_14nm_PHY_LN_CFG1(lane_idx));
writel(DSI_14nm_PHY_LN_TIMING_CTRL_9_TA_GO(timing->ta_go) |
DSI_14nm_PHY_LN_TIMING_CTRL_9_TA_SURE(timing->ta_sure),
base + REG_DSI_14nm_PHY_LN_TIMING_CTRL_9(lane_idx));
writel(DSI_14nm_PHY_LN_TIMING_CTRL_10_TA_GET(timing->ta_get),
base + REG_DSI_14nm_PHY_LN_TIMING_CTRL_10(lane_idx));
writel(DSI_14nm_PHY_LN_TIMING_CTRL_11_TRIG3_CMD(0xa0),
base + REG_DSI_14nm_PHY_LN_TIMING_CTRL_11(lane_idx));
}
data = 0x1c; if (phy->usecase != MSM_DSI_PHY_STANDALONE)
data |= DSI_14nm_PHY_CMN_LDO_CNTRL_VREG_CTRL(32);
writel(data, base + REG_DSI_14nm_PHY_CMN_LDO_CNTRL);
writel(0x1, base + REG_DSI_14nm_PHY_CMN_GLBL_TEST_CTRL);
/* 4 data lanes + 1 clk lane configuration */ for (i = 0; i < 5; i++) {
writel(0x1d, lane_base + REG_DSI_14nm_PHY_LN_VREG_CNTRL(i));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.