From 9feb08ad76c0dcfd635d96ff50a7e1522e45bfbe Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Thu, 30 Apr 2026 14:48:15 +0800 Subject: [PATCH 01/15] Revert "FROMLIST: coresight-tgu: add reset node to initialize" This reverts commit e6d6870c501390e5151db0d1f91910ffd00500f3. --- .../testing/sysfs-bus-coresight-devices-tgu | 7 -- drivers/hwtracing/coresight/coresight-tgu.c | 75 ------------------- 2 files changed, 82 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu index 4ff5ec9be733e..f0d7db72b61c4 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu @@ -42,10 +42,3 @@ KernelVersion 6.16 Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) Description: (RW) Set/Get the counter value with specific step for TGU. - -What: /sys/bus/coresight/devices//reset_tgu -Date: July 2025 -KernelVersion 6.16 -Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) -Description: - (Write) Write 1 to reset the dataset for TGU. diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c index 35c97f31639e3..303698a9d5ab4 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.c +++ b/drivers/hwtracing/coresight/coresight-tgu.c @@ -473,80 +473,6 @@ static ssize_t enable_tgu_store(struct device *dev, } static DEVICE_ATTR_RW(enable_tgu); -/* reset_tgu_store - Reset Trace and Gating Unit (TGU) configuration. */ -static ssize_t reset_tgu_store(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t size) -{ - unsigned long value; - struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent); - int i, j, ret; - - if (kstrtoul(buf, 0, &value) || value == 0) - return -EINVAL; - - if (!drvdata->enable) { - ret = pm_runtime_get_sync(drvdata->dev); - if (ret < 0) { - pm_runtime_put(drvdata->dev); - return ret; - } - } - - spin_lock(&drvdata->spinlock); - CS_UNLOCK(drvdata->base); - - tgu_writel(drvdata, 0, TGU_CONTROL); - - if (drvdata->value_table->priority) - memset(drvdata->value_table->priority, 0, - MAX_PRIORITY * drvdata->max_step * - drvdata->max_reg * sizeof(unsigned int)); - - if (drvdata->value_table->condition_decode) - memset(drvdata->value_table->condition_decode, 0, - drvdata->max_condition_decode * drvdata->max_step * - sizeof(unsigned int)); - - /* Initialize all condition registers to NOT(value=0x1000000) */ - for (i = 0; i < drvdata->max_step; i++) { - for (j = 0; j < drvdata->max_condition_decode; j++) { - drvdata->value_table - ->condition_decode[calculate_array_location( - drvdata, i, TGU_CONDITION_DECODE, j)] = - 0x1000000; - } - } - - if (drvdata->value_table->condition_select) - memset(drvdata->value_table->condition_select, 0, - drvdata->max_condition_select * drvdata->max_step * - sizeof(unsigned int)); - - if (drvdata->value_table->timer) - memset(drvdata->value_table->timer, 0, - (drvdata->max_step) * - (drvdata->max_timer) * - sizeof(unsigned int)); - - if (drvdata->value_table->counter) - memset(drvdata->value_table->counter, 0, - (drvdata->max_step) * - (drvdata->max_counter) * - sizeof(unsigned int)); - - dev_dbg(dev, "Coresight-TGU reset complete\n"); - - CS_LOCK(drvdata->base); - - drvdata->enable = false; - spin_unlock(&drvdata->spinlock); - pm_runtime_put(drvdata->dev); - - return size; -} -static DEVICE_ATTR_WO(reset_tgu); - static const struct coresight_ops_helper tgu_helper_ops = { .enable = tgu_enable, .disable = tgu_disable, @@ -558,7 +484,6 @@ static const struct coresight_ops tgu_ops = { static struct attribute *tgu_common_attrs[] = { &dev_attr_enable_tgu.attr, - &dev_attr_reset_tgu.attr, NULL, }; From fbd1e1e21b5ab4a60f9c54264ade510b0c48f431 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Thu, 30 Apr 2026 14:48:23 +0800 Subject: [PATCH 02/15] Revert "FROMLIST: coresight-tgu: add timer/counter functionality for TGU" This reverts commit aee7a587b21d6aeab97fe4a6b7e1ee745900b764. --- .../testing/sysfs-bus-coresight-devices-tgu | 14 -- drivers/hwtracing/coresight/coresight-tgu.c | 134 ------------------ drivers/hwtracing/coresight/coresight-tgu.h | 55 +------ 3 files changed, 1 insertion(+), 202 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu index f0d7db72b61c4..5ca91e122500e 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu @@ -28,17 +28,3 @@ KernelVersion 6.16 Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) Description: (RW) Set/Get the next action with specific step for TGU. - -What: /sys/bus/coresight/devices//step[0:7]_timer/reg[0:1] -Date: July 2025 -KernelVersion 6.16 -Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) -Description: - (RW) Set/Get the timer value with specific step for TGU. - -What: /sys/bus/coresight/devices//step[0:7]_counter/reg[0:1] -Date: July 2025 -KernelVersion 6.16 -Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) -Description: - (RW) Set/Get the counter value with specific step for TGU. diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c index 303698a9d5ab4..71436fbdcc3e2 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.c +++ b/drivers/hwtracing/coresight/coresight-tgu.c @@ -39,12 +39,6 @@ static int calculate_array_location(struct tgu_drvdata *drvdata, case TGU_CONDITION_SELECT: ret = step_index * (drvdata->max_condition_select) + reg_index; break; - case TGU_COUNTER: - ret = step_index * (drvdata->max_counter) + reg_index; - break; - case TGU_TIMER: - ret = step_index * (drvdata->max_timer) + reg_index; - break; default: break; } @@ -96,16 +90,6 @@ static ssize_t tgu_dataset_show(struct device *dev, drvdata, tgu_attr->step_index, tgu_attr->operation_index, tgu_attr->reg_num)]); - case TGU_TIMER: - return sysfs_emit(buf, "0x%x\n", - drvdata->value_table->timer[calculate_array_location( - drvdata, tgu_attr->step_index, tgu_attr->operation_index, - tgu_attr->reg_num)]); - case TGU_COUNTER: - return sysfs_emit(buf, "0x%x\n", - drvdata->value_table->counter[calculate_array_location( - drvdata, tgu_attr->step_index, tgu_attr->operation_index, - tgu_attr->reg_num)]); default: break; } @@ -159,18 +143,6 @@ static ssize_t tgu_dataset_store(struct device *dev, tgu_attr->reg_num)] = val; ret = size; break; - case TGU_TIMER: - tgu_drvdata->value_table->timer[calculate_array_location( - tgu_drvdata, tgu_attr->step_index, tgu_attr->operation_index, - tgu_attr->reg_num)] = val; - ret = size; - break; - case TGU_COUNTER: - tgu_drvdata->value_table->counter[calculate_array_location( - tgu_drvdata, tgu_attr->step_index, tgu_attr->operation_index, - tgu_attr->reg_num)] = val; - ret = size; - break; default: break; } @@ -216,24 +188,6 @@ static umode_t tgu_node_visible(struct kobject *kobject, attr->mode : 0; break; - case TGU_COUNTER: - if (drvdata->max_counter == 0) - ret = SYSFS_GROUP_INVISIBLE; - else - ret = (tgu_attr->reg_num < - drvdata->max_counter) ? - attr->mode : - 0; - break; - case TGU_TIMER: - if (drvdata->max_timer == 0) - ret = SYSFS_GROUP_INVISIBLE; - else - ret = (tgu_attr->reg_num < - drvdata->max_timer) ? - attr->mode : - 0; - break; default: break; } @@ -292,34 +246,6 @@ static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) CONDITION_SELECT_STEP(i, j)); } } - - for (i = 0; i < drvdata->max_step; i++) { - for (j = 0; j < drvdata->max_timer; j++) { - ret = check_array_location(drvdata, i, TGU_TIMER, j); - if (ret == -EINVAL) - goto exit; - - tgu_writel(drvdata, - drvdata->value_table->timer - [calculate_array_location(drvdata, i, - TGU_TIMER, j)], - TIMER_COMPARE_STEP(i, j)); - } - } - - for (i = 0; i < drvdata->max_step; i++) { - for (j = 0; j < drvdata->max_counter; j++) { - ret = check_array_location(drvdata, i, TGU_COUNTER, j); - if (ret == -EINVAL) - goto exit; - - tgu_writel(drvdata, - drvdata->value_table->counter - [calculate_array_location(drvdata, i, - TGU_COUNTER, j)], - COUNTER_COMPARE_STEP(i, j)); - } - } /* Enable TGU to program the triggers */ tgu_writel(drvdata, 1, TGU_CONTROL); exit: @@ -368,31 +294,6 @@ static void tgu_set_conditions(struct tgu_drvdata *drvdata) drvdata->max_condition_select = num_conditions + 1; } -static void tgu_set_timer_counter(struct tgu_drvdata *drvdata) -{ - int num_timers, num_counters; - u32 devid2; - - devid2 = readl_relaxed(drvdata->base + CORESIGHT_DEVID2); - - if (TGU_DEVID2_TIMER0(devid2) && TGU_DEVID2_TIMER1(devid2)) - num_timers = 2; - else if (TGU_DEVID2_TIMER0(devid2) || TGU_DEVID2_TIMER1(devid2)) - num_timers = 1; - else - num_timers = 0; - - if (TGU_DEVID2_COUNTER0(devid2) && TGU_DEVID2_COUNTER1(devid2)) - num_counters = 2; - else if (TGU_DEVID2_COUNTER0(devid2) || TGU_DEVID2_COUNTER1(devid2)) - num_counters = 1; - else - num_counters = 0; - - drvdata->max_timer = num_timers; - drvdata->max_counter = num_counters; -} - static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode, void *data) { @@ -542,22 +443,6 @@ static const struct attribute_group *tgu_attr_groups[] = { CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(5), CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(6), CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(7), - TIMER_ATTRIBUTE_GROUP_INIT(0), - TIMER_ATTRIBUTE_GROUP_INIT(1), - TIMER_ATTRIBUTE_GROUP_INIT(2), - TIMER_ATTRIBUTE_GROUP_INIT(3), - TIMER_ATTRIBUTE_GROUP_INIT(4), - TIMER_ATTRIBUTE_GROUP_INIT(5), - TIMER_ATTRIBUTE_GROUP_INIT(6), - TIMER_ATTRIBUTE_GROUP_INIT(7), - COUNTER_ATTRIBUTE_GROUP_INIT(0), - COUNTER_ATTRIBUTE_GROUP_INIT(1), - COUNTER_ATTRIBUTE_GROUP_INIT(2), - COUNTER_ATTRIBUTE_GROUP_INIT(3), - COUNTER_ATTRIBUTE_GROUP_INIT(4), - COUNTER_ATTRIBUTE_GROUP_INIT(5), - COUNTER_ATTRIBUTE_GROUP_INIT(6), - COUNTER_ATTRIBUTE_GROUP_INIT(7), NULL, }; @@ -595,7 +480,6 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) tgu_set_reg_number(drvdata); tgu_set_steps(drvdata); tgu_set_conditions(drvdata); - tgu_set_timer_counter(drvdata); drvdata->value_table = devm_kzalloc(dev, sizeof(*drvdata->value_table), GFP_KERNEL); @@ -629,24 +513,6 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) if (!drvdata->value_table->condition_select) return -ENOMEM; - drvdata->value_table->timer = devm_kzalloc( - dev, - drvdata->max_step * drvdata->max_timer * - sizeof(*(drvdata->value_table->timer)), - GFP_KERNEL); - - if (!drvdata->value_table->timer) - return -ENOMEM; - - drvdata->value_table->counter = devm_kzalloc( - dev, - drvdata->max_step * drvdata->max_counter * - sizeof(*(drvdata->value_table->counter)), - GFP_KERNEL); - - if (!drvdata->value_table->counter) - return -ENOMEM; - drvdata->enable = false; desc.type = CORESIGHT_DEV_TYPE_HELPER; desc.pdata = adev->dev.platform_data; diff --git a/drivers/hwtracing/coresight/coresight-tgu.h b/drivers/hwtracing/coresight/coresight-tgu.h index be9c87ec7e3ce..29f6fcf4d2be8 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.h +++ b/drivers/hwtracing/coresight/coresight-tgu.h @@ -8,7 +8,7 @@ /* Register addresses */ #define TGU_CONTROL 0x0000 -#define CORESIGHT_DEVID2 0xfc0 + /* Register read/write */ #define tgu_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off) #define tgu_readl(drvdata, off) __raw_readl(drvdata->base + off) @@ -16,11 +16,6 @@ #define TGU_DEVID_SENSE_INPUT(devid_val) ((int) BMVAL(devid_val, 10, 17)) #define TGU_DEVID_STEPS(devid_val) ((int)BMVAL(devid_val, 3, 6)) #define TGU_DEVID_CONDITIONS(devid_val) ((int)BMVAL(devid_val, 0, 2)) -#define TGU_DEVID2_TIMER0(devid_val) ((int)BMVAL(devid_val, 18, 23)) -#define TGU_DEVID2_TIMER1(devid_val) ((int)BMVAL(devid_val, 13, 17)) -#define TGU_DEVID2_COUNTER0(devid_val) ((int)BMVAL(devid_val, 6, 11)) -#define TGU_DEVID2_COUNTER1(devid_val) ((int)BMVAL(devid_val, 0, 5)) - #define NUMBER_BITS_EACH_SIGNAL 4 #define LENGTH_REGISTER 32 @@ -56,8 +51,6 @@ #define PRIORITY_START_OFFSET 0x0074 #define CONDITION_DECODE_OFFSET 0x0050 #define CONDITION_SELECT_OFFSET 0x0060 -#define TIMER_START_OFFSET 0x0040 -#define COUNTER_START_OFFSET 0x0048 #define PRIORITY_OFFSET 0x60 #define REG_OFFSET 0x4 @@ -69,12 +62,6 @@ #define CONDITION_DECODE_STEP(step, decode) \ (CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step) -#define TIMER_COMPARE_STEP(step, timer) \ - (TIMER_START_OFFSET + REG_OFFSET * timer + STEP_OFFSET * step) - -#define COUNTER_COMPARE_STEP(step, counter) \ - (COUNTER_START_OFFSET + REG_OFFSET * counter + STEP_OFFSET * step) - #define CONDITION_SELECT_STEP(step, select) \ (CONDITION_SELECT_OFFSET + REG_OFFSET * select + STEP_OFFSET * step) @@ -96,12 +83,6 @@ #define STEP_SELECT(step_index, reg_num) \ tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_SELECT, reg_num) -#define STEP_TIMER(step_index, reg_num) \ - tgu_dataset_rw(reg##reg_num, step_index, TGU_TIMER, reg_num) - -#define STEP_COUNTER(step_index, reg_num) \ - tgu_dataset_rw(reg##reg_num, step_index, TGU_COUNTER, reg_num) - #define STEP_PRIORITY_LIST(step_index, priority) \ {STEP_PRIORITY(step_index, 0, priority), \ STEP_PRIORITY(step_index, 1, priority), \ @@ -141,18 +122,6 @@ NULL \ } -#define STEP_TIMER_LIST(n) \ - {STEP_TIMER(n, 0), \ - STEP_TIMER(n, 1), \ - NULL \ - } - -#define STEP_COUNTER_LIST(n) \ - {STEP_COUNTER(n, 0), \ - STEP_COUNTER(n, 1), \ - NULL \ - } - #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\ (&(const struct attribute_group){\ .attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\ @@ -174,20 +143,6 @@ .name = "step" #step "_condition_select" \ }) -#define TIMER_ATTRIBUTE_GROUP_INIT(step)\ - (&(const struct attribute_group){\ - .attrs = (struct attribute*[])STEP_TIMER_LIST(step),\ - .is_visible = tgu_node_visible,\ - .name = "step" #step "_timer" \ - }) - -#define COUNTER_ATTRIBUTE_GROUP_INIT(step)\ - (&(const struct attribute_group){\ - .attrs = (struct attribute*[])STEP_COUNTER_LIST(step),\ - .is_visible = tgu_node_visible,\ - .name = "step" #step "_counter" \ - }) - enum operation_index { TGU_PRIORITY0, TGU_PRIORITY1, @@ -195,8 +150,6 @@ enum operation_index { TGU_PRIORITY3, TGU_CONDITION_DECODE, TGU_CONDITION_SELECT, - TGU_TIMER, - TGU_COUNTER }; /* Maximum priority that TGU supports */ @@ -213,8 +166,6 @@ struct value_table { unsigned int *priority; unsigned int *condition_decode; unsigned int *condition_select; - unsigned int *timer; - unsigned int *counter; }; /** @@ -229,8 +180,6 @@ struct value_table { * @max_step: Maximum step size * @max_condition_decode: Maximum number of condition_decode * @max_condition_select: Maximum number of condition_select - * @max_timer: Maximum number of timers - * @max_counter: Maximum number of counters * * This structure defines the data associated with a TGU device, * including its base address, device pointers, clock, spinlock for @@ -248,8 +197,6 @@ struct tgu_drvdata { int max_step; int max_condition_decode; int max_condition_select; - int max_timer; - int max_counter; }; #endif From a6f3ce1ed15de0e61caade761a0fdceec8154467 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Thu, 30 Apr 2026 14:48:26 +0800 Subject: [PATCH 03/15] Revert "FROMLIST: coresight-tgu: add support to configure next action" This reverts commit 78172ff966101276aa3805305ff692e41cf2aa62. --- .../testing/sysfs-bus-coresight-devices-tgu | 7 --- drivers/hwtracing/coresight/coresight-tgu.c | 59 ------------------- drivers/hwtracing/coresight/coresight-tgu.h | 27 --------- 3 files changed, 93 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu index 5ca91e122500e..7530fff3338be 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu @@ -21,10 +21,3 @@ KernelVersion 6.16 Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) Description: (RW) Set/Get the decode mode with specific step for TGU. - -What: /sys/bus/coresight/devices//step[0:7]_condition_select/reg[0:3] -Date: July 2025 -KernelVersion 6.16 -Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) -Description: - (RW) Set/Get the next action with specific step for TGU. diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c index 71436fbdcc3e2..f123ae0825553 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.c +++ b/drivers/hwtracing/coresight/coresight-tgu.c @@ -36,9 +36,6 @@ static int calculate_array_location(struct tgu_drvdata *drvdata, ret = step_index * (drvdata->max_condition_decode) + reg_index; break; - case TGU_CONDITION_SELECT: - ret = step_index * (drvdata->max_condition_select) + reg_index; - break; default: break; } @@ -84,12 +81,6 @@ static ssize_t tgu_dataset_show(struct device *dev, drvdata, tgu_attr->step_index, tgu_attr->operation_index, tgu_attr->reg_num)]); - case TGU_CONDITION_SELECT: - return sysfs_emit(buf, "0x%x\n", - drvdata->value_table->condition_select[calculate_array_location( - drvdata, tgu_attr->step_index, - tgu_attr->operation_index, - tgu_attr->reg_num)]); default: break; } @@ -136,13 +127,6 @@ static ssize_t tgu_dataset_store(struct device *dev, tgu_attr->reg_num)] = val; ret = size; break; - case TGU_CONDITION_SELECT: - tgu_drvdata->value_table->condition_select[calculate_array_location( - tgu_drvdata, tgu_attr->step_index, - tgu_attr->operation_index, - tgu_attr->reg_num)] = val; - ret = size; - break; default: break; } @@ -178,16 +162,6 @@ static umode_t tgu_node_visible(struct kobject *kobject, attr->mode : 0; break; - case TGU_CONDITION_SELECT: - /* 'default' register is at the end of 'select' region */ - if (tgu_attr->reg_num == - drvdata->max_condition_select - 1) - attr->name = "default"; - ret = (tgu_attr->reg_num < - drvdata->max_condition_select) ? - attr->mode : - 0; - break; default: break; } @@ -232,20 +206,6 @@ static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) CONDITION_DECODE_STEP(i, j)); } } - - for (i = 0; i < drvdata->max_step; i++) { - for (j = 0; j < drvdata->max_condition_select; j++) { - ret = check_array_location(drvdata, i, TGU_CONDITION_SELECT, j); - if (ret == -EINVAL) - goto exit; - - tgu_writel(drvdata, - drvdata->value_table->condition_select - [calculate_array_location(drvdata, i, - TGU_CONDITION_SELECT, j)], - CONDITION_SELECT_STEP(i, j)); - } - } /* Enable TGU to program the triggers */ tgu_writel(drvdata, 1, TGU_CONTROL); exit: @@ -290,8 +250,6 @@ static void tgu_set_conditions(struct tgu_drvdata *drvdata) num_conditions = TGU_DEVID_CONDITIONS(devid); drvdata->max_condition_decode = num_conditions; - /* select region has an additional 'default' register */ - drvdata->max_condition_select = num_conditions + 1; } static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode, @@ -435,14 +393,6 @@ static const struct attribute_group *tgu_attr_groups[] = { CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(5), CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(6), CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(7), - CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(0), - CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(1), - CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(2), - CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(3), - CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(4), - CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(5), - CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(6), - CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(7), NULL, }; @@ -504,15 +454,6 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) if (!drvdata->value_table->condition_decode) return -ENOMEM; - drvdata->value_table->condition_select = devm_kzalloc( - dev, - drvdata->max_condition_select * drvdata->max_step * - sizeof(*(drvdata->value_table->condition_select)), - GFP_KERNEL); - - if (!drvdata->value_table->condition_select) - return -ENOMEM; - drvdata->enable = false; desc.type = CORESIGHT_DEV_TYPE_HELPER; desc.pdata = adev->dev.platform_data; diff --git a/drivers/hwtracing/coresight/coresight-tgu.h b/drivers/hwtracing/coresight/coresight-tgu.h index 29f6fcf4d2be8..8d3c6ddc19ed1 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.h +++ b/drivers/hwtracing/coresight/coresight-tgu.h @@ -50,7 +50,6 @@ #define STEP_OFFSET 0x1D8 #define PRIORITY_START_OFFSET 0x0074 #define CONDITION_DECODE_OFFSET 0x0050 -#define CONDITION_SELECT_OFFSET 0x0060 #define PRIORITY_OFFSET 0x60 #define REG_OFFSET 0x4 @@ -62,9 +61,6 @@ #define CONDITION_DECODE_STEP(step, decode) \ (CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step) -#define CONDITION_SELECT_STEP(step, select) \ - (CONDITION_SELECT_OFFSET + REG_OFFSET * select + STEP_OFFSET * step) - #define tgu_dataset_rw(name, step_index, type, reg_num) \ (&((struct tgu_attribute[]){ { \ __ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \ @@ -80,9 +76,6 @@ #define STEP_DECODE(step_index, reg_num) \ tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_DECODE, reg_num) -#define STEP_SELECT(step_index, reg_num) \ - tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_SELECT, reg_num) - #define STEP_PRIORITY_LIST(step_index, priority) \ {STEP_PRIORITY(step_index, 0, priority), \ STEP_PRIORITY(step_index, 1, priority), \ @@ -113,15 +106,6 @@ NULL \ } -#define STEP_SELECT_LIST(n) \ - {STEP_SELECT(n, 0), \ - STEP_SELECT(n, 1), \ - STEP_SELECT(n, 2), \ - STEP_SELECT(n, 3), \ - STEP_SELECT(n, 4), \ - NULL \ - } - #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\ (&(const struct attribute_group){\ .attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\ @@ -136,20 +120,12 @@ .name = "step" #step "_condition_decode" \ }) -#define CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(step)\ - (&(const struct attribute_group){\ - .attrs = (struct attribute*[])STEP_SELECT_LIST(step),\ - .is_visible = tgu_node_visible,\ - .name = "step" #step "_condition_select" \ - }) - enum operation_index { TGU_PRIORITY0, TGU_PRIORITY1, TGU_PRIORITY2, TGU_PRIORITY3, TGU_CONDITION_DECODE, - TGU_CONDITION_SELECT, }; /* Maximum priority that TGU supports */ @@ -165,7 +141,6 @@ struct tgu_attribute { struct value_table { unsigned int *priority; unsigned int *condition_decode; - unsigned int *condition_select; }; /** @@ -179,7 +154,6 @@ struct value_table { * @max_reg: Maximum number of registers * @max_step: Maximum step size * @max_condition_decode: Maximum number of condition_decode - * @max_condition_select: Maximum number of condition_select * * This structure defines the data associated with a TGU device, * including its base address, device pointers, clock, spinlock for @@ -196,7 +170,6 @@ struct tgu_drvdata { int max_reg; int max_step; int max_condition_decode; - int max_condition_select; }; #endif From c8de789e5dd050028c09f6a8ba8d63b4396d1825 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Thu, 30 Apr 2026 14:48:28 +0800 Subject: [PATCH 04/15] Revert "FROMLIST: coresight-tgu: Add TGU decode support" This reverts commit c247e91d89d225af8465219a742e3d6c235ff672. --- .../testing/sysfs-bus-coresight-devices-tgu | 7 - drivers/hwtracing/coresight/coresight-tgu.c | 186 +++--------------- drivers/hwtracing/coresight/coresight-tgu.h | 27 --- 3 files changed, 25 insertions(+), 195 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu index 7530fff3338be..4132f5912308d 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu @@ -14,10 +14,3 @@ KernelVersion 6.16 Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) Description: (RW) Set/Get the sensed signal with specific step and priority for TGU. - -What: /sys/bus/coresight/devices//step[0:7]_condition_decode/reg[0:3] -Date: July 2025 -KernelVersion 6.16 -Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) -Description: - (RW) Set/Get the decode mode with specific step for TGU. diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c index f123ae0825553..901409bef2c57 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.c +++ b/drivers/hwtracing/coresight/coresight-tgu.c @@ -21,35 +21,13 @@ static int calculate_array_location(struct tgu_drvdata *drvdata, int step_index, int operation_index, int reg_index) { - int ret = -EINVAL; - - switch (operation_index) { - case TGU_PRIORITY0: - case TGU_PRIORITY1: - case TGU_PRIORITY2: - case TGU_PRIORITY3: - ret = operation_index * (drvdata->max_step) * - (drvdata->max_reg) + - step_index * (drvdata->max_reg) + reg_index; - break; - case TGU_CONDITION_DECODE: - ret = step_index * (drvdata->max_condition_decode) + - reg_index; - break; - default: - break; - } - return ret; -} + int ret; -static int check_array_location(struct tgu_drvdata *drvdata, int step, - int ops, int reg) -{ - int result = calculate_array_location(drvdata, step, ops, reg); + ret = operation_index * (drvdata->max_step) * + (drvdata->max_reg) + + step_index * (drvdata->max_reg) + reg_index; - if (result == -EINVAL) - dev_err(&drvdata->csdev->dev, "%s - Fail\n", __func__); - return result; + return ret; } static ssize_t tgu_dataset_show(struct device *dev, @@ -58,33 +36,13 @@ static ssize_t tgu_dataset_show(struct device *dev, struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent); struct tgu_attribute *tgu_attr = container_of(attr, struct tgu_attribute, attr); - int ret = 0; - - ret = check_array_location(drvdata, tgu_attr->step_index, - tgu_attr->operation_index, tgu_attr->reg_num); - if (ret == -EINVAL) - return ret; - switch (tgu_attr->operation_index) { - case TGU_PRIORITY0: - case TGU_PRIORITY1: - case TGU_PRIORITY2: - case TGU_PRIORITY3: - return sysfs_emit(buf, "0x%x\n", - drvdata->value_table->priority[calculate_array_location( - drvdata, tgu_attr->step_index, - tgu_attr->operation_index, - tgu_attr->reg_num)]); - case TGU_CONDITION_DECODE: - return sysfs_emit(buf, "0x%x\n", - drvdata->value_table->condition_decode[calculate_array_location( - drvdata, tgu_attr->step_index, - tgu_attr->operation_index, - tgu_attr->reg_num)]); - default: - break; - } - return -EINVAL; + return sysfs_emit(buf, "0x%x\n", + drvdata->value_table->priority[ + calculate_array_location( + drvdata, tgu_attr->step_index, + tgu_attr->operation_index, + tgu_attr->reg_num)]); } static ssize_t tgu_dataset_store(struct device *dev, @@ -93,44 +51,20 @@ static ssize_t tgu_dataset_store(struct device *dev, size_t size) { unsigned long val; - int ret = -EINVAL; struct tgu_drvdata *tgu_drvdata = dev_get_drvdata(dev->parent); struct tgu_attribute *tgu_attr = container_of(attr, struct tgu_attribute, attr); if (kstrtoul(buf, 0, &val)) - return ret; - - ret = check_array_location(tgu_drvdata, tgu_attr->step_index, - tgu_attr->operation_index, tgu_attr->reg_num); - - if (ret == -EINVAL) - return ret; + return -EINVAL; guard(spinlock)(&tgu_drvdata->spinlock); - switch (tgu_attr->operation_index) { - case TGU_PRIORITY0: - case TGU_PRIORITY1: - case TGU_PRIORITY2: - case TGU_PRIORITY3: - tgu_drvdata->value_table->priority[calculate_array_location( - tgu_drvdata, tgu_attr->step_index, - tgu_attr->operation_index, - tgu_attr->reg_num)] = val; - ret = size; - break; - case TGU_CONDITION_DECODE: - tgu_drvdata->value_table->condition_decode[calculate_array_location( - tgu_drvdata, tgu_attr->step_index, - tgu_attr->operation_index, - tgu_attr->reg_num)] = val; - ret = size; - break; - default: - break; - } - return ret; + tgu_drvdata->value_table->priority[calculate_array_location( + tgu_drvdata, tgu_attr->step_index, tgu_attr->operation_index, + tgu_attr->reg_num)] = val; + + return size; } static umode_t tgu_node_visible(struct kobject *kobject, @@ -147,70 +81,34 @@ static umode_t tgu_node_visible(struct kobject *kobject, container_of(dev_attr, struct tgu_attribute, attr); if (tgu_attr->step_index < drvdata->max_step) { - switch (tgu_attr->operation_index) { - case TGU_PRIORITY0: - case TGU_PRIORITY1: - case TGU_PRIORITY2: - case TGU_PRIORITY3: - ret = (tgu_attr->reg_num < drvdata->max_reg) ? - attr->mode : - 0; - break; - case TGU_CONDITION_DECODE: - ret = (tgu_attr->reg_num < - drvdata->max_condition_decode) ? - attr->mode : - 0; - break; - default: - break; - } + ret = (tgu_attr->reg_num < drvdata->max_reg) ? + attr->mode : + 0; } return ret; } -static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) +static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) { - int i, j, k, ret; + int i, j, k; CS_UNLOCK(drvdata->base); for (i = 0; i < drvdata->max_step; i++) { for (j = 0; j < MAX_PRIORITY; j++) { for (k = 0; k < drvdata->max_reg; k++) { - - ret = check_array_location(drvdata, i, j, k); - if (ret == -EINVAL) - goto exit; - tgu_writel(drvdata, drvdata->value_table->priority [calculate_array_location( - drvdata, i, j, k)], + drvdata, i, j, k)], PRIORITY_REG_STEP(i, j, k)); } } } - for (i = 0; i < drvdata->max_step; i++) { - for (j = 0; j < drvdata->max_condition_decode; j++) { - ret = check_array_location(drvdata, i, TGU_CONDITION_DECODE, j); - if (ret == -EINVAL) - goto exit; - - tgu_writel(drvdata, - drvdata->value_table->condition_decode - [calculate_array_location( - drvdata, i, - TGU_CONDITION_DECODE, j)], - CONDITION_DECODE_STEP(i, j)); - } - } /* Enable TGU to program the triggers */ tgu_writel(drvdata, 1, TGU_CONTROL); -exit: CS_LOCK(drvdata->base); - return ret >= 0 ? 0 : ret; } static void tgu_set_reg_number(struct tgu_drvdata *drvdata) @@ -241,35 +139,19 @@ static void tgu_set_steps(struct tgu_drvdata *drvdata) drvdata->max_step = num_steps; } -static void tgu_set_conditions(struct tgu_drvdata *drvdata) -{ - int num_conditions; - u32 devid; - - devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID); - - num_conditions = TGU_DEVID_CONDITIONS(devid); - drvdata->max_condition_decode = num_conditions; -} - static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode, void *data) { - int ret = 0; struct tgu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); guard(spinlock)(&drvdata->spinlock); if (drvdata->enable) return -EBUSY; - ret = tgu_write_all_hw_regs(drvdata); - - if (ret == -EINVAL) - goto exit; + tgu_write_all_hw_regs(drvdata); drvdata->enable = true; -exit: - return ret; + return 0; } static int tgu_disable(struct coresight_device *csdev, void *data) @@ -385,14 +267,6 @@ static const struct attribute_group *tgu_attr_groups[] = { PRIORITY_ATTRIBUTE_GROUP_INIT(7, 1), PRIORITY_ATTRIBUTE_GROUP_INIT(7, 2), PRIORITY_ATTRIBUTE_GROUP_INIT(7, 3), - CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(0), - CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(1), - CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(2), - CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(3), - CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(4), - CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(5), - CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(6), - CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(7), NULL, }; @@ -429,7 +303,6 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) tgu_set_reg_number(drvdata); tgu_set_steps(drvdata); - tgu_set_conditions(drvdata); drvdata->value_table = devm_kzalloc(dev, sizeof(*drvdata->value_table), GFP_KERNEL); @@ -445,15 +318,6 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) if (!drvdata->value_table->priority) return -ENOMEM; - drvdata->value_table->condition_decode = devm_kzalloc( - dev, - drvdata->max_condition_decode * drvdata->max_step * - sizeof(*(drvdata->value_table->condition_decode)), - GFP_KERNEL); - - if (!drvdata->value_table->condition_decode) - return -ENOMEM; - drvdata->enable = false; desc.type = CORESIGHT_DEV_TYPE_HELPER; desc.pdata = adev->dev.platform_data; diff --git a/drivers/hwtracing/coresight/coresight-tgu.h b/drivers/hwtracing/coresight/coresight-tgu.h index 8d3c6ddc19ed1..9b79106c92eaa 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.h +++ b/drivers/hwtracing/coresight/coresight-tgu.h @@ -15,7 +15,6 @@ #define TGU_DEVID_SENSE_INPUT(devid_val) ((int) BMVAL(devid_val, 10, 17)) #define TGU_DEVID_STEPS(devid_val) ((int)BMVAL(devid_val, 3, 6)) -#define TGU_DEVID_CONDITIONS(devid_val) ((int)BMVAL(devid_val, 0, 2)) #define NUMBER_BITS_EACH_SIGNAL 4 #define LENGTH_REGISTER 32 @@ -49,7 +48,6 @@ */ #define STEP_OFFSET 0x1D8 #define PRIORITY_START_OFFSET 0x0074 -#define CONDITION_DECODE_OFFSET 0x0050 #define PRIORITY_OFFSET 0x60 #define REG_OFFSET 0x4 @@ -58,9 +56,6 @@ (PRIORITY_START_OFFSET + PRIORITY_OFFSET * priority +\ REG_OFFSET * reg + STEP_OFFSET * step) -#define CONDITION_DECODE_STEP(step, decode) \ - (CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step) - #define tgu_dataset_rw(name, step_index, type, reg_num) \ (&((struct tgu_attribute[]){ { \ __ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \ @@ -73,9 +68,6 @@ tgu_dataset_rw(reg##reg_num, step_index, TGU_PRIORITY##priority, \ reg_num) -#define STEP_DECODE(step_index, reg_num) \ - tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_DECODE, reg_num) - #define STEP_PRIORITY_LIST(step_index, priority) \ {STEP_PRIORITY(step_index, 0, priority), \ STEP_PRIORITY(step_index, 1, priority), \ @@ -98,14 +90,6 @@ NULL \ } -#define STEP_DECODE_LIST(n) \ - {STEP_DECODE(n, 0), \ - STEP_DECODE(n, 1), \ - STEP_DECODE(n, 2), \ - STEP_DECODE(n, 3), \ - NULL \ - } - #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\ (&(const struct attribute_group){\ .attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\ @@ -113,19 +97,11 @@ .name = "step" #step "_priority" #priority \ }) -#define CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(step)\ - (&(const struct attribute_group){\ - .attrs = (struct attribute*[])STEP_DECODE_LIST(step),\ - .is_visible = tgu_node_visible,\ - .name = "step" #step "_condition_decode" \ - }) - enum operation_index { TGU_PRIORITY0, TGU_PRIORITY1, TGU_PRIORITY2, TGU_PRIORITY3, - TGU_CONDITION_DECODE, }; /* Maximum priority that TGU supports */ @@ -140,7 +116,6 @@ struct tgu_attribute { struct value_table { unsigned int *priority; - unsigned int *condition_decode; }; /** @@ -153,7 +128,6 @@ struct value_table { * @value_table: Store given value based on relevant parameters. * @max_reg: Maximum number of registers * @max_step: Maximum step size - * @max_condition_decode: Maximum number of condition_decode * * This structure defines the data associated with a TGU device, * including its base address, device pointers, clock, spinlock for @@ -169,7 +143,6 @@ struct tgu_drvdata { struct value_table *value_table; int max_reg; int max_step; - int max_condition_decode; }; #endif From 63a4ec54a7bd49ebf6757ac66aa4ca34e89e2290 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Thu, 30 Apr 2026 14:48:31 +0800 Subject: [PATCH 05/15] Revert "FROMLIST: coresight-tgu: Add signal priority support" This reverts commit 2e7b6a1c32c846d7e02cea801c40e3b7e2d23c44. --- .../testing/sysfs-bus-coresight-devices-tgu | 7 - drivers/hwtracing/coresight/coresight-tgu.c | 163 ------------------ drivers/hwtracing/coresight/coresight-tgu.h | 111 ------------ 3 files changed, 281 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu index 4132f5912308d..31553776f037c 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu @@ -7,10 +7,3 @@ Description: Accepts only one of the 2 values - 0 or 1. 0 : disable TGU. 1 : enable TGU. - -What: /sys/bus/coresight/devices//step[0:7]_priority[0:3]/reg[0:17] -Date: July 2025 -KernelVersion 6.16 -Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) -Description: - (RW) Set/Get the sensed signal with specific step and priority for TGU. diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c index 901409bef2c57..1d237d14d3c91 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.c +++ b/drivers/hwtracing/coresight/coresight-tgu.c @@ -17,128 +17,14 @@ DEFINE_CORESIGHT_DEVLIST(tgu_devs, "tgu"); -static int calculate_array_location(struct tgu_drvdata *drvdata, - int step_index, int operation_index, - int reg_index) -{ - int ret; - - ret = operation_index * (drvdata->max_step) * - (drvdata->max_reg) + - step_index * (drvdata->max_reg) + reg_index; - - return ret; -} - -static ssize_t tgu_dataset_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent); - struct tgu_attribute *tgu_attr = - container_of(attr, struct tgu_attribute, attr); - - return sysfs_emit(buf, "0x%x\n", - drvdata->value_table->priority[ - calculate_array_location( - drvdata, tgu_attr->step_index, - tgu_attr->operation_index, - tgu_attr->reg_num)]); -} - -static ssize_t tgu_dataset_store(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t size) -{ - unsigned long val; - - struct tgu_drvdata *tgu_drvdata = dev_get_drvdata(dev->parent); - struct tgu_attribute *tgu_attr = - container_of(attr, struct tgu_attribute, attr); - - if (kstrtoul(buf, 0, &val)) - return -EINVAL; - - guard(spinlock)(&tgu_drvdata->spinlock); - tgu_drvdata->value_table->priority[calculate_array_location( - tgu_drvdata, tgu_attr->step_index, tgu_attr->operation_index, - tgu_attr->reg_num)] = val; - - return size; -} - -static umode_t tgu_node_visible(struct kobject *kobject, - struct attribute *attr, - int n) -{ - struct device *dev = kobj_to_dev(kobject); - struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent); - int ret = SYSFS_GROUP_INVISIBLE; - - struct device_attribute *dev_attr = - container_of(attr, struct device_attribute, attr); - struct tgu_attribute *tgu_attr = - container_of(dev_attr, struct tgu_attribute, attr); - - if (tgu_attr->step_index < drvdata->max_step) { - ret = (tgu_attr->reg_num < drvdata->max_reg) ? - attr->mode : - 0; - } - return ret; -} - static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) { - int i, j, k; - CS_UNLOCK(drvdata->base); - - for (i = 0; i < drvdata->max_step; i++) { - for (j = 0; j < MAX_PRIORITY; j++) { - for (k = 0; k < drvdata->max_reg; k++) { - tgu_writel(drvdata, - drvdata->value_table->priority - [calculate_array_location( - drvdata, i, j, k)], - PRIORITY_REG_STEP(i, j, k)); - } - } - } - /* Enable TGU to program the triggers */ tgu_writel(drvdata, 1, TGU_CONTROL); CS_LOCK(drvdata->base); } -static void tgu_set_reg_number(struct tgu_drvdata *drvdata) -{ - int num_sense_input; - int num_reg; - u32 devid; - - devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID); - - num_sense_input = TGU_DEVID_SENSE_INPUT(devid); - if (((num_sense_input * NUMBER_BITS_EACH_SIGNAL) % LENGTH_REGISTER) == 0) - num_reg = (num_sense_input * NUMBER_BITS_EACH_SIGNAL) / LENGTH_REGISTER; - else - num_reg = ((num_sense_input * NUMBER_BITS_EACH_SIGNAL) / LENGTH_REGISTER) + 1; - drvdata->max_reg = num_reg; -} - -static void tgu_set_steps(struct tgu_drvdata *drvdata) -{ - int num_steps; - u32 devid; - - devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID); - - num_steps = TGU_DEVID_STEPS(devid); - - drvdata->max_step = num_steps; -} - static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode, void *data) { @@ -235,38 +121,6 @@ static const struct attribute_group tgu_common_grp = { static const struct attribute_group *tgu_attr_groups[] = { &tgu_common_grp, - PRIORITY_ATTRIBUTE_GROUP_INIT(0, 0), - PRIORITY_ATTRIBUTE_GROUP_INIT(0, 1), - PRIORITY_ATTRIBUTE_GROUP_INIT(0, 2), - PRIORITY_ATTRIBUTE_GROUP_INIT(0, 3), - PRIORITY_ATTRIBUTE_GROUP_INIT(1, 0), - PRIORITY_ATTRIBUTE_GROUP_INIT(1, 1), - PRIORITY_ATTRIBUTE_GROUP_INIT(1, 2), - PRIORITY_ATTRIBUTE_GROUP_INIT(1, 3), - PRIORITY_ATTRIBUTE_GROUP_INIT(2, 0), - PRIORITY_ATTRIBUTE_GROUP_INIT(2, 1), - PRIORITY_ATTRIBUTE_GROUP_INIT(2, 2), - PRIORITY_ATTRIBUTE_GROUP_INIT(2, 3), - PRIORITY_ATTRIBUTE_GROUP_INIT(3, 0), - PRIORITY_ATTRIBUTE_GROUP_INIT(3, 1), - PRIORITY_ATTRIBUTE_GROUP_INIT(3, 2), - PRIORITY_ATTRIBUTE_GROUP_INIT(3, 3), - PRIORITY_ATTRIBUTE_GROUP_INIT(4, 0), - PRIORITY_ATTRIBUTE_GROUP_INIT(4, 1), - PRIORITY_ATTRIBUTE_GROUP_INIT(4, 2), - PRIORITY_ATTRIBUTE_GROUP_INIT(4, 3), - PRIORITY_ATTRIBUTE_GROUP_INIT(5, 0), - PRIORITY_ATTRIBUTE_GROUP_INIT(5, 1), - PRIORITY_ATTRIBUTE_GROUP_INIT(5, 2), - PRIORITY_ATTRIBUTE_GROUP_INIT(5, 3), - PRIORITY_ATTRIBUTE_GROUP_INIT(6, 0), - PRIORITY_ATTRIBUTE_GROUP_INIT(6, 1), - PRIORITY_ATTRIBUTE_GROUP_INIT(6, 2), - PRIORITY_ATTRIBUTE_GROUP_INIT(6, 3), - PRIORITY_ATTRIBUTE_GROUP_INIT(7, 0), - PRIORITY_ATTRIBUTE_GROUP_INIT(7, 1), - PRIORITY_ATTRIBUTE_GROUP_INIT(7, 2), - PRIORITY_ATTRIBUTE_GROUP_INIT(7, 3), NULL, }; @@ -301,23 +155,6 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&drvdata->spinlock); - tgu_set_reg_number(drvdata); - tgu_set_steps(drvdata); - - drvdata->value_table = - devm_kzalloc(dev, sizeof(*drvdata->value_table), GFP_KERNEL); - if (!drvdata->value_table) - return -ENOMEM; - - drvdata->value_table->priority = devm_kzalloc( - dev, - MAX_PRIORITY * drvdata->max_reg * drvdata->max_step * - sizeof(*(drvdata->value_table->priority)), - GFP_KERNEL); - - if (!drvdata->value_table->priority) - return -ENOMEM; - drvdata->enable = false; desc.type = CORESIGHT_DEV_TYPE_HELPER; desc.pdata = adev->dev.platform_data; diff --git a/drivers/hwtracing/coresight/coresight-tgu.h b/drivers/hwtracing/coresight/coresight-tgu.h index 9b79106c92eaa..6c849a2f78faf 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.h +++ b/drivers/hwtracing/coresight/coresight-tgu.h @@ -13,111 +13,6 @@ #define tgu_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off) #define tgu_readl(drvdata, off) __raw_readl(drvdata->base + off) -#define TGU_DEVID_SENSE_INPUT(devid_val) ((int) BMVAL(devid_val, 10, 17)) -#define TGU_DEVID_STEPS(devid_val) ((int)BMVAL(devid_val, 3, 6)) -#define NUMBER_BITS_EACH_SIGNAL 4 -#define LENGTH_REGISTER 32 - -/* - * TGU configuration space Step configuration - * offset table space layout - * x-------------------------x$ x-------------x$ - * | |$ | |$ - * | | | reserve |$ - * | | | |$ - * |coresight management | |-------------|base+n*0x1D8+0x1F4$ - * | registe | |---> |prioroty[3] |$ - * | | | |-------------|base+n*0x1D8+0x194$ - * | | | |prioroty[2] |$ - * |-------------------------| | |-------------|base+n*0x1D8+0x134$ - * | | | |prioroty[1] |$ - * | step[7] | | |-------------|base+n*0x1D8+0xD4$ - * |-------------------------|->base+0x40+7*0x1D8 | |prioroty[0] |$ - * | | | |-------------|base+n*0x1D8+0x74$ - * | ... | | | condition |$ - * | | | | select |$ - * |-------------------------|->base+0x40+1*0x1D8 | |-------------|base+n*0x1D8+0x60$ - * | | | | condition |$ - * | step[0] |--------------------> | decode |$ - * |-------------------------|-> base+0x40 |-------------|base+n*0x1D8+0x50$ - * | | | |$ - * | Control and status space| |Timer/Counter|$ - * | space | | |$ - * x-------------------------x->base x-------------x base+n*0x1D8+0x40$ - * - */ -#define STEP_OFFSET 0x1D8 -#define PRIORITY_START_OFFSET 0x0074 -#define PRIORITY_OFFSET 0x60 -#define REG_OFFSET 0x4 - -/* Calculate compare step addresses */ -#define PRIORITY_REG_STEP(step, priority, reg)\ - (PRIORITY_START_OFFSET + PRIORITY_OFFSET * priority +\ - REG_OFFSET * reg + STEP_OFFSET * step) - -#define tgu_dataset_rw(name, step_index, type, reg_num) \ - (&((struct tgu_attribute[]){ { \ - __ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \ - step_index, \ - type, \ - reg_num, \ - } })[0].attr.attr) - -#define STEP_PRIORITY(step_index, reg_num, priority) \ - tgu_dataset_rw(reg##reg_num, step_index, TGU_PRIORITY##priority, \ - reg_num) - -#define STEP_PRIORITY_LIST(step_index, priority) \ - {STEP_PRIORITY(step_index, 0, priority), \ - STEP_PRIORITY(step_index, 1, priority), \ - STEP_PRIORITY(step_index, 2, priority), \ - STEP_PRIORITY(step_index, 3, priority), \ - STEP_PRIORITY(step_index, 4, priority), \ - STEP_PRIORITY(step_index, 5, priority), \ - STEP_PRIORITY(step_index, 6, priority), \ - STEP_PRIORITY(step_index, 7, priority), \ - STEP_PRIORITY(step_index, 8, priority), \ - STEP_PRIORITY(step_index, 9, priority), \ - STEP_PRIORITY(step_index, 10, priority), \ - STEP_PRIORITY(step_index, 11, priority), \ - STEP_PRIORITY(step_index, 12, priority), \ - STEP_PRIORITY(step_index, 13, priority), \ - STEP_PRIORITY(step_index, 14, priority), \ - STEP_PRIORITY(step_index, 15, priority), \ - STEP_PRIORITY(step_index, 16, priority), \ - STEP_PRIORITY(step_index, 17, priority), \ - NULL \ - } - -#define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\ - (&(const struct attribute_group){\ - .attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\ - .is_visible = tgu_node_visible,\ - .name = "step" #step "_priority" #priority \ - }) - -enum operation_index { - TGU_PRIORITY0, - TGU_PRIORITY1, - TGU_PRIORITY2, - TGU_PRIORITY3, -}; - -/* Maximum priority that TGU supports */ -#define MAX_PRIORITY 4 - -struct tgu_attribute { - struct device_attribute attr; - u32 step_index; - enum operation_index operation_index; - u32 reg_num; -}; - -struct value_table { - unsigned int *priority; -}; - /** * struct tgu_drvdata - Data structure for a TGU (Trigger Generator Unit) * @base: Memory-mapped base address of the TGU device @@ -125,9 +20,6 @@ struct value_table { * @csdev: Pointer to the associated coresight device * @spinlock: Spinlock for handling concurrent access * @enable: Flag indicating whether the TGU device is enabled - * @value_table: Store given value based on relevant parameters. - * @max_reg: Maximum number of registers - * @max_step: Maximum step size * * This structure defines the data associated with a TGU device, * including its base address, device pointers, clock, spinlock for @@ -140,9 +32,6 @@ struct tgu_drvdata { struct coresight_device *csdev; spinlock_t spinlock; bool enable; - struct value_table *value_table; - int max_reg; - int max_step; }; #endif From c5bb9699c0882ff5f0cf4868af8eec483cf69c28 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Thu, 30 Apr 2026 14:48:33 +0800 Subject: [PATCH 06/15] Revert "FROMLIST: coresight: Add coresight TGU driver" This reverts commit 9584fedeeac26274c52def10c0771050527c1a0b. --- .../testing/sysfs-bus-coresight-devices-tgu | 9 - drivers/hwtracing/coresight/Kconfig | 11 - drivers/hwtracing/coresight/Makefile | 1 - drivers/hwtracing/coresight/coresight-tgu.c | 209 ------------------ drivers/hwtracing/coresight/coresight-tgu.h | 37 ---- 5 files changed, 267 deletions(-) delete mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu delete mode 100644 drivers/hwtracing/coresight/coresight-tgu.c delete mode 100644 drivers/hwtracing/coresight/coresight-tgu.h diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu deleted file mode 100644 index 31553776f037c..0000000000000 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu +++ /dev/null @@ -1,9 +0,0 @@ -What: /sys/bus/coresight/devices//enable_tgu -Date: July 2025 -KernelVersion 6.16 -Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) -Description: - (RW) Set/Get the enable/disable status of TGU - Accepts only one of the 2 values - 0 or 1. - 0 : disable TGU. - 1 : enable TGU. diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index 5b0974e0e942b..6a4239ebb582e 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -20,17 +20,6 @@ menuconfig CORESIGHT module will be called coresight. if CORESIGHT -config CORESIGHT_TGU - tristate "CoreSight Trigger Generation Unit driver" - help - This driver provides support for Trigger Generation Unit that is - used to detect patterns or sequences on a given set of signals. - TGU is used to monitor a particular bus within a given region to - detect illegal transaction sequences or slave responses. It is also - used to monitor a data stream to detect protocol violations and to - provide a trigger point for centering data around a specific event - within the trace data buffer. - config CORESIGHT_LINKS_AND_SINKS tristate "CoreSight Link and Sink drivers" help diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index e5f143f91d698..821a1b06b20c2 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -54,7 +54,6 @@ coresight-cti-y := coresight-cti-core.o coresight-cti-platform.o \ coresight-cti-sysfs.o obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o -obj-$(CONFIG_CORESIGHT_TGU) += coresight-tgu.o obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o coresight-ctcu-y := coresight-ctcu-core.o coresight-ctcu-byte-cntr.o obj-$(CONFIG_CORESIGHT_KUNIT_TESTS) += coresight-kunit-tests.o diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c deleted file mode 100644 index 1d237d14d3c91..0000000000000 --- a/drivers/hwtracing/coresight/coresight-tgu.c +++ /dev/null @@ -1,209 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "coresight-priv.h" -#include "coresight-tgu.h" - -DEFINE_CORESIGHT_DEVLIST(tgu_devs, "tgu"); - -static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) -{ - CS_UNLOCK(drvdata->base); - /* Enable TGU to program the triggers */ - tgu_writel(drvdata, 1, TGU_CONTROL); - CS_LOCK(drvdata->base); -} - -static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode, - void *data) -{ - struct tgu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - - guard(spinlock)(&drvdata->spinlock); - if (drvdata->enable) - return -EBUSY; - - tgu_write_all_hw_regs(drvdata); - drvdata->enable = true; - - return 0; -} - -static int tgu_disable(struct coresight_device *csdev, void *data) -{ - struct tgu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - - spin_lock(&drvdata->spinlock); - if (drvdata->enable) { - CS_UNLOCK(drvdata->base); - tgu_writel(drvdata, 0, TGU_CONTROL); - CS_LOCK(drvdata->base); - - drvdata->enable = false; - } - spin_unlock(&drvdata->spinlock); - return 0; -} - -static ssize_t enable_tgu_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - bool enabled; - struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent); - - spin_lock(&drvdata->spinlock); - enabled = drvdata->enable; - spin_unlock(&drvdata->spinlock); - - return sysfs_emit(buf, "%d\n", enabled); -} - -/* enable_tgu_store - Configure Trace and Gating Unit (TGU) triggers. */ -static ssize_t enable_tgu_store(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t size) -{ - int ret = 0; - unsigned long val; - struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent); - - ret = kstrtoul(buf, 0, &val); - if (ret) - return ret; - - if (val) { - ret = pm_runtime_resume_and_get(dev->parent); - if (ret) - return ret; - ret = tgu_enable(drvdata->csdev, CS_MODE_SYSFS, NULL); - if (ret) - pm_runtime_put(dev->parent); - } else { - ret = tgu_disable(drvdata->csdev, NULL); - pm_runtime_put(dev->parent); - } - - if (ret) - return ret; - return size; -} -static DEVICE_ATTR_RW(enable_tgu); - -static const struct coresight_ops_helper tgu_helper_ops = { - .enable = tgu_enable, - .disable = tgu_disable, -}; - -static const struct coresight_ops tgu_ops = { - .helper_ops = &tgu_helper_ops, -}; - -static struct attribute *tgu_common_attrs[] = { - &dev_attr_enable_tgu.attr, - NULL, -}; - -static const struct attribute_group tgu_common_grp = { - .attrs = tgu_common_attrs, - { NULL }, -}; - -static const struct attribute_group *tgu_attr_groups[] = { - &tgu_common_grp, - NULL, -}; - -static int tgu_probe(struct amba_device *adev, const struct amba_id *id) -{ - int ret = 0; - struct device *dev = &adev->dev; - struct coresight_desc desc = { 0 }; - struct coresight_platform_data *pdata; - struct tgu_drvdata *drvdata; - - desc.name = coresight_alloc_device_name(&tgu_devs, dev); - if (!desc.name) - return -ENOMEM; - - pdata = coresight_get_platform_data(dev); - if (IS_ERR(pdata)) - return PTR_ERR(pdata); - - adev->dev.platform_data = pdata; - - drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - drvdata->dev = &adev->dev; - dev_set_drvdata(dev, drvdata); - - drvdata->base = devm_ioremap_resource(dev, &adev->res); - if (!drvdata->base) - return -ENOMEM; - - spin_lock_init(&drvdata->spinlock); - - drvdata->enable = false; - desc.type = CORESIGHT_DEV_TYPE_HELPER; - desc.pdata = adev->dev.platform_data; - desc.dev = &adev->dev; - desc.ops = &tgu_ops; - desc.groups = tgu_attr_groups; - - drvdata->csdev = coresight_register(&desc); - if (IS_ERR(drvdata->csdev)) { - ret = PTR_ERR(drvdata->csdev); - goto err; - } - - pm_runtime_put(&adev->dev); - return 0; -err: - pm_runtime_put(&adev->dev); - return ret; -} - -static void tgu_remove(struct amba_device *adev) -{ - struct tgu_drvdata *drvdata = dev_get_drvdata(&adev->dev); - - coresight_unregister(drvdata->csdev); -} - -static const struct amba_id tgu_ids[] = { - { - .id = 0x000f0e00, - .mask = 0x000fffff, - .data = "TGU", - }, - { 0, 0, NULL }, -}; - -MODULE_DEVICE_TABLE(amba, tgu_ids); - -static struct amba_driver tgu_driver = { - .drv = { - .name = "coresight-tgu", - .suppress_bind_attrs = true, - }, - .probe = tgu_probe, - .remove = tgu_remove, - .id_table = tgu_ids, -}; - -module_amba_driver(tgu_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("CoreSight TGU driver"); diff --git a/drivers/hwtracing/coresight/coresight-tgu.h b/drivers/hwtracing/coresight/coresight-tgu.h deleted file mode 100644 index 6c849a2f78faf..0000000000000 --- a/drivers/hwtracing/coresight/coresight-tgu.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved. - */ - -#ifndef _CORESIGHT_TGU_H -#define _CORESIGHT_TGU_H - -/* Register addresses */ -#define TGU_CONTROL 0x0000 - -/* Register read/write */ -#define tgu_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off) -#define tgu_readl(drvdata, off) __raw_readl(drvdata->base + off) - -/** - * struct tgu_drvdata - Data structure for a TGU (Trigger Generator Unit) - * @base: Memory-mapped base address of the TGU device - * @dev: Pointer to the associated device structure - * @csdev: Pointer to the associated coresight device - * @spinlock: Spinlock for handling concurrent access - * @enable: Flag indicating whether the TGU device is enabled - * - * This structure defines the data associated with a TGU device, - * including its base address, device pointers, clock, spinlock for - * synchronization, trigger data pointers, maximum limits for various - * trigger-related parameters, and enable status. - */ -struct tgu_drvdata { - void __iomem *base; - struct device *dev; - struct coresight_device *csdev; - spinlock_t spinlock; - bool enable; -}; - -#endif From 1d75138cf16d2eefee457f83890dfc21b165e552 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Thu, 30 Apr 2026 14:49:26 +0800 Subject: [PATCH 07/15] Revert "FROMLIST: dt-bindings: arm: Add support for Coresight TGU trace" This reverts commit 2ea01e7aff318d107c569a77d074a39cd46ba3ec. --- .../bindings/arm/qcom,coresight-tgu.yaml | 92 ------------------- 1 file changed, 92 deletions(-) delete mode 100644 Documentation/devicetree/bindings/arm/qcom,coresight-tgu.yaml diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tgu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tgu.yaml deleted file mode 100644 index 3576d38711261..0000000000000 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-tgu.yaml +++ /dev/null @@ -1,92 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause -# Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/arm/qcom,coresight-tgu.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Trigger Generation Unit - TGU - -description: | - The Trigger Generation Unit (TGU) is a Data Engine which can be utilized - to sense a plurality of signals and create a trigger into the CTI or - generate interrupts to processors. The TGU is like the trigger circuit - of a Logic Analyzer. The corresponding trigger logic can be realized by - configuring the conditions for each step after sensing the signal. - Once setup and enabled, it will observe sense inputs and based upon - the activity of those inputs, even over clock cycles, may detect a - preprogrammed state/sequence and then produce a trigger or interrupt. - - The primary use case of the TGU is to detect patterns or sequences on a - given set of signals within some region to indentify the issue in time - once there is abnormal behavior in the subsystem. - -maintainers: - - Mao Jinlong - - Sam Chai - -# Need a custom select here or 'arm,primecell' will match on lots of nodes -select: - properties: - compatible: - contains: - enum: - - qcom,coresight-tgu - required: - - compatible - -properties: - compatible: - items: - - const: qcom,coresight-tgu - - const: arm,primecell - - reg: - maxItems: 1 - - clocks: - maxItems: 1 - - clock-names: - items: - - const: apb_pclk - - in-ports: - $ref: /schemas/graph.yaml#/properties/ports - additionalProperties: false - - properties: - port: - description: - The port mechanism here ensures the relationship between TGU and - TPDM, as TPDM is one of the inputs for TGU. It will allow TGU to - function as TPDM's helper and enable TGU when the connected - TPDM is enabled. - $ref: /schemas/graph.yaml#/properties/port - -required: - - compatible - - reg - - clocks - - clock-names - -additionalProperties: false - -examples: - - | - tgu@10b0e000 { - compatible = "qcom,coresight-tgu", "arm,primecell"; - reg = <0x10b0e000 0x1000>; - - clocks = <&aoss_qmp>; - clock-names = "apb_pclk"; - - in-ports { - port { - tgu_in_tpdm_swao: endpoint{ - remote-endpoint = <&tpdm_swao_out_tgu>; - }; - }; - }; - }; -... From 03d42ac5545a84c0b5e524fea2172c940a6be217 Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Fri, 17 Apr 2026 00:33:30 -0700 Subject: [PATCH 08/15] FROMLIST: dt-bindings: arm: Add support for Qualcomm TGU trace The Trigger Generation Unit (TGU) is designed to detect patterns or sequences within a specific region of the System on Chip (SoC). Once configured and activated, it monitors sense inputs and can detect a pre-programmed state or sequence across clock cycles, subsequently producing a trigger. TGU configuration space offset table x-------------------------x | | | | | | Step configuration | | space layout | coresight management | x-------------x | registers | |---> | | | | | | reserve | | | | | | |-------------------------| | |-------------| | | | | priority[3] | | step[7] |<-- | |-------------| |-------------------------| | | | priority[2] | | | | | |-------------| | ... | |Steps region | | priority[1] | | | | | |-------------| |-------------------------| | | | priority[0] | | |<-- | |-------------| | step[0] |--------------------> | | |-------------------------| | condition | | | | | | control and status | x-------------x | space | | | x-------------------------x |Timer/Counter| | | x-------------x TGU Configuration in Hardware The TGU provides a step region for user configuration, similar to a flow chart. Each step region consists of three register clusters: 1.Priority Region: Sets the required signals with priority. 2.Condition Region: Defines specific requirements (e.g., signal A reaches three times) and the subsequent action once the requirement is met. 3.Timer/Counter (Optional): Provides timing or counting functionality. Add a new tgu.yaml file to describe the bindings required to define the TGU in the device trees. Link: https://lore.kernel.org/all/20260417073336.2712426-2-songwei.chai@oss.qualcomm.com/ Reviewed-by: Rob Herring (Arm) Signed-off-by: Songwei Chai --- .../devicetree/bindings/arm/qcom,tgu.yaml | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/qcom,tgu.yaml diff --git a/Documentation/devicetree/bindings/arm/qcom,tgu.yaml b/Documentation/devicetree/bindings/arm/qcom,tgu.yaml new file mode 100644 index 0000000000000..76440f2497b97 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/qcom,tgu.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +# Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/qcom,tgu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Trigger Generation Unit - TGU + +description: | + The Trigger Generation Unit (TGU) is a Data Engine which can be utilized + to sense a plurality of signals and create a trigger into the CTI or + generate interrupts to processors. The TGU is like the trigger circuit + of a Logic Analyzer. The corresponding trigger logic can be realized by + configuring the conditions for each step after sensing the signal. + Once setup and enabled, it will observe sense inputs and based upon + the activity of those inputs, even over clock cycles, may detect a + preprogrammed state/sequence and then produce a trigger or interrupt. + + The primary use case of the TGU is to detect patterns or sequences on a + given set of signals within some region to identify the issue in time + once there is abnormal behavior in the subsystem. + +maintainers: + - Mao Jinlong + - Songwei Chai + +# Need a custom select here or 'arm,primecell' will match on lots of nodes +select: + properties: + compatible: + contains: + enum: + - qcom,tgu + required: + - compatible + +properties: + compatible: + items: + - const: qcom,tgu + - const: arm,primecell + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: apb_pclk + +required: + - compatible + - reg + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + tgu@10b0e000 { + compatible = "qcom,tgu", "arm,primecell"; + reg = <0x10b0e000 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + }; +... From 3708f1500a98c2c21557bf78c9d0a3299237b47d Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Fri, 17 Apr 2026 00:33:31 -0700 Subject: [PATCH 09/15] FROMLIST: qcom-tgu: Add TGU driver Add driver to support device TGU (Trigger Generation Unit). TGU is a Data Engine which can be utilized to sense a plurality of signals and create a trigger into the CTI or generate interrupts to processors. Add probe/enable/disable functions for tgu. Link: https://lore.kernel.org/all/20260417073336.2712426-3-songwei.chai@oss.qualcomm.com/ Signed-off-by: Songwei Chai Acked-by: Konrad Dybcio --- .../ABI/testing/sysfs-bus-amba-devices-tgu | 9 + drivers/Makefile | 1 + drivers/hwtracing/Kconfig | 2 + drivers/hwtracing/qcom/Kconfig | 20 ++ drivers/hwtracing/qcom/Makefile | 3 + drivers/hwtracing/qcom/tgu.c | 193 ++++++++++++++++++ drivers/hwtracing/qcom/tgu.h | 51 +++++ 7 files changed, 279 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-amba-devices-tgu create mode 100644 drivers/hwtracing/qcom/Kconfig create mode 100644 drivers/hwtracing/qcom/Makefile create mode 100644 drivers/hwtracing/qcom/tgu.c create mode 100644 drivers/hwtracing/qcom/tgu.h diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu new file mode 100644 index 0000000000000..f877a00fcaa58 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu @@ -0,0 +1,9 @@ +What: /sys/bus/amba/devices//enable_tgu +Date: April 2026 +KernelVersion: 7.1 +Contact: Jinlong Mao , Songwei Chai +Description: + (RW) Set/Get the enable/disable status of TGU + Accepts only one of the 2 values - 0 or 1. + 0 : disable TGU. + 1 : enable TGU. diff --git a/drivers/Makefile b/drivers/Makefile index 8e1ffa4358d5f..acade03f59425 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -176,6 +176,7 @@ obj-$(CONFIG_RAS) += ras/ obj-$(CONFIG_USB4) += thunderbolt/ obj-$(CONFIG_CORESIGHT) += hwtracing/coresight/ obj-y += hwtracing/intel_th/ +obj-y += hwtracing/qcom/ obj-$(CONFIG_STM) += hwtracing/stm/ obj-$(CONFIG_HISI_PTT) += hwtracing/ptt/ obj-y += android/ diff --git a/drivers/hwtracing/Kconfig b/drivers/hwtracing/Kconfig index 911ee977103c0..8a640218eed84 100644 --- a/drivers/hwtracing/Kconfig +++ b/drivers/hwtracing/Kconfig @@ -7,4 +7,6 @@ source "drivers/hwtracing/intel_th/Kconfig" source "drivers/hwtracing/ptt/Kconfig" +source "drivers/hwtracing/qcom/Kconfig" + endmenu diff --git a/drivers/hwtracing/qcom/Kconfig b/drivers/hwtracing/qcom/Kconfig new file mode 100644 index 0000000000000..5c94c75ffa396 --- /dev/null +++ b/drivers/hwtracing/qcom/Kconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# QCOM specific hwtracing drivers +# +menu "Qualcomm specific hwtracing drivers" + +config QCOM_TGU + tristate "QCOM Trigger Generation Unit driver" + depends on ARCH_QCOM || COMPILE_TEST + depends on ARM_AMBA + help + This driver provides support for Trigger Generation Unit that is + used to detect patterns or sequences on a given set of signals. + TGU is used to monitor a particular bus within a given region to + detect illegal transaction sequences or slave responses. It is also + used to monitor a data stream to detect protocol violations and to + provide a trigger point for centering data around a specific event + within the trace data buffer. + +endmenu diff --git a/drivers/hwtracing/qcom/Makefile b/drivers/hwtracing/qcom/Makefile new file mode 100644 index 0000000000000..5a0a868c1ea0d --- /dev/null +++ b/drivers/hwtracing/qcom/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_QCOM_TGU) += tgu.o diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c new file mode 100644 index 0000000000000..49c8f710b9318 --- /dev/null +++ b/drivers/hwtracing/qcom/tgu.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tgu.h" + +static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) +{ + TGU_UNLOCK(drvdata->base); + /* Enable TGU to program the triggers */ + writel(1, drvdata->base + TGU_CONTROL); + TGU_LOCK(drvdata->base); +} + +static int tgu_enable(struct device *dev) +{ + struct tgu_drvdata *drvdata = dev_get_drvdata(dev); + + guard(spinlock)(&drvdata->lock); + drvdata->enabled = true; + + tgu_write_all_hw_regs(drvdata); + + return 0; +} + +static void tgu_do_disable(struct tgu_drvdata *drvdata) +{ + TGU_UNLOCK(drvdata->base); + writel(0, drvdata->base + TGU_CONTROL); + TGU_LOCK(drvdata->base); + + drvdata->enabled = false; +} + +static void tgu_disable(struct device *dev) +{ + struct tgu_drvdata *drvdata = dev_get_drvdata(dev); + + guard(spinlock)(&drvdata->lock); + if (!drvdata->enabled) + return; + + tgu_do_disable(drvdata); +} + +static ssize_t enable_tgu_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tgu_drvdata *drvdata = dev_get_drvdata(dev); + bool enabled; + + guard(spinlock)(&drvdata->lock); + enabled = drvdata->enabled; + + return sysfs_emit(buf, "%d\n", !!enabled); +} + +/* enable_tgu_store - Configure Trace and Gating Unit (TGU) triggers. */ +static ssize_t enable_tgu_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tgu_drvdata *drvdata = dev_get_drvdata(dev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 0, &val); + if (ret || val > 1) + return -EINVAL; + + if (val) { + scoped_guard(spinlock, &drvdata->lock) { + if (drvdata->enabled) + return -EBUSY; + } + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + ret = tgu_enable(dev); + if (ret) { + pm_runtime_put(dev); + return ret; + } + } else { + scoped_guard(spinlock, &drvdata->lock) { + if (!drvdata->enabled) + return -EINVAL; + } + + tgu_disable(dev); + pm_runtime_put(dev); + } + + return size; +} +static DEVICE_ATTR_RW(enable_tgu); + +static struct attribute *tgu_common_attrs[] = { + &dev_attr_enable_tgu.attr, + NULL, +}; + +static const struct attribute_group tgu_common_grp = { + .attrs = tgu_common_attrs, + NULL, +}; + +static const struct attribute_group *tgu_attr_groups[] = { + &tgu_common_grp, + NULL, +}; + +static int tgu_probe(struct amba_device *adev, const struct amba_id *id) +{ + struct device *dev = &adev->dev; + struct tgu_drvdata *drvdata; + int ret; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->dev = &adev->dev; + dev_set_drvdata(dev, drvdata); + + drvdata->base = devm_ioremap_resource(dev, &adev->res); + if (IS_ERR(drvdata->base)) + return PTR_ERR(drvdata->base); + + spin_lock_init(&drvdata->lock); + + ret = sysfs_create_groups(&dev->kobj, tgu_attr_groups); + if (ret) { + dev_err(dev, "failed to create sysfs groups: %d\n", ret); + return ret; + } + + drvdata->enabled = false; + + pm_runtime_put(&adev->dev); + + return 0; +} + +static void tgu_remove(struct amba_device *adev) +{ + struct device *dev = &adev->dev; + + sysfs_remove_groups(&dev->kobj, tgu_attr_groups); + + tgu_disable(dev); +} + +static const struct amba_id tgu_ids[] = { + { + .id = 0x000f0e00, + .mask = 0x000fffff, + }, + { 0, 0, NULL }, +}; + +MODULE_DEVICE_TABLE(amba, tgu_ids); + +static struct amba_driver tgu_driver = { + .drv = { + .name = "qcom-tgu", + .suppress_bind_attrs = true, + }, + .probe = tgu_probe, + .remove = tgu_remove, + .id_table = tgu_ids, +}; + +module_amba_driver(tgu_driver); + +MODULE_AUTHOR("Songwei Chai "); +MODULE_AUTHOR("Jinlong Mao "); +MODULE_DESCRIPTION("Qualcomm Trigger Generation Unit driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h new file mode 100644 index 0000000000000..dd7533b9d7350 --- /dev/null +++ b/drivers/hwtracing/qcom/tgu.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _QCOM_TGU_H +#define _QCOM_TGU_H + +/* Register addresses */ +#define TGU_CONTROL 0x0000 +#define TGU_LAR 0xfb0 +#define TGU_UNLOCK_OFFSET 0xc5acce55 + +static inline void TGU_LOCK(void __iomem *addr) +{ + do { + /* Wait for things to settle */ + mb(); + writel_relaxed(0x0, addr + TGU_LAR); + } while (0); +} + +static inline void TGU_UNLOCK(void __iomem *addr) +{ + do { + writel_relaxed(TGU_UNLOCK_OFFSET, addr + TGU_LAR); + /* Make sure everyone has seen this */ + mb(); + } while (0); +} + +/** + * struct tgu_drvdata - Data structure for a TGU (Trigger Generator Unit) + * @base: Memory-mapped base address of the TGU device + * @dev: Pointer to the associated device structure + * @lock: Spinlock for handling concurrent access to private data + * @enabled: Flag indicating whether the TGU device is enabled + * + * This structure defines the data associated with a TGU device, + * including its base address, device pointers, clock, spinlock for + * synchronization, trigger data pointers, maximum limits for various + * trigger-related parameters, and enable status. + */ +struct tgu_drvdata { + void __iomem *base; + struct device *dev; + spinlock_t lock; + bool enabled; +}; + +#endif From b422e97b8dafd3e620e1bddf9d935ee52c1c72a3 Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Fri, 17 Apr 2026 00:33:32 -0700 Subject: [PATCH 10/15] FROMLIST: qcom-tgu: Add signal priority support Like circuit of a Logic analyzer, in TGU, the requirement could be configured in each step and the trigger will be created once the requirements are met. Add priority functionality here to sort the signals into different priorities. The signal which is wanted could be configured in each step's priority node, the larger number means the higher priority and the signal with higher priority will be sensed more preferentially. Link: https://lore.kernel.org/all/20260417073336.2712426-4-songwei.chai@oss.qualcomm.com/ Reviewed-by: Jie Gan Signed-off-by: Songwei Chai --- .../ABI/testing/sysfs-bus-amba-devices-tgu | 7 + drivers/hwtracing/qcom/tgu.c | 161 ++++++++++++++++++ drivers/hwtracing/qcom/tgu.h | 114 +++++++++++++ 3 files changed, 282 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu index f877a00fcaa58..223873789ca61 100644 --- a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu @@ -7,3 +7,10 @@ Description: Accepts only one of the 2 values - 0 or 1. 0 : disable TGU. 1 : enable TGU. + +What: /sys/bus/amba/devices//step[0:7]_priority[0:3]/reg[0:17] +Date: April 2026 +KernelVersion: 7.1 +Contact: Jinlong Mao , Songwei Chai +Description: + (RW) Set/Get the sensed signal with specific step and priority for TGU. diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c index 49c8f710b9318..7d69986c3e3d2 100644 --- a/drivers/hwtracing/qcom/tgu.c +++ b/drivers/hwtracing/qcom/tgu.c @@ -14,14 +14,123 @@ #include "tgu.h" +static int calculate_array_location(struct tgu_drvdata *drvdata, + int step_index, int operation_index, + int reg_index) +{ + return operation_index * (drvdata->num_step) * (drvdata->num_reg) + + step_index * (drvdata->num_reg) + reg_index; +} + +static ssize_t tgu_dataset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tgu_drvdata *drvdata = dev_get_drvdata(dev); + struct tgu_attribute *tgu_attr = + container_of(attr, struct tgu_attribute, attr); + int index; + + index = calculate_array_location(drvdata, tgu_attr->step_index, + tgu_attr->operation_index, + tgu_attr->reg_num); + + return sysfs_emit(buf, "0x%x\n", + drvdata->value_table->priority[index]); +} + +static ssize_t tgu_dataset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tgu_drvdata *tgu_drvdata = dev_get_drvdata(dev); + struct tgu_attribute *tgu_attr = + container_of(attr, struct tgu_attribute, attr); + unsigned long val; + int index; + int ret; + + ret = kstrtoul(buf, 0, &val); + if (ret) + return ret; + + guard(spinlock)(&tgu_drvdata->lock); + index = calculate_array_location(tgu_drvdata, tgu_attr->step_index, + tgu_attr->operation_index, + tgu_attr->reg_num); + + tgu_drvdata->value_table->priority[index] = val; + + return size; +} + +static umode_t tgu_node_visible(struct kobject *kobject, + struct attribute *attr, + int n) +{ + struct device *dev = kobj_to_dev(kobject); + struct tgu_drvdata *drvdata = dev_get_drvdata(dev); + struct device_attribute *dev_attr = + container_of(attr, struct device_attribute, attr); + struct tgu_attribute *tgu_attr = + container_of(dev_attr, struct tgu_attribute, attr); + + if (tgu_attr->step_index >= drvdata->num_step) + return SYSFS_GROUP_INVISIBLE; + + if (tgu_attr->reg_num >= drvdata->num_reg) + return 0; + + return attr->mode; +} + static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) { + int i, j, k, index; + TGU_UNLOCK(drvdata->base); + for (i = 0; i < drvdata->num_step; i++) { + for (j = 0; j < MAX_PRIORITY; j++) { + for (k = 0; k < drvdata->num_reg; k++) { + index = calculate_array_location( + drvdata, i, j, k); + + writel(drvdata->value_table->priority[index], + drvdata->base + + PRIORITY_REG_STEP(i, j, k)); + } + } + } /* Enable TGU to program the triggers */ writel(1, drvdata->base + TGU_CONTROL); TGU_LOCK(drvdata->base); } +static void tgu_set_reg_number(struct tgu_drvdata *drvdata) +{ + int num_sense_input; + int num_reg; + u32 devid; + + devid = readl(drvdata->base + TGU_DEVID); + + num_sense_input = TGU_DEVID_SENSE_INPUT(devid); + num_reg = (num_sense_input * TGU_BITS_PER_SIGNAL) / LENGTH_REGISTER; + + if ((num_sense_input * TGU_BITS_PER_SIGNAL) % LENGTH_REGISTER) + num_reg++; + + drvdata->num_reg = num_reg; +} + +static void tgu_set_steps(struct tgu_drvdata *drvdata) +{ + u32 devid; + + devid = readl(drvdata->base + TGU_DEVID); + + drvdata->num_step = TGU_DEVID_STEPS(devid); +} + static int tgu_enable(struct device *dev) { struct tgu_drvdata *drvdata = dev_get_drvdata(dev); @@ -121,6 +230,38 @@ static const struct attribute_group tgu_common_grp = { static const struct attribute_group *tgu_attr_groups[] = { &tgu_common_grp, + PRIORITY_ATTRIBUTE_GROUP_INIT(0, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(0, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(0, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(0, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(1, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(1, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(1, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(1, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(2, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(2, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(2, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(2, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(3, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(3, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(3, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(3, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(4, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(4, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(4, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(4, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(5, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(5, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(5, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(5, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(6, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(6, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(6, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(6, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(7, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(7, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(7, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(7, 3), NULL, }; @@ -128,6 +269,8 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; struct tgu_drvdata *drvdata; + unsigned int *priority; + size_t priority_size; int ret; drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); @@ -143,12 +286,30 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&drvdata->lock); + tgu_set_reg_number(drvdata); + tgu_set_steps(drvdata); + ret = sysfs_create_groups(&dev->kobj, tgu_attr_groups); if (ret) { dev_err(dev, "failed to create sysfs groups: %d\n", ret); return ret; } + drvdata->value_table = + devm_kzalloc(dev, sizeof(*drvdata->value_table), GFP_KERNEL); + if (!drvdata->value_table) + return -ENOMEM; + + priority_size = MAX_PRIORITY * drvdata->num_reg * drvdata->num_step; + + priority = devm_kcalloc(dev, priority_size, + sizeof(*drvdata->value_table->priority), + GFP_KERNEL); + if (!priority) + return -ENOMEM; + + drvdata->value_table->priority = priority; + drvdata->enabled = false; pm_runtime_put(&adev->dev); diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h index dd7533b9d7350..f994d83acb1d6 100644 --- a/drivers/hwtracing/qcom/tgu.h +++ b/drivers/hwtracing/qcom/tgu.h @@ -10,6 +10,114 @@ #define TGU_CONTROL 0x0000 #define TGU_LAR 0xfb0 #define TGU_UNLOCK_OFFSET 0xc5acce55 +#define TGU_DEVID 0xfc8 + +#define TGU_DEVID_SENSE_INPUT(devid_val) \ + ((int)FIELD_GET(GENMASK(17, 10), devid_val)) +#define TGU_DEVID_STEPS(devid_val) \ + ((int)FIELD_GET(GENMASK(6, 3), devid_val)) +#define TGU_BITS_PER_SIGNAL 4 +#define LENGTH_REGISTER 32 + +/* + * TGU configuration space Step configuration + * offset table space layout + * x-------------------------x$ x-------------x$ + * | |$ | |$ + * | | | reserve |$ + * | | | |$ + * |coresight management | |-------------|base+n*0x1D8+0x1F4$ + * | registers | |---> |priority[3] |$ + * | | | |-------------|base+n*0x1D8+0x194$ + * | | | |priority[2] |$ + * |-------------------------| | |-------------|base+n*0x1D8+0x134$ + * | | | |priority[1] |$ + * | step[7] | | |-------------|base+n*0x1D8+0xD4$ + * |-------------------------|->base+0x40+7*0x1D8 | |priority[0] |$ + * | | | |-------------|base+n*0x1D8+0x74$ + * | ... | | | condition |$ + * | | | | select |$ + * |-------------------------|->base+0x40+1*0x1D8 | |-------------|base+n*0x1D8+0x60$ + * | | | | condition |$ + * | step[0] |--------------------> | decode |$ + * |-------------------------|-> base+0x40 |-------------|base+n*0x1D8+0x50$ + * | | | |$ + * | Control and status space| |Timer/Counter|$ + * | space | | |$ + * x-------------------------x->base x-------------x base+n*0x1D8+0x40$ + * + */ +#define STEP_OFFSET 0x1D8 +#define PRIORITY_START_OFFSET 0x0074 +#define PRIORITY_OFFSET 0x60 +#define REG_OFFSET 0x4 + +/* Calculate compare step addresses */ +#define PRIORITY_REG_STEP(step, priority, reg)\ + (PRIORITY_START_OFFSET + PRIORITY_OFFSET * priority +\ + REG_OFFSET * reg + STEP_OFFSET * step) + +#define tgu_dataset_rw(name, step_index, type, reg_num) \ + (&((struct tgu_attribute[]){ { \ + __ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \ + step_index, \ + type, \ + reg_num, \ + } })[0].attr.attr) + +#define STEP_PRIORITY(step_index, reg_num, priority) \ + tgu_dataset_rw(reg##reg_num, step_index, TGU_PRIORITY##priority, \ + reg_num) + +#define STEP_PRIORITY_LIST(step_index, priority) \ + {STEP_PRIORITY(step_index, 0, priority), \ + STEP_PRIORITY(step_index, 1, priority), \ + STEP_PRIORITY(step_index, 2, priority), \ + STEP_PRIORITY(step_index, 3, priority), \ + STEP_PRIORITY(step_index, 4, priority), \ + STEP_PRIORITY(step_index, 5, priority), \ + STEP_PRIORITY(step_index, 6, priority), \ + STEP_PRIORITY(step_index, 7, priority), \ + STEP_PRIORITY(step_index, 8, priority), \ + STEP_PRIORITY(step_index, 9, priority), \ + STEP_PRIORITY(step_index, 10, priority), \ + STEP_PRIORITY(step_index, 11, priority), \ + STEP_PRIORITY(step_index, 12, priority), \ + STEP_PRIORITY(step_index, 13, priority), \ + STEP_PRIORITY(step_index, 14, priority), \ + STEP_PRIORITY(step_index, 15, priority), \ + STEP_PRIORITY(step_index, 16, priority), \ + STEP_PRIORITY(step_index, 17, priority), \ + NULL \ + } + +#define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\ + (&(const struct attribute_group){\ + .attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\ + .is_visible = tgu_node_visible,\ + .name = "step" #step "_priority" #priority \ + }) + +enum operation_index { + TGU_PRIORITY0, + TGU_PRIORITY1, + TGU_PRIORITY2, + TGU_PRIORITY3, +}; + +/* Maximum priority that TGU supports */ +#define MAX_PRIORITY 4 + +struct tgu_attribute { + struct device_attribute attr; + u32 step_index; + enum operation_index operation_index; + u32 reg_num; +}; + +struct value_table { + unsigned int *priority; +}; static inline void TGU_LOCK(void __iomem *addr) { @@ -35,6 +143,9 @@ static inline void TGU_UNLOCK(void __iomem *addr) * @dev: Pointer to the associated device structure * @lock: Spinlock for handling concurrent access to private data * @enabled: Flag indicating whether the TGU device is enabled + * @value_table: Store given value based on relevant parameters + * @num_reg: Maximum number of registers + * @num_step: Maximum step size * * This structure defines the data associated with a TGU device, * including its base address, device pointers, clock, spinlock for @@ -46,6 +157,9 @@ struct tgu_drvdata { struct device *dev; spinlock_t lock; bool enabled; + struct value_table *value_table; + int num_reg; + int num_step; }; #endif From 35c65a210ce0fb768d50275e2bc0addb88c205e0 Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Fri, 17 Apr 2026 00:33:33 -0700 Subject: [PATCH 11/15] FROMLIST: qcom-tgu: Add TGU decode support Decoding is when all the potential pieces for creating a trigger are brought together for a given step. Example - there may be a counter keeping track of some occurrences and a priority-group that is being used to detect a pattern on the sense inputs. These 2 inputs to condition_decode must be programmed, for a given step, to establish the condition for the trigger, or movement to another steps. Link: https://lore.kernel.org/all/20260417073336.2712426-5-songwei.chai@oss.qualcomm.com/ Reviewed-by: Jie Gan Signed-off-by: Songwei Chai --- .../ABI/testing/sysfs-bus-amba-devices-tgu | 7 + drivers/hwtracing/qcom/tgu.c | 157 +++++++++++++++--- drivers/hwtracing/qcom/tgu.h | 27 +++ 3 files changed, 170 insertions(+), 21 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu index 223873789ca61..4ef0d696d3d0e 100644 --- a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu @@ -14,3 +14,10 @@ KernelVersion: 7.1 Contact: Jinlong Mao , Songwei Chai Description: (RW) Set/Get the sensed signal with specific step and priority for TGU. + +What: /sys/bus/amba/devices//step[0:7]_condition_decode/reg[0:3] +Date: April 2026 +KernelVersion: 7.1 +Contact: Jinlong Mao , Songwei Chai +Description: + (RW) Set/Get the decode mode with specific step for TGU. diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c index 7d69986c3e3d2..937211923d937 100644 --- a/drivers/hwtracing/qcom/tgu.c +++ b/drivers/hwtracing/qcom/tgu.c @@ -18,8 +18,33 @@ static int calculate_array_location(struct tgu_drvdata *drvdata, int step_index, int operation_index, int reg_index) { - return operation_index * (drvdata->num_step) * (drvdata->num_reg) + - step_index * (drvdata->num_reg) + reg_index; + switch (operation_index) { + case TGU_PRIORITY0: + case TGU_PRIORITY1: + case TGU_PRIORITY2: + case TGU_PRIORITY3: + return operation_index * (drvdata->num_step) * + (drvdata->num_reg) + + step_index * (drvdata->num_reg) + reg_index; + case TGU_CONDITION_DECODE: + return step_index * (drvdata->num_condition_decode) + + reg_index; + default: + break; + } + + return -EINVAL; +} + +static int check_array_location(struct tgu_drvdata *drvdata, int step, + int ops, int reg) +{ + int result = calculate_array_location(drvdata, step, ops, reg); + + if (result == -EINVAL) + dev_err(drvdata->dev, "check array location - Fail\n"); + + return result; } static ssize_t tgu_dataset_show(struct device *dev, @@ -30,12 +55,26 @@ static ssize_t tgu_dataset_show(struct device *dev, container_of(attr, struct tgu_attribute, attr); int index; - index = calculate_array_location(drvdata, tgu_attr->step_index, - tgu_attr->operation_index, - tgu_attr->reg_num); - - return sysfs_emit(buf, "0x%x\n", - drvdata->value_table->priority[index]); + index = check_array_location(drvdata, tgu_attr->step_index, + tgu_attr->operation_index, tgu_attr->reg_num); + + if (index == -EINVAL) + return index; + + switch (tgu_attr->operation_index) { + case TGU_PRIORITY0: + case TGU_PRIORITY1: + case TGU_PRIORITY2: + case TGU_PRIORITY3: + return sysfs_emit(buf, "0x%x\n", + drvdata->value_table->priority[index]); + case TGU_CONDITION_DECODE: + return sysfs_emit(buf, "0x%x\n", + drvdata->value_table->condition_decode[index]); + default: + break; + } + return -EINVAL; } static ssize_t tgu_dataset_store(struct device *dev, @@ -54,13 +93,31 @@ static ssize_t tgu_dataset_store(struct device *dev, return ret; guard(spinlock)(&tgu_drvdata->lock); - index = calculate_array_location(tgu_drvdata, tgu_attr->step_index, + index = check_array_location(tgu_drvdata, tgu_attr->step_index, tgu_attr->operation_index, tgu_attr->reg_num); - tgu_drvdata->value_table->priority[index] = val; + if (index == -EINVAL) + return index; + + switch (tgu_attr->operation_index) { + case TGU_PRIORITY0: + case TGU_PRIORITY1: + case TGU_PRIORITY2: + case TGU_PRIORITY3: + tgu_drvdata->value_table->priority[index] = val; + ret = size; + break; + case TGU_CONDITION_DECODE: + tgu_drvdata->value_table->condition_decode[index] = val; + ret = size; + break; + default: + ret = -EINVAL; + break; + } - return size; + return ret; } static umode_t tgu_node_visible(struct kobject *kobject, @@ -77,13 +134,26 @@ static umode_t tgu_node_visible(struct kobject *kobject, if (tgu_attr->step_index >= drvdata->num_step) return SYSFS_GROUP_INVISIBLE; - if (tgu_attr->reg_num >= drvdata->num_reg) - return 0; + switch (tgu_attr->operation_index) { + case TGU_PRIORITY0: + case TGU_PRIORITY1: + case TGU_PRIORITY2: + case TGU_PRIORITY3: + if (tgu_attr->reg_num < drvdata->num_reg) + return attr->mode; + break; + case TGU_CONDITION_DECODE: + if (tgu_attr->reg_num < drvdata->num_condition_decode) + return attr->mode; + break; + default: + break; + } - return attr->mode; + return 0; } -static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) +static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) { int i, j, k, index; @@ -91,8 +161,10 @@ static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) for (i = 0; i < drvdata->num_step; i++) { for (j = 0; j < MAX_PRIORITY; j++) { for (k = 0; k < drvdata->num_reg; k++) { - index = calculate_array_location( + index = check_array_location( drvdata, i, j, k); + if (index == -EINVAL) + goto exit; writel(drvdata->value_table->priority[index], drvdata->base + @@ -100,9 +172,23 @@ static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) } } } + + for (i = 0; i < drvdata->num_step; i++) { + for (j = 0; j < drvdata->num_condition_decode; j++) { + index = check_array_location(drvdata, i, + TGU_CONDITION_DECODE, j); + if (index == -EINVAL) + goto exit; + + writel(drvdata->value_table->condition_decode[index], + drvdata->base + CONDITION_DECODE_STEP(i, j)); + } + } /* Enable TGU to program the triggers */ writel(1, drvdata->base + TGU_CONTROL); +exit: TGU_LOCK(drvdata->base); + return index >= 0 ? 0 : -EINVAL; } static void tgu_set_reg_number(struct tgu_drvdata *drvdata) @@ -131,16 +217,26 @@ static void tgu_set_steps(struct tgu_drvdata *drvdata) drvdata->num_step = TGU_DEVID_STEPS(devid); } +static void tgu_set_conditions(struct tgu_drvdata *drvdata) +{ + u32 devid; + + devid = readl(drvdata->base + TGU_DEVID); + drvdata->num_condition_decode = TGU_DEVID_CONDITIONS(devid); +} + static int tgu_enable(struct device *dev) { struct tgu_drvdata *drvdata = dev_get_drvdata(dev); + int ret; guard(spinlock)(&drvdata->lock); - drvdata->enabled = true; - tgu_write_all_hw_regs(drvdata); + ret = tgu_write_all_hw_regs(drvdata); + if (!ret) + drvdata->enabled = true; - return 0; + return ret; } static void tgu_do_disable(struct tgu_drvdata *drvdata) @@ -262,6 +358,14 @@ static const struct attribute_group *tgu_attr_groups[] = { PRIORITY_ATTRIBUTE_GROUP_INIT(7, 1), PRIORITY_ATTRIBUTE_GROUP_INIT(7, 2), PRIORITY_ATTRIBUTE_GROUP_INIT(7, 3), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(0), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(1), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(2), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(3), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(4), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(5), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(6), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(7), NULL, }; @@ -269,8 +373,8 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; struct tgu_drvdata *drvdata; - unsigned int *priority; - size_t priority_size; + unsigned int *priority, *condition; + size_t priority_size, condition_size; int ret; drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); @@ -288,6 +392,7 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) tgu_set_reg_number(drvdata); tgu_set_steps(drvdata); + tgu_set_conditions(drvdata); ret = sysfs_create_groups(&dev->kobj, tgu_attr_groups); if (ret) { @@ -310,6 +415,16 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) drvdata->value_table->priority = priority; + condition_size = drvdata->num_condition_decode * drvdata->num_step; + + condition = devm_kcalloc(dev, condition_size, + sizeof(*(drvdata->value_table->condition_decode)), + GFP_KERNEL); + if (!condition) + return -ENOMEM; + + drvdata->value_table->condition_decode = condition; + drvdata->enabled = false; pm_runtime_put(&adev->dev); diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h index f994d83acb1d6..56e4161a8bc21 100644 --- a/drivers/hwtracing/qcom/tgu.h +++ b/drivers/hwtracing/qcom/tgu.h @@ -16,6 +16,8 @@ ((int)FIELD_GET(GENMASK(17, 10), devid_val)) #define TGU_DEVID_STEPS(devid_val) \ ((int)FIELD_GET(GENMASK(6, 3), devid_val)) +#define TGU_DEVID_CONDITIONS(devid_val) \ + ((int)FIELD_GET(GENMASK(2, 0), devid_val)) #define TGU_BITS_PER_SIGNAL 4 #define LENGTH_REGISTER 32 @@ -49,6 +51,7 @@ */ #define STEP_OFFSET 0x1D8 #define PRIORITY_START_OFFSET 0x0074 +#define CONDITION_DECODE_OFFSET 0x0050 #define PRIORITY_OFFSET 0x60 #define REG_OFFSET 0x4 @@ -57,6 +60,9 @@ (PRIORITY_START_OFFSET + PRIORITY_OFFSET * priority +\ REG_OFFSET * reg + STEP_OFFSET * step) +#define CONDITION_DECODE_STEP(step, decode) \ + (CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step) + #define tgu_dataset_rw(name, step_index, type, reg_num) \ (&((struct tgu_attribute[]){ { \ __ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \ @@ -68,6 +74,8 @@ #define STEP_PRIORITY(step_index, reg_num, priority) \ tgu_dataset_rw(reg##reg_num, step_index, TGU_PRIORITY##priority, \ reg_num) +#define STEP_DECODE(step_index, reg_num) \ + tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_DECODE, reg_num) #define STEP_PRIORITY_LIST(step_index, priority) \ {STEP_PRIORITY(step_index, 0, priority), \ @@ -91,6 +99,14 @@ NULL \ } +#define STEP_DECODE_LIST(n) \ + {STEP_DECODE(n, 0), \ + STEP_DECODE(n, 1), \ + STEP_DECODE(n, 2), \ + STEP_DECODE(n, 3), \ + NULL \ + } + #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\ (&(const struct attribute_group){\ .attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\ @@ -98,11 +114,19 @@ .name = "step" #step "_priority" #priority \ }) +#define CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(step)\ + (&(const struct attribute_group){\ + .attrs = (struct attribute*[])STEP_DECODE_LIST(step),\ + .is_visible = tgu_node_visible,\ + .name = "step" #step "_condition_decode" \ + }) + enum operation_index { TGU_PRIORITY0, TGU_PRIORITY1, TGU_PRIORITY2, TGU_PRIORITY3, + TGU_CONDITION_DECODE, }; /* Maximum priority that TGU supports */ @@ -117,6 +141,7 @@ struct tgu_attribute { struct value_table { unsigned int *priority; + unsigned int *condition_decode; }; static inline void TGU_LOCK(void __iomem *addr) @@ -146,6 +171,7 @@ static inline void TGU_UNLOCK(void __iomem *addr) * @value_table: Store given value based on relevant parameters * @num_reg: Maximum number of registers * @num_step: Maximum step size + * @num_condition_decode: Maximum number of condition_decode * * This structure defines the data associated with a TGU device, * including its base address, device pointers, clock, spinlock for @@ -160,6 +186,7 @@ struct tgu_drvdata { struct value_table *value_table; int num_reg; int num_step; + int num_condition_decode; }; #endif From 55bd3610928e1be6eae04f76ec82d0794e539681 Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Fri, 17 Apr 2026 00:33:34 -0700 Subject: [PATCH 12/15] FROMLIST: qcom-tgu: Add support to configure next action Add "select" node for each step to determine if another step is taken, trigger(s) are generated, counters/timers incremented/decremented, etc. Link: https://lore.kernel.org/all/20260417073336.2712426-6-songwei.chai@oss.qualcomm.com/ Reviewed-by: Jie Gan Signed-off-by: Songwei Chai --- .../ABI/testing/sysfs-bus-amba-devices-tgu | 7 +++ drivers/hwtracing/qcom/tgu.c | 53 ++++++++++++++++++- drivers/hwtracing/qcom/tgu.h | 26 +++++++++ 3 files changed, 84 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu index 4ef0d696d3d0e..786cb852bbe51 100644 --- a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu @@ -21,3 +21,10 @@ KernelVersion: 7.1 Contact: Jinlong Mao , Songwei Chai Description: (RW) Set/Get the decode mode with specific step for TGU. + +What: /sys/bus/amba/devices//step[0:7]_condition_select/reg[0:3] +Date: April 2026 +KernelVersion: 7.1 +Contact: Jinlong Mao , Songwei Chai +Description: + (RW) Set/Get the next action with specific step for TGU. diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c index 937211923d937..fefe932059cbb 100644 --- a/drivers/hwtracing/qcom/tgu.c +++ b/drivers/hwtracing/qcom/tgu.c @@ -29,6 +29,9 @@ static int calculate_array_location(struct tgu_drvdata *drvdata, case TGU_CONDITION_DECODE: return step_index * (drvdata->num_condition_decode) + reg_index; + case TGU_CONDITION_SELECT: + return step_index * (drvdata->num_condition_select) + + reg_index; default: break; } @@ -71,6 +74,9 @@ static ssize_t tgu_dataset_show(struct device *dev, case TGU_CONDITION_DECODE: return sysfs_emit(buf, "0x%x\n", drvdata->value_table->condition_decode[index]); + case TGU_CONDITION_SELECT: + return sysfs_emit(buf, "0x%x\n", + drvdata->value_table->condition_select[index]); default: break; } @@ -112,6 +118,10 @@ static ssize_t tgu_dataset_store(struct device *dev, tgu_drvdata->value_table->condition_decode[index] = val; ret = size; break; + case TGU_CONDITION_SELECT: + tgu_drvdata->value_table->condition_select[index] = val; + ret = size; + break; default: ret = -EINVAL; break; @@ -146,6 +156,13 @@ static umode_t tgu_node_visible(struct kobject *kobject, if (tgu_attr->reg_num < drvdata->num_condition_decode) return attr->mode; break; + case TGU_CONDITION_SELECT: + /* 'default' register is at the end of 'select' region */ + if (tgu_attr->reg_num == drvdata->num_condition_select - 1) + attr->name = "default"; + if (tgu_attr->reg_num < drvdata->num_condition_select) + return attr->mode; + break; default: break; } @@ -184,6 +201,18 @@ static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) drvdata->base + CONDITION_DECODE_STEP(i, j)); } } + + for (i = 0; i < drvdata->num_step; i++) { + for (j = 0; j < drvdata->num_condition_select; j++) { + index = check_array_location(drvdata, i, + TGU_CONDITION_SELECT, j); + if (index == -EINVAL) + goto exit; + + writel(drvdata->value_table->condition_select[index], + drvdata->base + CONDITION_SELECT_STEP(i, j)); + } + } /* Enable TGU to program the triggers */ writel(1, drvdata->base + TGU_CONTROL); exit: @@ -223,6 +252,8 @@ static void tgu_set_conditions(struct tgu_drvdata *drvdata) devid = readl(drvdata->base + TGU_DEVID); drvdata->num_condition_decode = TGU_DEVID_CONDITIONS(devid); + /* select region has an additional 'default' register */ + drvdata->num_condition_select = TGU_DEVID_CONDITIONS(devid) + 1; } static int tgu_enable(struct device *dev) @@ -366,6 +397,14 @@ static const struct attribute_group *tgu_attr_groups[] = { CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(5), CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(6), CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(7), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(0), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(1), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(2), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(3), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(4), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(5), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(6), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(7), NULL, }; @@ -373,8 +412,8 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; struct tgu_drvdata *drvdata; - unsigned int *priority, *condition; - size_t priority_size, condition_size; + unsigned int *priority, *condition, *select; + size_t priority_size, condition_size, select_size; int ret; drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); @@ -425,6 +464,16 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) drvdata->value_table->condition_decode = condition; + select_size = drvdata->num_condition_select * drvdata->num_step; + + select = devm_kcalloc(dev, select_size, + sizeof(*(drvdata->value_table->condition_select)), + GFP_KERNEL); + if (!select) + return -ENOMEM; + + drvdata->value_table->condition_select = select; + drvdata->enabled = false; pm_runtime_put(&adev->dev); diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h index 56e4161a8bc21..c61aa8dc51b0d 100644 --- a/drivers/hwtracing/qcom/tgu.h +++ b/drivers/hwtracing/qcom/tgu.h @@ -52,6 +52,7 @@ #define STEP_OFFSET 0x1D8 #define PRIORITY_START_OFFSET 0x0074 #define CONDITION_DECODE_OFFSET 0x0050 +#define CONDITION_SELECT_OFFSET 0x0060 #define PRIORITY_OFFSET 0x60 #define REG_OFFSET 0x4 @@ -63,6 +64,9 @@ #define CONDITION_DECODE_STEP(step, decode) \ (CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step) +#define CONDITION_SELECT_STEP(step, select) \ + (CONDITION_SELECT_OFFSET + REG_OFFSET * select + STEP_OFFSET * step) + #define tgu_dataset_rw(name, step_index, type, reg_num) \ (&((struct tgu_attribute[]){ { \ __ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \ @@ -76,6 +80,8 @@ reg_num) #define STEP_DECODE(step_index, reg_num) \ tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_DECODE, reg_num) +#define STEP_SELECT(step_index, reg_num) \ + tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_SELECT, reg_num) #define STEP_PRIORITY_LIST(step_index, priority) \ {STEP_PRIORITY(step_index, 0, priority), \ @@ -107,6 +113,15 @@ NULL \ } +#define STEP_SELECT_LIST(n) \ + {STEP_SELECT(n, 0), \ + STEP_SELECT(n, 1), \ + STEP_SELECT(n, 2), \ + STEP_SELECT(n, 3), \ + STEP_SELECT(n, 4), \ + NULL \ + } + #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\ (&(const struct attribute_group){\ .attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\ @@ -121,12 +136,20 @@ .name = "step" #step "_condition_decode" \ }) +#define CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(step)\ + (&(const struct attribute_group){\ + .attrs = (struct attribute*[])STEP_SELECT_LIST(step),\ + .is_visible = tgu_node_visible,\ + .name = "step" #step "_condition_select" \ + }) + enum operation_index { TGU_PRIORITY0, TGU_PRIORITY1, TGU_PRIORITY2, TGU_PRIORITY3, TGU_CONDITION_DECODE, + TGU_CONDITION_SELECT, }; /* Maximum priority that TGU supports */ @@ -142,6 +165,7 @@ struct tgu_attribute { struct value_table { unsigned int *priority; unsigned int *condition_decode; + unsigned int *condition_select; }; static inline void TGU_LOCK(void __iomem *addr) @@ -172,6 +196,7 @@ static inline void TGU_UNLOCK(void __iomem *addr) * @num_reg: Maximum number of registers * @num_step: Maximum step size * @num_condition_decode: Maximum number of condition_decode + * @num_condition_select: Maximum number of condition_select * * This structure defines the data associated with a TGU device, * including its base address, device pointers, clock, spinlock for @@ -187,6 +212,7 @@ struct tgu_drvdata { int num_reg; int num_step; int num_condition_decode; + int num_condition_select; }; #endif From 6a071d1853be58c3c94030b7d4b729e34c7d7e1e Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Fri, 17 Apr 2026 00:33:35 -0700 Subject: [PATCH 13/15] FROMLIST: qcom-tgu: Add timer/counter functionality for TGU Add counter and timer node for each step which could be programed if they are to be utilized in trigger event/sequence. Link: https://lore.kernel.org/all/20260417073336.2712426-7-songwei.chai@oss.qualcomm.com/ Reviewed-by: Jie Gan Signed-off-by: Songwei Chai --- .../ABI/testing/sysfs-bus-amba-devices-tgu | 14 +++ drivers/hwtracing/qcom/tgu.c | 116 +++++++++++++++++- drivers/hwtracing/qcom/tgu.h | 57 +++++++++ 3 files changed, 185 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu index 786cb852bbe51..7a3573e03e27d 100644 --- a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu @@ -28,3 +28,17 @@ KernelVersion: 7.1 Contact: Jinlong Mao , Songwei Chai Description: (RW) Set/Get the next action with specific step for TGU. + +What: /sys/bus/amba/devices//step[0:7]_timer/reg[0:1] +Date: April 2026 +KernelVersion: 7.1 +Contact: Jinlong Mao , Songwei Chai +Description: + (RW) Set/Get the timer value with specific step for TGU. + +What: /sys/bus/amba/devices//step[0:7]_counter/reg[0:1] +Date: April 2026 +KernelVersion: 7.1 +Contact: Jinlong Mao , Songwei Chai +Description: + (RW) Set/Get the counter value with specific step for TGU. diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c index fefe932059cbb..6d5bf2621cb05 100644 --- a/drivers/hwtracing/qcom/tgu.c +++ b/drivers/hwtracing/qcom/tgu.c @@ -32,6 +32,10 @@ static int calculate_array_location(struct tgu_drvdata *drvdata, case TGU_CONDITION_SELECT: return step_index * (drvdata->num_condition_select) + reg_index; + case TGU_COUNTER: + return step_index * (drvdata->num_counter) + reg_index; + case TGU_TIMER: + return step_index * (drvdata->num_timer) + reg_index; default: break; } @@ -77,6 +81,12 @@ static ssize_t tgu_dataset_show(struct device *dev, case TGU_CONDITION_SELECT: return sysfs_emit(buf, "0x%x\n", drvdata->value_table->condition_select[index]); + case TGU_TIMER: + return sysfs_emit(buf, "0x%x\n", + drvdata->value_table->timer[index]); + case TGU_COUNTER: + return sysfs_emit(buf, "0x%x\n", + drvdata->value_table->counter[index]); default: break; } @@ -122,6 +132,14 @@ static ssize_t tgu_dataset_store(struct device *dev, tgu_drvdata->value_table->condition_select[index] = val; ret = size; break; + case TGU_TIMER: + tgu_drvdata->value_table->timer[index] = val; + ret = size; + break; + case TGU_COUNTER: + tgu_drvdata->value_table->counter[index] = val; + ret = size; + break; default: ret = -EINVAL; break; @@ -163,6 +181,18 @@ static umode_t tgu_node_visible(struct kobject *kobject, if (tgu_attr->reg_num < drvdata->num_condition_select) return attr->mode; break; + case TGU_COUNTER: + if (!drvdata->num_counter) + break; + if (tgu_attr->reg_num < drvdata->num_counter) + return attr->mode; + break; + case TGU_TIMER: + if (!drvdata->num_timer) + break; + if (tgu_attr->reg_num < drvdata->num_timer) + return attr->mode; + break; default: break; } @@ -213,6 +243,30 @@ static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) drvdata->base + CONDITION_SELECT_STEP(i, j)); } } + + for (i = 0; i < drvdata->num_step; i++) { + for (j = 0; j < drvdata->num_timer; j++) { + index = check_array_location(drvdata, i, TGU_TIMER, j); + + if (index == -EINVAL) + goto exit; + + writel(drvdata->value_table->timer[index], + drvdata->base + TIMER_COMPARE_STEP(i, j)); + } + } + + for (i = 0; i < drvdata->num_step; i++) { + for (j = 0; j < drvdata->num_counter; j++) { + index = check_array_location(drvdata, i, TGU_COUNTER, j); + + if (index == -EINVAL) + goto exit; + + writel(drvdata->value_table->counter[index], + drvdata->base + COUNTER_COMPARE_STEP(i, j)); + } + } /* Enable TGU to program the triggers */ writel(1, drvdata->base + TGU_CONTROL); exit: @@ -256,6 +310,27 @@ static void tgu_set_conditions(struct tgu_drvdata *drvdata) drvdata->num_condition_select = TGU_DEVID_CONDITIONS(devid) + 1; } +static void tgu_set_timer_counter(struct tgu_drvdata *drvdata) +{ + int num_timers = 0, num_counters = 0; + u32 devid2; + + devid2 = readl(drvdata->base + CORESIGHT_DEVID2); + + if (TGU_DEVID2_TIMER0(devid2)) + num_timers++; + if (TGU_DEVID2_TIMER1(devid2)) + num_timers++; + + if (TGU_DEVID2_COUNTER0(devid2)) + num_counters++; + if (TGU_DEVID2_COUNTER1(devid2)) + num_counters++; + + drvdata->num_timer = num_timers; + drvdata->num_counter = num_counters; +} + static int tgu_enable(struct device *dev) { struct tgu_drvdata *drvdata = dev_get_drvdata(dev); @@ -405,6 +480,22 @@ static const struct attribute_group *tgu_attr_groups[] = { CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(5), CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(6), CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(7), + TIMER_ATTRIBUTE_GROUP_INIT(0), + TIMER_ATTRIBUTE_GROUP_INIT(1), + TIMER_ATTRIBUTE_GROUP_INIT(2), + TIMER_ATTRIBUTE_GROUP_INIT(3), + TIMER_ATTRIBUTE_GROUP_INIT(4), + TIMER_ATTRIBUTE_GROUP_INIT(5), + TIMER_ATTRIBUTE_GROUP_INIT(6), + TIMER_ATTRIBUTE_GROUP_INIT(7), + COUNTER_ATTRIBUTE_GROUP_INIT(0), + COUNTER_ATTRIBUTE_GROUP_INIT(1), + COUNTER_ATTRIBUTE_GROUP_INIT(2), + COUNTER_ATTRIBUTE_GROUP_INIT(3), + COUNTER_ATTRIBUTE_GROUP_INIT(4), + COUNTER_ATTRIBUTE_GROUP_INIT(5), + COUNTER_ATTRIBUTE_GROUP_INIT(6), + COUNTER_ATTRIBUTE_GROUP_INIT(7), NULL, }; @@ -412,8 +503,8 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; struct tgu_drvdata *drvdata; - unsigned int *priority, *condition, *select; - size_t priority_size, condition_size, select_size; + unsigned int *priority, *condition, *select, *timer, *counter; + size_t priority_size, condition_size, select_size, timer_size, counter_size; int ret; drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); @@ -432,6 +523,7 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) tgu_set_reg_number(drvdata); tgu_set_steps(drvdata); tgu_set_conditions(drvdata); + tgu_set_timer_counter(drvdata); ret = sysfs_create_groups(&dev->kobj, tgu_attr_groups); if (ret) { @@ -474,6 +566,26 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) drvdata->value_table->condition_select = select; + timer_size = drvdata->num_step * drvdata->num_timer; + + timer = devm_kcalloc(dev, timer_size, + sizeof(*(drvdata->value_table->timer)), + GFP_KERNEL); + if (!timer) + return -ENOMEM; + + drvdata->value_table->timer = timer; + + counter_size = drvdata->num_step * drvdata->num_counter; + + counter = devm_kcalloc(dev, counter_size, + sizeof(*(drvdata->value_table->counter)), + GFP_KERNEL); + if (!counter) + return -ENOMEM; + + drvdata->value_table->counter = counter; + drvdata->enabled = false; pm_runtime_put(&adev->dev); diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h index c61aa8dc51b0d..1bcbc99169def 100644 --- a/drivers/hwtracing/qcom/tgu.h +++ b/drivers/hwtracing/qcom/tgu.h @@ -11,6 +11,7 @@ #define TGU_LAR 0xfb0 #define TGU_UNLOCK_OFFSET 0xc5acce55 #define TGU_DEVID 0xfc8 +#define CORESIGHT_DEVID2 0xfc0 #define TGU_DEVID_SENSE_INPUT(devid_val) \ ((int)FIELD_GET(GENMASK(17, 10), devid_val)) @@ -18,6 +19,16 @@ ((int)FIELD_GET(GENMASK(6, 3), devid_val)) #define TGU_DEVID_CONDITIONS(devid_val) \ ((int)FIELD_GET(GENMASK(2, 0), devid_val)) +#define TGU_DEVID2_TIMER0(devid_val) \ + ((int)FIELD_GET(GENMASK(23, 18), devid_val)) +#define TGU_DEVID2_TIMER1(devid_val) \ + ((int)FIELD_GET(GENMASK(17, 13), devid_val)) +#define TGU_DEVID2_COUNTER0(devid_val) \ + ((int)FIELD_GET(GENMASK(11, 6), devid_val)) +#define TGU_DEVID2_COUNTER1(devid_val) \ + ((int)FIELD_GET(GENMASK(5, 0), devid_val)) + + #define TGU_BITS_PER_SIGNAL 4 #define LENGTH_REGISTER 32 @@ -53,6 +64,8 @@ #define PRIORITY_START_OFFSET 0x0074 #define CONDITION_DECODE_OFFSET 0x0050 #define CONDITION_SELECT_OFFSET 0x0060 +#define TIMER_START_OFFSET 0x0040 +#define COUNTER_START_OFFSET 0x0048 #define PRIORITY_OFFSET 0x60 #define REG_OFFSET 0x4 @@ -67,6 +80,12 @@ #define CONDITION_SELECT_STEP(step, select) \ (CONDITION_SELECT_OFFSET + REG_OFFSET * select + STEP_OFFSET * step) +#define TIMER_COMPARE_STEP(step, timer) \ + (TIMER_START_OFFSET + REG_OFFSET * timer + STEP_OFFSET * step) + +#define COUNTER_COMPARE_STEP(step, counter) \ + (COUNTER_START_OFFSET + REG_OFFSET * counter + STEP_OFFSET * step) + #define tgu_dataset_rw(name, step_index, type, reg_num) \ (&((struct tgu_attribute[]){ { \ __ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \ @@ -82,6 +101,10 @@ tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_DECODE, reg_num) #define STEP_SELECT(step_index, reg_num) \ tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_SELECT, reg_num) +#define STEP_TIMER(step_index, reg_num) \ + tgu_dataset_rw(reg##reg_num, step_index, TGU_TIMER, reg_num) +#define STEP_COUNTER(step_index, reg_num) \ + tgu_dataset_rw(reg##reg_num, step_index, TGU_COUNTER, reg_num) #define STEP_PRIORITY_LIST(step_index, priority) \ {STEP_PRIORITY(step_index, 0, priority), \ @@ -122,6 +145,18 @@ NULL \ } +#define STEP_TIMER_LIST(n) \ + {STEP_TIMER(n, 0), \ + STEP_TIMER(n, 1), \ + NULL \ + } + +#define STEP_COUNTER_LIST(n) \ + {STEP_COUNTER(n, 0), \ + STEP_COUNTER(n, 1), \ + NULL \ + } + #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\ (&(const struct attribute_group){\ .attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\ @@ -143,6 +178,20 @@ .name = "step" #step "_condition_select" \ }) +#define TIMER_ATTRIBUTE_GROUP_INIT(step)\ + (&(const struct attribute_group){\ + .attrs = (struct attribute*[])STEP_TIMER_LIST(step),\ + .is_visible = tgu_node_visible,\ + .name = "step" #step "_timer" \ + }) + +#define COUNTER_ATTRIBUTE_GROUP_INIT(step)\ + (&(const struct attribute_group){\ + .attrs = (struct attribute*[])STEP_COUNTER_LIST(step),\ + .is_visible = tgu_node_visible,\ + .name = "step" #step "_counter" \ + }) + enum operation_index { TGU_PRIORITY0, TGU_PRIORITY1, @@ -150,6 +199,8 @@ enum operation_index { TGU_PRIORITY3, TGU_CONDITION_DECODE, TGU_CONDITION_SELECT, + TGU_TIMER, + TGU_COUNTER, }; /* Maximum priority that TGU supports */ @@ -166,6 +217,8 @@ struct value_table { unsigned int *priority; unsigned int *condition_decode; unsigned int *condition_select; + unsigned int *timer; + unsigned int *counter; }; static inline void TGU_LOCK(void __iomem *addr) @@ -197,6 +250,8 @@ static inline void TGU_UNLOCK(void __iomem *addr) * @num_step: Maximum step size * @num_condition_decode: Maximum number of condition_decode * @num_condition_select: Maximum number of condition_select + * @num_timer: Maximum number of timers + * @num_counter: Maximum number of counters * * This structure defines the data associated with a TGU device, * including its base address, device pointers, clock, spinlock for @@ -213,6 +268,8 @@ struct tgu_drvdata { int num_step; int num_condition_decode; int num_condition_select; + int num_timer; + int num_counter; }; #endif From f7ea864129f86de60fbbef17df5b1bb2b53e239d Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Fri, 17 Apr 2026 00:33:36 -0700 Subject: [PATCH 14/15] FROMLIST: qcom-tgu: Add reset node to initialize Add reset node to initialize the value of priority/condition_decode/condition_select/timer/counter nodes. Link: https://lore.kernel.org/all/20260417073336.2712426-8-songwei.chai@oss.qualcomm.com/ Signed-off-by: Songwei Chai --- .../ABI/testing/sysfs-bus-amba-devices-tgu | 7 ++ drivers/hwtracing/qcom/tgu.c | 74 +++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu index 7a3573e03e27d..a6b6019c8ef17 100644 --- a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu @@ -42,3 +42,10 @@ KernelVersion: 7.1 Contact: Jinlong Mao , Songwei Chai Description: (RW) Set/Get the counter value with specific step for TGU. + +What: /sys/bus/amba/devices//reset_tgu +Date: April 2026 +KernelVersion: 7.1 +Contact: Jinlong Mao , Songwei Chai +Description: + (Write) Write 1 to reset the dataset for TGU. diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c index 6d5bf2621cb05..9fb51f2a912f9 100644 --- a/drivers/hwtracing/qcom/tgu.c +++ b/drivers/hwtracing/qcom/tgu.c @@ -420,8 +420,82 @@ static ssize_t enable_tgu_store(struct device *dev, } static DEVICE_ATTR_RW(enable_tgu); +/* reset_tgu_store - Reset Trace and Gating Unit (TGU) configuration. */ +static ssize_t reset_tgu_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) +{ + struct tgu_drvdata *drvdata = dev_get_drvdata(dev); + struct value_table *vt = drvdata->value_table; + u32 *cond_decode = drvdata->value_table->condition_decode; + unsigned long value; + int i, j, ret; + + if (kstrtoul(buf, 0, &value) || value != 1) + return -EINVAL; + + spin_lock(&drvdata->lock); + if (!drvdata->enabled) { + spin_unlock(&drvdata->lock); + ret = pm_runtime_resume_and_get(drvdata->dev); + if (ret) + return ret; + spin_lock(&drvdata->lock); + } + + tgu_do_disable(drvdata); + + if (vt->priority) { + size_t size = MAX_PRIORITY * drvdata->num_step * + drvdata->num_reg * sizeof(unsigned int); + memset(vt->priority, 0, size); + } + + if (vt->condition_decode) { + size_t size = drvdata->num_condition_decode * + drvdata->num_step * sizeof(unsigned int); + memset(vt->condition_decode, 0, size); + } + + /* Initialize all condition registers to NOT(value=0x1000000) */ + for (i = 0; i < drvdata->num_step; i++) { + for (j = 0; j < drvdata->num_condition_decode; j++) { + cond_decode[calculate_array_location(drvdata, i, + TGU_CONDITION_DECODE, j)] = 0x1000000; + } + } + + if (vt->condition_select) { + size_t size = drvdata->num_condition_select * + drvdata->num_step * sizeof(unsigned int); + memset(vt->condition_select, 0, size); + } + + if (vt->timer) { + size_t size = (drvdata->num_step) * (drvdata->num_timer) * + sizeof(unsigned int); + memset(vt->timer, 0, size); + } + + if (vt->counter) { + size_t size = (drvdata->num_step) * (drvdata->num_counter) * + sizeof(unsigned int); + memset(vt->counter, 0, size); + } + + spin_unlock(&drvdata->lock); + + dev_dbg(dev, "Qualcomm-TGU reset complete\n"); + + pm_runtime_put(drvdata->dev); + + return size; +} +static DEVICE_ATTR_WO(reset_tgu); + static struct attribute *tgu_common_attrs[] = { &dev_attr_enable_tgu.attr, + &dev_attr_reset_tgu.attr, NULL, }; From 23c5d79702f774a4021b52e310774c234d1086eb Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Thu, 30 Apr 2026 14:56:28 +0800 Subject: [PATCH 15/15] QCLINUX: arm64: configs: qcom.config: update the TGU config Update the TGU config according to the latest version of TGU driver. Signed-off-by: Jie Gan --- arch/arm64/configs/qcom.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 567bc0c34a784..c7dbcdfd0383f 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -16,7 +16,7 @@ CONFIG_CORESIGHT_CORESIGHT_TNOC=m CONFIG_CORESIGHT_CTCU=m CONFIG_CORESIGHT_DUMMY=m CONFIG_CORESIGHT_SOURCE_ETM4X=m -CONFIG_CORESIGHT_TGU=m +CONFIG_QCOM_TGU=m CONFIG_CORESIGHT_TPDM=m CONFIG_CPU_IDLE_THERMAL=y # CONFIG_DEBUG_INFO_REDUCED is not set