diff --git a/arch/arm/src/lc823450/Make.defs b/arch/arm/src/lc823450/Make.defs index 58905083ca..c013558f87 100644 --- a/arch/arm/src/lc823450/Make.defs +++ b/arch/arm/src/lc823450/Make.defs @@ -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 diff --git a/arch/arm/src/lc823450/lc823450_dvfs2.c b/arch/arm/src/lc823450/lc823450_dvfs2.c index 2bc8855f51..5aff75e36a 100644 --- a/arch/arm/src/lc823450/lc823450_dvfs2.c +++ b/arch/arm/src/lc823450/lc823450_dvfs2.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) + { + lc823450_dvfs_get_idletime(tmp_idle_total); + + /* Calculate idle ratio for each CPU */ + + for (i = 0; i < CONFIG_SMP_NCPUS; i++) { - g_dvfs_enabled = 1; + 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; diff --git a/arch/arm/src/lc823450/lc823450_dvfs2.h b/arch/arm/src/lc823450/lc823450_dvfs2.h index a4423d65e0..a04da7e3c7 100644 --- a/arch/arm/src/lc823450/lc823450_dvfs2.h +++ b/arch/arm/src/lc823450/lc823450_dvfs2.h @@ -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); diff --git a/arch/arm/src/lc823450/lc823450_i2s.c b/arch/arm/src/lc823450/lc823450_i2s.c index 2b993d6a1c..d14d09df15 100644 --- a/arch/arm/src/lc823450/lc823450_i2s.c +++ b/arch/arm/src/lc823450/lc823450_i2s.c @@ -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; diff --git a/arch/arm/src/lc823450/lc823450_idle.c b/arch/arm/src/lc823450/lc823450_idle.c index f4ced8826d..5baf8299d4 100644 --- a/arch/arm/src/lc823450/lc823450_idle.c +++ b/arch/arm/src/lc823450/lc823450_idle.c @@ -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 * Author: Masatoshi Tateishi * @@ -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 */ diff --git a/arch/arm/src/lc823450/lc823450_irq.c b/arch/arm/src/lc823450/lc823450_irq.c index bd159ef545..7b58b75060 100644 --- a/arch/arm/src/lc823450/lc823450_irq.c +++ b/arch/arm/src/lc823450/lc823450_irq.c @@ -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 } /**************************************************************************** diff --git a/arch/arm/src/lc823450/lc823450_procfs_dvfs.c b/arch/arm/src/lc823450/lc823450_procfs_dvfs.c index fa69b0a3ca..3e085dcaea 100644 --- a/arch/arm/src/lc823450/lc823450_procfs_dvfs.c +++ b/arch/arm/src/lc823450/lc823450_procfs_dvfs.c @@ -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]; /**************************************************************************** @@ -202,7 +208,9 @@ static ssize_t dvfs_read(FAR struct file *filep, FAR char *buffer, size_t copysize; size_t remaining; size_t totalsize; - off_t offset = filep->f_pos; + 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 { diff --git a/arch/arm/src/lc823450/lc823450_sddrv_dep.c b/arch/arm/src/lc823450/lc823450_sddrv_dep.c index 9e3806d707..3880cfbb94 100644 --- a/arch/arm/src/lc823450/lc823450_sddrv_dep.c +++ b/arch/arm/src/lc823450/lc823450_sddrv_dep.c @@ -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 diff --git a/arch/arm/src/lc823450/lc823450_timerisr.c b/arch/arm/src/lc823450/lc823450_timer.c similarity index 89% rename from arch/arm/src/lc823450/lc823450_timerisr.c rename to arch/arm/src/lc823450/lc823450_timer.c index 1e89f79527..4424d8826f 100644 --- a/arch/arm/src/lc823450/lc823450_timerisr.c +++ b/arch/arm/src/lc823450/lc823450_timer.c @@ -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 @@ -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))) @@ -612,23 +624,85 @@ void arm_timer_initialize(void) putreg32((NVIC_SYSTICK_CTRL_CLKSOURCE | NVIC_SYSTICK_CTRL_TICKINT | NVIC_SYSTICK_CTRL_ENABLE), - NVIC_SYSTICK_CTRL); + NVIC_SYSTICK_CTRL); /* And enable the timer interrupt */ 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; diff --git a/arch/arm/src/lc823450/lc823450_timer.h b/arch/arm/src/lc823450/lc823450_timer.h new file mode 100644 index 0000000000..b1af643ebf --- /dev/null +++ b/arch/arm/src/lc823450/lc823450_timer.h @@ -0,0 +1,79 @@ +/**************************************************************************** + * arch/arm/src/lc823450/lc823450_timer.h + * + * Copyright (C) 2018 Sony Corporation. All rights reserved. + * Author: Masayuki Ishikawa + * + * 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 + +#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 */ diff --git a/configs/lc823450-xgevk/README.txt b/configs/lc823450-xgevk/README.txt index a152c893e1..4697e0db32 100644 --- a/configs/lc823450-xgevk/README.txt +++ b/configs/lc823450-xgevk/README.txt @@ -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 ^^^^ diff --git a/configs/lc823450-xgevk/audio/defconfig b/configs/lc823450-xgevk/audio/defconfig index e06f30abc5..90a3a67b44 100644 --- a/configs/lc823450-xgevk/audio/defconfig +++ b/configs/lc823450-xgevk/audio/defconfig @@ -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 diff --git a/configs/lc823450-xgevk/rndis/defconfig b/configs/lc823450-xgevk/rndis/defconfig index 32a899edd9..c27c869db5 100644 --- a/configs/lc823450-xgevk/rndis/defconfig +++ b/configs/lc823450-xgevk/rndis/defconfig @@ -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