forked from Mirrors/opensbi
		
	platform: andes/ae350: Implement hart hotplug using HSM extension
Add hart_start() and hart_stop() callbacks for the multi-core ae350
platform, it utilizes the ATCSMU to put the harts into power-gated
deep sleep mode. The programming sequence is stated as below:
1. Set the wakeup events to PCSm_WE
2. Set the sleep command to PCSm_CTL
3. Set the reset vector to HARTm_RESET_VECTOR_{LO|HI}
4. Write back and invalidate D-cache by executing the CCTL command L1D_WBINVAL_ALL
5. Disable I/D-cache by clearing mcache_ctl.{I|D}C_EN
6. Disable D-cache coherency by clearing mcache_ctl_.DC_COHEN
7. Wait for mcache_ctl.DC_COHSTA to be cleared to ensure the previous step is completed
8. Execute WFI
Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
			
			
This commit is contained in:
		
				
					committed by
					
						
						Anup Patel
					
				
			
			
				
	
			
			
			
						parent
						
							9c4eb3521e
						
					
				
				
					commit
					787296ae92
				
			@@ -10,6 +10,104 @@
 | 
			
		||||
#include <platform_override.h>
 | 
			
		||||
#include <sbi_utils/fdt/fdt_helper.h>
 | 
			
		||||
#include <sbi_utils/fdt/fdt_fixup.h>
 | 
			
		||||
#include <sbi_utils/sys/atcsmu.h>
 | 
			
		||||
#include <sbi/sbi_bitops.h>
 | 
			
		||||
#include <sbi/sbi_error.h>
 | 
			
		||||
#include <sbi/sbi_hsm.h>
 | 
			
		||||
#include <sbi/sbi_ipi.h>
 | 
			
		||||
#include <sbi/sbi_init.h>
 | 
			
		||||
#include <andes/andes45.h>
 | 
			
		||||
 | 
			
		||||
static struct smu_data smu = { 0 };
 | 
			
		||||
extern void __ae350_enable_coherency_warmboot(void);
 | 
			
		||||
extern void __ae350_disable_coherency(void);
 | 
			
		||||
 | 
			
		||||
static __always_inline bool is_andes25(void)
 | 
			
		||||
{
 | 
			
		||||
	ulong marchid = csr_read(CSR_MARCHID);
 | 
			
		||||
	return !!(EXTRACT_FIELD(marchid, CSR_MARCHID_MICROID) == 0xa25);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ae350_hart_start(u32 hartid, ulong saddr)
 | 
			
		||||
{
 | 
			
		||||
	/* Don't send wakeup command at boot-time */
 | 
			
		||||
	if (!sbi_init_count(hartid) || (is_andes25() && hartid == 0))
 | 
			
		||||
		return sbi_ipi_raw_send(hartid);
 | 
			
		||||
 | 
			
		||||
	/* Write wakeup command to the sleep hart */
 | 
			
		||||
	smu_set_command(&smu, WAKEUP_CMD, hartid);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ae350_hart_stop(void)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	u32 hartid = current_hartid();
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * For Andes AX25MP, the hart0 shares power domain with
 | 
			
		||||
	 * L2-cache, instead of turning it off, it should fall
 | 
			
		||||
	 * through and jump to warmboot_addr.
 | 
			
		||||
	 */
 | 
			
		||||
	if (is_andes25() && hartid == 0)
 | 
			
		||||
		return SBI_ENOTSUPP;
 | 
			
		||||
 | 
			
		||||
	if (!smu_support_sleep_mode(&smu, DEEPSLEEP_MODE, hartid))
 | 
			
		||||
		return SBI_ENOTSUPP;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * disable all events, the current hart will be
 | 
			
		||||
	 * woken up from reset vector when other hart
 | 
			
		||||
	 * writes its PCS (power control slot) control
 | 
			
		||||
	 * register
 | 
			
		||||
	 */
 | 
			
		||||
	smu_set_wakeup_events(&smu, 0x0, hartid);
 | 
			
		||||
	smu_set_command(&smu, DEEP_SLEEP_CMD, hartid);
 | 
			
		||||
 | 
			
		||||
	rc = smu_set_reset_vector(&smu, (ulong)__ae350_enable_coherency_warmboot,
 | 
			
		||||
			       hartid);
 | 
			
		||||
	if (rc)
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
	__ae350_disable_coherency();
 | 
			
		||||
 | 
			
		||||
	wfi();
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
	/* It should never reach here */
 | 
			
		||||
	sbi_hart_hang();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct sbi_hsm_device andes_smu = {
 | 
			
		||||
	.name	      = "andes_smu",
 | 
			
		||||
	.hart_start   = ae350_hart_start,
 | 
			
		||||
	.hart_stop    = ae350_hart_stop,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void ae350_hsm_device_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	void *fdt;
 | 
			
		||||
 | 
			
		||||
	fdt = fdt_get_address();
 | 
			
		||||
 | 
			
		||||
	rc = fdt_parse_compat_addr(fdt, (uint64_t *)&smu.addr,
 | 
			
		||||
				   "andestech,atcsmu");
 | 
			
		||||
 | 
			
		||||
	if (!rc) {
 | 
			
		||||
		sbi_hsm_set_device(&andes_smu);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ae350_final_init(bool cold_boot, const struct fdt_match *match)
 | 
			
		||||
{
 | 
			
		||||
	if (cold_boot)
 | 
			
		||||
		ae350_hsm_device_init();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct fdt_match andes_ae350_match[] = {
 | 
			
		||||
	{ .compatible = "andestech,ae350" },
 | 
			
		||||
@@ -18,4 +116,5 @@ static const struct fdt_match andes_ae350_match[] = {
 | 
			
		||||
 | 
			
		||||
const struct platform_override andes_ae350 = {
 | 
			
		||||
	.match_table = andes_ae350_match,
 | 
			
		||||
	.final_init  = ae350_final_init,
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -3,4 +3,4 @@
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
carray-platform_override_modules-$(CONFIG_PLATFORM_ANDES_AE350) += andes_ae350
 | 
			
		||||
platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o
 | 
			
		||||
platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o andes/sleep.o
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										70
									
								
								platform/generic/andes/sleep.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								platform/generic/andes/sleep.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
/*
 | 
			
		||||
 * SPDX-License-Identifier: BSD-2-Clause
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2023 Andes Technology Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * Authors:
 | 
			
		||||
 *   Yu Chien Peter Lin <peterlin@andestech.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sbi/riscv_encoding.h>
 | 
			
		||||
#include <sbi/riscv_asm.h>
 | 
			
		||||
#include <andes/andes45.h>
 | 
			
		||||
 | 
			
		||||
	.section .text, "ax", %progbits
 | 
			
		||||
	.align 3
 | 
			
		||||
	.global __ae350_disable_coherency
 | 
			
		||||
__ae350_disable_coherency:
 | 
			
		||||
	/* flush d-cache */
 | 
			
		||||
	csrw	CSR_MCCTLCOMMAND, 0x6
 | 
			
		||||
	/* disable i/d-cache */
 | 
			
		||||
	csrc	CSR_MCACHE_CTL, 0x3
 | 
			
		||||
	/* disable d-cache coherency */
 | 
			
		||||
	lui	t1, 0x80
 | 
			
		||||
	csrc	CSR_MCACHE_CTL, t1
 | 
			
		||||
	/*
 | 
			
		||||
	 * wait for mcache_ctl.DC_COHSTA to be cleared,
 | 
			
		||||
	 * the bit is hard-wired 0 on platforms w/o CM
 | 
			
		||||
	 * (Coherence Manager)
 | 
			
		||||
	 */
 | 
			
		||||
check_cm_disabled:
 | 
			
		||||
	csrr	t1, CSR_MCACHE_CTL
 | 
			
		||||
	srli	t1, t1, 20
 | 
			
		||||
	andi	t1, t1, 0x1
 | 
			
		||||
	bnez	t1, check_cm_disabled
 | 
			
		||||
 | 
			
		||||
	ret
 | 
			
		||||
 | 
			
		||||
	.section .text, "ax", %progbits
 | 
			
		||||
	.align 3
 | 
			
		||||
	.global __ae350_enable_coherency
 | 
			
		||||
__ae350_enable_coherency:
 | 
			
		||||
	/* enable d-cache coherency */
 | 
			
		||||
	lui		t1, 0x80
 | 
			
		||||
	csrs	CSR_MCACHE_CTL, t1
 | 
			
		||||
	/*
 | 
			
		||||
	 * mcache_ctl.DC_COHEN is hard-wired 0 on platforms
 | 
			
		||||
	 * w/o CM support
 | 
			
		||||
	 */
 | 
			
		||||
	csrr	t1, CSR_MCACHE_CTL
 | 
			
		||||
	srli	t1, t1, 19
 | 
			
		||||
	andi	t1, t1, 0x1
 | 
			
		||||
	beqz	t1, enable_L1_cache
 | 
			
		||||
	/* wait for mcache_ctl.DC_COHSTA to be set */
 | 
			
		||||
check_cm_enabled:
 | 
			
		||||
	csrr	t1, CSR_MCACHE_CTL
 | 
			
		||||
	srli	t1, t1, 20
 | 
			
		||||
	andi	t1, t1, 0x1
 | 
			
		||||
	beqz	t1, check_cm_enabled
 | 
			
		||||
enable_L1_cache:
 | 
			
		||||
	/* enable i/d-cache */
 | 
			
		||||
	csrs	CSR_MCACHE_CTL, 0x3
 | 
			
		||||
 | 
			
		||||
	ret
 | 
			
		||||
 | 
			
		||||
	.section .text, "ax", %progbits
 | 
			
		||||
	.align 3
 | 
			
		||||
	.global __ae350_enable_coherency_warmboot
 | 
			
		||||
__ae350_enable_coherency_warmboot:
 | 
			
		||||
	call ra, __ae350_enable_coherency
 | 
			
		||||
	j _start_warm
 | 
			
		||||
							
								
								
									
										10
									
								
								platform/generic/include/andes/andes45.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								platform/generic/include/andes/andes45.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
#ifndef _RISCV_ANDES45_H
 | 
			
		||||
#define _RISCV_ANDES45_H
 | 
			
		||||
 | 
			
		||||
#define CSR_MARCHID_MICROID 0xfff
 | 
			
		||||
 | 
			
		||||
/* Memory and Miscellaneous Registers */
 | 
			
		||||
#define CSR_MCACHE_CTL 0x7ca
 | 
			
		||||
#define CSR_MCCTLCOMMAND 0x7cc
 | 
			
		||||
 | 
			
		||||
#endif /* _RISCV_ANDES45_H */
 | 
			
		||||
		Reference in New Issue
	
	Block a user