diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 70a7af90812..3cea8205891 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -156,6 +156,19 @@ config ARCH_HAVE_EL3 runing at EL3 is not necessary and system register for EL3 is not accessible +config ARCH_HAVE_CLUSTER_PMU + bool + default n + ---help--- + Some processors implement cluster PMUs, such as Cortex-R82 + +config ARCH_CLUSTER_PMU + bool "Enable the cluster PMUs" + default n + depends on ARCH_HAVE_CLUSTER_PMU + ---help--- + If the processor supports cluster PMU, can configure cluster PMU + config ARCH_ARM64_EXCEPTION_LEVEL int "Exception level to operate" default 1 @@ -253,6 +266,7 @@ config ARCH_CORTEX_R82 select ARCH_ICACHE select ARCH_HAVE_MPU select ARCH_HAVE_FPU + select ARCH_HAVE_CLUSTER_PMU select ARCH_HAVE_TESTSET select ARM64_HAVE_NEON diff --git a/arch/arm64/src/common/arm64_arch.h b/arch/arm64/src/common/arm64_arch.h index 7a897c1b66a..fbd47f54375 100644 --- a/arch/arm64/src/common/arm64_arch.h +++ b/arch/arm64/src/common/arm64_arch.h @@ -96,6 +96,17 @@ #define SCTLR_SA_BIT BIT(3) #define SCTLR_I_BIT BIT(12) +#define ACTLR_AUX_BIT BIT(9) +#define ACTLR_CLPORTS_BIT BIT(8) +#define ACTLR_CLPMU_BIT BIT(7) +#define ACTLR_TESTR1_BIT BIT(6) +#define ACTLR_CDBG_BIT BIT(5) +#define ACTLR_PATCH_BIT BIT(4) +#define ACTLR_BPRED_BIT BIT(3) +#define ACTLR_POWER_BIT BIT(2) +#define ACTLR_DIAGNOSTIC_BIT BIT(1) +#define ACTLR_REGIONS_BIT BIT(0) + /* SPSR M[3:0] define * * ArmĀ® Architecture Registers Armv8, for Armv8-A architecture profile diff --git a/arch/arm64/src/common/arm64_boot.c b/arch/arm64/src/common/arm64_boot.c index bbeda1c0222..be482650250 100644 --- a/arch/arm64/src/common/arm64_boot.c +++ b/arch/arm64/src/common/arm64_boot.c @@ -129,6 +129,12 @@ void arm64_boot_el2_init(void) SCTLR_SA_BIT); /* Enable SP alignment check */ write_sysreg(reg, sctlr_el2); +#ifdef CONFIG_ARCH_CLUSTER_PMU + reg = read_sysreg(actlr_el2); + reg |= ACTLR_CLPMU_BIT; + write_sysreg(reg, actlr_el2); +#endif + reg = read_sysreg(hcr_el2); reg |= HCR_RW_BIT; /* EL1 Execution state is AArch64 */ write_sysreg(reg, hcr_el2); diff --git a/arch/arm64/src/common/arm64_perf.c b/arch/arm64/src/common/arm64_perf.c index d2bc84a64d1..8195ce127fc 100644 --- a/arch/arm64/src/common/arm64_perf.c +++ b/arch/arm64/src/common/arm64_perf.c @@ -42,11 +42,19 @@ void up_perf_init(void *arg) { g_cpu_freq = (unsigned long)(uintptr_t)arg; +#ifdef CONFIG_ARCH_CLUSTER_PMU + pmu_clucntr_control_config(CLUSTERPMCR_EL1_C | CLUSTERPMCR_EL1_P | + CLUSTERPMCR_EL1_E); + pmu_clucntr_ovsclr_config(CLUSTERPMOVSCLR_EL1_C); + pmu_clucntr_irq_disable(CLUSTERPMINTENCLR_EL1_C); + pmu_clucntr_enable(CLUSTERPMCNTENSET_EL1_C); +#else pmu_ccntr_ccfiltr_config(PMCCFILTR_EL0_NSH); pmu_cntr_control_config(PMCR_EL0_C | PMCR_EL0_E); pmu_cntr_trap_control(PMUSERENR_EL0_EN); pmu_cntr_irq_disable(PMINTENCLR_EL1_C); pmu_cntr_enable(PMCNTENSET_EL0_C); +#endif } unsigned long up_perf_getfreq(void) @@ -56,7 +64,11 @@ unsigned long up_perf_getfreq(void) unsigned long up_perf_gettime(void) { +#ifdef CONFIG_ARCH_CLUSTER_PMU + return pmu_get_cluccntr(); +#else return pmu_get_ccntr(); +#endif } void up_perf_convert(unsigned long elapsed, struct timespec *ts) diff --git a/arch/arm64/src/common/arm64_pmu.h b/arch/arm64/src/common/arm64_pmu.h index 34b8c3bbb53..95269d9afe4 100644 --- a/arch/arm64/src/common/arm64_pmu.h +++ b/arch/arm64/src/common/arm64_pmu.h @@ -85,6 +85,41 @@ #define PMUSERENR_EL0_SW (1ul << 1) /* Software Increment write trap control */ #define PMUSERENR_EL0_EN (1ul << 0) /* Software can access all PMU registers at EL0 */ +#ifdef CONFIG_ARCH_CLUSTER_PMU + +/* The CORTEX-R82 processor implements the cluster PMU */ + +/* CLUSTERPMCR_EL1 */ + +#define CLUSTERPMCR_EL1_X (1ul << 4) /* Enable export of events */ +#define CLUSTERPMCR_EL1_C (1ul << 2) /* Cycle counter reset */ +#define CLUSTERPMCR_EL1_P (1ul << 1) /* Event counter reset */ +#define CLUSTERPMCR_EL1_E (1ul << 0) /* All counters that are accessible at Non-secure EL1 are enabled by PMCNTENSET_EL0 */ + +/* CLUSTERPMCNTENSET_EL1 */ + +#define CLUSTERPMCNTENSET_EL1_C (1ul << 31) /* Enables the cycle counter register */ + +/* CLUSTERPMOVSCLR_EL1 */ + +#define CLUSTERPMOVSCLR_EL1_C (1ul << 31) /* CLUSTERPMCCNTR_EL0 overflow bit */ + +/* CLUSTERPMSELR_EL1 */ + +#define CLUSTERPMSELR_EL1_SEL_C (0x1ful << 0) /* When CLUSTERPMSELR_EL0.SEL is 0b11111, it selects the cycle counter */ + +/* CLUSTERPMINTENCLR_EL1 */ + +#define CLUSTERPMINTENCLR_EL1_C (1ul << 31) /* CLUSTERPMCCNTR_EL0 overflow interrupt request disable bit */ + +#define clusterpmcr_el1 s3_0_c15_c5_0 +#define clusterpmcntenset_el1 s3_0_c15_c5_1 +#define clusterpmovsclr_el1 s3_0_c15_c5_4 +#define clusterpmintenclr_el1 s3_0_c15_c5_7 +#define clusterpmccntr_el1 s3_0_c15_c6_0 + +#endif + /**************************************************************************** * Inline Functions ****************************************************************************/ @@ -232,4 +267,162 @@ static inline void pmu_cntr_irq_disable(uint64_t mask) write_sysreg(mask, pmintenclr_el1); } +#ifdef CONFIG_ARCH_CLUSTER_PMU + +/**************************************************************************** + * Name: pmu_get_cluccntr + * + * Description: + * Read cluster cycle counter. + * + * Return Value: + * Cycle count. + * + ****************************************************************************/ + +static inline uint64_t pmu_get_cluccntr(void) +{ + return read_sysreg(clusterpmccntr_el1); +} + +/**************************************************************************** + * Name: pmu_cntr_control_config + * + * Description: + * Config counters. + * + * Parameters: + * mask - Configuration flags for counters. + * + ****************************************************************************/ + +static inline void pmu_clucntr_control_config(uint64_t mask) +{ + write_sysreg(mask, clusterpmcr_el1); +} + +/**************************************************************************** + * Name: pmu_clucntr_enable + * + * Description: + * Enable counters. + * + * Parameters: + * mask - Counters to enable. + * + * Note: + * Enables one or more of the following: + * event counters (0-30) + * cycle counter + * + ****************************************************************************/ + +static inline void pmu_clucntr_enable(uint64_t mask) +{ + write_sysreg(mask, clusterpmcntenset_el1); +} + +/**************************************************************************** + * Name: pmu_clucntr_ovsclr_config + * + * Description: + * Clear counter overflow bits. + * + * Parameters: + * mask - Corresponds to the counter overflow bit to clear. + * + ****************************************************************************/ + +static inline void pmu_clucntr_ovsclr_config(uint64_t mask) +{ + write_sysreg(mask, clusterpmovsclr_el1); +} + +/**************************************************************************** + * Name: pmu_clucntr_select + * + * Description: + * Selects the current event counter or the cycle counter. + * + * Parameters: + * mask - Select counter flag. + * + ****************************************************************************/ + +static inline void pmu_clucntr_select(uint64_t mask) +{ + write_sysreg(mask, clusterpmselr_el1); +} + +/**************************************************************************** + * Name: pmu_clucntr_irq_disable + * + * Description: + * Disable counter overflow interrupt request. + * + * Parameters: + * mask - Counter overflow interrupt request bits to clear. + * + * Note: + * Sets overflow interrupt request bits for one or more of the following: + * event counters (0-30) + * cycle counter + * + ****************************************************************************/ + +static inline void pmu_clucntr_irq_disable(uint64_t mask) +{ + write_sysreg(mask, clusterpmintenclr_el1); +} + +/**************************************************************************** + * Name: pmu_clucntr_get_xevtyper + * + * Description: + * Gets the selected counter type. + * + * Return Value: + * Select the value of the counter type. + * + ****************************************************************************/ + +static inline uint64_t pmu_clucntr_get_xevtyper(void) +{ + return read_sysreg(clusterpmxevtyper_el1); +} + +/**************************************************************************** + * Name: pmu_clucntr_set_xevtyper + * + * Description: + * Sets the selected counter type. + * + * Parameters: + * mask - The value of the type counter. + * + ****************************************************************************/ + +static inline void pmu_clucntr_set_xevtyper(uint64_t mask) +{ + write_sysreg(mask, clusterpmxevtyper_el1); +} + +/**************************************************************************** + * Name: pmu_clucntr_get_xevcntr + * + * Description: + * Reads the value of the selected counter. + * + * Return Value: + * Select the value of the counter. + * + ****************************************************************************/ + +static inline uint64_t pmu_clucntr_get_xevcntr(void) +{ + return read_sysreg(clusterpmxevcntr_el1); +} + +#endif + #endif /* __ARCH_ARM64_SRC_COMMON_ARM64_PMU_H */