cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wm_adsp.c (52102B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * wm_adsp.c  --  Wolfson ADSP support
      4 *
      5 * Copyright 2012 Wolfson Microelectronics plc
      6 *
      7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
      8 */
      9
     10#include <linux/ctype.h>
     11#include <linux/module.h>
     12#include <linux/moduleparam.h>
     13#include <linux/init.h>
     14#include <linux/delay.h>
     15#include <linux/firmware.h>
     16#include <linux/list.h>
     17#include <linux/pm.h>
     18#include <linux/pm_runtime.h>
     19#include <linux/regmap.h>
     20#include <linux/regulator/consumer.h>
     21#include <linux/slab.h>
     22#include <linux/workqueue.h>
     23#include <linux/debugfs.h>
     24#include <sound/core.h>
     25#include <sound/pcm.h>
     26#include <sound/pcm_params.h>
     27#include <sound/soc.h>
     28#include <sound/jack.h>
     29#include <sound/initval.h>
     30#include <sound/tlv.h>
     31
     32#include "wm_adsp.h"
     33
     34#define adsp_crit(_dsp, fmt, ...) \
     35	dev_crit(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
     36#define adsp_err(_dsp, fmt, ...) \
     37	dev_err(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
     38#define adsp_warn(_dsp, fmt, ...) \
     39	dev_warn(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
     40#define adsp_info(_dsp, fmt, ...) \
     41	dev_info(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
     42#define adsp_dbg(_dsp, fmt, ...) \
     43	dev_dbg(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
     44
     45#define compr_err(_obj, fmt, ...) \
     46	adsp_err(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
     47		 ##__VA_ARGS__)
     48#define compr_dbg(_obj, fmt, ...) \
     49	adsp_dbg(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
     50		 ##__VA_ARGS__)
     51
     52#define ADSP_MAX_STD_CTRL_SIZE               512
     53
     54static const struct cs_dsp_client_ops wm_adsp1_client_ops;
     55static const struct cs_dsp_client_ops wm_adsp2_client_ops;
     56
     57#define WM_ADSP_FW_MBC_VSS  0
     58#define WM_ADSP_FW_HIFI     1
     59#define WM_ADSP_FW_TX       2
     60#define WM_ADSP_FW_TX_SPK   3
     61#define WM_ADSP_FW_RX       4
     62#define WM_ADSP_FW_RX_ANC   5
     63#define WM_ADSP_FW_CTRL     6
     64#define WM_ADSP_FW_ASR      7
     65#define WM_ADSP_FW_TRACE    8
     66#define WM_ADSP_FW_SPK_PROT 9
     67#define WM_ADSP_FW_SPK_CALI 10
     68#define WM_ADSP_FW_SPK_DIAG 11
     69#define WM_ADSP_FW_MISC     12
     70
     71#define WM_ADSP_NUM_FW      13
     72
     73static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
     74	[WM_ADSP_FW_MBC_VSS] =  "MBC/VSS",
     75	[WM_ADSP_FW_HIFI] =     "MasterHiFi",
     76	[WM_ADSP_FW_TX] =       "Tx",
     77	[WM_ADSP_FW_TX_SPK] =   "Tx Speaker",
     78	[WM_ADSP_FW_RX] =       "Rx",
     79	[WM_ADSP_FW_RX_ANC] =   "Rx ANC",
     80	[WM_ADSP_FW_CTRL] =     "Voice Ctrl",
     81	[WM_ADSP_FW_ASR] =      "ASR Assist",
     82	[WM_ADSP_FW_TRACE] =    "Dbg Trace",
     83	[WM_ADSP_FW_SPK_PROT] = "Protection",
     84	[WM_ADSP_FW_SPK_CALI] = "Calibration",
     85	[WM_ADSP_FW_SPK_DIAG] = "Diagnostic",
     86	[WM_ADSP_FW_MISC] =     "Misc",
     87};
     88
     89struct wm_adsp_system_config_xm_hdr {
     90	__be32 sys_enable;
     91	__be32 fw_id;
     92	__be32 fw_rev;
     93	__be32 boot_status;
     94	__be32 watchdog;
     95	__be32 dma_buffer_size;
     96	__be32 rdma[6];
     97	__be32 wdma[8];
     98	__be32 build_job_name[3];
     99	__be32 build_job_number;
    100} __packed;
    101
    102struct wm_halo_system_config_xm_hdr {
    103	__be32 halo_heartbeat;
    104	__be32 build_job_name[3];
    105	__be32 build_job_number;
    106} __packed;
    107
    108struct wm_adsp_alg_xm_struct {
    109	__be32 magic;
    110	__be32 smoothing;
    111	__be32 threshold;
    112	__be32 host_buf_ptr;
    113	__be32 start_seq;
    114	__be32 high_water_mark;
    115	__be32 low_water_mark;
    116	__be64 smoothed_power;
    117} __packed;
    118
    119struct wm_adsp_host_buf_coeff_v1 {
    120	__be32 host_buf_ptr;		/* Host buffer pointer */
    121	__be32 versions;		/* Version numbers */
    122	__be32 name[4];			/* The buffer name */
    123} __packed;
    124
    125struct wm_adsp_buffer {
    126	__be32 buf1_base;		/* Base addr of first buffer area */
    127	__be32 buf1_size;		/* Size of buf1 area in DSP words */
    128	__be32 buf2_base;		/* Base addr of 2nd buffer area */
    129	__be32 buf1_buf2_size;		/* Size of buf1+buf2 in DSP words */
    130	__be32 buf3_base;		/* Base addr of buf3 area */
    131	__be32 buf_total_size;		/* Size of buf1+buf2+buf3 in DSP words */
    132	__be32 high_water_mark;		/* Point at which IRQ is asserted */
    133	__be32 irq_count;		/* bits 1-31 count IRQ assertions */
    134	__be32 irq_ack;			/* acked IRQ count, bit 0 enables IRQ */
    135	__be32 next_write_index;	/* word index of next write */
    136	__be32 next_read_index;		/* word index of next read */
    137	__be32 error;			/* error if any */
    138	__be32 oldest_block_index;	/* word index of oldest surviving */
    139	__be32 requested_rewind;	/* how many blocks rewind was done */
    140	__be32 reserved_space;		/* internal */
    141	__be32 min_free;		/* min free space since stream start */
    142	__be32 blocks_written[2];	/* total blocks written (64 bit) */
    143	__be32 words_written[2];	/* total words written (64 bit) */
    144} __packed;
    145
    146struct wm_adsp_compr;
    147
    148struct wm_adsp_compr_buf {
    149	struct list_head list;
    150	struct wm_adsp *dsp;
    151	struct wm_adsp_compr *compr;
    152
    153	struct wm_adsp_buffer_region *regions;
    154	u32 host_buf_ptr;
    155
    156	u32 error;
    157	u32 irq_count;
    158	int read_index;
    159	int avail;
    160	int host_buf_mem_type;
    161
    162	char *name;
    163};
    164
    165struct wm_adsp_compr {
    166	struct list_head list;
    167	struct wm_adsp *dsp;
    168	struct wm_adsp_compr_buf *buf;
    169
    170	struct snd_compr_stream *stream;
    171	struct snd_compressed_buffer size;
    172
    173	u32 *raw_buf;
    174	unsigned int copied_total;
    175
    176	unsigned int sample_rate;
    177
    178	const char *name;
    179};
    180
    181#define WM_ADSP_MIN_FRAGMENTS          1
    182#define WM_ADSP_MAX_FRAGMENTS          256
    183#define WM_ADSP_MIN_FRAGMENT_SIZE      (16 * CS_DSP_DATA_WORD_SIZE)
    184#define WM_ADSP_MAX_FRAGMENT_SIZE      (4096 * CS_DSP_DATA_WORD_SIZE)
    185
    186#define WM_ADSP_ALG_XM_STRUCT_MAGIC    0x49aec7
    187
    188#define HOST_BUFFER_FIELD(field) \
    189	(offsetof(struct wm_adsp_buffer, field) / sizeof(__be32))
    190
    191#define ALG_XM_FIELD(field) \
    192	(offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32))
    193
    194#define HOST_BUF_COEFF_SUPPORTED_COMPAT_VER	1
    195
    196#define HOST_BUF_COEFF_COMPAT_VER_MASK		0xFF00
    197#define HOST_BUF_COEFF_COMPAT_VER_SHIFT		8
    198
    199static int wm_adsp_buffer_init(struct wm_adsp *dsp);
    200static int wm_adsp_buffer_free(struct wm_adsp *dsp);
    201
    202struct wm_adsp_buffer_region {
    203	unsigned int offset;
    204	unsigned int cumulative_size;
    205	unsigned int mem_type;
    206	unsigned int base_addr;
    207};
    208
    209struct wm_adsp_buffer_region_def {
    210	unsigned int mem_type;
    211	unsigned int base_offset;
    212	unsigned int size_offset;
    213};
    214
    215static const struct wm_adsp_buffer_region_def default_regions[] = {
    216	{
    217		.mem_type = WMFW_ADSP2_XM,
    218		.base_offset = HOST_BUFFER_FIELD(buf1_base),
    219		.size_offset = HOST_BUFFER_FIELD(buf1_size),
    220	},
    221	{
    222		.mem_type = WMFW_ADSP2_XM,
    223		.base_offset = HOST_BUFFER_FIELD(buf2_base),
    224		.size_offset = HOST_BUFFER_FIELD(buf1_buf2_size),
    225	},
    226	{
    227		.mem_type = WMFW_ADSP2_YM,
    228		.base_offset = HOST_BUFFER_FIELD(buf3_base),
    229		.size_offset = HOST_BUFFER_FIELD(buf_total_size),
    230	},
    231};
    232
    233struct wm_adsp_fw_caps {
    234	u32 id;
    235	struct snd_codec_desc desc;
    236	int num_regions;
    237	const struct wm_adsp_buffer_region_def *region_defs;
    238};
    239
    240static const struct wm_adsp_fw_caps ctrl_caps[] = {
    241	{
    242		.id = SND_AUDIOCODEC_BESPOKE,
    243		.desc = {
    244			.max_ch = 8,
    245			.sample_rates = { 16000 },
    246			.num_sample_rates = 1,
    247			.formats = SNDRV_PCM_FMTBIT_S16_LE,
    248		},
    249		.num_regions = ARRAY_SIZE(default_regions),
    250		.region_defs = default_regions,
    251	},
    252};
    253
    254static const struct wm_adsp_fw_caps trace_caps[] = {
    255	{
    256		.id = SND_AUDIOCODEC_BESPOKE,
    257		.desc = {
    258			.max_ch = 8,
    259			.sample_rates = {
    260				4000, 8000, 11025, 12000, 16000, 22050,
    261				24000, 32000, 44100, 48000, 64000, 88200,
    262				96000, 176400, 192000
    263			},
    264			.num_sample_rates = 15,
    265			.formats = SNDRV_PCM_FMTBIT_S16_LE,
    266		},
    267		.num_regions = ARRAY_SIZE(default_regions),
    268		.region_defs = default_regions,
    269	},
    270};
    271
    272static const struct {
    273	const char *file;
    274	int compr_direction;
    275	int num_caps;
    276	const struct wm_adsp_fw_caps *caps;
    277	bool voice_trigger;
    278} wm_adsp_fw[WM_ADSP_NUM_FW] = {
    279	[WM_ADSP_FW_MBC_VSS] =  { .file = "mbc-vss" },
    280	[WM_ADSP_FW_HIFI] =     { .file = "hifi" },
    281	[WM_ADSP_FW_TX] =       { .file = "tx" },
    282	[WM_ADSP_FW_TX_SPK] =   { .file = "tx-spk" },
    283	[WM_ADSP_FW_RX] =       { .file = "rx" },
    284	[WM_ADSP_FW_RX_ANC] =   { .file = "rx-anc" },
    285	[WM_ADSP_FW_CTRL] =     {
    286		.file = "ctrl",
    287		.compr_direction = SND_COMPRESS_CAPTURE,
    288		.num_caps = ARRAY_SIZE(ctrl_caps),
    289		.caps = ctrl_caps,
    290		.voice_trigger = true,
    291	},
    292	[WM_ADSP_FW_ASR] =      { .file = "asr" },
    293	[WM_ADSP_FW_TRACE] =    {
    294		.file = "trace",
    295		.compr_direction = SND_COMPRESS_CAPTURE,
    296		.num_caps = ARRAY_SIZE(trace_caps),
    297		.caps = trace_caps,
    298	},
    299	[WM_ADSP_FW_SPK_PROT] = {
    300		.file = "spk-prot",
    301		.compr_direction = SND_COMPRESS_CAPTURE,
    302		.num_caps = ARRAY_SIZE(trace_caps),
    303		.caps = trace_caps,
    304	},
    305	[WM_ADSP_FW_SPK_CALI] = { .file = "spk-cali" },
    306	[WM_ADSP_FW_SPK_DIAG] = { .file = "spk-diag" },
    307	[WM_ADSP_FW_MISC] =     { .file = "misc" },
    308};
    309
    310struct wm_coeff_ctl {
    311	const char *name;
    312	struct cs_dsp_coeff_ctl *cs_ctl;
    313	struct soc_bytes_ext bytes_ext;
    314	struct work_struct work;
    315};
    316
    317int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
    318		   struct snd_ctl_elem_value *ucontrol)
    319{
    320	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
    321	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
    322	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
    323
    324	ucontrol->value.enumerated.item[0] = dsp[e->shift_l].fw;
    325
    326	return 0;
    327}
    328EXPORT_SYMBOL_GPL(wm_adsp_fw_get);
    329
    330int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
    331		   struct snd_ctl_elem_value *ucontrol)
    332{
    333	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
    334	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
    335	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
    336	int ret = 1;
    337
    338	if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw)
    339		return 0;
    340
    341	if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW)
    342		return -EINVAL;
    343
    344	mutex_lock(&dsp[e->shift_l].cs_dsp.pwr_lock);
    345
    346	if (dsp[e->shift_l].cs_dsp.booted || !list_empty(&dsp[e->shift_l].compr_list))
    347		ret = -EBUSY;
    348	else
    349		dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0];
    350
    351	mutex_unlock(&dsp[e->shift_l].cs_dsp.pwr_lock);
    352
    353	return ret;
    354}
    355EXPORT_SYMBOL_GPL(wm_adsp_fw_put);
    356
    357const struct soc_enum wm_adsp_fw_enum[] = {
    358	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
    359	SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
    360	SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
    361	SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
    362	SOC_ENUM_SINGLE(0, 4, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
    363	SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
    364	SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
    365};
    366EXPORT_SYMBOL_GPL(wm_adsp_fw_enum);
    367
    368static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
    369{
    370	return container_of(ext, struct wm_coeff_ctl, bytes_ext);
    371}
    372
    373static int wm_coeff_info(struct snd_kcontrol *kctl,
    374			 struct snd_ctl_elem_info *uinfo)
    375{
    376	struct soc_bytes_ext *bytes_ext =
    377		(struct soc_bytes_ext *)kctl->private_value;
    378	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
    379	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
    380
    381	switch (cs_ctl->type) {
    382	case WMFW_CTL_TYPE_ACKED:
    383		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    384		uinfo->value.integer.min = CS_DSP_ACKED_CTL_MIN_VALUE;
    385		uinfo->value.integer.max = CS_DSP_ACKED_CTL_MAX_VALUE;
    386		uinfo->value.integer.step = 1;
    387		uinfo->count = 1;
    388		break;
    389	default:
    390		uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
    391		uinfo->count = cs_ctl->len;
    392		break;
    393	}
    394
    395	return 0;
    396}
    397
    398static int wm_coeff_put(struct snd_kcontrol *kctl,
    399			struct snd_ctl_elem_value *ucontrol)
    400{
    401	struct soc_bytes_ext *bytes_ext =
    402		(struct soc_bytes_ext *)kctl->private_value;
    403	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
    404	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
    405	char *p = ucontrol->value.bytes.data;
    406	int ret = 0;
    407
    408	mutex_lock(&cs_ctl->dsp->pwr_lock);
    409	ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, p, cs_ctl->len);
    410	mutex_unlock(&cs_ctl->dsp->pwr_lock);
    411
    412	return ret;
    413}
    414
    415static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
    416			    const unsigned int __user *bytes, unsigned int size)
    417{
    418	struct soc_bytes_ext *bytes_ext =
    419		(struct soc_bytes_ext *)kctl->private_value;
    420	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
    421	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
    422	int ret = 0;
    423
    424	mutex_lock(&cs_ctl->dsp->pwr_lock);
    425
    426	if (copy_from_user(cs_ctl->cache, bytes, size))
    427		ret = -EFAULT;
    428	else
    429		ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, cs_ctl->cache, size);
    430
    431	mutex_unlock(&cs_ctl->dsp->pwr_lock);
    432
    433	return ret;
    434}
    435
    436static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
    437			      struct snd_ctl_elem_value *ucontrol)
    438{
    439	struct soc_bytes_ext *bytes_ext =
    440		(struct soc_bytes_ext *)kctl->private_value;
    441	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
    442	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
    443	unsigned int val = ucontrol->value.integer.value[0];
    444	int ret;
    445
    446	if (val == 0)
    447		return 0;	/* 0 means no event */
    448
    449	mutex_lock(&cs_ctl->dsp->pwr_lock);
    450
    451	if (cs_ctl->enabled)
    452		ret = cs_dsp_coeff_write_acked_control(cs_ctl, val);
    453	else
    454		ret = -EPERM;
    455
    456	mutex_unlock(&cs_ctl->dsp->pwr_lock);
    457
    458	return ret;
    459}
    460
    461static int wm_coeff_get(struct snd_kcontrol *kctl,
    462			struct snd_ctl_elem_value *ucontrol)
    463{
    464	struct soc_bytes_ext *bytes_ext =
    465		(struct soc_bytes_ext *)kctl->private_value;
    466	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
    467	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
    468	char *p = ucontrol->value.bytes.data;
    469	int ret;
    470
    471	mutex_lock(&cs_ctl->dsp->pwr_lock);
    472	ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, p, cs_ctl->len);
    473	mutex_unlock(&cs_ctl->dsp->pwr_lock);
    474
    475	return ret;
    476}
    477
    478static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
    479			    unsigned int __user *bytes, unsigned int size)
    480{
    481	struct soc_bytes_ext *bytes_ext =
    482		(struct soc_bytes_ext *)kctl->private_value;
    483	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
    484	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
    485	int ret = 0;
    486
    487	mutex_lock(&cs_ctl->dsp->pwr_lock);
    488
    489	ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, cs_ctl->cache, size);
    490
    491	if (!ret && copy_to_user(bytes, cs_ctl->cache, size))
    492		ret = -EFAULT;
    493
    494	mutex_unlock(&cs_ctl->dsp->pwr_lock);
    495
    496	return ret;
    497}
    498
    499static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol,
    500			      struct snd_ctl_elem_value *ucontrol)
    501{
    502	/*
    503	 * Although it's not useful to read an acked control, we must satisfy
    504	 * user-side assumptions that all controls are readable and that a
    505	 * write of the same value should be filtered out (it's valid to send
    506	 * the same event number again to the firmware). We therefore return 0,
    507	 * meaning "no event" so valid event numbers will always be a change
    508	 */
    509	ucontrol->value.integer.value[0] = 0;
    510
    511	return 0;
    512}
    513
    514static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len)
    515{
    516	unsigned int out, rd, wr, vol;
    517
    518	if (len > ADSP_MAX_STD_CTRL_SIZE) {
    519		rd = SNDRV_CTL_ELEM_ACCESS_TLV_READ;
    520		wr = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE;
    521		vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
    522
    523		out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
    524	} else {
    525		rd = SNDRV_CTL_ELEM_ACCESS_READ;
    526		wr = SNDRV_CTL_ELEM_ACCESS_WRITE;
    527		vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
    528
    529		out = 0;
    530	}
    531
    532	if (in) {
    533		out |= rd;
    534		if (in & WMFW_CTL_FLAG_WRITEABLE)
    535			out |= wr;
    536		if (in & WMFW_CTL_FLAG_VOLATILE)
    537			out |= vol;
    538	} else {
    539		out |= rd | wr | vol;
    540	}
    541
    542	return out;
    543}
    544
    545static void wm_adsp_ctl_work(struct work_struct *work)
    546{
    547	struct wm_coeff_ctl *ctl = container_of(work,
    548						struct wm_coeff_ctl,
    549						work);
    550	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
    551	struct wm_adsp *dsp = container_of(cs_ctl->dsp,
    552					   struct wm_adsp,
    553					   cs_dsp);
    554	struct snd_kcontrol_new *kcontrol;
    555
    556	kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
    557	if (!kcontrol)
    558		return;
    559
    560	kcontrol->name = ctl->name;
    561	kcontrol->info = wm_coeff_info;
    562	kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
    563	kcontrol->tlv.c = snd_soc_bytes_tlv_callback;
    564	kcontrol->private_value = (unsigned long)&ctl->bytes_ext;
    565	kcontrol->access = wmfw_convert_flags(cs_ctl->flags, cs_ctl->len);
    566
    567	switch (cs_ctl->type) {
    568	case WMFW_CTL_TYPE_ACKED:
    569		kcontrol->get = wm_coeff_get_acked;
    570		kcontrol->put = wm_coeff_put_acked;
    571		break;
    572	default:
    573		if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
    574			ctl->bytes_ext.max = cs_ctl->len;
    575			ctl->bytes_ext.get = wm_coeff_tlv_get;
    576			ctl->bytes_ext.put = wm_coeff_tlv_put;
    577		} else {
    578			kcontrol->get = wm_coeff_get;
    579			kcontrol->put = wm_coeff_put;
    580		}
    581		break;
    582	}
    583
    584	snd_soc_add_component_controls(dsp->component, kcontrol, 1);
    585
    586	kfree(kcontrol);
    587}
    588
    589static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
    590{
    591	struct wm_adsp *dsp = container_of(cs_ctl->dsp, struct wm_adsp, cs_dsp);
    592	struct cs_dsp *cs_dsp = &dsp->cs_dsp;
    593	struct wm_coeff_ctl *ctl;
    594	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
    595	const char *region_name;
    596	int ret;
    597
    598	if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
    599		return 0;
    600
    601	region_name = cs_dsp_mem_region_name(cs_ctl->alg_region.type);
    602	if (!region_name) {
    603		adsp_err(dsp, "Unknown region type: %d\n", cs_ctl->alg_region.type);
    604		return -EINVAL;
    605	}
    606
    607	switch (cs_dsp->fw_ver) {
    608	case 0:
    609	case 1:
    610		ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
    611				"%s %s %x", cs_dsp->name, region_name,
    612				cs_ctl->alg_region.alg);
    613		break;
    614	case 2:
    615		ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
    616				"%s%c %.12s %x", cs_dsp->name, *region_name,
    617				wm_adsp_fw_text[dsp->fw], cs_ctl->alg_region.alg);
    618		break;
    619	default:
    620		ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
    621				"%s %.12s %x", cs_dsp->name,
    622				wm_adsp_fw_text[dsp->fw], cs_ctl->alg_region.alg);
    623		break;
    624	}
    625
    626	if (cs_ctl->subname) {
    627		int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
    628		int skip = 0;
    629
    630		if (dsp->component->name_prefix)
    631			avail -= strlen(dsp->component->name_prefix) + 1;
    632
    633		/* Truncate the subname from the start if it is too long */
    634		if (cs_ctl->subname_len > avail)
    635			skip = cs_ctl->subname_len - avail;
    636
    637		snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret,
    638			 " %.*s", cs_ctl->subname_len - skip, cs_ctl->subname + skip);
    639	}
    640
    641	ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
    642	if (!ctl)
    643		return -ENOMEM;
    644	ctl->cs_ctl = cs_ctl;
    645
    646	ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
    647	if (!ctl->name) {
    648		ret = -ENOMEM;
    649		goto err_ctl;
    650	}
    651
    652	cs_ctl->priv = ctl;
    653
    654	INIT_WORK(&ctl->work, wm_adsp_ctl_work);
    655	schedule_work(&ctl->work);
    656
    657	return 0;
    658
    659err_ctl:
    660	kfree(ctl);
    661
    662	return ret;
    663}
    664
    665static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl)
    666{
    667	struct wm_coeff_ctl *ctl = cs_ctl->priv;
    668
    669	cancel_work_sync(&ctl->work);
    670
    671	kfree(ctl->name);
    672	kfree(ctl);
    673}
    674
    675int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
    676		      unsigned int alg, void *buf, size_t len)
    677{
    678	struct cs_dsp_coeff_ctl *cs_ctl;
    679	struct wm_coeff_ctl *ctl;
    680	struct snd_kcontrol *kcontrol;
    681	char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
    682	int ret;
    683
    684	cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg);
    685	if (!cs_ctl)
    686		return -EINVAL;
    687
    688	ctl = cs_ctl->priv;
    689
    690	if (len > cs_ctl->len)
    691		return -EINVAL;
    692
    693	ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
    694	if (ret)
    695		return ret;
    696
    697	if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
    698		return 0;
    699
    700	if (dsp->component->name_prefix)
    701		snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s",
    702			 dsp->component->name_prefix, ctl->name);
    703	else
    704		snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s",
    705			 ctl->name);
    706
    707	kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl_name);
    708	if (!kcontrol) {
    709		adsp_err(dsp, "Can't find kcontrol %s\n", ctl_name);
    710		return -EINVAL;
    711	}
    712
    713	snd_ctl_notify(dsp->component->card->snd_card,
    714		       SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id);
    715
    716	return 0;
    717}
    718EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
    719
    720int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
    721		     unsigned int alg, void *buf, size_t len)
    722{
    723	struct cs_dsp_coeff_ctl *cs_ctl;
    724
    725	cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg);
    726	if (!cs_ctl)
    727		return -EINVAL;
    728
    729	if (len > cs_ctl->len)
    730		return -EINVAL;
    731
    732	return cs_dsp_coeff_read_ctrl(cs_ctl, 0, buf, len);
    733}
    734EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
    735
    736static void wm_adsp_release_firmware_files(struct wm_adsp *dsp,
    737					   const struct firmware *wmfw_firmware,
    738					   char *wmfw_filename,
    739					   const struct firmware *coeff_firmware,
    740					   char *coeff_filename)
    741{
    742	if (wmfw_firmware)
    743		release_firmware(wmfw_firmware);
    744	kfree(wmfw_filename);
    745
    746	if (coeff_firmware)
    747		release_firmware(coeff_firmware);
    748	kfree(coeff_filename);
    749}
    750
    751static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
    752					 const struct firmware **firmware, char **filename,
    753					 const char *dir, const char *system_name,
    754					 const char *asoc_component_prefix,
    755					 const char *filetype)
    756{
    757	struct cs_dsp *cs_dsp = &dsp->cs_dsp;
    758	char *s, c;
    759	int ret = 0;
    760
    761	if (system_name && asoc_component_prefix)
    762		*filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, dsp->part,
    763				      dsp->fwf_name, wm_adsp_fw[dsp->fw].file, system_name,
    764				      asoc_component_prefix, filetype);
    765	else if (system_name)
    766		*filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, dsp->part,
    767				      dsp->fwf_name, wm_adsp_fw[dsp->fw].file, system_name,
    768				      filetype);
    769	else
    770		*filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, dsp->part, dsp->fwf_name,
    771				      wm_adsp_fw[dsp->fw].file, filetype);
    772
    773	if (*filename == NULL)
    774		return -ENOMEM;
    775
    776	/*
    777	 * Make sure that filename is lower-case and any non alpha-numeric
    778	 * characters except full stop and forward slash are replaced with
    779	 * hyphens.
    780	 */
    781	s = *filename;
    782	while (*s) {
    783		c = *s;
    784		if (isalnum(c))
    785			*s = tolower(c);
    786		else if ((c != '.') && (c != '/'))
    787			*s = '-';
    788		s++;
    789	}
    790
    791	ret = firmware_request_nowarn(firmware, *filename, cs_dsp->dev);
    792	if (ret != 0) {
    793		adsp_dbg(dsp, "Failed to request '%s'\n", *filename);
    794		kfree(*filename);
    795		*filename = NULL;
    796	}
    797
    798	return ret;
    799}
    800
    801static const char *cirrus_dir = "cirrus/";
    802static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
    803					  const struct firmware **wmfw_firmware,
    804					  char **wmfw_filename,
    805					  const struct firmware **coeff_firmware,
    806					  char **coeff_filename)
    807{
    808	const char *system_name = dsp->system_name;
    809	const char *asoc_component_prefix = dsp->component->name_prefix;
    810	int ret = 0;
    811
    812	if (system_name && asoc_component_prefix) {
    813		if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
    814						   cirrus_dir, system_name,
    815						   asoc_component_prefix, "wmfw")) {
    816			adsp_dbg(dsp, "Found '%s'\n", *wmfw_filename);
    817			wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
    818						      cirrus_dir, system_name,
    819						      asoc_component_prefix, "bin");
    820			return 0;
    821		}
    822	}
    823
    824	if (system_name) {
    825		if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
    826						   cirrus_dir, system_name,
    827						   NULL, "wmfw")) {
    828			adsp_dbg(dsp, "Found '%s'\n", *wmfw_filename);
    829			if (asoc_component_prefix)
    830				wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
    831							      cirrus_dir, system_name,
    832							      asoc_component_prefix, "bin");
    833
    834			if (!*coeff_firmware)
    835				wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
    836							      cirrus_dir, system_name,
    837							      NULL, "bin");
    838			return 0;
    839		}
    840	}
    841
    842	if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
    843					   "", NULL, NULL, "wmfw")) {
    844		adsp_dbg(dsp, "Found '%s'\n", *wmfw_filename);
    845		wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
    846					      "", NULL, NULL, "bin");
    847		return 0;
    848	}
    849
    850	ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
    851					    cirrus_dir, NULL, NULL, "wmfw");
    852	if (!ret) {
    853		adsp_dbg(dsp, "Found '%s'\n", *wmfw_filename);
    854		wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
    855					      cirrus_dir, NULL, NULL, "bin");
    856		return 0;
    857	}
    858
    859	adsp_err(dsp, "Failed to request firmware <%s>%s-%s-%s<-%s<%s>>.wmfw\n",
    860		 cirrus_dir, dsp->part, dsp->fwf_name, wm_adsp_fw[dsp->fw].file,
    861		 system_name, asoc_component_prefix);
    862
    863	return -ENOENT;
    864}
    865
    866static int wm_adsp_common_init(struct wm_adsp *dsp)
    867{
    868	char *p;
    869
    870	INIT_LIST_HEAD(&dsp->compr_list);
    871	INIT_LIST_HEAD(&dsp->buffer_list);
    872
    873	if (!dsp->fwf_name) {
    874		p = devm_kstrdup(dsp->cs_dsp.dev, dsp->cs_dsp.name, GFP_KERNEL);
    875		if (!p)
    876			return -ENOMEM;
    877
    878		dsp->fwf_name = p;
    879		for (; *p != 0; ++p)
    880			*p = tolower(*p);
    881	}
    882
    883	return 0;
    884}
    885
    886int wm_adsp1_init(struct wm_adsp *dsp)
    887{
    888	int ret;
    889
    890	dsp->cs_dsp.client_ops = &wm_adsp1_client_ops;
    891
    892	ret = cs_dsp_adsp1_init(&dsp->cs_dsp);
    893	if (ret)
    894		return ret;
    895
    896	return wm_adsp_common_init(dsp);
    897}
    898EXPORT_SYMBOL_GPL(wm_adsp1_init);
    899
    900int wm_adsp1_event(struct snd_soc_dapm_widget *w,
    901		   struct snd_kcontrol *kcontrol,
    902		   int event)
    903{
    904	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    905	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
    906	struct wm_adsp *dsp = &dsps[w->shift];
    907	int ret = 0;
    908	char *wmfw_filename = NULL;
    909	const struct firmware *wmfw_firmware = NULL;
    910	char *coeff_filename = NULL;
    911	const struct firmware *coeff_firmware = NULL;
    912
    913	dsp->component = component;
    914
    915	switch (event) {
    916	case SND_SOC_DAPM_POST_PMU:
    917		ret = wm_adsp_request_firmware_files(dsp,
    918						     &wmfw_firmware, &wmfw_filename,
    919						     &coeff_firmware, &coeff_filename);
    920		if (ret)
    921			break;
    922
    923		ret = cs_dsp_adsp1_power_up(&dsp->cs_dsp,
    924					    wmfw_firmware, wmfw_filename,
    925					    coeff_firmware, coeff_filename,
    926					    wm_adsp_fw_text[dsp->fw]);
    927
    928		wm_adsp_release_firmware_files(dsp,
    929					       wmfw_firmware, wmfw_filename,
    930					       coeff_firmware, coeff_filename);
    931		break;
    932	case SND_SOC_DAPM_PRE_PMD:
    933		cs_dsp_adsp1_power_down(&dsp->cs_dsp);
    934		break;
    935	default:
    936		break;
    937	}
    938
    939	return ret;
    940}
    941EXPORT_SYMBOL_GPL(wm_adsp1_event);
    942
    943int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq)
    944{
    945	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    946	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
    947	struct wm_adsp *dsp = &dsps[w->shift];
    948
    949	return cs_dsp_set_dspclk(&dsp->cs_dsp, freq);
    950}
    951EXPORT_SYMBOL_GPL(wm_adsp2_set_dspclk);
    952
    953int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
    954			   struct snd_ctl_elem_value *ucontrol)
    955{
    956	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
    957	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
    958	struct soc_mixer_control *mc =
    959		(struct soc_mixer_control *)kcontrol->private_value;
    960	struct wm_adsp *dsp = &dsps[mc->shift - 1];
    961
    962	ucontrol->value.integer.value[0] = dsp->preloaded;
    963
    964	return 0;
    965}
    966EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get);
    967
    968int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
    969			   struct snd_ctl_elem_value *ucontrol)
    970{
    971	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
    972	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
    973	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
    974	struct soc_mixer_control *mc =
    975		(struct soc_mixer_control *)kcontrol->private_value;
    976	struct wm_adsp *dsp = &dsps[mc->shift - 1];
    977	char preload[32];
    978
    979	if (dsp->preloaded == ucontrol->value.integer.value[0])
    980		return 0;
    981
    982	snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name);
    983
    984	if (ucontrol->value.integer.value[0] || dsp->toggle_preload)
    985		snd_soc_component_force_enable_pin(component, preload);
    986	else
    987		snd_soc_component_disable_pin(component, preload);
    988
    989	snd_soc_dapm_sync(dapm);
    990
    991	flush_work(&dsp->boot_work);
    992
    993	dsp->preloaded = ucontrol->value.integer.value[0];
    994
    995	if (dsp->toggle_preload) {
    996		snd_soc_component_disable_pin(component, preload);
    997		snd_soc_dapm_sync(dapm);
    998	}
    999
   1000	return 1;
   1001}
   1002EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
   1003
   1004static void wm_adsp_boot_work(struct work_struct *work)
   1005{
   1006	struct wm_adsp *dsp = container_of(work,
   1007					   struct wm_adsp,
   1008					   boot_work);
   1009	int ret = 0;
   1010	char *wmfw_filename = NULL;
   1011	const struct firmware *wmfw_firmware = NULL;
   1012	char *coeff_filename = NULL;
   1013	const struct firmware *coeff_firmware = NULL;
   1014
   1015	ret = wm_adsp_request_firmware_files(dsp,
   1016					     &wmfw_firmware, &wmfw_filename,
   1017					     &coeff_firmware, &coeff_filename);
   1018	if (ret)
   1019		return;
   1020
   1021	cs_dsp_power_up(&dsp->cs_dsp,
   1022			wmfw_firmware, wmfw_filename,
   1023			coeff_firmware, coeff_filename,
   1024			wm_adsp_fw_text[dsp->fw]);
   1025
   1026	wm_adsp_release_firmware_files(dsp,
   1027				       wmfw_firmware, wmfw_filename,
   1028				       coeff_firmware, coeff_filename);
   1029}
   1030
   1031int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
   1032			struct snd_kcontrol *kcontrol, int event)
   1033{
   1034	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
   1035	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
   1036	struct wm_adsp *dsp = &dsps[w->shift];
   1037
   1038	switch (event) {
   1039	case SND_SOC_DAPM_PRE_PMU:
   1040		queue_work(system_unbound_wq, &dsp->boot_work);
   1041		break;
   1042	case SND_SOC_DAPM_PRE_PMD:
   1043		cs_dsp_power_down(&dsp->cs_dsp);
   1044		break;
   1045	default:
   1046		break;
   1047	}
   1048
   1049	return 0;
   1050}
   1051EXPORT_SYMBOL_GPL(wm_adsp_early_event);
   1052
   1053static int wm_adsp_event_post_run(struct cs_dsp *cs_dsp)
   1054{
   1055	struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
   1056
   1057	if (wm_adsp_fw[dsp->fw].num_caps != 0)
   1058		return wm_adsp_buffer_init(dsp);
   1059
   1060	return 0;
   1061}
   1062
   1063static void wm_adsp_event_post_stop(struct cs_dsp *cs_dsp)
   1064{
   1065	struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
   1066
   1067	if (wm_adsp_fw[dsp->fw].num_caps != 0)
   1068		wm_adsp_buffer_free(dsp);
   1069
   1070	dsp->fatal_error = false;
   1071}
   1072
   1073int wm_adsp_event(struct snd_soc_dapm_widget *w,
   1074		  struct snd_kcontrol *kcontrol, int event)
   1075{
   1076	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
   1077	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
   1078	struct wm_adsp *dsp = &dsps[w->shift];
   1079	int ret = 0;
   1080
   1081	switch (event) {
   1082	case SND_SOC_DAPM_POST_PMU:
   1083		flush_work(&dsp->boot_work);
   1084		ret = cs_dsp_run(&dsp->cs_dsp);
   1085		break;
   1086	case SND_SOC_DAPM_PRE_PMD:
   1087		cs_dsp_stop(&dsp->cs_dsp);
   1088		break;
   1089	default:
   1090		break;
   1091	}
   1092
   1093	return ret;
   1094}
   1095EXPORT_SYMBOL_GPL(wm_adsp_event);
   1096
   1097int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
   1098{
   1099	char preload[32];
   1100
   1101	snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name);
   1102	snd_soc_component_disable_pin(component, preload);
   1103
   1104	cs_dsp_init_debugfs(&dsp->cs_dsp, component->debugfs_root);
   1105
   1106	dsp->component = component;
   1107
   1108	return 0;
   1109}
   1110EXPORT_SYMBOL_GPL(wm_adsp2_component_probe);
   1111
   1112int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component)
   1113{
   1114	cs_dsp_cleanup_debugfs(&dsp->cs_dsp);
   1115
   1116	return 0;
   1117}
   1118EXPORT_SYMBOL_GPL(wm_adsp2_component_remove);
   1119
   1120int wm_adsp2_init(struct wm_adsp *dsp)
   1121{
   1122	int ret;
   1123
   1124	INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
   1125
   1126	dsp->sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr);
   1127	dsp->cs_dsp.client_ops = &wm_adsp2_client_ops;
   1128
   1129	ret = cs_dsp_adsp2_init(&dsp->cs_dsp);
   1130	if (ret)
   1131		return ret;
   1132
   1133	return wm_adsp_common_init(dsp);
   1134}
   1135EXPORT_SYMBOL_GPL(wm_adsp2_init);
   1136
   1137int wm_halo_init(struct wm_adsp *dsp)
   1138{
   1139	int ret;
   1140
   1141	INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
   1142
   1143	dsp->sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr);
   1144	dsp->cs_dsp.client_ops = &wm_adsp2_client_ops;
   1145
   1146	ret = cs_dsp_halo_init(&dsp->cs_dsp);
   1147	if (ret)
   1148		return ret;
   1149
   1150	return wm_adsp_common_init(dsp);
   1151}
   1152EXPORT_SYMBOL_GPL(wm_halo_init);
   1153
   1154void wm_adsp2_remove(struct wm_adsp *dsp)
   1155{
   1156	cs_dsp_remove(&dsp->cs_dsp);
   1157}
   1158EXPORT_SYMBOL_GPL(wm_adsp2_remove);
   1159
   1160static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
   1161{
   1162	return compr->buf != NULL;
   1163}
   1164
   1165static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
   1166{
   1167	struct wm_adsp_compr_buf *buf = NULL, *tmp;
   1168
   1169	if (compr->dsp->fatal_error)
   1170		return -EINVAL;
   1171
   1172	list_for_each_entry(tmp, &compr->dsp->buffer_list, list) {
   1173		if (!tmp->name || !strcmp(compr->name, tmp->name)) {
   1174			buf = tmp;
   1175			break;
   1176		}
   1177	}
   1178
   1179	if (!buf)
   1180		return -EINVAL;
   1181
   1182	compr->buf = buf;
   1183	buf->compr = compr;
   1184
   1185	return 0;
   1186}
   1187
   1188static void wm_adsp_compr_detach(struct wm_adsp_compr *compr)
   1189{
   1190	if (!compr)
   1191		return;
   1192
   1193	/* Wake the poll so it can see buffer is no longer attached */
   1194	if (compr->stream)
   1195		snd_compr_fragment_elapsed(compr->stream);
   1196
   1197	if (wm_adsp_compr_attached(compr)) {
   1198		compr->buf->compr = NULL;
   1199		compr->buf = NULL;
   1200	}
   1201}
   1202
   1203int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
   1204{
   1205	struct wm_adsp_compr *compr, *tmp;
   1206	struct snd_soc_pcm_runtime *rtd = stream->private_data;
   1207	int ret = 0;
   1208
   1209	mutex_lock(&dsp->cs_dsp.pwr_lock);
   1210
   1211	if (wm_adsp_fw[dsp->fw].num_caps == 0) {
   1212		adsp_err(dsp, "%s: Firmware does not support compressed API\n",
   1213			 asoc_rtd_to_codec(rtd, 0)->name);
   1214		ret = -ENXIO;
   1215		goto out;
   1216	}
   1217
   1218	if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
   1219		adsp_err(dsp, "%s: Firmware does not support stream direction\n",
   1220			 asoc_rtd_to_codec(rtd, 0)->name);
   1221		ret = -EINVAL;
   1222		goto out;
   1223	}
   1224
   1225	list_for_each_entry(tmp, &dsp->compr_list, list) {
   1226		if (!strcmp(tmp->name, asoc_rtd_to_codec(rtd, 0)->name)) {
   1227			adsp_err(dsp, "%s: Only a single stream supported per dai\n",
   1228				 asoc_rtd_to_codec(rtd, 0)->name);
   1229			ret = -EBUSY;
   1230			goto out;
   1231		}
   1232	}
   1233
   1234	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
   1235	if (!compr) {
   1236		ret = -ENOMEM;
   1237		goto out;
   1238	}
   1239
   1240	compr->dsp = dsp;
   1241	compr->stream = stream;
   1242	compr->name = asoc_rtd_to_codec(rtd, 0)->name;
   1243
   1244	list_add_tail(&compr->list, &dsp->compr_list);
   1245
   1246	stream->runtime->private_data = compr;
   1247
   1248out:
   1249	mutex_unlock(&dsp->cs_dsp.pwr_lock);
   1250
   1251	return ret;
   1252}
   1253EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
   1254
   1255int wm_adsp_compr_free(struct snd_soc_component *component,
   1256		       struct snd_compr_stream *stream)
   1257{
   1258	struct wm_adsp_compr *compr = stream->runtime->private_data;
   1259	struct wm_adsp *dsp = compr->dsp;
   1260
   1261	mutex_lock(&dsp->cs_dsp.pwr_lock);
   1262
   1263	wm_adsp_compr_detach(compr);
   1264	list_del(&compr->list);
   1265
   1266	kfree(compr->raw_buf);
   1267	kfree(compr);
   1268
   1269	mutex_unlock(&dsp->cs_dsp.pwr_lock);
   1270
   1271	return 0;
   1272}
   1273EXPORT_SYMBOL_GPL(wm_adsp_compr_free);
   1274
   1275static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
   1276				      struct snd_compr_params *params)
   1277{
   1278	struct wm_adsp_compr *compr = stream->runtime->private_data;
   1279	struct wm_adsp *dsp = compr->dsp;
   1280	const struct wm_adsp_fw_caps *caps;
   1281	const struct snd_codec_desc *desc;
   1282	int i, j;
   1283
   1284	if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE ||
   1285	    params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE ||
   1286	    params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS ||
   1287	    params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS ||
   1288	    params->buffer.fragment_size % CS_DSP_DATA_WORD_SIZE) {
   1289		compr_err(compr, "Invalid buffer fragsize=%d fragments=%d\n",
   1290			  params->buffer.fragment_size,
   1291			  params->buffer.fragments);
   1292
   1293		return -EINVAL;
   1294	}
   1295
   1296	for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) {
   1297		caps = &wm_adsp_fw[dsp->fw].caps[i];
   1298		desc = &caps->desc;
   1299
   1300		if (caps->id != params->codec.id)
   1301			continue;
   1302
   1303		if (stream->direction == SND_COMPRESS_PLAYBACK) {
   1304			if (desc->max_ch < params->codec.ch_out)
   1305				continue;
   1306		} else {
   1307			if (desc->max_ch < params->codec.ch_in)
   1308				continue;
   1309		}
   1310
   1311		if (!(desc->formats & (1 << params->codec.format)))
   1312			continue;
   1313
   1314		for (j = 0; j < desc->num_sample_rates; ++j)
   1315			if (desc->sample_rates[j] == params->codec.sample_rate)
   1316				return 0;
   1317	}
   1318
   1319	compr_err(compr, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
   1320		  params->codec.id, params->codec.ch_in, params->codec.ch_out,
   1321		  params->codec.sample_rate, params->codec.format);
   1322	return -EINVAL;
   1323}
   1324
   1325static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr)
   1326{
   1327	return compr->size.fragment_size / CS_DSP_DATA_WORD_SIZE;
   1328}
   1329
   1330int wm_adsp_compr_set_params(struct snd_soc_component *component,
   1331			     struct snd_compr_stream *stream,
   1332			     struct snd_compr_params *params)
   1333{
   1334	struct wm_adsp_compr *compr = stream->runtime->private_data;
   1335	unsigned int size;
   1336	int ret;
   1337
   1338	ret = wm_adsp_compr_check_params(stream, params);
   1339	if (ret)
   1340		return ret;
   1341
   1342	compr->size = params->buffer;
   1343
   1344	compr_dbg(compr, "fragment_size=%d fragments=%d\n",
   1345		  compr->size.fragment_size, compr->size.fragments);
   1346
   1347	size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
   1348	compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
   1349	if (!compr->raw_buf)
   1350		return -ENOMEM;
   1351
   1352	compr->sample_rate = params->codec.sample_rate;
   1353
   1354	return 0;
   1355}
   1356EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
   1357
   1358int wm_adsp_compr_get_caps(struct snd_soc_component *component,
   1359			   struct snd_compr_stream *stream,
   1360			   struct snd_compr_caps *caps)
   1361{
   1362	struct wm_adsp_compr *compr = stream->runtime->private_data;
   1363	int fw = compr->dsp->fw;
   1364	int i;
   1365
   1366	if (wm_adsp_fw[fw].caps) {
   1367		for (i = 0; i < wm_adsp_fw[fw].num_caps; i++)
   1368			caps->codecs[i] = wm_adsp_fw[fw].caps[i].id;
   1369
   1370		caps->num_codecs = i;
   1371		caps->direction = wm_adsp_fw[fw].compr_direction;
   1372
   1373		caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE;
   1374		caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE;
   1375		caps->min_fragments = WM_ADSP_MIN_FRAGMENTS;
   1376		caps->max_fragments = WM_ADSP_MAX_FRAGMENTS;
   1377	}
   1378
   1379	return 0;
   1380}
   1381EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
   1382
   1383static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
   1384				      unsigned int field_offset, u32 *data)
   1385{
   1386	return cs_dsp_read_data_word(&buf->dsp->cs_dsp, buf->host_buf_mem_type,
   1387				     buf->host_buf_ptr + field_offset, data);
   1388}
   1389
   1390static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
   1391				       unsigned int field_offset, u32 data)
   1392{
   1393	return cs_dsp_write_data_word(&buf->dsp->cs_dsp, buf->host_buf_mem_type,
   1394				      buf->host_buf_ptr + field_offset,
   1395				      data);
   1396}
   1397
   1398static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
   1399{
   1400	const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
   1401	struct wm_adsp_buffer_region *region;
   1402	u32 offset = 0;
   1403	int i, ret;
   1404
   1405	buf->regions = kcalloc(caps->num_regions, sizeof(*buf->regions),
   1406			       GFP_KERNEL);
   1407	if (!buf->regions)
   1408		return -ENOMEM;
   1409
   1410	for (i = 0; i < caps->num_regions; ++i) {
   1411		region = &buf->regions[i];
   1412
   1413		region->offset = offset;
   1414		region->mem_type = caps->region_defs[i].mem_type;
   1415
   1416		ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
   1417					  &region->base_addr);
   1418		if (ret < 0)
   1419			return ret;
   1420
   1421		ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
   1422					  &offset);
   1423		if (ret < 0)
   1424			return ret;
   1425
   1426		region->cumulative_size = offset;
   1427
   1428		compr_dbg(buf,
   1429			  "region=%d type=%d base=%08x off=%08x size=%08x\n",
   1430			  i, region->mem_type, region->base_addr,
   1431			  region->offset, region->cumulative_size);
   1432	}
   1433
   1434	return 0;
   1435}
   1436
   1437static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf)
   1438{
   1439	buf->irq_count = 0xFFFFFFFF;
   1440	buf->read_index = -1;
   1441	buf->avail = 0;
   1442}
   1443
   1444static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp)
   1445{
   1446	struct wm_adsp_compr_buf *buf;
   1447
   1448	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
   1449	if (!buf)
   1450		return NULL;
   1451
   1452	buf->dsp = dsp;
   1453
   1454	wm_adsp_buffer_clear(buf);
   1455
   1456	return buf;
   1457}
   1458
   1459static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
   1460{
   1461	struct cs_dsp_alg_region *alg_region;
   1462	struct wm_adsp_compr_buf *buf;
   1463	u32 xmalg, addr, magic;
   1464	int i, ret;
   1465
   1466	alg_region = cs_dsp_find_alg_region(&dsp->cs_dsp, WMFW_ADSP2_XM, dsp->cs_dsp.fw_id);
   1467	if (!alg_region) {
   1468		adsp_err(dsp, "No algorithm region found\n");
   1469		return -EINVAL;
   1470	}
   1471
   1472	xmalg = dsp->sys_config_size / sizeof(__be32);
   1473
   1474	addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
   1475	ret = cs_dsp_read_data_word(&dsp->cs_dsp, WMFW_ADSP2_XM, addr, &magic);
   1476	if (ret < 0)
   1477		return ret;
   1478
   1479	if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
   1480		return -ENODEV;
   1481
   1482	buf = wm_adsp_buffer_alloc(dsp);
   1483	if (!buf)
   1484		return -ENOMEM;
   1485
   1486	addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
   1487	for (i = 0; i < 5; ++i) {
   1488		ret = cs_dsp_read_data_word(&dsp->cs_dsp, WMFW_ADSP2_XM, addr,
   1489					    &buf->host_buf_ptr);
   1490		if (ret < 0)
   1491			goto err;
   1492
   1493		if (buf->host_buf_ptr)
   1494			break;
   1495
   1496		usleep_range(1000, 2000);
   1497	}
   1498
   1499	if (!buf->host_buf_ptr) {
   1500		ret = -EIO;
   1501		goto err;
   1502	}
   1503
   1504	buf->host_buf_mem_type = WMFW_ADSP2_XM;
   1505
   1506	ret = wm_adsp_buffer_populate(buf);
   1507	if (ret < 0)
   1508		goto err;
   1509
   1510	list_add_tail(&buf->list, &dsp->buffer_list);
   1511
   1512	compr_dbg(buf, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr);
   1513
   1514	return 0;
   1515
   1516err:
   1517	kfree(buf);
   1518
   1519	return ret;
   1520}
   1521
   1522static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl)
   1523{
   1524	struct wm_adsp_host_buf_coeff_v1 coeff_v1;
   1525	struct wm_adsp_compr_buf *buf;
   1526	struct wm_adsp *dsp = container_of(cs_ctl->dsp, struct wm_adsp, cs_dsp);
   1527	unsigned int version = 0;
   1528	int ret, i;
   1529
   1530	for (i = 0; i < 5; ++i) {
   1531		ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, &coeff_v1,
   1532					     min(cs_ctl->len, sizeof(coeff_v1)));
   1533		if (ret < 0)
   1534			return ret;
   1535
   1536		if (coeff_v1.host_buf_ptr)
   1537			break;
   1538
   1539		usleep_range(1000, 2000);
   1540	}
   1541
   1542	if (!coeff_v1.host_buf_ptr) {
   1543		adsp_err(dsp, "Failed to acquire host buffer\n");
   1544		return -EIO;
   1545	}
   1546
   1547	buf = wm_adsp_buffer_alloc(dsp);
   1548	if (!buf)
   1549		return -ENOMEM;
   1550
   1551	buf->host_buf_mem_type = cs_ctl->alg_region.type;
   1552	buf->host_buf_ptr = be32_to_cpu(coeff_v1.host_buf_ptr);
   1553
   1554	ret = wm_adsp_buffer_populate(buf);
   1555	if (ret < 0)
   1556		goto err;
   1557
   1558	/*
   1559	 * v0 host_buffer coefficients didn't have versioning, so if the
   1560	 * control is one word, assume version 0.
   1561	 */
   1562	if (cs_ctl->len == 4)
   1563		goto done;
   1564
   1565	version = be32_to_cpu(coeff_v1.versions) & HOST_BUF_COEFF_COMPAT_VER_MASK;
   1566	version >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
   1567
   1568	if (version > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) {
   1569		adsp_err(dsp,
   1570			 "Host buffer coeff ver %u > supported version %u\n",
   1571			 version, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
   1572		ret = -EINVAL;
   1573		goto err;
   1574	}
   1575
   1576	cs_dsp_remove_padding((u32 *)&coeff_v1.name, ARRAY_SIZE(coeff_v1.name));
   1577
   1578	buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", dsp->part,
   1579			      (char *)&coeff_v1.name);
   1580
   1581done:
   1582	list_add_tail(&buf->list, &dsp->buffer_list);
   1583
   1584	compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n",
   1585		  buf->host_buf_ptr, version);
   1586
   1587	return version;
   1588
   1589err:
   1590	kfree(buf);
   1591
   1592	return ret;
   1593}
   1594
   1595static int wm_adsp_buffer_init(struct wm_adsp *dsp)
   1596{
   1597	struct cs_dsp_coeff_ctl *cs_ctl;
   1598	int ret;
   1599
   1600	list_for_each_entry(cs_ctl, &dsp->cs_dsp.ctl_list, list) {
   1601		if (cs_ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
   1602			continue;
   1603
   1604		if (!cs_ctl->enabled)
   1605			continue;
   1606
   1607		ret = wm_adsp_buffer_parse_coeff(cs_ctl);
   1608		if (ret < 0) {
   1609			adsp_err(dsp, "Failed to parse coeff: %d\n", ret);
   1610			goto error;
   1611		} else if (ret == 0) {
   1612			/* Only one buffer supported for version 0 */
   1613			return 0;
   1614		}
   1615	}
   1616
   1617	if (list_empty(&dsp->buffer_list)) {
   1618		/* Fall back to legacy support */
   1619		ret = wm_adsp_buffer_parse_legacy(dsp);
   1620		if (ret)
   1621			adsp_warn(dsp, "Failed to parse legacy: %d\n", ret);
   1622	}
   1623
   1624	return 0;
   1625
   1626error:
   1627	wm_adsp_buffer_free(dsp);
   1628	return ret;
   1629}
   1630
   1631static int wm_adsp_buffer_free(struct wm_adsp *dsp)
   1632{
   1633	struct wm_adsp_compr_buf *buf, *tmp;
   1634
   1635	list_for_each_entry_safe(buf, tmp, &dsp->buffer_list, list) {
   1636		wm_adsp_compr_detach(buf->compr);
   1637
   1638		kfree(buf->name);
   1639		kfree(buf->regions);
   1640		list_del(&buf->list);
   1641		kfree(buf);
   1642	}
   1643
   1644	return 0;
   1645}
   1646
   1647static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf)
   1648{
   1649	int ret;
   1650
   1651	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
   1652	if (ret < 0) {
   1653		compr_err(buf, "Failed to check buffer error: %d\n", ret);
   1654		return ret;
   1655	}
   1656	if (buf->error != 0) {
   1657		compr_err(buf, "Buffer error occurred: %d\n", buf->error);
   1658		return -EIO;
   1659	}
   1660
   1661	return 0;
   1662}
   1663
   1664int wm_adsp_compr_trigger(struct snd_soc_component *component,
   1665			  struct snd_compr_stream *stream, int cmd)
   1666{
   1667	struct wm_adsp_compr *compr = stream->runtime->private_data;
   1668	struct wm_adsp *dsp = compr->dsp;
   1669	int ret = 0;
   1670
   1671	compr_dbg(compr, "Trigger: %d\n", cmd);
   1672
   1673	mutex_lock(&dsp->cs_dsp.pwr_lock);
   1674
   1675	switch (cmd) {
   1676	case SNDRV_PCM_TRIGGER_START:
   1677		if (!wm_adsp_compr_attached(compr)) {
   1678			ret = wm_adsp_compr_attach(compr);
   1679			if (ret < 0) {
   1680				compr_err(compr, "Failed to link buffer and stream: %d\n",
   1681					  ret);
   1682				break;
   1683			}
   1684		}
   1685
   1686		ret = wm_adsp_buffer_get_error(compr->buf);
   1687		if (ret < 0)
   1688			break;
   1689
   1690		/* Trigger the IRQ at one fragment of data */
   1691		ret = wm_adsp_buffer_write(compr->buf,
   1692					   HOST_BUFFER_FIELD(high_water_mark),
   1693					   wm_adsp_compr_frag_words(compr));
   1694		if (ret < 0) {
   1695			compr_err(compr, "Failed to set high water mark: %d\n",
   1696				  ret);
   1697			break;
   1698		}
   1699		break;
   1700	case SNDRV_PCM_TRIGGER_STOP:
   1701		if (wm_adsp_compr_attached(compr))
   1702			wm_adsp_buffer_clear(compr->buf);
   1703		break;
   1704	default:
   1705		ret = -EINVAL;
   1706		break;
   1707	}
   1708
   1709	mutex_unlock(&dsp->cs_dsp.pwr_lock);
   1710
   1711	return ret;
   1712}
   1713EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
   1714
   1715static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf)
   1716{
   1717	int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1;
   1718
   1719	return buf->regions[last_region].cumulative_size;
   1720}
   1721
   1722static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
   1723{
   1724	u32 next_read_index, next_write_index;
   1725	int write_index, read_index, avail;
   1726	int ret;
   1727
   1728	/* Only sync read index if we haven't already read a valid index */
   1729	if (buf->read_index < 0) {
   1730		ret = wm_adsp_buffer_read(buf,
   1731				HOST_BUFFER_FIELD(next_read_index),
   1732				&next_read_index);
   1733		if (ret < 0)
   1734			return ret;
   1735
   1736		read_index = sign_extend32(next_read_index, 23);
   1737
   1738		if (read_index < 0) {
   1739			compr_dbg(buf, "Avail check on unstarted stream\n");
   1740			return 0;
   1741		}
   1742
   1743		buf->read_index = read_index;
   1744	}
   1745
   1746	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index),
   1747			&next_write_index);
   1748	if (ret < 0)
   1749		return ret;
   1750
   1751	write_index = sign_extend32(next_write_index, 23);
   1752
   1753	avail = write_index - buf->read_index;
   1754	if (avail < 0)
   1755		avail += wm_adsp_buffer_size(buf);
   1756
   1757	compr_dbg(buf, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
   1758		  buf->read_index, write_index, avail * CS_DSP_DATA_WORD_SIZE);
   1759
   1760	buf->avail = avail;
   1761
   1762	return 0;
   1763}
   1764
   1765int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
   1766{
   1767	struct wm_adsp_compr_buf *buf;
   1768	struct wm_adsp_compr *compr;
   1769	int ret = 0;
   1770
   1771	mutex_lock(&dsp->cs_dsp.pwr_lock);
   1772
   1773	if (list_empty(&dsp->buffer_list)) {
   1774		ret = -ENODEV;
   1775		goto out;
   1776	}
   1777
   1778	adsp_dbg(dsp, "Handling buffer IRQ\n");
   1779
   1780	list_for_each_entry(buf, &dsp->buffer_list, list) {
   1781		compr = buf->compr;
   1782
   1783		ret = wm_adsp_buffer_get_error(buf);
   1784		if (ret < 0)
   1785			goto out_notify; /* Wake poll to report error */
   1786
   1787		ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
   1788					  &buf->irq_count);
   1789		if (ret < 0) {
   1790			compr_err(buf, "Failed to get irq_count: %d\n", ret);
   1791			goto out;
   1792		}
   1793
   1794		ret = wm_adsp_buffer_update_avail(buf);
   1795		if (ret < 0) {
   1796			compr_err(buf, "Error reading avail: %d\n", ret);
   1797			goto out;
   1798		}
   1799
   1800		if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2)
   1801			ret = WM_ADSP_COMPR_VOICE_TRIGGER;
   1802
   1803out_notify:
   1804		if (compr && compr->stream)
   1805			snd_compr_fragment_elapsed(compr->stream);
   1806	}
   1807
   1808out:
   1809	mutex_unlock(&dsp->cs_dsp.pwr_lock);
   1810
   1811	return ret;
   1812}
   1813EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq);
   1814
   1815static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
   1816{
   1817	if (buf->irq_count & 0x01)
   1818		return 0;
   1819
   1820	compr_dbg(buf, "Enable IRQ(0x%x) for next fragment\n", buf->irq_count);
   1821
   1822	buf->irq_count |= 0x01;
   1823
   1824	return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack),
   1825				    buf->irq_count);
   1826}
   1827
   1828int wm_adsp_compr_pointer(struct snd_soc_component *component,
   1829			  struct snd_compr_stream *stream,
   1830			  struct snd_compr_tstamp *tstamp)
   1831{
   1832	struct wm_adsp_compr *compr = stream->runtime->private_data;
   1833	struct wm_adsp *dsp = compr->dsp;
   1834	struct wm_adsp_compr_buf *buf;
   1835	int ret = 0;
   1836
   1837	compr_dbg(compr, "Pointer request\n");
   1838
   1839	mutex_lock(&dsp->cs_dsp.pwr_lock);
   1840
   1841	buf = compr->buf;
   1842
   1843	if (dsp->fatal_error || !buf || buf->error) {
   1844		snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
   1845		ret = -EIO;
   1846		goto out;
   1847	}
   1848
   1849	if (buf->avail < wm_adsp_compr_frag_words(compr)) {
   1850		ret = wm_adsp_buffer_update_avail(buf);
   1851		if (ret < 0) {
   1852			compr_err(compr, "Error reading avail: %d\n", ret);
   1853			goto out;
   1854		}
   1855
   1856		/*
   1857		 * If we really have less than 1 fragment available tell the
   1858		 * DSP to inform us once a whole fragment is available.
   1859		 */
   1860		if (buf->avail < wm_adsp_compr_frag_words(compr)) {
   1861			ret = wm_adsp_buffer_get_error(buf);
   1862			if (ret < 0) {
   1863				if (buf->error)
   1864					snd_compr_stop_error(stream,
   1865							SNDRV_PCM_STATE_XRUN);
   1866				goto out;
   1867			}
   1868
   1869			ret = wm_adsp_buffer_reenable_irq(buf);
   1870			if (ret < 0) {
   1871				compr_err(compr, "Failed to re-enable buffer IRQ: %d\n",
   1872					  ret);
   1873				goto out;
   1874			}
   1875		}
   1876	}
   1877
   1878	tstamp->copied_total = compr->copied_total;
   1879	tstamp->copied_total += buf->avail * CS_DSP_DATA_WORD_SIZE;
   1880	tstamp->sampling_rate = compr->sample_rate;
   1881
   1882out:
   1883	mutex_unlock(&dsp->cs_dsp.pwr_lock);
   1884
   1885	return ret;
   1886}
   1887EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
   1888
   1889static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
   1890{
   1891	struct wm_adsp_compr_buf *buf = compr->buf;
   1892	unsigned int adsp_addr;
   1893	int mem_type, nwords, max_read;
   1894	int i, ret;
   1895
   1896	/* Calculate read parameters */
   1897	for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
   1898		if (buf->read_index < buf->regions[i].cumulative_size)
   1899			break;
   1900
   1901	if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions)
   1902		return -EINVAL;
   1903
   1904	mem_type = buf->regions[i].mem_type;
   1905	adsp_addr = buf->regions[i].base_addr +
   1906		    (buf->read_index - buf->regions[i].offset);
   1907
   1908	max_read = wm_adsp_compr_frag_words(compr);
   1909	nwords = buf->regions[i].cumulative_size - buf->read_index;
   1910
   1911	if (nwords > target)
   1912		nwords = target;
   1913	if (nwords > buf->avail)
   1914		nwords = buf->avail;
   1915	if (nwords > max_read)
   1916		nwords = max_read;
   1917	if (!nwords)
   1918		return 0;
   1919
   1920	/* Read data from DSP */
   1921	ret = cs_dsp_read_raw_data_block(&buf->dsp->cs_dsp, mem_type, adsp_addr,
   1922					 nwords, (__be32 *)compr->raw_buf);
   1923	if (ret < 0)
   1924		return ret;
   1925
   1926	cs_dsp_remove_padding(compr->raw_buf, nwords);
   1927
   1928	/* update read index to account for words read */
   1929	buf->read_index += nwords;
   1930	if (buf->read_index == wm_adsp_buffer_size(buf))
   1931		buf->read_index = 0;
   1932
   1933	ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index),
   1934				   buf->read_index);
   1935	if (ret < 0)
   1936		return ret;
   1937
   1938	/* update avail to account for words read */
   1939	buf->avail -= nwords;
   1940
   1941	return nwords;
   1942}
   1943
   1944static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
   1945			      char __user *buf, size_t count)
   1946{
   1947	struct wm_adsp *dsp = compr->dsp;
   1948	int ntotal = 0;
   1949	int nwords, nbytes;
   1950
   1951	compr_dbg(compr, "Requested read of %zu bytes\n", count);
   1952
   1953	if (dsp->fatal_error || !compr->buf || compr->buf->error) {
   1954		snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
   1955		return -EIO;
   1956	}
   1957
   1958	count /= CS_DSP_DATA_WORD_SIZE;
   1959
   1960	do {
   1961		nwords = wm_adsp_buffer_capture_block(compr, count);
   1962		if (nwords < 0) {
   1963			compr_err(compr, "Failed to capture block: %d\n",
   1964				  nwords);
   1965			return nwords;
   1966		}
   1967
   1968		nbytes = nwords * CS_DSP_DATA_WORD_SIZE;
   1969
   1970		compr_dbg(compr, "Read %d bytes\n", nbytes);
   1971
   1972		if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
   1973			compr_err(compr, "Failed to copy data to user: %d, %d\n",
   1974				  ntotal, nbytes);
   1975			return -EFAULT;
   1976		}
   1977
   1978		count -= nwords;
   1979		ntotal += nbytes;
   1980	} while (nwords > 0 && count > 0);
   1981
   1982	compr->copied_total += ntotal;
   1983
   1984	return ntotal;
   1985}
   1986
   1987int wm_adsp_compr_copy(struct snd_soc_component *component,
   1988		       struct snd_compr_stream *stream, char __user *buf,
   1989		       size_t count)
   1990{
   1991	struct wm_adsp_compr *compr = stream->runtime->private_data;
   1992	struct wm_adsp *dsp = compr->dsp;
   1993	int ret;
   1994
   1995	mutex_lock(&dsp->cs_dsp.pwr_lock);
   1996
   1997	if (stream->direction == SND_COMPRESS_CAPTURE)
   1998		ret = wm_adsp_compr_read(compr, buf, count);
   1999	else
   2000		ret = -ENOTSUPP;
   2001
   2002	mutex_unlock(&dsp->cs_dsp.pwr_lock);
   2003
   2004	return ret;
   2005}
   2006EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
   2007
   2008static void wm_adsp_fatal_error(struct cs_dsp *cs_dsp)
   2009{
   2010	struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
   2011	struct wm_adsp_compr *compr;
   2012
   2013	dsp->fatal_error = true;
   2014
   2015	list_for_each_entry(compr, &dsp->compr_list, list) {
   2016		if (compr->stream)
   2017			snd_compr_fragment_elapsed(compr->stream);
   2018	}
   2019}
   2020
   2021irqreturn_t wm_adsp2_bus_error(int irq, void *data)
   2022{
   2023	struct wm_adsp *dsp = (struct wm_adsp *)data;
   2024
   2025	cs_dsp_adsp2_bus_error(&dsp->cs_dsp);
   2026
   2027	return IRQ_HANDLED;
   2028}
   2029EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
   2030
   2031irqreturn_t wm_halo_bus_error(int irq, void *data)
   2032{
   2033	struct wm_adsp *dsp = (struct wm_adsp *)data;
   2034
   2035	cs_dsp_halo_bus_error(&dsp->cs_dsp);
   2036
   2037	return IRQ_HANDLED;
   2038}
   2039EXPORT_SYMBOL_GPL(wm_halo_bus_error);
   2040
   2041irqreturn_t wm_halo_wdt_expire(int irq, void *data)
   2042{
   2043	struct wm_adsp *dsp = data;
   2044
   2045	cs_dsp_halo_wdt_expire(&dsp->cs_dsp);
   2046
   2047	return IRQ_HANDLED;
   2048}
   2049EXPORT_SYMBOL_GPL(wm_halo_wdt_expire);
   2050
   2051static const struct cs_dsp_client_ops wm_adsp1_client_ops = {
   2052	.control_add = wm_adsp_control_add,
   2053	.control_remove = wm_adsp_control_remove,
   2054};
   2055
   2056static const struct cs_dsp_client_ops wm_adsp2_client_ops = {
   2057	.control_add = wm_adsp_control_add,
   2058	.control_remove = wm_adsp_control_remove,
   2059	.post_run = wm_adsp_event_post_run,
   2060	.post_stop = wm_adsp_event_post_stop,
   2061	.watchdog_expired = wm_adsp_fatal_error,
   2062};
   2063
   2064MODULE_LICENSE("GPL v2");