xref: /rk3399_ARM-atf/drivers/delay_timer/delay_timer.c (revision 82cb2c1ad9897473743f08437d0a3995bed561b9)
19055c7d1SRyan Harkin /*
29055c7d1SRyan Harkin  * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
39055c7d1SRyan Harkin  *
4*82cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
59055c7d1SRyan Harkin  */
69055c7d1SRyan Harkin 
79055c7d1SRyan Harkin #include <assert.h>
89055c7d1SRyan Harkin #include <delay_timer.h>
99055c7d1SRyan Harkin #include <platform_def.h>
109055c7d1SRyan Harkin 
119055c7d1SRyan Harkin /***********************************************************
129055c7d1SRyan Harkin  * The delay timer implementation
139055c7d1SRyan Harkin  ***********************************************************/
149055c7d1SRyan Harkin static const timer_ops_t *ops;
159055c7d1SRyan Harkin 
169055c7d1SRyan Harkin /***********************************************************
179055c7d1SRyan Harkin  * Delay for the given number of microseconds. The driver must
189055c7d1SRyan Harkin  * be initialized before calling this function.
199055c7d1SRyan Harkin  ***********************************************************/
209055c7d1SRyan Harkin void udelay(uint32_t usec)
219055c7d1SRyan Harkin {
229055c7d1SRyan Harkin 	assert(ops != 0 &&
239055c7d1SRyan Harkin 		(ops->clk_mult != 0) &&
249055c7d1SRyan Harkin 		(ops->clk_div != 0) &&
259055c7d1SRyan Harkin 		(ops->get_timer_value != 0));
269055c7d1SRyan Harkin 
270bcedb22SAntonio Nino Diaz 	uint32_t start, delta, total_delta;
289055c7d1SRyan Harkin 
290bcedb22SAntonio Nino Diaz 	assert(usec < UINT32_MAX / ops->clk_div);
300bcedb22SAntonio Nino Diaz 
319055c7d1SRyan Harkin 	start = ops->get_timer_value();
320bcedb22SAntonio Nino Diaz 
330bcedb22SAntonio Nino Diaz 	total_delta = (usec * ops->clk_div) / ops->clk_mult;
340bcedb22SAntonio Nino Diaz 
359055c7d1SRyan Harkin 	do {
360bcedb22SAntonio Nino Diaz 		/*
370bcedb22SAntonio Nino Diaz 		 * If the timer value wraps around, the subtraction will
380bcedb22SAntonio Nino Diaz 		 * overflow and it will still give the correct result.
390bcedb22SAntonio Nino Diaz 		 */
400bcedb22SAntonio Nino Diaz 		delta = start - ops->get_timer_value(); /* Decreasing counter */
410bcedb22SAntonio Nino Diaz 
420bcedb22SAntonio Nino Diaz 	} while (delta < total_delta);
439055c7d1SRyan Harkin }
449055c7d1SRyan Harkin 
459055c7d1SRyan Harkin /***********************************************************
469055c7d1SRyan Harkin  * Delay for the given number of milliseconds. The driver must
479055c7d1SRyan Harkin  * be initialized before calling this function.
489055c7d1SRyan Harkin  ***********************************************************/
499055c7d1SRyan Harkin void mdelay(uint32_t msec)
509055c7d1SRyan Harkin {
519055c7d1SRyan Harkin 	udelay(msec*1000);
529055c7d1SRyan Harkin }
539055c7d1SRyan Harkin 
549055c7d1SRyan Harkin /***********************************************************
559055c7d1SRyan Harkin  * Initialize the timer. The fields in the provided timer
569055c7d1SRyan Harkin  * ops pointer must be valid.
579055c7d1SRyan Harkin  ***********************************************************/
589055c7d1SRyan Harkin void timer_init(const timer_ops_t *ops_ptr)
599055c7d1SRyan Harkin {
609055c7d1SRyan Harkin 	assert(ops_ptr != 0  &&
619055c7d1SRyan Harkin 		(ops_ptr->clk_mult != 0) &&
629055c7d1SRyan Harkin 		(ops_ptr->clk_div != 0) &&
639055c7d1SRyan Harkin 		(ops_ptr->get_timer_value != 0));
649055c7d1SRyan Harkin 
659055c7d1SRyan Harkin 	ops = ops_ptr;
669055c7d1SRyan Harkin }
67