diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index a33dfe4507264bb9e2943f1a04699ccf7f155d76..b87772cd3d322d6dc70e56c4fb8649437e72782f 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -112,12 +112,34 @@ static void pmc_sys_mode(struct clk *clk, int is_on) at91_sys_write(AT91_PMC_SCDR, clk->pmc_mask); } +static void pmc_uckr_mode(struct clk *clk, int is_on) +{ + unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR); + + if (is_on) { + is_on = AT91_PMC_LOCKU; + at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask); + } else + at91_sys_write(AT91_CKGR_UCKR, uckr & ~(clk->pmc_mask)); + + do { + cpu_relax(); + } while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKU) != is_on); +} + /* USB function clocks (PLLB must be 48 MHz) */ static struct clk udpck = { .name = "udpck", .parent = &pllb, .mode = pmc_sys_mode, }; +static struct clk utmi_clk = { + .name = "utmi_clk", + .parent = &main_clk, + .pmc_mask = AT91_PMC_UPLLEN, /* in CKGR_UCKR */ + .mode = pmc_uckr_mode, + .type = CLK_TYPE_PLL, +}; static struct clk uhpck = { .name = "uhpck", .parent = &pllb, @@ -361,7 +383,7 @@ static void __init init_programmable_clock(struct clk *clk) static int at91_clk_show(struct seq_file *s, void *unused) { - u32 scsr, pcsr, sr; + u32 scsr, pcsr, uckr = 0, sr; struct clk *clk; seq_printf(s, "SCSR = %8x\n", scsr = at91_sys_read(AT91_PMC_SCSR)); @@ -370,6 +392,8 @@ static int at91_clk_show(struct seq_file *s, void *unused) seq_printf(s, "MCFR = %8x\n", at91_sys_read(AT91_CKGR_MCFR)); seq_printf(s, "PLLA = %8x\n", at91_sys_read(AT91_CKGR_PLLAR)); seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR)); + if (cpu_is_at91cap9()) + seq_printf(s, "UCKR = %8x\n", uckr = at91_sys_read(AT91_CKGR_UCKR)); seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR)); seq_printf(s, "SR = %8x\n", sr = at91_sys_read(AT91_PMC_SR)); @@ -382,6 +406,8 @@ static int at91_clk_show(struct seq_file *s, void *unused) state = (scsr & clk->pmc_mask) ? "on" : "off"; else if (clk->mode == pmc_periph_mode) state = (pcsr & clk->pmc_mask) ? "on" : "off"; + else if (clk->mode == pmc_uckr_mode) + state = (uckr & clk->pmc_mask) ? "on" : "off"; else if (clk->pmc_mask) state = (sr & clk->pmc_mask) ? "on" : "off"; else if (clk == &clk32k || clk == &main_clk) @@ -581,6 +607,17 @@ int __init at91_clock_init(unsigned long main_clock) udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init); uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init); + /* + * USB HS clock init + */ + if (cpu_is_at91cap9()) { + /* + * multiplier is hard-wired to 40 + * (obtain the USB High Speed 480 MHz when input is 12 MHz) + */ + utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz; + } + /* * MCK and CPU derive from one of those primary clocks. * For now, assume this parentage won't change. @@ -598,6 +635,9 @@ int __init at91_clock_init(unsigned long main_clock) for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++) list_add_tail(&standard_pmc_clocks[i]->node, &clocks); + if (cpu_is_at91cap9()) + list_add_tail(&utmi_clk.node, &clocks); + /* MCK and CPU clock are "always on" */ clk_enable(&mck); diff --git a/include/asm-arm/arch-at91/at91_pmc.h b/include/asm-arm/arch-at91/at91_pmc.h index c2b13c2801557c83490eee49e8d524db9793b638..2001e81f226780b0764bbf7fc9bb7d30ee06593b 100644 --- a/include/asm-arm/arch-at91/at91_pmc.h +++ b/include/asm-arm/arch-at91/at91_pmc.h @@ -39,10 +39,14 @@ #define AT91_PMC_PCSR (AT91_PMC + 0x18) /* Peripheral Clock Status Register */ #define AT91_CKGR_UCKR (AT91_PMC + 0x1C) /* UTMI Clock Register [SAM9RL, CAP9] */ +#define AT91_PMC_UPLLEN (1 << 16) /* UTMI PLL Enable */ +#define AT91_PMC_UPLLCOUNT (0xf << 20) /* UTMI PLL Start-up Time */ +#define AT91_PMC_BIASEN (1 << 24) /* UTMI BIAS Enable */ +#define AT91_PMC_BIASCOUNT (0xf << 28) /* UTMI PLL Start-up Time */ #define AT91_CKGR_MOR (AT91_PMC + 0x20) /* Main Oscillator Register [not on SAM9RL] */ #define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */ -#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass [AT91SAM926x only] */ +#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass [SAM9x, CAP9] */ #define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */ #define AT91_CKGR_MCFR (AT91_PMC + 0x24) /* Main Clock Frequency Register */ @@ -97,6 +101,7 @@ #define AT91_PMC_LOCKA (1 << 1) /* PLLA Lock */ #define AT91_PMC_LOCKB (1 << 2) /* PLLB Lock */ #define AT91_PMC_MCKRDY (1 << 3) /* Master Clock */ +#define AT91_PMC_LOCKU (1 << 6) /* UPLL Lock [AT91CAP9 only] */ #define AT91_PMC_PCK0RDY (1 << 8) /* Programmable Clock 0 */ #define AT91_PMC_PCK1RDY (1 << 9) /* Programmable Clock 1 */ #define AT91_PMC_PCK2RDY (1 << 10) /* Programmable Clock 2 */ diff --git a/include/asm-arm/arch-at91/board.h b/include/asm-arm/arch-at91/board.h index dc189f01c5b3c969071057484e75b4d72df236db..1f247028686d9d894d7dc5021ea266518b0c26a7 100644 --- a/include/asm-arm/arch-at91/board.h +++ b/include/asm-arm/arch-at91/board.h @@ -36,6 +36,7 @@ #include #include #include +#include /* USB Device */ struct at91_udc_data { @@ -45,6 +46,9 @@ struct at91_udc_data { }; extern void __init at91_add_device_udc(struct at91_udc_data *data); + /* USB High Speed Device */ +extern void __init at91_add_device_usba(struct usba_platform_data *data); + /* Compact Flash */ struct at91_cf_data { u8 irq_pin; /* I/O IRQ */