* TRCRSCTLR1 (always true) used to get the counter to decrement. From
* there a resource selector is configured with the counter and the
* timestamp control register to use the resource selector to trigger the
- * event that will insert a timestamp packet in the stream.
+ * event that will insert a timestamp packet in the stream:
+ *
+ * +--------------+
+ * | Resource 1 | fixed "always-true" resource
+ * +--------------+
+ * |
+ * +------v-------+
+ * | Counter x | (reload to 1 on underflow)
+ * +--------------+
+ * |
+ * +------v--------------+
+ * | Resource Selector y | (trigger on counter x == 0)
+ * +---------------------+
+ * |
+ * +------v---------------+
+ * | Timestamp Generator | (timestamp on resource y)
+ * +----------------------+
*/
static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata)
{
- int ctridx, ret = -EINVAL;
- int counter, rselector;
- u32 val = 0;
+ int ctridx;
+ int rselector;
struct etmv4_config *config = &drvdata->config;
/* No point in trying if we don't have at least one counter */
if (!drvdata->nr_cntr)
- goto out;
+ return -EINVAL;
/* Find a counter that hasn't been initialised */
for (ctridx = 0; ctridx < drvdata->nr_cntr; ctridx++)
/* All the counters have been configured already, bail out */
if (ctridx == drvdata->nr_cntr) {
pr_debug("%s: no available counter found\n", __func__);
- ret = -ENOSPC;
- goto out;
+ return -ENOSPC;
}
/*
- * Searching for an available resource selector to use, starting at
- * '2' since every implementation has at least 2 resource selector.
- * ETMIDR4 gives the number of resource selector _pairs_,
- * hence multiply by 2.
+ * Searching for an available resource selector to use, starting at '2'
+ * since resource 0 is the fixed 'always returns false' resource and 1
+ * is the fixed 'always returns true' resource. See IHI0064H_b '7.3.64
+ * TRCRSCTLRn, Resource Selection Control Registers, n=2-31'. If there
+ * are no resources, there would also be no counters so wouldn't get
+ * here.
+ *
+ * ETMIDR4 gives the number of resource selector _pairs_, hence multiply
+ * by 2.
*/
for (rselector = 2; rselector < drvdata->nr_resource * 2; rselector++)
if (!config->res_ctrl[rselector])
if (rselector == drvdata->nr_resource * 2) {
pr_debug("%s: no available resource selector found\n",
__func__);
- ret = -ENOSPC;
- goto out;
+ return -ENOSPC;
}
- /* Remember what counter we used */
- counter = 1 << ctridx;
-
/*
* Initialise original and reload counter value to the smallest
* possible value in order to get as much precision as we can.
config->cntr_val[ctridx] = 1;
config->cntrldvr[ctridx] = 1;
- /* Set the trace counter control register */
- val = 0x1 << 16 | /* Bit 16, reload counter automatically */
- 0x0 << 7 | /* Select single resource selector */
- 0x1; /* Resource selector 1, i.e always true */
-
- config->cntr_ctrl[ctridx] = val;
-
- val = 0x2 << 16 | /* Group 0b0010 - Counter and sequencers */
- counter << 0; /* Counter to use */
-
- config->res_ctrl[rselector] = val;
+ /*
+ * Trace Counter Control Register TRCCNTCTLRn
+ *
+ * CNTCHAIN = 0, don't reload on the previous counter
+ * RLDSELF = true, reload counter automatically on underflow
+ * RLDEVENT = RES_SEL_FALSE (0), reload on single false resource (never reload)
+ * CNTEVENT = RES_SEL_TRUE (1), count single fixed 'always true' resource (always decrement)
+ */
+ config->cntr_ctrl[ctridx] = TRCCNTCTLRn_RLDSELF |
+ FIELD_PREP(TRCCNTCTLRn_RLDEVENT_MASK,
+ etm4_res_sel_single(ETM4_RES_SEL_FALSE)) |
+ FIELD_PREP(TRCCNTCTLRn_CNTEVENT_MASK,
+ etm4_res_sel_single(ETM4_RES_SEL_TRUE));
- val = 0x0 << 7 | /* Select single resource selector */
- rselector; /* Resource selector */
+ /*
+ * Resource Selection Control Register TRCRSCTLRn
+ *
+ * PAIRINV = 0, INV = 0, don't invert
+ * GROUP = 2, SELECT = ctridx, trigger when counter 'ctridx' reaches 0
+ *
+ * Multiple counters can be selected, and each bit signifies a counter,
+ * so set bit 'ctridx' to select our counter.
+ */
+ config->res_ctrl[rselector] = FIELD_PREP(TRCRSCTLRn_GROUP_MASK, 2) |
+ FIELD_PREP(TRCRSCTLRn_SELECT_MASK, 1 << ctridx);
- config->ts_ctrl = val;
+ /*
+ * Global Timestamp Control Register TRCTSCTLR
+ *
+ * EVENT = generate timestamp on single resource 'rselector'
+ */
+ config->ts_ctrl = FIELD_PREP(TRCTSCTLR_EVENT_MASK,
+ etm4_res_sel_single(rselector));
- ret = 0;
-out:
- return ret;
+ return 0;
}
static int etm4_parse_event_config(struct coresight_device *csdev,
#define TRCRSCTLRn_GROUP_MASK GENMASK(19, 16)
#define TRCRSCTLRn_SELECT_MASK GENMASK(15, 0)
+#define TRCCNTCTLRn_CNTCHAIN BIT(17)
+#define TRCCNTCTLRn_RLDSELF BIT(16)
+#define TRCCNTCTLRn_RLDEVENT_MASK GENMASK(15, 8)
+#define TRCCNTCTLRn_CNTEVENT_MASK GENMASK(7, 0)
+
+#define TRCTSCTLR_EVENT_MASK GENMASK(7, 0)
+
+#define ETM4_RES_SEL_FALSE 0 /* Fixed function 'always false' resource selector */
+#define ETM4_RES_SEL_TRUE 1 /* Fixed function 'always true' resource selector */
+
+#define ETM4_RES_SEL_SINGLE_MASK GENMASK(4, 0)
+#define ETM4_RES_SEL_PAIR_MASK GENMASK(3, 0)
+#define ETM4_RES_SEL_TYPE_PAIR BIT(7)
+
+/*
+ * Utilities for programming EVENT resource selectors, e.g. TRCCNTCTLRn_RLDEVENT.
+ *
+ * Resource selectors have a common format across registers:
+ *
+ * 7 6 5 4 0
+ * +------+------+-------+
+ * | TYPE | RES0 | SEL |
+ * +------+------+-------+
+ *
+ * Where TYPE indicates whether the selector is for a single event or a pair.
+ * When TYPE is pair, SEL is 4 bits wide and using pair 0 is UNPREDICTABLE.
+ * Otherwise for single it's 5 bits wide.
+ */
+static inline u32 etm4_res_sel_single(u8 res_sel_idx)
+{
+ WARN_ON_ONCE(!FIELD_FIT(ETM4_RES_SEL_SINGLE_MASK, res_sel_idx));
+ return FIELD_PREP(ETM4_RES_SEL_SINGLE_MASK, res_sel_idx);
+}
+
+static inline u32 etm4_res_sel_pair(u8 res_sel_idx)
+{
+ if (__builtin_constant_p(res_sel_idx))
+ BUILD_BUG_ON(res_sel_idx == 0);
+ WARN_ON_ONCE(!FIELD_FIT(ETM4_RES_SEL_PAIR_MASK, res_sel_idx) ||
+ (res_sel_idx == 0));
+ return FIELD_PREP(ETM4_RES_SEL_PAIR_MASK, res_sel_idx) |
+ ETM4_RES_SEL_TYPE_PAIR;
+}
+
/*
* System instructions to access ETM registers.
* See ETMv4.4 spec ARM IHI0064F section 4.3.6 System instructions
u32 eventctrl0;
u32 eventctrl1;
u32 stall_ctrl;
- u32 ts_ctrl;
+ u32 ts_ctrl; /* TRCTSCTLR */
u32 ccctlr;
u32 bb_ctrl;
u32 vinst_ctrl;
u32 seq_rst;
u32 seq_state;
u8 cntr_idx;
- u32 cntrldvr[ETMv4_MAX_CNTR];
- u32 cntr_ctrl[ETMv4_MAX_CNTR];
- u32 cntr_val[ETMv4_MAX_CNTR];
+ u32 cntrldvr[ETMv4_MAX_CNTR]; /* TRCCNTRLDVRn */
+ u32 cntr_ctrl[ETMv4_MAX_CNTR]; /* TRCCNTCTLRn */
+ u32 cntr_val[ETMv4_MAX_CNTR]; /* TRCCNTVRn */
u8 res_idx;
- u32 res_ctrl[ETM_MAX_RES_SEL];
+ u32 res_ctrl[ETM_MAX_RES_SEL]; /* TRCRSCTLRn */
u8 ss_idx;
u32 ss_ctrl[ETM_MAX_SS_CMP];
u32 ss_status[ETM_MAX_SS_CMP];