From 71e4267a7aaf0902665c0835aa25615ce0ec2dc7 Mon Sep 17 00:00:00 2001 From: liaoao Date: Fri, 15 Sep 2023 21:33:00 +0800 Subject: [PATCH] coresight: add etm3 device support Signed-off-by: liaoao --- drivers/coresight/CMakeLists.txt | 4 + drivers/coresight/Kconfig | 16 + drivers/coresight/Make.defs | 4 + drivers/coresight/coresight_common.c | 7 +- drivers/coresight/coresight_common.h | 3 +- drivers/coresight/coresight_etm3.c | 733 ++++++++++++++++++++++++ drivers/coresight/coresight_stm.c | 4 +- drivers/coresight/coresight_tpiu.c | 19 +- include/nuttx/coresight/coresight.h | 4 + include/nuttx/coresight/coresight_etm.h | 139 +++++ 10 files changed, 914 insertions(+), 19 deletions(-) create mode 100644 drivers/coresight/coresight_etm3.c create mode 100644 include/nuttx/coresight/coresight_etm.h diff --git a/drivers/coresight/CMakeLists.txt b/drivers/coresight/CMakeLists.txt index b2add74a8a..e12b869f5b 100644 --- a/drivers/coresight/CMakeLists.txt +++ b/drivers/coresight/CMakeLists.txt @@ -21,6 +21,10 @@ if(CONFIG_CORESIGHT) set(SRCS coresight_core.c coresight_common.c) + if(CONFIG_CORESIGHT_ETM_VERSION STREQUAL "v3") + list(APPEND SRCS coresight_etm3.c) + endif() + if(CONFIG_CORESIGHT_FUNNEL) list(APPEND SRCS coresight_funnel.c) endif() diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig index 6dbff6c83c..ad0d7e50b6 100644 --- a/drivers/coresight/Kconfig +++ b/drivers/coresight/Kconfig @@ -19,6 +19,22 @@ config CORESIGHT_TIMEOUT int "Timeout us for waiting register state change" default 100 +config CORESIGHT_ETM + bool "ETM coresight device support" + default n + +if CORESIGHT_ETM + +config CORESIGHT_ETM_VERSION + string "Coresight ETM version" + default "v3" + +config CORESIGHT_ETM_USE_COPROCESSOR + bool "Whether use coprocessor to access ETM registers" + default n + +endif # CORESIGHT_ETM + config CORESIGHT_FUNNEL bool "Funnel coresight device support" default n diff --git a/drivers/coresight/Make.defs b/drivers/coresight/Make.defs index 71723d5e6e..fa8fc3e366 100644 --- a/drivers/coresight/Make.defs +++ b/drivers/coresight/Make.defs @@ -24,6 +24,10 @@ ifeq ($(CONFIG_CORESIGHT),y) CSRCS += coresight_core.c coresight_common.c +ifeq ($(CONFIG_CORESIGHT_ETM_VERSION),"v3") +CSRCS += coresight_etm3.c +endif + ifeq ($(CONFIG_CORESIGHT_FUNNEL),y) CSRCS += coresight_funnel.c endif diff --git a/drivers/coresight/coresight_common.c b/drivers/coresight/coresight_common.c index bd7f3172a8..10af662402 100644 --- a/drivers/coresight/coresight_common.c +++ b/drivers/coresight/coresight_common.c @@ -272,15 +272,14 @@ void coresight_put_system_trace_id(int traceid) * ****************************************************************************/ -int coresight_timeout(uintptr_t addr, uint32_t off, - uint32_t bitmask, uint32_t val) +int coresight_timeout(uint32_t val, uint32_t mask, uintptr_t addr) { int i; for (i = CONFIG_CORESIGHT_TIMEOUT; i > 0; i--) { - uint32_t value = coresight_get32(addr + off); - if ((value & bitmask) == val) + uint32_t value = coresight_get32(addr); + if ((value & mask) == val) { return 0; } diff --git a/drivers/coresight/coresight_common.h b/drivers/coresight/coresight_common.h index e11eea5767..164d7d2183 100644 --- a/drivers/coresight/coresight_common.h +++ b/drivers/coresight/coresight_common.h @@ -183,8 +183,7 @@ void coresight_put_system_trace_id(int traceid); * ****************************************************************************/ -int coresight_timeout(uintptr_t addr, uint32_t off, - uint32_t bitmask, uint32_t val); +int coresight_timeout(uint32_t val, uint32_t mask, uintptr_t addr); /**************************************************************************** * Name: coresight_insert_barrier_packet diff --git a/drivers/coresight/coresight_etm3.c b/drivers/coresight/coresight_etm3.c new file mode 100644 index 0000000000..03bf424fbc --- /dev/null +++ b/drivers/coresight/coresight_etm3.c @@ -0,0 +1,733 @@ +/**************************************************************************** + * drivers/coresight/coresight_etm3.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include + +#include "coresight_common.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Device registers: + * 0x000 - 0x2FC: Trace registers + * 0x300 - 0x314: Management registers + * 0x318 - 0xEFC: Trace registers + * + * Coresight registers + * 0xF00 - 0xF9C: Management registers + * 0xFA0 - 0xFA4: Management registers in PFTv1.0 + * Trace registers in PFTv1.1 + * 0xFA8 - 0xFFC: Management registers + */ + +#define ETM_CR 0x000 +#define ETM_CCR 0x004 +#define ETM_TRIGGER 0x008 +#define ETM_SR 0x010 +#define ETM_SCR 0x014 +#define ETM_TSSCR 0x018 +#define ETM_TECR2 0x01c +#define ETM_TEEVR 0x020 +#define ETM_TECR1 0x024 +#define ETM_FFLR 0x02c +#define ETM_ACVR(n) (0x040 + (n * 4)) +#define ETM_ACTR(n) (0x080 + (n * 4)) +#define ETM_CNTRLDVR(n) (0x140 + (n * 4)) +#define ETM_CNTENR(n) (0x150 + (n * 4)) +#define ETM_CNTRLDEVR(n) (0x160 + (n * 4)) +#define ETM_CNTVR(n) (0x170 + (n * 4)) +#define ETM_SQ12EVR 0x180 +#define ETM_SQ21EVR 0x184 +#define ETM_SQ23EVR 0x188 +#define ETM_SQ31EVR 0x18c +#define ETM_SQ32EVR 0x190 +#define ETM_SQ13EVR 0x194 +#define ETM_SQR 0x19c +#define ETM_EXTOUTEVR(n) (0x1a0 + (n * 4)) +#define ETM_CIDCVR(n) (0x1b0 + (n * 4)) +#define ETM_CIDCMR 0x1bc +#define ETM_IMPSPEC0 0x1c0 +#define ETM_IMPSPEC1 0x1c4 +#define ETM_IMPSPEC2 0x1c8 +#define ETM_IMPSPEC3 0x1cc +#define ETM_IMPSPEC4 0x1d0 +#define ETM_IMPSPEC5 0x1d4 +#define ETM_IMPSPEC6 0x1d8 +#define ETM_IMPSPEC7 0x1dc +#define ETM_SYNCFR 0x1e0 +#define ETM_IDR 0x1e4 +#define ETM_CCER 0x1e8 +#define ETM_EXTINSELR 0x1ec +#define ETM_TESSEICR 0x1f0 +#define ETM_EIBCR 0x1f4 +#define ETM_TSEVR 0x1f8 +#define ETM_AUXCR 0x1fc +#define ETM_TRACEIDR 0x200 +#define ETM_VMIDCVR 0x240 + +/* Management registers (0x300-0x314) */ + +#define ETM_OSLAR 0x300 +#define ETM_OSLSR 0x304 +#define ETM_OSSRR 0x308 +#define ETM_PDCR 0x310 +#define ETM_PDSR 0x314 + +/* Register definition */ + +/* ETMCR - 0x00 */ + +#define ETM_CR_PWD_DWN BIT(0) +#define ETM_CR_STALL_MODE BIT(7) +#define ETM_CR_BRANCH_BROADCAST BIT(8) +#define ETM_CR_ETM_PRG BIT(10) +#define ETM_CR_ETM_EN BIT(11) +#define ETM_CR_CYC_ACC BIT(12) +#define ETM_CR_CTXID_SIZE (BIT(14) | BIT(15)) +#define ETM_CR_TIMESTAMP_EN BIT(28) + +/* ETM_CR_RETURN_STACK is supported by PTM, ETM not support it */ + +#define ETM_CR_RETURN_STACK BIT(29) + +/* ETMCCR - 0x04 */ + +#define ETM_CCR_FIFOFULL BIT(23) + +/* ETMPDCR - 0x310 */ + +#define ETM_PDCR_PWD_UP BIT(3) + +/* ETMTECR1 - 0x024 */ + +#define ETM_TECR1_ADDR_COMP_1 BIT(0) +#define ETM_TECR1_INC_EXC BIT(24) +#define ETM_TECR1_START_STOP BIT(25) + +/* ETMCCER - 0x1E8 */ + +#define ETM_CCER_TIMESTAMP BIT(22) +#define ETM_CCER_RETSTACK BIT(23) + +#define ETM_MODE_EXCLUDE BIT(0) +#define ETM_MODE_CYCACC BIT(1) +#define ETM_MODE_STALL BIT(2) +#define ETM_MODE_TIMESTAMP BIT(3) +#define ETM_MODE_CTXID BIT(4) +#define ETM_MODE_BBROAD BIT(5) +#define ETM_MODE_RET_STACK BIT(6) +#define ETM_MODE_EXCL_KERN BIT(30) +#define ETM_MODE_EXCL_USER BIT(31) +#define ETM_MODE_ALL \ + (ETM_MODE_EXCLUDE | ETM_MODE_CYCACC | ETM_MODE_STALL | \ + ETM_MODE_TIMESTAMP | ETM_MODE_CTXID | ETM_MODE_BBROAD | \ + ETM_MODE_RET_STACK | ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER) + +#define ETM_SQR_MASK 0x3 +#define ETM_TRACEID_MASK 0x3f +#define ETM_EVENT_MASK 0x1ffff +#define ETM_SYNC_MASK 0xfff +#define ETM_ALL_MASK 0xffffffff + +#define ETM_SR_PROGRAM BIT(1) +#define ETM_SEQ_STATE_MAX_VAL 0x2 +#define ETM_PORT_SIZE_MASK (GENMASK(21, 21) | GENMASK(6, 4)) + +#define ETM_ARCH_V3_3 0x23 +#define ETM_ARCH_V3_5 0x25 +#define PFT_ARCH_V1_0 0x30 +#define PFT_ARCH_V1_1 0x31 + +/* Hard wired, always true */ + +#define ETM_HARD_WIRE_RES_A ((0x0f << 0) | (0x06 << 4)) + +/* Single addr comparator 1 */ + +#define ETM_ADD_COMP_0 ((0x00 << 7) | (0x00 << 11)) + +/* NOT(A) */ + +#define ETM_EVENT_NOT_A BIT(14) + +#define ETM_DEFAULT_EVENT_VAL \ + (ETM_HARD_WIRE_RES_A | ETM_ADD_COMP_0 | ETM_EVENT_NOT_A) + +#define ETM3X_SUPPORTED_OPTIONS \ + (ETM_CR_CYC_ACC | ETM_CR_TIMESTAMP_EN | ETM_CR_RETURN_STACK) + +/**************************************************************************** + * Private Functions Prototypes + ****************************************************************************/ + +static int etm_enable(FAR struct coresight_dev_s *csdev); +static void etm_disable(FAR struct coresight_dev_s *csdev); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct coresight_source_ops_s g_etm_source_ops = +{ + .enable = etm_enable, + .disable = etm_disable, +}; + +static const struct coresight_ops_s g_etm_ops = +{ + .source_ops = &g_etm_source_ops, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifndef CONFIG_CORESIGHT_ETM_USE_COPROCESSOR +static inline void etm_write_reg(FAR struct coresight_etm_dev_s *etmdev, + uint32_t val, uint32_t off) +{ + coresight_put32(val, etmdev->csdev.addr + off); +} + +static inline uint32_t etm_read_reg(FAR struct coresight_etm_dev_s *etmdev, + uint32_t off) +{ + return coresight_get32(etmdev->csdev.addr + off); +} +#endif + +/**************************************************************************** + * Name: etm_modify_reg32 + * + * Description: + * Set a bitmask of register to specific value. + * + ****************************************************************************/ + +static void etm_modify_reg32(FAR struct coresight_etm_dev_s *etmdev, + uint32_t val, uint32_t mask, uint32_t off) +{ + uint32_t temp = etm_read_reg(etmdev, off); + + etm_write_reg(etmdev, (temp & ~mask) | (val & mask), off); +} + +/**************************************************************************** + * Name: etm_os_unlock + * + * Description: + * When the ETM trace registers are locked, any attempt to access the + * locked registers returns a slave-generated error response.In ETMv3.5, + * the OS Lock is always set from an ETM reset. ARM recommends that, after + * programming the ETM registers, you always execute an ISB instruction to + * ensure that all updates are committed to the ETM before you restart + * normal code execution. + * + ****************************************************************************/ + +static void etm_os_unlock(FAR struct coresight_etm_dev_s *etmdev) +{ + etm_write_reg(etmdev, 0x0, ETM_OSLAR); +} + +/**************************************************************************** + * Name: etm_clr_pwrdwn + * + * Description: + * When pwrdown bit is set to 1, the ETM must be powered down and disabled, + * and then operated in a low power mode with all clocks stopped. When this + * bit is set to 1, writes to some registers and fields might be ignored. + * ARM recommends that you use a read-modify-write procedure when modifying + * the ETMCR. + * + ****************************************************************************/ + +static void etm_clr_pwrdwn(FAR struct coresight_etm_dev_s *etmdev) +{ + etm_modify_reg32(etmdev, 0, ETM_CR_PWD_DWN, ETM_CR); +} + +/**************************************************************************** + * Name: etm_set_pwrdwn + ****************************************************************************/ + +static void etm_set_pwrdwn(FAR struct coresight_etm_dev_s *etmdev) +{ + etm_modify_reg32(etmdev, ETM_CR_PWD_DWN, ETM_CR_PWD_DWN, ETM_CR); +} + +/**************************************************************************** + * Name: etm_set_pwrup + * + * Description: + * Power is provided to the ETM trace registers. This register can only be + * accessed using a memory-mapped interface or from an external debugger. + * + ****************************************************************************/ + +static void etm_set_pwrup(FAR struct coresight_etm_dev_s *etmdev) +{ + coresight_modify32(ETM_PDCR_PWD_UP, ETM_PDCR_PWD_UP, + etmdev->csdev.addr + ETM_PDCR); +} + +/**************************************************************************** + * Name: etm_clr_pwrup + ****************************************************************************/ + +static void etm_clr_pwrup(FAR struct coresight_etm_dev_s *etmdev) +{ + coresight_modify32(0, ETM_PDCR_PWD_UP, etmdev->csdev.addr + ETM_PDCR); +} + +/**************************************************************************** + * Name: etm_timeout + * + * Description: + * Loop until a bitmask of register has changed to a specific value. + * + ****************************************************************************/ + +static int etm_timeout(FAR struct coresight_etm_dev_s *etmdev, + uint32_t val, uint32_t mask, uint32_t off) +{ + int i; + + for (i = CONFIG_CORESIGHT_TIMEOUT; i > 0; i--) + { + uint32_t value = etm_read_reg(etmdev, off); + if ((value & mask) == val) + { + return 0; + } + + up_udelay(1); + } + + return -EAGAIN; +} + +/**************************************************************************** + * Name: etm_set_program + * + * Description: + * Set ETM Programming bit to disable all operations during programming. + * When programming the ETM registers you must enable all the changes at + * the same time. + * + ****************************************************************************/ + +static void etm_set_program(FAR struct coresight_etm_dev_s *etmdev) +{ + etm_modify_reg32(etmdev, ETM_CR_ETM_PRG, ETM_CR_ETM_PRG, ETM_CR); + + if (etm_timeout(etmdev, ETM_SR_PROGRAM, ETM_SR_PROGRAM, ETM_SR) < 0) + { + cserr("timeout observed at setting ETM_SR_PROGRAM\n"); + } +} + +/**************************************************************************** + * Name: etm_clr_program + ****************************************************************************/ + +static void etm_clr_program(FAR struct coresight_etm_dev_s *etmdev) +{ + etm_modify_reg32(etmdev, 0, ETM_CR_ETM_PRG, ETM_CR); + + if (etm_timeout(etmdev, 0, ETM_SR_PROGRAM, ETM_SR) < 0) + { + cserr("timeout observed at clearing ETM_SR_PROGRAM\n"); + } +} + +/**************************************************************************** + * Name: etm_init_arch_data + * + * Description: + * Get capabilities of current ETM architecture version. + * + ****************************************************************************/ + +static void etm_init_arch_data(FAR struct coresight_etm_dev_s *etmdev) +{ + uint32_t etmccr; + + coresight_unlock(etmdev->csdev.addr); + etm_os_unlock(etmdev); + etm_clr_pwrdwn(etmdev); + etm_set_pwrup(etmdev); + etm_set_program(etmdev); + + etmdev->arch = BMVAL(etm_read_reg(etmdev, ETM_IDR), 4, 11); + etmdev->port_size = etm_read_reg(etmdev, ETM_CR) & ETM_PORT_SIZE_MASK; + + etmccr = etm_read_reg(etmdev, ETM_CCR); + etmdev->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2; + etmdev->nr_cntr = BMVAL(etmccr, 13, 15); + etmdev->nr_ext_inp = BMVAL(etmccr, 17, 19); + etmdev->nr_ext_out = BMVAL(etmccr, 20, 22); + etmdev->nr_ctxid_cmp = BMVAL(etmccr, 24, 25); + + etm_clr_program(etmdev); + etm_clr_pwrup(etmdev); + etm_set_pwrdwn(etmdev); + coresight_lock(etmdev->csdev.addr); +} + +/**************************************************************************** + * Name: etm_arch_supported + * + * Description: + * If ETM/PTM implement is supported by current driver. + * + ****************************************************************************/ + +static bool etm_arch_supported(uint8_t arch) +{ + switch (arch) + { + case ETM_ARCH_V3_3: + case ETM_ARCH_V3_5: + case PFT_ARCH_V1_0: + case PFT_ARCH_V1_1: + return true; + default: + return false; + } +} + +/**************************************************************************** + * Name: etm_set_default + * + * Description: + * Setup default ETM config. + * + ****************************************************************************/ + +void etm_set_default(struct etm_config_s *config) +{ + int i; + + /* Trace all memory, set according to spec */ + + config->enable_ctrl1 = BIT(24); + config->enable_ctrl2 = 0x0; + config->enable_event = ETM_HARD_WIRE_RES_A; + + /* Disable all other event */ + + config->trigger_event = ETM_DEFAULT_EVENT_VAL; + config->seq_12_event = ETM_DEFAULT_EVENT_VAL; + config->seq_21_event = ETM_DEFAULT_EVENT_VAL; + config->seq_23_event = ETM_DEFAULT_EVENT_VAL; + config->seq_31_event = ETM_DEFAULT_EVENT_VAL; + config->seq_32_event = ETM_DEFAULT_EVENT_VAL; + config->seq_13_event = ETM_DEFAULT_EVENT_VAL; + config->timestamp_event = ETM_DEFAULT_EVENT_VAL; + + for (i = 0; i < ETM_MAX_CNTR; i++) + { + config->cntr_event[i] = ETM_DEFAULT_EVENT_VAL; + config->cntr_rld_event[i] = ETM_DEFAULT_EVENT_VAL; + } + + config->sync_freq = 0x400; +} + +/**************************************************************************** + * Name: etm_hw_enable + ****************************************************************************/ + +static int etm_hw_enable(FAR struct coresight_etm_dev_s *etmdev) +{ + FAR struct etm_config_s *config = &etmdev->cfg; + uint32_t etmcr; + int ret; + int i; + + ret = coresight_claim_device(etmdev->csdev.addr); + if (ret < 0) + { + return ret; + } + + coresight_unlock(etmdev->csdev.addr); + etm_os_unlock(etmdev); + etm_set_pwrup(etmdev); + etm_clr_pwrdwn(etmdev); + etm_set_program(etmdev); + + etmcr = etm_read_reg(etmdev, ETM_CR); + etmcr &= ~ETM3X_SUPPORTED_OPTIONS; + etmcr |= ETM_CR_ETM_EN; + etm_write_reg(etmdev, config->ctrl | etmcr, ETM_CR); + etm_write_reg(etmdev, config->trigger_event, ETM_TRIGGER); + etm_write_reg(etmdev, config->startstop_ctrl, ETM_TSSCR); + etm_write_reg(etmdev, config->enable_event, ETM_TEEVR); + etm_write_reg(etmdev, config->enable_ctrl1, ETM_TECR1); + etm_write_reg(etmdev, config->fifofull_level, ETM_FFLR); + for (i = 0; i < etmdev->nr_addr_cmp; i++) + { + etm_write_reg(etmdev, config->addr_val[i], ETM_ACVR(i)); + etm_write_reg(etmdev, config->addr_acctype[i], ETM_ACTR(i)); + } + + for (i = 0; i < etmdev->nr_cntr; i++) + { + etm_write_reg(etmdev, config->cntr_rld_val[i], ETM_CNTRLDVR(i)); + etm_write_reg(etmdev, config->cntr_event[i], ETM_CNTENR(i)); + etm_write_reg(etmdev, config->cntr_rld_event[i], ETM_CNTRLDEVR(i)); + etm_write_reg(etmdev, config->cntr_val[i], ETM_CNTVR(i)); + } + + etm_write_reg(etmdev, config->seq_12_event, ETM_SQ12EVR); + etm_write_reg(etmdev, config->seq_21_event, ETM_SQ21EVR); + etm_write_reg(etmdev, config->seq_23_event, ETM_SQ23EVR); + etm_write_reg(etmdev, config->seq_31_event, ETM_SQ31EVR); + etm_write_reg(etmdev, config->seq_32_event, ETM_SQ32EVR); + etm_write_reg(etmdev, config->seq_13_event, ETM_SQ13EVR); + etm_write_reg(etmdev, config->seq_curr_state, ETM_SQR); + for (i = 0; i < etmdev->nr_ext_out; i++) + { + etm_write_reg(etmdev, ETM_DEFAULT_EVENT_VAL, ETM_EXTOUTEVR(i)); + } + + for (i = 0; i < etmdev->nr_ctxid_cmp; i++) + { + etm_write_reg(etmdev, config->ctxid_pid[i], ETM_CIDCVR(i)); + } + + etm_write_reg(etmdev, config->ctxid_mask, ETM_CIDCMR); + etm_write_reg(etmdev, config->sync_freq, ETM_SYNCFR); + + /* No external input selected */ + + etm_write_reg(etmdev, 0x0, ETM_EXTINSELR); + etm_write_reg(etmdev, config->timestamp_event, ETM_TSEVR); + + /* No auxiliary control selected */ + + etm_write_reg(etmdev, 0x0, ETM_AUXCR); + + etm_write_reg(etmdev, etmdev->traceid, ETM_TRACEIDR); + + /* No VMID comparator value selected */ + + etm_write_reg(etmdev, 0x0, ETM_VMIDCVR); + + etm_clr_program(etmdev); + coresight_lock(etmdev->csdev.addr); + + return ret; +} + +/**************************************************************************** + * Name: etm_hw_disable + ****************************************************************************/ + +static void etm_hw_disable(FAR struct coresight_etm_dev_s *etmdev) +{ + FAR struct etm_config_s *config = &etmdev->cfg; + int i; + + coresight_unlock(etmdev->csdev.addr); + etm_set_program(etmdev); + + /* Read back sequencer and counters for post trace analysis */ + + config->seq_curr_state = etm_read_reg(etmdev, ETM_SQR) & ETM_SQR_MASK; + for (i = 0; i < etmdev->nr_cntr; i++) + { + config->cntr_val[i] = etm_read_reg(etmdev, ETM_CNTVR(i)); + } + + etm_set_pwrdwn(etmdev); + coresight_lock(etmdev->csdev.addr); + + coresight_disclaim_device(etmdev->csdev.addr); +} + +/**************************************************************************** + * Name: etm_enable + ****************************************************************************/ + +static int etm_enable(FAR struct coresight_dev_s *csdev) +{ + FAR struct coresight_etm_dev_s *etmdev = + (FAR struct coresight_etm_dev_s *)csdev; + int ret = 0; + + if (etmdev->refcnt++ == 0) + { + ret = etm_hw_enable(etmdev); + if (ret < 0) + { + etmdev->refcnt--; + cserr("%s enabled\n", csdev->name); + } + } + + return ret; +} + +/**************************************************************************** + * Name: etm_enable + ****************************************************************************/ + +static void etm_disable(FAR struct coresight_dev_s *csdev) +{ + FAR struct coresight_etm_dev_s *etmdev = + (FAR struct coresight_etm_dev_s *)csdev; + + if (--etmdev->refcnt == 0) + { + etm_hw_disable(etmdev); + csinfo("etm %s disabled\n", csdev->name); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: etm_config + * + * Description: + * Configure the etm device. + * + * Input Parameters: + * etmdev - Pointer to the ETM device to config. + * config - Configuration need to be set to ETM device. + * + * Returned Value: + * Zero on success; a negative value on failure. + * + ****************************************************************************/ + +int etm_config(FAR struct coresight_etm_dev_s *etmdev, + FAR const struct etm_config_s *config) +{ + coresight_unlock(etmdev->csdev.addr); + etm_os_unlock(etmdev); + etm_clr_pwrdwn(etmdev); + etm_set_pwrup(etmdev); + etm_set_program(etmdev); + + memcpy(&etmdev->cfg, config, sizeof(struct etm_config_s)); + + if ((etmdev->cfg.ctrl & ETM_CR_RETURN_STACK) && + !(etm_read_reg(etmdev, ETM_CCER) & ETM_CCER_RETSTACK)) + { + etmdev->cfg.ctrl &= ~ETM_CR_RETURN_STACK; + } + + etm_clr_program(etmdev); + etm_clr_pwrup(etmdev); + etm_set_pwrdwn(etmdev); + coresight_lock(etmdev->csdev.addr); + + return 0; +} + +/**************************************************************************** + * Name: etm_register + * + * Description: + * Register an ETM/PTM devices. + * + * Input Parameters: + * desc - A description of this coresight device. + * + * Returned Value: + * Pointer to an ETM device on success; NULL on failure. + * + ****************************************************************************/ + +FAR struct coresight_etm_dev_s * +etm_register(FAR const struct coresight_desc_s *desc) +{ + FAR struct coresight_etm_dev_s *etmdev; + FAR struct coresight_dev_s *csdev; + int ret; + + etmdev = kmm_zalloc(sizeof(struct coresight_etm_dev_s)); + if (etmdev == NULL) + { + cserr("%s:malloc failed!\n", desc->name); + return NULL; + } + + etmdev->cpu = desc->cpu; + etmdev->csdev.addr = desc->addr; + + etm_init_arch_data(etmdev); + + if (!etm_arch_supported(etmdev->arch)) + { + kmm_free(etmdev); + cserr("%s:current implement version is not supported\n", desc->name); + return NULL; + } + + etmdev->traceid = coresight_get_cpu_trace_id(etmdev->cpu); + etm_set_default(&etmdev->cfg); + + csdev = &etmdev->csdev; + csdev->ops = &g_etm_ops; + ret = coresight_register(csdev, desc); + if (ret < 0) + { + kmm_free(etmdev); + cserr("%s:register failed\n", desc->name); + return NULL; + } + + return etmdev; +} + +/**************************************************************************** + * Name: etm_unregister + * + * Description: + * Unregister an EMT/PTM device. + * + ****************************************************************************/ + +void etm_unregister(FAR struct coresight_etm_dev_s *etmdev) +{ + coresight_unregister(&etmdev->csdev); + kmm_free(etmdev); +} diff --git a/drivers/coresight/coresight_stm.c b/drivers/coresight/coresight_stm.c index 308d02ae08..c64eaf048d 100644 --- a/drivers/coresight/coresight_stm.c +++ b/drivers/coresight/coresight_stm.c @@ -150,8 +150,8 @@ static void stm_hw_disable(FAR struct coresight_stm_dev_s *stmdev) coresight_put32(0x0, stmdev->csdev.addr + STM_HEER); coresight_put32(0x0, stmdev->csdev.addr + STM_HETER); - if (coresight_timeout(stmdev->csdev.addr, STM_TCSR, - STM_TCSR_BUSY, 0) < 0) + if (coresight_timeout(0x0, STM_TCSR_BUSY, + stmdev->csdev.addr + STM_TCSR) < 0) { cserr("timeout waiting for STM stopped\n"); } diff --git a/drivers/coresight/coresight_tpiu.c b/drivers/coresight/coresight_tpiu.c index 6685d2a006..907cfb0958 100644 --- a/drivers/coresight/coresight_tpiu.c +++ b/drivers/coresight/coresight_tpiu.c @@ -107,25 +107,22 @@ static int tpiu_hw_enable(FAR struct coresight_tpiu_dev_s *tpiudev) static void tpiu_hw_disable(FAR struct coresight_tpiu_dev_s *tpiudev) { - uint32_t ffcr; - coresight_unlock(tpiudev->csdev.addr); /* Trigger a formatter stop event. */ - ffcr = coresight_get32(tpiudev->csdev.addr + TPIU_FFCR); - ffcr |= TPIU_FFCR_STOP_FI; - coresight_put32(ffcr, tpiudev->csdev.addr + TPIU_FFCR); - ffcr |= TPIU_FFCR_FON_MAN; - coresight_put32(ffcr, tpiudev->csdev.addr + TPIU_FFCR); - if (coresight_timeout(tpiudev->csdev.addr, TPIU_FFCR, - TPIU_FFCR_FON_MAN, 0) < 0) + coresight_modify32(TPIU_FFCR_STOP_FI, TPIU_FFCR_STOP_FI, + tpiudev->csdev.addr + TPIU_FFCR); + coresight_modify32(TPIU_FFCR_FON_MAN, TPIU_FFCR_FON_MAN, + tpiudev->csdev.addr + TPIU_FFCR); + if (coresight_timeout(0, TPIU_FFCR_FON_MAN, + tpiudev->csdev.addr + TPIU_FFCR) < 0) { cserr("timeout while waiting for completion of Manual Flush\n"); } - if (coresight_timeout(tpiudev->csdev.addr, TPIU_FFSR, - TPIU_FFSR_FT_STOPPED, TPIU_FFSR_FT_STOPPED) < 0) + if (coresight_timeout(TPIU_FFSR_FT_STOPPED, TPIU_FFSR_FT_STOPPED, + tpiudev->csdev.addr + TPIU_FFSR) < 0) { cserr("timeout while waiting for Formatter to Stop\n"); } diff --git a/include/nuttx/coresight/coresight.h b/include/nuttx/coresight/coresight.h index f34fe5449b..178a332304 100644 --- a/include/nuttx/coresight/coresight.h +++ b/include/nuttx/coresight/coresight.h @@ -122,6 +122,10 @@ struct coresight_desc_s enum coresight_dev_type_e type; union coresight_dev_subtype_u subtype; + /* Used in ETM device. */ + + uint8_t cpu; + /* Used in funnel devices. */ int inport_num; diff --git a/include/nuttx/coresight/coresight_etm.h b/include/nuttx/coresight/coresight_etm.h new file mode 100644 index 0000000000..a76d27ddbb --- /dev/null +++ b/include/nuttx/coresight/coresight_etm.h @@ -0,0 +1,139 @@ +/**************************************************************************** + * include/nuttx/coresight/coresight_etm.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_CORESIGHT_CORESIGHT_ETM_H +#define __INCLUDE_NUTTX_CORESIGHT_CORESIGHT_ETM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ETM_MAX_ADDR_CMP 16 +#define ETM_MAX_CNTR 4 +#define ETM_MAX_CTXID_CMP 3 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct etm_config_s +{ + uint32_t ctrl; /* ETMCR */ + uint32_t trigger_event; /* ETMTRIGGER */ + uint32_t startstop_ctrl; /* ETMTSSCR */ + uint32_t enable_event; /* ETMTEEVR */ + uint32_t enable_ctrl1; /* ETMTECR1 */ + uint32_t enable_ctrl2; /* ETMTECR2 */ + uint32_t fifofull_level; /* ETMFFLR */ + uint8_t addr_idx; /* Index for the address comparator selection. */ + uint32_t addr_val[ETM_MAX_ADDR_CMP]; /* Value for address comparator register. */ + uint32_t addr_acctype[ETM_MAX_ADDR_CMP]; /* Access type for address comparator register. */ + uint32_t addr_type[ETM_MAX_ADDR_CMP]; /* Current status of the comparator register. */ + uint8_t cntr_idx; /* Index for the counter register selection */ + uint32_t cntr_rld_val[ETM_MAX_CNTR]; /* Reload value of a counter register. */ + uint32_t cntr_event[ETM_MAX_CNTR]; /* Control for counter enable register. */ + uint32_t cntr_rld_event[ETM_MAX_CNTR]; /* Value for counter reload event register. */ + uint32_t cntr_val[ETM_MAX_CNTR]; /* Counter value register. */ + uint32_t seq_12_event; /* Event causing the transition from 1 to 2 */ + uint32_t seq_21_event; /* Event causing the transition from 2 to 1 */ + uint32_t seq_23_event; /* Event causing the transition from 2 to 3 */ + uint32_t seq_31_event; /* Event causing the transition from 3 to 1 */ + uint32_t seq_32_event; /* Event causing the transition from 3 to 2 */ + uint32_t seq_13_event; /* Event causing the transition from 1 to 3 */ + uint32_t seq_curr_state; /* Current value of the sequencer register. */ + uint8_t ctxid_idx; /* Index for the context ID registers. */ + uint32_t ctxid_pid[ETM_MAX_CTXID_CMP]; /* Value for the context ID to trigger on */ + uint32_t ctxid_mask; /* Mask applicable to all the context IDs. */ + uint32_t sync_freq; /* Synchronisation frequency. */ + uint32_t timestamp_event; /* ETMTSEVR */ +}; + +struct coresight_etm_dev_s +{ + struct coresight_dev_s csdev; + struct etm_config_s cfg; + uint8_t refcnt; + int cpu; /* The cpu this component is affined to */ + int port_size; /* Out port size */ + int traceid; /* Trace id */ + uint8_t arch; /* ETM/PTM version number */ + uint8_t nr_addr_cmp; /* Number of pairs of address comparators */ + uint8_t nr_cntr; /* Number of counters */ + uint8_t nr_ext_inp; /* Number of external input */ + uint8_t nr_ext_out; /* Number of external output */ + uint8_t nr_ctxid_cmp; /* Number of contextID comparators */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: etm_register + * + * Description: + * Register an ETM/PTM devices. + * + * Input Parameters: + * desc - A description of this coresight device. + * + * Returned Value: + * Pointer to an ETM device on success; NULL on failure. + * + ****************************************************************************/ + +FAR struct coresight_etm_dev_s * +etm_register(FAR const struct coresight_desc_s *desc); + +/**************************************************************************** + * Name: etm_unregister + * + * Description: + * Unregister an EMT/PTM device. + * + ****************************************************************************/ + +void etm_unregister(FAR struct coresight_etm_dev_s *etmdev); + +/**************************************************************************** + * Name: etm_config + * + * Description: + * Configure the etm device. + * + * Input Parameters: + * etmdev - Pointer to the ETM device to config. + * config - Configuration need to be set to ETM device. + * + * Returned Value: + * Zero on success; a negative value on failure. + * + ****************************************************************************/ + +int etm_config(FAR struct coresight_etm_dev_s *etmdev, + FAR const struct etm_config_s *config); + +#endif //__INCLUDE_NUTTX_CORESIGHT_CORESIGHT_ETM_H