1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2007 4 * Sascha Hauer, Pengutronix 5 * 6 * (C) Copyright 2009 Freescale Semiconductor, Inc. 7 */ 8 9#include <common.h> 10#include <init.h> 11#include <time.h> 12#include <asm/io.h> 13#include <div64.h> 14#include <asm/global_data.h> 15#include <asm/arch/imx-regs.h> 16#include <asm/arch/clock.h> 17#include <asm/arch/sys_proto.h> 18 19/* General purpose timers registers */ 20struct mxc_gpt { 21 unsigned int control; 22 unsigned int prescaler; 23 unsigned int status; 24 unsigned int nouse[6]; 25 unsigned int counter; 26}; 27 28static struct mxc_gpt *cur_gpt = (struct mxc_gpt *)GPT1_BASE_ADDR; 29 30/* General purpose timers bitfields */ 31#define GPTCR_SWR (1 << 15) /* Software reset */ 32#define GPTCR_24MEN (1 << 10) /* Enable 24MHz clock input */ 33#define GPTCR_FRR (1 << 9) /* Freerun / restart */ 34#define GPTCR_CLKSOURCE_32 (4 << 6) /* Clock source 32khz */ 35#define GPTCR_CLKSOURCE_OSC (5 << 6) /* Clock source OSC */ 36#define GPTCR_CLKSOURCE_PRE (1 << 6) /* Clock source PRECLK */ 37#define GPTCR_CLKSOURCE_MASK (0x7 << 6) 38#define GPTCR_TEN 1 /* Timer enable */ 39 40#define GPTPR_PRESCALER24M_SHIFT 12 41#define GPTPR_PRESCALER24M_MASK (0xF << GPTPR_PRESCALER24M_SHIFT) 42 43DECLARE_GLOBAL_DATA_PTR; 44 45static inline int gpt_has_clk_source_osc(void) 46{ 47 if (((is_mx6dq()) && (soc_rev() > CHIP_REV_1_0)) || 48 is_mx6dqp() || is_mx6sdl() || is_mx6sx() || is_mx6ul() || 49 is_mx6ull() || is_mx6sll() || is_mx7()) 50 return 1; 51 52 return 0; 53} 54 55static inline ulong gpt_get_clk(void) 56{ 57#ifdef CONFIG_MXC_GPT_HCLK 58 if (gpt_has_clk_source_osc()) 59 return MXC_HCLK >> 3; 60 else 61 return mxc_get_clock(MXC_IPG_PERCLK); 62#else 63 return MXC_CLK32; 64#endif 65} 66 67int timer_init(void) 68{ 69 int i; 70 71 /* setup GP Timer 1 */ 72 __raw_writel(GPTCR_SWR, &cur_gpt->control); 73 74 /* We have no udelay by now */ 75 for (i = 0; i < 100; i++) 76 __raw_writel(0, &cur_gpt->control); 77 78 i = __raw_readl(&cur_gpt->control); 79 i &= ~GPTCR_CLKSOURCE_MASK; 80 81#ifdef CONFIG_MXC_GPT_HCLK 82 if (gpt_has_clk_source_osc()) { 83 i |= GPTCR_CLKSOURCE_OSC | GPTCR_TEN; 84 85 /* 86 * For DL/S, SX, UL, ULL, SLL set 24Mhz OSC 87 * Enable bit and prescaler 88 */ 89 if (is_mx6sdl() || is_mx6sx() || is_mx6ul() || is_mx6ull() || 90 is_mx6sll() || is_mx7()) { 91 i |= GPTCR_24MEN; 92 93 /* Produce 3Mhz clock */ 94 __raw_writel((7 << GPTPR_PRESCALER24M_SHIFT), 95 &cur_gpt->prescaler); 96 } 97 } else { 98 i |= GPTCR_CLKSOURCE_PRE | GPTCR_TEN; 99 } 100#else 101 __raw_writel(0, &cur_gpt->prescaler); /* 32Khz */ 102 i |= GPTCR_CLKSOURCE_32 | GPTCR_TEN; 103#endif 104 __raw_writel(i, &cur_gpt->control); 105 106 gd->arch.tbl = __raw_readl(&cur_gpt->counter); 107 gd->arch.tbu = 0; 108 109 return 0; 110} 111 112unsigned long timer_read_counter(void) 113{ 114 return __raw_readl(&cur_gpt->counter); /* current tick value */ 115} 116 117/* 118 * This function is derived from PowerPC code (timebase clock frequency). 119 * On ARM it returns the number of timer ticks per second. 120 */ 121ulong get_tbclk(void) 122{ 123 return gpt_get_clk(); 124} 125 126/* 127 * This function is intended for SHORT delays only. 128 * It will overflow at around 10 seconds @ 400MHz, 129 * or 20 seconds @ 200MHz. 130 */ 131unsigned long usec2ticks(unsigned long _usec) 132{ 133 unsigned long long usec = _usec; 134 135 usec *= get_tbclk(); 136 usec += 999999; 137 do_div(usec, 1000000); 138 139 return usec; 140} 141