uboot/arch/arm/mach-imx/syscounter.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2015 Freescale Semiconductor, Inc.
   4 *
   5 * The file use ls102xa/timer.c as a reference.
   6 */
   7
   8#include <common.h>
   9#include <init.h>
  10#include <time.h>
  11#include <asm/io.h>
  12#include <div64.h>
  13#include <asm/arch/imx-regs.h>
  14#include <asm/arch/sys_proto.h>
  15#include <asm/mach-imx/syscounter.h>
  16#include <linux/delay.h>
  17
  18DECLARE_GLOBAL_DATA_PTR;
  19
  20/*
  21 * This function is intended for SHORT delays only.
  22 * It will overflow at around 10 seconds @ 400MHz,
  23 * or 20 seconds @ 200MHz.
  24 */
  25unsigned long usec2ticks(unsigned long usec)
  26{
  27        ulong ticks;
  28
  29        if (usec < 1000)
  30                ticks = ((usec * (get_tbclk()/1000)) + 500) / 1000;
  31        else
  32                ticks = ((usec / 10) * (get_tbclk() / 100000));
  33
  34        return ticks;
  35}
  36
  37static inline unsigned long long tick_to_time(unsigned long long tick)
  38{
  39        unsigned long freq;
  40
  41        asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (freq));
  42
  43        tick *= CONFIG_SYS_HZ;
  44        do_div(tick, freq);
  45
  46        return tick;
  47}
  48
  49static inline unsigned long long us_to_tick(unsigned long long usec)
  50{
  51        unsigned long freq;
  52
  53        asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (freq));
  54
  55        usec = usec * freq  + 999999;
  56        do_div(usec, 1000000);
  57
  58        return usec;
  59}
  60
  61#ifndef CONFIG_SKIP_LOWLEVEL_INIT
  62int timer_init(void)
  63{
  64        struct sctr_regs *sctr = (struct sctr_regs *)SCTR_BASE_ADDR;
  65        unsigned long val, freq;
  66
  67        freq = CONFIG_SC_TIMER_CLK;
  68        asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r" (freq));
  69
  70        writel(freq, &sctr->cntfid0);
  71
  72        /* Enable system counter */
  73        val = readl(&sctr->cntcr);
  74        val &= ~(SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1);
  75        val |= SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG;
  76        writel(val, &sctr->cntcr);
  77
  78        gd->arch.tbl = 0;
  79        gd->arch.tbu = 0;
  80
  81        return 0;
  82}
  83#endif
  84
  85unsigned long long get_ticks(void)
  86{
  87        unsigned long long now;
  88
  89        asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (now));
  90
  91        gd->arch.tbl = (unsigned long)(now & 0xffffffff);
  92        gd->arch.tbu = (unsigned long)(now >> 32);
  93
  94        return now;
  95}
  96
  97ulong get_timer(ulong base)
  98{
  99        return tick_to_time(get_ticks()) - base;
 100}
 101
 102void __udelay(unsigned long usec)
 103{
 104        unsigned long long tmp;
 105        ulong tmo;
 106
 107        tmo = us_to_tick(usec);
 108        tmp = get_ticks() + tmo;        /* get current timestamp */
 109
 110        while (get_ticks() < tmp)       /* loop till event */
 111                 /*NOP*/;
 112}
 113
 114/*
 115 * This function is derived from PowerPC code (timebase clock frequency).
 116 * On ARM it returns the number of timer ticks per second.
 117 */
 118ulong get_tbclk(void)
 119{
 120        unsigned long freq;
 121
 122        asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (freq));
 123
 124        return freq;
 125}
 126