intel_th: Add switch triggering support
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>
Fri, 3 May 2019 08:44:48 +0000 (11:44 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 3 May 2019 16:16:21 +0000 (18:16 +0200)
Add support for asserting window switch trigger when tracing to MSU output
ports. This allows for software controlled switching between windows of
the MSU buffer, which can be used for double buffering while exporting the
trace data further from the MSU.

Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/hwtracing/intel_th/core.c
drivers/hwtracing/intel_th/gth.c
drivers/hwtracing/intel_th/gth.h
drivers/hwtracing/intel_th/intel_th.h

index 390031df3edffe3d15c75e54abdf4325d1b43556..033dce563c993ae4f859209b9d4a474da9cf074c 100644 (file)
@@ -430,9 +430,9 @@ static const struct intel_th_subdevice {
                .nres   = 1,
                .res    = {
                        {
-                               /* Handle TSCU from GTH driver */
+                               /* Handle TSCU and CTS from GTH driver */
                                .start  = REG_GTH_OFFSET,
-                               .end    = REG_TSCU_OFFSET + REG_TSCU_LENGTH - 1,
+                               .end    = REG_CTS_OFFSET + REG_CTS_LENGTH - 1,
                                .flags  = IORESOURCE_MEM,
                        },
                },
@@ -987,6 +987,27 @@ int intel_th_trace_enable(struct intel_th_device *thdev)
 }
 EXPORT_SYMBOL_GPL(intel_th_trace_enable);
 
+/**
+ * intel_th_trace_switch() - execute a switch sequence
+ * @thdev:     output device that requests tracing switch
+ */
+int intel_th_trace_switch(struct intel_th_device *thdev)
+{
+       struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
+       struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
+
+       if (WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH))
+               return -EINVAL;
+
+       if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT))
+               return -EINVAL;
+
+       hubdrv->trig_switch(hub, &thdev->output);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(intel_th_trace_switch);
+
 /**
  * intel_th_trace_disable() - disable tracing for an output device
  * @thdev:     output device that requests tracing be disabled
index a879445ef4516291a5f8023ad4a9b4439e3a1217..fa9d34af87acc0de4d14276a6a037234f0ae7218 100644 (file)
@@ -308,6 +308,11 @@ static int intel_th_gth_reset(struct gth_device *gth)
        iowrite32(0, gth->base + REG_GTH_SCR);
        iowrite32(0xfc, gth->base + REG_GTH_SCR2);
 
+       /* setup CTS for single trigger */
+       iowrite32(CTS_EVENT_ENABLE_IF_ANYTHING, gth->base + REG_CTS_C0S0_EN);
+       iowrite32(CTS_ACTION_CONTROL_SET_STATE(CTS_STATE_IDLE) |
+                 CTS_ACTION_CONTROL_TRIGGER, gth->base + REG_CTS_C0S0_ACT);
+
        return 0;
 }
 
@@ -594,6 +599,37 @@ static void intel_th_gth_enable(struct intel_th_device *thdev,
        intel_th_gth_start(gth, output);
 }
 
+/**
+ * intel_th_gth_switch() - execute a switch sequence
+ * @thdev:     GTH device
+ * @output:    output device's descriptor
+ *
+ * This will execute a switch sequence that will trigger a switch window
+ * when tracing to MSC in multi-block mode.
+ */
+static void intel_th_gth_switch(struct intel_th_device *thdev,
+                               struct intel_th_output *output)
+{
+       struct gth_device *gth = dev_get_drvdata(&thdev->dev);
+       unsigned long count;
+       u32 reg;
+
+       /* trigger */
+       iowrite32(0, gth->base + REG_CTS_CTL);
+       iowrite32(CTS_CTL_SEQUENCER_ENABLE, gth->base + REG_CTS_CTL);
+       /* wait on trigger status */
+       for (reg = 0, count = CTS_TRIG_WAITLOOP_DEPTH;
+            count && !(reg & BIT(4)); count--) {
+               reg = ioread32(gth->base + REG_CTS_STAT);
+               cpu_relax();
+       }
+       if (!count)
+               dev_dbg(&thdev->dev, "timeout waiting for CTS Trigger\n");
+
+       intel_th_gth_stop(gth, output, false);
+       intel_th_gth_start(gth, output);
+}
+
 /**
  * intel_th_gth_assign() - assign output device to a GTH output port
  * @thdev:     GTH device
@@ -777,6 +813,7 @@ static struct intel_th_driver intel_th_gth_driver = {
        .unassign       = intel_th_gth_unassign,
        .set_output     = intel_th_gth_set_output,
        .enable         = intel_th_gth_enable,
+       .trig_switch    = intel_th_gth_switch,
        .disable        = intel_th_gth_disable,
        .driver = {
                .name   = "gth",
index 6f2b0b9308755ad2bfba17cf085418293ddd1e24..bfcc0fd011774cc2d96791e098174af06726cd42 100644 (file)
@@ -49,6 +49,12 @@ enum {
        REG_GTH_SCRPD3          = 0xec, /* ScratchPad[3] */
        REG_TSCU_TSUCTRL        = 0x2000, /* TSCU control register */
        REG_TSCU_TSCUSTAT       = 0x2004, /* TSCU status register */
+
+       /* Common Capture Sequencer (CTS) registers */
+       REG_CTS_C0S0_EN         = 0x30c0, /* clause_event_enable_c0s0 */
+       REG_CTS_C0S0_ACT        = 0x3180, /* clause_action_control_c0s0 */
+       REG_CTS_STAT            = 0x32a0, /* cts_status */
+       REG_CTS_CTL             = 0x32a4, /* cts_control */
 };
 
 /* waiting for Pipeline Empty bit(s) to assert for GTH */
@@ -57,4 +63,17 @@ enum {
 #define TSUCTRL_CTCRESYNC      BIT(0)
 #define TSCUSTAT_CTCSYNCING    BIT(1)
 
+/* waiting for Trigger status to assert for CTS */
+#define CTS_TRIG_WAITLOOP_DEPTH        10000
+
+#define CTS_EVENT_ENABLE_IF_ANYTHING   BIT(31)
+#define CTS_ACTION_CONTROL_STATE_OFF   27
+#define CTS_ACTION_CONTROL_SET_STATE(x)        \
+       (((x) & 0x1f) << CTS_ACTION_CONTROL_STATE_OFF)
+#define CTS_ACTION_CONTROL_TRIGGER     BIT(4)
+
+#define CTS_STATE_IDLE                 0x10u
+
+#define CTS_CTL_SEQUENCER_ENABLE       BIT(0)
+
 #endif /* __INTEL_TH_GTH_H__ */
index 74a6a4071e7fe163ecffc914f4f22cf9e9a4961d..0df480072b6ca01321af79967f22e7a63b343333 100644 (file)
@@ -164,6 +164,8 @@ struct intel_th_driver {
                                            struct intel_th_device *othdev);
        void                    (*enable)(struct intel_th_device *thdev,
                                          struct intel_th_output *output);
+       void                    (*trig_switch)(struct intel_th_device *thdev,
+                                              struct intel_th_output *output);
        void                    (*disable)(struct intel_th_device *thdev,
                                           struct intel_th_output *output);
        /* output ops */
@@ -228,6 +230,7 @@ int intel_th_driver_register(struct intel_th_driver *thdrv);
 void intel_th_driver_unregister(struct intel_th_driver *thdrv);
 
 int intel_th_trace_enable(struct intel_th_device *thdev);
+int intel_th_trace_switch(struct intel_th_device *thdev);
 int intel_th_trace_disable(struct intel_th_device *thdev);
 int intel_th_set_output(struct intel_th_device *thdev,
                        unsigned int master);
@@ -308,6 +311,9 @@ enum {
        REG_TSCU_OFFSET         = 0x2000,
        REG_TSCU_LENGTH         = 0x1000,
 
+       REG_CTS_OFFSET          = 0x3000,
+       REG_CTS_LENGTH          = 0x1000,
+
        /* Software Trace Hub (STH) [0x4000..0x4fff] */
        REG_STH_OFFSET          = 0x4000,
        REG_STH_LENGTH          = 0x2000,