Merged in masayuki2009/nuttx.nuttx/lc823450_dvfs_auto (pull request #604)
lc823450 dvfs auto * arch/arm/src/lc823450: Fix up_enable_irq() timing for I2S. In previous commit, I2S IRQ might be sometimes assigned to CPU1 when CONFIG_SMP=y. This change fixes this issue. Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com> * arch/arm/src/lc823450: Refactor timer driver. Introduce lc823450_timer.h and move lc823450_timerisr.c to lc823450_timer.c Add MTM timer APIs for DVFS. Introduce up_rtc_gettime() for CONFIG_RTC_HIRES. Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com> * arch/arm/src/lc823450: Introduce idle time calculation in DVFS Also, DVFS autonomous mode based on CPU idle time is supported. NOTE: voltage control is still disabled. Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com> * configs/lc823450-xgevk: Update defconfigs Enable RTC_HIRES instead of RTC_DATETIME (audio/rndis) Disable TCP_WRITE_BUFFERS and change SCHED_LPWORKPRIORITY (rndis) Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com> * configs/lc823450-xgevk: Update README.txt Update SMP and DVFS related part Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com> Approved-by: Gregory Nutt <gnutt@nuttx.org>
This commit is contained in:
parent
9812f6f932
commit
82e94a9948
@ -84,7 +84,7 @@ endif
|
||||
CHIP_ASRCS =
|
||||
|
||||
CHIP_CSRCS = lc823450_start.c lc823450_irq.c lc823450_idle.c
|
||||
CHIP_CSRCS += lc823450_timerisr.c lc823450_lowputc.c
|
||||
CHIP_CSRCS += lc823450_timer.c lc823450_lowputc.c
|
||||
CHIP_CSRCS += lc823450_serial.c lc823450_clockconfig.c lc823450_syscontrol.c
|
||||
CHIP_CSRCS += lc823450_gpio.c
|
||||
|
||||
|
@ -51,6 +51,8 @@
|
||||
#include "lc823450_syscontrol.h"
|
||||
#include "lc823450_intc.h"
|
||||
#include "lc823450_sdc.h"
|
||||
#include "lc823450_gpio.h"
|
||||
#include "lc823450_timer.h"
|
||||
#include "lc823450_dvfs2.h"
|
||||
|
||||
/****************************************************************************
|
||||
@ -61,6 +63,25 @@
|
||||
#define FREQ_080 1
|
||||
#define FREQ_040 2
|
||||
|
||||
#define FREQ_KP 2
|
||||
#define FREQ_UP 1
|
||||
#define FREQ_DN 0
|
||||
|
||||
#define UP_THRESHOLD 20
|
||||
#define DN_THRESHOLD 60
|
||||
|
||||
#ifndef CONFIG_SMP_NCPUS
|
||||
# define CONFIG_SMP_NCPUS 1
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DVFS_CHANGE_VOLTAGE
|
||||
# define CORE12V_PIN (GPIO_PORT2 | GPIO_PIN1)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_RTC_HIRES
|
||||
# error "Should be enabled to get high-accuracy for CPU idle time"
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
@ -90,28 +111,49 @@ static struct freq_entry _dvfs_idl_tbl[3] =
|
||||
static uint16_t _dvfs_cur_idx = 0; /* current speed index */
|
||||
static uint16_t _dvfs_cur_hdiv = 3;
|
||||
static uint16_t _dvfs_cur_mdiv = OSCCNT_MAINDIV_1;
|
||||
static uint16_t _dvfs_core12v = 0;
|
||||
|
||||
#if 0
|
||||
static uint16_t _dvfs_init_timeout = (5 * 100); /* in ticks */
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMP) && (CONFIG_SMP_NCPUS == 2)
|
||||
static uint8_t _dvfs_cpu_is_active[CONFIG_SMP_NCPUS];
|
||||
#endif
|
||||
|
||||
static void lc823450_dvfs_set_div(int idx, int tbl);
|
||||
|
||||
static uint64_t g_idle_starttime[CONFIG_SMP_NCPUS];
|
||||
static uint64_t g_idle_totaltime[CONFIG_SMP_NCPUS];
|
||||
static uint64_t g_idle_totaltime0[CONFIG_SMP_NCPUS];
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
int8_t g_dvfs_enabled = 0;
|
||||
int8_t g_dvfs_auto = 0;
|
||||
uint16_t g_dvfs_cur_freq = 160;
|
||||
|
||||
uint32_t g_dvfs_freq_stat[3] =
|
||||
{
|
||||
0, 0, 0
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_get_current_time()
|
||||
****************************************************************************/
|
||||
|
||||
static uint64_t _get_current_time64(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
#ifdef CONFIG_CLOCK_MONOTONIC
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
#endif
|
||||
return (uint64_t)ts.tv_sec * NSEC_PER_SEC + (uint64_t)ts.tv_nsec;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lc823450_dvfs_update_lpm
|
||||
****************************************************************************/
|
||||
@ -121,7 +163,7 @@ static void lc823450_dvfs_update_lpm(int freq)
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SMP) && (CONFIG_SMP_NCPUS == 2)
|
||||
#if CONFIG_SMP_NCPUS == 2
|
||||
static int _dvfs_another_cpu_state(int me)
|
||||
{
|
||||
if (0 == me)
|
||||
@ -135,6 +177,50 @@ static int _dvfs_another_cpu_state(int me)
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lc823450_dvfs_oneshot
|
||||
* Callback for 1 shot timer
|
||||
****************************************************************************/
|
||||
|
||||
int lc823450_dvfs_oneshot(int irq, uint32_t *regs, FAR void *arg)
|
||||
{
|
||||
/* voltage has reached at 1.2V */
|
||||
|
||||
_dvfs_core12v = 1;
|
||||
|
||||
lc823450_mtm_stop_oneshot();
|
||||
|
||||
/* go to max freq */
|
||||
|
||||
lc823450_dvfs_set_div(FREQ_160, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lc832450_set_core_voltage
|
||||
* high=true (1.2V), high=false (1.0V)
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_DVFS_CHANGE_VOLTAGE
|
||||
static void lc832450_set_core_voltage(bool high)
|
||||
{
|
||||
if (false == high)
|
||||
{
|
||||
_dvfs_core12v = 0;
|
||||
}
|
||||
|
||||
lc823450_gpio_write(CORE12V_PIN, (int)high);
|
||||
|
||||
if (high)
|
||||
{
|
||||
/* start 3ms timer to change internal dividers */
|
||||
|
||||
lc823450_mtm_start_oneshot(3);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lc823450_dvfs_set_div
|
||||
* Set dividers in the OSC block
|
||||
@ -160,6 +246,16 @@ static void lc823450_dvfs_set_div(int idx, int tbl)
|
||||
t_mdiv = _dvfs_idl_tbl[idx].mdiv;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DVFS_CHANGE_VOLTAGE
|
||||
if (100 < target && !_dvfs_core12v)
|
||||
{
|
||||
/* Set high voltage (i.e. 1.2v) */
|
||||
|
||||
lc832450_set_core_voltage(true);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (100 < target)
|
||||
{
|
||||
/* Set ROM wait cycle (CPU=1wait) */
|
||||
@ -242,6 +338,18 @@ static void lc823450_dvfs_set_div(int idx, int tbl)
|
||||
_dvfs_cur_mdiv = t_mdiv;
|
||||
g_dvfs_cur_freq = target;
|
||||
|
||||
|
||||
#ifdef CONFIG_DVFS_CHANGE_VOLTAGE
|
||||
/* NOTE: check the index instead of the target freq */
|
||||
|
||||
if (_dvfs_core12v && _dvfs_cur_idx != FREQ_160)
|
||||
{
|
||||
/* set to lower voltage (i.e. 1.0v) */
|
||||
|
||||
lc832450_set_core_voltage(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (100 > target)
|
||||
{
|
||||
/* Clear ROM wait cycle (CPU=0wait) */
|
||||
@ -251,10 +359,123 @@ static void lc823450_dvfs_set_div(int idx, int tbl)
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lc823450_dvfs_change_idx
|
||||
* up: 1=clock up, 0=clock down
|
||||
* called in autonomous mode from interrupt context
|
||||
****************************************************************************/
|
||||
|
||||
static void lc823450_dvfs_change_idx(int up)
|
||||
{
|
||||
uint16_t idx = _dvfs_cur_idx;
|
||||
|
||||
/* NOTE: clock index is in reverse order to the speed */
|
||||
|
||||
/* clock up */
|
||||
|
||||
if (up && (FREQ_160 < idx))
|
||||
{
|
||||
idx--;
|
||||
}
|
||||
|
||||
/* clock down */
|
||||
|
||||
if (!up && (FREQ_040 > idx))
|
||||
{
|
||||
idx++;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DVFS_EXCLUDE_40M
|
||||
if (idx == FREQ_040)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (idx != _dvfs_cur_idx)
|
||||
{
|
||||
lc823450_dvfs_set_div(idx, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lc823450_dvfs_do_auto
|
||||
****************************************************************************/
|
||||
|
||||
static void lc823450_dvfs_do_auto(uint32_t idle[])
|
||||
{
|
||||
uint32_t state[CONFIG_SMP_NCPUS];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_SMP_NCPUS; i++)
|
||||
{
|
||||
if (UP_THRESHOLD >= idle[i])
|
||||
{
|
||||
state[i] = FREQ_UP;
|
||||
}
|
||||
else if (DN_THRESHOLD <= idle[i])
|
||||
{
|
||||
state[i] = FREQ_DN;
|
||||
}
|
||||
else
|
||||
{
|
||||
state[i] = FREQ_KP;
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_SMP_NCPUS == 1
|
||||
if (FREQ_UP == state[0])
|
||||
#elif CONFIG_SMP_NCPUS == 2
|
||||
if (FREQ_UP == state[0] || FREQ_UP == state[1])
|
||||
#endif
|
||||
{
|
||||
lc823450_dvfs_change_idx(FREQ_UP);
|
||||
}
|
||||
|
||||
#if CONFIG_SMP_NCPUS == 1
|
||||
if (FREQ_DN == state[0])
|
||||
#elif CONFIG_SMP_NCPUS == 2
|
||||
if (FREQ_DN == state[0] && FREQ_DN == state[1])
|
||||
#endif
|
||||
{
|
||||
lc823450_dvfs_change_idx(FREQ_DN);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lc823450_dvfs_get_idletime
|
||||
****************************************************************************/
|
||||
|
||||
void lc823450_dvfs_get_idletime(uint64_t idletime[])
|
||||
{
|
||||
irqstate_t flags = spin_lock_irqsave();
|
||||
|
||||
/* First, copy g_idle_totaltime to the caller */
|
||||
|
||||
memcpy(idletime, g_idle_totaltime, sizeof(g_idle_totaltime));
|
||||
|
||||
#if CONFIG_SMP_NCPUS == 2
|
||||
int me = up_cpu_index();
|
||||
|
||||
if (0 == _dvfs_another_cpu_state(me))
|
||||
{
|
||||
/* Another CPU is in idle, so consider this situation */
|
||||
|
||||
int cpu = (me == 0) ? 1 : 0;
|
||||
idletime[cpu] += (_get_current_time64() - g_idle_starttime[cpu]);
|
||||
|
||||
/* NOTE: g_idletotaltime[cpu] must not be updated */
|
||||
}
|
||||
#endif
|
||||
|
||||
spin_unlock_irqrestore(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lc823450_get_apb
|
||||
* Assumption: CPU=APB
|
||||
@ -267,22 +488,39 @@ uint32_t lc823450_get_apb(void)
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lc823450_dvfs_tick_callback
|
||||
* This callback is called in the timer interupt
|
||||
* This callback is called in the timer interupt on CPU0
|
||||
****************************************************************************/
|
||||
|
||||
void lc823450_dvfs_tick_callback(void)
|
||||
{
|
||||
#if 0
|
||||
if (_dvfs_init_timeout)
|
||||
{
|
||||
_dvfs_init_timeout--;
|
||||
uint64_t tmp_idle_total[CONFIG_SMP_NCPUS];
|
||||
uint32_t idle[CONFIG_SMP_NCPUS];
|
||||
int i;
|
||||
|
||||
if (0 == _dvfs_init_timeout)
|
||||
if (g_dvfs_enabled && g_dvfs_auto)
|
||||
{
|
||||
g_dvfs_enabled = 1;
|
||||
lc823450_dvfs_get_idletime(tmp_idle_total);
|
||||
|
||||
/* Calculate idle ratio for each CPU */
|
||||
|
||||
for (i = 0; i < CONFIG_SMP_NCPUS; i++)
|
||||
{
|
||||
idle[i] = 100 * (tmp_idle_total[i] - g_idle_totaltime0[i])
|
||||
/ NSEC_PER_TICK;
|
||||
}
|
||||
|
||||
/* Update g_idle_totaltime0 */
|
||||
|
||||
memcpy(g_idle_totaltime0, tmp_idle_total, sizeof(tmp_idle_total));
|
||||
|
||||
/* Do autonomous mode */
|
||||
|
||||
lc823450_dvfs_do_auto(idle);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Update freqency statistics */
|
||||
|
||||
g_dvfs_freq_stat[_dvfs_cur_idx]++;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -293,18 +531,22 @@ void lc823450_dvfs_enter_idle(void)
|
||||
{
|
||||
irqstate_t flags = spin_lock_irqsave();
|
||||
|
||||
if (0 == g_dvfs_enabled)
|
||||
{
|
||||
goto exit_with_error;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SMP) && (CONFIG_SMP_NCPUS == 2)
|
||||
int me = up_cpu_index();
|
||||
|
||||
/* Update my state first : 0 (idle) */
|
||||
|
||||
_dvfs_cpu_is_active[me] = 0;
|
||||
|
||||
/* Update my idle start time */
|
||||
|
||||
g_idle_starttime[me] = _get_current_time64();
|
||||
|
||||
if (0 == g_dvfs_enabled)
|
||||
{
|
||||
goto exit_with_error;
|
||||
}
|
||||
|
||||
#if CONFIG_SMP_NCPUS == 2
|
||||
/* check if another core is still active */
|
||||
|
||||
if (_dvfs_another_cpu_state(me))
|
||||
@ -313,7 +555,6 @@ void lc823450_dvfs_enter_idle(void)
|
||||
|
||||
goto exit_with_error;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DVFS_CHECK_SDC
|
||||
@ -340,18 +581,16 @@ void lc823450_dvfs_exit_idle(int irq)
|
||||
{
|
||||
irqstate_t flags = spin_lock_irqsave();
|
||||
|
||||
int me = up_cpu_index();
|
||||
uint64_t d;
|
||||
uint64_t now;
|
||||
|
||||
if (0 == g_dvfs_enabled)
|
||||
{
|
||||
goto exit_with_error;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SMP) && (CONFIG_SMP_NCPUS == 2)
|
||||
int me = up_cpu_index();
|
||||
|
||||
/* Update my state first: 1 (active) */
|
||||
|
||||
_dvfs_cpu_is_active[me] = 1;
|
||||
|
||||
#if CONFIG_SMP_NCPUS == 2
|
||||
/* Check if another core is already active */
|
||||
|
||||
if (_dvfs_another_cpu_state(me))
|
||||
@ -367,6 +606,21 @@ void lc823450_dvfs_exit_idle(int irq)
|
||||
lc823450_dvfs_set_div(_dvfs_cur_idx, 0);
|
||||
|
||||
exit_with_error:
|
||||
|
||||
if (0 == _dvfs_cpu_is_active[me])
|
||||
{
|
||||
/* In case of idle to active transition */
|
||||
/* Accumulate idle total time on this CPU */
|
||||
|
||||
now = _get_current_time64();
|
||||
d = now - g_idle_starttime[me];
|
||||
g_idle_totaltime[me] += d;
|
||||
}
|
||||
|
||||
/* Finally update my state : 1 (active) */
|
||||
|
||||
_dvfs_cpu_is_active[me] = 1;
|
||||
|
||||
spin_unlock_irqrestore(flags);
|
||||
}
|
||||
|
||||
@ -410,9 +664,11 @@ int lc823450_dvfs_set_freq(int freq)
|
||||
idx = FREQ_080;
|
||||
break;
|
||||
|
||||
#ifndef CONFIG_DVFS_EXCLUDE_40M
|
||||
case 40:
|
||||
idx = FREQ_040;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
ret = -1;
|
||||
|
@ -59,11 +59,14 @@ extern "C"
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
void lc823450_dvfs_get_idletime(uint64_t idaletime[]);
|
||||
|
||||
void lc823450_dvfs_set_min(uint8_t id, uint16_t mhz);
|
||||
void lc823450_dvfs_enter_idle(void);
|
||||
void lc823450_dvfs_exit_idle(int irq);
|
||||
int lc823450_dvfs_set_freq(int freq);
|
||||
void lc823450_dvfs_tick_callback(void);
|
||||
int lc823450_dvfs_oneshot(int irq, uint32_t *regs, FAR void *arg);
|
||||
|
||||
int dvfs_procfs_register(void);
|
||||
|
||||
|
@ -484,6 +484,10 @@ FAR struct i2s_dev_s *lc823450_i2sdev_initialize(void)
|
||||
|
||||
irq_attach(LC823450_IRQ_AUDIOBUF0, _i2s_isr, NULL);
|
||||
|
||||
/* Enable IRQ for Audio Buffer */
|
||||
|
||||
up_enable_irq(LC823450_IRQ_AUDIOBUF0);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* Restore the original affinity */
|
||||
|
||||
@ -491,10 +495,6 @@ FAR struct i2s_dev_s *lc823450_i2sdev_initialize(void)
|
||||
nxsig_usleep(10 * 1000);
|
||||
#endif
|
||||
|
||||
/* Enable IRQ for Audio Buffer */
|
||||
|
||||
up_enable_irq(LC823450_IRQ_AUDIOBUF0);
|
||||
|
||||
/* Success exit */
|
||||
|
||||
return &priv->dev;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/lc823450/lc823450_idle.c
|
||||
*
|
||||
* Copyright (C) 2014-2017 Sony Corporation. All rights reserved.
|
||||
* Copyright (C) 2014-2018 Sony Corporation. All rights reserved.
|
||||
* Author: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
|
||||
* Author: Masatoshi Tateishi <Masatoshi.Tateishi@jp.sony.com>
|
||||
*
|
||||
@ -57,35 +57,8 @@
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_LC823450_SLEEP_MODE
|
||||
static int32_t g_in_sleep;
|
||||
static uint64_t g_sleep_t0;
|
||||
#endif /* CONFIG_LC823450_SLEEP_MODE */
|
||||
|
||||
static uint32_t g_idle_counter[2];
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_get_current_time()
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_LC823450_SLEEP_MODE
|
||||
static uint64_t up_get_current_time(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
#ifdef CONFIG_CLOCK_MONOTONIC
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
#endif
|
||||
return (uint64_t)ts.tv_sec * NSEC_PER_SEC + (uint64_t)ts.tv_nsec;
|
||||
}
|
||||
#endif /* CONFIG_LC823450_SLEEP_MODE */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -113,21 +86,18 @@ void up_idle(void)
|
||||
sched_process_timer();
|
||||
#else
|
||||
|
||||
#ifdef CONFIG_LC823450_SLEEP_MODE
|
||||
/* DVFS and LED control must be done with local interrupts disabled */
|
||||
|
||||
irqstate_t flags;
|
||||
flags = enter_critical_section();
|
||||
|
||||
g_sleep_t0 = up_get_current_time();
|
||||
g_in_sleep = 1;
|
||||
flags = up_irq_save();
|
||||
|
||||
#ifdef CONFIG_LC823450_SLEEP_MODE
|
||||
/* Clear SLEEPDEEP flag */
|
||||
|
||||
uint32_t regval = getreg32(NVIC_SYSCON);
|
||||
regval &= ~NVIC_SYSCON_SLEEPDEEP;
|
||||
putreg32(regval, NVIC_SYSCON);
|
||||
|
||||
leave_critical_section(flags);
|
||||
#endif /* CONFIG_LC823450_SLEEP_MODE */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DVFS
|
||||
lc823450_dvfs_enter_idle();
|
||||
@ -135,6 +105,8 @@ void up_idle(void)
|
||||
|
||||
board_autoled_off(LED_CPU0 + up_cpu_index());
|
||||
|
||||
up_irq_restore(flags);
|
||||
|
||||
/* Sleep until an interrupt occurs to save power */
|
||||
|
||||
asm("WFI");
|
||||
@ -144,22 +116,3 @@ void up_idle(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_update_idle_time()
|
||||
*
|
||||
* Description:
|
||||
* up_update_idle_time() is the logic that will update idle time
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_LC823450_SLEEP_MODE
|
||||
void up_update_idle_time(void)
|
||||
{
|
||||
if (g_in_sleep)
|
||||
{
|
||||
g_in_sleep = 0;
|
||||
uint64_t t1 = up_get_current_time();
|
||||
sched_add_idl_tm(t1 - g_sleep_t0);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_LC823450_SLEEP_MODE */
|
||||
|
@ -717,10 +717,6 @@ void up_ack_irq(int irq)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LC823450_SLEEP_MODE
|
||||
extern void up_update_idle_time(void);
|
||||
up_update_idle_time();
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -68,12 +68,16 @@
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define DVFS_LINELEN 64
|
||||
#define DVFS_LINELEN 128
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a,b) (a < b ? a : b)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SMP_NCPUS
|
||||
# define CONFIG_SMP_NCPUS 1
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
@ -129,7 +133,9 @@ static const struct procfs_entry_s g_procfs_dvfs =
|
||||
****************************************************************************/
|
||||
|
||||
extern int8_t g_dvfs_enabled;
|
||||
extern int8_t g_dvfs_auto;
|
||||
extern uint16_t g_dvfs_cur_freq;
|
||||
extern uint32_t g_dvfs_freq_stat[3];
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
@ -203,6 +209,8 @@ static ssize_t dvfs_read(FAR struct file *filep, FAR char *buffer,
|
||||
size_t remaining;
|
||||
size_t totalsize;
|
||||
off_t offset = filep->f_pos;
|
||||
int i;
|
||||
uint64_t idletime[CONFIG_SMP_NCPUS];
|
||||
|
||||
finfo("buffer=%p buflen=%d\n", buffer, (int)buflen);
|
||||
|
||||
@ -230,6 +238,42 @@ static ssize_t dvfs_read(FAR struct file *filep, FAR char *buffer,
|
||||
"enable %d \n", g_dvfs_enabled);
|
||||
copysize = procfs_memcpy(priv->line, linesize, buffer, remaining, &offset);
|
||||
totalsize += copysize;
|
||||
buffer += copysize;
|
||||
remaining -= copysize;
|
||||
|
||||
linesize = snprintf(priv->line,
|
||||
DVFS_LINELEN,
|
||||
"auto %d \n", g_dvfs_auto);
|
||||
copysize = procfs_memcpy(priv->line, linesize, buffer, remaining, &offset);
|
||||
totalsize += copysize;
|
||||
buffer += copysize;
|
||||
remaining -= copysize;
|
||||
|
||||
linesize = snprintf(priv->line,
|
||||
DVFS_LINELEN,
|
||||
"fstat %d %d %d \n",
|
||||
g_dvfs_freq_stat[0],
|
||||
g_dvfs_freq_stat[1],
|
||||
g_dvfs_freq_stat[2]);
|
||||
copysize = procfs_memcpy(priv->line, linesize, buffer, remaining, &offset);
|
||||
totalsize += copysize;
|
||||
buffer += copysize;
|
||||
remaining -= copysize;
|
||||
|
||||
lc823450_dvfs_get_idletime(idletime);
|
||||
|
||||
for (i = 0; i < CONFIG_SMP_NCPUS; i++)
|
||||
{
|
||||
linesize = snprintf(priv->line,
|
||||
DVFS_LINELEN,
|
||||
"idle%d %lld \n",
|
||||
i, idletime[i]);
|
||||
|
||||
copysize = procfs_memcpy(priv->line, linesize, buffer, remaining, &offset);
|
||||
totalsize += copysize;
|
||||
buffer += copysize;
|
||||
remaining -= copysize;
|
||||
}
|
||||
|
||||
/* Update the file offset */
|
||||
|
||||
@ -251,8 +295,7 @@ static ssize_t dvfs_write(FAR struct file *filep, FAR const char *buffer,
|
||||
char line[DVFS_LINELEN];
|
||||
char cmd[16];
|
||||
int n;
|
||||
int freq;
|
||||
int enable;
|
||||
int tmp;
|
||||
|
||||
n = MIN(buflen, DVFS_LINELEN - 1);
|
||||
strncpy(line, buffer, n);
|
||||
@ -264,13 +307,18 @@ static ssize_t dvfs_write(FAR struct file *filep, FAR const char *buffer,
|
||||
|
||||
if (0 == strcmp(cmd, "cur_freq"))
|
||||
{
|
||||
freq = atoi(line + (n + 1));
|
||||
(void)lc823450_dvfs_set_freq(freq);
|
||||
tmp = atoi(line + (n + 1));
|
||||
(void)lc823450_dvfs_set_freq(tmp);
|
||||
}
|
||||
else if (0 == strcmp(cmd, "enable"))
|
||||
{
|
||||
enable = atoi(line + (n + 1));
|
||||
g_dvfs_enabled = enable;
|
||||
tmp = atoi(line + (n + 1));
|
||||
g_dvfs_enabled = tmp;
|
||||
}
|
||||
else if (0 == strcmp(cmd, "auto"))
|
||||
{
|
||||
tmp = atoi(line + (n + 1));
|
||||
g_dvfs_auto = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "lc823450_dma.h"
|
||||
#include "lc823450_gpio.h"
|
||||
#include "lc823450_syscontrol.h"
|
||||
#include "lc823450_timer.h"
|
||||
|
||||
#ifdef CONFIG_LC823450_SDC_DMA
|
||||
# include <semaphore.h>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/lc823450/lc823450_timerisr.c
|
||||
* arch/arm/src/lc823450/lc823450_timer.c
|
||||
*
|
||||
* Copyright (C) 2014-2017 Sony Corporation. All rights reserved.
|
||||
* Author: Masatoshi Tateishi <Masatoshi.Tateishi@jp.sony.com>
|
||||
@ -61,6 +61,7 @@
|
||||
#include "lc823450_syscontrol.h"
|
||||
#include "lc823450_clockconfig.h"
|
||||
#include "lc823450_serial.h"
|
||||
#include "lc823450_timer.h"
|
||||
|
||||
#ifdef CONFIG_DVFS
|
||||
# include "lc823450_dvfs2.h"
|
||||
@ -116,6 +117,17 @@
|
||||
# define rMT30CNT (LC823450_MTM3_REGBASE + LC823450_MTM_0CNT)
|
||||
#endif /* CONFIG_PROFILE */
|
||||
|
||||
#ifdef CONFIG_DVFS
|
||||
# define rMT01STS (LC823450_MTM0_REGBASE + LC823450_MTM_1STS)
|
||||
# define rMT01A (LC823450_MTM0_REGBASE + LC823450_MTM_1A)
|
||||
# define rMT01B (LC823450_MTM0_REGBASE + LC823450_MTM_1B)
|
||||
# define rMT01CTL (LC823450_MTM0_REGBASE + LC823450_MTM_1CTL)
|
||||
# define rMT01PSCL (LC823450_MTM0_REGBASE + LC823450_MTM_1PSCL)
|
||||
# define rMT01TIER (LC823450_MTM0_REGBASE + LC823450_MTM_1TIER)
|
||||
# define rMT01CNT (LC823450_MTM0_REGBASE + LC823450_MTM_1CNT)
|
||||
# define rMT0OPR (LC823450_MTM0_REGBASE + LC823450_MTM_OPR)
|
||||
#endif
|
||||
|
||||
#ifndef container_of
|
||||
# define container_of(ptr, type, member) \
|
||||
((type *)((void *)(ptr) - offsetof(type, member)))
|
||||
@ -618,17 +630,79 @@ void arm_timer_initialize(void)
|
||||
|
||||
up_enable_irq(LC823450_IRQ_SYSTICK);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DVFS
|
||||
/* attach timer interrupt handler */
|
||||
|
||||
(void)irq_attach(LC823450_IRQ_MTIMER01, (xcpt_t)lc823450_dvfs_oneshot, NULL);
|
||||
|
||||
/* enable MTM0-ch1 */
|
||||
|
||||
up_enable_irq(LC823450_IRQ_MTIMER01);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_hr_gettime
|
||||
* Name: lc823450_mtm_start_oneshot
|
||||
* NOTE: Assumption: MTM0-ch0 is running (i.e. tick timer)
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_DVFS
|
||||
void lc823450_mtm_start_oneshot(int msec)
|
||||
{
|
||||
uint32_t r = MTM_RELOAD; /* 10ms */
|
||||
|
||||
r /= 10; /* 1ms */
|
||||
r *= msec;
|
||||
|
||||
putreg32(0, rMT01A); /* AEVT counter */
|
||||
putreg32(r - 1, rMT01B); /* BEVT counter */
|
||||
|
||||
/* Clear the counter by BEVT */
|
||||
|
||||
putreg32(0x80, rMT01CTL);
|
||||
|
||||
/* Set prescaler to 9 : (1/10) */
|
||||
|
||||
putreg32(9, rMT01PSCL);
|
||||
|
||||
/* Enable BEVT Interrupt */
|
||||
|
||||
putreg32(1 << 1, rMT01TIER);
|
||||
|
||||
|
||||
/* Enable MTM0-ch1 */
|
||||
|
||||
modifyreg32(rMT0OPR, 0, 1 << 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lc823450_mtm_stop_oneshot
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_DVFS
|
||||
void lc823450_mtm_stop_oneshot(void)
|
||||
{
|
||||
/* Clear the interrupt (BEVT) */
|
||||
|
||||
putreg32(1 << 1, rMT01STS);
|
||||
|
||||
/* Disable MTM0-ch1 */
|
||||
|
||||
modifyreg32(rMT0OPR, 1 << 1, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_rtc_gettime
|
||||
*
|
||||
* Description:
|
||||
* This function is used in clock_gettime() to obtain high resolution time.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_hr_gettime(FAR struct timespec *tp)
|
||||
int up_rtc_gettime(FAR struct timespec *tp)
|
||||
{
|
||||
uint64_t secs;
|
||||
uint64_t nsecs;
|
79
arch/arm/src/lc823450/lc823450_timer.h
Normal file
79
arch/arm/src/lc823450/lc823450_timer.h
Normal file
@ -0,0 +1,79 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/lc823450/lc823450_timer.h
|
||||
*
|
||||
* Copyright (C) 2018 Sony Corporation. All rights reserved.
|
||||
* Author: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_ARM_SRC_LC823450_LC823450_TIMER_H
|
||||
#define __ARCH_ARM_SRC_LC823450_LC823450_TIMER_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_HRT_TIMER
|
||||
int up_hrttimer_usleep(unsigned int usec);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DVFS
|
||||
void lc823450_mtm_start_oneshot(int msec);
|
||||
void lc823450_mtm_stop_oneshot(void);
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARCH_ARM_SRC_LC823450_LC823450_TIMER_H */
|
@ -65,14 +65,6 @@ index 687f50ca..8418eff8 100644
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
If other deadlocks or ASSERT() still happen, please try the following.
|
||||
|
||||
$ cd nuttx; git revert e238c8b0904988b966c3b33e7df2ba3faba52e2b
|
||||
|
||||
This will revert the changes for clock_systimer() for 64bit so that it can
|
||||
use spinlock to protect the internal data. We think that there still exist
|
||||
race conditions somewhere in SMP logic but the revert might relax the conditions.
|
||||
|
||||
Other Status
|
||||
^^^^^^^^^^^^
|
||||
|
||||
@ -281,13 +273,20 @@ By default, DVFS is disabled. To enable,
|
||||
|
||||
nsh> echo "enable 1" > /proc/dvfs
|
||||
|
||||
In addition, you can change CPU frequency to 160/80/40. To change the
|
||||
frequency, enable the DVFS first then do the following.
|
||||
In addition, you can change CPU frequency to 160/80/40 manually.
|
||||
To change the frequency, enable the DVFS first then do the following.
|
||||
|
||||
nsh> echo "cur_freq 80" > /proc/dvfs.
|
||||
|
||||
Currently, DVFS works in manual mode and Vdd1 is fixed to 1.2V
|
||||
which will be changed in the future version.
|
||||
If you want to run in autonomous mode,
|
||||
|
||||
nsh> echo "auto 1" > /proc/dvfs.
|
||||
|
||||
In autonomous mode, you don't need to set cur_freq. Instead,
|
||||
cur_freq will show the current CPU frequency.
|
||||
|
||||
NOTE: Currently Vdd1 is fixed to 1.2V which will be changed
|
||||
in the future version.
|
||||
|
||||
TODO
|
||||
^^^^
|
||||
|
@ -106,7 +106,7 @@ CONFIG_RAM_SIZE=1044480
|
||||
CONFIG_RAM_START=0x02001000
|
||||
CONFIG_RAW_BINARY=y
|
||||
CONFIG_READLINE_CMD_HISTORY=y
|
||||
CONFIG_RTC_DATETIME=y
|
||||
CONFIG_RTC_HIRES=y
|
||||
CONFIG_RTC=y
|
||||
CONFIG_SCHED_ATEXIT=y
|
||||
CONFIG_SCHED_CHILD_STATUS=y
|
||||
|
@ -86,7 +86,6 @@ CONFIG_NET_ROUTE=y
|
||||
CONFIG_NET_SOCKOPTS=y
|
||||
CONFIG_NET_STATISTICS=y
|
||||
CONFIG_NET_TCP_RWND_CONTROL=y
|
||||
CONFIG_NET_TCP_WRITE_BUFFERS=y
|
||||
CONFIG_NET_TCP=y
|
||||
CONFIG_NET_UDP=y
|
||||
CONFIG_NETUTILS_CODECS=y
|
||||
@ -142,7 +141,7 @@ CONFIG_RAM_START=0x02001000
|
||||
CONFIG_RAW_BINARY=y
|
||||
CONFIG_READLINE_CMD_HISTORY=y
|
||||
CONFIG_RNDIS=y
|
||||
CONFIG_RTC_DATETIME=y
|
||||
CONFIG_RTC_HIRES=y
|
||||
CONFIG_RTC=y
|
||||
CONFIG_SCHED_ATEXIT=y
|
||||
CONFIG_SCHED_CHILD_STATUS=y
|
||||
@ -153,6 +152,7 @@ CONFIG_SCHED_HPWORK=y
|
||||
CONFIG_SCHED_INSTRUMENTATION_BUFFER=y
|
||||
CONFIG_SCHED_INSTRUMENTATION_PREEMPTION=y
|
||||
CONFIG_SCHED_INSTRUMENTATION=y
|
||||
CONFIG_SCHED_LPWORKPRIORITY=60
|
||||
CONFIG_SCHED_LPWORK=y
|
||||
CONFIG_SCHED_ONEXIT_MAX=32
|
||||
CONFIG_SCHED_ONEXIT=y
|
||||
|
Loading…
Reference in New Issue
Block a user