mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-11-22 19:01:33 +00:00
lib: utils/suspend: Add SiFive SMC0 driver
The SiFive SMC0 controls the clock and power domain of the core complex on the SiFive platform. The core complex enters the low power state after the secondary cores enter the tile power gating and last core execute the `CEASE` instruction with the corresponding SMC0 configurations. The devices that inside both tile power domain and core complex power domain will be off, including caches and timer. Therefore we need to flush the last level cache before entering the core complex power gating and update the timer after waking up. Reviewed-by: Cyan Yang <cyan.yang@sifive.com> Reviewed-by: Anup Patel <anup@brainfault.org> Signed-off-by: Nick Hu <nick.hu@sifive.com> Link: https://lore.kernel.org/r/20251020-cache-upstream-v7-12-69a132447d8a@sifive.com Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
#include <sbi_utils/fdt/fdt_driver.h>
|
||||
#include <sbi_utils/fdt/fdt_helper.h>
|
||||
#include <sbi_utils/hsm/fdt_hsm_sifive_inst.h>
|
||||
#include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
|
||||
|
||||
struct sifive_tmc0 {
|
||||
unsigned long reg;
|
||||
@@ -77,6 +78,62 @@ static unsigned long tmc0_offset;
|
||||
#define SIFIVE_TMC_WAKE_MASK_WREQ BIT(31)
|
||||
#define SIFIVE_TMC_WAKE_MASK_ACK BIT(30)
|
||||
|
||||
int sifive_tmc0_set_wakemask_enareq(u32 hartid)
|
||||
{
|
||||
struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
|
||||
struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
|
||||
unsigned long addr;
|
||||
u32 v;
|
||||
|
||||
if (!tmc0)
|
||||
return SBI_ENODEV;
|
||||
|
||||
addr = tmc0->reg + SIFIVE_TMC_WAKE_MASK_OFF;
|
||||
v = readl((void *)addr);
|
||||
writel(v | SIFIVE_TMC_WAKE_MASK_WREQ, (void *)addr);
|
||||
|
||||
while (!(readl((void *)addr) & SIFIVE_TMC_WAKE_MASK_ACK));
|
||||
|
||||
return SBI_OK;
|
||||
}
|
||||
|
||||
void sifive_tmc0_set_wakemask_disreq(u32 hartid)
|
||||
{
|
||||
struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
|
||||
struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
|
||||
unsigned long addr;
|
||||
u32 v;
|
||||
|
||||
if (!tmc0)
|
||||
return;
|
||||
|
||||
addr = tmc0->reg + SIFIVE_TMC_WAKE_MASK_OFF;
|
||||
v = readl((void *)addr);
|
||||
writel(v & ~SIFIVE_TMC_WAKE_MASK_WREQ, (void *)addr);
|
||||
|
||||
while (readl((void *)addr) & SIFIVE_TMC_WAKE_MASK_ACK);
|
||||
}
|
||||
|
||||
bool sifive_tmc0_is_pg(u32 hartid)
|
||||
{
|
||||
struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
|
||||
struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
|
||||
unsigned long addr;
|
||||
u32 v;
|
||||
|
||||
if (!tmc0)
|
||||
return false;
|
||||
|
||||
addr = tmc0->reg + SIFIVE_TMC_PG_OFF;
|
||||
v = readl((void *)addr);
|
||||
if (!(v & SIFIVE_TMC_PG_ENA_ACK) ||
|
||||
(v & SIFIVE_TMC_PG_ENARSP) ||
|
||||
(v & SIFIVE_TMC_PG_DIS_REQ))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sifive_tmc0_set_resumepc(physical_addr_t addr)
|
||||
{
|
||||
struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
|
||||
|
||||
Reference in New Issue
Block a user