diff --git a/arch/arm/cpu/arm926ejs/at91/clock.c b/arch/arm/cpu/arm926ejs/at91/clock.c index ecf91f518..7a10a7787 100644 --- a/arch/arm/cpu/arm926ejs/at91/clock.c +++ b/arch/arm/cpu/arm926ejs/at91/clock.c @@ -11,47 +11,46 @@ * (at your option) any later version. */ -#include +#include #include #include #include #include -static unsigned long cpu_clk_rate_hz; -static unsigned long main_clk_rate_hz; -static unsigned long mck_rate_hz; -static unsigned long plla_rate_hz; -static unsigned long pllb_rate_hz; -static u32 at91_pllb_usb_init; +#if !defined(CONFIG_AT91FAMILY) +# error You need to define CONFIG_AT91FAMILY in your board config! +#endif + +DECLARE_GLOBAL_DATA_PTR; unsigned long get_cpu_clk_rate(void) { - return cpu_clk_rate_hz; + return gd->cpu_clk_rate_hz; } unsigned long get_main_clk_rate(void) { - return main_clk_rate_hz; + return gd->main_clk_rate_hz; } unsigned long get_mck_clk_rate(void) { - return mck_rate_hz; + return gd->mck_rate_hz; } unsigned long get_plla_clk_rate(void) { - return plla_rate_hz; + return gd->plla_rate_hz; } unsigned long get_pllb_clk_rate(void) { - return pllb_rate_hz; + return gd->pllb_rate_hz; } u32 get_pllb_init(void) { - return at91_pllb_usb_init; + return gd->at91_pllb_usb_init; } static unsigned long at91_css_to_rate(unsigned long css) @@ -60,11 +59,11 @@ static unsigned long at91_css_to_rate(unsigned long css) case AT91_PMC_MCKR_CSS_SLOW: return AT91_SLOW_CLOCK; case AT91_PMC_MCKR_CSS_MAIN: - return main_clk_rate_hz; + return gd->main_clk_rate_hz; case AT91_PMC_MCKR_CSS_PLLA: - return plla_rate_hz; + return gd->plla_rate_hz; case AT91_PMC_MCKR_CSS_PLLB: - return pllb_rate_hz; + return gd->pllb_rate_hz; } return 0; @@ -163,10 +162,10 @@ int at91_clock_init(unsigned long main_clock) main_clock = tmp * (AT91_SLOW_CLOCK / 16); } #endif - main_clk_rate_hz = main_clock; + gd->main_clk_rate_hz = main_clock; /* report if PLLA is more than mildly overclocked */ - plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar)); + gd->plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar)); #ifdef CONFIG_USB_ATMEL /* @@ -175,9 +174,9 @@ int at91_clock_init(unsigned long main_clock) * * REVISIT: assumes MCK doesn't derive from PLLB! */ - at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | + gd->at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_PLLBR_USBDIV_2; - pllb_rate_hz = at91_pll_rate(main_clock, at91_pllb_usb_init); + gd->pllb_rate_hz = at91_pll_rate(main_clock, gd->at91_pllb_usb_init); #endif /* @@ -187,30 +186,30 @@ int at91_clock_init(unsigned long main_clock) mckr = readl(&pmc->mckr); #if defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) /* plla divisor by 2 */ - plla_rate_hz /= (1 << ((mckr & 1 << 12) >> 12)); + gd->plla_rate_hz /= (1 << ((mckr & 1 << 12) >> 12)); #endif - mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK); - freq = mck_rate_hz; + gd->mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK); + freq = gd->mck_rate_hz; freq /= (1 << ((mckr & AT91_PMC_MCKR_PRES_MASK) >> 2)); /* prescale */ #if defined(CONFIG_AT91RM9200) /* mdiv */ - mck_rate_hz = freq / (1 + ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8)); + gd->mck_rate_hz = freq / (1 + ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8)); #elif defined(CONFIG_AT91SAM9G20) /* mdiv ; (x >> 7) = ((x >> 8) * 2) */ - mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) ? + gd->mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) ? freq / ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 7) : freq; if (mckr & AT91_PMC_MCKR_MDIV_MASK) freq /= 2; /* processor clock division */ #elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) - mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) == + gd->mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) == (AT91_PMC_MCKR_MDIV_2 | AT91_PMC_MCKR_MDIV_4) ? freq / 3 : freq / (1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8)); #else - mck_rate_hz = freq / (1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8)); + gd->mck_rate_hz = freq / (1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8)); #endif - cpu_clk_rate_hz = freq; + gd->cpu_clk_rate_hz = freq; return 0; } diff --git a/arch/arm/cpu/arm926ejs/at91/timer.c b/arch/arm/cpu/arm926ejs/at91/timer.c index 8efc34bcf..82b8d7e7d 100644 --- a/arch/arm/cpu/arm926ejs/at91/timer.c +++ b/arch/arm/cpu/arm926ejs/at91/timer.c @@ -30,55 +30,63 @@ #include #include +#if !defined(CONFIG_AT91FAMILY) +# error You need to define CONFIG_AT91FAMILY in your board config! +#endif + +DECLARE_GLOBAL_DATA_PTR; + /* * We're using the AT91CAP9/SAM9 PITC in 32 bit mode, by * setting the 20 bit counter period to its maximum (0xfffff). + * (See the relevant data sheets to understand that this really works) + * + * We do also mimic the typical powerpc way of incrementing + * two 32 bit registers called tbl and tbu. + * + * Those registers increment at 1/16 the main clock rate. */ -#define TIMER_LOAD_VAL 0xfffff -static ulong timestamp; -static ulong lastinc; -static ulong timer_freq; +#define TIMER_LOAD_VAL 0xfffff static inline unsigned long long tick_to_time(unsigned long long tick) { tick *= CONFIG_SYS_HZ; - do_div(tick, timer_freq); + do_div(tick, gd->timer_rate_hz); return tick; } static inline unsigned long long usec_to_tick(unsigned long long usec) { - usec *= timer_freq; + usec *= gd->timer_rate_hz; do_div(usec, 1000000); return usec; } -/* nothing really to do with interrupts, just starts up a counter. */ +/* + * Use the PITC in full 32 bit incrementing mode + */ int timer_init(void) { at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; at91_pit_t *pit = (at91_pit_t *) AT91_PIT_BASE; - /* - * Enable PITC Clock - * The clock is already enabled for system controller in boot - */ + + /* Enable PITC Clock */ writel(1 << AT91_ID_SYS, &pmc->pcer); /* Enable PITC */ writel(TIMER_LOAD_VAL | AT91_PIT_MR_EN , &pit->mr); - reset_timer_masked(); - - timer_freq = get_mck_clk_rate() >> 4; + gd->timer_rate_hz = gd->mck_rate_hz / 16; + gd->tbu = gd->tbl = 0; return 0; } /* - * timer without interrupts + * Get the current 64 bit timer tick count */ unsigned long long get_ticks(void) { @@ -86,28 +94,11 @@ unsigned long long get_ticks(void) ulong now = readl(&pit->piir); - if (now >= lastinc) /* normal mode (non roll) */ - /* move stamp forward with absolut diff ticks */ - timestamp += (now - lastinc); - else /* we have rollover of incrementer */ - timestamp += (0xFFFFFFFF - lastinc) + now; - lastinc = now; - return timestamp; -} - -void reset_timer_masked(void) -{ - /* reset time */ - at91_pit_t *pit = (at91_pit_t *) AT91_PIT_BASE; - - /* capture current incrementer value time */ - lastinc = readl(&pit->piir); - timestamp = 0; /* start "advancing" time stamp from 0 */ -} - -ulong get_timer_masked(void) -{ - return tick_to_time(get_ticks()); + /* increment tbu if tbl has rolled over */ + if (now < gd->tbl) + gd->tbu++; + gd->tbl = now; + return (((unsigned long long)gd->tbu) << 32) | gd->tbl; } void __udelay(unsigned long usec) @@ -119,24 +110,32 @@ void __udelay(unsigned long usec) tmp = get_ticks() + tmo; /* get current timestamp */ while (get_ticks() < tmp) /* loop till event */ - /*NOP*/; + ; } +/* + * reset_timer() and get_timer(base) are a pair of functions that are used by + * some timeout/sleep mechanisms in u-boot. + * + * reset_timer() marks the current time as epoch and + * get_timer(base) works relative to that epoch. + * + * The time is used in CONFIG_SYS_HZ units! + */ void reset_timer(void) { - reset_timer_masked(); + gd->timer_reset_value = get_ticks(); } ulong get_timer(ulong base) { - return get_timer_masked () - base; + return tick_to_time(get_ticks() - gd->timer_reset_value) - base; } /* - * This function is derived from PowerPC code (timebase clock frequency). - * On ARM it returns the number of timer ticks per second. + * Return the number of timer ticks per second. */ ulong get_tbclk(void) { - return timer_freq; + return gd->timer_rate_hz; } diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index 6152f348f..6dae4328e 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -47,6 +47,20 @@ typedef struct global_data { #ifdef CONFIG_FSL_ESDHC unsigned long sdhc_clk; #endif +#ifdef CONFIG_AT91FAMILY + /* "static data" needed by at91's clock.c */ + unsigned long cpu_clk_rate_hz; + unsigned long main_clk_rate_hz; + unsigned long mck_rate_hz; + unsigned long plla_rate_hz; + unsigned long pllb_rate_hz; + unsigned long at91_pllb_usb_init; + /* "static data" needed by at91's timer.c */ + unsigned long timer_rate_hz; + unsigned long tbl; + unsigned long tbu; + unsigned long long timer_reset_value; +#endif #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) unsigned long relocaddr; /* Start address of U-Boot in RAM */ phys_size_t ram_size; /* RAM size */