ASoC: wm_adsp: Add HALO MPU fault logging
authorRichard Fitzgerald <rf@opensource.cirrus.com>
Tue, 19 Mar 2019 11:52:14 +0000 (11:52 +0000)
committerMark Brown <broonie@kernel.org>
Tue, 19 Mar 2019 13:00:25 +0000 (13:00 +0000)
A Halo Core DSP has a memory protection unit that can trap and signal
memory access faults. This patch adds a function that dumps the fault
information.

The interrupt reaches the host via the parent codec interrupt controller
so this fault function is exported to be called by the codec driver.

Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_adsp.h

index bd31056..3e74cbb 100644 (file)
  */
 #define WM_ADSP_FW_EVENT_SHUTDOWN            0x000001
 
+/*
+ * HALO system info
+ */
+#define HALO_AHBM_WINDOW_DEBUG_0             0x02040
+#define HALO_AHBM_WINDOW_DEBUG_1             0x02044
+
 /*
  * HALO core
  */
 #define HALO_MPU_WINDOW_ACCESS_3             0x43050
 #define HALO_MPU_XREG_ACCESS_3               0x43054
 #define HALO_MPU_YREG_ACCESS_3               0x4305C
+#define HALO_MPU_XM_VIO_ADDR                 0x43100
+#define HALO_MPU_XM_VIO_STATUS               0x43104
+#define HALO_MPU_YM_VIO_ADDR                 0x43108
+#define HALO_MPU_YM_VIO_STATUS               0x4310C
+#define HALO_MPU_PM_VIO_ADDR                 0x43110
+#define HALO_MPU_PM_VIO_STATUS               0x43114
 #define HALO_MPU_LOCK_CONFIG                 0x43140
 
+/*
+ * HALO_AHBM_WINDOW_DEBUG_1
+ */
+#define HALO_AHBM_CORE_ERR_ADDR_MASK         0x0fffff00
+#define HALO_AHBM_CORE_ERR_ADDR_SHIFT                 8
+#define HALO_AHBM_FLAGS_ERR_MASK             0x000000ff
+
 /*
  * HALO_CCM_CORE_CONTROL
  */
  */
 #define HALO_CORE_SOFT_RESET_MASK           0x00000001
 
+/*
+ * HALO_MPU_?M_VIO_STATUS
+ */
+#define HALO_MPU_VIO_STS_MASK               0x007e0000
+#define HALO_MPU_VIO_STS_SHIFT                      17
+#define HALO_MPU_VIO_ERR_WR_MASK            0x00008000
+#define HALO_MPU_VIO_ERR_SRC_MASK           0x00007fff
+#define HALO_MPU_VIO_ERR_SRC_SHIFT                   0
+
 struct wm_adsp_ops wm_adsp1_ops;
 struct wm_adsp_ops wm_adsp2_ops[];
 struct wm_adsp_ops wm_halo_ops;
@@ -4295,6 +4323,62 @@ error:
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
 
+irqreturn_t wm_halo_bus_error(struct wm_adsp *dsp)
+{
+       struct regmap *regmap = dsp->regmap;
+       unsigned int fault[6];
+       struct reg_sequence clear[] = {
+               { dsp->base + HALO_MPU_XM_VIO_STATUS,     0x0 },
+               { dsp->base + HALO_MPU_YM_VIO_STATUS,     0x0 },
+               { dsp->base + HALO_MPU_PM_VIO_STATUS,     0x0 },
+       };
+       int ret;
+
+       mutex_lock(&dsp->pwr_lock);
+
+       ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1,
+                         fault);
+       if (ret) {
+               adsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret);
+               goto exit_unlock;
+       }
+
+       adsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n",
+                 *fault & HALO_AHBM_FLAGS_ERR_MASK,
+                 (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >>
+                 HALO_AHBM_CORE_ERR_ADDR_SHIFT);
+
+       ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0,
+                         fault);
+       if (ret) {
+               adsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret);
+               goto exit_unlock;
+       }
+
+       adsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault);
+
+       ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR,
+                              fault, ARRAY_SIZE(fault));
+       if (ret) {
+               adsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret);
+               goto exit_unlock;
+       }
+
+       adsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]);
+       adsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]);
+       adsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]);
+
+       ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear));
+       if (ret)
+               adsp_warn(dsp, "Failed to clear MPU status: %d\n", ret);
+
+exit_unlock:
+       mutex_unlock(&dsp->pwr_lock);
+
+       return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(wm_halo_bus_error);
+
 struct wm_adsp_ops wm_adsp1_ops = {
        .validate_version = wm_adsp_validate_version,
        .parse_sizes = wm_adsp1_parse_sizes,
index e7f1fde..521dccb 100644 (file)
@@ -175,6 +175,7 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *kcontrol, int event);
 
 irqreturn_t wm_adsp2_bus_error(struct wm_adsp *adsp);
+irqreturn_t wm_halo_bus_error(struct wm_adsp *dsp);
 
 int wm_adsp_event(struct snd_soc_dapm_widget *w,
                  struct snd_kcontrol *kcontrol, int event);