/*************************************************************************** * * 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); }