734 lines
22 KiB
C
734 lines
22 KiB
C
|
/****************************************************************************
|
||
|
* 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 <errno.h>
|
||
|
#include <debug.h>
|
||
|
#include <nuttx/bits.h>
|
||
|
#include <nuttx/kmalloc.h>
|
||
|
|
||
|
#include <nuttx/coresight/coresight_etm.h>
|
||
|
|
||
|
#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);
|
||
|
}
|