uboot/arch/arm/cpu/arm1136/mx35/timer.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2007
   3 * Sascha Hauer, Pengutronix
   4 *
   5 * (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
   6 *
   7 * SPDX-License-Identifier:     GPL-2.0+
   8 */
   9
  10#include <common.h>
  11#include <asm/io.h>
  12#include <div64.h>
  13#include <asm/arch/imx-regs.h>
  14#include <asm/arch/crm_regs.h>
  15#include <asm/arch/clock.h>
  16
  17DECLARE_GLOBAL_DATA_PTR;
  18
  19#define timestamp       (gd->arch.tbl)
  20#define lastinc         (gd->arch.lastinc)
  21
  22/* General purpose timers bitfields */
  23#define GPTCR_SWR       (1<<15) /* Software reset */
  24#define GPTCR_FRR       (1<<9)  /* Freerun / restart */
  25#define GPTCR_CLKSOURCE_32   (4<<6)     /* Clock source */
  26#define GPTCR_TEN       (1)     /* Timer enable */
  27
  28/*
  29 * "time" is measured in 1 / CONFIG_SYS_HZ seconds,
  30 * "tick" is internal timer period
  31 */
  32/* ~0.4% error - measured with stop-watch on 100s boot-delay */
  33static inline unsigned long long tick_to_time(unsigned long long tick)
  34{
  35        tick *= CONFIG_SYS_HZ;
  36        do_div(tick, MXC_CLK32);
  37
  38        return tick;
  39}
  40
  41static inline unsigned long long us_to_tick(unsigned long long us)
  42{
  43        us = us * MXC_CLK32 + 999999;
  44        do_div(us, 1000000);
  45
  46        return us;
  47}
  48
  49/*
  50 * nothing really to do with interrupts, just starts up a counter.
  51 * The 32KHz 32-bit timer overruns in 134217 seconds
  52 */
  53int timer_init(void)
  54{
  55        int i;
  56        struct gpt_regs *gpt = (struct gpt_regs *)GPT1_BASE_ADDR;
  57        struct ccm_regs *ccm = (struct ccm_regs *)CCM_BASE_ADDR;
  58
  59        /* setup GP Timer 1 */
  60        writel(GPTCR_SWR, &gpt->ctrl);
  61
  62        writel(readl(&ccm->cgr1) | 3 << MXC_CCM_CGR1_GPT_OFFSET, &ccm->cgr1);
  63
  64        for (i = 0; i < 100; i++)
  65                writel(0, &gpt->ctrl); /* We have no udelay by now */
  66        writel(0, &gpt->pre); /* prescaler = 1 */
  67        /* Freerun Mode, 32KHz input */
  68        writel(readl(&gpt->ctrl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR,
  69                        &gpt->ctrl);
  70        writel(readl(&gpt->ctrl) | GPTCR_TEN, &gpt->ctrl);
  71
  72        return 0;
  73}
  74
  75unsigned long long get_ticks(void)
  76{
  77        struct gpt_regs *gpt = (struct gpt_regs *)GPT1_BASE_ADDR;
  78        ulong now = readl(&gpt->counter); /* current tick value */
  79
  80        if (now >= lastinc) {
  81                /*
  82                 * normal mode (non roll)
  83                 * move stamp forward with absolut diff ticks
  84                 */
  85                timestamp += (now - lastinc);
  86        } else {
  87                /* we have rollover of incrementer */
  88                timestamp += (0xFFFFFFFF - lastinc) + now;
  89        }
  90        lastinc = now;
  91        return timestamp;
  92}
  93
  94ulong get_timer_masked(void)
  95{
  96        /*
  97         * get_ticks() returns a long long (64 bit), it wraps in
  98         * 2^64 / MXC_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~
  99         * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in
 100         * 5 * 10^6 days - long enough.
 101         */
 102        return tick_to_time(get_ticks());
 103}
 104
 105ulong get_timer(ulong base)
 106{
 107        return get_timer_masked() - base;
 108}
 109
 110/* delay x useconds AND preserve advance timstamp value */
 111void __udelay(unsigned long usec)
 112{
 113        unsigned long long tmp;
 114        ulong tmo;
 115
 116        tmo = us_to_tick(usec);
 117        tmp = get_ticks() + tmo;        /* get current timestamp */
 118
 119        while (get_ticks() < tmp)       /* loop till event */
 120                 /*NOP*/;
 121}
 122
 123/*
 124 * This function is derived from PowerPC code (timebase clock frequency).
 125 * On ARM it returns the number of timer ticks per second.
 126 */
 127ulong get_tbclk(void)
 128{
 129        return MXC_CLK32;
 130}
 131