273 lines
7.1 KiB
C
273 lines
7.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 "app_utils.h"
|
|
#include "analog.h"
|
|
#include "cmsis.h"
|
|
#include "hal_timer.h"
|
|
#include "hal_trace.h"
|
|
#include "hal_wdt.h"
|
|
#include "pmu.h"
|
|
#ifdef RTOS
|
|
#include "cmsis_os.h"
|
|
#endif
|
|
|
|
#define FREQ_FREE 0UL
|
|
#define FREQ_26M 26UL
|
|
#define FREQ_52M 52UL
|
|
#define FREQ_78M 78UL
|
|
#define FREQ_104M 104UL
|
|
#define FREQ_208M 208UL
|
|
|
|
/*
|
|
* qos_users, quality of services users, this kind of user must run with the
|
|
* minist frequency they requiested, if there are more users, the frequency
|
|
* should be boost for these users
|
|
* e.g. the key word recorgnithion function request 26M Hz, and the music
|
|
* also need 26M, if both of them are running, the cpu freq should boost to
|
|
* 26M + 26M = 52M Hz
|
|
*/
|
|
/*
|
|
* NOTE:
|
|
* The macro QOS_USERS works only when the APP_SYSFREQ_USER_APP_XXX is not large
|
|
* than 32, currently this works, but if the are more user, another way needed
|
|
*/
|
|
#define QOS_USERS \
|
|
((1 << (APP_SYSFREQ_USER_AI_VOICE)) | (1 << (APP_SYSFREQ_USER_BT_A2DP)))
|
|
|
|
static const uint32_t freq_map[] = {
|
|
[HAL_CMU_FREQ_32K] = FREQ_FREE, [HAL_CMU_FREQ_26M] = FREQ_26M,
|
|
[HAL_CMU_FREQ_52M] = FREQ_52M, [HAL_CMU_FREQ_78M] = FREQ_78M,
|
|
[HAL_CMU_FREQ_104M] = FREQ_104M, [HAL_CMU_FREQ_208M] = FREQ_208M,
|
|
};
|
|
|
|
static const uint32_t user_map[] = {
|
|
[0] = APP_SYSFREQ_USER_AI_VOICE,
|
|
[1] = APP_SYSFREQ_USER_BT_A2DP,
|
|
};
|
|
/*
|
|
* qos_freqs_map
|
|
* filled with user's freq, one user's freq occupy 4bits,
|
|
* that limit the frequecy number is not large than 16
|
|
*
|
|
* bit field structure:
|
|
-----------------------------------------------------
|
|
|user7 | user6 |..................|user1 | user 0|
|
|
-----------------------------------------------------
|
|
|31~28 | 27~24 |..................|7~4 | 3~0 |
|
|
-----------------------------------------------------
|
|
*
|
|
* Ok, this is ugly, but there is not so much frequecy level,
|
|
* and maybe work for a long time
|
|
*/
|
|
static uint32_t qos_freqs_map;
|
|
|
|
/*
|
|
* qos_users_map
|
|
* filled with user's number, one user's occupy 1 bit,
|
|
*
|
|
bit field structure:
|
|
-----------------------------------------------------
|
|
|user31~7(reseverd)| user7 |........| user 1| user 0|
|
|
-----------------------------------------------------
|
|
*
|
|
*/
|
|
static uint32_t qos_users_map;
|
|
|
|
static int app_qosfreq_req(enum APP_SYSFREQ_USER_T user,
|
|
enum APP_SYSFREQ_FREQ_T freq) {
|
|
int ret;
|
|
int qos_freq_num = 0;
|
|
uint32_t max_qos_freq = 0;
|
|
int user_idx;
|
|
int i;
|
|
uint32_t lock;
|
|
|
|
if (freq >= APP_SYSFREQ_FREQ_QTY)
|
|
return -1;
|
|
|
|
lock = int_lock();
|
|
for (i = 0; i < ARRAY_SIZE(user_map); i++) {
|
|
if (user == user_map[i]) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= ARRAY_SIZE(user_map)) {
|
|
int_unlock(lock);
|
|
ASSERT(0, "can not find qos user");
|
|
return 0;
|
|
}
|
|
|
|
user_idx = i;
|
|
if ((int)freq != (int)HAL_CMU_FREQ_32K) { // require freq
|
|
qos_freqs_map &= ~(0xf << (4 * i));
|
|
qos_freqs_map |= freq << (4 * i);
|
|
qos_users_map |= 1 << user_idx;
|
|
} else { // release freq
|
|
qos_freqs_map &= ~(0xf << (4 * i));
|
|
qos_users_map &= ~(1 << user_idx);
|
|
}
|
|
|
|
// scan the qos_user_map and sum every user's request freq
|
|
for (i = 0; i < ARRAY_SIZE(user_map); i++) {
|
|
if ((qos_users_map >> i) & 0x1) {
|
|
uint32_t real_freq;
|
|
int freq_num;
|
|
|
|
freq_num = (qos_freqs_map >> (4 * i)) & 0xf;
|
|
real_freq = freq_map[freq_num];
|
|
max_qos_freq += real_freq;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(freq_map); i++) {
|
|
if (i) {
|
|
if ((max_qos_freq > freq_map[i - 1]) && (max_qos_freq <= freq_map[i])) {
|
|
qos_freq_num = i;
|
|
break;
|
|
}
|
|
} else {
|
|
if (max_qos_freq == freq_map[i]) {
|
|
qos_freq_num = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i >= ARRAY_SIZE(freq_map)) {
|
|
qos_freq_num = (HAL_CMU_FREQ_QTY - 1);
|
|
int_unlock(lock);
|
|
TRACE(0, "WARNING: required sysfreq exceed");
|
|
// ASSERT(0, "can not find actual freq");
|
|
return 0;
|
|
}
|
|
|
|
user = APP_SYSFREQ_USER_QOS;
|
|
TRACE(2, "User %d require sysfreq %d", user, qos_freq_num);
|
|
ret = hal_sysfreq_req((enum HAL_SYSFREQ_USER_T)user,
|
|
(enum HAL_CMU_FREQ_T)qos_freq_num);
|
|
|
|
int_unlock(lock);
|
|
return ret;
|
|
}
|
|
|
|
int app_sysfreq_req(enum APP_SYSFREQ_USER_T user,
|
|
enum APP_SYSFREQ_FREQ_T freq) {
|
|
int ret;
|
|
|
|
// if user is qos user
|
|
if ((1 << user) & QOS_USERS) {
|
|
ret = app_qosfreq_req(user, freq);
|
|
} else { // if user is NOT qos user
|
|
ret = hal_sysfreq_req((enum HAL_SYSFREQ_USER_T)user,
|
|
(enum HAL_CMU_FREQ_T)freq);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef RTOS
|
|
|
|
extern int rtx_task_idle_health_check(void);
|
|
static void watchdog_ping_handler(void const *n);
|
|
static osTimerId wdt_ping_timer_id;
|
|
osTimerDef(wdt_ping_timer, watchdog_ping_handler);
|
|
static uint32_t wdt_ping_period;
|
|
|
|
static void watchdog_ping(void) {
|
|
hal_wdt_ping(HAL_WDT_ID_0);
|
|
#ifndef CHIP_BEST2000
|
|
pmu_wdt_feed();
|
|
#endif
|
|
}
|
|
|
|
static void app_wdt_irq_handle(enum HAL_WDT_ID_T id, uint32_t status) {
|
|
analog_aud_codec_mute();
|
|
ASSERT(0, "%s id:%d status:%d", __func__, id, status);
|
|
}
|
|
|
|
static void pmu_wdt_irq_handle(void) {
|
|
analog_aud_codec_mute();
|
|
ASSERT(1, "%s", __func__);
|
|
}
|
|
|
|
static void watchdog_ping_handler(void const *unused) {
|
|
int ret;
|
|
|
|
watchdog_ping();
|
|
ret = rtx_task_idle_health_check();
|
|
if (ret < 0) {
|
|
ASSERT(0, "System soft lockup");
|
|
}
|
|
|
|
osTimerStart(wdt_ping_timer_id, wdt_ping_period);
|
|
}
|
|
|
|
int app_wdt_open(int seconds) {
|
|
uint32_t lock = int_lock();
|
|
|
|
hal_wdt_set_irq_callback(HAL_WDT_ID_0, app_wdt_irq_handle);
|
|
hal_wdt_set_timeout(HAL_WDT_ID_0, seconds);
|
|
hal_wdt_start(HAL_WDT_ID_0);
|
|
pmu_wdt_set_irq_handler(pmu_wdt_irq_handle);
|
|
#ifndef CHIP_BEST2000
|
|
pmu_wdt_config(seconds * 1100, seconds * 1100);
|
|
pmu_wdt_start();
|
|
#endif
|
|
int_unlock(lock);
|
|
wdt_ping_timer_id = osTimerCreate(osTimer(wdt_ping_timer), osTimerOnce, NULL);
|
|
if (!wdt_ping_timer_id) {
|
|
TRACE(0, "Warning: can not create watchdog ping timer");
|
|
return -1;
|
|
}
|
|
wdt_ping_period = seconds * 1000 / 4;
|
|
|
|
osTimerStart(wdt_ping_timer_id, wdt_ping_period);
|
|
return 0;
|
|
}
|
|
|
|
int app_wdt_reopen(int seconds) {
|
|
uint32_t lock = int_lock();
|
|
hal_wdt_stop(HAL_WDT_ID_0);
|
|
hal_wdt_set_timeout(HAL_WDT_ID_0, seconds);
|
|
hal_wdt_start(HAL_WDT_ID_0);
|
|
#ifndef CHIP_BEST2000
|
|
pmu_wdt_config(seconds * 1000, seconds * 1000);
|
|
pmu_wdt_start();
|
|
#endif
|
|
int_unlock(lock);
|
|
|
|
osTimerStart(wdt_ping_timer_id, wdt_ping_period);
|
|
return 0;
|
|
}
|
|
|
|
int app_wdt_close(void) {
|
|
uint32_t lock;
|
|
|
|
osTimerStop(wdt_ping_timer_id);
|
|
|
|
lock = int_lock();
|
|
hal_wdt_stop(HAL_WDT_ID_0);
|
|
#ifndef CHIP_BEST2000
|
|
pmu_wdt_stop();
|
|
#endif
|
|
int_unlock(lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|