[PATCH 2/2] platform: thead: restore platform CSR when suspend

Samuel Holland samuel.holland at sifive.com
Sun Dec 7 02:59:23 PST 2025


Hi Xiang,

On 2025-12-04 8:58 AM, Xiang W wrote:
> Some CSRs in Thead need to be backed up and restored during HART
> suspend.
> 
> Signed-off-by: David Li <davidli.li at linux.alibaba.com>
> Signed-off-by: Xiang W <wangxiang at iscas.ac.cn>
> ---
>  .../generic/include/thead/c9xx_encoding.h     |  1 +
>  platform/generic/thead/thead-generic.c        | 53 +++++++++++++++++++
>  2 files changed, 54 insertions(+)
> 
> diff --git a/platform/generic/include/thead/c9xx_encoding.h b/platform/generic/include/thead/c9xx_encoding.h
> index a45b171e..bcbd9e24 100644
> --- a/platform/generic/include/thead/c9xx_encoding.h
> +++ b/platform/generic/include/thead/c9xx_encoding.h
> @@ -16,6 +16,7 @@
>  #define THEAD_C9XX_CSR_MCOUNTEROF	0x7cb
>  #define THEAD_C9XX_CSR_MHINT2		0x7cc
>  #define THEAD_C9XX_CSR_MHINT3		0x7cd
> +#define THEAD_C9XX_CSR_MHINT4		0x7ce
>  #define THEAD_C9XX_CSR_MRADDR		0x7e0
>  #define THEAD_C9XX_CSR_MEXSTATUS	0x7e1
>  #define THEAD_C9XX_CSR_MNMICAUSE	0x7e2
> diff --git a/platform/generic/thead/thead-generic.c b/platform/generic/thead/thead-generic.c
> index ddb4f0bf..63e33849 100644
> --- a/platform/generic/thead/thead-generic.c
> +++ b/platform/generic/thead/thead-generic.c
> @@ -7,6 +7,7 @@
>   */
>  
>  #include <platform_override.h>
> +#include <thead/c9xx_encoding.h>
>  #include <thead/c9xx_errata.h>
>  #include <thead/c9xx_pmu.h>
>  #include <sbi/sbi_const.h>
> @@ -15,10 +16,61 @@
>  #include <sbi/sbi_string.h>
>  #include <sbi_utils/fdt/fdt_helper.h>
>  
> +/* redefine CSR register */
> +#define CSR_MXSTATUS	THEAD_C9XX_CSR_MXSTATUS
> +#define CSR_MHCR	THEAD_C9XX_CSR_MHCR
> +#define CSR_MCCR2	THEAD_C9XX_CSR_MCCR2
> +#define CSR_MHINT	THEAD_C9XX_CSR_MHINT
> +#define CSR_MHINT2_E	THEAD_C9XX_CSR_MHINT2
> +#define CSR_MHINT4	THEAD_C9XX_CSR_MHINT4
> +#define CSR_MSMPR	THEAD_C9XX_CSR_MSMPR
> +#define CSR_SMPEN	CSR_MSMPR
> +
>  struct thead_generic_quirks {
>  	u64	errata;
>  };
>  
> +extern struct sbi_platform platform;
> +
> +static inline bool thead_has_hotplug(void)
> +{
> +	return platform.hart_count > 1;
> +}

Why is non-retentive suspend not applicable when there is only one hart?

> +
> +static void thead_suspend_non_ret_save(unsigned long *data)
> +{
> +	data[0] = csr_read(CSR_SMPEN);
> +	data[1] = csr_read(CSR_MCCR2);
> +	data[2] = csr_read(CSR_MXSTATUS);
> +	data[3] = csr_read(CSR_MHINT);
> +	data[4] = csr_read(CSR_MHCR);
> +	data[5] = csr_read(CSR_MHINT2_E);
> +	data[6] = csr_read(CSR_MHINT4);
> +}

This logic is used by both C908 and C910. Do they both have all of these CSRs?

Also, it looks like similar logic is needed for C906 in
platform/generic/allwinner/sun20i-d1.c.

> +
> +static void thead_suspend_non_ret_restore(unsigned long *data)
> +{
> +	csr_write(CSR_SMPEN, data[0]);
> +	csr_write(CSR_MCCR2, data[1]);
> +	csr_write(CSR_MXSTATUS, data[2]);
> +	csr_write(CSR_MHINT, data[3]);
> +	csr_write(CSR_MHCR, data[4]);
> +	csr_write(CSR_MHINT2_E, data[5]);
> +	csr_write(CSR_MHINT4, data[6]);
> +}
> +
> +static int thead_nascent_init(void)
> +{
> +
> +	if (thead_has_hotplug()) {
> +		platform.suspend_backup_csr_count = 7;
> +		generic_platform_ops.suspend_non_ret_save = thead_suspend_non_ret_save;
> +		generic_platform_ops.suspend_non_ret_restore = thead_suspend_non_ret_restore;

Please modify generic_platform_ops only from inside thead_generic_platform_init.
The nascent_init hook is called on every hart on every entry (including warm
resume), so this is inefficient, and it would crash if we implement a
ro_after_init feature.

Since you need to access platform.hart_count, you can move the
fdt_driver_init_by_offset() call later in fw_platform_init(). This should be
safe for all existing platform overrides.

Regards,
Samuel

> +	}
> +
> +	return generic_nascent_init();
> +}
> +
>  static int thead_tlb_flush_early_init(bool cold_boot)
>  {
>  	thead_register_tlb_flush_trap_handler();
> @@ -44,6 +96,7 @@ static int thead_generic_platform_init(const void *fdt, int nodeoff,
>  {
>  	const struct thead_generic_quirks *quirks = match->data;
>  
> +	generic_platform_ops.nascent_init = thead_nascent_init;
>  	if (quirks->errata & THEAD_QUIRK_ERRATA_TLB_FLUSH)
>  		generic_platform_ops.early_init = thead_tlb_flush_early_init;
>  	if (quirks->errata & THEAD_QUIRK_ERRATA_THEAD_PMU)




More information about the opensbi mailing list