arm: at91: clock: Add the generated clock support
Some peripherals may need a second clock source that may be different from the system clock. This second clock is the generated clock (GCK) and is managed by the PMC via PMC_PCR. For simplicity, the clock source of the GCK is fixed to PLLA_CLK. Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com> Reviewed-by: Andreas Bießmann <andreas.devel@googlemail.com>
This commit is contained in:
parent
79667b7b76
commit
c19000556e
3 changed files with 118 additions and 0 deletions
|
@ -5,11 +5,13 @@
|
|||
* Copyright (C) 2005 Ivan Kokshaysky
|
||||
* Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
|
||||
* Copyright (C) 2013 Bo Shen <voice.shen@atmel.com>
|
||||
* Copyright (C) 2015 Wenyou Yang <wenyou.yang@atmel.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/at91_pmc.h>
|
||||
|
@ -173,3 +175,96 @@ void at91_periph_clk_disable(int id)
|
|||
|
||||
writel(regval, &pmc->pcr);
|
||||
}
|
||||
|
||||
int at91_enable_periph_generated_clk(u32 id, u32 clk_source, u32 div)
|
||||
{
|
||||
struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
|
||||
u32 regval, status;
|
||||
u32 timeout = 1000;
|
||||
|
||||
if (id > AT91_PMC_PCR_PID_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
if (div > 0xff)
|
||||
return -EINVAL;
|
||||
|
||||
writel(id, &pmc->pcr);
|
||||
regval = readl(&pmc->pcr);
|
||||
regval &= ~AT91_PMC_PCR_GCKCSS;
|
||||
regval &= ~AT91_PMC_PCR_GCKDIV;
|
||||
|
||||
switch (clk_source) {
|
||||
case GCK_CSS_SLOW_CLK:
|
||||
regval |= AT91_PMC_PCR_GCKCSS_SLOW_CLK;
|
||||
break;
|
||||
case GCK_CSS_MAIN_CLK:
|
||||
regval |= AT91_PMC_PCR_GCKCSS_MAIN_CLK;
|
||||
break;
|
||||
case GCK_CSS_PLLA_CLK:
|
||||
regval |= AT91_PMC_PCR_GCKCSS_PLLA_CLK;
|
||||
break;
|
||||
case GCK_CSS_UPLL_CLK:
|
||||
regval |= AT91_PMC_PCR_GCKCSS_UPLL_CLK;
|
||||
break;
|
||||
case GCK_CSS_MCK_CLK:
|
||||
regval |= AT91_PMC_PCR_GCKCSS_MCK_CLK;
|
||||
break;
|
||||
case GCK_CSS_AUDIO_CLK:
|
||||
regval |= AT91_PMC_PCR_GCKCSS_AUDIO_CLK;
|
||||
break;
|
||||
default:
|
||||
printf("Error GCK clock source selection!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regval |= AT91_PMC_PCR_CMD_WRITE |
|
||||
AT91_PMC_PCR_GCKDIV_(div) |
|
||||
AT91_PMC_PCR_GCKEN;
|
||||
|
||||
writel(regval, &pmc->pcr);
|
||||
|
||||
do {
|
||||
udelay(1);
|
||||
status = readl(&pmc->sr);
|
||||
} while ((!!(--timeout)) && (!(status & AT91_PMC_GCKRDY)));
|
||||
|
||||
if (!timeout)
|
||||
printf("Timeout waiting for GCK ready!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 at91_get_periph_generated_clk(u32 id)
|
||||
{
|
||||
struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
|
||||
u32 regval, clk_source, div;
|
||||
u32 freq;
|
||||
|
||||
if (id > AT91_PMC_PCR_PID_MASK)
|
||||
return 0;
|
||||
|
||||
writel(id, &pmc->pcr);
|
||||
regval = readl(&pmc->pcr);
|
||||
|
||||
clk_source = regval & AT91_PMC_PCR_GCKCSS;
|
||||
switch (clk_source) {
|
||||
case AT91_PMC_PCR_GCKCSS_SLOW_CLK:
|
||||
freq = CONFIG_SYS_AT91_SLOW_CLOCK;
|
||||
break;
|
||||
case AT91_PMC_PCR_GCKCSS_MAIN_CLK:
|
||||
freq = gd->arch.main_clk_rate_hz;
|
||||
break;
|
||||
case AT91_PMC_PCR_GCKCSS_PLLA_CLK:
|
||||
freq = gd->arch.plla_rate_hz;
|
||||
break;
|
||||
default:
|
||||
printf("Improper GCK clock source selection!\n");
|
||||
freq = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
div = ((regval & AT91_PMC_PCR_GCKDIV) >> AT91_PMC_PCR_GCKDIV_OFFSET);
|
||||
div += 1;
|
||||
|
||||
return freq / div;
|
||||
}
|
||||
|
|
|
@ -153,8 +153,20 @@ typedef struct at91_pmc {
|
|||
#define AT91_PMC_IXR_MOSCSELS 0x00010000
|
||||
|
||||
#define AT91_PMC_PCR_PID_MASK (0x3f)
|
||||
#define AT91_PMC_PCR_GCKCSS (0x7 << 8)
|
||||
#define AT91_PMC_PCR_GCKCSS_SLOW_CLK (0x0 << 8)
|
||||
#define AT91_PMC_PCR_GCKCSS_MAIN_CLK (0x1 << 8)
|
||||
#define AT91_PMC_PCR_GCKCSS_PLLA_CLK (0x2 << 8)
|
||||
#define AT91_PMC_PCR_GCKCSS_UPLL_CLK (0x3 << 8)
|
||||
#define AT91_PMC_PCR_GCKCSS_MCK_CLK (0x4 << 8)
|
||||
#define AT91_PMC_PCR_GCKCSS_AUDIO_CLK (0x5 << 8)
|
||||
#define AT91_PMC_PCR_CMD_WRITE (0x1 << 12)
|
||||
#define AT91_PMC_PCR_DIV (0x3 << 16)
|
||||
#define AT91_PMC_PCR_GCKDIV (0xff << 20)
|
||||
#define AT91_PMC_PCR_GCKDIV_(x) ((x & 0xff) << 20)
|
||||
#define AT91_PMC_PCR_GCKDIV_OFFSET 20
|
||||
#define AT91_PMC_PCR_EN (0x1 << 28)
|
||||
#define AT91_PMC_PCR_GCKEN (0x1 << 29)
|
||||
|
||||
#define AT91_PMC_PCK (1 << 0) /* Processor Clock */
|
||||
#define AT91RM9200_PMC_UDP (1 << 1) /* USB Devcice Port Clock [AT91RM9200 only] */
|
||||
|
@ -236,6 +248,7 @@ typedef struct at91_pmc {
|
|||
#define AT91_PMC_PCK1RDY (1 << 9) /* Programmable Clock 1 */
|
||||
#define AT91_PMC_PCK2RDY (1 << 10) /* Programmable Clock 2 */
|
||||
#define AT91_PMC_PCK3RDY (1 << 11) /* Programmable Clock 3 */
|
||||
#define AT91_PMC_GCKRDY (1 << 24)
|
||||
|
||||
#define AT91_PMC_PROTKEY 0x504d4301 /* Activation Code */
|
||||
#endif
|
||||
|
|
|
@ -13,6 +13,13 @@
|
|||
#include <asm/arch/at91_pmc.h>
|
||||
#include <asm/global_data.h>
|
||||
|
||||
#define GCK_CSS_SLOW_CLK 0
|
||||
#define GCK_CSS_MAIN_CLK 1
|
||||
#define GCK_CSS_PLLA_CLK 2
|
||||
#define GCK_CSS_UPLL_CLK 3
|
||||
#define GCK_CSS_MCK_CLK 4
|
||||
#define GCK_CSS_AUDIO_CLK 5
|
||||
|
||||
static inline unsigned long get_cpu_clk_rate(void)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
@ -119,4 +126,7 @@ static inline unsigned long get_pit_clk_rate(void)
|
|||
int at91_clock_init(unsigned long main_clock);
|
||||
void at91_periph_clk_enable(int id);
|
||||
void at91_periph_clk_disable(int id);
|
||||
int at91_enable_periph_generated_clk(u32 id, u32 clk_source, u32 div);
|
||||
u32 at91_get_periph_generated_clk(u32 id);
|
||||
|
||||
#endif /* __ASM_ARM_ARCH_CLK_H__ */
|
||||
|
|
Loading…
Reference in a new issue