diff options
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 137 | ||||
-rw-r--r-- | sound/soc/codecs/wm_adsp.h | 23 |
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 | } |
2639 | EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); | 2670 | EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); |
2640 | 2671 | ||
2672 | static 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 | |||
2641 | int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, | 2684 | int 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 | } |
3625 | EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); | 3672 | EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); |
3626 | 3673 | ||
3674 | int 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 | } | ||
3703 | EXPORT_SYMBOL_GPL(wm_adsp2_lock); | ||
3704 | |||
3705 | irqreturn_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 | } | ||
3762 | EXPORT_SYMBOL_GPL(wm_adsp2_bus_error); | ||
3763 | |||
3627 | MODULE_LICENSE("GPL v2"); | 3764 | MODULE_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 | |||
26 | struct wm_adsp_region { | 43 | struct 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, | |||
114 | int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, | 133 | int 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 | |||
137 | int wm_adsp2_lock(struct wm_adsp *adsp, unsigned int regions); | ||
138 | irqreturn_t wm_adsp2_bus_error(struct wm_adsp *adsp); | ||
139 | |||
117 | int wm_adsp2_event(struct snd_soc_dapm_widget *w, | 140 | int 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 | ||