aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMayuresh Kulkarni <mkulkarni@opensource.wolfsonmicro.com>2017-04-05 06:08:00 -0400
committerMark Brown <broonie@kernel.org>2017-04-05 11:14:15 -0400
commit51a2c944ead91171495ef338689da057bbcaab0c (patch)
treeca1fdade4dc4b7cd48999fd370776a18b9477f37
parente1ea1879f2889a26370bd0bc29c1e95caf9d36f2 (diff)
ASoC: wm_adsp: add support for DSP region lock
Newer ADSP2V2 codecs include a memory protection unit that can be set to trap illegal accesses. When enabling an ADSPV2 core we must configure the memory region traps so that the firmware can access its own memory. Signed-off-by: Mayuresh Kulkarni <mkulkarni@opensource.wolfsonmicro.com> Signed-off-by: Nikesh Oswal <Nikesh.Oswal@wolfsonmicro.com> Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/wm_adsp.c137
-rw-r--r--sound/soc/codecs/wm_adsp.h23
2 files changed, 160 insertions, 0 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index a9acf222b502..20695b691aff 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -176,6 +176,37 @@
176#define ADSP2_RAM_RDY_SHIFT 0 176#define ADSP2_RAM_RDY_SHIFT 0
177#define ADSP2_RAM_RDY_WIDTH 1 177#define ADSP2_RAM_RDY_WIDTH 1
178 178
179/*
180 * ADSP2 Lock support
181 */
182#define ADSP2_LOCK_CODE_0 0x5555
183#define ADSP2_LOCK_CODE_1 0xAAAA
184
185#define ADSP2_WATCHDOG 0x0A
186#define ADSP2_BUS_ERR_ADDR 0x52
187#define ADSP2_REGION_LOCK_STATUS 0x64
188#define ADSP2_LOCK_REGION_1_LOCK_REGION_0 0x66
189#define ADSP2_LOCK_REGION_3_LOCK_REGION_2 0x68
190#define ADSP2_LOCK_REGION_5_LOCK_REGION_4 0x6A
191#define ADSP2_LOCK_REGION_7_LOCK_REGION_6 0x6C
192#define ADSP2_LOCK_REGION_9_LOCK_REGION_8 0x6E
193#define ADSP2_LOCK_REGION_CTRL 0x7A
194#define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR 0x7C
195
196#define ADSP2_REGION_LOCK_ERR_MASK 0x8000
197#define ADSP2_SLAVE_ERR_MASK 0x4000
198#define ADSP2_WDT_TIMEOUT_STS_MASK 0x2000
199#define ADSP2_CTRL_ERR_PAUSE_ENA 0x0002
200#define ADSP2_CTRL_ERR_EINT 0x0001
201
202#define ADSP2_BUS_ERR_ADDR_MASK 0x00FFFFFF
203#define ADSP2_XMEM_ERR_ADDR_MASK 0x0000FFFF
204#define ADSP2_PMEM_ERR_ADDR_MASK 0x7FFF0000
205#define ADSP2_PMEM_ERR_ADDR_SHIFT 16
206#define ADSP2_WDT_ENA_MASK 0xFFFFFFFD
207
208#define ADSP2_LOCK_REGION_SHIFT 16
209
179#define ADSP_MAX_STD_CTRL_SIZE 512 210#define ADSP_MAX_STD_CTRL_SIZE 512
180 211
181#define WM_ADSP_ACKED_CTL_TIMEOUT_MS 100 212#define WM_ADSP_ACKED_CTL_TIMEOUT_MS 100
@@ -2638,6 +2669,18 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
2638} 2669}
2639EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); 2670EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
2640 2671
2672static void wm_adsp_stop_watchdog(struct wm_adsp *dsp)
2673{
2674 switch (dsp->rev) {
2675 case 0:
2676 case 1:
2677 return;
2678 default:
2679 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
2680 ADSP2_WDT_ENA_MASK, 0);
2681 }
2682}
2683
2641int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, 2684int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
2642 struct snd_kcontrol *kcontrol, int event, 2685 struct snd_kcontrol *kcontrol, int event,
2643 unsigned int freq) 2686 unsigned int freq)
@@ -2710,6 +2753,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
2710 if (ret != 0) 2753 if (ret != 0)
2711 goto err; 2754 goto err;
2712 2755
2756 wm_adsp2_lock(dsp, dsp->lock_regions);
2757
2713 ret = regmap_update_bits(dsp->regmap, 2758 ret = regmap_update_bits(dsp->regmap,
2714 dsp->base + ADSP2_CONTROL, 2759 dsp->base + ADSP2_CONTROL,
2715 ADSP2_CORE_ENA | ADSP2_START, 2760 ADSP2_CORE_ENA | ADSP2_START,
@@ -2733,6 +2778,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
2733 /* Tell the firmware to cleanup */ 2778 /* Tell the firmware to cleanup */
2734 wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN); 2779 wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN);
2735 2780
2781 wm_adsp_stop_watchdog(dsp);
2782
2736 /* Log firmware state, it can be useful for analysis */ 2783 /* Log firmware state, it can be useful for analysis */
2737 switch (dsp->rev) { 2784 switch (dsp->rev) {
2738 case 0: 2785 case 0:
@@ -3624,4 +3671,94 @@ int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf,
3624} 3671}
3625EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); 3672EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
3626 3673
3674int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
3675{
3676 struct regmap *regmap = dsp->regmap;
3677 unsigned int code0, code1, lock_reg;
3678
3679 if (!(lock_regions & WM_ADSP2_REGION_ALL))
3680 return 0;
3681
3682 lock_regions &= WM_ADSP2_REGION_ALL;
3683 lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0;
3684
3685 while (lock_regions) {
3686 code0 = code1 = 0;
3687 if (lock_regions & BIT(0)) {
3688 code0 = ADSP2_LOCK_CODE_0;
3689 code1 = ADSP2_LOCK_CODE_1;
3690 }
3691 if (lock_regions & BIT(1)) {
3692 code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT;
3693 code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT;
3694 }
3695 regmap_write(regmap, lock_reg, code0);
3696 regmap_write(regmap, lock_reg, code1);
3697 lock_regions >>= 2;
3698 lock_reg += 2;
3699 }
3700
3701 return 0;
3702}
3703EXPORT_SYMBOL_GPL(wm_adsp2_lock);
3704
3705irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp)
3706{
3707 unsigned int val;
3708 struct regmap *regmap = dsp->regmap;
3709 int ret = 0;
3710
3711 ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val);
3712 if (ret) {
3713 adsp_err(dsp,
3714 "Failed to read Region Lock Ctrl register: %d\n", ret);
3715 return IRQ_HANDLED;
3716 }
3717
3718 if (val & ADSP2_WDT_TIMEOUT_STS_MASK) {
3719 adsp_err(dsp, "watchdog timeout error\n");
3720 wm_adsp_stop_watchdog(dsp);
3721 }
3722
3723 if (val & (ADSP2_SLAVE_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) {
3724 if (val & ADSP2_SLAVE_ERR_MASK)
3725 adsp_err(dsp, "bus error: slave error\n");
3726 else
3727 adsp_err(dsp, "bus error: region lock error\n");
3728
3729 ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val);
3730 if (ret) {
3731 adsp_err(dsp,
3732 "Failed to read Bus Err Addr register: %d\n",
3733 ret);
3734 return IRQ_HANDLED;
3735 }
3736
3737 adsp_err(dsp, "bus error address = 0x%x\n",
3738 val & ADSP2_BUS_ERR_ADDR_MASK);
3739
3740 ret = regmap_read(regmap,
3741 dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR,
3742 &val);
3743 if (ret) {
3744 adsp_err(dsp,
3745 "Failed to read Pmem Xmem Err Addr register: %d\n",
3746 ret);
3747 return IRQ_HANDLED;
3748 }
3749
3750 adsp_err(dsp, "xmem error address = 0x%x\n",
3751 val & ADSP2_XMEM_ERR_ADDR_MASK);
3752 adsp_err(dsp, "pmem error address = 0x%x\n",
3753 (val & ADSP2_PMEM_ERR_ADDR_MASK) >>
3754 ADSP2_PMEM_ERR_ADDR_SHIFT);
3755 }
3756
3757 regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL,
3758 ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT);
3759
3760 return IRQ_HANDLED;
3761}
3762EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
3763
3627MODULE_LICENSE("GPL v2"); 3764MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 997227f4d404..41cc11c19b83 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -23,6 +23,23 @@
23#define WM_ADSP_COMPR_OK 0 23#define WM_ADSP_COMPR_OK 0
24#define WM_ADSP_COMPR_VOICE_TRIGGER 1 24#define WM_ADSP_COMPR_VOICE_TRIGGER 1
25 25
26#define WM_ADSP2_REGION_0 BIT(0)
27#define WM_ADSP2_REGION_1 BIT(1)
28#define WM_ADSP2_REGION_2 BIT(2)
29#define WM_ADSP2_REGION_3 BIT(3)
30#define WM_ADSP2_REGION_4 BIT(4)
31#define WM_ADSP2_REGION_5 BIT(5)
32#define WM_ADSP2_REGION_6 BIT(6)
33#define WM_ADSP2_REGION_7 BIT(7)
34#define WM_ADSP2_REGION_8 BIT(8)
35#define WM_ADSP2_REGION_9 BIT(9)
36#define WM_ADSP2_REGION_1_9 (WM_ADSP2_REGION_1 | \
37 WM_ADSP2_REGION_2 | WM_ADSP2_REGION_3 | \
38 WM_ADSP2_REGION_4 | WM_ADSP2_REGION_5 | \
39 WM_ADSP2_REGION_6 | WM_ADSP2_REGION_7 | \
40 WM_ADSP2_REGION_8 | WM_ADSP2_REGION_9)
41#define WM_ADSP2_REGION_ALL (WM_ADSP2_REGION_0 | WM_ADSP2_REGION_1_9)
42
26struct wm_adsp_region { 43struct wm_adsp_region {
27 int type; 44 int type;
28 unsigned int base; 45 unsigned int base;
@@ -76,6 +93,8 @@ struct wm_adsp {
76 93
77 struct mutex pwr_lock; 94 struct mutex pwr_lock;
78 95
96 unsigned int lock_regions;
97
79#ifdef CONFIG_DEBUG_FS 98#ifdef CONFIG_DEBUG_FS
80 struct dentry *debugfs_root; 99 struct dentry *debugfs_root;
81 char *wmfw_file_name; 100 char *wmfw_file_name;
@@ -114,6 +133,10 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
114int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, 133int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
115 struct snd_kcontrol *kcontrol, int event, 134 struct snd_kcontrol *kcontrol, int event,
116 unsigned int freq); 135 unsigned int freq);
136
137int wm_adsp2_lock(struct wm_adsp *adsp, unsigned int regions);
138irqreturn_t wm_adsp2_bus_error(struct wm_adsp *adsp);
139
117int wm_adsp2_event(struct snd_soc_dapm_widget *w, 140int wm_adsp2_event(struct snd_soc_dapm_widget *w,
118 struct snd_kcontrol *kcontrol, int event); 141 struct snd_kcontrol *kcontrol, int event);
119 142