#ifndef _LINUX_CORESIGHT_H
#define _LINUX_CORESIGHT_H
#include <linux/amba/bus.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/perf_event.h>
#include <linux/sched.h>
#include <linux/platform_device.h>
#define CORESIGHT_PERIPHIDR4 0xfd0
#define CORESIGHT_PERIPHIDR5 0xfd4
#define CORESIGHT_PERIPHIDR6 0xfd8
#define CORESIGHT_PERIPHIDR7 0xfdC
#define CORESIGHT_PERIPHIDR0 0xfe0
#define CORESIGHT_PERIPHIDR1 0xfe4
#define CORESIGHT_PERIPHIDR2 0xfe8
#define CORESIGHT_PERIPHIDR3 0xfeC
#define CORESIGHT_COMPIDR0 0xff0
#define CORESIGHT_COMPIDR1 0xff4
#define CORESIGHT_COMPIDR2 0xff8
#define CORESIGHT_COMPIDR3 0xffC
#define ETM_ARCH_V3_3 0x23
#define ETM_ARCH_V3_5 0x25
#define PFT_ARCH_V1_0 0x30
#define PFT_ARCH_V1_1 0x31
#define CORESIGHT_UNLOCK 0xc5acce55
extern const struct bus_type coresight_bustype;
enum coresight_dev_type {
CORESIGHT_DEV_TYPE_SINK,
CORESIGHT_DEV_TYPE_LINK,
CORESIGHT_DEV_TYPE_LINKSINK,
CORESIGHT_DEV_TYPE_SOURCE,
CORESIGHT_DEV_TYPE_HELPER,
CORESIGHT_DEV_TYPE_MAX
};
enum coresight_dev_subtype_sink {
CORESIGHT_DEV_SUBTYPE_SINK_DUMMY,
CORESIGHT_DEV_SUBTYPE_SINK_PORT,
CORESIGHT_DEV_SUBTYPE_SINK_BUFFER,
CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM,
CORESIGHT_DEV_SUBTYPE_SINK_PERCPU_SYSMEM,
};
enum coresight_dev_subtype_link {
CORESIGHT_DEV_SUBTYPE_LINK_MERG,
CORESIGHT_DEV_SUBTYPE_LINK_SPLIT,
CORESIGHT_DEV_SUBTYPE_LINK_FIFO,
};
enum coresight_dev_subtype_source {
CORESIGHT_DEV_SUBTYPE_SOURCE_PROC,
CORESIGHT_DEV_SUBTYPE_SOURCE_BUS,
CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE,
CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM,
CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS,
};
enum coresight_dev_subtype_helper {
CORESIGHT_DEV_SUBTYPE_HELPER_CATU,
CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI,
CORESIGHT_DEV_SUBTYPE_HELPER_CTCU,
};
union coresight_dev_subtype {
struct {
enum coresight_dev_subtype_sink sink_subtype;
enum coresight_dev_subtype_link link_subtype;
};
enum coresight_dev_subtype_source source_subtype;
enum coresight_dev_subtype_helper helper_subtype;
};
struct coresight_platform_data {
int nr_inconns;
int nr_outconns;
struct coresight_connection **out_conns;
struct coresight_connection **in_conns;
};
struct csdev_access {
bool io_mem;
union {
void __iomem *base;
struct {
u64 (*read)(u32 offset, bool relaxed, bool _64bit);
void (*write)(u64 val, u32 offset, bool relaxed,
bool _64bit);
};
};
};
#define CSDEV_ACCESS_IOMEM(_addr) \
((struct csdev_access) { \
.io_mem = true, \
.base = (_addr), \
})
struct coresight_desc {
enum coresight_dev_type type;
union coresight_dev_subtype subtype;
const struct coresight_ops *ops;
struct coresight_platform_data *pdata;
struct device *dev;
const struct attribute_group **groups;
const char *name;
struct csdev_access access;
};
struct coresight_connection {
int src_port;
int dest_port;
struct fwnode_handle *dest_fwnode;
struct coresight_device *dest_dev;
struct coresight_sysfs_link *link;
struct coresight_device *src_dev;
struct fwnode_handle *filter_src_fwnode;
struct coresight_device *filter_src_dev;
int src_refcnt;
int dest_refcnt;
};
struct coresight_sysfs_link {
struct coresight_device *orig;
const char *orig_name;
struct coresight_device *target;
const char *target_name;
};
#define CORESIGHT_TRACE_IDS_MAX 128
struct coresight_trace_id_map {
DECLARE_BITMAP(used_ids, CORESIGHT_TRACE_IDS_MAX);
atomic_t __percpu *cpu_map;
atomic_t perf_cs_etm_session_active;
raw_spinlock_t lock;
};
struct coresight_device {
struct coresight_platform_data *pdata;
enum coresight_dev_type type;
union coresight_dev_subtype subtype;
const struct coresight_ops *ops;
struct csdev_access access;
struct device dev;
atomic_t mode;
int refcnt;
bool orphan;
bool sysfs_sink_activated;
struct dev_ext_attribute *ea;
struct coresight_device *def_sink;
struct coresight_trace_id_map perf_sink_id_map;
int nr_links;
bool has_conns_grp;
struct list_head feature_csdev_list;
struct list_head config_csdev_list;
raw_spinlock_t cscfg_csdev_lock;
void *active_cscfg_ctxt;
};
struct coresight_dev_list {
int nr_idx;
const char *pfx;
struct fwnode_handle **fwnode_list;
};
#define DEFINE_CORESIGHT_DEVLIST(var, dev_pfx) \
static struct coresight_dev_list (var) = { \
.pfx = dev_pfx, \
.nr_idx = 0, \
.fwnode_list = NULL, \
}
#define to_coresight_device(d) container_of(d, struct coresight_device, dev)
struct coresight_path {
struct list_head path_list;
u8 trace_id;
struct perf_output_handle *handle;
};
enum cs_mode {
CS_MODE_DISABLED,
CS_MODE_SYSFS,
CS_MODE_PERF,
};
#define coresight_ops(csdev) csdev->ops
#define source_ops(csdev) csdev->ops->source_ops
#define sink_ops(csdev) csdev->ops->sink_ops
#define link_ops(csdev) csdev->ops->link_ops
#define helper_ops(csdev) csdev->ops->helper_ops
#define ect_ops(csdev) csdev->ops->ect_ops
#define panic_ops(csdev) csdev->ops->panic_ops
struct coresight_ops_sink {
int (*enable)(struct coresight_device *csdev, enum cs_mode mode,
struct coresight_path *path);
int (*disable)(struct coresight_device *csdev);
void *(*alloc_buffer)(struct coresight_device *csdev,
struct perf_event *event, void **pages,
int nr_pages, bool overwrite);
void (*free_buffer)(void *config);
unsigned long (*update_buffer)(struct coresight_device *csdev,
struct perf_output_handle *handle,
void *sink_config);
};
struct coresight_ops_link {
int (*enable)(struct coresight_device *csdev,
struct coresight_connection *in,
struct coresight_connection *out);
void (*disable)(struct coresight_device *csdev,
struct coresight_connection *in,
struct coresight_connection *out);
};
struct coresight_ops_source {
int (*cpu_id)(struct coresight_device *csdev);
int (*enable)(struct coresight_device *csdev, struct perf_event *event,
enum cs_mode mode, struct coresight_path *path);
void (*disable)(struct coresight_device *csdev,
struct perf_event *event);
int (*resume_perf)(struct coresight_device *csdev);
void (*pause_perf)(struct coresight_device *csdev);
};
struct coresight_ops_helper {
int (*enable)(struct coresight_device *csdev, enum cs_mode mode,
struct coresight_path *path);
int (*disable)(struct coresight_device *csdev,
struct coresight_path *path);
};
struct coresight_ops_panic {
int (*sync)(struct coresight_device *csdev);
};
struct coresight_ops {
int (*trace_id)(struct coresight_device *csdev, enum cs_mode mode,
struct coresight_device *sink);
const struct coresight_ops_sink *sink_ops;
const struct coresight_ops_link *link_ops;
const struct coresight_ops_source *source_ops;
const struct coresight_ops_helper *helper_ops;
const struct coresight_ops_panic *panic_ops;
};
static inline u32 csdev_access_relaxed_read32(struct csdev_access *csa,
u32 offset)
{
if (likely(csa->io_mem))
return readl_relaxed(csa->base + offset);
return csa->read(offset, true, false);
}
#define CORESIGHT_CIDRn(i) (0xFF0 + ((i) * 4))
static inline u32 coresight_get_cid(void __iomem *base)
{
u32 i, cid = 0;
for (i = 0; i < 4; i++)
cid |= readl(base + CORESIGHT_CIDRn(i)) << (i * 8);
return cid;
}
static inline bool is_coresight_device(void __iomem *base)
{
u32 cid = coresight_get_cid(base);
return cid == CORESIGHT_CID;
}
#define CORESIGHT_PIDRn(i) (0xFE0 + ((i) * 4))
static inline u32 coresight_get_pid(struct csdev_access *csa)
{
u32 i, pid = 0;
for (i = 0; i < 4; i++)
pid |= csdev_access_relaxed_read32(csa, CORESIGHT_PIDRn(i)) << (i * 8);
return pid;
}
static inline u64 csdev_access_relaxed_read_pair(struct csdev_access *csa,
u32 lo_offset, u32 hi_offset)
{
if (likely(csa->io_mem)) {
return readl_relaxed(csa->base + lo_offset) |
((u64)readl_relaxed(csa->base + hi_offset) << 32);
}
return csa->read(lo_offset, true, false) | (csa->read(hi_offset, true, false) << 32);
}
static inline void csdev_access_relaxed_write_pair(struct csdev_access *csa, u64 val,
u32 lo_offset, u32 hi_offset)
{
if (likely(csa->io_mem)) {
writel_relaxed((u32)val, csa->base + lo_offset);
writel_relaxed((u32)(val >> 32), csa->base + hi_offset);
} else {
csa->write((u32)val, lo_offset, true, false);
csa->write((u32)(val >> 32), hi_offset, true, false);
}
}
static inline u32 csdev_access_read32(struct csdev_access *csa, u32 offset)
{
if (likely(csa->io_mem))
return readl(csa->base + offset);
return csa->read(offset, false, false);
}
static inline void csdev_access_relaxed_write32(struct csdev_access *csa,
u32 val, u32 offset)
{
if (likely(csa->io_mem))
writel_relaxed(val, csa->base + offset);
else
csa->write(val, offset, true, false);
}
static inline void csdev_access_write32(struct csdev_access *csa, u32 val, u32 offset)
{
if (likely(csa->io_mem))
writel(val, csa->base + offset);
else
csa->write(val, offset, false, false);
}
#ifdef CONFIG_64BIT
static inline u64 csdev_access_relaxed_read64(struct csdev_access *csa,
u32 offset)
{
if (likely(csa->io_mem))
return readq_relaxed(csa->base + offset);
return csa->read(offset, true, true);
}
static inline u64 csdev_access_read64(struct csdev_access *csa, u32 offset)
{
if (likely(csa->io_mem))
return readq(csa->base + offset);
return csa->read(offset, false, true);
}
static inline void csdev_access_relaxed_write64(struct csdev_access *csa,
u64 val, u32 offset)
{
if (likely(csa->io_mem))
writeq_relaxed(val, csa->base + offset);
else
csa->write(val, offset, true, true);
}
static inline void csdev_access_write64(struct csdev_access *csa, u64 val, u32 offset)
{
if (likely(csa->io_mem))
writeq(val, csa->base + offset);
else
csa->write(val, offset, false, true);
}
#else
static inline u64 csdev_access_relaxed_read64(struct csdev_access *csa,
u32 offset)
{
WARN_ON(1);
return 0;
}
static inline u64 csdev_access_read64(struct csdev_access *csa, u32 offset)
{
WARN_ON(1);
return 0;
}
static inline void csdev_access_relaxed_write64(struct csdev_access *csa,
u64 val, u32 offset)
{
WARN_ON(1);
}
static inline void csdev_access_write64(struct csdev_access *csa, u64 val, u32 offset)
{
WARN_ON(1);
}
#endif
static inline bool coresight_is_device_source(struct coresight_device *csdev)
{
return csdev && (csdev->type == CORESIGHT_DEV_TYPE_SOURCE);
}
static inline bool coresight_is_percpu_source(struct coresight_device *csdev)
{
return csdev && coresight_is_device_source(csdev) &&
(csdev->subtype.source_subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_PROC);
}
static inline bool coresight_is_percpu_sink(struct coresight_device *csdev)
{
return csdev && (csdev->type == CORESIGHT_DEV_TYPE_SINK) &&
(csdev->subtype.sink_subtype == CORESIGHT_DEV_SUBTYPE_SINK_PERCPU_SYSMEM);
}
static inline bool coresight_take_mode(struct coresight_device *csdev,
enum cs_mode new_mode)
{
int curr = CS_MODE_DISABLED;
return atomic_try_cmpxchg_acquire(&csdev->mode, &curr, new_mode);
}
static inline enum cs_mode coresight_get_mode(struct coresight_device *csdev)
{
return atomic_read_acquire(&csdev->mode);
}
static inline void coresight_set_mode(struct coresight_device *csdev,
enum cs_mode new_mode)
{
enum cs_mode current_mode = coresight_get_mode(csdev);
WARN(new_mode != CS_MODE_DISABLED && current_mode != CS_MODE_DISABLED &&
current_mode != new_mode, "Device already in use\n");
atomic_set_release(&csdev->mode, new_mode);
}
struct coresight_device *coresight_register(struct coresight_desc *desc);
void coresight_unregister(struct coresight_device *csdev);
int coresight_enable_sysfs(struct coresight_device *csdev);
void coresight_disable_sysfs(struct coresight_device *csdev);
int coresight_timeout(struct csdev_access *csa, u32 offset, int position, int value);
typedef void (*coresight_timeout_cb_t) (struct csdev_access *, u32, int, int);
int coresight_timeout_action(struct csdev_access *csa, u32 offset, int position, int value,
coresight_timeout_cb_t cb);
int coresight_claim_device(struct coresight_device *csdev);
int coresight_claim_device_unlocked(struct coresight_device *csdev);
int coresight_claim_device(struct coresight_device *csdev);
int coresight_claim_device_unlocked(struct coresight_device *csdev);
void coresight_clear_self_claim_tag(struct csdev_access *csa);
void coresight_clear_self_claim_tag_unlocked(struct csdev_access *csa);
void coresight_disclaim_device(struct coresight_device *csdev);
void coresight_disclaim_device_unlocked(struct coresight_device *csdev);
char *coresight_alloc_device_name(struct coresight_dev_list *devs,
struct device *dev);
bool coresight_loses_context_with_cpu(struct device *dev);
u32 coresight_relaxed_read32(struct coresight_device *csdev, u32 offset);
u32 coresight_read32(struct coresight_device *csdev, u32 offset);
void coresight_write32(struct coresight_device *csdev, u32 val, u32 offset);
void coresight_relaxed_write32(struct coresight_device *csdev,
u32 val, u32 offset);
u64 coresight_relaxed_read64(struct coresight_device *csdev, u32 offset);
u64 coresight_read64(struct coresight_device *csdev, u32 offset);
void coresight_relaxed_write64(struct coresight_device *csdev,
u64 val, u32 offset);
void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset);
int coresight_get_cpu(struct device *dev);
int coresight_get_static_trace_id(struct device *dev, u32 *id);
struct coresight_platform_data *coresight_get_platform_data(struct device *dev);
struct coresight_connection *
coresight_add_out_conn(struct device *dev,
struct coresight_platform_data *pdata,
const struct coresight_connection *new_conn);
int coresight_add_in_conn(struct coresight_connection *conn);
struct coresight_device *
coresight_find_input_type(struct coresight_platform_data *pdata,
enum coresight_dev_type type,
union coresight_dev_subtype subtype);
struct coresight_device *
coresight_find_output_type(struct coresight_platform_data *pdata,
enum coresight_dev_type type,
union coresight_dev_subtype subtype);
int coresight_init_driver(const char *drv, struct amba_driver *amba_drv,
struct platform_driver *pdev_drv, struct module *owner);
void coresight_remove_driver(struct amba_driver *amba_drv,
struct platform_driver *pdev_drv);
int coresight_etm_get_trace_id(struct coresight_device *csdev, enum cs_mode mode,
struct coresight_device *sink);
int coresight_get_enable_clocks(struct device *dev, struct clk **pclk,
struct clk **atclk);
#endif