mirror of
https://github.com/torvalds/linux.git
synced 2026-08-01 12:11:59 +02:00
Merge "coresight: Add dual etr sink support"
This commit is contained in:
commit
6056678a5e
|
|
@ -35,6 +35,7 @@ config CORESIGHT_LINK_AND_SINK_TMC
|
|||
tristate "Coresight generic TMC driver"
|
||||
|
||||
depends on CORESIGHT_LINKS_AND_SINKS
|
||||
select CORESIGHT_CSR
|
||||
help
|
||||
This enables support for the Trace Memory Controller driver.
|
||||
Depending on its configuration the device can act as a link (embedded
|
||||
|
|
@ -226,6 +227,14 @@ config CORESIGHT_HWEVENT
|
|||
Hardware Event mux control registers to select hardware events
|
||||
based on user input.
|
||||
|
||||
config CORESIGHT_CSR
|
||||
tristate "CoreSight Slave Register driver"
|
||||
help
|
||||
This driver provides support for CoreSight Slave Register block
|
||||
that hosts miscellaneous configuration registers.
|
||||
Those configuration registers can be used to control, various
|
||||
coresight configurations.
|
||||
|
||||
config CORESIGHT_TRBE
|
||||
tristate "Trace Buffer Extension (TRBE) driver"
|
||||
depends on ARM64 && CORESIGHT_SOURCE_ETM4X
|
||||
|
|
|
|||
|
|
@ -31,3 +31,4 @@ obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
|
|||
obj-$(CONFIG_CORESIGHT_REMOTE_ETM) += coresight-remote-etm.o
|
||||
obj-$(CONFIG_CORESIGHT_TGU) += coresight-tgu.o
|
||||
obj-$(CONFIG_CORESIGHT_HWEVENT) += coresight-hwevent.o
|
||||
obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
|
||||
|
|
|
|||
64
drivers/hwtracing/coresight/coresight-common.h
Normal file
64
drivers/hwtracing/coresight/coresight-common.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _CORESIGHT_COMMON_H
|
||||
#define _CORESIGHT_COMMON_H
|
||||
|
||||
#define BM(lsb, msb) ((BIT(msb) - BIT(lsb)) + BIT(msb))
|
||||
#define BVAL(val, n) ((val & BIT(n)) >> n)
|
||||
|
||||
struct coresight_csr {
|
||||
const char *name;
|
||||
struct list_head link;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_CORESIGHT_CSR)
|
||||
extern void msm_qdss_csr_enable_bam_to_usb(struct coresight_csr *csr);
|
||||
extern void msm_qdss_csr_enable_flush(struct coresight_csr *csr);
|
||||
extern void msm_qdss_csr_disable_bam_to_usb(struct coresight_csr *csr);
|
||||
extern void msm_qdss_csr_disable_flush(struct coresight_csr *csr);
|
||||
extern void msm_qdss_csr_enable_eth(struct coresight_csr *csr);
|
||||
extern void msm_qdss_csr_disable_eth(struct coresight_csr *csr);
|
||||
extern int coresight_csr_hwctrl_set(struct coresight_csr *csr, uint64_t addr,
|
||||
uint32_t val);
|
||||
extern void coresight_csr_set_byte_cntr(struct coresight_csr *csr, int irqctrl_offset,
|
||||
uint32_t count);
|
||||
extern struct coresight_csr *coresight_csr_get(const char *name);
|
||||
extern int coresight_csr_set_etr_atid(struct coresight_csr *csr,
|
||||
uint32_t atid_offset, uint32_t atid, bool enable);
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
extern int of_get_coresight_csr_name(struct device_node *node,
|
||||
const char **csr_name);
|
||||
#else
|
||||
static inline int of_get_coresight_csr_name(struct device_node *node,
|
||||
const char **csr_name){ return -EINVAL; }
|
||||
#endif
|
||||
|
||||
#else
|
||||
static inline void msm_qdss_csr_enable_bam_to_usb(struct coresight_csr *csr) {}
|
||||
static inline void msm_qdss_csr_disable_bam_to_usb(struct coresight_csr *csr) {}
|
||||
static inline void msm_qdss_csr_disable_flush(struct coresight_csr *csr) {}
|
||||
static inline void msm_qdss_csr_enable_eth(struct coresight_csr *csr) {}
|
||||
static inline void msm_qdss_csr_disable_eth(struct coresight_csr *csr) {}
|
||||
static inline int coresight_csr_hwctrl_set(struct coresight_csr *csr,
|
||||
uint64_t addr, uint32_t val) { return -EINVAL; }
|
||||
static inline void coresight_csr_set_byte_cntr(struct coresight_csr *csr, int irqctrl_offset,
|
||||
uint32_t count) {}
|
||||
static inline struct coresight_csr *coresight_csr_get(const char *name)
|
||||
{ return NULL; }
|
||||
static inline int coresight_csr_set_etr_atid(struct coresight_csr *csr,
|
||||
uint32_t atid_offset, uint32_t atid, bool enable)
|
||||
{return -EINVAL; }
|
||||
static inline int of_get_coresight_csr_name(struct device_node *node,
|
||||
const char **csr_name){ return -EINVAL; }
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_CORESIGHT_CTI) && IS_ENABLED(CONFIG_OF)
|
||||
extern struct coresight_cti_data *of_get_coresight_cti_data(
|
||||
struct device *dev, struct device_node *node);
|
||||
#else
|
||||
static inline struct coresight_cti_data *of_get_coresight_cti_data(
|
||||
struct device *dev, struct device_node *node) { return NULL; }
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -22,8 +22,11 @@
|
|||
|
||||
#include "coresight-etm-perf.h"
|
||||
#include "coresight-priv.h"
|
||||
#include "coresight-common.h"
|
||||
#include "coresight-syscfg.h"
|
||||
|
||||
#define MAX_SINK_NAME 20
|
||||
|
||||
static DEFINE_MUTEX(coresight_mutex);
|
||||
static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
|
||||
|
||||
|
|
@ -59,6 +62,8 @@ EXPORT_SYMBOL_GPL(coresight_barrier_pkt);
|
|||
|
||||
static const struct cti_assoc_op *cti_assoc_ops;
|
||||
|
||||
static const struct csr_set_atid_op *csr_set_atid_ops;
|
||||
|
||||
void coresight_set_cti_ops(const struct cti_assoc_op *cti_op)
|
||||
{
|
||||
cti_assoc_ops = cti_op;
|
||||
|
|
@ -83,6 +88,18 @@ struct coresight_device *coresight_get_percpu_sink(int cpu)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_get_percpu_sink);
|
||||
|
||||
void coresight_set_csr_ops(const struct csr_set_atid_op *csr_op)
|
||||
{
|
||||
csr_set_atid_ops = csr_op;
|
||||
}
|
||||
EXPORT_SYMBOL(coresight_set_csr_ops);
|
||||
|
||||
void coresight_remove_csr_ops(void)
|
||||
{
|
||||
csr_set_atid_ops = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(coresight_remove_csr_ops);
|
||||
|
||||
static int coresight_id_match(struct device *dev, void *data)
|
||||
{
|
||||
int trace_id, i_trace_id;
|
||||
|
|
@ -492,6 +509,42 @@ static bool coresight_disable_source(struct coresight_device *csdev)
|
|||
return !csdev->enable;
|
||||
}
|
||||
|
||||
static struct coresight_device *coresight_get_source(struct list_head *path)
|
||||
{
|
||||
struct coresight_device *csdev;
|
||||
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
csdev = list_first_entry(path, struct coresight_node, link)->csdev;
|
||||
if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE)
|
||||
return NULL;
|
||||
|
||||
return csdev;
|
||||
}
|
||||
|
||||
static int coresight_set_csr_atid(struct list_head *path,
|
||||
struct coresight_device *sink_csdev, bool enable)
|
||||
{
|
||||
int atid, ret = 0;
|
||||
struct coresight_device *src_csdev;
|
||||
|
||||
src_csdev = coresight_get_source(path);
|
||||
if (!src_csdev)
|
||||
ret = -EINVAL;
|
||||
|
||||
atid = of_coresight_get_atid(src_csdev);
|
||||
if (atid < 0)
|
||||
ret = -EINVAL;
|
||||
|
||||
if (csr_set_atid_ops)
|
||||
ret = csr_set_atid_ops->set_atid(sink_csdev, atid, enable);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* coresight_disable_path_from : Disable components in the given path beyond
|
||||
* @nd in the list. If @nd is NULL, all the components, except the SOURCE are
|
||||
|
|
@ -523,6 +576,9 @@ static void coresight_disable_path_from(struct list_head *path,
|
|||
|
||||
switch (type) {
|
||||
case CORESIGHT_DEV_TYPE_SINK:
|
||||
if (csdev->type == CORESIGHT_DEV_TYPE_SINK)
|
||||
coresight_set_csr_atid(path, csdev, false);
|
||||
|
||||
coresight_disable_sink(csdev);
|
||||
break;
|
||||
case CORESIGHT_DEV_TYPE_SOURCE:
|
||||
|
|
@ -584,6 +640,13 @@ int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data)
|
|||
*/
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (csdev->type == CORESIGHT_DEV_TYPE_SINK) {
|
||||
ret = coresight_set_csr_atid(path, csdev, true);
|
||||
if (ret)
|
||||
dev_dbg(&csdev->dev, "Set csr atid register fail%s\n");
|
||||
}
|
||||
|
||||
break;
|
||||
case CORESIGHT_DEV_TYPE_SOURCE:
|
||||
/* sources are enabled from either sysFS or Perf */
|
||||
|
|
@ -678,6 +741,52 @@ coresight_get_enabled_sink(struct coresight_device *source)
|
|||
return coresight_find_enabled_sink(source);
|
||||
}
|
||||
|
||||
static int coresight_enabled_sink(struct device *dev, const void *data)
|
||||
{
|
||||
const bool *reset = data;
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
|
||||
csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
|
||||
csdev->activated) {
|
||||
/*
|
||||
* Now that we have a handle on the sink for this session,
|
||||
* disable the sysFS "enable_sink" flag so that possible
|
||||
* concurrent perf session that wish to use another sink don't
|
||||
* trip on it. Doing so has no ramification for the current
|
||||
* session.
|
||||
*/
|
||||
if (*reset)
|
||||
csdev->activated = false;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* coresight_get_enabled_sink_from_bus - returns the first enabled sink found on the bus
|
||||
* @deactivate: Whether the 'enable_sink' flag should be reset
|
||||
*
|
||||
* When operated from perf the deactivate parameter should be set to 'true'.
|
||||
* That way the "enabled_sink" flag of the sink that was selected can be reset,
|
||||
* allowing for other concurrent perf sessions to choose a different sink.
|
||||
*
|
||||
* When operated from sysFS users have full control and as such the deactivate
|
||||
* parameter should be set to 'false', hence mandating users to explicitly
|
||||
* clear the flag.
|
||||
*/
|
||||
static struct coresight_device *coresight_get_enabled_sink_from_bus(bool deactivate)
|
||||
{
|
||||
struct device *dev = NULL;
|
||||
|
||||
dev = bus_find_device(&coresight_bustype, NULL, &deactivate,
|
||||
coresight_enabled_sink);
|
||||
|
||||
return dev ? to_coresight_device(dev) : NULL;
|
||||
}
|
||||
|
||||
static int coresight_sink_by_id(struct device *dev, const void *data)
|
||||
{
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
|
@ -1157,7 +1266,12 @@ int coresight_enable(struct coresight_device *csdev)
|
|||
goto out;
|
||||
}
|
||||
|
||||
sink = coresight_get_enabled_sink(csdev);
|
||||
if (csdev->def_sink) {
|
||||
sink = csdev->def_sink;
|
||||
sink->activated = true;
|
||||
} else
|
||||
sink = coresight_get_enabled_sink(csdev);
|
||||
|
||||
if (!sink) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
|
@ -1250,15 +1364,22 @@ static ssize_t enable_sink_store(struct device *dev,
|
|||
{
|
||||
int ret;
|
||||
unsigned long val;
|
||||
struct coresight_device *sink;
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val)
|
||||
if (val) {
|
||||
sink = coresight_get_enabled_sink_from_bus(false);
|
||||
if (sink && sink->type != csdev->type) {
|
||||
dev_err(&csdev->dev,
|
||||
"Another type sink is enabled.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
csdev->activated = true;
|
||||
else
|
||||
} else
|
||||
csdev->activated = false;
|
||||
|
||||
return size;
|
||||
|
|
@ -1298,6 +1419,57 @@ static ssize_t enable_source_store(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR_RW(enable_source);
|
||||
|
||||
static ssize_t sink_name_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
if (csdev->def_sink)
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", dev_name(&csdev->def_sink->dev));
|
||||
else
|
||||
return scnprintf(buf, PAGE_SIZE, "\n");
|
||||
}
|
||||
|
||||
static ssize_t sink_name_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
u32 hash;
|
||||
char *sink_name;
|
||||
struct coresight_device *new_sink, *current_sink;
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
if (size >= MAX_SINK_NAME)
|
||||
return -EINVAL;
|
||||
|
||||
if (size == 0) {
|
||||
csdev->def_sink = NULL;
|
||||
return size;
|
||||
}
|
||||
|
||||
sink_name = kstrdup(buf, GFP_KERNEL);
|
||||
sink_name[size-1] = 0;
|
||||
|
||||
hash = hashlen_hash(hashlen_string(NULL, sink_name));
|
||||
new_sink = coresight_get_sink_by_id(hash);
|
||||
current_sink = coresight_get_enabled_sink_from_bus(false);
|
||||
|
||||
if (!new_sink || (current_sink &&
|
||||
new_sink && current_sink->type !=
|
||||
new_sink->type)) {
|
||||
dev_err(&csdev->dev,
|
||||
"Sink name is invalid or another type sink is enabled.\n");
|
||||
kfree(sink_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
csdev->def_sink = new_sink;
|
||||
kfree(sink_name);
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(sink_name);
|
||||
|
||||
static struct attribute *coresight_sink_attrs[] = {
|
||||
&dev_attr_enable_sink.attr,
|
||||
NULL,
|
||||
|
|
@ -1306,6 +1478,7 @@ ATTRIBUTE_GROUPS(coresight_sink);
|
|||
|
||||
static struct attribute *coresight_source_attrs[] = {
|
||||
&dev_attr_enable_source.attr,
|
||||
&dev_attr_sink_name.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(coresight_source);
|
||||
|
|
|
|||
817
drivers/hwtracing/coresight/coresight-csr.c
Normal file
817
drivers/hwtracing/coresight/coresight-csr.c
Normal file
|
|
@ -0,0 +1,817 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2012-2013, 2015-2017, 2019-2021 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/coresight.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "coresight-priv.h"
|
||||
#include "coresight-common.h"
|
||||
|
||||
#define csr_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off)
|
||||
#define csr_readl(drvdata, off) __raw_readl(drvdata->base + off)
|
||||
|
||||
#define CSR_LOCK(drvdata) \
|
||||
do { \
|
||||
mb(); /* ensure configuration take effect before we lock it */ \
|
||||
csr_writel(drvdata, 0x0, CORESIGHT_LAR); \
|
||||
} while (0)
|
||||
#define CSR_UNLOCK(drvdata) \
|
||||
do { \
|
||||
csr_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \
|
||||
mb(); /* ensure unlock take effect before we configure */ \
|
||||
} while (0)
|
||||
|
||||
#define CSR_SWDBGPWRCTRL (0x000)
|
||||
#define CSR_SWDBGPWRACK (0x004)
|
||||
#define CSR_SWSPADREG0 (0x008)
|
||||
#define CSR_SWSPADREG1 (0x00C)
|
||||
#define CSR_STMTRANSCTRL (0x010)
|
||||
#define CSR_STMAWIDCTRL (0x014)
|
||||
#define CSR_STMCHNOFST0 (0x018)
|
||||
#define CSR_STMCHNOFST1 (0x01C)
|
||||
#define CSR_STMEXTHWCTRL0 (0x020)
|
||||
#define CSR_STMEXTHWCTRL1 (0x024)
|
||||
#define CSR_STMEXTHWCTRL2 (0x028)
|
||||
#define CSR_STMEXTHWCTRL3 (0x02C)
|
||||
#define CSR_USBBAMCTRL (0x030)
|
||||
#define CSR_USBFLSHCTRL (0x034)
|
||||
#define CSR_TIMESTAMPCTRL (0x038)
|
||||
#define CSR_AOTIMEVAL0 (0x03C)
|
||||
#define CSR_AOTIMEVAL1 (0x040)
|
||||
#define CSR_QDSSTIMEVAL0 (0x044)
|
||||
#define CSR_QDSSTIMEVAL1 (0x048)
|
||||
#define CSR_QDSSTIMELOAD0 (0x04C)
|
||||
#define CSR_QDSSTIMELOAD1 (0x050)
|
||||
#define CSR_DAPMSAVAL (0x054)
|
||||
#define CSR_QDSSCLKVOTE (0x058)
|
||||
#define CSR_QDSSCLKIPI (0x05C)
|
||||
#define CSR_QDSSPWRREQIGNORE (0x060)
|
||||
#define CSR_QDSSSPARE (0x064)
|
||||
#define CSR_IPCAT (0x068)
|
||||
#define CSR_BYTECNTVAL (0x06C)
|
||||
#define CSR_ARADDR_EXT (0x130)
|
||||
#define CSR_AWADDR_EXT (0x134)
|
||||
#define MSR_NUM ((drvdata->msr_end - drvdata->msr_start + 1) \
|
||||
/ sizeof(uint32_t))
|
||||
#define MSR_MAX_NUM 128
|
||||
|
||||
#define BLKSIZE_256 0
|
||||
#define BLKSIZE_512 1
|
||||
#define BLKSIZE_1024 2
|
||||
#define BLKSIZE_2048 3
|
||||
|
||||
#define FLUSHPERIOD_1 0x1
|
||||
#define FLUSHPERIOD_2048 0x800
|
||||
#define PERFLSHEOT_BIT BIT(18)
|
||||
|
||||
#define CSR_ATID_REG_OFFSET(atid, atid_offset) \
|
||||
((atid / 32) * 4 + atid_offset)
|
||||
|
||||
#define CSR_ATID_REG_BIT(atid) (atid % 32)
|
||||
#define CSR_MAX_ATID 128
|
||||
#define CSR_ATID_REG_SIZE 0xc
|
||||
|
||||
#define CSR_ARADDR_EXT_VAL 0x104
|
||||
#define CSR_AWADDR_EXT_VAL 0x104
|
||||
|
||||
#define CSR_ATID_REG_OFFSET(atid, atid_offset) \
|
||||
((atid / 32) * 4 + atid_offset)
|
||||
|
||||
#define CSR_ATID_REG_BIT(atid) (atid % 32)
|
||||
#define CSR_MAX_ATID 128
|
||||
#define CSR_ATID_REG_SIZE 0xc
|
||||
|
||||
struct csr_drvdata {
|
||||
void __iomem *base;
|
||||
phys_addr_t pbase;
|
||||
phys_addr_t msr_start;
|
||||
phys_addr_t msr_end;
|
||||
struct device *dev;
|
||||
struct coresight_device *csdev;
|
||||
uint32_t *msr;
|
||||
atomic_t *msr_refcnt;
|
||||
uint32_t blksize;
|
||||
uint32_t flushperiod;
|
||||
struct coresight_csr csr;
|
||||
struct clk *clk;
|
||||
spinlock_t spin_lock;
|
||||
bool usb_bam_support;
|
||||
bool perflsheot_set_support;
|
||||
bool hwctrl_set_support;
|
||||
bool set_byte_cntr_support;
|
||||
bool timestamp_support;
|
||||
bool enable_flush;
|
||||
bool msr_support;
|
||||
};
|
||||
|
||||
DEFINE_CORESIGHT_DEVLIST(csr_devs, "csr");
|
||||
|
||||
static LIST_HEAD(csr_list);
|
||||
static DEFINE_MUTEX(csr_lock);
|
||||
|
||||
#define to_csr_drvdata(c) container_of(c, struct csr_drvdata, csr)
|
||||
|
||||
static void msm_qdss_csr_config_flush_period(struct csr_drvdata *drvdata)
|
||||
{
|
||||
uint32_t usbflshctrl;
|
||||
|
||||
CSR_UNLOCK(drvdata);
|
||||
|
||||
usbflshctrl = csr_readl(drvdata, CSR_USBFLSHCTRL);
|
||||
usbflshctrl = (usbflshctrl & ~0x3FFFC) | (drvdata->flushperiod << 2);
|
||||
csr_writel(drvdata, usbflshctrl, CSR_USBFLSHCTRL);
|
||||
|
||||
CSR_LOCK(drvdata);
|
||||
}
|
||||
|
||||
void msm_qdss_csr_enable_bam_to_usb(struct coresight_csr *csr)
|
||||
{
|
||||
struct csr_drvdata *drvdata;
|
||||
uint32_t usbbamctrl;
|
||||
unsigned long flags;
|
||||
|
||||
if (csr == NULL)
|
||||
return;
|
||||
|
||||
drvdata = to_csr_drvdata(csr);
|
||||
if (IS_ERR_OR_NULL(drvdata) || !drvdata->usb_bam_support)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spin_lock, flags);
|
||||
CSR_UNLOCK(drvdata);
|
||||
|
||||
usbbamctrl = csr_readl(drvdata, CSR_USBBAMCTRL);
|
||||
usbbamctrl = (usbbamctrl & ~0x3) | drvdata->blksize;
|
||||
csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
|
||||
|
||||
usbbamctrl |= 0x4;
|
||||
csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
|
||||
|
||||
CSR_LOCK(drvdata);
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(msm_qdss_csr_enable_bam_to_usb);
|
||||
|
||||
void msm_qdss_csr_enable_flush(struct coresight_csr *csr)
|
||||
{
|
||||
struct csr_drvdata *drvdata;
|
||||
uint32_t usbflshctrl;
|
||||
unsigned long flags;
|
||||
|
||||
if (csr == NULL)
|
||||
return;
|
||||
|
||||
drvdata = to_csr_drvdata(csr);
|
||||
if (IS_ERR_OR_NULL(drvdata) || !drvdata->usb_bam_support)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spin_lock, flags);
|
||||
|
||||
msm_qdss_csr_config_flush_period(drvdata);
|
||||
|
||||
CSR_UNLOCK(drvdata);
|
||||
|
||||
usbflshctrl = csr_readl(drvdata, CSR_USBFLSHCTRL);
|
||||
usbflshctrl |= 0x2;
|
||||
if (drvdata->perflsheot_set_support)
|
||||
usbflshctrl |= PERFLSHEOT_BIT;
|
||||
csr_writel(drvdata, usbflshctrl, CSR_USBFLSHCTRL);
|
||||
|
||||
CSR_LOCK(drvdata);
|
||||
drvdata->enable_flush = true;
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(msm_qdss_csr_enable_flush);
|
||||
|
||||
|
||||
void msm_qdss_csr_disable_bam_to_usb(struct coresight_csr *csr)
|
||||
{
|
||||
struct csr_drvdata *drvdata;
|
||||
uint32_t usbbamctrl;
|
||||
unsigned long flags;
|
||||
|
||||
if (csr == NULL)
|
||||
return;
|
||||
|
||||
drvdata = to_csr_drvdata(csr);
|
||||
if (IS_ERR_OR_NULL(drvdata) || !drvdata->usb_bam_support)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spin_lock, flags);
|
||||
CSR_UNLOCK(drvdata);
|
||||
|
||||
usbbamctrl = csr_readl(drvdata, CSR_USBBAMCTRL);
|
||||
usbbamctrl &= (~0x4);
|
||||
csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
|
||||
|
||||
CSR_LOCK(drvdata);
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(msm_qdss_csr_disable_bam_to_usb);
|
||||
|
||||
void msm_qdss_csr_disable_flush(struct coresight_csr *csr)
|
||||
{
|
||||
struct csr_drvdata *drvdata;
|
||||
uint32_t usbflshctrl;
|
||||
unsigned long flags;
|
||||
|
||||
if (csr == NULL)
|
||||
return;
|
||||
|
||||
drvdata = to_csr_drvdata(csr);
|
||||
if (IS_ERR_OR_NULL(drvdata) || !drvdata->usb_bam_support)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spin_lock, flags);
|
||||
CSR_UNLOCK(drvdata);
|
||||
|
||||
usbflshctrl = csr_readl(drvdata, CSR_USBFLSHCTRL);
|
||||
usbflshctrl &= ~0x2;
|
||||
if (drvdata->perflsheot_set_support)
|
||||
usbflshctrl &= ~PERFLSHEOT_BIT;
|
||||
csr_writel(drvdata, usbflshctrl, CSR_USBFLSHCTRL);
|
||||
|
||||
CSR_LOCK(drvdata);
|
||||
drvdata->enable_flush = false;
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(msm_qdss_csr_disable_flush);
|
||||
|
||||
void msm_qdss_csr_enable_eth(struct coresight_csr *csr)
|
||||
{
|
||||
struct csr_drvdata *drvdata;
|
||||
unsigned long flags;
|
||||
|
||||
if (csr == NULL)
|
||||
return;
|
||||
|
||||
drvdata = to_csr_drvdata(csr);
|
||||
if (IS_ERR_OR_NULL(drvdata))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spin_lock, flags);
|
||||
CSR_UNLOCK(drvdata);
|
||||
csr_writel(drvdata, CSR_ARADDR_EXT_VAL, CSR_ARADDR_EXT);
|
||||
csr_writel(drvdata, CSR_AWADDR_EXT_VAL, CSR_AWADDR_EXT);
|
||||
CSR_LOCK(drvdata);
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(msm_qdss_csr_enable_eth);
|
||||
|
||||
void msm_qdss_csr_disable_eth(struct coresight_csr *csr)
|
||||
{
|
||||
struct csr_drvdata *drvdata;
|
||||
unsigned long flags;
|
||||
|
||||
if (csr == NULL)
|
||||
return;
|
||||
|
||||
drvdata = to_csr_drvdata(csr);
|
||||
if (IS_ERR_OR_NULL(drvdata))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spin_lock, flags);
|
||||
CSR_UNLOCK(drvdata);
|
||||
csr_writel(drvdata, 0, CSR_ARADDR_EXT);
|
||||
csr_writel(drvdata, 0, CSR_AWADDR_EXT);
|
||||
CSR_LOCK(drvdata);
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(msm_qdss_csr_disable_eth);
|
||||
|
||||
int coresight_csr_hwctrl_set(struct coresight_csr *csr, uint64_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
struct csr_drvdata *drvdata;
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (csr == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
drvdata = to_csr_drvdata(csr);
|
||||
if (IS_ERR_OR_NULL(drvdata) || !drvdata->hwctrl_set_support)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spin_lock, flags);
|
||||
CSR_UNLOCK(drvdata);
|
||||
|
||||
if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL0))
|
||||
csr_writel(drvdata, val, CSR_STMEXTHWCTRL0);
|
||||
else if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL1))
|
||||
csr_writel(drvdata, val, CSR_STMEXTHWCTRL1);
|
||||
else if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL2))
|
||||
csr_writel(drvdata, val, CSR_STMEXTHWCTRL2);
|
||||
else if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL3))
|
||||
csr_writel(drvdata, val, CSR_STMEXTHWCTRL3);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
CSR_LOCK(drvdata);
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(coresight_csr_hwctrl_set);
|
||||
|
||||
void coresight_csr_set_byte_cntr(struct coresight_csr *csr, int irqctrl_offset, uint32_t count)
|
||||
{
|
||||
struct csr_drvdata *drvdata;
|
||||
unsigned long flags;
|
||||
|
||||
if (csr == NULL)
|
||||
return;
|
||||
|
||||
drvdata = to_csr_drvdata(csr);
|
||||
if (IS_ERR_OR_NULL(drvdata) || !drvdata->set_byte_cntr_support)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spin_lock, flags);
|
||||
CSR_UNLOCK(drvdata);
|
||||
|
||||
csr_writel(drvdata, count, irqctrl_offset);
|
||||
|
||||
/* make sure byte count value is written */
|
||||
mb();
|
||||
|
||||
CSR_LOCK(drvdata);
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(coresight_csr_set_byte_cntr);
|
||||
|
||||
int coresight_csr_set_etr_atid(struct coresight_csr *csr,
|
||||
uint32_t atid_offset, uint32_t atid,
|
||||
bool enable)
|
||||
{
|
||||
struct csr_drvdata *drvdata;
|
||||
unsigned long flags;
|
||||
uint32_t reg_offset;
|
||||
int bit;
|
||||
uint32_t val;
|
||||
|
||||
if (csr == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
drvdata = to_csr_drvdata(csr);
|
||||
if (IS_ERR_OR_NULL(drvdata))
|
||||
return -EINVAL;
|
||||
|
||||
if (atid < 0 || atid_offset <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spin_lock, flags);
|
||||
CSR_UNLOCK(drvdata);
|
||||
|
||||
reg_offset = CSR_ATID_REG_OFFSET(atid, atid_offset);
|
||||
bit = CSR_ATID_REG_BIT(atid);
|
||||
if (reg_offset - atid_offset > CSR_ATID_REG_SIZE
|
||||
|| bit >= CSR_MAX_ATID) {
|
||||
CSR_LOCK(drvdata);
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val = csr_readl(drvdata, reg_offset);
|
||||
if (enable)
|
||||
val = val | BIT(bit);
|
||||
else
|
||||
val = val & ~BIT(bit);
|
||||
csr_writel(drvdata, val, reg_offset);
|
||||
|
||||
CSR_LOCK(drvdata);
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(coresight_csr_set_etr_atid);
|
||||
|
||||
struct coresight_csr *coresight_csr_get(const char *name)
|
||||
{
|
||||
struct coresight_csr *csr;
|
||||
|
||||
mutex_lock(&csr_lock);
|
||||
list_for_each_entry(csr, &csr_list, link) {
|
||||
if (!strcmp(csr->name, name)) {
|
||||
mutex_unlock(&csr_lock);
|
||||
return csr;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&csr_lock);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
EXPORT_SYMBOL(coresight_csr_get);
|
||||
|
||||
int of_get_coresight_csr_name(struct device_node *node, const char **csr_name)
|
||||
{
|
||||
int ret;
|
||||
struct device_node *csr_node;
|
||||
|
||||
csr_node = of_parse_phandle(node, "coresight-csr", 0);
|
||||
if (!csr_node)
|
||||
return -EINVAL;
|
||||
|
||||
ret = of_property_read_string(csr_node, "coresight-name", csr_name);
|
||||
of_node_put(csr_node);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(of_get_coresight_csr_name);
|
||||
|
||||
static ssize_t timestamp_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ssize_t size = 0;
|
||||
uint64_t time_tick = 0;
|
||||
uint32_t val, time_val0, time_val1;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
struct csr_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
if (IS_ERR_OR_NULL(drvdata) || !drvdata->timestamp_support) {
|
||||
dev_err(dev, "Invalid param\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(drvdata->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spin_lock, flags);
|
||||
CSR_UNLOCK(drvdata);
|
||||
|
||||
val = csr_readl(drvdata, CSR_TIMESTAMPCTRL);
|
||||
|
||||
val = val & ~BIT(0);
|
||||
csr_writel(drvdata, val, CSR_TIMESTAMPCTRL);
|
||||
|
||||
val = val | BIT(0);
|
||||
csr_writel(drvdata, val, CSR_TIMESTAMPCTRL);
|
||||
|
||||
time_val0 = csr_readl(drvdata, CSR_QDSSTIMEVAL0);
|
||||
time_val1 = csr_readl(drvdata, CSR_QDSSTIMEVAL1);
|
||||
|
||||
CSR_LOCK(drvdata);
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
|
||||
clk_disable_unprepare(drvdata->clk);
|
||||
|
||||
time_tick |= (uint64_t)time_val1 << 32;
|
||||
time_tick |= (uint64_t)time_val0;
|
||||
size = scnprintf(buf, PAGE_SIZE, "%llu\n", time_tick);
|
||||
dev_dbg(dev, "timestamp : %s\n", buf);
|
||||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(timestamp);
|
||||
|
||||
static ssize_t msr_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int i;
|
||||
ssize_t len = 0;
|
||||
struct csr_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
if (IS_ERR_OR_NULL(drvdata) || !drvdata->msr_support ||
|
||||
IS_ERR_OR_NULL(drvdata->msr))
|
||||
return -EINVAL;
|
||||
for (i = 0; i < MSR_NUM; i++)
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%d 0x%x\n",
|
||||
i, drvdata->msr[i]);
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t msr_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
uint32_t offset, val, rval;
|
||||
int nval, ret;
|
||||
unsigned long flags;
|
||||
struct csr_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
if (IS_ERR_OR_NULL(drvdata) || !drvdata->msr_support ||
|
||||
IS_ERR_OR_NULL(drvdata->msr))
|
||||
return -EINVAL;
|
||||
|
||||
nval = sscanf(buf, "%x %x", &offset, &val);
|
||||
if (nval != 2)
|
||||
return -EINVAL;
|
||||
if (offset >= MSR_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
if (atomic_read(drvdata->msr_refcnt) == 0) {
|
||||
ret = clk_prepare_enable(drvdata->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
atomic_inc(drvdata->msr_refcnt);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&drvdata->spin_lock, flags);
|
||||
CSR_UNLOCK(drvdata);
|
||||
csr_writel(drvdata, val, drvdata->msr_start + offset * 4);
|
||||
rval = csr_readl(drvdata, drvdata->msr_start + offset * 4);
|
||||
drvdata->msr[offset] = rval;
|
||||
CSR_LOCK(drvdata);
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(msr);
|
||||
|
||||
static ssize_t msr_reset_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
unsigned long flags, val;
|
||||
int i;
|
||||
struct csr_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
if (IS_ERR_OR_NULL(drvdata) || !drvdata->msr_support ||
|
||||
IS_ERR_OR_NULL(drvdata->msr))
|
||||
return -EINVAL;
|
||||
|
||||
if (kstrtoul(buf, 0, &val) || val != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (atomic_read(drvdata->msr_refcnt) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
atomic_set(drvdata->msr_refcnt, 0);
|
||||
spin_lock_irqsave(&drvdata->spin_lock, flags);
|
||||
CSR_UNLOCK(drvdata);
|
||||
for (i = 0; i < MSR_NUM; i++) {
|
||||
csr_writel(drvdata, 0, drvdata->msr_start + i * 4);
|
||||
drvdata->msr[i] = 0;
|
||||
}
|
||||
CSR_LOCK(drvdata);
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
clk_disable_unprepare(drvdata->clk);
|
||||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_WO(msr_reset);
|
||||
|
||||
static ssize_t flushperiod_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct csr_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
if (IS_ERR_OR_NULL(drvdata) || !drvdata->usb_bam_support) {
|
||||
dev_err(dev, "Invalid param\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%#lx\n", drvdata->flushperiod);
|
||||
}
|
||||
|
||||
static ssize_t flushperiod_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long val;
|
||||
struct csr_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
if (IS_ERR_OR_NULL(drvdata) || !drvdata->usb_bam_support) {
|
||||
dev_err(dev, "Invalid param\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&drvdata->spin_lock, flags);
|
||||
|
||||
if (kstrtoul(buf, 0, &val) || val > 0xffff) {
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (drvdata->flushperiod == val)
|
||||
goto out;
|
||||
|
||||
drvdata->flushperiod = val;
|
||||
|
||||
if (drvdata->enable_flush)
|
||||
msm_qdss_csr_config_flush_period(drvdata);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&drvdata->spin_lock, flags);
|
||||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(flushperiod);
|
||||
|
||||
static struct attribute *swao_csr_attrs[] = {
|
||||
&dev_attr_timestamp.attr,
|
||||
&dev_attr_msr.attr,
|
||||
&dev_attr_msr_reset.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group swao_csr_attr_grp = {
|
||||
.attrs = swao_csr_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *swao_csr_attr_grps[] = {
|
||||
&swao_csr_attr_grp,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *csr_attrs[] = {
|
||||
&dev_attr_flushperiod.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group csr_attr_grp = {
|
||||
.attrs = csr_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *csr_attr_grps[] = {
|
||||
&csr_attr_grp,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int csr_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct coresight_platform_data *pdata;
|
||||
struct csr_drvdata *drvdata;
|
||||
struct resource *res, *msr_res;
|
||||
struct coresight_desc desc = { 0 };
|
||||
|
||||
desc.name = coresight_alloc_device_name(&csr_devs, dev);
|
||||
if (!desc.name)
|
||||
return -ENOMEM;
|
||||
pdata = coresight_get_platform_data(dev);
|
||||
if (IS_ERR(pdata))
|
||||
return PTR_ERR(pdata);
|
||||
pdev->dev.platform_data = pdata;
|
||||
|
||||
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
|
||||
if (!drvdata)
|
||||
return -ENOMEM;
|
||||
drvdata->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, drvdata);
|
||||
|
||||
drvdata->clk = devm_clk_get(dev, "apb_pclk");
|
||||
if (IS_ERR(drvdata->clk))
|
||||
dev_dbg(dev, "csr not config clk\n");
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr-base");
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
drvdata->pbase = res->start;
|
||||
|
||||
drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
|
||||
if (!drvdata->base)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "qcom,blk-size",
|
||||
&drvdata->blksize);
|
||||
if (ret)
|
||||
drvdata->blksize = BLKSIZE_256;
|
||||
|
||||
drvdata->usb_bam_support = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,usb-bam-support");
|
||||
if (!drvdata->usb_bam_support)
|
||||
dev_dbg(dev, "usb_bam support handled by other subsystem\n");
|
||||
else
|
||||
dev_dbg(dev, "usb_bam operation supported\n");
|
||||
|
||||
drvdata->hwctrl_set_support = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,hwctrl-set-support");
|
||||
if (!drvdata->hwctrl_set_support)
|
||||
dev_dbg(dev, "hwctrl_set_support handled by other subsystem\n");
|
||||
else
|
||||
dev_dbg(dev, "hwctrl_set_support operation supported\n");
|
||||
|
||||
drvdata->set_byte_cntr_support = of_property_read_bool(
|
||||
pdev->dev.of_node, "qcom,set-byte-cntr-support");
|
||||
if (!drvdata->set_byte_cntr_support)
|
||||
dev_dbg(dev, "set byte_cntr_support handled by other subsystem\n");
|
||||
else
|
||||
dev_dbg(dev, "set_byte_cntr_support operation supported\n");
|
||||
|
||||
drvdata->timestamp_support = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,timestamp-support");
|
||||
if (!drvdata->timestamp_support)
|
||||
dev_dbg(dev, "timestamp_support handled by other subsystem\n");
|
||||
else
|
||||
dev_dbg(dev, "timestamp_support operation supported\n");
|
||||
|
||||
drvdata->perflsheot_set_support = of_property_read_bool(
|
||||
pdev->dev.of_node, "qcom,perflsheot-set-support");
|
||||
if (!drvdata->perflsheot_set_support)
|
||||
dev_dbg(dev, "perflsheot_set_support handled by other subsystem\n");
|
||||
else
|
||||
dev_dbg(dev, "perflsheot_set_support operation supported\n");
|
||||
|
||||
if (drvdata->usb_bam_support)
|
||||
drvdata->flushperiod = FLUSHPERIOD_1;
|
||||
drvdata->msr_support = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,msr-support");
|
||||
if (!drvdata->msr_support) {
|
||||
dev_dbg(dev, "msr_support handled by other subsystem\n");
|
||||
} else {
|
||||
msr_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"msr-base");
|
||||
if (!msr_res || msr_res->start < res->start || msr_res->end
|
||||
> res->end)
|
||||
return -ENODEV;
|
||||
drvdata->msr_start = msr_res->start - res->start;
|
||||
drvdata->msr_end = msr_res->end - res->start;
|
||||
drvdata->msr = devm_kzalloc(dev, MSR_NUM * sizeof(uint32_t),
|
||||
GFP_KERNEL);
|
||||
if (!drvdata->msr)
|
||||
return -ENOMEM;
|
||||
|
||||
drvdata->msr_refcnt = devm_kzalloc(dev, sizeof(atomic_t),
|
||||
GFP_KERNEL);
|
||||
if (!drvdata->msr_refcnt)
|
||||
return -ENOMEM;
|
||||
atomic_set(drvdata->msr_refcnt, 0);
|
||||
dev_dbg(dev, "msr_support operation supported\n");
|
||||
}
|
||||
|
||||
desc.type = CORESIGHT_DEV_TYPE_HELPER;
|
||||
desc.pdata = pdev->dev.platform_data;
|
||||
desc.dev = &pdev->dev;
|
||||
if (drvdata->timestamp_support || drvdata->msr_support)
|
||||
desc.groups = swao_csr_attr_grps;
|
||||
else if (drvdata->usb_bam_support)
|
||||
desc.groups = csr_attr_grps;
|
||||
|
||||
drvdata->csdev = coresight_register(&desc);
|
||||
if (IS_ERR(drvdata->csdev))
|
||||
return PTR_ERR(drvdata->csdev);
|
||||
|
||||
/* Store the driver data pointer for use in exported functions */
|
||||
spin_lock_init(&drvdata->spin_lock);
|
||||
drvdata->csr.name = desc.name;
|
||||
|
||||
mutex_lock(&csr_lock);
|
||||
list_add_tail(&drvdata->csr.link, &csr_list);
|
||||
mutex_unlock(&csr_lock);
|
||||
|
||||
dev_info(dev, "CSR initialized: %s\n", drvdata->csr.name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int csr_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct csr_drvdata *drvdata = platform_get_drvdata(pdev);
|
||||
|
||||
mutex_lock(&csr_lock);
|
||||
list_del(&drvdata->csr.link);
|
||||
mutex_unlock(&csr_lock);
|
||||
|
||||
coresight_unregister(drvdata->csdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id csr_match[] = {
|
||||
{.compatible = "qcom,coresight-csr"},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver csr_driver = {
|
||||
.probe = csr_probe,
|
||||
.remove = csr_remove,
|
||||
.driver = {
|
||||
.name = "coresight-csr",
|
||||
.of_match_table = csr_match,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init csr_init(void)
|
||||
{
|
||||
return platform_driver_register(&csr_driver);
|
||||
}
|
||||
module_init(csr_init);
|
||||
|
||||
static void __exit csr_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&csr_driver);
|
||||
}
|
||||
module_exit(csr_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("CoreSight CSR driver");
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2012, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2012, 2021 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
|
|
@ -204,6 +204,16 @@ static int of_coresight_get_cpu(struct device *dev)
|
|||
return cpu;
|
||||
}
|
||||
|
||||
int of_coresight_get_atid(struct coresight_device *csdev)
|
||||
{
|
||||
int atid, ret = 0;
|
||||
|
||||
ret = of_property_read_u32(csdev->dev.parent->of_node, "atid", &atid);
|
||||
if (ret)
|
||||
return ret;
|
||||
return atid;
|
||||
}
|
||||
|
||||
/*
|
||||
* of_coresight_parse_endpoint : Parse the given output endpoint @ep
|
||||
* and fill the connection information in @conn
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2011-2012, 2021 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _CORESIGHT_PRIV_H
|
||||
|
|
@ -183,6 +183,14 @@ struct cti_assoc_op {
|
|||
extern void coresight_set_cti_ops(const struct cti_assoc_op *cti_op);
|
||||
extern void coresight_remove_cti_ops(void);
|
||||
|
||||
struct csr_set_atid_op {
|
||||
int (*set_atid)(struct coresight_device *csdev, u32 atid, bool enable);
|
||||
};
|
||||
|
||||
extern void coresight_set_csr_ops(const struct csr_set_atid_op *csr_op);
|
||||
extern void coresight_remove_csr_ops(void);
|
||||
int of_coresight_get_atid(struct coresight_device *src_dev);
|
||||
|
||||
/*
|
||||
* Macros and inline functions to handle CoreSight UCI data and driver
|
||||
* private data in AMBA ID table entries, and extract data values.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012, 2021 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Description: CoreSight Trace Memory Controller driver
|
||||
*/
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "coresight-priv.h"
|
||||
#include "coresight-tmc.h"
|
||||
#include "coresight-common.h"
|
||||
|
||||
DEFINE_CORESIGHT_DEVLIST(etb_devs, "tmc_etb");
|
||||
DEFINE_CORESIGHT_DEVLIST(etf_devs, "tmc_etf");
|
||||
|
|
@ -491,6 +492,17 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
|
||||
}
|
||||
|
||||
ret = of_get_coresight_csr_name(adev->dev.of_node, &drvdata->csr_name);
|
||||
if (ret)
|
||||
dev_dbg(dev, "No csr data\n");
|
||||
else {
|
||||
drvdata->csr = coresight_csr_get(drvdata->csr_name);
|
||||
if (IS_ERR(drvdata->csr)) {
|
||||
dev_dbg(dev, "failed to get csr, defer probe\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
}
|
||||
|
||||
desc.dev = dev;
|
||||
desc.groups = coresight_tmc_groups;
|
||||
|
||||
|
|
@ -512,6 +524,10 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
idr_init(&drvdata->idr);
|
||||
mutex_init(&drvdata->idr_mutex);
|
||||
dev_list = &etr_devs;
|
||||
|
||||
if (!of_property_read_u32(dev->of_node, "csr-atid-offset",
|
||||
&drvdata->atid_offset))
|
||||
coresight_set_csr_ops(&csr_atid_ops);
|
||||
break;
|
||||
case TMC_CONFIG_TYPE_ETF:
|
||||
desc.type = CORESIGHT_DEV_TYPE_LINKSINK;
|
||||
|
|
@ -589,6 +605,8 @@ static void tmc_remove(struct amba_device *adev)
|
|||
* etb fops in this case, device is there until last file
|
||||
* handler to this device is closed.
|
||||
*/
|
||||
|
||||
coresight_remove_csr_ops();
|
||||
misc_deregister(&drvdata->miscdev);
|
||||
coresight_unregister(drvdata->csdev);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "coresight-etm-perf.h"
|
||||
#include "coresight-priv.h"
|
||||
#include "coresight-tmc.h"
|
||||
#include "coresight-common.h"
|
||||
|
||||
struct etr_flat_buf {
|
||||
struct device *dev;
|
||||
|
|
@ -679,6 +680,18 @@ static ssize_t tmc_etr_get_data_flat_buf(struct etr_buf *etr_buf,
|
|||
return len;
|
||||
}
|
||||
|
||||
static int tmc_etr_set_atid(struct coresight_device *csdev, u32 atid, bool enable)
|
||||
{
|
||||
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
|
||||
return coresight_csr_set_etr_atid(drvdata->csr, drvdata->atid_offset,
|
||||
atid, enable);
|
||||
}
|
||||
|
||||
const struct csr_set_atid_op csr_atid_ops = {
|
||||
.set_atid = tmc_etr_set_atid,
|
||||
};
|
||||
|
||||
static const struct etr_buf_operations etr_flat_buf_ops = {
|
||||
.alloc = tmc_etr_alloc_flat_buf,
|
||||
.free = tmc_etr_free_flat_buf,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/miscdevice.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/refcount.h>
|
||||
#include "coresight-priv.h"
|
||||
|
||||
#define TMC_RSZ 0x004
|
||||
#define TMC_STS 0x00c
|
||||
|
|
@ -211,6 +212,9 @@ struct tmc_drvdata {
|
|||
struct mutex idr_mutex;
|
||||
struct etr_buf *sysfs_buf;
|
||||
struct etr_buf *perf_buf;
|
||||
struct coresight_csr *csr;
|
||||
const char *csr_name;
|
||||
u32 atid_offset;
|
||||
};
|
||||
|
||||
struct etr_buf_operations {
|
||||
|
|
@ -274,6 +278,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata);
|
|||
int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata);
|
||||
void tmc_etr_disable_hw(struct tmc_drvdata *drvdata);
|
||||
extern const struct coresight_ops tmc_etr_cs_ops;
|
||||
extern const struct csr_set_atid_op csr_atid_ops;
|
||||
ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata,
|
||||
loff_t pos, size_t len, char **bufpp);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user