1852bd07cSMinkyu Kang /* 2852bd07cSMinkyu Kang * Copyright (C) 2009 Samsung Electronics 3852bd07cSMinkyu Kang * Heungjun Kim <riverful.kim@samsung.com> 4852bd07cSMinkyu Kang * Inki Dae <inki.dae@samsung.com> 5852bd07cSMinkyu Kang * Minkyu Kang <mk7.kang@samsung.com> 6852bd07cSMinkyu Kang * 7852bd07cSMinkyu Kang * See file CREDITS for list of people who contributed to this 8852bd07cSMinkyu Kang * project. 9852bd07cSMinkyu Kang * 10852bd07cSMinkyu Kang * This program is free software; you can redistribute it and/or 11852bd07cSMinkyu Kang * modify it under the terms of the GNU General Public License as 12852bd07cSMinkyu Kang * published by the Free Software Foundation; either version 2 of 13852bd07cSMinkyu Kang * the License, or (at your option) any later version. 14852bd07cSMinkyu Kang * 15852bd07cSMinkyu Kang * This program is distributed in the hope that it will be useful, 16852bd07cSMinkyu Kang * but WITHOUT ANY WARRANTY; without even the implied warranty of 17852bd07cSMinkyu Kang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18852bd07cSMinkyu Kang * GNU General Public License for more details. 19852bd07cSMinkyu Kang * 20852bd07cSMinkyu Kang * You should have received a copy of the GNU General Public License 21852bd07cSMinkyu Kang * along with this program; if not, write to the Free Software 22852bd07cSMinkyu Kang * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 23852bd07cSMinkyu Kang * MA 02111-1307 USA 24852bd07cSMinkyu Kang */ 25852bd07cSMinkyu Kang 26852bd07cSMinkyu Kang #include <common.h> 27852bd07cSMinkyu Kang #include <asm/io.h> 28852bd07cSMinkyu Kang #include <asm/arch/pwm.h> 29852bd07cSMinkyu Kang #include <asm/arch/clk.h> 3070fc52dfSMinkyu Kang #include <pwm.h> 31852bd07cSMinkyu Kang 329aca34d6SMinkyu Kang DECLARE_GLOBAL_DATA_PTR; 33852bd07cSMinkyu Kang 343936b4f0SZhong Hongbo unsigned long get_current_tick(void); 353936b4f0SZhong Hongbo 36852bd07cSMinkyu Kang /* macro to read the 16 bit timer */ 3737168dabSMinkyu Kang static inline struct s5p_timer *s5p_get_base_timer(void) 38852bd07cSMinkyu Kang { 3937168dabSMinkyu Kang return (struct s5p_timer *)samsung_get_base_timer(); 40852bd07cSMinkyu Kang } 41852bd07cSMinkyu Kang 423d00c0cbSSimon Glass /** 433d00c0cbSSimon Glass * Read the countdown timer. 443d00c0cbSSimon Glass * 453d00c0cbSSimon Glass * This operates at 1MHz and counts downwards. It will wrap about every 463d00c0cbSSimon Glass * hour (2^32 microseconds). 473d00c0cbSSimon Glass * 483d00c0cbSSimon Glass * @return current value of timer 493d00c0cbSSimon Glass */ 503d00c0cbSSimon Glass static unsigned long timer_get_us_down(void) 513d00c0cbSSimon Glass { 523d00c0cbSSimon Glass struct s5p_timer *const timer = s5p_get_base_timer(); 533d00c0cbSSimon Glass 543d00c0cbSSimon Glass return readl(&timer->tcnto4); 553d00c0cbSSimon Glass } 563d00c0cbSSimon Glass 57852bd07cSMinkyu Kang int timer_init(void) 58852bd07cSMinkyu Kang { 5970fc52dfSMinkyu Kang /* PWM Timer 4 */ 603d00c0cbSSimon Glass pwm_init(4, MUX_DIV_4, 0); 61*34b5ee1fSGabe Black pwm_config(4, 100000, 100000); 6270fc52dfSMinkyu Kang pwm_enable(4); 63852bd07cSMinkyu Kang 643d00c0cbSSimon Glass /* Use this as the current monotonic time in us */ 653d00c0cbSSimon Glass gd->arch.timer_reset_value = 0; 663d00c0cbSSimon Glass 673d00c0cbSSimon Glass /* Use this as the last timer value we saw */ 683d00c0cbSSimon Glass gd->arch.lastinc = timer_get_us_down(); 693936b4f0SZhong Hongbo reset_timer_masked(); 703936b4f0SZhong Hongbo 71852bd07cSMinkyu Kang return 0; 72852bd07cSMinkyu Kang } 73852bd07cSMinkyu Kang 74852bd07cSMinkyu Kang /* 75852bd07cSMinkyu Kang * timer without interrupts 76852bd07cSMinkyu Kang */ 77852bd07cSMinkyu Kang unsigned long get_timer(unsigned long base) 78852bd07cSMinkyu Kang { 793d00c0cbSSimon Glass ulong now = timer_get_us_down(); 803d00c0cbSSimon Glass 813d00c0cbSSimon Glass /* 823d00c0cbSSimon Glass * Increment the time by the amount elapsed since the last read. 833d00c0cbSSimon Glass * The timer may have wrapped around, but it makes no difference to 843d00c0cbSSimon Glass * our arithmetic here. 853d00c0cbSSimon Glass */ 863d00c0cbSSimon Glass gd->arch.timer_reset_value += gd->arch.lastinc - now; 873d00c0cbSSimon Glass gd->arch.lastinc = now; 883d00c0cbSSimon Glass 893d00c0cbSSimon Glass /* Divide by 1000 to convert from us to ms */ 903d00c0cbSSimon Glass return gd->arch.timer_reset_value / 1000 - base; 91852bd07cSMinkyu Kang } 92852bd07cSMinkyu Kang 93f24869d3SChe-Liang Chiou unsigned long timer_get_us(void) 94f24869d3SChe-Liang Chiou { 95f24869d3SChe-Liang Chiou static unsigned long base_time_us; 96f24869d3SChe-Liang Chiou 97f24869d3SChe-Liang Chiou struct s5p_timer *const timer = 98f24869d3SChe-Liang Chiou (struct s5p_timer *)samsung_get_base_timer(); 99f24869d3SChe-Liang Chiou unsigned long now_downward_us = readl(&timer->tcnto4); 100f24869d3SChe-Liang Chiou 101f24869d3SChe-Liang Chiou if (!base_time_us) 102f24869d3SChe-Liang Chiou base_time_us = now_downward_us; 103f24869d3SChe-Liang Chiou 104f24869d3SChe-Liang Chiou /* Note that this timer counts downward. */ 105f24869d3SChe-Liang Chiou return base_time_us - now_downward_us; 106f24869d3SChe-Liang Chiou } 107f24869d3SChe-Liang Chiou 108852bd07cSMinkyu Kang /* delay x useconds */ 109852bd07cSMinkyu Kang void __udelay(unsigned long usec) 110852bd07cSMinkyu Kang { 1113d00c0cbSSimon Glass unsigned long count_value; 112852bd07cSMinkyu Kang 1133d00c0cbSSimon Glass count_value = timer_get_us_down(); 1143d00c0cbSSimon Glass while ((int)(count_value - timer_get_us_down()) < (int)usec) 1153d00c0cbSSimon Glass ; 116852bd07cSMinkyu Kang } 117852bd07cSMinkyu Kang 118852bd07cSMinkyu Kang void reset_timer_masked(void) 119852bd07cSMinkyu Kang { 12037168dabSMinkyu Kang struct s5p_timer *const timer = s5p_get_base_timer(); 121852bd07cSMinkyu Kang 122852bd07cSMinkyu Kang /* reset time */ 123582601daSSimon Glass gd->arch.lastinc = readl(&timer->tcnto4); 12466ee6923SSimon Glass gd->arch.tbl = 0; 125852bd07cSMinkyu Kang } 126852bd07cSMinkyu Kang 127852bd07cSMinkyu Kang /* 128852bd07cSMinkyu Kang * This function is derived from PowerPC code (read timebase as long long). 129852bd07cSMinkyu Kang * On ARM it just returns the timer value. 130852bd07cSMinkyu Kang */ 131852bd07cSMinkyu Kang unsigned long long get_ticks(void) 132852bd07cSMinkyu Kang { 133852bd07cSMinkyu Kang return get_timer(0); 134852bd07cSMinkyu Kang } 135852bd07cSMinkyu Kang 136852bd07cSMinkyu Kang /* 137852bd07cSMinkyu Kang * This function is derived from PowerPC code (timebase clock frequency). 138852bd07cSMinkyu Kang * On ARM it returns the number of timer ticks per second. 139852bd07cSMinkyu Kang */ 140852bd07cSMinkyu Kang unsigned long get_tbclk(void) 141852bd07cSMinkyu Kang { 142852bd07cSMinkyu Kang return CONFIG_SYS_HZ; 143852bd07cSMinkyu Kang } 144