Skip to content

Commit

Permalink
platform: intel: add clock switch for waiti
Browse files Browse the repository at this point in the history
Platforms with cAVS version 1.8 & 2.0 have hardware requirement that
DSP should use LPRO as clock source in waiti.
This patch adds config for that and enables it for platforms that
need it.

Signed-off-by: Janusz Jankowski <[email protected]>
  • Loading branch information
jajanusz committed Apr 24, 2020
1 parent 1b71a50 commit 7605252
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 7 deletions.
13 changes: 13 additions & 0 deletions src/platform/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ config CANNONLAKE
select CAVS
select CAVS_VERSION_1_8
select WAITI_DELAY
select CAVS_USE_LPRO_IN_WAITI
help
Select if your target platform is Cannonlake-compatible

Expand All @@ -113,6 +114,7 @@ config SUECREEK
select CAVS
select CAVS_VERSION_2_0
select WAITI_DELAY
select CAVS_USE_LPRO_IN_WAITI
help
Select if your target platform is Suecreek-compatible

Expand All @@ -130,6 +132,7 @@ config ICELAKE
select CAVS
select CAVS_VERSION_2_0
select WAITI_DELAY
select CAVS_USE_LPRO_IN_WAITI
help
Select if your target platform is Icelake-compatible

Expand Down Expand Up @@ -219,6 +222,16 @@ config CONFIG_CHERRYTRAIL_EXTRA_DW_DMA
Select if you need support for all 3 DMACs versus the default 2 used
in baytrail.

config CAVS_USE_LPRO_IN_WAITI
bool
default n
depends on CAVS
select WAKEUP_HOOK
help
Select if platform requires DSP clock source to be switched to LPRO
while in waiti.
After waiti clock source is restored.

# TODO: it should just take manifest version and offsets
config FIRMWARE_SHORT_NAME
string "Rimage firmware name"
Expand Down
9 changes: 9 additions & 0 deletions src/platform/intel/cavs/include/cavs/drivers/interrupt.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,20 @@
#ifndef __CAVS_DRIVERS_INTERRUPT_H__
#define __CAVS_DRIVERS_INTERRUPT_H__

#include <sof/lib/clk.h>

extern char irq_name_level2[];
extern char irq_name_level3[];
extern char irq_name_level4[];
extern char irq_name_level5[];

#if CONFIG_CAVS_USE_LPRO_IN_WAITI
static inline void platform_interrupt_on_wakeup(void)
{
platform_clock_on_wakeup();
}
#endif

#endif /* __CAVS_DRIVERS_INTERRUPT_H__ */

#else
Expand Down
5 changes: 5 additions & 0 deletions src/platform/intel/cavs/include/cavs/lib/clk.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ extern uint32_t cpu_freq_status_mask[];

void platform_clock_init(void);

#if CONFIG_CAVS_USE_LPRO_IN_WAITI
void platform_clock_on_waiti(void);
void platform_clock_on_wakeup(void);
#endif

#endif /* __CAVS_LIB_CLK_H__ */

#else
Expand Down
79 changes: 72 additions & 7 deletions src/platform/intel/cavs/lib/clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,41 @@ static struct clock_info platform_clocks_info[NUM_CLOCKS];

struct clock_info *clocks = platform_clocks_info;

static int clock_platform_set_cpu_freq(int clock, int freq_idx)
#if CONFIG_CAVS_USE_LPRO_IN_WAITI
/* Track freq_idx value, so it can be stored before switching to LPRO. */
static int cpu_current_freq_idx;

static inline int get_cpu_current_freq_idx(void)
{
uint32_t enc = cpu_freq_enc[freq_idx];
return *cache_to_uncache(&cpu_current_freq_idx);
}

static inline void set_cpu_current_freq_idx(int freq_idx)
{
*cache_to_uncache(&cpu_current_freq_idx) = freq_idx;
}
#else
static inline void set_cpu_current_freq_idx(int freq_idx)
{
}
#endif

/* set CPU frequency request for CCU */
#if CAVS_VERSION == CAVS_VERSION_1_5
static inline void select_cpu_clock(int freq_idx, bool release_unused)
{
uint32_t enc = cpu_freq_enc[freq_idx];

io_reg_update_bits(SHIM_BASE + SHIM_CLKCTL, SHIM_CLKCTL_HDCS, 0);
io_reg_update_bits(SHIM_BASE + SHIM_CLKCTL,
SHIM_CLKCTL_DPCS_MASK(cpu_get_id()),
enc);

set_cpu_current_freq_idx(freq_idx);
}
#else
static inline void select_cpu_clock(int freq_idx, bool release_unused)
{
uint32_t enc = cpu_freq_enc[freq_idx];
uint32_t status_mask = cpu_freq_status_mask[freq_idx];

/* request clock */
Expand All @@ -39,14 +63,53 @@ static int clock_platform_set_cpu_freq(int clock, int freq_idx)
io_reg_update_bits(SHIM_BASE + SHIM_CLKCTL,
SHIM_CLKCTL_OSC_SOURCE_MASK, enc);

/* release other clocks */
io_reg_write(SHIM_BASE + SHIM_CLKCTL,
(io_reg_read(SHIM_BASE + SHIM_CLKCTL) &
~SHIM_CLKCTL_OSC_REQUEST_MASK) | enc);
if (release_unused) {
/* release other clocks */
io_reg_write(SHIM_BASE + SHIM_CLKCTL,
(io_reg_read(SHIM_BASE + SHIM_CLKCTL) &
~SHIM_CLKCTL_OSC_REQUEST_MASK) | enc);
}

set_cpu_current_freq_idx(freq_idx);
}
#endif

static int clock_platform_set_cpu_freq(int clock, int freq_idx)
{
select_cpu_clock(freq_idx, true);
return 0;
}

#if CONFIG_CAVS_USE_LPRO_IN_WAITI
/* Store clock source that was active before going to waiti,
* so it can be restored on wake up.
*/
static int active_freq_idx = CPU_DEFAULT_IDX;

void platform_clock_on_wakeup(void)
{
int freq_idx = *cache_to_uncache(&active_freq_idx);

if (freq_idx != get_cpu_current_freq_idx())
select_cpu_clock(freq_idx, true);
}

void platform_clock_on_waiti(void)
{
int freq_idx = get_cpu_current_freq_idx();

*cache_to_uncache(&active_freq_idx) = freq_idx;

if (freq_idx != CPU_LPRO_FREQ_IDX)
/* LPRO requests are fast, but requests for other ROs
* can take a lot of time. That's why it's better to
* not release active clock just for waiti,
* so they can be switched without delay on wake up.
*/
select_cpu_clock(CPU_LPRO_FREQ_IDX, false);
}
#endif

void platform_clock_init(void)
{
int i;
Expand All @@ -70,4 +133,6 @@ void platform_clock_init(void)
.notification_mask = NOTIFIER_TARGET_CORE_ALL_MASK,
.set_freq = NULL,
};

set_cpu_current_freq_idx(CPU_DEFAULT_IDX);
}
3 changes: 3 additions & 0 deletions src/platform/intel/cavs/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,9 @@ int platform_init(struct sof *sof)

void platform_wait_for_interrupt(int level)
{
#if CONFIG_CAVS_USE_LPRO_IN_WAITI
platform_clock_on_waiti();
#endif
#if (CONFIG_CAVS_LPS)
if (pm_runtime_is_active(PM_RUNTIME_DSP, PLATFORM_MASTER_CORE_ID))
arch_wait_for_interrupt(level);
Expand Down

0 comments on commit 7605252

Please sign in to comment.