313 lines
9.0 KiB
C
313 lines
9.0 KiB
C
/****************************************************************************
|
|
* drivers/coresight/coresight_common.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 <string.h>
|
|
#include <nuttx/spinlock.h>
|
|
#include <nuttx/bits.h>
|
|
#include <nuttx/arch.h>
|
|
|
|
#include "coresight_common.h"
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#define CORESIGHT_UNLOCK 0xc5acce55
|
|
#define CORESIGHT_LOCK 0x0
|
|
|
|
#define CORESIGHT_CLAIM_SELF_HOSTED BIT(1)
|
|
|
|
#define CORESIGHT_SOURCE_BITMAP_SIZE 32
|
|
|
|
#define CORESIGHT_ETM_PMU_SEED 0x10
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
static DECLARE_BITMAP(g_coresight_trace_id_bitmap,
|
|
CORESIGHT_SOURCE_BITMAP_SIZE);
|
|
static spinlock_t g_coresight_trace_id_lock = SP_UNLOCKED;
|
|
|
|
static const uint32_t g_coresight_barrier_pkt[4] =
|
|
{
|
|
0x7fffffff,
|
|
0x7fffffff,
|
|
0x7fffffff,
|
|
0x7fffffff
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: coresight_lock
|
|
*
|
|
* Description:
|
|
* To ensure that the software being debugged can never access an unlocked
|
|
* CoreSight component, a software monitor that accesses debug registers
|
|
* must unlock the component before accessing any registers, and lock the
|
|
* component again before exiting the monitor.
|
|
*
|
|
* Input Parameters:
|
|
* addr - Base addr of the coresight device.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void coresight_lock(uintptr_t addr)
|
|
{
|
|
coresight_put32(CORESIGHT_LOCK, addr + CORESIGHT_LAR);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: coresight_unlock
|
|
****************************************************************************/
|
|
|
|
void coresight_unlock(uintptr_t addr)
|
|
{
|
|
coresight_put32(CORESIGHT_UNLOCK, addr + CORESIGHT_LAR);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: coresight_claim_device
|
|
*
|
|
* Description:
|
|
* Claim the device for self-hosted usage to prevent an external tool from
|
|
* touching this device.Use Protocol 3: Set private bit and check for race.
|
|
*
|
|
* Input Parameters:
|
|
* addr - Base addr of the coresight device.
|
|
*
|
|
* Returned Value:
|
|
* Zero on success; a negative value on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int coresight_claim_device(uintptr_t addr)
|
|
{
|
|
int ret = -EBUSY;
|
|
|
|
coresight_unlock(addr);
|
|
if (coresight_get32(addr + CORESIGHT_CLAIMCLR) != 0)
|
|
{
|
|
goto out;
|
|
}
|
|
|
|
coresight_put32(CORESIGHT_CLAIM_SELF_HOSTED, addr + CORESIGHT_CLAIMSET);
|
|
if (coresight_get32(addr + CORESIGHT_CLAIMCLR) ==
|
|
CORESIGHT_CLAIM_SELF_HOSTED)
|
|
{
|
|
ret = 0;
|
|
}
|
|
else
|
|
{
|
|
/* There was a race setting the tags, clean up and fail */
|
|
|
|
coresight_put32(CORESIGHT_CLAIM_SELF_HOSTED,
|
|
addr + CORESIGHT_CLAIMCLR);
|
|
}
|
|
|
|
out:
|
|
coresight_lock(addr);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: coresight_disclaim_device
|
|
*
|
|
* Description:
|
|
* Disclaim the device, then an external tool can touch the device.
|
|
*
|
|
* Input Parameters:
|
|
* addr - Base addr of the coresight device.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void coresight_disclaim_device(uintptr_t addr)
|
|
{
|
|
coresight_unlock(addr);
|
|
if (coresight_get32(addr + CORESIGHT_CLAIMCLR) ==
|
|
CORESIGHT_CLAIM_SELF_HOSTED)
|
|
{
|
|
coresight_put32(CORESIGHT_CLAIM_SELF_HOSTED,
|
|
addr + CORESIGHT_CLAIMCLR);
|
|
}
|
|
else
|
|
{
|
|
cserr("current device is not claimed or something wrong happend\n");
|
|
}
|
|
|
|
coresight_lock(addr);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: coresight_get_cpu_trace_id
|
|
*
|
|
* Description:
|
|
* Used to get an unique trace id associated with cpu id of an ETM
|
|
* coresight device.
|
|
*
|
|
* Input Parameters:
|
|
* cpu - CPU index to generate an unique trace id.
|
|
*
|
|
* Returned Value:
|
|
* Unique trace id on success; a negative value on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int coresight_get_cpu_trace_id(int cpu)
|
|
{
|
|
int traceid = CORESIGHT_ETM_PMU_SEED + cpu * 2;
|
|
|
|
if (traceid >= CORESIGHT_SOURCE_BITMAP_SIZE)
|
|
{
|
|
cserr("trace id is out of bounds\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return traceid;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: coresight_get_system_trace_id
|
|
*
|
|
* Description:
|
|
* Used to get an unique trace id of a STM coresight device. The trace ID
|
|
* value for *ETM* tracers start at CPU_ID * 2 + 0x10, and Trace ID 0x00
|
|
* and anything equal to or higher than 0x70 is reserved.
|
|
*
|
|
* Returned Value:
|
|
* Unique trace id on success; a negative value on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int coresight_get_system_trace_id(void)
|
|
{
|
|
int max = CORESIGHT_SOURCE_BITMAP_SIZE / 2;
|
|
irqstate_t flags;
|
|
int traceid = 0;
|
|
int i;
|
|
|
|
flags = spin_lock_irqsave(&g_coresight_trace_id_lock);
|
|
for (i = 0; i < max - 1; i++)
|
|
{
|
|
if (test_bit(1 + 2 * i, g_coresight_trace_id_bitmap) == 0)
|
|
{
|
|
traceid = 1 + 2 * i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (traceid == 0)
|
|
{
|
|
cserr("get system trace id failed\n");
|
|
spin_unlock_irqrestore(&g_coresight_trace_id_lock, flags);
|
|
return -EINVAL;
|
|
}
|
|
|
|
__set_bit(traceid, g_coresight_trace_id_bitmap);
|
|
spin_unlock_irqrestore(&g_coresight_trace_id_lock, flags);
|
|
|
|
return traceid;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: coresight_put_system_trace_id
|
|
*
|
|
* Description:
|
|
* Release an allocated system trace ID.
|
|
*
|
|
* Input Parameters:
|
|
* traceid - Traceid to be released.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void coresight_put_system_trace_id(int traceid)
|
|
{
|
|
irqstate_t flags;
|
|
|
|
flags = spin_lock_irqsave(&g_coresight_trace_id_lock);
|
|
__clear_bit(traceid, g_coresight_trace_id_bitmap);
|
|
spin_unlock_irqrestore(&g_coresight_trace_id_lock, flags);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: coresight_timeout
|
|
*
|
|
* Description:
|
|
* Loop until a bitmask of register has changed to a specific value.
|
|
*
|
|
* Input Parameters:
|
|
* addr - Base addr of the coresight device.
|
|
* off - Register offset of the coresight device.
|
|
* bitmask - Bitmask to be checked.
|
|
* val - Value to be matched.
|
|
*
|
|
* Returned Value:
|
|
* Zero on success; a negative value on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
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);
|
|
if ((value & mask) == val)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
up_udelay(1);
|
|
}
|
|
|
|
return -EAGAIN;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: coresight_insert_barrier_packet
|
|
*
|
|
* Description:
|
|
* When losing synchronisation a new barrier packet needs to be inserted at
|
|
* the beginning of the data collected in a buffer. That way the decoder
|
|
* knows that it needs to look for another sync sequence.
|
|
*
|
|
* Input Parameters:
|
|
* buf - buffer that a new barrier packet inserts to.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void coresight_insert_barrier_packet(FAR void *buf)
|
|
{
|
|
if (buf != NULL)
|
|
{
|
|
memcpy(buf, g_coresight_barrier_pkt, sizeof(g_coresight_barrier_pkt));
|
|
}
|
|
}
|