提交 a36795c1 编写于 作者: J Jon Hunter 提交者: Paul Walmsley

OMAP: clock: fix configuration of J-Type DPLLs to work for OMAP3 and OMAP4

J-Type DPLLs have additional configuration parameters that need to
be programmed when setting the multipler and divider for the DPLL.
These parameters being the sigma delta divider (SD_DIV) for the DPLL
and the digital controlled oscillator (DCO) to be used by the DPLL.

The current code is implemented specifically to configure the
OMAP3630 PER J-Type DPLL. The OMAP4430 USB DPLL is also a J-Type DPLL
and so this code needs to be updated to work for both OMAP3 and OMAP4
devices and any other future devices that have J-TYPE DPLLs.

For the OMAP3630 PER DPLL both the SD_DIV and DCO paramenters are
used but for the OMAP4430 USB DPLL only the SD_DIV field is used.
The current implementation will only program the SD_DIV and DCO
fields if the DPLL has both and hence this does not work for
OMAP4430.

In order to make the code more generic add two new fields to the
dpll_data structure for the SD_DIV field and DCO field bit-masks
and only program these fields if the masks are defined for a specific
DPLL. This simplifies the code and allows us to remove the flag
DPLL_NO_DCO_SEL.

Tested on OMAP36xx Zoom3 and OMAP4 Blaze.
Signed-off-by: NJon Hunter <jon-hunter@ti.com>
[paul@pwsan.com: removed explicit inlining and added '_' prefix on lookup_*()
 functions; added testing info to commit message; added 35xx comments back in]
Signed-off-by: NPaul Walmsley <paul@pwsan.com>
上级 b183aaf7
...@@ -49,7 +49,6 @@ ...@@ -49,7 +49,6 @@
/* DPLL Type and DCO Selection Flags */ /* DPLL Type and DCO Selection Flags */
#define DPLL_J_TYPE 0x1 #define DPLL_J_TYPE 0x1
#define DPLL_NO_DCO_SEL 0x2
int omap2_clk_enable(struct clk *clk); int omap2_clk_enable(struct clk *clk);
void omap2_clk_disable(struct clk *clk); void omap2_clk_disable(struct clk *clk);
......
...@@ -602,6 +602,8 @@ static struct dpll_data dpll4_dd_3630 __initdata = { ...@@ -602,6 +602,8 @@ static struct dpll_data dpll4_dd_3630 __initdata = {
.autoidle_mask = OMAP3430_AUTO_PERIPH_DPLL_MASK, .autoidle_mask = OMAP3430_AUTO_PERIPH_DPLL_MASK,
.idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
.idlest_mask = OMAP3430_ST_PERIPH_CLK_MASK, .idlest_mask = OMAP3430_ST_PERIPH_CLK_MASK,
.dco_mask = OMAP3630_PERIPH_DPLL_DCO_SEL_MASK,
.sddiv_mask = OMAP3630_PERIPH_DPLL_SD_DIV_MASK,
.max_multiplier = OMAP3630_MAX_JTYPE_DPLL_MULT, .max_multiplier = OMAP3630_MAX_JTYPE_DPLL_MULT,
.min_divider = 1, .min_divider = 1,
.max_divider = OMAP3_MAX_DPLL_DIV, .max_divider = OMAP3_MAX_DPLL_DIV,
......
...@@ -940,6 +940,7 @@ static struct dpll_data dpll_unipro_dd = { ...@@ -940,6 +940,7 @@ static struct dpll_data dpll_unipro_dd = {
.enable_mask = OMAP4430_DPLL_EN_MASK, .enable_mask = OMAP4430_DPLL_EN_MASK,
.autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK, .autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK,
.idlest_mask = OMAP4430_ST_DPLL_CLK_MASK, .idlest_mask = OMAP4430_ST_DPLL_CLK_MASK,
.sddiv_mask = OMAP4430_DPLL_SD_DIV_MASK,
.max_multiplier = OMAP4430_MAX_DPLL_MULT, .max_multiplier = OMAP4430_MAX_DPLL_MULT,
.max_divider = OMAP4430_MAX_DPLL_DIV, .max_divider = OMAP4430_MAX_DPLL_DIV,
.min_divider = 1, .min_divider = 1,
...@@ -992,7 +993,7 @@ static struct clk usb_hs_clk_div_ck = { ...@@ -992,7 +993,7 @@ static struct clk usb_hs_clk_div_ck = {
static struct dpll_data dpll_usb_dd = { static struct dpll_data dpll_usb_dd = {
.mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_USB, .mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_USB,
.clk_bypass = &usb_hs_clk_div_ck, .clk_bypass = &usb_hs_clk_div_ck,
.flags = DPLL_J_TYPE | DPLL_NO_DCO_SEL, .flags = DPLL_J_TYPE,
.clk_ref = &sys_clkin_ck, .clk_ref = &sys_clkin_ck,
.control_reg = OMAP4430_CM_CLKMODE_DPLL_USB, .control_reg = OMAP4430_CM_CLKMODE_DPLL_USB,
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
......
...@@ -223,10 +223,9 @@ static int _omap3_noncore_dpll_stop(struct clk *clk) ...@@ -223,10 +223,9 @@ static int _omap3_noncore_dpll_stop(struct clk *clk)
} }
/** /**
* lookup_dco_sddiv - Set j-type DPLL4 compensation variables * _lookup_dco - Lookup DCO used by j-type DPLL
* @clk: pointer to a DPLL struct clk * @clk: pointer to a DPLL struct clk
* @dco: digital control oscillator selector * @dco: digital control oscillator selector
* @sd_div: target sigma-delta divider
* @m: DPLL multiplier to set * @m: DPLL multiplier to set
* @n: DPLL divider to set * @n: DPLL divider to set
* *
...@@ -235,11 +234,9 @@ static int _omap3_noncore_dpll_stop(struct clk *clk) ...@@ -235,11 +234,9 @@ static int _omap3_noncore_dpll_stop(struct clk *clk)
* XXX This code is not needed for 3430/AM35xx; can it be optimized * XXX This code is not needed for 3430/AM35xx; can it be optimized
* out in non-multi-OMAP builds for those chips? * out in non-multi-OMAP builds for those chips?
*/ */
static void lookup_dco_sddiv(struct clk *clk, u8 *dco, u8 *sd_div, u16 m, static void _lookup_dco(struct clk *clk, u8 *dco, u16 m, u8 n)
u8 n)
{ {
unsigned long fint, clkinp, sd; /* watch out for overflow */ unsigned long fint, clkinp; /* watch out for overflow */
int mod1, mod2;
clkinp = clk->parent->rate; clkinp = clk->parent->rate;
fint = (clkinp / n) * m; fint = (clkinp / n) * m;
...@@ -248,6 +245,27 @@ static void lookup_dco_sddiv(struct clk *clk, u8 *dco, u8 *sd_div, u16 m, ...@@ -248,6 +245,27 @@ static void lookup_dco_sddiv(struct clk *clk, u8 *dco, u8 *sd_div, u16 m,
*dco = 2; *dco = 2;
else else
*dco = 4; *dco = 4;
}
/**
* _lookup_sddiv - Calculate sigma delta divider for j-type DPLL
* @clk: pointer to a DPLL struct clk
* @sd_div: target sigma-delta divider
* @m: DPLL multiplier to set
* @n: DPLL divider to set
*
* See 36xx TRM section 3.5.3.3.3.2 "Type B DPLL (Low-Jitter)"
*
* XXX This code is not needed for 3430/AM35xx; can it be optimized
* out in non-multi-OMAP builds for those chips?
*/
static void _lookup_sddiv(struct clk *clk, u8 *sd_div, u16 m, u8 n)
{
unsigned long clkinp, sd; /* watch out for overflow */
int mod1, mod2;
clkinp = clk->parent->rate;
/* /*
* target sigma-delta to near 250MHz * target sigma-delta to near 250MHz
* sd = ceil[(m/(n+1)) * (clkinp_MHz / 250)] * sd = ceil[(m/(n+1)) * (clkinp_MHz / 250)]
...@@ -276,6 +294,7 @@ static void lookup_dco_sddiv(struct clk *clk, u8 *dco, u8 *sd_div, u16 m, ...@@ -276,6 +294,7 @@ static void lookup_dco_sddiv(struct clk *clk, u8 *dco, u8 *sd_div, u16 m,
static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
{ {
struct dpll_data *dd = clk->dpll_data; struct dpll_data *dd = clk->dpll_data;
u8 dco, sd_div;
u32 v; u32 v;
/* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */
...@@ -298,18 +317,16 @@ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) ...@@ -298,18 +317,16 @@ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
v |= m << __ffs(dd->mult_mask); v |= m << __ffs(dd->mult_mask);
v |= (n - 1) << __ffs(dd->div1_mask); v |= (n - 1) << __ffs(dd->div1_mask);
/* /* Configure dco and sd_div for dplls that have these fields */
* XXX This code is not needed for 3430/AM35XX; can it be optimized if (dd->dco_mask) {
* out in non-multi-OMAP builds for those chips? _lookup_dco(clk, &dco, m, n);
*/ v &= ~(dd->dco_mask);
if ((dd->flags & DPLL_J_TYPE) && !(dd->flags & DPLL_NO_DCO_SEL)) { v |= dco << __ffs(dd->dco_mask);
u8 dco, sd_div; }
lookup_dco_sddiv(clk, &dco, &sd_div, m, n); if (dd->sddiv_mask) {
/* XXX This probably will need revision for OMAP4 */ _lookup_sddiv(clk, &sd_div, m, n);
v &= ~(OMAP3630_PERIPH_DPLL_DCO_SEL_MASK v &= ~(dd->sddiv_mask);
| OMAP3630_PERIPH_DPLL_SD_DIV_MASK); v |= sd_div << __ffs(dd->sddiv_mask);
v |= dco << __ffs(OMAP3630_PERIPH_DPLL_DCO_SEL_MASK);
v |= sd_div << __ffs(OMAP3630_PERIPH_DPLL_SD_DIV_MASK);
} }
__raw_writel(v, dd->mult_div1_reg); __raw_writel(v, dd->mult_div1_reg);
......
...@@ -124,8 +124,7 @@ struct clksel { ...@@ -124,8 +124,7 @@ struct clksel {
* *
* Possible values for @flags: * Possible values for @flags:
* DPLL_J_TYPE: "J-type DPLL" (only some 36xx, 4xxx DPLLs) * DPLL_J_TYPE: "J-type DPLL" (only some 36xx, 4xxx DPLLs)
* NO_DCO_SEL: don't program DCO (only for some J-type DPLLs) *
* @freqsel_mask is only used on the OMAP34xx family and AM35xx. * @freqsel_mask is only used on the OMAP34xx family and AM35xx.
* *
* XXX Some DPLLs have multiple bypass inputs, so it's not technically * XXX Some DPLLs have multiple bypass inputs, so it's not technically
...@@ -161,6 +160,8 @@ struct dpll_data { ...@@ -161,6 +160,8 @@ struct dpll_data {
u32 autoidle_mask; u32 autoidle_mask;
u32 freqsel_mask; u32 freqsel_mask;
u32 idlest_mask; u32 idlest_mask;
u32 dco_mask;
u32 sddiv_mask;
u8 auto_recal_bit; u8 auto_recal_bit;
u8 recal_en_bit; u8 recal_en_bit;
u8 recal_st_bit; u8 recal_st_bit;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册