lib: utils/andes: arm the SMU sleep command last

Once the sleep command is written, the next WFI puts the core to sleep,
so everything that can fail has to run before it.

Also, use writel() so the command store cannot still be in flight at the
WFI.

Signed-off-by: Ben Zong-You Xie <ben717@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Link: https://lore.kernel.org/r/20260728081041.2724668-8-ben717@andestech.com
Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
Ben Zong-You Xie
2026-09-01 10:46:23 +05:30
committed by Anup Patel
parent 0fb4799307
commit 06af8bd61b
4 changed files with 35 additions and 9 deletions
+2 -2
View File
@@ -56,7 +56,7 @@ bool atcsmu_support_sleep_mode(u32 sleep_type, u32 hartid)
void atcsmu_set_command(u32 pcs_ctl, u32 hartid) void atcsmu_set_command(u32 pcs_ctl, u32 hartid)
{ {
writel_relaxed(pcs_ctl, (char *)atcsmu_base + PCSm_CTL_OFFSET(hartid)); writel(pcs_ctl, (char *)atcsmu_base + PCSm_CTL_OFFSET(hartid));
} }
int atcsmu_set_reset_vector(u64 wakeup_addr, u32 hartid) int atcsmu_set_reset_vector(u64 wakeup_addr, u32 hartid)
@@ -141,12 +141,12 @@ static int ae350_hart_stop(void)
atcsmu_set_command(LIGHT_SLEEP_CMD, hartid); atcsmu_set_command(LIGHT_SLEEP_CMD, hartid);
} else if (sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND) { } else if (sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND) {
/* Power-gated: SMU wakes it via cold reset, interrupts not needed */ /* Power-gated: SMU wakes it via cold reset, interrupts not needed */
atcsmu_set_command(DEEP_SLEEP_CMD, hartid);
rc = atcsmu_set_reset_vector((ulong)ae350_enable_coherency_warmboot, hartid); rc = atcsmu_set_reset_vector((ulong)ae350_enable_coherency_warmboot, hartid);
if (rc) if (rc)
return SBI_EFAIL; return SBI_EFAIL;
ae350_non_ret_save(sbi_scratch_thishart_ptr()); ae350_non_ret_save(sbi_scratch_thishart_ptr());
atcsmu_set_command(DEEP_SLEEP_CMD, hartid);
} }
ae350_disable_coherency(); ae350_disable_coherency();
+24 -7
View File
@@ -57,9 +57,11 @@ static int ae350_system_suspend_check(u32 sleep_type)
static int ae350_system_suspend(u32 sleep_type, unsigned long addr) static int ae350_system_suspend(u32 sleep_type, unsigned long addr)
{ {
u32 hartid = current_hartid(); u32 hartid = current_hartid();
unsigned long saved_mie;
int rc; int rc;
/* Prevent the core leaving the WFI mode unexpectedly */ /* Prevent the core leaving the WFI mode unexpectedly */
saved_mie = csr_read(CSR_MIE);
csr_write(CSR_MIE, 0); csr_write(CSR_MIE, 0);
/* SMU wakes the primary hart on RTC alarm / UART2 */ /* SMU wakes the primary hart on RTC alarm / UART2 */
@@ -68,7 +70,7 @@ static int ae350_system_suspend(u32 sleep_type, unsigned long addr)
if (sleep_type == SBI_SUSP_AE350_LIGHT_SLEEP) { if (sleep_type == SBI_SUSP_AE350_LIGHT_SLEEP) {
rc = wait_secondary_harts_sleep(hartid, false); rc = wait_secondary_harts_sleep(hartid, false);
if (rc) if (rc)
return rc; goto err_restore_mie;
/* Clock-gated only: enable SEI to resume past the WFI */ /* Clock-gated only: enable SEI to resume past the WFI */
csr_set(CSR_MIE, MIP_SEIP); csr_set(CSR_MIE, MIP_SEIP);
@@ -76,18 +78,24 @@ static int ae350_system_suspend(u32 sleep_type, unsigned long addr)
} else if (sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND) { } else if (sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND) {
rc = wait_secondary_harts_sleep(hartid, true); rc = wait_secondary_harts_sleep(hartid, true);
if (rc) if (rc)
return rc; goto err_restore_mie;
atcsmu_set_command(DEEP_SLEEP_CMD, hartid);
rc = atcsmu_set_reset_vector((ulong)ae350_enable_coherency_warmboot, hartid); rc = atcsmu_set_reset_vector((ulong)ae350_enable_coherency_warmboot, hartid);
if (rc) if (rc)
return rc; goto err_restore_mie;
ae350_non_ret_save(sbi_scratch_thishart_ptr()); ae350_non_ret_save(sbi_scratch_thishart_ptr());
fdt_cmo_llc_enable(false);
/* No LLC is fine; only fail on real errors */
rc = fdt_cmo_llc_enable(false);
if (rc && rc != SBI_ENODEV)
goto err_discard_save;
rc = fdt_cmo_llc_flush_all(); rc = fdt_cmo_llc_flush_all();
if (rc) if (rc && rc != SBI_ENODEV)
return rc; goto err_enable_llc;
atcsmu_set_command(DEEP_SLEEP_CMD, hartid);
} }
ae350_disable_coherency(); ae350_disable_coherency();
@@ -97,6 +105,15 @@ static int ae350_system_suspend(u32 sleep_type, unsigned long addr)
ae350_enable_coherency(); ae350_enable_coherency();
return SBI_OK; return SBI_OK;
err_enable_llc:
fdt_cmo_llc_enable(true);
err_discard_save:
ae350_non_ret_discard(sbi_scratch_thishart_ptr());
err_restore_mie:
csr_write(CSR_MIE, saved_mie);
return rc;
} }
static void ae350_system_resume(void) static void ae350_system_resume(void)
+8
View File
@@ -38,6 +38,14 @@ void ae350_non_ret_save(struct sbi_scratch *scratch)
andes_hdata->saved = true; andes_hdata->saved = true;
} }
void ae350_non_ret_discard(struct sbi_scratch *scratch)
{
struct andes_hart_data *andes_hdata = sbi_scratch_offset_ptr(scratch,
andes_hart_data_offset);
andes_hdata->saved = false;
}
void ae350_non_ret_restore(struct sbi_scratch *scratch) void ae350_non_ret_restore(struct sbi_scratch *scratch)
{ {
struct andes_hart_data *andes_hdata = sbi_scratch_offset_ptr(scratch, struct andes_hart_data *andes_hdata = sbi_scratch_offset_ptr(scratch,
+1
View File
@@ -102,6 +102,7 @@ struct andes_hart_data {
}; };
void ae350_non_ret_save(struct sbi_scratch *scratch); void ae350_non_ret_save(struct sbi_scratch *scratch);
void ae350_non_ret_discard(struct sbi_scratch *scratch);
void ae350_non_ret_restore(struct sbi_scratch *scratch); void ae350_non_ret_restore(struct sbi_scratch *scratch);
void ae350_enable_coherency_warmboot(void); void ae350_enable_coherency_warmboot(void);