pinebuds/platform/hal/hal_sysfreq.c
2022-08-15 17:20:27 +08:00

160 lines
4.1 KiB
C

/***************************************************************************
*
* Copyright 2015-2019 BES.
* All rights reserved. All unpublished rights reserved.
*
* No part of this work may be used or reproduced in any form or by any
* means, or stored in a database or retrieval system, without prior written
* permission of BES.
*
* Use of this work is governed by a license granted by BES.
* This work contains confidential and proprietary information of
* BES. which is protected by copyright, trade secret,
* trademark and other intellectual property rights.
*
****************************************************************************/
#include "plat_types.h"
#include "hal_sysfreq.h"
#include "hal_location.h"
#include "hal_trace.h"
#include "cmsis.h"
#ifndef ROM_BUILD
#include "pmu.h"
#endif
static uint32_t BOOT_BSS_LOC sysfreq_bundle[(HAL_SYSFREQ_USER_QTY + 3) / 4];
static uint8_t * const sysfreq_per_user = (uint8_t *)&sysfreq_bundle[0];
static enum HAL_SYSFREQ_USER_T BOOT_DATA_LOC top_user = HAL_SYSFREQ_USER_QTY;
static enum HAL_CMU_FREQ_T BOOT_DATA_LOC min_sysfreq = HAL_CMU_FREQ_26M;
static enum HAL_CMU_FREQ_T hal_sysfreq_revise_freq(enum HAL_CMU_FREQ_T freq)
{
return freq > min_sysfreq ? freq : min_sysfreq;
}
void hal_sysfreq_set_min_freq(enum HAL_CMU_FREQ_T freq)
{
uint32_t lock;
lock = int_lock();
if (min_sysfreq < freq) {
min_sysfreq = freq;
if (min_sysfreq > hal_sysfreq_get()) {
hal_cmu_sys_set_freq(min_sysfreq);
}
}
int_unlock(lock);
}
int hal_sysfreq_req(enum HAL_SYSFREQ_USER_T user, enum HAL_CMU_FREQ_T freq)
{
uint32_t lock;
enum HAL_CMU_FREQ_T cur_sys_freq;
int i;
if (user >= HAL_SYSFREQ_USER_QTY) {
return 1;
}
if (freq >= HAL_CMU_FREQ_QTY) {
return 2;
}
lock = int_lock();
cur_sys_freq = hal_sysfreq_get();
sysfreq_per_user[user] = freq;
if (freq == cur_sys_freq) {
top_user = user;
} else if (freq > cur_sys_freq) {
top_user = user;
freq = hal_sysfreq_revise_freq(freq);
#ifndef ROM_BUILD
pmu_sys_freq_config(freq);
#ifdef ULTRA_LOW_POWER
// Enable PLL if required
hal_cmu_low_freq_mode_disable(hal_sysfreq_revise_freq(cur_sys_freq), freq);
#endif
#endif
hal_cmu_sys_set_freq(freq);
} else /* if (freq < cur_sys_freq) */ {
if (top_user == user || top_user == HAL_SYSFREQ_USER_QTY) {
if (top_user == user) {
freq = sysfreq_per_user[0];
user = 0;
for (i = 1; i < HAL_SYSFREQ_USER_QTY; i++) {
if (freq < sysfreq_per_user[i]) {
freq = sysfreq_per_user[i];
user = i;
}
}
}
top_user = user;
if (freq != cur_sys_freq) {
freq = hal_sysfreq_revise_freq(freq);
hal_cmu_sys_set_freq(freq);
#ifndef ROM_BUILD
#ifdef ULTRA_LOW_POWER
// Disable PLL if capable
hal_cmu_low_freq_mode_enable(hal_sysfreq_revise_freq(cur_sys_freq), freq);
#endif
pmu_sys_freq_config(freq);
#endif
}
}
}
int_unlock(lock);
return 0;
}
enum HAL_CMU_FREQ_T hal_sysfreq_get(void)
{
if (top_user < HAL_SYSFREQ_USER_QTY) {
return sysfreq_per_user[top_user];
} else {
return hal_cmu_sys_get_freq();
}
}
enum HAL_CMU_FREQ_T hal_sysfreq_get_hw_freq(void)
{
if (top_user < HAL_SYSFREQ_USER_QTY) {
return hal_sysfreq_revise_freq(sysfreq_per_user[top_user]);
} else {
return hal_cmu_sys_get_freq();
}
}
int hal_sysfreq_busy(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(sysfreq_bundle); i++) {
if (sysfreq_bundle[i] != 0) {
return 1;
}
}
return 0;
}
void hal_sysfreq_print(void)
{
int i;
for (i = 0; i < HAL_SYSFREQ_USER_QTY; i++) {
if (sysfreq_per_user[i] != 0) {
TRACE(2,"*** SYSFREQ user=%d freq=%d", i, sysfreq_per_user[i]);
}
}
TRACE(1,"*** SYSFREQ top_user=%d", top_user);
}