aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristofer Jonsson <kristofer.jonsson@arm.com>2020-08-25 16:32:21 +0200
committerKristofer Jonsson <kristofer.jonsson@arm.com>2020-08-26 11:50:54 +0200
commitef387ea3cbff63e06d1d0808047b9f19adf244c9 (patch)
tree731748dee197d39c356eaf6aa044d81de533b909
parent9716b5e00c10b000067ca3ee1ad91fef4cccbb46 (diff)
downloadethos-u-core-driver-20.08.tar.gz
Save and restore PMU settings and counters20.08-rc220.08
Change-Id: I54a1927fef998bc97f5507f2de9faf7d4a7960f5
-rw-r--r--include/ethosu_device.h5
-rw-r--r--src/ethosu_device.c50
-rw-r--r--src/ethosu_driver.c9
-rw-r--r--src/ethosu_pmu.c101
4 files changed, 121 insertions, 44 deletions
diff --git a/include/ethosu_device.h b/include/ethosu_device.h
index 9c78bfc..e08aa3d 100644
--- a/include/ethosu_device.h
+++ b/include/ethosu_device.h
@@ -55,8 +55,11 @@ enum ethosu_error_codes
struct ethosu_device
{
uintptr_t base_address;
- bool restore_pmu_config;
+ uint32_t pmcr;
uint64_t pmccntr;
+ uint32_t pmcnten;
+ uint32_t pmint;
+ uint32_t pmccntr_cfg;
uint32_t pmu_evcntr[ETHOSU_PMU_NCOUNTERS];
enum ethosu_pmu_event_type pmu_evtypr[ETHOSU_PMU_NCOUNTERS];
};
diff --git a/src/ethosu_device.c b/src/ethosu_device.c
index 9cb67ce..4729c49 100644
--- a/src/ethosu_device.c
+++ b/src/ethosu_device.c
@@ -38,6 +38,7 @@ enum ethosu_error_codes ethosu_dev_init(struct ethosu_device *dev, const void *b
{
#if !defined(ARM_NPU_STUB)
dev->base_address = (uintptr_t)base_address;
+ ethosu_save_pmu_config(dev);
#else
UNUSED(dev);
UNUSED(base_address);
@@ -559,15 +560,26 @@ void ethosu_write_reg(struct ethosu_device *dev, uint32_t address, uint32_t valu
enum ethosu_error_codes ethosu_save_pmu_config(struct ethosu_device *dev)
{
#if !defined(ARM_NPU_STUB)
+ // Save the PMU control register
+ dev->pmcr = ethosu_read_reg(dev, NPU_REG_PMCR);
+
+ // Save IRQ control
+ dev->pmint = ethosu_read_reg(dev, NPU_REG_PMINTSET);
+
+ // Save the enabled events mask
+ dev->pmcnten = ethosu_read_reg(dev, NPU_REG_PMCNTENSET);
+
+ // Save start and stop event
+ dev->pmccntr_cfg = ethosu_read_reg(dev, NPU_REG_PMCCNTR_CFG);
+
+ // Save the cycle counter
dev->pmccntr = ETHOSU_PMU_Get_CCNTR();
+
+ // Save the event settings and counters
for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
{
- dev->pmu_evcntr[i] = ETHOSU_PMU_Get_EVCNTR(i);
- dev->pmu_evtypr[i] = ETHOSU_PMU_Get_EVTYPER(i);
- }
- if (!dev->restore_pmu_config)
- {
- dev->restore_pmu_config = true;
+ dev->pmu_evcntr[i] = ethosu_read_reg(dev, NPU_REG_PMEVCNTR0 + i * sizeof(uint32_t));
+ dev->pmu_evtypr[i] = ethosu_read_reg(dev, NPU_REG_PMEVTYPER0 + i * sizeof(uint32_t));
}
#else
UNUSED(dev);
@@ -579,14 +591,26 @@ enum ethosu_error_codes ethosu_save_pmu_config(struct ethosu_device *dev)
enum ethosu_error_codes ethosu_restore_pmu_config(struct ethosu_device *dev)
{
#if !defined(ARM_NPU_STUB)
- if (dev->restore_pmu_config)
+ // Restore PMU control register
+ ethosu_write_reg(dev, NPU_REG_PMCR, dev->pmcr);
+
+ // Restore IRQ control
+ ethosu_write_reg(dev, NPU_REG_PMINTSET, dev->pmint);
+
+ // Restore enabled event mask
+ ethosu_write_reg(dev, NPU_REG_PMCNTENSET, dev->pmcnten);
+
+ // Restore start and stop event
+ ethosu_write_reg(dev, NPU_REG_PMCCNTR_CFG, dev->pmccntr_cfg);
+
+ // Restore the cycle counter
+ ETHOSU_PMU_Set_CCNTR(dev->pmccntr);
+
+ // Restore event settings and counters
+ for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
{
- ETHOSU_PMU_Set_CCNTR(dev->pmccntr);
- for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
- {
- ETHOSU_PMU_Set_EVCNTR(i, dev->pmu_evcntr[i]);
- ETHOSU_PMU_Set_EVTYPER(i, dev->pmu_evtypr[i]);
- }
+ ethosu_write_reg(dev, NPU_REG_PMEVCNTR0 + i * sizeof(uint32_t), dev->pmu_evcntr[i]);
+ ethosu_write_reg(dev, NPU_REG_PMEVTYPER0 + i * sizeof(uint32_t), dev->pmu_evtypr[i]);
}
#else
UNUSED(dev);
diff --git a/src/ethosu_driver.c b/src/ethosu_driver.c
index f47d3f2..702edb4 100644
--- a/src/ethosu_driver.c
+++ b/src/ethosu_driver.c
@@ -29,12 +29,9 @@
#include <stdio.h>
#include <stdlib.h>
-struct ethosu_driver ethosu_drv = {.dev = {.base_address = NULL,
- .restore_pmu_config = false,
- .pmccntr = 0,
- .pmu_evcntr = {0, 0, 0, 0},
- .pmu_evtypr = {0, 0, 0, 0}},
- .abort_inference = false};
+struct ethosu_driver ethosu_drv = {
+ .dev = {.base_address = NULL, .pmccntr = 0, .pmu_evcntr = {0, 0, 0, 0}, .pmu_evtypr = {0, 0, 0, 0}},
+ .abort_inference = false};
// IRQ
static volatile bool irq_triggered = false;
diff --git a/src/ethosu_pmu.c b/src/ethosu_pmu.c
index 62dc5da..c9a46b0 100644
--- a/src/ethosu_pmu.c
+++ b/src/ethosu_pmu.c
@@ -110,79 +110,111 @@ void ethosu_pmu_driver_exit(void) {}
void ETHOSU_PMU_Enable(void)
{
+ LOG_DEBUG("%s:\n", __FUNCTION__);
struct pmcr_r pmcr;
- pmcr.word = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCR);
+ pmcr.word = ethosu_drv.dev.pmcr;
pmcr.cnt_en = 1;
ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCR, pmcr.word);
+ ethosu_drv.dev.pmcr = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCR);
}
void ETHOSU_PMU_Disable(void)
{
+ LOG_DEBUG("%s:\n", __FUNCTION__);
struct pmcr_r pmcr;
- pmcr.word = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCR);
+ pmcr.word = ethosu_drv.dev.pmcr;
pmcr.cnt_en = 0;
ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCR, pmcr.word);
+ ethosu_drv.dev.pmcr = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCR);
}
void ETHOSU_PMU_Set_EVTYPER(uint32_t num, enum ethosu_pmu_event_type type)
{
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMEVTYPER(num), pmu_event_value(type));
+ ASSERT(num < ETHOSU_PMU_NCOUNTERS);
+ uint32_t val = pmu_event_value(type);
+ LOG_DEBUG("%s: num=%u, type=%d, val=%u\n", __FUNCTION__, num, type, val);
+ ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMEVTYPER(num), val);
+ ethosu_drv.dev.pmu_evtypr[num] = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMEVTYPER(num));
}
enum ethosu_pmu_event_type ETHOSU_PMU_Get_EVTYPER(uint32_t num)
{
- return pmu_event_type(ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMEVTYPER(num)));
+ ASSERT(num < ETHOSU_PMU_NCOUNTERS);
+ uint32_t val = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMEVTYPER(num));
+ enum ethosu_pmu_event_type type = pmu_event_type(val);
+ LOG_DEBUG("%s: num=%u, type=%d, val=%u\n", __FUNCTION__, num, type, val);
+ return type;
}
void ETHOSU_PMU_CYCCNT_Reset(void)
{
+ LOG_DEBUG("%s:\n", __FUNCTION__);
struct pmcr_r pmcr;
- pmcr.word = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCR);
+ pmcr.word = ethosu_drv.dev.pmcr;
pmcr.cycle_cnt_rst = 1;
ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCR, pmcr.word);
+ ethosu_drv.dev.pmcr = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCR);
+ ethosu_drv.dev.pmccntr_cfg = 0;
}
void ETHOSU_PMU_EVCNTR_ALL_Reset(void)
{
+ LOG_DEBUG("%s:\n", __FUNCTION__);
struct pmcr_r pmcr;
- pmcr.word = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCR);
+ pmcr.word = ethosu_drv.dev.pmcr;
pmcr.event_cnt_rst = 1;
ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCR, pmcr.word);
+ ethosu_drv.dev.pmcr = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCR);
+
+ for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
+ {
+ ethosu_drv.dev.pmu_evcntr[i] = 0;
+ }
}
void ETHOSU_PMU_CNTR_Enable(uint32_t mask)
{
+ LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCNTENSET, mask);
+ ethosu_drv.dev.pmcnten = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCNTENSET);
}
void ETHOSU_PMU_CNTR_Disable(uint32_t mask)
{
+ LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCNTENCLR, mask);
+ ethosu_drv.dev.pmcnten = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCNTENSET);
}
uint32_t ETHOSU_PMU_CNTR_Status(void)
{
- return ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCNTENSET);
+ uint32_t val = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCNTENSET);
+ LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, val);
+ return val;
}
uint64_t ETHOSU_PMU_Get_CCNTR(void)
{
- uint64_t val1 = (((uint64_t)ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_HI)) << 32) |
- ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_LO);
- uint64_t val2 = (((uint64_t)ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_HI)) << 32) |
- ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_LO);
+ uint64_t val = (((uint64_t)ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_HI)) << 32) |
+ ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_LO);
- if (val2 > val1)
+ LOG_DEBUG("%s: val=%llu, pmccntr=%llu\n", __FUNCTION__, val, ethosu_drv.dev.pmccntr);
+
+ // Return the cached value in case the NPU was powered off
+ if (ethosu_drv.dev.pmccntr > val)
{
- return val2;
+ return ethosu_drv.dev.pmccntr;
}
- return val1;
+
+ return val;
}
void ETHOSU_PMU_Set_CCNTR(uint64_t val)
{
uint32_t mask = ETHOSU_PMU_CNTR_Status();
+ LOG_DEBUG("%s: val=%llu\n", __FUNCTION__, val);
+
if (mask & ETHOSU_PMU_CCNT_Msk)
{
ETHOSU_PMU_CNTR_Disable(ETHOSU_PMU_CCNT_Msk);
@@ -199,16 +231,29 @@ void ETHOSU_PMU_Set_CCNTR(uint64_t val)
uint32_t ETHOSU_PMU_Get_EVCNTR(uint32_t num)
{
- return ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMEVCNTR(num));
+ ASSERT(num < ETHOSU_PMU_NCOUNTERS);
+ uint32_t val = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMEVCNTR(num));
+ LOG_DEBUG("%s: num=%u, val=%u, pmu_evcntr=%u\n", __FUNCTION__, num, val, ethosu_drv.dev.pmu_evcntr[num]);
+
+ // Return the cached value in case the NPU was powered off
+ if (ethosu_drv.dev.pmu_evcntr[num] > val)
+ {
+ return ethosu_drv.dev.pmu_evcntr[num];
+ }
+
+ return val;
}
void ETHOSU_PMU_Set_EVCNTR(uint32_t num, uint32_t val)
{
+ ASSERT(num < ETHOSU_PMU_NCOUNTERS);
+ LOG_DEBUG("%s: num=%u, val=%u\n", __FUNCTION__, num, val);
ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMEVCNTR(num), val);
}
uint32_t ETHOSU_PMU_Get_CNTR_OVS(void)
{
+ LOG_DEBUG("%s:\n", __FUNCTION__);
return ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMOVSSET);
}
@@ -216,26 +261,34 @@ uint32_t ETHOSU_PMU_Get_CNTR_OVS(void)
// implementation.
void ETHOSU_PMU_Set_CNTR_OVS(uint32_t mask)
{
+ LOG_DEBUG("%s:\n", __FUNCTION__);
ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMOVSCLR, mask);
}
void ETHOSU_PMU_Set_CNTR_IRQ_Enable(uint32_t mask)
{
+ LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMINTSET, mask);
+ ethosu_drv.dev.pmint = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMINTSET);
}
void ETHOSU_PMU_Set_CNTR_IRQ_Disable(uint32_t mask)
{
+ LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMINTCLR, mask);
+ ethosu_drv.dev.pmint = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMINTSET);
}
uint32_t ETHOSU_PMU_Get_IRQ_Enable(void)
{
- return ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMINTSET);
+ uint32_t mask = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMINTSET);
+ LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
+ return mask;
}
void ETHOSU_PMU_CNTR_Increment(uint32_t mask)
{
+ LOG_DEBUG("%s:\n", __FUNCTION__);
uint32_t cntrs_active = ETHOSU_PMU_CNTR_Status();
if (mask & ETHOSU_PMU_CCNT_Msk)
@@ -271,16 +324,16 @@ void ETHOSU_PMU_CNTR_Increment(uint32_t mask)
void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(uint32_t start_event)
{
- struct pmccntr_cfg_r cfg;
- cfg.word = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_CFG);
- cfg.CYCLE_CNT_CFG_START = start_event & ETHOSU_PMCCNTR_CFG_START_STOP_EVENT_MASK;
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_CFG, cfg.word);
+ LOG_DEBUG("%s: start_event=%u\n", __FUNCTION__, start_event);
+ struct pmccntr_cfg_r *cfg = (struct pmccntr_cfg_r *)&ethosu_drv.dev.pmccntr_cfg;
+ cfg->CYCLE_CNT_CFG_START = start_event & ETHOSU_PMCCNTR_CFG_START_STOP_EVENT_MASK;
+ ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_CFG, cfg->word);
}
void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(uint32_t stop_event)
{
- struct pmccntr_cfg_r cfg;
- cfg.word = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_CFG);
- cfg.CYCLE_CNT_CFG_STOP = stop_event & ETHOSU_PMCCNTR_CFG_START_STOP_EVENT_MASK;
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_CFG, cfg.word);
+ LOG_DEBUG("%s: stop_event=%u\n", __FUNCTION__, stop_event);
+ struct pmccntr_cfg_r *cfg = (struct pmccntr_cfg_r *)&ethosu_drv.dev.pmccntr_cfg;
+ cfg->CYCLE_CNT_CFG_STOP = stop_event & ETHOSU_PMCCNTR_CFG_START_STOP_EVENT_MASK;
+ ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_CFG, cfg->word);
}