1/* 2 * Copyright (C) 2010 Linaro Limited 3 * John Rigby <john.rigby@linaro.org> 4 * 5 * Based on original from Linux kernel source and 6 * internal ST-Ericsson U-Boot source. 7 * (C) Copyright 2009 Alessandro Rubini 8 * (C) Copyright 2010 ST-Ericsson 9 * 10 * SPDX-License-Identifier: GPL-2.0+ 11 */ 12 13#include <common.h> 14#include <asm/io.h> 15#include <asm/arch/hardware.h> 16 17DECLARE_GLOBAL_DATA_PTR; 18 19/* 20 * The MTU device has some interrupt control registers 21 * followed by 4 timers. 22 */ 23 24/* The timers */ 25struct u8500_mtu_timer { 26 u32 lr; /* Load value */ 27 u32 cv; /* Current value */ 28 u32 cr; /* Control reg */ 29 u32 bglr; /* ??? */ 30}; 31 32/* The MTU that contains the timers */ 33struct u8500_mtu { 34 u32 imsc; /* Interrupt mask set/clear */ 35 u32 ris; /* Raw interrupt status */ 36 u32 mis; /* Masked interrupt status */ 37 u32 icr; /* Interrupt clear register */ 38 struct u8500_mtu_timer pt[4]; 39}; 40 41/* bits for the control register */ 42#define MTU_CR_ONESHOT 0x01 /* if 0 = wraps reloading from BGLR */ 43#define MTU_CR_32BITS 0x02 44 45#define MTU_CR_PRESCALE_1 0x00 46#define MTU_CR_PRESCALE_16 0x04 47#define MTU_CR_PRESCALE_256 0x08 48#define MTU_CR_PRESCALE_MASK 0x0c 49 50#define MTU_CR_PERIODIC 0x40 /* if 0 = free-running */ 51#define MTU_CR_ENA 0x80 52 53/* 54 * The MTU is clocked at 133 MHz by default. (V1 and later) 55 */ 56#define TIMER_CLOCK (133 * 1000 * 1000 / 16) 57#define COUNT_TO_USEC(x) ((x) * 16 / 133) 58#define USEC_TO_COUNT(x) ((x) * 133 / 16) 59#define TICKS_PER_HZ (TIMER_CLOCK / CONFIG_SYS_HZ) 60#define TICKS_TO_HZ(x) ((x) / TICKS_PER_HZ) 61#define TIMER_LOAD_VAL 0xffffffff 62 63/* 64 * MTU timer to use (from 0 to 3). 65 */ 66#define MTU_TIMER 2 67 68static struct u8500_mtu_timer *timer_base = 69 &((struct u8500_mtu *)U8500_MTU0_BASE_V1)->pt[MTU_TIMER]; 70 71/* macro to read the 32 bit timer: since it decrements, we invert read value */ 72#define READ_TIMER() (~readl(&timer_base->cv)) 73 74/* Configure a free-running, auto-wrap counter with /16 prescaler */ 75int timer_init(void) 76{ 77 writel(MTU_CR_ENA | MTU_CR_PRESCALE_16 | MTU_CR_32BITS, 78 &timer_base->cr); 79 return 0; 80} 81 82ulong get_timer_masked(void) 83{ 84 /* current tick value */ 85 ulong now = TICKS_TO_HZ(READ_TIMER()); 86 87 if (now >= gd->arch.lastinc) { /* normal (non rollover) */ 88 gd->arch.tbl += (now - gd->arch.lastinc); 89 } else { /* rollover */ 90 gd->arch.tbl += (TICKS_TO_HZ(TIMER_LOAD_VAL) - 91 gd->arch.lastinc) + now; 92 } 93 gd->arch.lastinc = now; 94 return gd->arch.tbl; 95} 96 97/* Delay x useconds */ 98void __udelay(ulong usec) 99{ 100 long tmo = usec * (TIMER_CLOCK / 1000) / 1000; 101 ulong now, last = READ_TIMER(); 102 103 while (tmo > 0) { 104 now = READ_TIMER(); 105 if (now > last) /* normal (non rollover) */ 106 tmo -= now - last; 107 else /* rollover */ 108 tmo -= TIMER_LOAD_VAL - last + now; 109 last = now; 110 } 111} 112 113ulong get_timer(ulong base) 114{ 115 return get_timer_masked() - base; 116} 117 118/* 119 * Emulation of Power architecture long long timebase. 120 * 121 * TODO: Support gd->arch.tbu for real long long timebase. 122 */ 123unsigned long long get_ticks(void) 124{ 125 return get_timer(0); 126} 127 128/* 129 * Emulation of Power architecture timebase. 130 * NB: Low resolution compared to Power tbclk. 131 */ 132ulong get_tbclk(void) 133{ 134 return CONFIG_SYS_HZ; 135} 136