101 lines
2.6 KiB
C
101 lines
2.6 KiB
C
/**
|
|
* @file udelay.c
|
|
* @brief udelay common source
|
|
*
|
|
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include <udelay/udelay.h>
|
|
#include <armv7-r/pmu.h>
|
|
#include <sdrv_ckgen.h>
|
|
#include <clock_ip.h>
|
|
#include <debug.h>
|
|
|
|
static uint32_t core_frequency;
|
|
static uint32_t cnt_per_us;
|
|
|
|
static inline uint32_t udelay_us_to_counter(uint32_t us)
|
|
{
|
|
if (us > MAX_UDELAY) {
|
|
us = MAX_UDELAY;
|
|
}
|
|
|
|
if (cnt_per_us == 0x0) {
|
|
core_frequency = sdrv_ckgen_bus_get_rate(CLK_NODE(g_ckgen_bus_cr5_sf),
|
|
CKGEN_BUS_CLK_OUT_M);
|
|
|
|
cnt_per_us = (uint32_t)(core_frequency / 1000000);
|
|
}
|
|
|
|
return cnt_per_us * us;
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize ARM Performance Monitor cycle counter
|
|
*
|
|
* sdrv udelay is implement by arm pmu cycle counter, you must
|
|
* call this function before use udelay().
|
|
*
|
|
* note: this function must called after cpu clock has configurated.
|
|
*/
|
|
void sdrv_pmu_counter_init(void)
|
|
{
|
|
core_frequency = sdrv_ckgen_bus_get_rate(CLK_NODE(g_ckgen_bus_cr5_sf),
|
|
CKGEN_BUS_CLK_OUT_M);
|
|
|
|
cnt_per_us = (uint32_t)(core_frequency / 1000000);
|
|
|
|
if (!pmu_cycle_cntr_status()) {
|
|
pmu_enable();
|
|
pmu_start_cycle_cntr(false);
|
|
}
|
|
else {
|
|
pmu_stop_clear_cycle_cntr();
|
|
pmu_start_cycle_cntr(false);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief delay for microseconds
|
|
*
|
|
* @param us microseconds
|
|
*/
|
|
void udelay(uint32_t us)
|
|
{
|
|
#if CONFIG_ARM_WITH_PMU
|
|
if (!pmu_cycle_cntr_status()) {
|
|
sdrv_pmu_counter_init();
|
|
}
|
|
|
|
if (pmu_cycle_cntr_status() && (us > 0)) {
|
|
uint32_t tick_to, start_tick, current_tick;
|
|
uint32_t tmt = 0u;
|
|
|
|
start_tick = pmu_get_cycle_cntr();
|
|
|
|
/* make sure cycled information: 100 loops takes ~5us */
|
|
while ((start_tick == pmu_get_cycle_cntr()) && (tmt++ < 100u));
|
|
|
|
/* timeout check is not a must here, just in case the pmccntr abnormal */
|
|
if (tmt < 100u) {
|
|
tick_to = start_tick + udelay_us_to_counter(us);
|
|
|
|
if (tick_to > start_tick) {
|
|
/* tick_to not overflowed */
|
|
do {
|
|
current_tick = pmu_get_cycle_cntr();
|
|
} while ((current_tick < tick_to)
|
|
&& (current_tick > start_tick));
|
|
} else {
|
|
/* current_tick overflowed */
|
|
do {
|
|
current_tick = pmu_get_cycle_cntr();
|
|
} while ((current_tick > start_tick) || (current_tick < tick_to));
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|