diff options
| -rw-r--r-- | arch/arm/cpu/tegra20-common/clock.c | 38 | ||||
| -rw-r--r-- | arch/arm/cpu/tegra20-common/warmboot_avp.c | 2 | ||||
| -rw-r--r-- | arch/arm/include/asm/arch-tegra/clk_rst.h | 11 | ||||
| -rw-r--r-- | arch/arm/include/asm/arch-tegra/clock.h | 12 | ||||
| -rw-r--r-- | arch/arm/include/asm/arch-tegra20/clock-tables.h | 7 | 
5 files changed, 67 insertions, 3 deletions
diff --git a/arch/arm/cpu/tegra20-common/clock.c b/arch/arm/cpu/tegra20-common/clock.c index a670b0746..12987a689 100644 --- a/arch/arm/cpu/tegra20-common/clock.c +++ b/arch/arm/cpu/tegra20-common/clock.c @@ -396,6 +396,16 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {  	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   * 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);  } +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   * required child clock rate. This function assumes that a second-stage diff --git a/arch/arm/cpu/tegra20-common/warmboot_avp.c b/arch/arm/cpu/tegra20-common/warmboot_avp.c index bc6281d2e..bc4660689 100644 --- a/arch/arm/cpu/tegra20-common/warmboot_avp.c +++ b/arch/arm/cpu/tegra20-common/warmboot_avp.c @@ -214,7 +214,7 @@ void wb_start(void)  	reg = PLLM_OUT1_RSTN_RESET_DISABLE | PLLM_OUT1_CLKEN_ENABLE |  	      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 |  	      SCLK_SWAKE_RUN_SRC_PLLM_OUT1 | SCLK_SWAKE_IDLE_SRC_PLLM_OUT1 | diff --git a/arch/arm/include/asm/arch-tegra/clk_rst.h b/arch/arm/include/asm/arch-tegra/clk_rst.h index 8c3be9151..7b548c229 100644 --- a/arch/arm/include/asm/arch-tegra/clk_rst.h +++ b/arch/arm/include/asm/arch-tegra/clk_rst.h @@ -27,8 +27,7 @@  /* PLL registers - there are several PLLs in the clock controller */  struct clk_pll {  	uint pll_base;		/* the control register */ -	uint pll_out;		/* output control */ -	uint reserved; +	uint pll_out[2];	/* output control */  	uint pll_misc;		/* other misc things */  }; @@ -112,6 +111,14 @@ struct clk_rst_ctlr {  #define PLL_DIVM_SHIFT		0  #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 */  #define PLL_CPCON_SHIFT		8  #define PLL_CPCON_MASK		(15U << PLL_CPCON_SHIFT) diff --git a/arch/arm/include/asm/arch-tegra/clock.h b/arch/arm/include/asm/arch-tegra/clock.h index 3eff163e8..eac1dc266 100644 --- a/arch/arm/include/asm/arch-tegra/clock.h +++ b/arch/arm/include/asm/arch-tegra/clock.h @@ -58,6 +58,18 @@ unsigned long clock_start_pll(enum clock_id id, u32 divm, u32 divn,  		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.   *   * @param id	clock id to read (note: USB is not supported) diff --git a/arch/arm/include/asm/arch-tegra20/clock-tables.h b/arch/arm/include/asm/arch-tegra20/clock-tables.h index f2b276908..53708e047 100644 --- a/arch/arm/include/asm/arch-tegra20/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra20/clock-tables.h @@ -176,6 +176,13 @@ enum periph_id {  	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 */  #define PERIPH_REG(id) ((id) >> 5)  |