@@ -18,10 +18,12 @@
#define TRACER_RUNNING_BIT 1
#define TRACER_CYCLE_ACC_BIT 2
#define TRACER_TRACE_DATA_BIT 3
+#define TRACER_TIMESTAMP_BIT 4
#define TRACER_ACCESSED BIT(TRACER_ACCESSED_BIT)
#define TRACER_RUNNING BIT(TRACER_RUNNING_BIT)
#define TRACER_CYCLE_ACC BIT(TRACER_CYCLE_ACC_BIT)
#define TRACER_TRACE_DATA BIT(TRACER_TRACE_DATA_BIT)
+#define TRACER_TIMESTAMP BIT(TRACER_TIMESTAMP_BIT)
#define TRACER_TIMEOUT 10000
@@ -57,6 +59,7 @@
#define ETMCTRL_DATA_DO_BOTH (ETMCTRL_DATA_DO_DATA | ETMCTRL_DATA_DO_ADDR)
#define ETMCTRL_BRANCH_OUTPUT (1 << 8)
#define ETMCTRL_CYCLEACCURATE (1 << 12)
+#define ETMCTRL_TIMESTAMP_EN (1 << 28)
/* ETM configuration code register */
#define ETMR_CONFCODE (0x04)
@@ -129,8 +132,12 @@
#define ETMR_ID 0x1e4
#define ETMIDR_VERSION(x) (((x) >> 4) & 0xff)
+#define ETMIDR_VERSION_3_1 0x21
#define ETMIDR_VERSION_PFT_1_0 0x30
+#define ETMR_CCE 0x1e8
+#define ETMCCER_TIMESTAMPING_IMPLEMENTED BIT(22)
+
#define ETMR_TRACEIDR 0x200
/* ETM management registers, "ETM Architecture", 3.5.24 */
@@ -116,6 +116,9 @@ static int trace_start_etm(struct tracectx *t, int id)
if (t->flags & TRACER_TRACE_DATA)
v |= ETMCTRL_DATA_DO_ADDR;
+ if (t->flags & TRACER_TIMESTAMP)
+ v |= ETMCTRL_TIMESTAMP_EN;
+
etm_unlock(t, id);
etm_writel(t, id, v, ETMR_CTRL);
@@ -647,6 +650,36 @@ static ssize_t trace_mode_store(struct kobject *kobj,
static struct kobj_attribute trace_mode_attr =
__ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
+static ssize_t trace_timestamp_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_TIMESTAMP));
+}
+
+static ssize_t trace_timestamp_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned int timestamp;
+
+ if (sscanf(buf, "%u", ×tamp) != 1)
+ return -EINVAL;
+
+ mutex_lock(&tracer.mutex);
+ if (timestamp)
+ tracer.flags |= TRACER_TIMESTAMP;
+ else
+ tracer.flags &= ~TRACER_TIMESTAMP;
+ mutex_unlock(&tracer.mutex);
+
+ return n;
+}
+
+static struct kobj_attribute trace_timestamp_attr =
+ __ATTR(trace_timestamp, 0644,
+ trace_timestamp_show, trace_timestamp_store);
+
static ssize_t trace_range_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
@@ -726,6 +759,7 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id
int new_count;
u32 etmccr;
u32 etmidr;
+ u32 etmccer = 0;
u8 etm_version = 0;
mutex_lock(&t->mutex);
@@ -766,6 +800,8 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id
if (etmccr & ETMCCR_ETMIDR_PRESENT) {
etmidr = etm_readl(t, t->etm_regs_count, ETMR_ID);
etm_version = ETMIDR_VERSION(etmidr);
+ if (etm_version >= ETMIDR_VERSION_3_1)
+ etmccer = etm_readl(t, t->etm_regs_count, ETMR_CCE);
}
etm_writel(t, t->etm_regs_count, 0x441, ETMR_CTRL);
etm_writel(t, t->etm_regs_count, new_count, ETMR_TRACEIDR);
@@ -785,6 +821,14 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id
if (ret)
dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
+ if (etmccer & ETMCCER_TIMESTAMPING_IMPLEMENTED) {
+ ret = sysfs_create_file(&dev->dev.kobj,
+ &trace_timestamp_attr.attr);
+ if (ret)
+ dev_dbg(&dev->dev,
+ "Failed to create trace_timestamp in sysfs\n");
+ }
+
ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr);
if (ret)
dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n");