mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-06-23 23:22:02 +00:00
tegra20: add clock_set_pllout function
Common practice on Tegra 2 boards is to use the pllp_out4 FO to generate the ULPI reference clock. For this to work we have to override the default hardware generated output divider. This function adds a clean way to do so. Signed-off-by: Lucas Stach <dev@lynxeye.de> Signed-off-by: Tom Warren <twarren@nvidia.com>
This commit is contained in:
parent
3f44e44f33
commit
65530a842e
5 changed files with 67 additions and 3 deletions
|
@ -396,6 +396,16 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
|
||||||
NONE(CRAM2),
|
NONE(CRAM2),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* number of clock outputs of a PLL */
|
||||||
|
static const u8 pll_num_clkouts[] = {
|
||||||
|
1, /* PLLC */
|
||||||
|
1, /* PLLM */
|
||||||
|
4, /* PLLP */
|
||||||
|
1, /* PLLA */
|
||||||
|
0, /* PLLU */
|
||||||
|
0, /* PLLD */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the oscillator frequency, from the corresponding hardware configuration
|
* Get the oscillator frequency, from the corresponding hardware configuration
|
||||||
* field.
|
* field.
|
||||||
|
@ -604,6 +614,34 @@ unsigned long clock_get_periph_rate(enum periph_id periph_id,
|
||||||
(readl(reg) & OUT_CLK_DIVISOR_MASK) >> OUT_CLK_DIVISOR_SHIFT);
|
(readl(reg) & OUT_CLK_DIVISOR_MASK) >> OUT_CLK_DIVISOR_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int clock_set_pllout(enum clock_id clkid, enum pll_out_id pllout, unsigned rate)
|
||||||
|
{
|
||||||
|
struct clk_pll *pll = get_pll(clkid);
|
||||||
|
int data = 0, div = 0, offset = 0;
|
||||||
|
|
||||||
|
if (!clock_id_is_pll(clkid))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (pllout + 1 > pll_num_clkouts[clkid])
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
div = clk_get_divider(8, pll_rate[clkid], rate);
|
||||||
|
|
||||||
|
if (div < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* out2 and out4 are in the high part of the register */
|
||||||
|
if (pllout == PLL_OUT2 || pllout == PLL_OUT4)
|
||||||
|
offset = 16;
|
||||||
|
|
||||||
|
data = (div << PLL_OUT_RATIO_SHIFT) |
|
||||||
|
PLL_OUT_OVRRIDE | PLL_OUT_CLKEN | PLL_OUT_RSTN;
|
||||||
|
clrsetbits_le32(&pll->pll_out[pllout >> 1],
|
||||||
|
PLL_OUT_RATIO_MASK << offset, data << offset);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the best available 7.1 format divisor given a parent clock rate and
|
* Find the best available 7.1 format divisor given a parent clock rate and
|
||||||
* required child clock rate. This function assumes that a second-stage
|
* required child clock rate. This function assumes that a second-stage
|
||||||
|
|
|
@ -214,7 +214,7 @@ void wb_start(void)
|
||||||
|
|
||||||
reg = PLLM_OUT1_RSTN_RESET_DISABLE | PLLM_OUT1_CLKEN_ENABLE |
|
reg = PLLM_OUT1_RSTN_RESET_DISABLE | PLLM_OUT1_CLKEN_ENABLE |
|
||||||
PLLM_OUT1_RATIO_VAL_8;
|
PLLM_OUT1_RATIO_VAL_8;
|
||||||
writel(reg, &clkrst->crc_pll[CLOCK_ID_MEMORY].pll_out);
|
writel(reg, &clkrst->crc_pll[CLOCK_ID_MEMORY].pll_out[0]);
|
||||||
|
|
||||||
reg = SCLK_SWAKE_FIQ_SRC_PLLM_OUT1 | SCLK_SWAKE_IRQ_SRC_PLLM_OUT1 |
|
reg = SCLK_SWAKE_FIQ_SRC_PLLM_OUT1 | SCLK_SWAKE_IRQ_SRC_PLLM_OUT1 |
|
||||||
SCLK_SWAKE_RUN_SRC_PLLM_OUT1 | SCLK_SWAKE_IDLE_SRC_PLLM_OUT1 |
|
SCLK_SWAKE_RUN_SRC_PLLM_OUT1 | SCLK_SWAKE_IDLE_SRC_PLLM_OUT1 |
|
||||||
|
|
|
@ -27,8 +27,7 @@
|
||||||
/* PLL registers - there are several PLLs in the clock controller */
|
/* PLL registers - there are several PLLs in the clock controller */
|
||||||
struct clk_pll {
|
struct clk_pll {
|
||||||
uint pll_base; /* the control register */
|
uint pll_base; /* the control register */
|
||||||
uint pll_out; /* output control */
|
uint pll_out[2]; /* output control */
|
||||||
uint reserved;
|
|
||||||
uint pll_misc; /* other misc things */
|
uint pll_misc; /* other misc things */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -112,6 +111,14 @@ struct clk_rst_ctlr {
|
||||||
#define PLL_DIVM_SHIFT 0
|
#define PLL_DIVM_SHIFT 0
|
||||||
#define PLL_DIVM_MASK (0x1f << PLL_DIVM_SHIFT)
|
#define PLL_DIVM_MASK (0x1f << PLL_DIVM_SHIFT)
|
||||||
|
|
||||||
|
/* CLK_RST_CONTROLLER_PLLx_OUTx_0 */
|
||||||
|
#define PLL_OUT_RSTN (1 << 0)
|
||||||
|
#define PLL_OUT_CLKEN (1 << 1)
|
||||||
|
#define PLL_OUT_OVRRIDE (1 << 2)
|
||||||
|
|
||||||
|
#define PLL_OUT_RATIO_SHIFT 8
|
||||||
|
#define PLL_OUT_RATIO_MASK (0xffU << PLL_OUT_RATIO_SHIFT)
|
||||||
|
|
||||||
/* CLK_RST_CONTROLLER_PLLx_MISC_0 */
|
/* CLK_RST_CONTROLLER_PLLx_MISC_0 */
|
||||||
#define PLL_CPCON_SHIFT 8
|
#define PLL_CPCON_SHIFT 8
|
||||||
#define PLL_CPCON_MASK (15U << PLL_CPCON_SHIFT)
|
#define PLL_CPCON_MASK (15U << PLL_CPCON_SHIFT)
|
||||||
|
|
|
@ -57,6 +57,18 @@ enum clock_osc_freq clock_get_osc_freq(void);
|
||||||
unsigned long clock_start_pll(enum clock_id id, u32 divm, u32 divn,
|
unsigned long clock_start_pll(enum clock_id id, u32 divm, u32 divn,
|
||||||
u32 divp, u32 cpcon, u32 lfcon);
|
u32 divp, u32 cpcon, u32 lfcon);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set PLL output frequency
|
||||||
|
*
|
||||||
|
* @param clkid clock id
|
||||||
|
* @param pllout pll output id
|
||||||
|
* @param rate desired output rate
|
||||||
|
*
|
||||||
|
* @return 0 if ok, -1 on error (invalid clock id or no suitable divider)
|
||||||
|
*/
|
||||||
|
int clock_set_pllout(enum clock_id clkid, enum pll_out_id pllout,
|
||||||
|
unsigned rate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read low-level parameters of a PLL.
|
* Read low-level parameters of a PLL.
|
||||||
*
|
*
|
||||||
|
|
|
@ -176,6 +176,13 @@ enum periph_id {
|
||||||
PERIPH_ID_NONE = -1,
|
PERIPH_ID_NONE = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum pll_out_id {
|
||||||
|
PLL_OUT1,
|
||||||
|
PLL_OUT2,
|
||||||
|
PLL_OUT3,
|
||||||
|
PLL_OUT4
|
||||||
|
};
|
||||||
|
|
||||||
/* Converts a clock number to a clock register: 0=L, 1=H, 2=U */
|
/* Converts a clock number to a clock register: 0=L, 1=H, 2=U */
|
||||||
#define PERIPH_REG(id) ((id) >> 5)
|
#define PERIPH_REG(id) ((id) >> 5)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue