ASoC: wm_adsp: Factor out DSP specific operations
In preparation for the addition of more types of DSP core refactor the handling of DSP specific operations such as starting the memory or enabling the core into a set of callbacks. This should make it easier to add new core types and allow for more code reuse between them. Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
a5dcb24d70
commit
4e08d50d1f
|
@ -77,7 +77,7 @@ static int cs47l24_adsp_power_ev(struct snd_soc_dapm_widget *w,
|
||||||
|
|
||||||
wm_adsp2_set_dspclk(w, v);
|
wm_adsp2_set_dspclk(w, v);
|
||||||
|
|
||||||
return wm_adsp2_early_event(w, kcontrol, event);
|
return wm_adsp_early_event(w, kcontrol, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
|
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
|
||||||
|
|
|
@ -661,7 +661,7 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return wm_adsp2_early_event(w, kcontrol, event);
|
return wm_adsp_early_event(w, kcontrol, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
|
static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
|
||||||
|
|
|
@ -213,7 +213,7 @@ static int wm5110_adsp_power_ev(struct snd_soc_dapm_widget *w,
|
||||||
|
|
||||||
wm_adsp2_set_dspclk(w, v);
|
wm_adsp2_set_dspclk(w, v);
|
||||||
|
|
||||||
return wm_adsp2_early_event(w, kcontrol, event);
|
return wm_adsp_early_event(w, kcontrol, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct reg_sequence wm5110_no_dre_left_enable[] = {
|
static const struct reg_sequence wm5110_no_dre_left_enable[] = {
|
||||||
|
|
|
@ -227,6 +227,9 @@
|
||||||
*/
|
*/
|
||||||
#define WM_ADSP_FW_EVENT_SHUTDOWN 0x000001
|
#define WM_ADSP_FW_EVENT_SHUTDOWN 0x000001
|
||||||
|
|
||||||
|
struct wm_adsp_ops wm_adsp1_ops;
|
||||||
|
struct wm_adsp_ops wm_adsp2_ops[];
|
||||||
|
|
||||||
struct wm_adsp_buf {
|
struct wm_adsp_buf {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
void *buf;
|
void *buf;
|
||||||
|
@ -1640,6 +1643,52 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int wm_adsp1_parse_sizes(struct wm_adsp *dsp,
|
||||||
|
const char * const file,
|
||||||
|
unsigned int pos,
|
||||||
|
const struct firmware *firmware)
|
||||||
|
{
|
||||||
|
const struct wmfw_adsp1_sizes *adsp1_sizes;
|
||||||
|
|
||||||
|
adsp1_sizes = (void *)&firmware->data[pos];
|
||||||
|
|
||||||
|
adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file,
|
||||||
|
le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm),
|
||||||
|
le32_to_cpu(adsp1_sizes->zm));
|
||||||
|
|
||||||
|
return pos + sizeof(*adsp1_sizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int wm_adsp2_parse_sizes(struct wm_adsp *dsp,
|
||||||
|
const char * const file,
|
||||||
|
unsigned int pos,
|
||||||
|
const struct firmware *firmware)
|
||||||
|
{
|
||||||
|
const struct wmfw_adsp2_sizes *adsp2_sizes;
|
||||||
|
|
||||||
|
adsp2_sizes = (void *)&firmware->data[pos];
|
||||||
|
|
||||||
|
adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file,
|
||||||
|
le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym),
|
||||||
|
le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm));
|
||||||
|
|
||||||
|
return pos + sizeof(*adsp2_sizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool wm_adsp_validate_version(struct wm_adsp *dsp, unsigned int version)
|
||||||
|
{
|
||||||
|
switch (version) {
|
||||||
|
case 0:
|
||||||
|
adsp_warn(dsp, "Deprecated file format %d\n", version);
|
||||||
|
return true;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int wm_adsp_load(struct wm_adsp *dsp)
|
static int wm_adsp_load(struct wm_adsp *dsp)
|
||||||
{
|
{
|
||||||
LIST_HEAD(buf_list);
|
LIST_HEAD(buf_list);
|
||||||
|
@ -1648,7 +1697,6 @@ static int wm_adsp_load(struct wm_adsp *dsp)
|
||||||
unsigned int pos = 0;
|
unsigned int pos = 0;
|
||||||
const struct wmfw_header *header;
|
const struct wmfw_header *header;
|
||||||
const struct wmfw_adsp1_sizes *adsp1_sizes;
|
const struct wmfw_adsp1_sizes *adsp1_sizes;
|
||||||
const struct wmfw_adsp2_sizes *adsp2_sizes;
|
|
||||||
const struct wmfw_footer *footer;
|
const struct wmfw_footer *footer;
|
||||||
const struct wmfw_region *region;
|
const struct wmfw_region *region;
|
||||||
const struct wm_adsp_region *mem;
|
const struct wm_adsp_region *mem;
|
||||||
|
@ -1657,7 +1705,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
|
||||||
struct wm_adsp_buf *buf;
|
struct wm_adsp_buf *buf;
|
||||||
unsigned int reg;
|
unsigned int reg;
|
||||||
int regions = 0;
|
int regions = 0;
|
||||||
int ret, offset, type, sizes;
|
int ret, offset, type;
|
||||||
|
|
||||||
file = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
file = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
|
@ -1688,15 +1736,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
|
||||||
goto out_fw;
|
goto out_fw;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (header->ver) {
|
if (!dsp->ops->validate_version(dsp, header->ver)) {
|
||||||
case 0:
|
|
||||||
adsp_warn(dsp, "%s: Depreciated file format %d\n",
|
|
||||||
file, header->ver);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
adsp_err(dsp, "%s: unknown file format %d\n",
|
adsp_err(dsp, "%s: unknown file format %d\n",
|
||||||
file, header->ver);
|
file, header->ver);
|
||||||
goto out_fw;
|
goto out_fw;
|
||||||
|
@ -1711,39 +1751,13 @@ static int wm_adsp_load(struct wm_adsp *dsp)
|
||||||
goto out_fw;
|
goto out_fw;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (dsp->type) {
|
pos = sizeof(*header);
|
||||||
case WMFW_ADSP1:
|
pos = dsp->ops->parse_sizes(dsp, file, pos, firmware);
|
||||||
pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
|
|
||||||
adsp1_sizes = (void *)&(header[1]);
|
|
||||||
footer = (void *)&(adsp1_sizes[1]);
|
|
||||||
sizes = sizeof(*adsp1_sizes);
|
|
||||||
|
|
||||||
adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n",
|
footer = (void *)&firmware->data[pos];
|
||||||
file, le32_to_cpu(adsp1_sizes->dm),
|
pos += sizeof(*footer);
|
||||||
le32_to_cpu(adsp1_sizes->pm),
|
|
||||||
le32_to_cpu(adsp1_sizes->zm));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMFW_ADSP2:
|
if (le32_to_cpu(header->len) != pos) {
|
||||||
pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer);
|
|
||||||
adsp2_sizes = (void *)&(header[1]);
|
|
||||||
footer = (void *)&(adsp2_sizes[1]);
|
|
||||||
sizes = sizeof(*adsp2_sizes);
|
|
||||||
|
|
||||||
adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n",
|
|
||||||
file, le32_to_cpu(adsp2_sizes->xm),
|
|
||||||
le32_to_cpu(adsp2_sizes->ym),
|
|
||||||
le32_to_cpu(adsp2_sizes->pm),
|
|
||||||
le32_to_cpu(adsp2_sizes->zm));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
WARN(1, "Unknown DSP type");
|
|
||||||
goto out_fw;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (le32_to_cpu(header->len) != sizeof(*header) +
|
|
||||||
sizes + sizeof(*footer)) {
|
|
||||||
adsp_err(dsp, "%s: unexpected header length %d\n",
|
adsp_err(dsp, "%s: unexpected header length %d\n",
|
||||||
file, le32_to_cpu(header->len));
|
file, le32_to_cpu(header->len));
|
||||||
goto out_fw;
|
goto out_fw;
|
||||||
|
@ -2458,6 +2472,8 @@ static int wm_adsp_common_init(struct wm_adsp *dsp)
|
||||||
|
|
||||||
int wm_adsp1_init(struct wm_adsp *dsp)
|
int wm_adsp1_init(struct wm_adsp *dsp)
|
||||||
{
|
{
|
||||||
|
dsp->ops = &wm_adsp1_ops;
|
||||||
|
|
||||||
return wm_adsp_common_init(dsp);
|
return wm_adsp_common_init(dsp);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(wm_adsp1_init);
|
EXPORT_SYMBOL_GPL(wm_adsp1_init);
|
||||||
|
@ -2577,23 +2593,11 @@ err_mutex:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(wm_adsp1_event);
|
EXPORT_SYMBOL_GPL(wm_adsp1_event);
|
||||||
|
|
||||||
static int wm_adsp2_ena(struct wm_adsp *dsp)
|
static int wm_adsp2v2_enable_core(struct wm_adsp *dsp)
|
||||||
{
|
{
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
int ret, count;
|
int ret, count;
|
||||||
|
|
||||||
switch (dsp->rev) {
|
|
||||||
case 0:
|
|
||||||
ret = regmap_update_bits_async(dsp->regmap,
|
|
||||||
dsp->base + ADSP2_CONTROL,
|
|
||||||
ADSP2_SYS_ENA, ADSP2_SYS_ENA);
|
|
||||||
if (ret != 0)
|
|
||||||
return ret;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for the RAM to start, should be near instantaneous */
|
/* Wait for the RAM to start, should be near instantaneous */
|
||||||
for (count = 0; count < 10; ++count) {
|
for (count = 0; count < 10; ++count) {
|
||||||
ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
|
ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
|
||||||
|
@ -2616,6 +2620,18 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int wm_adsp2_enable_core(struct wm_adsp *dsp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||||
|
ADSP2_SYS_ENA, ADSP2_SYS_ENA);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return wm_adsp2v2_enable_core(dsp);
|
||||||
|
}
|
||||||
|
|
||||||
static int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
|
static int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
|
||||||
{
|
{
|
||||||
struct regmap *regmap = dsp->regmap;
|
struct regmap *regmap = dsp->regmap;
|
||||||
|
@ -2646,7 +2662,36 @@ static int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wm_adsp2_boot_work(struct work_struct *work)
|
static int wm_adsp2_enable_memory(struct wm_adsp *dsp)
|
||||||
|
{
|
||||||
|
return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||||
|
ADSP2_MEM_ENA, ADSP2_MEM_ENA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wm_adsp2_disable_memory(struct wm_adsp *dsp)
|
||||||
|
{
|
||||||
|
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||||
|
ADSP2_MEM_ENA, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wm_adsp2_disable_core(struct wm_adsp *dsp)
|
||||||
|
{
|
||||||
|
regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
|
||||||
|
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
|
||||||
|
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
|
||||||
|
|
||||||
|
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||||
|
ADSP2_SYS_ENA, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wm_adsp2v2_disable_core(struct wm_adsp *dsp)
|
||||||
|
{
|
||||||
|
regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
|
||||||
|
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
|
||||||
|
regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wm_adsp_boot_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct wm_adsp *dsp = container_of(work,
|
struct wm_adsp *dsp = container_of(work,
|
||||||
struct wm_adsp,
|
struct wm_adsp,
|
||||||
|
@ -2655,20 +2700,23 @@ static void wm_adsp2_boot_work(struct work_struct *work)
|
||||||
|
|
||||||
mutex_lock(&dsp->pwr_lock);
|
mutex_lock(&dsp->pwr_lock);
|
||||||
|
|
||||||
ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
if (dsp->ops->enable_memory) {
|
||||||
ADSP2_MEM_ENA, ADSP2_MEM_ENA);
|
ret = dsp->ops->enable_memory(dsp);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto err_mutex;
|
goto err_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
ret = wm_adsp2_ena(dsp);
|
if (dsp->ops->enable_core) {
|
||||||
if (ret != 0)
|
ret = dsp->ops->enable_core(dsp);
|
||||||
goto err_mem;
|
if (ret != 0)
|
||||||
|
goto err_mem;
|
||||||
|
}
|
||||||
|
|
||||||
ret = wm_adsp_load(dsp);
|
ret = wm_adsp_load(dsp);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto err_ena;
|
goto err_ena;
|
||||||
|
|
||||||
ret = wm_adsp2_setup_algs(dsp);
|
ret = dsp->ops->setup_algs(dsp);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto err_ena;
|
goto err_ena;
|
||||||
|
|
||||||
|
@ -2681,17 +2729,8 @@ static void wm_adsp2_boot_work(struct work_struct *work)
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto err_ena;
|
goto err_ena;
|
||||||
|
|
||||||
switch (dsp->rev) {
|
if (dsp->ops->disable_core)
|
||||||
case 0:
|
dsp->ops->disable_core(dsp);
|
||||||
/* Turn DSP back off until we are ready to run */
|
|
||||||
ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
|
||||||
ADSP2_SYS_ENA, 0);
|
|
||||||
if (ret != 0)
|
|
||||||
goto err_ena;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp->booted = true;
|
dsp->booted = true;
|
||||||
|
|
||||||
|
@ -2700,11 +2739,11 @@ static void wm_adsp2_boot_work(struct work_struct *work)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
err_ena:
|
err_ena:
|
||||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
if (dsp->ops->disable_core)
|
||||||
ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
|
dsp->ops->disable_core(dsp);
|
||||||
err_mem:
|
err_mem:
|
||||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
if (dsp->ops->disable_memory)
|
||||||
ADSP2_MEM_ENA, 0);
|
dsp->ops->disable_memory(dsp);
|
||||||
err_mutex:
|
err_mutex:
|
||||||
mutex_unlock(&dsp->pwr_lock);
|
mutex_unlock(&dsp->pwr_lock);
|
||||||
}
|
}
|
||||||
|
@ -2771,18 +2810,12 @@ EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
|
||||||
|
|
||||||
static void wm_adsp_stop_watchdog(struct wm_adsp *dsp)
|
static void wm_adsp_stop_watchdog(struct wm_adsp *dsp)
|
||||||
{
|
{
|
||||||
switch (dsp->rev) {
|
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
|
||||||
case 0:
|
ADSP2_WDT_ENA_MASK, 0);
|
||||||
case 1:
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
|
|
||||||
ADSP2_WDT_ENA_MASK, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
|
int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
|
||||||
struct snd_kcontrol *kcontrol, int event)
|
struct snd_kcontrol *kcontrol, int event)
|
||||||
{
|
{
|
||||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||||
struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
|
struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
|
||||||
|
@ -2803,8 +2836,8 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
|
||||||
|
|
||||||
dsp->booted = false;
|
dsp->booted = false;
|
||||||
|
|
||||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
if (dsp->ops->disable_memory)
|
||||||
ADSP2_MEM_ENA, 0);
|
dsp->ops->disable_memory(dsp);
|
||||||
|
|
||||||
list_for_each_entry(ctl, &dsp->ctl_list, list)
|
list_for_each_entry(ctl, &dsp->ctl_list, list)
|
||||||
ctl->enabled = 0;
|
ctl->enabled = 0;
|
||||||
|
@ -2821,10 +2854,23 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
|
EXPORT_SYMBOL_GPL(wm_adsp_early_event);
|
||||||
|
|
||||||
int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
static int wm_adsp2_start_core(struct wm_adsp *dsp)
|
||||||
struct snd_kcontrol *kcontrol, int event)
|
{
|
||||||
|
return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||||
|
ADSP2_CORE_ENA | ADSP2_START,
|
||||||
|
ADSP2_CORE_ENA | ADSP2_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wm_adsp2_stop_core(struct wm_adsp *dsp)
|
||||||
|
{
|
||||||
|
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||||
|
ADSP2_CORE_ENA | ADSP2_START, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int wm_adsp_event(struct snd_soc_dapm_widget *w,
|
||||||
|
struct snd_kcontrol *kcontrol, int event)
|
||||||
{
|
{
|
||||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||||
struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
|
struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
|
||||||
|
@ -2842,23 +2888,31 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = wm_adsp2_ena(dsp);
|
if (dsp->ops->enable_core) {
|
||||||
if (ret != 0)
|
ret = dsp->ops->enable_core(dsp);
|
||||||
goto err;
|
if (ret != 0)
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Sync set controls */
|
/* Sync set controls */
|
||||||
ret = wm_coeff_sync_controls(dsp);
|
ret = wm_coeff_sync_controls(dsp);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
wm_adsp2_lock(dsp, dsp->lock_regions);
|
if (dsp->ops->lock_memory) {
|
||||||
|
ret = dsp->ops->lock_memory(dsp, dsp->lock_regions);
|
||||||
|
if (ret != 0) {
|
||||||
|
adsp_err(dsp, "Error configuring MPU: %d\n",
|
||||||
|
ret);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = regmap_update_bits(dsp->regmap,
|
if (dsp->ops->start_core) {
|
||||||
dsp->base + ADSP2_CONTROL,
|
ret = dsp->ops->start_core(dsp);
|
||||||
ADSP2_CORE_ENA | ADSP2_START,
|
if (ret != 0)
|
||||||
ADSP2_CORE_ENA | ADSP2_START);
|
goto err;
|
||||||
if (ret != 0)
|
}
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (wm_adsp_fw[dsp->fw].num_caps != 0) {
|
if (wm_adsp_fw[dsp->fw].num_caps != 0) {
|
||||||
ret = wm_adsp_buffer_init(dsp);
|
ret = wm_adsp_buffer_init(dsp);
|
||||||
|
@ -2869,56 +2923,27 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
||||||
dsp->running = true;
|
dsp->running = true;
|
||||||
|
|
||||||
mutex_unlock(&dsp->pwr_lock);
|
mutex_unlock(&dsp->pwr_lock);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SND_SOC_DAPM_PRE_PMD:
|
case SND_SOC_DAPM_PRE_PMD:
|
||||||
/* Tell the firmware to cleanup */
|
/* Tell the firmware to cleanup */
|
||||||
wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN);
|
wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN);
|
||||||
|
|
||||||
wm_adsp_stop_watchdog(dsp);
|
if (dsp->ops->stop_watchdog)
|
||||||
|
dsp->ops->stop_watchdog(dsp);
|
||||||
|
|
||||||
/* Log firmware state, it can be useful for analysis */
|
/* Log firmware state, it can be useful for analysis */
|
||||||
switch (dsp->rev) {
|
if (dsp->ops->show_fw_status)
|
||||||
case 0:
|
dsp->ops->show_fw_status(dsp);
|
||||||
wm_adsp2_show_fw_status(dsp);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
wm_adsp2v2_show_fw_status(dsp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&dsp->pwr_lock);
|
mutex_lock(&dsp->pwr_lock);
|
||||||
|
|
||||||
dsp->running = false;
|
dsp->running = false;
|
||||||
|
|
||||||
regmap_update_bits(dsp->regmap,
|
if (dsp->ops->stop_core)
|
||||||
dsp->base + ADSP2_CONTROL,
|
dsp->ops->stop_core(dsp);
|
||||||
ADSP2_CORE_ENA | ADSP2_START, 0);
|
if (dsp->ops->disable_core)
|
||||||
|
dsp->ops->disable_core(dsp);
|
||||||
/* Make sure DMAs are quiesced */
|
|
||||||
switch (dsp->rev) {
|
|
||||||
case 0:
|
|
||||||
regmap_write(dsp->regmap,
|
|
||||||
dsp->base + ADSP2_RDMA_CONFIG_1, 0);
|
|
||||||
regmap_write(dsp->regmap,
|
|
||||||
dsp->base + ADSP2_WDMA_CONFIG_1, 0);
|
|
||||||
regmap_write(dsp->regmap,
|
|
||||||
dsp->base + ADSP2_WDMA_CONFIG_2, 0);
|
|
||||||
|
|
||||||
regmap_update_bits(dsp->regmap,
|
|
||||||
dsp->base + ADSP2_CONTROL,
|
|
||||||
ADSP2_SYS_ENA, 0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
regmap_write(dsp->regmap,
|
|
||||||
dsp->base + ADSP2_RDMA_CONFIG_1, 0);
|
|
||||||
regmap_write(dsp->regmap,
|
|
||||||
dsp->base + ADSP2_WDMA_CONFIG_1, 0);
|
|
||||||
regmap_write(dsp->regmap,
|
|
||||||
dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wm_adsp_fw[dsp->fw].num_caps != 0)
|
if (wm_adsp_fw[dsp->fw].num_caps != 0)
|
||||||
wm_adsp_buffer_free(dsp);
|
wm_adsp_buffer_free(dsp);
|
||||||
|
@ -2936,12 +2961,14 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
err:
|
||||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
if (dsp->ops->stop_core)
|
||||||
ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
|
dsp->ops->stop_core(dsp);
|
||||||
|
if (dsp->ops->disable_core)
|
||||||
|
dsp->ops->disable_core(dsp);
|
||||||
mutex_unlock(&dsp->pwr_lock);
|
mutex_unlock(&dsp->pwr_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(wm_adsp2_event);
|
EXPORT_SYMBOL_GPL(wm_adsp_event);
|
||||||
|
|
||||||
int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
|
int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
|
||||||
{
|
{
|
||||||
|
@ -2987,12 +3014,18 @@ int wm_adsp2_init(struct wm_adsp *dsp)
|
||||||
"Failed to clear memory retention: %d\n", ret);
|
"Failed to clear memory retention: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dsp->ops = &wm_adsp2_ops[0];
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
dsp->ops = &wm_adsp2_ops[1];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
dsp->ops = &wm_adsp2_ops[2];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
|
INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3988,4 +4021,64 @@ error:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
|
EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
|
||||||
|
|
||||||
|
struct wm_adsp_ops wm_adsp1_ops = {
|
||||||
|
.validate_version = wm_adsp_validate_version,
|
||||||
|
.parse_sizes = wm_adsp1_parse_sizes,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wm_adsp_ops wm_adsp2_ops[] = {
|
||||||
|
{
|
||||||
|
.parse_sizes = wm_adsp2_parse_sizes,
|
||||||
|
.validate_version = wm_adsp_validate_version,
|
||||||
|
.setup_algs = wm_adsp2_setup_algs,
|
||||||
|
|
||||||
|
.show_fw_status = wm_adsp2_show_fw_status,
|
||||||
|
|
||||||
|
.enable_memory = wm_adsp2_enable_memory,
|
||||||
|
.disable_memory = wm_adsp2_disable_memory,
|
||||||
|
|
||||||
|
.enable_core = wm_adsp2_enable_core,
|
||||||
|
.disable_core = wm_adsp2_disable_core,
|
||||||
|
|
||||||
|
.start_core = wm_adsp2_start_core,
|
||||||
|
.stop_core = wm_adsp2_stop_core,
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.parse_sizes = wm_adsp2_parse_sizes,
|
||||||
|
.validate_version = wm_adsp_validate_version,
|
||||||
|
.setup_algs = wm_adsp2_setup_algs,
|
||||||
|
|
||||||
|
.show_fw_status = wm_adsp2v2_show_fw_status,
|
||||||
|
|
||||||
|
.enable_memory = wm_adsp2_enable_memory,
|
||||||
|
.disable_memory = wm_adsp2_disable_memory,
|
||||||
|
.lock_memory = wm_adsp2_lock,
|
||||||
|
|
||||||
|
.enable_core = wm_adsp2v2_enable_core,
|
||||||
|
.disable_core = wm_adsp2v2_disable_core,
|
||||||
|
|
||||||
|
.start_core = wm_adsp2_start_core,
|
||||||
|
.stop_core = wm_adsp2_stop_core,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.parse_sizes = wm_adsp2_parse_sizes,
|
||||||
|
.validate_version = wm_adsp_validate_version,
|
||||||
|
.setup_algs = wm_adsp2_setup_algs,
|
||||||
|
|
||||||
|
.show_fw_status = wm_adsp2v2_show_fw_status,
|
||||||
|
.stop_watchdog = wm_adsp_stop_watchdog,
|
||||||
|
|
||||||
|
.enable_memory = wm_adsp2_enable_memory,
|
||||||
|
.disable_memory = wm_adsp2_disable_memory,
|
||||||
|
.lock_memory = wm_adsp2_lock,
|
||||||
|
|
||||||
|
.enable_core = wm_adsp2v2_enable_core,
|
||||||
|
.disable_core = wm_adsp2v2_disable_core,
|
||||||
|
|
||||||
|
.start_core = wm_adsp2_start_core,
|
||||||
|
.stop_core = wm_adsp2_stop_core,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|
|
@ -54,6 +54,7 @@ struct wm_adsp_alg_region {
|
||||||
|
|
||||||
struct wm_adsp_compr;
|
struct wm_adsp_compr;
|
||||||
struct wm_adsp_compr_buf;
|
struct wm_adsp_compr_buf;
|
||||||
|
struct wm_adsp_ops;
|
||||||
|
|
||||||
struct wm_adsp {
|
struct wm_adsp {
|
||||||
const char *part;
|
const char *part;
|
||||||
|
@ -66,6 +67,8 @@ struct wm_adsp {
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
struct snd_soc_component *component;
|
struct snd_soc_component *component;
|
||||||
|
|
||||||
|
struct wm_adsp_ops *ops;
|
||||||
|
|
||||||
unsigned int base;
|
unsigned int base;
|
||||||
unsigned int sysclk_reg;
|
unsigned int sysclk_reg;
|
||||||
unsigned int sysclk_mask;
|
unsigned int sysclk_mask;
|
||||||
|
@ -106,6 +109,28 @@ struct wm_adsp {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wm_adsp_ops {
|
||||||
|
bool (*validate_version)(struct wm_adsp *dsp, unsigned int version);
|
||||||
|
unsigned int (*parse_sizes)(struct wm_adsp *dsp,
|
||||||
|
const char * const file,
|
||||||
|
unsigned int pos,
|
||||||
|
const struct firmware *firmware);
|
||||||
|
int (*setup_algs)(struct wm_adsp *dsp);
|
||||||
|
|
||||||
|
void (*show_fw_status)(struct wm_adsp *dsp);
|
||||||
|
void (*stop_watchdog)(struct wm_adsp *dsp);
|
||||||
|
|
||||||
|
int (*enable_memory)(struct wm_adsp *dsp);
|
||||||
|
void (*disable_memory)(struct wm_adsp *dsp);
|
||||||
|
int (*lock_memory)(struct wm_adsp *dsp, unsigned int lock_regions);
|
||||||
|
|
||||||
|
int (*enable_core)(struct wm_adsp *dsp);
|
||||||
|
void (*disable_core)(struct wm_adsp *dsp);
|
||||||
|
|
||||||
|
int (*start_core)(struct wm_adsp *dsp);
|
||||||
|
void (*stop_core)(struct wm_adsp *dsp);
|
||||||
|
};
|
||||||
|
|
||||||
#define WM_ADSP1(wname, num) \
|
#define WM_ADSP1(wname, num) \
|
||||||
SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
|
SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
|
||||||
wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
|
wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
|
||||||
|
@ -121,7 +146,7 @@ struct wm_adsp {
|
||||||
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \
|
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \
|
||||||
.subseq = 100, /* Ensure we run after SYSCLK supply widget */ }, \
|
.subseq = 100, /* Ensure we run after SYSCLK supply widget */ }, \
|
||||||
{ .id = snd_soc_dapm_out_drv, .name = wname, \
|
{ .id = snd_soc_dapm_out_drv, .name = wname, \
|
||||||
.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
|
.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp_event, \
|
||||||
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
|
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
|
||||||
|
|
||||||
#define WM_ADSP_FW_CONTROL(dspname, num) \
|
#define WM_ADSP_FW_CONTROL(dspname, num) \
|
||||||
|
@ -138,13 +163,13 @@ int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *com
|
||||||
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
|
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
|
||||||
struct snd_kcontrol *kcontrol, int event);
|
struct snd_kcontrol *kcontrol, int event);
|
||||||
|
|
||||||
int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
|
int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
|
||||||
struct snd_kcontrol *kcontrol, int event);
|
struct snd_kcontrol *kcontrol, int event);
|
||||||
|
|
||||||
irqreturn_t wm_adsp2_bus_error(struct wm_adsp *adsp);
|
irqreturn_t wm_adsp2_bus_error(struct wm_adsp *adsp);
|
||||||
|
|
||||||
int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
int wm_adsp_event(struct snd_soc_dapm_widget *w,
|
||||||
struct snd_kcontrol *kcontrol, int event);
|
struct snd_kcontrol *kcontrol, int event);
|
||||||
|
|
||||||
int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq);
|
int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue