Linux Audio

Check our new training course

Loading...
v6.13.7
   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/array_size.h>
  11#include <linux/ctype.h>
  12#include <linux/module.h>
  13#include <linux/moduleparam.h>
  14#include <linux/init.h>
  15#include <linux/delay.h>
  16#include <linux/firmware.h>
  17#include <linux/list.h>
  18#include <linux/pm.h>
 
  19#include <linux/regmap.h>
  20#include <linux/regulator/consumer.h>
  21#include <linux/slab.h>
  22#include <linux/vmalloc.h>
  23#include <linux/workqueue.h>
  24#include <linux/debugfs.h>
  25#include <sound/core.h>
  26#include <sound/pcm.h>
  27#include <sound/pcm_params.h>
  28#include <sound/soc.h>
  29#include <sound/jack.h>
  30#include <sound/initval.h>
  31#include <sound/tlv.h>
  32
  33#include "wm_adsp.h"
  34
  35#define adsp_crit(_dsp, fmt, ...) \
  36	dev_crit(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
  37#define adsp_err(_dsp, fmt, ...) \
  38	dev_err(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
  39#define adsp_warn(_dsp, fmt, ...) \
  40	dev_warn(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
  41#define adsp_info(_dsp, fmt, ...) \
  42	dev_info(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
  43#define adsp_dbg(_dsp, fmt, ...) \
  44	dev_dbg(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
  45
  46#define compr_err(_obj, fmt, ...) \
  47	adsp_err(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
  48		 ##__VA_ARGS__)
  49#define compr_dbg(_obj, fmt, ...) \
  50	adsp_dbg(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
  51		 ##__VA_ARGS__)
  52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  53#define ADSP_MAX_STD_CTRL_SIZE               512
  54
  55static const struct cs_dsp_client_ops wm_adsp1_client_ops;
  56static const struct cs_dsp_client_ops wm_adsp2_client_ops;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  57
  58#define WM_ADSP_FW_MBC_VSS  0
  59#define WM_ADSP_FW_HIFI     1
  60#define WM_ADSP_FW_TX       2
  61#define WM_ADSP_FW_TX_SPK   3
  62#define WM_ADSP_FW_RX       4
  63#define WM_ADSP_FW_RX_ANC   5
  64#define WM_ADSP_FW_CTRL     6
  65#define WM_ADSP_FW_ASR      7
  66#define WM_ADSP_FW_TRACE    8
  67#define WM_ADSP_FW_SPK_PROT 9
  68#define WM_ADSP_FW_SPK_CALI 10
  69#define WM_ADSP_FW_SPK_DIAG 11
  70#define WM_ADSP_FW_MISC     12
  71
  72#define WM_ADSP_NUM_FW      13
  73
  74static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
  75	[WM_ADSP_FW_MBC_VSS] =  "MBC/VSS",
  76	[WM_ADSP_FW_HIFI] =     "MasterHiFi",
  77	[WM_ADSP_FW_TX] =       "Tx",
  78	[WM_ADSP_FW_TX_SPK] =   "Tx Speaker",
  79	[WM_ADSP_FW_RX] =       "Rx",
  80	[WM_ADSP_FW_RX_ANC] =   "Rx ANC",
  81	[WM_ADSP_FW_CTRL] =     "Voice Ctrl",
  82	[WM_ADSP_FW_ASR] =      "ASR Assist",
  83	[WM_ADSP_FW_TRACE] =    "Dbg Trace",
  84	[WM_ADSP_FW_SPK_PROT] = "Protection",
  85	[WM_ADSP_FW_SPK_CALI] = "Calibration",
  86	[WM_ADSP_FW_SPK_DIAG] = "Diagnostic",
  87	[WM_ADSP_FW_MISC] =     "Misc",
  88};
  89
  90struct wm_adsp_system_config_xm_hdr {
  91	__be32 sys_enable;
  92	__be32 fw_id;
  93	__be32 fw_rev;
  94	__be32 boot_status;
  95	__be32 watchdog;
  96	__be32 dma_buffer_size;
  97	__be32 rdma[6];
  98	__be32 wdma[8];
  99	__be32 build_job_name[3];
 100	__be32 build_job_number;
 101} __packed;
 102
 103struct wm_halo_system_config_xm_hdr {
 104	__be32 halo_heartbeat;
 105	__be32 build_job_name[3];
 106	__be32 build_job_number;
 107} __packed;
 108
 109struct wm_adsp_alg_xm_struct {
 110	__be32 magic;
 111	__be32 smoothing;
 112	__be32 threshold;
 113	__be32 host_buf_ptr;
 114	__be32 start_seq;
 115	__be32 high_water_mark;
 116	__be32 low_water_mark;
 117	__be64 smoothed_power;
 118} __packed;
 119
 120struct wm_adsp_host_buf_coeff_v1 {
 121	__be32 host_buf_ptr;		/* Host buffer pointer */
 122	__be32 versions;		/* Version numbers */
 123	__be32 name[4];			/* The buffer name */
 124} __packed;
 125
 126struct wm_adsp_buffer {
 127	__be32 buf1_base;		/* Base addr of first buffer area */
 128	__be32 buf1_size;		/* Size of buf1 area in DSP words */
 129	__be32 buf2_base;		/* Base addr of 2nd buffer area */
 130	__be32 buf1_buf2_size;		/* Size of buf1+buf2 in DSP words */
 131	__be32 buf3_base;		/* Base addr of buf3 area */
 132	__be32 buf_total_size;		/* Size of buf1+buf2+buf3 in DSP words */
 133	__be32 high_water_mark;		/* Point at which IRQ is asserted */
 134	__be32 irq_count;		/* bits 1-31 count IRQ assertions */
 135	__be32 irq_ack;			/* acked IRQ count, bit 0 enables IRQ */
 136	__be32 next_write_index;	/* word index of next write */
 137	__be32 next_read_index;		/* word index of next read */
 138	__be32 error;			/* error if any */
 139	__be32 oldest_block_index;	/* word index of oldest surviving */
 140	__be32 requested_rewind;	/* how many blocks rewind was done */
 141	__be32 reserved_space;		/* internal */
 142	__be32 min_free;		/* min free space since stream start */
 143	__be32 blocks_written[2];	/* total blocks written (64 bit) */
 144	__be32 words_written[2];	/* total words written (64 bit) */
 145} __packed;
 146
 147struct wm_adsp_compr;
 148
 149struct wm_adsp_compr_buf {
 150	struct list_head list;
 151	struct wm_adsp *dsp;
 152	struct wm_adsp_compr *compr;
 153
 154	struct wm_adsp_buffer_region *regions;
 155	u32 host_buf_ptr;
 156
 157	u32 error;
 158	u32 irq_count;
 159	int read_index;
 160	int avail;
 161	int host_buf_mem_type;
 162
 163	char *name;
 164};
 165
 166struct wm_adsp_compr {
 167	struct list_head list;
 168	struct wm_adsp *dsp;
 169	struct wm_adsp_compr_buf *buf;
 170
 171	struct snd_compr_stream *stream;
 172	struct snd_compressed_buffer size;
 173
 174	u32 *raw_buf;
 175	unsigned int copied_total;
 176
 177	unsigned int sample_rate;
 178
 179	const char *name;
 180};
 181
 
 
 182#define WM_ADSP_MIN_FRAGMENTS          1
 183#define WM_ADSP_MAX_FRAGMENTS          256
 184#define WM_ADSP_MIN_FRAGMENT_SIZE      (16 * CS_DSP_DATA_WORD_SIZE)
 185#define WM_ADSP_MAX_FRAGMENT_SIZE      (4096 * CS_DSP_DATA_WORD_SIZE)
 186
 187#define WM_ADSP_ALG_XM_STRUCT_MAGIC    0x49aec7
 188
 189#define HOST_BUFFER_FIELD(field) \
 190	(offsetof(struct wm_adsp_buffer, field) / sizeof(__be32))
 191
 192#define ALG_XM_FIELD(field) \
 193	(offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32))
 194
 195#define HOST_BUF_COEFF_SUPPORTED_COMPAT_VER	1
 196
 197#define HOST_BUF_COEFF_COMPAT_VER_MASK		0xFF00
 198#define HOST_BUF_COEFF_COMPAT_VER_SHIFT		8
 199
 200static int wm_adsp_buffer_init(struct wm_adsp *dsp);
 201static int wm_adsp_buffer_free(struct wm_adsp *dsp);
 202
 203struct wm_adsp_buffer_region {
 204	unsigned int offset;
 205	unsigned int cumulative_size;
 206	unsigned int mem_type;
 207	unsigned int base_addr;
 208};
 209
 210struct wm_adsp_buffer_region_def {
 211	unsigned int mem_type;
 212	unsigned int base_offset;
 213	unsigned int size_offset;
 214};
 215
 216static const struct wm_adsp_buffer_region_def default_regions[] = {
 217	{
 218		.mem_type = WMFW_ADSP2_XM,
 219		.base_offset = HOST_BUFFER_FIELD(buf1_base),
 220		.size_offset = HOST_BUFFER_FIELD(buf1_size),
 221	},
 222	{
 223		.mem_type = WMFW_ADSP2_XM,
 224		.base_offset = HOST_BUFFER_FIELD(buf2_base),
 225		.size_offset = HOST_BUFFER_FIELD(buf1_buf2_size),
 226	},
 227	{
 228		.mem_type = WMFW_ADSP2_YM,
 229		.base_offset = HOST_BUFFER_FIELD(buf3_base),
 230		.size_offset = HOST_BUFFER_FIELD(buf_total_size),
 231	},
 232};
 233
 234struct wm_adsp_fw_caps {
 235	u32 id;
 236	struct snd_codec_desc desc;
 237	int num_regions;
 238	const struct wm_adsp_buffer_region_def *region_defs;
 239};
 240
 241static const struct wm_adsp_fw_caps ctrl_caps[] = {
 242	{
 243		.id = SND_AUDIOCODEC_BESPOKE,
 244		.desc = {
 245			.max_ch = 8,
 246			.sample_rates = { 16000 },
 247			.num_sample_rates = 1,
 248			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 249		},
 250		.num_regions = ARRAY_SIZE(default_regions),
 251		.region_defs = default_regions,
 252	},
 253};
 254
 255static const struct wm_adsp_fw_caps trace_caps[] = {
 256	{
 257		.id = SND_AUDIOCODEC_BESPOKE,
 258		.desc = {
 259			.max_ch = 8,
 260			.sample_rates = {
 261				4000, 8000, 11025, 12000, 16000, 22050,
 262				24000, 32000, 44100, 48000, 64000, 88200,
 263				96000, 176400, 192000
 264			},
 265			.num_sample_rates = 15,
 266			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 267		},
 268		.num_regions = ARRAY_SIZE(default_regions),
 269		.region_defs = default_regions,
 270	},
 271};
 272
 273static const struct {
 274	const char *file;
 275	int compr_direction;
 276	int num_caps;
 277	const struct wm_adsp_fw_caps *caps;
 278	bool voice_trigger;
 279} wm_adsp_fw[WM_ADSP_NUM_FW] = {
 280	[WM_ADSP_FW_MBC_VSS] =  { .file = "mbc-vss" },
 281	[WM_ADSP_FW_HIFI] =     { .file = "hifi" },
 282	[WM_ADSP_FW_TX] =       { .file = "tx" },
 283	[WM_ADSP_FW_TX_SPK] =   { .file = "tx-spk" },
 284	[WM_ADSP_FW_RX] =       { .file = "rx" },
 285	[WM_ADSP_FW_RX_ANC] =   { .file = "rx-anc" },
 286	[WM_ADSP_FW_CTRL] =     {
 287		.file = "ctrl",
 288		.compr_direction = SND_COMPRESS_CAPTURE,
 289		.num_caps = ARRAY_SIZE(ctrl_caps),
 290		.caps = ctrl_caps,
 291		.voice_trigger = true,
 292	},
 293	[WM_ADSP_FW_ASR] =      { .file = "asr" },
 294	[WM_ADSP_FW_TRACE] =    {
 295		.file = "trace",
 296		.compr_direction = SND_COMPRESS_CAPTURE,
 297		.num_caps = ARRAY_SIZE(trace_caps),
 298		.caps = trace_caps,
 299	},
 300	[WM_ADSP_FW_SPK_PROT] = {
 301		.file = "spk-prot",
 302		.compr_direction = SND_COMPRESS_CAPTURE,
 303		.num_caps = ARRAY_SIZE(trace_caps),
 304		.caps = trace_caps,
 305	},
 306	[WM_ADSP_FW_SPK_CALI] = { .file = "spk-cali" },
 307	[WM_ADSP_FW_SPK_DIAG] = { .file = "spk-diag" },
 308	[WM_ADSP_FW_MISC] =     { .file = "misc" },
 309};
 310
 
 
 
 
 
 
 
 311struct wm_coeff_ctl {
 312	const char *name;
 313	struct cs_dsp_coeff_ctl *cs_ctl;
 
 
 
 
 
 
 
 
 
 
 
 
 314	struct soc_bytes_ext bytes_ext;
 315	struct work_struct work;
 
 316};
 317
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 318int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
 319		   struct snd_ctl_elem_value *ucontrol)
 320{
 321	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 322	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 323	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
 324
 325	ucontrol->value.enumerated.item[0] = dsp[e->shift_l].fw;
 326
 327	return 0;
 328}
 329EXPORT_SYMBOL_GPL(wm_adsp_fw_get);
 330
 331int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
 332		   struct snd_ctl_elem_value *ucontrol)
 333{
 334	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 335	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 336	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
 337	int ret = 1;
 338
 339	if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw)
 340		return 0;
 341
 342	if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW)
 343		return -EINVAL;
 344
 345	mutex_lock(&dsp[e->shift_l].cs_dsp.pwr_lock);
 346
 347	if (dsp[e->shift_l].cs_dsp.booted || !list_empty(&dsp[e->shift_l].compr_list))
 348		ret = -EBUSY;
 349	else
 350		dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0];
 351
 352	mutex_unlock(&dsp[e->shift_l].cs_dsp.pwr_lock);
 353
 354	return ret;
 355}
 356EXPORT_SYMBOL_GPL(wm_adsp_fw_put);
 357
 358const struct soc_enum wm_adsp_fw_enum[] = {
 359	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 360	SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 361	SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 362	SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 363	SOC_ENUM_SINGLE(0, 4, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 364	SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 365	SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 366};
 367EXPORT_SYMBOL_GPL(wm_adsp_fw_enum);
 368
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 369static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
 370{
 371	return container_of(ext, struct wm_coeff_ctl, bytes_ext);
 372}
 373
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 374static int wm_coeff_info(struct snd_kcontrol *kctl,
 375			 struct snd_ctl_elem_info *uinfo)
 376{
 377	struct soc_bytes_ext *bytes_ext =
 378		(struct soc_bytes_ext *)kctl->private_value;
 379	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 380	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
 381
 382	switch (cs_ctl->type) {
 383	case WMFW_CTL_TYPE_ACKED:
 384		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 385		uinfo->value.integer.min = CS_DSP_ACKED_CTL_MIN_VALUE;
 386		uinfo->value.integer.max = CS_DSP_ACKED_CTL_MAX_VALUE;
 387		uinfo->value.integer.step = 1;
 388		uinfo->count = 1;
 389		break;
 390	default:
 391		uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
 392		uinfo->count = cs_ctl->len;
 393		break;
 394	}
 395
 396	return 0;
 397}
 398
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 399static int wm_coeff_put(struct snd_kcontrol *kctl,
 400			struct snd_ctl_elem_value *ucontrol)
 401{
 402	struct soc_bytes_ext *bytes_ext =
 403		(struct soc_bytes_ext *)kctl->private_value;
 404	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 405	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
 406	char *p = ucontrol->value.bytes.data;
 
 407
 408	return cs_dsp_coeff_lock_and_write_ctrl(cs_ctl, 0, p, cs_ctl->len);
 
 
 
 
 409}
 410
 411static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
 412			    const unsigned int __user *bytes, unsigned int size)
 413{
 414	struct soc_bytes_ext *bytes_ext =
 415		(struct soc_bytes_ext *)kctl->private_value;
 416	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 417	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
 418	void *scratch;
 419	int ret = 0;
 420
 421	scratch = vmalloc(size);
 422	if (!scratch)
 423		return -ENOMEM;
 424
 425	if (copy_from_user(scratch, bytes, size))
 426		ret = -EFAULT;
 427	else
 428		ret = cs_dsp_coeff_lock_and_write_ctrl(cs_ctl, 0, scratch, size);
 429
 430	vfree(scratch);
 431
 432	return ret;
 433}
 434
 435static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
 436			      struct snd_ctl_elem_value *ucontrol)
 437{
 438	struct soc_bytes_ext *bytes_ext =
 439		(struct soc_bytes_ext *)kctl->private_value;
 440	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 441	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
 442	unsigned int val = ucontrol->value.integer.value[0];
 443	int ret;
 444
 445	if (val == 0)
 446		return 0;	/* 0 means no event */
 447
 448	mutex_lock(&cs_ctl->dsp->pwr_lock);
 449
 450	if (cs_ctl->enabled)
 451		ret = cs_dsp_coeff_write_acked_control(cs_ctl, val);
 452	else
 453		ret = -EPERM;
 454
 455	mutex_unlock(&cs_ctl->dsp->pwr_lock);
 456
 457	if (ret < 0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 458		return ret;
 
 
 459
 460	return 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 461}
 462
 463static int wm_coeff_get(struct snd_kcontrol *kctl,
 464			struct snd_ctl_elem_value *ucontrol)
 465{
 466	struct soc_bytes_ext *bytes_ext =
 467		(struct soc_bytes_ext *)kctl->private_value;
 468	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 469	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
 470	char *p = ucontrol->value.bytes.data;
 
 
 
 
 
 471
 472	return cs_dsp_coeff_lock_and_read_ctrl(cs_ctl, 0, p, cs_ctl->len);
 473}
 474
 475static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
 476			    unsigned int __user *bytes, unsigned int size)
 477{
 478	struct soc_bytes_ext *bytes_ext =
 479		(struct soc_bytes_ext *)kctl->private_value;
 480	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 481	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
 482	int ret = 0;
 483
 484	mutex_lock(&cs_ctl->dsp->pwr_lock);
 485
 486	ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, cs_ctl->cache, size);
 487
 488	if (!ret && copy_to_user(bytes, cs_ctl->cache, size))
 489		ret = -EFAULT;
 490
 491	mutex_unlock(&cs_ctl->dsp->pwr_lock);
 492
 493	return ret;
 494}
 495
 496static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol,
 497			      struct snd_ctl_elem_value *ucontrol)
 498{
 499	/*
 500	 * Although it's not useful to read an acked control, we must satisfy
 501	 * user-side assumptions that all controls are readable and that a
 502	 * write of the same value should be filtered out (it's valid to send
 503	 * the same event number again to the firmware). We therefore return 0,
 504	 * meaning "no event" so valid event numbers will always be a change
 505	 */
 506	ucontrol->value.integer.value[0] = 0;
 507
 508	return 0;
 509}
 510
 
 
 
 
 
 
 511static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len)
 512{
 513	unsigned int out, rd, wr, vol;
 514
 515	if (len > ADSP_MAX_STD_CTRL_SIZE) {
 516		rd = SNDRV_CTL_ELEM_ACCESS_TLV_READ;
 517		wr = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE;
 518		vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
 519
 520		out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
 521	} else {
 522		rd = SNDRV_CTL_ELEM_ACCESS_READ;
 523		wr = SNDRV_CTL_ELEM_ACCESS_WRITE;
 524		vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
 525
 526		out = 0;
 527	}
 528
 529	if (in) {
 530		out |= rd;
 531		if (in & WMFW_CTL_FLAG_WRITEABLE)
 532			out |= wr;
 533		if (in & WMFW_CTL_FLAG_VOLATILE)
 534			out |= vol;
 535	} else {
 536		out |= rd | wr | vol;
 537	}
 538
 539	return out;
 540}
 541
 542static void wm_adsp_ctl_work(struct work_struct *work)
 543{
 544	struct wm_coeff_ctl *ctl = container_of(work,
 545						struct wm_coeff_ctl,
 546						work);
 547	struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
 548	struct wm_adsp *dsp = container_of(cs_ctl->dsp,
 549					   struct wm_adsp,
 550					   cs_dsp);
 551	struct snd_kcontrol_new *kcontrol;
 
 
 
 
 552
 553	kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
 554	if (!kcontrol)
 555		return;
 556
 557	kcontrol->name = ctl->name;
 558	kcontrol->info = wm_coeff_info;
 559	kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 560	kcontrol->tlv.c = snd_soc_bytes_tlv_callback;
 561	kcontrol->private_value = (unsigned long)&ctl->bytes_ext;
 562	kcontrol->access = wmfw_convert_flags(cs_ctl->flags, cs_ctl->len);
 563
 564	switch (cs_ctl->type) {
 565	case WMFW_CTL_TYPE_ACKED:
 566		kcontrol->get = wm_coeff_get_acked;
 567		kcontrol->put = wm_coeff_put_acked;
 568		break;
 569	default:
 570		if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
 571			ctl->bytes_ext.max = cs_ctl->len;
 572			ctl->bytes_ext.get = wm_coeff_tlv_get;
 573			ctl->bytes_ext.put = wm_coeff_tlv_put;
 574		} else {
 575			kcontrol->get = wm_coeff_get;
 576			kcontrol->put = wm_coeff_put;
 577		}
 578		break;
 579	}
 580
 581	snd_soc_add_component_controls(dsp->component, kcontrol, 1);
 
 
 
 
 
 
 582
 
 583	kfree(kcontrol);
 
 584}
 585
 586int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
 587{
 588	struct wm_adsp *dsp = container_of(cs_ctl->dsp, struct wm_adsp, cs_dsp);
 589	struct cs_dsp *cs_dsp = &dsp->cs_dsp;
 590	struct wm_coeff_ctl *ctl;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 591	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
 592	const char *region_name;
 593	int ret;
 594
 595	if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
 596		return 0;
 597
 598	region_name = cs_dsp_mem_region_name(cs_ctl->alg_region.type);
 599	if (!region_name) {
 600		adsp_err(dsp, "Unknown region type: %d\n", cs_ctl->alg_region.type);
 601		return -EINVAL;
 602	}
 603
 604	switch (cs_dsp->wmfw_ver) {
 605	case 0:
 606	case 1:
 607		ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
 608				"%s %s %x", cs_dsp->name, region_name,
 609				cs_ctl->alg_region.alg);
 610		break;
 611	case 2:
 612		ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
 613				"%s%c %.12s %x", cs_dsp->name, *region_name,
 614				wm_adsp_fw_text[dsp->fw], cs_ctl->alg_region.alg);
 615		break;
 616	default:
 617		ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
 618				"%s %.12s %x", cs_dsp->name,
 619				wm_adsp_fw_text[dsp->fw], cs_ctl->alg_region.alg);
 620		break;
 621	}
 622
 623	if (cs_ctl->subname) {
 624		int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
 625		int skip = 0;
 626
 627		if (dsp->component->name_prefix)
 628			avail -= strlen(dsp->component->name_prefix) + 1;
 629
 630		/* Truncate the subname from the start if it is too long */
 631		if (cs_ctl->subname_len > avail)
 632			skip = cs_ctl->subname_len - avail;
 633
 634		snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret,
 635			 " %.*s", cs_ctl->subname_len - skip, cs_ctl->subname + skip);
 
 
 
 
 
 
 
 
 636	}
 637
 638	ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
 639	if (!ctl)
 640		return -ENOMEM;
 641	ctl->cs_ctl = cs_ctl;
 642
 643	ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
 644	if (!ctl->name) {
 645		ret = -ENOMEM;
 646		goto err_ctl;
 647	}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 648
 649	cs_ctl->priv = ctl;
 
 
 
 
 
 
 
 650
 651	INIT_WORK(&ctl->work, wm_adsp_ctl_work);
 652	schedule_work(&ctl->work);
 
 
 653
 654	return 0;
 655
 
 
 
 
 
 
 656err_ctl:
 657	kfree(ctl);
 658
 659	return ret;
 660}
 661EXPORT_SYMBOL_GPL(wm_adsp_control_add);
 662
 663static int wm_adsp_control_add_cb(struct cs_dsp_coeff_ctl *cs_ctl)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 664{
 665	struct wm_adsp *dsp = container_of(cs_ctl->dsp, struct wm_adsp, cs_dsp);
 666
 667	if (dsp->control_add)
 668		return (dsp->control_add)(dsp, cs_ctl);
 669	else
 670		return wm_adsp_control_add(cs_ctl);
 
 
 
 
 
 
 
 
 
 
 
 
 
 671}
 672
 673static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl)
 674{
 675	struct wm_coeff_ctl *ctl = cs_ctl->priv;
 676
 677	cancel_work_sync(&ctl->work);
 
 
 
 
 
 
 
 
 
 678
 679	kfree(ctl->name);
 680	kfree(ctl);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 681}
 682
 683int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
 684		      unsigned int alg, void *buf, size_t len)
 685{
 686	struct cs_dsp_coeff_ctl *cs_ctl;
 
 687	int ret;
 688
 689	mutex_lock(&dsp->cs_dsp.pwr_lock);
 690	cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg);
 691	ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
 692	mutex_unlock(&dsp->cs_dsp.pwr_lock);
 693
 694	if (ret < 0)
 695		return ret;
 696
 697	return 0;
 
 
 
 
 
 
 698}
 699EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
 700
 701int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
 702		     unsigned int alg, void *buf, size_t len)
 703{
 704	int ret;
 
 
 
 
 705
 706	mutex_lock(&dsp->cs_dsp.pwr_lock);
 707	ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg),
 708				     0, buf, len);
 709	mutex_unlock(&dsp->cs_dsp.pwr_lock);
 710
 711	return ret;
 712}
 713EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
 714
 715static void wm_adsp_release_firmware_files(struct wm_adsp *dsp,
 716					   const struct firmware *wmfw_firmware,
 717					   char *wmfw_filename,
 718					   const struct firmware *coeff_firmware,
 719					   char *coeff_filename)
 720{
 721	if (wmfw_firmware)
 722		release_firmware(wmfw_firmware);
 723	kfree(wmfw_filename);
 724
 725	if (coeff_firmware)
 726		release_firmware(coeff_firmware);
 727	kfree(coeff_filename);
 728}
 729
 730static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
 731					 const struct firmware **firmware, char **filename,
 732					 const char *dir, const char *system_name,
 733					 const char *asoc_component_prefix,
 734					 const char *filetype)
 735{
 736	struct cs_dsp *cs_dsp = &dsp->cs_dsp;
 737	const char *fwf;
 738	char *s, c;
 739	int ret = 0;
 740
 741	if (dsp->fwf_name)
 742		fwf = dsp->fwf_name;
 743	else
 744		fwf = dsp->cs_dsp.name;
 
 
 
 
 745
 746	if (system_name && asoc_component_prefix)
 747		*filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, dsp->part,
 748				      fwf, wm_adsp_fw[dsp->fw].file, system_name,
 749				      asoc_component_prefix, filetype);
 750	else if (system_name)
 751		*filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, dsp->part,
 752				      fwf, wm_adsp_fw[dsp->fw].file, system_name,
 753				      filetype);
 754	else
 755		*filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, dsp->part, fwf,
 756				      wm_adsp_fw[dsp->fw].file, filetype);
 757
 758	if (*filename == NULL)
 759		return -ENOMEM;
 
 
 760
 761	/*
 762	 * Make sure that filename is lower-case and any non alpha-numeric
 763	 * characters except full stop and forward slash are replaced with
 764	 * hyphens.
 765	 */
 766	s = *filename;
 767	while (*s) {
 768		c = *s;
 769		if (isalnum(c))
 770			*s = tolower(c);
 771		else if ((c != '.') && (c != '/'))
 772			*s = '-';
 773		s++;
 774	}
 775
 776	ret = firmware_request_nowarn(firmware, *filename, cs_dsp->dev);
 
 
 
 777	if (ret != 0) {
 778		adsp_dbg(dsp, "Failed to request '%s'\n", *filename);
 779		kfree(*filename);
 780		*filename = NULL;
 781	} else {
 782		adsp_dbg(dsp, "Found '%s'\n", *filename);
 783	}
 784
 785	return ret;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 786}
 787
 788static const char *cirrus_dir = "cirrus/";
 789static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
 790					  const struct firmware **wmfw_firmware,
 791					  char **wmfw_filename,
 792					  const struct firmware **coeff_firmware,
 793					  char **coeff_filename)
 794{
 795	const char *system_name = dsp->system_name;
 796	const char *asoc_component_prefix = dsp->component->name_prefix;
 797	int ret = 0;
 798
 799	if (system_name && asoc_component_prefix) {
 800		if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
 801						   cirrus_dir, system_name,
 802						   asoc_component_prefix, "wmfw")) {
 803			wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
 804						      cirrus_dir, system_name,
 805						      asoc_component_prefix, "bin");
 806			return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 807		}
 808	}
 809
 810	if (system_name) {
 811		if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
 812						   cirrus_dir, system_name,
 813						   NULL, "wmfw")) {
 814			if (asoc_component_prefix)
 815				wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
 816							      cirrus_dir, system_name,
 817							      asoc_component_prefix, "bin");
 818
 819			if (!*coeff_firmware)
 820				wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
 821							      cirrus_dir, system_name,
 822							      NULL, "bin");
 823			return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 824		}
 825	}
 826
 827	/* Check system-specific bin without wmfw before falling back to generic */
 828	if (dsp->wmfw_optional && system_name) {
 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
 839		if (*coeff_firmware)
 840			return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 841	}
 842
 843	/* Check legacy location */
 844	if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
 845					   "", NULL, NULL, "wmfw")) {
 846		wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
 847					      "", NULL, NULL, "bin");
 848		return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 849	}
 850
 851	/* Fall back to generic wmfw and optional matching bin */
 852	ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
 853					    cirrus_dir, NULL, NULL, "wmfw");
 854	if (!ret || dsp->wmfw_optional) {
 855		wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
 856					      cirrus_dir, NULL, NULL, "bin");
 857		return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 858	}
 859
 860	adsp_err(dsp, "Failed to request firmware <%s>%s-%s-%s<-%s<%s>>.wmfw\n",
 861		 cirrus_dir, dsp->part,
 862		 dsp->fwf_name ? dsp->fwf_name : dsp->cs_dsp.name,
 863		 wm_adsp_fw[dsp->fw].file, system_name, asoc_component_prefix);
 
 
 
 864
 865	return -ENOENT;
 
 
 
 
 
 
 
 
 866}
 867
 868static int wm_adsp_common_init(struct wm_adsp *dsp)
 869{
 870	INIT_LIST_HEAD(&dsp->compr_list);
 871	INIT_LIST_HEAD(&dsp->buffer_list);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 872
 873	return 0;
 874}
 875
 876int wm_adsp1_init(struct wm_adsp *dsp)
 877{
 878	int ret;
 879
 880	dsp->cs_dsp.client_ops = &wm_adsp1_client_ops;
 881
 882	ret = cs_dsp_adsp1_init(&dsp->cs_dsp);
 883	if (ret)
 884		return ret;
 885
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 886	return wm_adsp_common_init(dsp);
 887}
 888EXPORT_SYMBOL_GPL(wm_adsp1_init);
 889
 890int wm_adsp1_event(struct snd_soc_dapm_widget *w,
 891		   struct snd_kcontrol *kcontrol,
 892		   int event)
 893{
 894	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 895	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
 896	struct wm_adsp *dsp = &dsps[w->shift];
 897	int ret = 0;
 898	char *wmfw_filename = NULL;
 899	const struct firmware *wmfw_firmware = NULL;
 900	char *coeff_filename = NULL;
 901	const struct firmware *coeff_firmware = NULL;
 902
 903	dsp->component = component;
 904
 
 
 905	switch (event) {
 906	case SND_SOC_DAPM_POST_PMU:
 907		ret = wm_adsp_request_firmware_files(dsp,
 908						     &wmfw_firmware, &wmfw_filename,
 909						     &coeff_firmware, &coeff_filename);
 910		if (ret)
 911			break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 912
 913		ret = cs_dsp_adsp1_power_up(&dsp->cs_dsp,
 914					    wmfw_firmware, wmfw_filename,
 915					    coeff_firmware, coeff_filename,
 916					    wm_adsp_fw_text[dsp->fw]);
 917
 918		wm_adsp_release_firmware_files(dsp,
 919					       wmfw_firmware, wmfw_filename,
 920					       coeff_firmware, coeff_filename);
 921		break;
 
 922	case SND_SOC_DAPM_PRE_PMD:
 923		cs_dsp_adsp1_power_down(&dsp->cs_dsp);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 924		break;
 
 925	default:
 926		break;
 927	}
 928
 
 
 
 
 
 
 
 
 
 
 929	return ret;
 930}
 931EXPORT_SYMBOL_GPL(wm_adsp1_event);
 932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 933int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq)
 934{
 935	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 936	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
 937	struct wm_adsp *dsp = &dsps[w->shift];
 
 938
 939	return cs_dsp_set_dspclk(&dsp->cs_dsp, freq);
 
 
 
 
 
 
 940}
 941EXPORT_SYMBOL_GPL(wm_adsp2_set_dspclk);
 942
 943int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
 944			   struct snd_ctl_elem_value *ucontrol)
 945{
 946	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 947	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
 948	struct soc_mixer_control *mc =
 949		(struct soc_mixer_control *)kcontrol->private_value;
 950	struct wm_adsp *dsp = &dsps[mc->shift - 1];
 951
 952	ucontrol->value.integer.value[0] = dsp->preloaded;
 953
 954	return 0;
 955}
 956EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get);
 957
 958int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
 959			   struct snd_ctl_elem_value *ucontrol)
 960{
 961	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 962	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
 963	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 964	struct soc_mixer_control *mc =
 965		(struct soc_mixer_control *)kcontrol->private_value;
 966	struct wm_adsp *dsp = &dsps[mc->shift - 1];
 967	char preload[32];
 968
 969	if (dsp->preloaded == ucontrol->value.integer.value[0])
 970		return 0;
 971
 972	snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name);
 973
 974	if (ucontrol->value.integer.value[0] || dsp->toggle_preload)
 975		snd_soc_component_force_enable_pin(component, preload);
 976	else
 977		snd_soc_component_disable_pin(component, preload);
 978
 979	snd_soc_dapm_sync(dapm);
 980
 981	flush_work(&dsp->boot_work);
 982
 983	dsp->preloaded = ucontrol->value.integer.value[0];
 984
 985	if (dsp->toggle_preload) {
 986		snd_soc_component_disable_pin(component, preload);
 987		snd_soc_dapm_sync(dapm);
 988	}
 989
 990	return 1;
 991}
 992EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
 993
 994int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware)
 995{
 996	int ret = 0;
 997	char *wmfw_filename = NULL;
 998	const struct firmware *wmfw_firmware = NULL;
 999	char *coeff_filename = NULL;
1000	const struct firmware *coeff_firmware = NULL;
1001
1002	if (load_firmware) {
1003		ret = wm_adsp_request_firmware_files(dsp,
1004						     &wmfw_firmware, &wmfw_filename,
1005						     &coeff_firmware, &coeff_filename);
1006		if (ret)
1007			return ret;
1008	}
1009
1010	ret = cs_dsp_power_up(&dsp->cs_dsp,
1011			      wmfw_firmware, wmfw_filename,
1012			      coeff_firmware, coeff_filename,
1013			      wm_adsp_fw_text[dsp->fw]);
1014
1015	wm_adsp_release_firmware_files(dsp,
1016				       wmfw_firmware, wmfw_filename,
1017				       coeff_firmware, coeff_filename);
1018
1019	return ret;
1020}
1021EXPORT_SYMBOL_GPL(wm_adsp_power_up);
1022
1023void wm_adsp_power_down(struct wm_adsp *dsp)
1024{
1025	cs_dsp_power_down(&dsp->cs_dsp);
1026}
1027EXPORT_SYMBOL_GPL(wm_adsp_power_down);
1028
1029static void wm_adsp_boot_work(struct work_struct *work)
1030{
1031	struct wm_adsp *dsp = container_of(work,
1032					   struct wm_adsp,
1033					   boot_work);
1034
1035	wm_adsp_power_up(dsp, true);
1036}
1037
1038int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
1039			struct snd_kcontrol *kcontrol, int event)
1040{
1041	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
1042	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
1043	struct wm_adsp *dsp = &dsps[w->shift];
 
1044
1045	switch (event) {
1046	case SND_SOC_DAPM_PRE_PMU:
1047		queue_work(system_unbound_wq, &dsp->boot_work);
1048		break;
1049	case SND_SOC_DAPM_PRE_PMD:
1050		wm_adsp_power_down(dsp);
1051		break;
1052	default:
1053		break;
1054	}
1055
1056	return 0;
1057}
1058EXPORT_SYMBOL_GPL(wm_adsp_early_event);
1059
1060static int wm_adsp_pre_run(struct cs_dsp *cs_dsp)
1061{
1062	struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
1063
1064	if (!dsp->pre_run)
1065		return 0;
1066
1067	return (*dsp->pre_run)(dsp);
1068}
1069
1070static int wm_adsp_event_post_run(struct cs_dsp *cs_dsp)
1071{
1072	struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
1073
1074	if (wm_adsp_fw[dsp->fw].num_caps != 0)
1075		return wm_adsp_buffer_init(dsp);
1076
1077	return 0;
1078}
1079
1080static void wm_adsp_event_post_stop(struct cs_dsp *cs_dsp)
1081{
1082	struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
1083
1084	if (wm_adsp_fw[dsp->fw].num_caps != 0)
1085		wm_adsp_buffer_free(dsp);
 
 
 
1086
1087	dsp->fatal_error = false;
1088}
 
1089
1090int wm_adsp_run(struct wm_adsp *dsp)
1091{
1092	flush_work(&dsp->boot_work);
1093
1094	return cs_dsp_run(&dsp->cs_dsp);
1095}
1096EXPORT_SYMBOL_GPL(wm_adsp_run);
1097
1098void wm_adsp_stop(struct wm_adsp *dsp)
1099{
1100	cs_dsp_stop(&dsp->cs_dsp);
 
1101}
1102EXPORT_SYMBOL_GPL(wm_adsp_stop);
1103
1104int wm_adsp_event(struct snd_soc_dapm_widget *w,
1105		  struct snd_kcontrol *kcontrol, int event)
1106{
1107	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
1108	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
1109	struct wm_adsp *dsp = &dsps[w->shift];
 
1110
1111	switch (event) {
1112	case SND_SOC_DAPM_POST_PMU:
1113		return wm_adsp_run(dsp);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1114	case SND_SOC_DAPM_PRE_PMD:
1115		wm_adsp_stop(dsp);
1116		return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1117	default:
1118		return 0;
1119	}
 
 
 
 
 
 
 
 
 
1120}
1121EXPORT_SYMBOL_GPL(wm_adsp_event);
1122
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1123int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
1124{
1125	char preload[32];
1126
1127	if (!dsp->cs_dsp.no_core_startstop) {
1128		snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name);
1129		snd_soc_component_disable_pin(component, preload);
1130	}
1131
1132	cs_dsp_init_debugfs(&dsp->cs_dsp, component->debugfs_root);
1133
1134	dsp->component = component;
1135
1136	return 0;
1137}
1138EXPORT_SYMBOL_GPL(wm_adsp2_component_probe);
1139
1140int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component)
1141{
1142	cs_dsp_cleanup_debugfs(&dsp->cs_dsp);
1143
1144	return 0;
1145}
1146EXPORT_SYMBOL_GPL(wm_adsp2_component_remove);
1147
1148int wm_adsp2_init(struct wm_adsp *dsp)
1149{
1150	int ret;
1151
1152	INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
1153
1154	dsp->sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr);
1155	dsp->cs_dsp.client_ops = &wm_adsp2_client_ops;
1156
1157	ret = cs_dsp_adsp2_init(&dsp->cs_dsp);
1158	if (ret)
1159		return ret;
1160
1161	return wm_adsp_common_init(dsp);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1162}
1163EXPORT_SYMBOL_GPL(wm_adsp2_init);
1164
1165int wm_halo_init(struct wm_adsp *dsp)
1166{
1167	int ret;
1168
1169	INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
1170
1171	dsp->sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr);
1172	dsp->cs_dsp.client_ops = &wm_adsp2_client_ops;
1173
1174	ret = cs_dsp_halo_init(&dsp->cs_dsp);
1175	if (ret)
1176		return ret;
1177
1178	return wm_adsp_common_init(dsp);
 
 
 
 
1179}
1180EXPORT_SYMBOL_GPL(wm_halo_init);
1181
1182void wm_adsp2_remove(struct wm_adsp *dsp)
1183{
1184	cs_dsp_remove(&dsp->cs_dsp);
 
 
 
 
 
 
 
1185}
1186EXPORT_SYMBOL_GPL(wm_adsp2_remove);
1187
1188static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
1189{
1190	return compr->buf != NULL;
1191}
1192
1193static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
1194{
1195	struct wm_adsp_compr_buf *buf = NULL, *tmp;
1196
1197	if (compr->dsp->fatal_error)
1198		return -EINVAL;
1199
1200	list_for_each_entry(tmp, &compr->dsp->buffer_list, list) {
1201		if (!tmp->name || !strcmp(compr->name, tmp->name)) {
1202			buf = tmp;
1203			break;
1204		}
1205	}
1206
1207	if (!buf)
1208		return -EINVAL;
1209
1210	compr->buf = buf;
1211	buf->compr = compr;
1212
1213	return 0;
1214}
1215
1216static void wm_adsp_compr_detach(struct wm_adsp_compr *compr)
1217{
1218	if (!compr)
1219		return;
1220
1221	/* Wake the poll so it can see buffer is no longer attached */
1222	if (compr->stream)
1223		snd_compr_fragment_elapsed(compr->stream);
1224
1225	if (wm_adsp_compr_attached(compr)) {
1226		compr->buf->compr = NULL;
1227		compr->buf = NULL;
1228	}
1229}
1230
1231int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
1232{
1233	struct wm_adsp_compr *compr, *tmp;
1234	struct snd_soc_pcm_runtime *rtd = stream->private_data;
1235	int ret = 0;
1236
1237	mutex_lock(&dsp->cs_dsp.pwr_lock);
1238
1239	if (wm_adsp_fw[dsp->fw].num_caps == 0) {
1240		adsp_err(dsp, "%s: Firmware does not support compressed API\n",
1241			 snd_soc_rtd_to_codec(rtd, 0)->name);
1242		ret = -ENXIO;
1243		goto out;
1244	}
1245
1246	if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
1247		adsp_err(dsp, "%s: Firmware does not support stream direction\n",
1248			 snd_soc_rtd_to_codec(rtd, 0)->name);
1249		ret = -EINVAL;
1250		goto out;
1251	}
1252
1253	list_for_each_entry(tmp, &dsp->compr_list, list) {
1254		if (!strcmp(tmp->name, snd_soc_rtd_to_codec(rtd, 0)->name)) {
1255			adsp_err(dsp, "%s: Only a single stream supported per dai\n",
1256				 snd_soc_rtd_to_codec(rtd, 0)->name);
1257			ret = -EBUSY;
1258			goto out;
1259		}
1260	}
1261
1262	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
1263	if (!compr) {
1264		ret = -ENOMEM;
1265		goto out;
1266	}
1267
1268	compr->dsp = dsp;
1269	compr->stream = stream;
1270	compr->name = snd_soc_rtd_to_codec(rtd, 0)->name;
1271
1272	list_add_tail(&compr->list, &dsp->compr_list);
1273
1274	stream->runtime->private_data = compr;
1275
1276out:
1277	mutex_unlock(&dsp->cs_dsp.pwr_lock);
1278
1279	return ret;
1280}
1281EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
1282
1283int wm_adsp_compr_free(struct snd_soc_component *component,
1284		       struct snd_compr_stream *stream)
1285{
1286	struct wm_adsp_compr *compr = stream->runtime->private_data;
1287	struct wm_adsp *dsp = compr->dsp;
1288
1289	mutex_lock(&dsp->cs_dsp.pwr_lock);
1290
1291	wm_adsp_compr_detach(compr);
1292	list_del(&compr->list);
1293
1294	kfree(compr->raw_buf);
1295	kfree(compr);
1296
1297	mutex_unlock(&dsp->cs_dsp.pwr_lock);
1298
1299	return 0;
1300}
1301EXPORT_SYMBOL_GPL(wm_adsp_compr_free);
1302
1303static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
1304				      struct snd_compr_params *params)
1305{
1306	struct wm_adsp_compr *compr = stream->runtime->private_data;
1307	struct wm_adsp *dsp = compr->dsp;
1308	const struct wm_adsp_fw_caps *caps;
1309	const struct snd_codec_desc *desc;
1310	int i, j;
1311
1312	if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE ||
1313	    params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE ||
1314	    params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS ||
1315	    params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS ||
1316	    params->buffer.fragment_size % CS_DSP_DATA_WORD_SIZE) {
1317		compr_err(compr, "Invalid buffer fragsize=%d fragments=%d\n",
1318			  params->buffer.fragment_size,
1319			  params->buffer.fragments);
1320
1321		return -EINVAL;
1322	}
1323
1324	for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) {
1325		caps = &wm_adsp_fw[dsp->fw].caps[i];
1326		desc = &caps->desc;
1327
1328		if (caps->id != params->codec.id)
1329			continue;
1330
1331		if (stream->direction == SND_COMPRESS_PLAYBACK) {
1332			if (desc->max_ch < params->codec.ch_out)
1333				continue;
1334		} else {
1335			if (desc->max_ch < params->codec.ch_in)
1336				continue;
1337		}
1338
1339		if (!(desc->formats & (1 << params->codec.format)))
1340			continue;
1341
1342		for (j = 0; j < desc->num_sample_rates; ++j)
1343			if (desc->sample_rates[j] == params->codec.sample_rate)
1344				return 0;
1345	}
1346
1347	compr_err(compr, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
1348		  params->codec.id, params->codec.ch_in, params->codec.ch_out,
1349		  params->codec.sample_rate, params->codec.format);
1350	return -EINVAL;
1351}
1352
1353static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr)
1354{
1355	return compr->size.fragment_size / CS_DSP_DATA_WORD_SIZE;
1356}
1357
1358int wm_adsp_compr_set_params(struct snd_soc_component *component,
1359			     struct snd_compr_stream *stream,
1360			     struct snd_compr_params *params)
1361{
1362	struct wm_adsp_compr *compr = stream->runtime->private_data;
1363	unsigned int size;
1364	int ret;
1365
1366	ret = wm_adsp_compr_check_params(stream, params);
1367	if (ret)
1368		return ret;
1369
1370	compr->size = params->buffer;
1371
1372	compr_dbg(compr, "fragment_size=%d fragments=%d\n",
1373		  compr->size.fragment_size, compr->size.fragments);
1374
1375	size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
1376	compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
1377	if (!compr->raw_buf)
1378		return -ENOMEM;
1379
1380	compr->sample_rate = params->codec.sample_rate;
1381
1382	return 0;
1383}
1384EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
1385
1386int wm_adsp_compr_get_caps(struct snd_soc_component *component,
1387			   struct snd_compr_stream *stream,
1388			   struct snd_compr_caps *caps)
1389{
1390	struct wm_adsp_compr *compr = stream->runtime->private_data;
1391	int fw = compr->dsp->fw;
1392	int i;
1393
1394	if (wm_adsp_fw[fw].caps) {
1395		for (i = 0; i < wm_adsp_fw[fw].num_caps; i++)
1396			caps->codecs[i] = wm_adsp_fw[fw].caps[i].id;
1397
1398		caps->num_codecs = i;
1399		caps->direction = wm_adsp_fw[fw].compr_direction;
1400
1401		caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE;
1402		caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE;
1403		caps->min_fragments = WM_ADSP_MIN_FRAGMENTS;
1404		caps->max_fragments = WM_ADSP_MAX_FRAGMENTS;
1405	}
1406
1407	return 0;
1408}
1409EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
1410
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1411static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
1412				      unsigned int field_offset, u32 *data)
1413{
1414	return cs_dsp_read_data_word(&buf->dsp->cs_dsp, buf->host_buf_mem_type,
1415				     buf->host_buf_ptr + field_offset, data);
1416}
1417
1418static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
1419				       unsigned int field_offset, u32 data)
1420{
1421	return cs_dsp_write_data_word(&buf->dsp->cs_dsp, buf->host_buf_mem_type,
1422				      buf->host_buf_ptr + field_offset,
1423				      data);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1424}
1425
1426static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
1427{
1428	const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
1429	struct wm_adsp_buffer_region *region;
1430	u32 offset = 0;
1431	int i, ret;
1432
1433	buf->regions = kcalloc(caps->num_regions, sizeof(*buf->regions),
1434			       GFP_KERNEL);
1435	if (!buf->regions)
1436		return -ENOMEM;
1437
1438	for (i = 0; i < caps->num_regions; ++i) {
1439		region = &buf->regions[i];
1440
1441		region->offset = offset;
1442		region->mem_type = caps->region_defs[i].mem_type;
1443
1444		ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
1445					  &region->base_addr);
1446		if (ret < 0)
1447			goto err;
1448
1449		ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
1450					  &offset);
1451		if (ret < 0)
1452			goto err;
1453
1454		region->cumulative_size = offset;
1455
1456		compr_dbg(buf,
1457			  "region=%d type=%d base=%08x off=%08x size=%08x\n",
1458			  i, region->mem_type, region->base_addr,
1459			  region->offset, region->cumulative_size);
1460	}
1461
1462	return 0;
1463
1464err:
1465	kfree(buf->regions);
1466	return ret;
1467}
1468
1469static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf)
1470{
1471	buf->irq_count = 0xFFFFFFFF;
1472	buf->read_index = -1;
1473	buf->avail = 0;
1474}
1475
1476static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp)
1477{
1478	struct wm_adsp_compr_buf *buf;
1479
1480	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
1481	if (!buf)
1482		return NULL;
1483
1484	buf->dsp = dsp;
1485
1486	wm_adsp_buffer_clear(buf);
1487
 
 
1488	return buf;
1489}
1490
1491static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
1492{
1493	struct cs_dsp_alg_region *alg_region;
1494	struct wm_adsp_compr_buf *buf;
1495	u32 xmalg, addr, magic;
1496	int i, ret;
1497
1498	alg_region = cs_dsp_find_alg_region(&dsp->cs_dsp, WMFW_ADSP2_XM, dsp->cs_dsp.fw_id);
1499	if (!alg_region) {
1500		adsp_err(dsp, "No algorithm region found\n");
1501		return -EINVAL;
1502	}
1503
1504	xmalg = dsp->sys_config_size / sizeof(__be32);
 
 
 
 
1505
1506	addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
1507	ret = cs_dsp_read_data_word(&dsp->cs_dsp, WMFW_ADSP2_XM, addr, &magic);
1508	if (ret < 0)
1509		return ret;
1510
1511	if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
1512		return -ENODEV;
1513
1514	buf = wm_adsp_buffer_alloc(dsp);
1515	if (!buf)
1516		return -ENOMEM;
1517
1518	addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
1519	for (i = 0; i < 5; ++i) {
1520		ret = cs_dsp_read_data_word(&dsp->cs_dsp, WMFW_ADSP2_XM, addr,
1521					    &buf->host_buf_ptr);
1522		if (ret < 0)
1523			goto err;
1524
1525		if (buf->host_buf_ptr)
1526			break;
1527
1528		usleep_range(1000, 2000);
1529	}
1530
1531	if (!buf->host_buf_ptr) {
1532		ret = -EIO;
1533		goto err;
1534	}
1535
1536	buf->host_buf_mem_type = WMFW_ADSP2_XM;
1537
1538	ret = wm_adsp_buffer_populate(buf);
1539	if (ret < 0)
1540		goto err;
1541
1542	list_add_tail(&buf->list, &dsp->buffer_list);
1543
1544	compr_dbg(buf, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr);
1545
1546	return 0;
1547
1548err:
1549	kfree(buf);
1550
1551	return ret;
1552}
1553
1554static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl)
1555{
1556	struct wm_adsp_host_buf_coeff_v1 coeff_v1;
1557	struct wm_adsp_compr_buf *buf;
1558	struct wm_adsp *dsp = container_of(cs_ctl->dsp, struct wm_adsp, cs_dsp);
1559	unsigned int version = 0;
1560	int ret, i;
1561
 
 
 
 
1562	for (i = 0; i < 5; ++i) {
1563		ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, &coeff_v1,
1564					     min(cs_ctl->len, sizeof(coeff_v1)));
1565		if (ret < 0)
1566			return ret;
1567
1568		if (coeff_v1.host_buf_ptr)
1569			break;
1570
1571		usleep_range(1000, 2000);
1572	}
1573
1574	if (!coeff_v1.host_buf_ptr) {
1575		adsp_err(dsp, "Failed to acquire host buffer\n");
1576		return -EIO;
1577	}
1578
1579	buf = wm_adsp_buffer_alloc(dsp);
1580	if (!buf)
1581		return -ENOMEM;
1582
1583	buf->host_buf_mem_type = cs_ctl->alg_region.type;
1584	buf->host_buf_ptr = be32_to_cpu(coeff_v1.host_buf_ptr);
1585
1586	ret = wm_adsp_buffer_populate(buf);
1587	if (ret < 0)
1588		goto err;
1589
1590	/*
1591	 * v0 host_buffer coefficients didn't have versioning, so if the
1592	 * control is one word, assume version 0.
1593	 */
1594	if (cs_ctl->len == 4)
1595		goto done;
 
 
 
 
 
 
 
1596
1597	version = be32_to_cpu(coeff_v1.versions) & HOST_BUF_COEFF_COMPAT_VER_MASK;
1598	version >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
 
1599
1600	if (version > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) {
1601		adsp_err(dsp,
1602			 "Host buffer coeff ver %u > supported version %u\n",
1603			 version, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
1604		ret = -EINVAL;
1605		goto err;
1606	}
1607
1608	cs_dsp_remove_padding((u32 *)&coeff_v1.name, ARRAY_SIZE(coeff_v1.name));
 
1609
1610	buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", dsp->part,
1611			      (char *)&coeff_v1.name);
 
1612
1613done:
1614	list_add_tail(&buf->list, &dsp->buffer_list);
1615
1616	compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n",
1617		  buf->host_buf_ptr, version);
1618
1619	return version;
1620
1621err:
1622	kfree(buf);
1623
1624	return ret;
1625}
1626
1627static int wm_adsp_buffer_init(struct wm_adsp *dsp)
1628{
1629	struct cs_dsp_coeff_ctl *cs_ctl;
1630	int ret;
1631
1632	list_for_each_entry(cs_ctl, &dsp->cs_dsp.ctl_list, list) {
1633		if (cs_ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
1634			continue;
1635
1636		if (!cs_ctl->enabled)
1637			continue;
1638
1639		ret = wm_adsp_buffer_parse_coeff(cs_ctl);
1640		if (ret < 0) {
1641			adsp_err(dsp, "Failed to parse coeff: %d\n", ret);
1642			goto error;
1643		} else if (ret == 0) {
1644			/* Only one buffer supported for version 0 */
1645			return 0;
1646		}
1647	}
1648
1649	if (list_empty(&dsp->buffer_list)) {
1650		/* Fall back to legacy support */
1651		ret = wm_adsp_buffer_parse_legacy(dsp);
1652		if (ret == -ENODEV)
1653			adsp_info(dsp, "Legacy support not available\n");
1654		else if (ret)
1655			adsp_warn(dsp, "Failed to parse legacy: %d\n", ret);
1656	}
1657
1658	return 0;
1659
1660error:
1661	wm_adsp_buffer_free(dsp);
1662	return ret;
1663}
1664
1665static int wm_adsp_buffer_free(struct wm_adsp *dsp)
1666{
1667	struct wm_adsp_compr_buf *buf, *tmp;
1668
1669	list_for_each_entry_safe(buf, tmp, &dsp->buffer_list, list) {
1670		wm_adsp_compr_detach(buf->compr);
1671
1672		kfree(buf->name);
1673		kfree(buf->regions);
1674		list_del(&buf->list);
1675		kfree(buf);
1676	}
1677
1678	return 0;
1679}
1680
1681static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf)
1682{
1683	int ret;
1684
1685	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
1686	if (ret < 0) {
1687		compr_err(buf, "Failed to check buffer error: %d\n", ret);
1688		return ret;
1689	}
1690	if (buf->error != 0) {
1691		compr_err(buf, "Buffer error occurred: %d\n", buf->error);
1692		return -EIO;
1693	}
1694
1695	return 0;
1696}
1697
1698int wm_adsp_compr_trigger(struct snd_soc_component *component,
1699			  struct snd_compr_stream *stream, int cmd)
1700{
1701	struct wm_adsp_compr *compr = stream->runtime->private_data;
1702	struct wm_adsp *dsp = compr->dsp;
1703	int ret = 0;
1704
1705	compr_dbg(compr, "Trigger: %d\n", cmd);
1706
1707	mutex_lock(&dsp->cs_dsp.pwr_lock);
1708
1709	switch (cmd) {
1710	case SNDRV_PCM_TRIGGER_START:
1711		if (!wm_adsp_compr_attached(compr)) {
1712			ret = wm_adsp_compr_attach(compr);
1713			if (ret < 0) {
1714				compr_err(compr, "Failed to link buffer and stream: %d\n",
1715					  ret);
1716				break;
1717			}
1718		}
1719
1720		ret = wm_adsp_buffer_get_error(compr->buf);
1721		if (ret < 0)
1722			break;
1723
1724		/* Trigger the IRQ at one fragment of data */
1725		ret = wm_adsp_buffer_write(compr->buf,
1726					   HOST_BUFFER_FIELD(high_water_mark),
1727					   wm_adsp_compr_frag_words(compr));
1728		if (ret < 0) {
1729			compr_err(compr, "Failed to set high water mark: %d\n",
1730				  ret);
1731			break;
1732		}
1733		break;
1734	case SNDRV_PCM_TRIGGER_STOP:
1735		if (wm_adsp_compr_attached(compr))
1736			wm_adsp_buffer_clear(compr->buf);
1737		break;
1738	default:
1739		ret = -EINVAL;
1740		break;
1741	}
1742
1743	mutex_unlock(&dsp->cs_dsp.pwr_lock);
1744
1745	return ret;
1746}
1747EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
1748
1749static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf)
1750{
1751	int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1;
1752
1753	return buf->regions[last_region].cumulative_size;
1754}
1755
1756static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
1757{
1758	u32 next_read_index, next_write_index;
1759	int write_index, read_index, avail;
1760	int ret;
1761
1762	/* Only sync read index if we haven't already read a valid index */
1763	if (buf->read_index < 0) {
1764		ret = wm_adsp_buffer_read(buf,
1765				HOST_BUFFER_FIELD(next_read_index),
1766				&next_read_index);
1767		if (ret < 0)
1768			return ret;
1769
1770		read_index = sign_extend32(next_read_index, 23);
1771
1772		if (read_index < 0) {
1773			compr_dbg(buf, "Avail check on unstarted stream\n");
1774			return 0;
1775		}
1776
1777		buf->read_index = read_index;
1778	}
1779
1780	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index),
1781			&next_write_index);
1782	if (ret < 0)
1783		return ret;
1784
1785	write_index = sign_extend32(next_write_index, 23);
1786
1787	avail = write_index - buf->read_index;
1788	if (avail < 0)
1789		avail += wm_adsp_buffer_size(buf);
1790
1791	compr_dbg(buf, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
1792		  buf->read_index, write_index, avail * CS_DSP_DATA_WORD_SIZE);
1793
1794	buf->avail = avail;
1795
1796	return 0;
1797}
1798
1799int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
1800{
1801	struct wm_adsp_compr_buf *buf;
1802	struct wm_adsp_compr *compr;
1803	int ret = 0;
1804
1805	mutex_lock(&dsp->cs_dsp.pwr_lock);
1806
1807	if (list_empty(&dsp->buffer_list)) {
1808		ret = -ENODEV;
1809		goto out;
1810	}
1811
1812	adsp_dbg(dsp, "Handling buffer IRQ\n");
1813
1814	list_for_each_entry(buf, &dsp->buffer_list, list) {
1815		compr = buf->compr;
1816
1817		ret = wm_adsp_buffer_get_error(buf);
1818		if (ret < 0)
1819			goto out_notify; /* Wake poll to report error */
1820
1821		ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
1822					  &buf->irq_count);
1823		if (ret < 0) {
1824			compr_err(buf, "Failed to get irq_count: %d\n", ret);
1825			goto out;
1826		}
1827
1828		ret = wm_adsp_buffer_update_avail(buf);
1829		if (ret < 0) {
1830			compr_err(buf, "Error reading avail: %d\n", ret);
1831			goto out;
1832		}
1833
1834		if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2)
1835			ret = WM_ADSP_COMPR_VOICE_TRIGGER;
1836
1837out_notify:
1838		if (compr && compr->stream)
1839			snd_compr_fragment_elapsed(compr->stream);
1840	}
1841
1842out:
1843	mutex_unlock(&dsp->cs_dsp.pwr_lock);
1844
1845	return ret;
1846}
1847EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq);
1848
1849static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
1850{
1851	if (buf->irq_count & 0x01)
1852		return 0;
1853
1854	compr_dbg(buf, "Enable IRQ(0x%x) for next fragment\n", buf->irq_count);
1855
1856	buf->irq_count |= 0x01;
1857
1858	return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack),
1859				    buf->irq_count);
1860}
1861
1862int wm_adsp_compr_pointer(struct snd_soc_component *component,
1863			  struct snd_compr_stream *stream,
1864			  struct snd_compr_tstamp *tstamp)
1865{
1866	struct wm_adsp_compr *compr = stream->runtime->private_data;
1867	struct wm_adsp *dsp = compr->dsp;
1868	struct wm_adsp_compr_buf *buf;
1869	int ret = 0;
1870
1871	compr_dbg(compr, "Pointer request\n");
1872
1873	mutex_lock(&dsp->cs_dsp.pwr_lock);
1874
1875	buf = compr->buf;
1876
1877	if (dsp->fatal_error || !buf || buf->error) {
1878		snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
1879		ret = -EIO;
1880		goto out;
1881	}
1882
1883	if (buf->avail < wm_adsp_compr_frag_words(compr)) {
1884		ret = wm_adsp_buffer_update_avail(buf);
1885		if (ret < 0) {
1886			compr_err(compr, "Error reading avail: %d\n", ret);
1887			goto out;
1888		}
1889
1890		/*
1891		 * If we really have less than 1 fragment available tell the
1892		 * DSP to inform us once a whole fragment is available.
1893		 */
1894		if (buf->avail < wm_adsp_compr_frag_words(compr)) {
1895			ret = wm_adsp_buffer_get_error(buf);
1896			if (ret < 0) {
1897				if (buf->error)
1898					snd_compr_stop_error(stream,
1899							SNDRV_PCM_STATE_XRUN);
1900				goto out;
1901			}
1902
1903			ret = wm_adsp_buffer_reenable_irq(buf);
1904			if (ret < 0) {
1905				compr_err(compr, "Failed to re-enable buffer IRQ: %d\n",
1906					  ret);
1907				goto out;
1908			}
1909		}
1910	}
1911
1912	tstamp->copied_total = compr->copied_total;
1913	tstamp->copied_total += buf->avail * CS_DSP_DATA_WORD_SIZE;
1914	tstamp->sampling_rate = compr->sample_rate;
1915
1916out:
1917	mutex_unlock(&dsp->cs_dsp.pwr_lock);
1918
1919	return ret;
1920}
1921EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
1922
1923static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
1924{
1925	struct wm_adsp_compr_buf *buf = compr->buf;
1926	unsigned int adsp_addr;
1927	int mem_type, nwords, max_read;
1928	int i, ret;
1929
1930	/* Calculate read parameters */
1931	for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
1932		if (buf->read_index < buf->regions[i].cumulative_size)
1933			break;
1934
1935	if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions)
1936		return -EINVAL;
1937
1938	mem_type = buf->regions[i].mem_type;
1939	adsp_addr = buf->regions[i].base_addr +
1940		    (buf->read_index - buf->regions[i].offset);
1941
1942	max_read = wm_adsp_compr_frag_words(compr);
1943	nwords = buf->regions[i].cumulative_size - buf->read_index;
1944
1945	if (nwords > target)
1946		nwords = target;
1947	if (nwords > buf->avail)
1948		nwords = buf->avail;
1949	if (nwords > max_read)
1950		nwords = max_read;
1951	if (!nwords)
1952		return 0;
1953
1954	/* Read data from DSP */
1955	ret = cs_dsp_read_raw_data_block(&buf->dsp->cs_dsp, mem_type, adsp_addr,
1956					 nwords, (__be32 *)compr->raw_buf);
1957	if (ret < 0)
1958		return ret;
1959
1960	cs_dsp_remove_padding(compr->raw_buf, nwords);
1961
1962	/* update read index to account for words read */
1963	buf->read_index += nwords;
1964	if (buf->read_index == wm_adsp_buffer_size(buf))
1965		buf->read_index = 0;
1966
1967	ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index),
1968				   buf->read_index);
1969	if (ret < 0)
1970		return ret;
1971
1972	/* update avail to account for words read */
1973	buf->avail -= nwords;
1974
1975	return nwords;
1976}
1977
1978static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
1979			      char __user *buf, size_t count)
1980{
1981	struct wm_adsp *dsp = compr->dsp;
1982	int ntotal = 0;
1983	int nwords, nbytes;
1984
1985	compr_dbg(compr, "Requested read of %zu bytes\n", count);
1986
1987	if (dsp->fatal_error || !compr->buf || compr->buf->error) {
1988		snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
1989		return -EIO;
1990	}
1991
1992	count /= CS_DSP_DATA_WORD_SIZE;
1993
1994	do {
1995		nwords = wm_adsp_buffer_capture_block(compr, count);
1996		if (nwords < 0) {
1997			compr_err(compr, "Failed to capture block: %d\n",
1998				  nwords);
1999			return nwords;
2000		}
2001
2002		nbytes = nwords * CS_DSP_DATA_WORD_SIZE;
2003
2004		compr_dbg(compr, "Read %d bytes\n", nbytes);
2005
2006		if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
2007			compr_err(compr, "Failed to copy data to user: %d, %d\n",
2008				  ntotal, nbytes);
2009			return -EFAULT;
2010		}
2011
2012		count -= nwords;
2013		ntotal += nbytes;
2014	} while (nwords > 0 && count > 0);
2015
2016	compr->copied_total += ntotal;
2017
2018	return ntotal;
2019}
2020
2021int wm_adsp_compr_copy(struct snd_soc_component *component,
2022		       struct snd_compr_stream *stream, char __user *buf,
2023		       size_t count)
2024{
2025	struct wm_adsp_compr *compr = stream->runtime->private_data;
2026	struct wm_adsp *dsp = compr->dsp;
2027	int ret;
2028
2029	mutex_lock(&dsp->cs_dsp.pwr_lock);
2030
2031	if (stream->direction == SND_COMPRESS_CAPTURE)
2032		ret = wm_adsp_compr_read(compr, buf, count);
2033	else
2034		ret = -ENOTSUPP;
2035
2036	mutex_unlock(&dsp->cs_dsp.pwr_lock);
2037
2038	return ret;
2039}
2040EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
2041
2042static void wm_adsp_fatal_error(struct cs_dsp *cs_dsp)
2043{
2044	struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
2045	struct wm_adsp_compr *compr;
2046
2047	dsp->fatal_error = true;
2048
2049	list_for_each_entry(compr, &dsp->compr_list, list) {
2050		if (compr->stream)
2051			snd_compr_fragment_elapsed(compr->stream);
2052	}
2053}
2054
2055irqreturn_t wm_adsp2_bus_error(int irq, void *data)
2056{
2057	struct wm_adsp *dsp = (struct wm_adsp *)data;
 
 
 
2058
2059	cs_dsp_adsp2_bus_error(&dsp->cs_dsp);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2060
2061	return IRQ_HANDLED;
2062}
2063EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
2064
2065irqreturn_t wm_halo_bus_error(int irq, void *data)
2066{
2067	struct wm_adsp *dsp = (struct wm_adsp *)data;
 
 
 
 
 
 
 
 
2068
2069	cs_dsp_halo_bus_error(&dsp->cs_dsp);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2070
2071	return IRQ_HANDLED;
2072}
2073EXPORT_SYMBOL_GPL(wm_halo_bus_error);
2074
2075irqreturn_t wm_halo_wdt_expire(int irq, void *data)
2076{
2077	struct wm_adsp *dsp = data;
2078
2079	cs_dsp_halo_wdt_expire(&dsp->cs_dsp);
 
 
 
 
 
 
2080
2081	return IRQ_HANDLED;
2082}
2083EXPORT_SYMBOL_GPL(wm_halo_wdt_expire);
2084
2085static const struct cs_dsp_client_ops wm_adsp1_client_ops = {
2086	.control_add = wm_adsp_control_add_cb,
2087	.control_remove = wm_adsp_control_remove,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2088};
2089
2090static const struct cs_dsp_client_ops wm_adsp2_client_ops = {
2091	.control_add = wm_adsp_control_add_cb,
2092	.control_remove = wm_adsp_control_remove,
2093	.pre_run = wm_adsp_pre_run,
2094	.post_run = wm_adsp_event_post_run,
2095	.post_stop = wm_adsp_event_post_stop,
2096	.watchdog_expired = wm_adsp_fatal_error,
 
 
 
 
 
 
 
2097};
2098
2099MODULE_DESCRIPTION("Cirrus Logic ASoC DSP Support");
2100MODULE_LICENSE("GPL v2");
2101MODULE_IMPORT_NS("FW_CS_DSP");
v5.9
   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/vmalloc.h>
  23#include <linux/workqueue.h>
  24#include <linux/debugfs.h>
  25#include <sound/core.h>
  26#include <sound/pcm.h>
  27#include <sound/pcm_params.h>
  28#include <sound/soc.h>
  29#include <sound/jack.h>
  30#include <sound/initval.h>
  31#include <sound/tlv.h>
  32
  33#include "wm_adsp.h"
  34
  35#define adsp_crit(_dsp, fmt, ...) \
  36	dev_crit(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  37#define adsp_err(_dsp, fmt, ...) \
  38	dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  39#define adsp_warn(_dsp, fmt, ...) \
  40	dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  41#define adsp_info(_dsp, fmt, ...) \
  42	dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  43#define adsp_dbg(_dsp, fmt, ...) \
  44	dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  45
  46#define compr_err(_obj, fmt, ...) \
  47	adsp_err(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
  48		 ##__VA_ARGS__)
  49#define compr_dbg(_obj, fmt, ...) \
  50	adsp_dbg(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
  51		 ##__VA_ARGS__)
  52
  53#define ADSP1_CONTROL_1                   0x00
  54#define ADSP1_CONTROL_2                   0x02
  55#define ADSP1_CONTROL_3                   0x03
  56#define ADSP1_CONTROL_4                   0x04
  57#define ADSP1_CONTROL_5                   0x06
  58#define ADSP1_CONTROL_6                   0x07
  59#define ADSP1_CONTROL_7                   0x08
  60#define ADSP1_CONTROL_8                   0x09
  61#define ADSP1_CONTROL_9                   0x0A
  62#define ADSP1_CONTROL_10                  0x0B
  63#define ADSP1_CONTROL_11                  0x0C
  64#define ADSP1_CONTROL_12                  0x0D
  65#define ADSP1_CONTROL_13                  0x0F
  66#define ADSP1_CONTROL_14                  0x10
  67#define ADSP1_CONTROL_15                  0x11
  68#define ADSP1_CONTROL_16                  0x12
  69#define ADSP1_CONTROL_17                  0x13
  70#define ADSP1_CONTROL_18                  0x14
  71#define ADSP1_CONTROL_19                  0x16
  72#define ADSP1_CONTROL_20                  0x17
  73#define ADSP1_CONTROL_21                  0x18
  74#define ADSP1_CONTROL_22                  0x1A
  75#define ADSP1_CONTROL_23                  0x1B
  76#define ADSP1_CONTROL_24                  0x1C
  77#define ADSP1_CONTROL_25                  0x1E
  78#define ADSP1_CONTROL_26                  0x20
  79#define ADSP1_CONTROL_27                  0x21
  80#define ADSP1_CONTROL_28                  0x22
  81#define ADSP1_CONTROL_29                  0x23
  82#define ADSP1_CONTROL_30                  0x24
  83#define ADSP1_CONTROL_31                  0x26
  84
  85/*
  86 * ADSP1 Control 19
  87 */
  88#define ADSP1_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
  89#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
  90#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
  91
  92
  93/*
  94 * ADSP1 Control 30
  95 */
  96#define ADSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
  97#define ADSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
  98#define ADSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
  99#define ADSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
 100#define ADSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
 101#define ADSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
 102#define ADSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
 103#define ADSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
 104#define ADSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
 105#define ADSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
 106#define ADSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
 107#define ADSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
 108#define ADSP1_START                       0x0001  /* DSP1_START */
 109#define ADSP1_START_MASK                  0x0001  /* DSP1_START */
 110#define ADSP1_START_SHIFT                      0  /* DSP1_START */
 111#define ADSP1_START_WIDTH                      1  /* DSP1_START */
 112
 113/*
 114 * ADSP1 Control 31
 115 */
 116#define ADSP1_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
 117#define ADSP1_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
 118#define ADSP1_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
 119
 120#define ADSP2_CONTROL                     0x0
 121#define ADSP2_CLOCKING                    0x1
 122#define ADSP2V2_CLOCKING                  0x2
 123#define ADSP2_STATUS1                     0x4
 124#define ADSP2_WDMA_CONFIG_1               0x30
 125#define ADSP2_WDMA_CONFIG_2               0x31
 126#define ADSP2V2_WDMA_CONFIG_2             0x32
 127#define ADSP2_RDMA_CONFIG_1               0x34
 128
 129#define ADSP2_SCRATCH0                    0x40
 130#define ADSP2_SCRATCH1                    0x41
 131#define ADSP2_SCRATCH2                    0x42
 132#define ADSP2_SCRATCH3                    0x43
 133
 134#define ADSP2V2_SCRATCH0_1                0x40
 135#define ADSP2V2_SCRATCH2_3                0x42
 136
 137/*
 138 * ADSP2 Control
 139 */
 140
 141#define ADSP2_MEM_ENA                     0x0010  /* DSP1_MEM_ENA */
 142#define ADSP2_MEM_ENA_MASK                0x0010  /* DSP1_MEM_ENA */
 143#define ADSP2_MEM_ENA_SHIFT                    4  /* DSP1_MEM_ENA */
 144#define ADSP2_MEM_ENA_WIDTH                    1  /* DSP1_MEM_ENA */
 145#define ADSP2_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
 146#define ADSP2_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
 147#define ADSP2_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
 148#define ADSP2_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
 149#define ADSP2_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
 150#define ADSP2_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
 151#define ADSP2_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
 152#define ADSP2_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
 153#define ADSP2_START                       0x0001  /* DSP1_START */
 154#define ADSP2_START_MASK                  0x0001  /* DSP1_START */
 155#define ADSP2_START_SHIFT                      0  /* DSP1_START */
 156#define ADSP2_START_WIDTH                      1  /* DSP1_START */
 157
 158/*
 159 * ADSP2 clocking
 160 */
 161#define ADSP2_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
 162#define ADSP2_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
 163#define ADSP2_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
 164
 165/*
 166 * ADSP2V2 clocking
 167 */
 168#define ADSP2V2_CLK_SEL_MASK             0x70000  /* CLK_SEL_ENA */
 169#define ADSP2V2_CLK_SEL_SHIFT                 16  /* CLK_SEL_ENA */
 170#define ADSP2V2_CLK_SEL_WIDTH                  3  /* CLK_SEL_ENA */
 171
 172#define ADSP2V2_RATE_MASK                 0x7800  /* DSP_RATE */
 173#define ADSP2V2_RATE_SHIFT                    11  /* DSP_RATE */
 174#define ADSP2V2_RATE_WIDTH                     4  /* DSP_RATE */
 175
 176/*
 177 * ADSP2 Status 1
 178 */
 179#define ADSP2_RAM_RDY                     0x0001
 180#define ADSP2_RAM_RDY_MASK                0x0001
 181#define ADSP2_RAM_RDY_SHIFT                    0
 182#define ADSP2_RAM_RDY_WIDTH                    1
 183
 184/*
 185 * ADSP2 Lock support
 186 */
 187#define ADSP2_LOCK_CODE_0                    0x5555
 188#define ADSP2_LOCK_CODE_1                    0xAAAA
 189
 190#define ADSP2_WATCHDOG                       0x0A
 191#define ADSP2_BUS_ERR_ADDR                   0x52
 192#define ADSP2_REGION_LOCK_STATUS             0x64
 193#define ADSP2_LOCK_REGION_1_LOCK_REGION_0    0x66
 194#define ADSP2_LOCK_REGION_3_LOCK_REGION_2    0x68
 195#define ADSP2_LOCK_REGION_5_LOCK_REGION_4    0x6A
 196#define ADSP2_LOCK_REGION_7_LOCK_REGION_6    0x6C
 197#define ADSP2_LOCK_REGION_9_LOCK_REGION_8    0x6E
 198#define ADSP2_LOCK_REGION_CTRL               0x7A
 199#define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR    0x7C
 200
 201#define ADSP2_REGION_LOCK_ERR_MASK           0x8000
 202#define ADSP2_SLAVE_ERR_MASK                 0x4000
 203#define ADSP2_WDT_TIMEOUT_STS_MASK           0x2000
 204#define ADSP2_CTRL_ERR_PAUSE_ENA             0x0002
 205#define ADSP2_CTRL_ERR_EINT                  0x0001
 206
 207#define ADSP2_BUS_ERR_ADDR_MASK              0x00FFFFFF
 208#define ADSP2_XMEM_ERR_ADDR_MASK             0x0000FFFF
 209#define ADSP2_PMEM_ERR_ADDR_MASK             0x7FFF0000
 210#define ADSP2_PMEM_ERR_ADDR_SHIFT            16
 211#define ADSP2_WDT_ENA_MASK                   0xFFFFFFFD
 212
 213#define ADSP2_LOCK_REGION_SHIFT              16
 214
 215#define ADSP_MAX_STD_CTRL_SIZE               512
 216
 217#define WM_ADSP_ACKED_CTL_TIMEOUT_MS         100
 218#define WM_ADSP_ACKED_CTL_N_QUICKPOLLS       10
 219#define WM_ADSP_ACKED_CTL_MIN_VALUE          0
 220#define WM_ADSP_ACKED_CTL_MAX_VALUE          0xFFFFFF
 221
 222/*
 223 * Event control messages
 224 */
 225#define WM_ADSP_FW_EVENT_SHUTDOWN            0x000001
 226
 227/*
 228 * HALO system info
 229 */
 230#define HALO_AHBM_WINDOW_DEBUG_0             0x02040
 231#define HALO_AHBM_WINDOW_DEBUG_1             0x02044
 232
 233/*
 234 * HALO core
 235 */
 236#define HALO_SCRATCH1                        0x005c0
 237#define HALO_SCRATCH2                        0x005c8
 238#define HALO_SCRATCH3                        0x005d0
 239#define HALO_SCRATCH4                        0x005d8
 240#define HALO_CCM_CORE_CONTROL                0x41000
 241#define HALO_CORE_SOFT_RESET                 0x00010
 242#define HALO_WDT_CONTROL                     0x47000
 243
 244/*
 245 * HALO MPU banks
 246 */
 247#define HALO_MPU_XMEM_ACCESS_0               0x43000
 248#define HALO_MPU_YMEM_ACCESS_0               0x43004
 249#define HALO_MPU_WINDOW_ACCESS_0             0x43008
 250#define HALO_MPU_XREG_ACCESS_0               0x4300C
 251#define HALO_MPU_YREG_ACCESS_0               0x43014
 252#define HALO_MPU_XMEM_ACCESS_1               0x43018
 253#define HALO_MPU_YMEM_ACCESS_1               0x4301C
 254#define HALO_MPU_WINDOW_ACCESS_1             0x43020
 255#define HALO_MPU_XREG_ACCESS_1               0x43024
 256#define HALO_MPU_YREG_ACCESS_1               0x4302C
 257#define HALO_MPU_XMEM_ACCESS_2               0x43030
 258#define HALO_MPU_YMEM_ACCESS_2               0x43034
 259#define HALO_MPU_WINDOW_ACCESS_2             0x43038
 260#define HALO_MPU_XREG_ACCESS_2               0x4303C
 261#define HALO_MPU_YREG_ACCESS_2               0x43044
 262#define HALO_MPU_XMEM_ACCESS_3               0x43048
 263#define HALO_MPU_YMEM_ACCESS_3               0x4304C
 264#define HALO_MPU_WINDOW_ACCESS_3             0x43050
 265#define HALO_MPU_XREG_ACCESS_3               0x43054
 266#define HALO_MPU_YREG_ACCESS_3               0x4305C
 267#define HALO_MPU_XM_VIO_ADDR                 0x43100
 268#define HALO_MPU_XM_VIO_STATUS               0x43104
 269#define HALO_MPU_YM_VIO_ADDR                 0x43108
 270#define HALO_MPU_YM_VIO_STATUS               0x4310C
 271#define HALO_MPU_PM_VIO_ADDR                 0x43110
 272#define HALO_MPU_PM_VIO_STATUS               0x43114
 273#define HALO_MPU_LOCK_CONFIG                 0x43140
 274
 275/*
 276 * HALO_AHBM_WINDOW_DEBUG_1
 277 */
 278#define HALO_AHBM_CORE_ERR_ADDR_MASK         0x0fffff00
 279#define HALO_AHBM_CORE_ERR_ADDR_SHIFT                 8
 280#define HALO_AHBM_FLAGS_ERR_MASK             0x000000ff
 281
 282/*
 283 * HALO_CCM_CORE_CONTROL
 284 */
 285#define HALO_CORE_EN                        0x00000001
 286
 287/*
 288 * HALO_CORE_SOFT_RESET
 289 */
 290#define HALO_CORE_SOFT_RESET_MASK           0x00000001
 291
 292/*
 293 * HALO_WDT_CONTROL
 294 */
 295#define HALO_WDT_EN_MASK                    0x00000001
 296
 297/*
 298 * HALO_MPU_?M_VIO_STATUS
 299 */
 300#define HALO_MPU_VIO_STS_MASK               0x007e0000
 301#define HALO_MPU_VIO_STS_SHIFT                      17
 302#define HALO_MPU_VIO_ERR_WR_MASK            0x00008000
 303#define HALO_MPU_VIO_ERR_SRC_MASK           0x00007fff
 304#define HALO_MPU_VIO_ERR_SRC_SHIFT                   0
 305
 306static struct wm_adsp_ops wm_adsp1_ops;
 307static struct wm_adsp_ops wm_adsp2_ops[];
 308static struct wm_adsp_ops wm_halo_ops;
 309
 310struct wm_adsp_buf {
 311	struct list_head list;
 312	void *buf;
 313};
 314
 315static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
 316					     struct list_head *list)
 317{
 318	struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
 319
 320	if (buf == NULL)
 321		return NULL;
 322
 323	buf->buf = vmalloc(len);
 324	if (!buf->buf) {
 325		kfree(buf);
 326		return NULL;
 327	}
 328	memcpy(buf->buf, src, len);
 329
 330	if (list)
 331		list_add_tail(&buf->list, list);
 332
 333	return buf;
 334}
 335
 336static void wm_adsp_buf_free(struct list_head *list)
 337{
 338	while (!list_empty(list)) {
 339		struct wm_adsp_buf *buf = list_first_entry(list,
 340							   struct wm_adsp_buf,
 341							   list);
 342		list_del(&buf->list);
 343		vfree(buf->buf);
 344		kfree(buf);
 345	}
 346}
 347
 348#define WM_ADSP_FW_MBC_VSS  0
 349#define WM_ADSP_FW_HIFI     1
 350#define WM_ADSP_FW_TX       2
 351#define WM_ADSP_FW_TX_SPK   3
 352#define WM_ADSP_FW_RX       4
 353#define WM_ADSP_FW_RX_ANC   5
 354#define WM_ADSP_FW_CTRL     6
 355#define WM_ADSP_FW_ASR      7
 356#define WM_ADSP_FW_TRACE    8
 357#define WM_ADSP_FW_SPK_PROT 9
 358#define WM_ADSP_FW_SPK_CALI 10
 359#define WM_ADSP_FW_SPK_DIAG 11
 360#define WM_ADSP_FW_MISC     12
 361
 362#define WM_ADSP_NUM_FW      13
 363
 364static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
 365	[WM_ADSP_FW_MBC_VSS] =  "MBC/VSS",
 366	[WM_ADSP_FW_HIFI] =     "MasterHiFi",
 367	[WM_ADSP_FW_TX] =       "Tx",
 368	[WM_ADSP_FW_TX_SPK] =   "Tx Speaker",
 369	[WM_ADSP_FW_RX] =       "Rx",
 370	[WM_ADSP_FW_RX_ANC] =   "Rx ANC",
 371	[WM_ADSP_FW_CTRL] =     "Voice Ctrl",
 372	[WM_ADSP_FW_ASR] =      "ASR Assist",
 373	[WM_ADSP_FW_TRACE] =    "Dbg Trace",
 374	[WM_ADSP_FW_SPK_PROT] = "Protection",
 375	[WM_ADSP_FW_SPK_CALI] = "Calibration",
 376	[WM_ADSP_FW_SPK_DIAG] = "Diagnostic",
 377	[WM_ADSP_FW_MISC] =     "Misc",
 378};
 379
 380struct wm_adsp_system_config_xm_hdr {
 381	__be32 sys_enable;
 382	__be32 fw_id;
 383	__be32 fw_rev;
 384	__be32 boot_status;
 385	__be32 watchdog;
 386	__be32 dma_buffer_size;
 387	__be32 rdma[6];
 388	__be32 wdma[8];
 389	__be32 build_job_name[3];
 390	__be32 build_job_number;
 391};
 392
 393struct wm_halo_system_config_xm_hdr {
 394	__be32 halo_heartbeat;
 395	__be32 build_job_name[3];
 396	__be32 build_job_number;
 397};
 398
 399struct wm_adsp_alg_xm_struct {
 400	__be32 magic;
 401	__be32 smoothing;
 402	__be32 threshold;
 403	__be32 host_buf_ptr;
 404	__be32 start_seq;
 405	__be32 high_water_mark;
 406	__be32 low_water_mark;
 407	__be64 smoothed_power;
 408};
 409
 410struct wm_adsp_host_buf_coeff_v1 {
 411	__be32 host_buf_ptr;		/* Host buffer pointer */
 412	__be32 versions;		/* Version numbers */
 413	__be32 name[4];			/* The buffer name */
 414};
 415
 416struct wm_adsp_buffer {
 417	__be32 buf1_base;		/* Base addr of first buffer area */
 418	__be32 buf1_size;		/* Size of buf1 area in DSP words */
 419	__be32 buf2_base;		/* Base addr of 2nd buffer area */
 420	__be32 buf1_buf2_size;		/* Size of buf1+buf2 in DSP words */
 421	__be32 buf3_base;		/* Base addr of buf3 area */
 422	__be32 buf_total_size;		/* Size of buf1+buf2+buf3 in DSP words */
 423	__be32 high_water_mark;		/* Point at which IRQ is asserted */
 424	__be32 irq_count;		/* bits 1-31 count IRQ assertions */
 425	__be32 irq_ack;			/* acked IRQ count, bit 0 enables IRQ */
 426	__be32 next_write_index;	/* word index of next write */
 427	__be32 next_read_index;		/* word index of next read */
 428	__be32 error;			/* error if any */
 429	__be32 oldest_block_index;	/* word index of oldest surviving */
 430	__be32 requested_rewind;	/* how many blocks rewind was done */
 431	__be32 reserved_space;		/* internal */
 432	__be32 min_free;		/* min free space since stream start */
 433	__be32 blocks_written[2];	/* total blocks written (64 bit) */
 434	__be32 words_written[2];	/* total words written (64 bit) */
 435};
 436
 437struct wm_adsp_compr;
 438
 439struct wm_adsp_compr_buf {
 440	struct list_head list;
 441	struct wm_adsp *dsp;
 442	struct wm_adsp_compr *compr;
 443
 444	struct wm_adsp_buffer_region *regions;
 445	u32 host_buf_ptr;
 446
 447	u32 error;
 448	u32 irq_count;
 449	int read_index;
 450	int avail;
 451	int host_buf_mem_type;
 452
 453	char *name;
 454};
 455
 456struct wm_adsp_compr {
 457	struct list_head list;
 458	struct wm_adsp *dsp;
 459	struct wm_adsp_compr_buf *buf;
 460
 461	struct snd_compr_stream *stream;
 462	struct snd_compressed_buffer size;
 463
 464	u32 *raw_buf;
 465	unsigned int copied_total;
 466
 467	unsigned int sample_rate;
 468
 469	const char *name;
 470};
 471
 472#define WM_ADSP_DATA_WORD_SIZE         3
 473
 474#define WM_ADSP_MIN_FRAGMENTS          1
 475#define WM_ADSP_MAX_FRAGMENTS          256
 476#define WM_ADSP_MIN_FRAGMENT_SIZE      (64 * WM_ADSP_DATA_WORD_SIZE)
 477#define WM_ADSP_MAX_FRAGMENT_SIZE      (4096 * WM_ADSP_DATA_WORD_SIZE)
 478
 479#define WM_ADSP_ALG_XM_STRUCT_MAGIC    0x49aec7
 480
 481#define HOST_BUFFER_FIELD(field) \
 482	(offsetof(struct wm_adsp_buffer, field) / sizeof(__be32))
 483
 484#define ALG_XM_FIELD(field) \
 485	(offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32))
 486
 487#define HOST_BUF_COEFF_SUPPORTED_COMPAT_VER	1
 488
 489#define HOST_BUF_COEFF_COMPAT_VER_MASK		0xFF00
 490#define HOST_BUF_COEFF_COMPAT_VER_SHIFT		8
 491
 492static int wm_adsp_buffer_init(struct wm_adsp *dsp);
 493static int wm_adsp_buffer_free(struct wm_adsp *dsp);
 494
 495struct wm_adsp_buffer_region {
 496	unsigned int offset;
 497	unsigned int cumulative_size;
 498	unsigned int mem_type;
 499	unsigned int base_addr;
 500};
 501
 502struct wm_adsp_buffer_region_def {
 503	unsigned int mem_type;
 504	unsigned int base_offset;
 505	unsigned int size_offset;
 506};
 507
 508static const struct wm_adsp_buffer_region_def default_regions[] = {
 509	{
 510		.mem_type = WMFW_ADSP2_XM,
 511		.base_offset = HOST_BUFFER_FIELD(buf1_base),
 512		.size_offset = HOST_BUFFER_FIELD(buf1_size),
 513	},
 514	{
 515		.mem_type = WMFW_ADSP2_XM,
 516		.base_offset = HOST_BUFFER_FIELD(buf2_base),
 517		.size_offset = HOST_BUFFER_FIELD(buf1_buf2_size),
 518	},
 519	{
 520		.mem_type = WMFW_ADSP2_YM,
 521		.base_offset = HOST_BUFFER_FIELD(buf3_base),
 522		.size_offset = HOST_BUFFER_FIELD(buf_total_size),
 523	},
 524};
 525
 526struct wm_adsp_fw_caps {
 527	u32 id;
 528	struct snd_codec_desc desc;
 529	int num_regions;
 530	const struct wm_adsp_buffer_region_def *region_defs;
 531};
 532
 533static const struct wm_adsp_fw_caps ctrl_caps[] = {
 534	{
 535		.id = SND_AUDIOCODEC_BESPOKE,
 536		.desc = {
 537			.max_ch = 8,
 538			.sample_rates = { 16000 },
 539			.num_sample_rates = 1,
 540			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 541		},
 542		.num_regions = ARRAY_SIZE(default_regions),
 543		.region_defs = default_regions,
 544	},
 545};
 546
 547static const struct wm_adsp_fw_caps trace_caps[] = {
 548	{
 549		.id = SND_AUDIOCODEC_BESPOKE,
 550		.desc = {
 551			.max_ch = 8,
 552			.sample_rates = {
 553				4000, 8000, 11025, 12000, 16000, 22050,
 554				24000, 32000, 44100, 48000, 64000, 88200,
 555				96000, 176400, 192000
 556			},
 557			.num_sample_rates = 15,
 558			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 559		},
 560		.num_regions = ARRAY_SIZE(default_regions),
 561		.region_defs = default_regions,
 562	},
 563};
 564
 565static const struct {
 566	const char *file;
 567	int compr_direction;
 568	int num_caps;
 569	const struct wm_adsp_fw_caps *caps;
 570	bool voice_trigger;
 571} wm_adsp_fw[WM_ADSP_NUM_FW] = {
 572	[WM_ADSP_FW_MBC_VSS] =  { .file = "mbc-vss" },
 573	[WM_ADSP_FW_HIFI] =     { .file = "hifi" },
 574	[WM_ADSP_FW_TX] =       { .file = "tx" },
 575	[WM_ADSP_FW_TX_SPK] =   { .file = "tx-spk" },
 576	[WM_ADSP_FW_RX] =       { .file = "rx" },
 577	[WM_ADSP_FW_RX_ANC] =   { .file = "rx-anc" },
 578	[WM_ADSP_FW_CTRL] =     {
 579		.file = "ctrl",
 580		.compr_direction = SND_COMPRESS_CAPTURE,
 581		.num_caps = ARRAY_SIZE(ctrl_caps),
 582		.caps = ctrl_caps,
 583		.voice_trigger = true,
 584	},
 585	[WM_ADSP_FW_ASR] =      { .file = "asr" },
 586	[WM_ADSP_FW_TRACE] =    {
 587		.file = "trace",
 588		.compr_direction = SND_COMPRESS_CAPTURE,
 589		.num_caps = ARRAY_SIZE(trace_caps),
 590		.caps = trace_caps,
 591	},
 592	[WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" },
 
 
 
 
 
 593	[WM_ADSP_FW_SPK_CALI] = { .file = "spk-cali" },
 594	[WM_ADSP_FW_SPK_DIAG] = { .file = "spk-diag" },
 595	[WM_ADSP_FW_MISC] =     { .file = "misc" },
 596};
 597
 598struct wm_coeff_ctl_ops {
 599	int (*xget)(struct snd_kcontrol *kcontrol,
 600		    struct snd_ctl_elem_value *ucontrol);
 601	int (*xput)(struct snd_kcontrol *kcontrol,
 602		    struct snd_ctl_elem_value *ucontrol);
 603};
 604
 605struct wm_coeff_ctl {
 606	const char *name;
 607	const char *fw_name;
 608	/* Subname is needed to match with firmware */
 609	const char *subname;
 610	unsigned int subname_len;
 611	struct wm_adsp_alg_region alg_region;
 612	struct wm_coeff_ctl_ops ops;
 613	struct wm_adsp *dsp;
 614	unsigned int enabled:1;
 615	struct list_head list;
 616	void *cache;
 617	unsigned int offset;
 618	size_t len;
 619	unsigned int set:1;
 620	struct soc_bytes_ext bytes_ext;
 621	unsigned int flags;
 622	unsigned int type;
 623};
 624
 625static const char *wm_adsp_mem_region_name(unsigned int type)
 626{
 627	switch (type) {
 628	case WMFW_ADSP1_PM:
 629		return "PM";
 630	case WMFW_HALO_PM_PACKED:
 631		return "PM_PACKED";
 632	case WMFW_ADSP1_DM:
 633		return "DM";
 634	case WMFW_ADSP2_XM:
 635		return "XM";
 636	case WMFW_HALO_XM_PACKED:
 637		return "XM_PACKED";
 638	case WMFW_ADSP2_YM:
 639		return "YM";
 640	case WMFW_HALO_YM_PACKED:
 641		return "YM_PACKED";
 642	case WMFW_ADSP1_ZM:
 643		return "ZM";
 644	default:
 645		return NULL;
 646	}
 647}
 648
 649#ifdef CONFIG_DEBUG_FS
 650static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s)
 651{
 652	char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
 653
 654	kfree(dsp->wmfw_file_name);
 655	dsp->wmfw_file_name = tmp;
 656}
 657
 658static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s)
 659{
 660	char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
 661
 662	kfree(dsp->bin_file_name);
 663	dsp->bin_file_name = tmp;
 664}
 665
 666static void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
 667{
 668	kfree(dsp->wmfw_file_name);
 669	kfree(dsp->bin_file_name);
 670	dsp->wmfw_file_name = NULL;
 671	dsp->bin_file_name = NULL;
 672}
 673
 674static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
 675					 char __user *user_buf,
 676					 size_t count, loff_t *ppos)
 677{
 678	struct wm_adsp *dsp = file->private_data;
 679	ssize_t ret;
 680
 681	mutex_lock(&dsp->pwr_lock);
 682
 683	if (!dsp->wmfw_file_name || !dsp->booted)
 684		ret = 0;
 685	else
 686		ret = simple_read_from_buffer(user_buf, count, ppos,
 687					      dsp->wmfw_file_name,
 688					      strlen(dsp->wmfw_file_name));
 689
 690	mutex_unlock(&dsp->pwr_lock);
 691	return ret;
 692}
 693
 694static ssize_t wm_adsp_debugfs_bin_read(struct file *file,
 695					char __user *user_buf,
 696					size_t count, loff_t *ppos)
 697{
 698	struct wm_adsp *dsp = file->private_data;
 699	ssize_t ret;
 700
 701	mutex_lock(&dsp->pwr_lock);
 702
 703	if (!dsp->bin_file_name || !dsp->booted)
 704		ret = 0;
 705	else
 706		ret = simple_read_from_buffer(user_buf, count, ppos,
 707					      dsp->bin_file_name,
 708					      strlen(dsp->bin_file_name));
 709
 710	mutex_unlock(&dsp->pwr_lock);
 711	return ret;
 712}
 713
 714static const struct {
 715	const char *name;
 716	const struct file_operations fops;
 717} wm_adsp_debugfs_fops[] = {
 718	{
 719		.name = "wmfw_file_name",
 720		.fops = {
 721			.open = simple_open,
 722			.read = wm_adsp_debugfs_wmfw_read,
 723		},
 724	},
 725	{
 726		.name = "bin_file_name",
 727		.fops = {
 728			.open = simple_open,
 729			.read = wm_adsp_debugfs_bin_read,
 730		},
 731	},
 732};
 733
 734static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
 735				  struct snd_soc_component *component)
 736{
 737	struct dentry *root = NULL;
 738	int i;
 739
 740	root = debugfs_create_dir(dsp->name, component->debugfs_root);
 741
 742	debugfs_create_bool("booted", 0444, root, &dsp->booted);
 743	debugfs_create_bool("running", 0444, root, &dsp->running);
 744	debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id);
 745	debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version);
 746
 747	for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i)
 748		debugfs_create_file(wm_adsp_debugfs_fops[i].name, 0444, root,
 749				    dsp, &wm_adsp_debugfs_fops[i].fops);
 750
 751	dsp->debugfs_root = root;
 752}
 753
 754static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
 755{
 756	wm_adsp_debugfs_clear(dsp);
 757	debugfs_remove_recursive(dsp->debugfs_root);
 758}
 759#else
 760static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
 761					 struct snd_soc_component *component)
 762{
 763}
 764
 765static inline void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
 766{
 767}
 768
 769static inline void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp,
 770						 const char *s)
 771{
 772}
 773
 774static inline void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp,
 775						const char *s)
 776{
 777}
 778
 779static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
 780{
 781}
 782#endif
 783
 784int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
 785		   struct snd_ctl_elem_value *ucontrol)
 786{
 787	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 788	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 789	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
 790
 791	ucontrol->value.enumerated.item[0] = dsp[e->shift_l].fw;
 792
 793	return 0;
 794}
 795EXPORT_SYMBOL_GPL(wm_adsp_fw_get);
 796
 797int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
 798		   struct snd_ctl_elem_value *ucontrol)
 799{
 800	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 801	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 802	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
 803	int ret = 0;
 804
 805	if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw)
 806		return 0;
 807
 808	if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW)
 809		return -EINVAL;
 810
 811	mutex_lock(&dsp[e->shift_l].pwr_lock);
 812
 813	if (dsp[e->shift_l].booted || !list_empty(&dsp[e->shift_l].compr_list))
 814		ret = -EBUSY;
 815	else
 816		dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0];
 817
 818	mutex_unlock(&dsp[e->shift_l].pwr_lock);
 819
 820	return ret;
 821}
 822EXPORT_SYMBOL_GPL(wm_adsp_fw_put);
 823
 824const struct soc_enum wm_adsp_fw_enum[] = {
 825	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 826	SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 827	SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 828	SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 829	SOC_ENUM_SINGLE(0, 4, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 830	SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 831	SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 832};
 833EXPORT_SYMBOL_GPL(wm_adsp_fw_enum);
 834
 835static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
 836							int type)
 837{
 838	int i;
 839
 840	for (i = 0; i < dsp->num_mems; i++)
 841		if (dsp->mem[i].type == type)
 842			return &dsp->mem[i];
 843
 844	return NULL;
 845}
 846
 847static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
 848					  unsigned int offset)
 849{
 850	switch (mem->type) {
 851	case WMFW_ADSP1_PM:
 852		return mem->base + (offset * 3);
 853	case WMFW_ADSP1_DM:
 854	case WMFW_ADSP2_XM:
 855	case WMFW_ADSP2_YM:
 856	case WMFW_ADSP1_ZM:
 857		return mem->base + (offset * 2);
 858	default:
 859		WARN(1, "Unknown memory region type");
 860		return offset;
 861	}
 862}
 863
 864static unsigned int wm_halo_region_to_reg(struct wm_adsp_region const *mem,
 865					  unsigned int offset)
 866{
 867	switch (mem->type) {
 868	case WMFW_ADSP2_XM:
 869	case WMFW_ADSP2_YM:
 870		return mem->base + (offset * 4);
 871	case WMFW_HALO_XM_PACKED:
 872	case WMFW_HALO_YM_PACKED:
 873		return (mem->base + (offset * 3)) & ~0x3;
 874	case WMFW_HALO_PM_PACKED:
 875		return mem->base + (offset * 5);
 876	default:
 877		WARN(1, "Unknown memory region type");
 878		return offset;
 879	}
 880}
 881
 882static void wm_adsp_read_fw_status(struct wm_adsp *dsp,
 883				   int noffs, unsigned int *offs)
 884{
 885	unsigned int i;
 886	int ret;
 887
 888	for (i = 0; i < noffs; ++i) {
 889		ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]);
 890		if (ret) {
 891			adsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret);
 892			return;
 893		}
 894	}
 895}
 896
 897static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
 898{
 899	unsigned int offs[] = {
 900		ADSP2_SCRATCH0, ADSP2_SCRATCH1, ADSP2_SCRATCH2, ADSP2_SCRATCH3,
 901	};
 902
 903	wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
 904
 905	adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
 906		 offs[0], offs[1], offs[2], offs[3]);
 907}
 908
 909static void wm_adsp2v2_show_fw_status(struct wm_adsp *dsp)
 910{
 911	unsigned int offs[] = { ADSP2V2_SCRATCH0_1, ADSP2V2_SCRATCH2_3 };
 912
 913	wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
 914
 915	adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
 916		 offs[0] & 0xFFFF, offs[0] >> 16,
 917		 offs[1] & 0xFFFF, offs[1] >> 16);
 918}
 919
 920static void wm_halo_show_fw_status(struct wm_adsp *dsp)
 921{
 922	unsigned int offs[] = {
 923		HALO_SCRATCH1, HALO_SCRATCH2, HALO_SCRATCH3, HALO_SCRATCH4,
 924	};
 925
 926	wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
 927
 928	adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
 929		 offs[0], offs[1], offs[2], offs[3]);
 930}
 931
 932static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
 933{
 934	return container_of(ext, struct wm_coeff_ctl, bytes_ext);
 935}
 936
 937static int wm_coeff_base_reg(struct wm_coeff_ctl *ctl, unsigned int *reg)
 938{
 939	const struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
 940	struct wm_adsp *dsp = ctl->dsp;
 941	const struct wm_adsp_region *mem;
 942
 943	mem = wm_adsp_find_region(dsp, alg_region->type);
 944	if (!mem) {
 945		adsp_err(dsp, "No base for region %x\n",
 946			 alg_region->type);
 947		return -EINVAL;
 948	}
 949
 950	*reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset);
 951
 952	return 0;
 953}
 954
 955static int wm_coeff_info(struct snd_kcontrol *kctl,
 956			 struct snd_ctl_elem_info *uinfo)
 957{
 958	struct soc_bytes_ext *bytes_ext =
 959		(struct soc_bytes_ext *)kctl->private_value;
 960	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 
 961
 962	switch (ctl->type) {
 963	case WMFW_CTL_TYPE_ACKED:
 964		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 965		uinfo->value.integer.min = WM_ADSP_ACKED_CTL_MIN_VALUE;
 966		uinfo->value.integer.max = WM_ADSP_ACKED_CTL_MAX_VALUE;
 967		uinfo->value.integer.step = 1;
 968		uinfo->count = 1;
 969		break;
 970	default:
 971		uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
 972		uinfo->count = ctl->len;
 973		break;
 974	}
 975
 976	return 0;
 977}
 978
 979static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl,
 980					unsigned int event_id)
 981{
 982	struct wm_adsp *dsp = ctl->dsp;
 983	u32 val = cpu_to_be32(event_id);
 984	unsigned int reg;
 985	int i, ret;
 986
 987	ret = wm_coeff_base_reg(ctl, &reg);
 988	if (ret)
 989		return ret;
 990
 991	adsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n",
 992		 event_id, ctl->alg_region.alg,
 993		 wm_adsp_mem_region_name(ctl->alg_region.type), ctl->offset);
 994
 995	ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
 996	if (ret) {
 997		adsp_err(dsp, "Failed to write %x: %d\n", reg, ret);
 998		return ret;
 999	}
1000
1001	/*
1002	 * Poll for ack, we initially poll at ~1ms intervals for firmwares
1003	 * that respond quickly, then go to ~10ms polls. A firmware is unlikely
1004	 * to ack instantly so we do the first 1ms delay before reading the
1005	 * control to avoid a pointless bus transaction
1006	 */
1007	for (i = 0; i < WM_ADSP_ACKED_CTL_TIMEOUT_MS;) {
1008		switch (i) {
1009		case 0 ... WM_ADSP_ACKED_CTL_N_QUICKPOLLS - 1:
1010			usleep_range(1000, 2000);
1011			i++;
1012			break;
1013		default:
1014			usleep_range(10000, 20000);
1015			i += 10;
1016			break;
1017		}
1018
1019		ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
1020		if (ret) {
1021			adsp_err(dsp, "Failed to read %x: %d\n", reg, ret);
1022			return ret;
1023		}
1024
1025		if (val == 0) {
1026			adsp_dbg(dsp, "Acked control ACKED at poll %u\n", i);
1027			return 0;
1028		}
1029	}
1030
1031	adsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n",
1032		  reg, ctl->alg_region.alg,
1033		  wm_adsp_mem_region_name(ctl->alg_region.type),
1034		  ctl->offset);
1035
1036	return -ETIMEDOUT;
1037}
1038
1039static int wm_coeff_write_ctrl_raw(struct wm_coeff_ctl *ctl,
1040				   const void *buf, size_t len)
1041{
1042	struct wm_adsp *dsp = ctl->dsp;
1043	void *scratch;
1044	int ret;
1045	unsigned int reg;
1046
1047	ret = wm_coeff_base_reg(ctl, &reg);
1048	if (ret)
1049		return ret;
1050
1051	scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);
1052	if (!scratch)
1053		return -ENOMEM;
1054
1055	ret = regmap_raw_write(dsp->regmap, reg, scratch,
1056			       len);
1057	if (ret) {
1058		adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
1059			 len, reg, ret);
1060		kfree(scratch);
1061		return ret;
1062	}
1063	adsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg);
1064
1065	kfree(scratch);
1066
1067	return 0;
1068}
1069
1070static int wm_coeff_write_ctrl(struct wm_coeff_ctl *ctl,
1071			       const void *buf, size_t len)
1072{
1073	int ret = 0;
1074
1075	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
1076		ret = -EPERM;
1077	else if (buf != ctl->cache)
1078		memcpy(ctl->cache, buf, len);
1079
1080	ctl->set = 1;
1081	if (ctl->enabled && ctl->dsp->running)
1082		ret = wm_coeff_write_ctrl_raw(ctl, buf, len);
1083
1084	return ret;
1085}
1086
1087static int wm_coeff_put(struct snd_kcontrol *kctl,
1088			struct snd_ctl_elem_value *ucontrol)
1089{
1090	struct soc_bytes_ext *bytes_ext =
1091		(struct soc_bytes_ext *)kctl->private_value;
1092	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 
1093	char *p = ucontrol->value.bytes.data;
1094	int ret = 0;
1095
1096	mutex_lock(&ctl->dsp->pwr_lock);
1097	ret = wm_coeff_write_ctrl(ctl, p, ctl->len);
1098	mutex_unlock(&ctl->dsp->pwr_lock);
1099
1100	return ret;
1101}
1102
1103static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
1104			    const unsigned int __user *bytes, unsigned int size)
1105{
1106	struct soc_bytes_ext *bytes_ext =
1107		(struct soc_bytes_ext *)kctl->private_value;
1108	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 
 
1109	int ret = 0;
1110
1111	mutex_lock(&ctl->dsp->pwr_lock);
 
 
1112
1113	if (copy_from_user(ctl->cache, bytes, size))
1114		ret = -EFAULT;
1115	else
1116		ret = wm_coeff_write_ctrl(ctl, ctl->cache, size);
1117
1118	mutex_unlock(&ctl->dsp->pwr_lock);
1119
1120	return ret;
1121}
1122
1123static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
1124			      struct snd_ctl_elem_value *ucontrol)
1125{
1126	struct soc_bytes_ext *bytes_ext =
1127		(struct soc_bytes_ext *)kctl->private_value;
1128	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 
1129	unsigned int val = ucontrol->value.integer.value[0];
1130	int ret;
1131
1132	if (val == 0)
1133		return 0;	/* 0 means no event */
1134
1135	mutex_lock(&ctl->dsp->pwr_lock);
1136
1137	if (ctl->enabled && ctl->dsp->running)
1138		ret = wm_coeff_write_acked_control(ctl, val);
1139	else
1140		ret = -EPERM;
1141
1142	mutex_unlock(&ctl->dsp->pwr_lock);
1143
1144	return ret;
1145}
1146
1147static int wm_coeff_read_ctrl_raw(struct wm_coeff_ctl *ctl,
1148				  void *buf, size_t len)
1149{
1150	struct wm_adsp *dsp = ctl->dsp;
1151	void *scratch;
1152	int ret;
1153	unsigned int reg;
1154
1155	ret = wm_coeff_base_reg(ctl, &reg);
1156	if (ret)
1157		return ret;
1158
1159	scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);
1160	if (!scratch)
1161		return -ENOMEM;
1162
1163	ret = regmap_raw_read(dsp->regmap, reg, scratch, len);
1164	if (ret) {
1165		adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
1166			 len, reg, ret);
1167		kfree(scratch);
1168		return ret;
1169	}
1170	adsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg);
1171
1172	memcpy(buf, scratch, len);
1173	kfree(scratch);
1174
1175	return 0;
1176}
1177
1178static int wm_coeff_read_ctrl(struct wm_coeff_ctl *ctl, void *buf, size_t len)
1179{
1180	int ret = 0;
1181
1182	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
1183		if (ctl->enabled && ctl->dsp->running)
1184			return wm_coeff_read_ctrl_raw(ctl, buf, len);
1185		else
1186			return -EPERM;
1187	} else {
1188		if (!ctl->flags && ctl->enabled && ctl->dsp->running)
1189			ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len);
1190
1191		if (buf != ctl->cache)
1192			memcpy(buf, ctl->cache, len);
1193	}
1194
1195	return ret;
1196}
1197
1198static int wm_coeff_get(struct snd_kcontrol *kctl,
1199			struct snd_ctl_elem_value *ucontrol)
1200{
1201	struct soc_bytes_ext *bytes_ext =
1202		(struct soc_bytes_ext *)kctl->private_value;
1203	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 
1204	char *p = ucontrol->value.bytes.data;
1205	int ret;
1206
1207	mutex_lock(&ctl->dsp->pwr_lock);
1208	ret = wm_coeff_read_ctrl(ctl, p, ctl->len);
1209	mutex_unlock(&ctl->dsp->pwr_lock);
1210
1211	return ret;
1212}
1213
1214static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
1215			    unsigned int __user *bytes, unsigned int size)
1216{
1217	struct soc_bytes_ext *bytes_ext =
1218		(struct soc_bytes_ext *)kctl->private_value;
1219	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 
1220	int ret = 0;
1221
1222	mutex_lock(&ctl->dsp->pwr_lock);
1223
1224	ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, size);
1225
1226	if (!ret && copy_to_user(bytes, ctl->cache, size))
1227		ret = -EFAULT;
1228
1229	mutex_unlock(&ctl->dsp->pwr_lock);
1230
1231	return ret;
1232}
1233
1234static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol,
1235			      struct snd_ctl_elem_value *ucontrol)
1236{
1237	/*
1238	 * Although it's not useful to read an acked control, we must satisfy
1239	 * user-side assumptions that all controls are readable and that a
1240	 * write of the same value should be filtered out (it's valid to send
1241	 * the same event number again to the firmware). We therefore return 0,
1242	 * meaning "no event" so valid event numbers will always be a change
1243	 */
1244	ucontrol->value.integer.value[0] = 0;
1245
1246	return 0;
1247}
1248
1249struct wmfw_ctl_work {
1250	struct wm_adsp *dsp;
1251	struct wm_coeff_ctl *ctl;
1252	struct work_struct work;
1253};
1254
1255static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len)
1256{
1257	unsigned int out, rd, wr, vol;
1258
1259	if (len > ADSP_MAX_STD_CTRL_SIZE) {
1260		rd = SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1261		wr = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE;
1262		vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
1263
1264		out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
1265	} else {
1266		rd = SNDRV_CTL_ELEM_ACCESS_READ;
1267		wr = SNDRV_CTL_ELEM_ACCESS_WRITE;
1268		vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
1269
1270		out = 0;
1271	}
1272
1273	if (in) {
1274		out |= rd;
1275		if (in & WMFW_CTL_FLAG_WRITEABLE)
1276			out |= wr;
1277		if (in & WMFW_CTL_FLAG_VOLATILE)
1278			out |= vol;
1279	} else {
1280		out |= rd | wr | vol;
1281	}
1282
1283	return out;
1284}
1285
1286static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
1287{
 
 
 
 
 
 
 
1288	struct snd_kcontrol_new *kcontrol;
1289	int ret;
1290
1291	if (!ctl || !ctl->name)
1292		return -EINVAL;
1293
1294	kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
1295	if (!kcontrol)
1296		return -ENOMEM;
1297
1298	kcontrol->name = ctl->name;
1299	kcontrol->info = wm_coeff_info;
1300	kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1301	kcontrol->tlv.c = snd_soc_bytes_tlv_callback;
1302	kcontrol->private_value = (unsigned long)&ctl->bytes_ext;
1303	kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len);
1304
1305	switch (ctl->type) {
1306	case WMFW_CTL_TYPE_ACKED:
1307		kcontrol->get = wm_coeff_get_acked;
1308		kcontrol->put = wm_coeff_put_acked;
1309		break;
1310	default:
1311		if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
1312			ctl->bytes_ext.max = ctl->len;
1313			ctl->bytes_ext.get = wm_coeff_tlv_get;
1314			ctl->bytes_ext.put = wm_coeff_tlv_put;
1315		} else {
1316			kcontrol->get = wm_coeff_get;
1317			kcontrol->put = wm_coeff_put;
1318		}
1319		break;
1320	}
1321
1322	ret = snd_soc_add_component_controls(dsp->component, kcontrol, 1);
1323	if (ret < 0)
1324		goto err_kcontrol;
1325
1326	kfree(kcontrol);
1327
1328	return 0;
1329
1330err_kcontrol:
1331	kfree(kcontrol);
1332	return ret;
1333}
1334
1335static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
1336{
 
 
1337	struct wm_coeff_ctl *ctl;
1338	int ret;
1339
1340	list_for_each_entry(ctl, &dsp->ctl_list, list) {
1341		if (!ctl->enabled || ctl->set)
1342			continue;
1343		if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
1344			continue;
1345
1346		/*
1347		 * For readable controls populate the cache from the DSP memory.
1348		 * For non-readable controls the cache was zero-filled when
1349		 * created so we don't need to do anything.
1350		 */
1351		if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) {
1352			ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len);
1353			if (ret < 0)
1354				return ret;
1355		}
1356	}
1357
1358	return 0;
1359}
1360
1361static int wm_coeff_sync_controls(struct wm_adsp *dsp)
1362{
1363	struct wm_coeff_ctl *ctl;
1364	int ret;
1365
1366	list_for_each_entry(ctl, &dsp->ctl_list, list) {
1367		if (!ctl->enabled)
1368			continue;
1369		if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
1370			ret = wm_coeff_write_ctrl_raw(ctl, ctl->cache,
1371						      ctl->len);
1372			if (ret < 0)
1373				return ret;
1374		}
1375	}
1376
1377	return 0;
1378}
1379
1380static void wm_adsp_signal_event_controls(struct wm_adsp *dsp,
1381					  unsigned int event)
1382{
1383	struct wm_coeff_ctl *ctl;
1384	int ret;
1385
1386	list_for_each_entry(ctl, &dsp->ctl_list, list) {
1387		if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT)
1388			continue;
1389
1390		if (!ctl->enabled)
1391			continue;
1392
1393		ret = wm_coeff_write_acked_control(ctl, event);
1394		if (ret)
1395			adsp_warn(dsp,
1396				  "Failed to send 0x%x event to alg 0x%x (%d)\n",
1397				  event, ctl->alg_region.alg, ret);
1398	}
1399}
1400
1401static void wm_adsp_ctl_work(struct work_struct *work)
1402{
1403	struct wmfw_ctl_work *ctl_work = container_of(work,
1404						      struct wmfw_ctl_work,
1405						      work);
1406
1407	wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl);
1408	kfree(ctl_work);
1409}
1410
1411static void wm_adsp_free_ctl_blk(struct wm_coeff_ctl *ctl)
1412{
1413	kfree(ctl->cache);
1414	kfree(ctl->name);
1415	kfree(ctl->subname);
1416	kfree(ctl);
1417}
1418
1419static int wm_adsp_create_control(struct wm_adsp *dsp,
1420				  const struct wm_adsp_alg_region *alg_region,
1421				  unsigned int offset, unsigned int len,
1422				  const char *subname, unsigned int subname_len,
1423				  unsigned int flags, unsigned int type)
1424{
1425	struct wm_coeff_ctl *ctl;
1426	struct wmfw_ctl_work *ctl_work;
1427	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
1428	const char *region_name;
1429	int ret;
1430
1431	region_name = wm_adsp_mem_region_name(alg_region->type);
 
 
 
1432	if (!region_name) {
1433		adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);
1434		return -EINVAL;
1435	}
1436
1437	switch (dsp->fw_ver) {
1438	case 0:
1439	case 1:
1440		snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x",
1441			 dsp->name, region_name, alg_region->alg);
1442		subname = NULL; /* don't append subname */
1443		break;
1444	case 2:
1445		ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
1446				"%s%c %.12s %x", dsp->name, *region_name,
1447				wm_adsp_fw_text[dsp->fw], alg_region->alg);
1448		break;
1449	default:
1450		ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
1451				"%s %.12s %x", dsp->name,
1452				wm_adsp_fw_text[dsp->fw], alg_region->alg);
1453		break;
1454	}
1455
1456	if (subname) {
1457		int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
1458		int skip = 0;
1459
1460		if (dsp->component->name_prefix)
1461			avail -= strlen(dsp->component->name_prefix) + 1;
1462
1463		/* Truncate the subname from the start if it is too long */
1464		if (subname_len > avail)
1465			skip = subname_len - avail;
1466
1467		snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret,
1468			 " %.*s", subname_len - skip, subname + skip);
1469	}
1470
1471	list_for_each_entry(ctl, &dsp->ctl_list, list) {
1472		if (!strcmp(ctl->name, name)) {
1473			if (!ctl->enabled)
1474				ctl->enabled = 1;
1475			return 0;
1476		}
1477	}
1478
1479	ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
1480	if (!ctl)
1481		return -ENOMEM;
1482	ctl->fw_name = wm_adsp_fw_text[dsp->fw];
1483	ctl->alg_region = *alg_region;
1484	ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
1485	if (!ctl->name) {
1486		ret = -ENOMEM;
1487		goto err_ctl;
1488	}
1489	if (subname) {
1490		ctl->subname_len = subname_len;
1491		ctl->subname = kmemdup(subname,
1492				       strlen(subname) + 1, GFP_KERNEL);
1493		if (!ctl->subname) {
1494			ret = -ENOMEM;
1495			goto err_ctl_name;
1496		}
1497	}
1498	ctl->enabled = 1;
1499	ctl->set = 0;
1500	ctl->ops.xget = wm_coeff_get;
1501	ctl->ops.xput = wm_coeff_put;
1502	ctl->dsp = dsp;
1503
1504	ctl->flags = flags;
1505	ctl->type = type;
1506	ctl->offset = offset;
1507	ctl->len = len;
1508	ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
1509	if (!ctl->cache) {
1510		ret = -ENOMEM;
1511		goto err_ctl_subname;
1512	}
1513
1514	list_add(&ctl->list, &dsp->ctl_list);
1515
1516	if (flags & WMFW_CTL_FLAG_SYS)
1517		return 0;
1518
1519	ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
1520	if (!ctl_work) {
1521		ret = -ENOMEM;
1522		goto err_ctl_cache;
1523	}
1524
1525	ctl_work->dsp = dsp;
1526	ctl_work->ctl = ctl;
1527	INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
1528	schedule_work(&ctl_work->work);
1529
1530	return 0;
1531
1532err_ctl_cache:
1533	kfree(ctl->cache);
1534err_ctl_subname:
1535	kfree(ctl->subname);
1536err_ctl_name:
1537	kfree(ctl->name);
1538err_ctl:
1539	kfree(ctl);
1540
1541	return ret;
1542}
 
1543
1544struct wm_coeff_parsed_alg {
1545	int id;
1546	const u8 *name;
1547	int name_len;
1548	int ncoeff;
1549};
1550
1551struct wm_coeff_parsed_coeff {
1552	int offset;
1553	int mem_type;
1554	const u8 *name;
1555	int name_len;
1556	int ctl_type;
1557	int flags;
1558	int len;
1559};
1560
1561static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
1562{
1563	int length;
1564
1565	switch (bytes) {
1566	case 1:
1567		length = **pos;
1568		break;
1569	case 2:
1570		length = le16_to_cpu(*((__le16 *)*pos));
1571		break;
1572	default:
1573		return 0;
1574	}
1575
1576	if (str)
1577		*str = *pos + bytes;
1578
1579	*pos += ((length + bytes) + 3) & ~0x03;
1580
1581	return length;
1582}
1583
1584static int wm_coeff_parse_int(int bytes, const u8 **pos)
1585{
1586	int val = 0;
1587
1588	switch (bytes) {
1589	case 2:
1590		val = le16_to_cpu(*((__le16 *)*pos));
1591		break;
1592	case 4:
1593		val = le32_to_cpu(*((__le32 *)*pos));
1594		break;
1595	default:
1596		break;
1597	}
1598
1599	*pos += bytes;
1600
1601	return val;
1602}
1603
1604static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data,
1605				      struct wm_coeff_parsed_alg *blk)
1606{
1607	const struct wmfw_adsp_alg_data *raw;
1608
1609	switch (dsp->fw_ver) {
1610	case 0:
1611	case 1:
1612		raw = (const struct wmfw_adsp_alg_data *)*data;
1613		*data = raw->data;
1614
1615		blk->id = le32_to_cpu(raw->id);
1616		blk->name = raw->name;
1617		blk->name_len = strlen(raw->name);
1618		blk->ncoeff = le32_to_cpu(raw->ncoeff);
1619		break;
1620	default:
1621		blk->id = wm_coeff_parse_int(sizeof(raw->id), data);
1622		blk->name_len = wm_coeff_parse_string(sizeof(u8), data,
1623						      &blk->name);
1624		wm_coeff_parse_string(sizeof(u16), data, NULL);
1625		blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data);
1626		break;
1627	}
1628
1629	adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
1630	adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
1631	adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
1632}
1633
1634static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
1635					struct wm_coeff_parsed_coeff *blk)
1636{
1637	const struct wmfw_adsp_coeff_data *raw;
1638	const u8 *tmp;
1639	int length;
1640
1641	switch (dsp->fw_ver) {
1642	case 0:
1643	case 1:
1644		raw = (const struct wmfw_adsp_coeff_data *)*data;
1645		*data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
1646
1647		blk->offset = le16_to_cpu(raw->hdr.offset);
1648		blk->mem_type = le16_to_cpu(raw->hdr.type);
1649		blk->name = raw->name;
1650		blk->name_len = strlen(raw->name);
1651		blk->ctl_type = le16_to_cpu(raw->ctl_type);
1652		blk->flags = le16_to_cpu(raw->flags);
1653		blk->len = le32_to_cpu(raw->len);
1654		break;
1655	default:
1656		tmp = *data;
1657		blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
1658		blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
1659		length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
1660		blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp,
1661						      &blk->name);
1662		wm_coeff_parse_string(sizeof(u8), &tmp, NULL);
1663		wm_coeff_parse_string(sizeof(u16), &tmp, NULL);
1664		blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
1665		blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp);
1666		blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp);
1667
1668		*data = *data + sizeof(raw->hdr) + length;
1669		break;
1670	}
1671
1672	adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
1673	adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
1674	adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
1675	adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
1676	adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
1677	adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
1678}
1679
1680static int wm_adsp_check_coeff_flags(struct wm_adsp *dsp,
1681				const struct wm_coeff_parsed_coeff *coeff_blk,
1682				unsigned int f_required,
1683				unsigned int f_illegal)
1684{
1685	if ((coeff_blk->flags & f_illegal) ||
1686	    ((coeff_blk->flags & f_required) != f_required)) {
1687		adsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n",
1688			 coeff_blk->flags, coeff_blk->ctl_type);
1689		return -EINVAL;
1690	}
1691
1692	return 0;
1693}
1694
1695static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
1696			       const struct wmfw_region *region)
1697{
1698	struct wm_adsp_alg_region alg_region = {};
1699	struct wm_coeff_parsed_alg alg_blk;
1700	struct wm_coeff_parsed_coeff coeff_blk;
1701	const u8 *data = region->data;
1702	int i, ret;
1703
1704	wm_coeff_parse_alg(dsp, &data, &alg_blk);
1705	for (i = 0; i < alg_blk.ncoeff; i++) {
1706		wm_coeff_parse_coeff(dsp, &data, &coeff_blk);
1707
1708		switch (coeff_blk.ctl_type) {
1709		case SNDRV_CTL_ELEM_TYPE_BYTES:
1710			break;
1711		case WMFW_CTL_TYPE_ACKED:
1712			if (coeff_blk.flags & WMFW_CTL_FLAG_SYS)
1713				continue;	/* ignore */
1714
1715			ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
1716						WMFW_CTL_FLAG_VOLATILE |
1717						WMFW_CTL_FLAG_WRITEABLE |
1718						WMFW_CTL_FLAG_READABLE,
1719						0);
1720			if (ret)
1721				return -EINVAL;
1722			break;
1723		case WMFW_CTL_TYPE_HOSTEVENT:
1724			ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
1725						WMFW_CTL_FLAG_SYS |
1726						WMFW_CTL_FLAG_VOLATILE |
1727						WMFW_CTL_FLAG_WRITEABLE |
1728						WMFW_CTL_FLAG_READABLE,
1729						0);
1730			if (ret)
1731				return -EINVAL;
1732			break;
1733		case WMFW_CTL_TYPE_HOST_BUFFER:
1734			ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
1735						WMFW_CTL_FLAG_SYS |
1736						WMFW_CTL_FLAG_VOLATILE |
1737						WMFW_CTL_FLAG_READABLE,
1738						0);
1739			if (ret)
1740				return -EINVAL;
1741			break;
1742		default:
1743			adsp_err(dsp, "Unknown control type: %d\n",
1744				 coeff_blk.ctl_type);
1745			return -EINVAL;
1746		}
1747
1748		alg_region.type = coeff_blk.mem_type;
1749		alg_region.alg = alg_blk.id;
1750
1751		ret = wm_adsp_create_control(dsp, &alg_region,
1752					     coeff_blk.offset,
1753					     coeff_blk.len,
1754					     coeff_blk.name,
1755					     coeff_blk.name_len,
1756					     coeff_blk.flags,
1757					     coeff_blk.ctl_type);
1758		if (ret < 0)
1759			adsp_err(dsp, "Failed to create control: %.*s, %d\n",
1760				 coeff_blk.name_len, coeff_blk.name, ret);
1761	}
1762
1763	return 0;
1764}
1765
1766static unsigned int wm_adsp1_parse_sizes(struct wm_adsp *dsp,
1767					 const char * const file,
1768					 unsigned int pos,
1769					 const struct firmware *firmware)
1770{
1771	const struct wmfw_adsp1_sizes *adsp1_sizes;
1772
1773	adsp1_sizes = (void *)&firmware->data[pos];
1774
1775	adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file,
1776		 le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm),
1777		 le32_to_cpu(adsp1_sizes->zm));
1778
1779	return pos + sizeof(*adsp1_sizes);
1780}
1781
1782static unsigned int wm_adsp2_parse_sizes(struct wm_adsp *dsp,
1783					 const char * const file,
1784					 unsigned int pos,
1785					 const struct firmware *firmware)
1786{
1787	const struct wmfw_adsp2_sizes *adsp2_sizes;
1788
1789	adsp2_sizes = (void *)&firmware->data[pos];
1790
1791	adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file,
1792		 le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym),
1793		 le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm));
1794
1795	return pos + sizeof(*adsp2_sizes);
1796}
1797
1798static bool wm_adsp_validate_version(struct wm_adsp *dsp, unsigned int version)
1799{
1800	switch (version) {
1801	case 0:
1802		adsp_warn(dsp, "Deprecated file format %d\n", version);
1803		return true;
1804	case 1:
1805	case 2:
1806		return true;
1807	default:
1808		return false;
1809	}
1810}
1811
1812static bool wm_halo_validate_version(struct wm_adsp *dsp, unsigned int version)
1813{
1814	switch (version) {
1815	case 3:
1816		return true;
1817	default:
1818		return false;
1819	}
1820}
1821
1822static int wm_adsp_load(struct wm_adsp *dsp)
1823{
1824	LIST_HEAD(buf_list);
1825	const struct firmware *firmware;
1826	struct regmap *regmap = dsp->regmap;
1827	unsigned int pos = 0;
1828	const struct wmfw_header *header;
1829	const struct wmfw_adsp1_sizes *adsp1_sizes;
1830	const struct wmfw_footer *footer;
1831	const struct wmfw_region *region;
1832	const struct wm_adsp_region *mem;
1833	const char *region_name;
1834	char *file, *text = NULL;
1835	struct wm_adsp_buf *buf;
1836	unsigned int reg;
1837	int regions = 0;
1838	int ret, offset, type;
1839
1840	file = kzalloc(PAGE_SIZE, GFP_KERNEL);
1841	if (file == NULL)
1842		return -ENOMEM;
1843
1844	snprintf(file, PAGE_SIZE, "%s-%s-%s.wmfw", dsp->part, dsp->fwf_name,
1845		 wm_adsp_fw[dsp->fw].file);
1846	file[PAGE_SIZE - 1] = '\0';
1847
1848	ret = request_firmware(&firmware, file, dsp->dev);
1849	if (ret != 0) {
1850		adsp_err(dsp, "Failed to request '%s'\n", file);
1851		goto out;
1852	}
1853	ret = -EINVAL;
1854
1855	pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
1856	if (pos >= firmware->size) {
1857		adsp_err(dsp, "%s: file too short, %zu bytes\n",
1858			 file, firmware->size);
1859		goto out_fw;
1860	}
1861
1862	header = (void *)&firmware->data[0];
1863
1864	if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
1865		adsp_err(dsp, "%s: invalid magic\n", file);
1866		goto out_fw;
1867	}
1868
1869	if (!dsp->ops->validate_version(dsp, header->ver)) {
1870		adsp_err(dsp, "%s: unknown file format %d\n",
1871			 file, header->ver);
1872		goto out_fw;
1873	}
1874
1875	adsp_info(dsp, "Firmware version: %d\n", header->ver);
1876	dsp->fw_ver = header->ver;
1877
1878	if (header->core != dsp->type) {
1879		adsp_err(dsp, "%s: invalid core %d != %d\n",
1880			 file, header->core, dsp->type);
1881		goto out_fw;
1882	}
1883
1884	pos = sizeof(*header);
1885	pos = dsp->ops->parse_sizes(dsp, file, pos, firmware);
1886
1887	footer = (void *)&firmware->data[pos];
1888	pos += sizeof(*footer);
1889
1890	if (le32_to_cpu(header->len) != pos) {
1891		adsp_err(dsp, "%s: unexpected header length %d\n",
1892			 file, le32_to_cpu(header->len));
1893		goto out_fw;
1894	}
1895
1896	adsp_dbg(dsp, "%s: timestamp %llu\n", file,
1897		 le64_to_cpu(footer->timestamp));
1898
1899	while (pos < firmware->size &&
1900	       sizeof(*region) < firmware->size - pos) {
1901		region = (void *)&(firmware->data[pos]);
1902		region_name = "Unknown";
1903		reg = 0;
1904		text = NULL;
1905		offset = le32_to_cpu(region->offset) & 0xffffff;
1906		type = be32_to_cpu(region->type) & 0xff;
1907
1908		switch (type) {
1909		case WMFW_NAME_TEXT:
1910			region_name = "Firmware name";
1911			text = kzalloc(le32_to_cpu(region->len) + 1,
1912				       GFP_KERNEL);
1913			break;
1914		case WMFW_ALGORITHM_DATA:
1915			region_name = "Algorithm";
1916			ret = wm_adsp_parse_coeff(dsp, region);
1917			if (ret != 0)
1918				goto out_fw;
1919			break;
1920		case WMFW_INFO_TEXT:
1921			region_name = "Information";
1922			text = kzalloc(le32_to_cpu(region->len) + 1,
1923				       GFP_KERNEL);
1924			break;
1925		case WMFW_ABSOLUTE:
1926			region_name = "Absolute";
1927			reg = offset;
1928			break;
1929		case WMFW_ADSP1_PM:
1930		case WMFW_ADSP1_DM:
1931		case WMFW_ADSP2_XM:
1932		case WMFW_ADSP2_YM:
1933		case WMFW_ADSP1_ZM:
1934		case WMFW_HALO_PM_PACKED:
1935		case WMFW_HALO_XM_PACKED:
1936		case WMFW_HALO_YM_PACKED:
1937			mem = wm_adsp_find_region(dsp, type);
1938			if (!mem) {
1939				adsp_err(dsp, "No region of type: %x\n", type);
1940				goto out_fw;
1941			}
1942
1943			region_name = wm_adsp_mem_region_name(type);
1944			reg = dsp->ops->region_to_reg(mem, offset);
1945			break;
1946		default:
1947			adsp_warn(dsp,
1948				  "%s.%d: Unknown region type %x at %d(%x)\n",
1949				  file, regions, type, pos, pos);
1950			break;
1951		}
1952
1953		adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
1954			 regions, le32_to_cpu(region->len), offset,
1955			 region_name);
1956
1957		if (le32_to_cpu(region->len) >
1958		    firmware->size - pos - sizeof(*region)) {
1959			adsp_err(dsp,
1960				 "%s.%d: %s region len %d bytes exceeds file length %zu\n",
1961				 file, regions, region_name,
1962				 le32_to_cpu(region->len), firmware->size);
1963			ret = -EINVAL;
1964			goto out_fw;
1965		}
1966
1967		if (text) {
1968			memcpy(text, region->data, le32_to_cpu(region->len));
1969			adsp_info(dsp, "%s: %s\n", file, text);
1970			kfree(text);
1971			text = NULL;
1972		}
1973
1974		if (reg) {
1975			buf = wm_adsp_buf_alloc(region->data,
1976						le32_to_cpu(region->len),
1977						&buf_list);
1978			if (!buf) {
1979				adsp_err(dsp, "Out of memory\n");
1980				ret = -ENOMEM;
1981				goto out_fw;
1982			}
1983
1984			ret = regmap_raw_write_async(regmap, reg, buf->buf,
1985						     le32_to_cpu(region->len));
1986			if (ret != 0) {
1987				adsp_err(dsp,
1988					"%s.%d: Failed to write %d bytes at %d in %s: %d\n",
1989					file, regions,
1990					le32_to_cpu(region->len), offset,
1991					region_name, ret);
1992				goto out_fw;
1993			}
1994		}
1995
1996		pos += le32_to_cpu(region->len) + sizeof(*region);
1997		regions++;
1998	}
1999
2000	ret = regmap_async_complete(regmap);
2001	if (ret != 0) {
2002		adsp_err(dsp, "Failed to complete async write: %d\n", ret);
2003		goto out_fw;
2004	}
2005
2006	if (pos > firmware->size)
2007		adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
2008			  file, regions, pos - firmware->size);
2009
2010	wm_adsp_debugfs_save_wmfwname(dsp, file);
2011
2012out_fw:
2013	regmap_async_complete(regmap);
2014	wm_adsp_buf_free(&buf_list);
2015	release_firmware(firmware);
2016	kfree(text);
2017out:
2018	kfree(file);
2019
2020	return ret;
2021}
2022
2023/*
2024 * Find wm_coeff_ctl with input name as its subname
2025 * If not found, return NULL
2026 */
2027static struct wm_coeff_ctl *wm_adsp_get_ctl(struct wm_adsp *dsp,
2028					     const char *name, int type,
2029					     unsigned int alg)
2030{
2031	struct wm_coeff_ctl *pos, *rslt = NULL;
2032
2033	list_for_each_entry(pos, &dsp->ctl_list, list) {
2034		if (!pos->subname)
2035			continue;
2036		if (strncmp(pos->subname, name, pos->subname_len) == 0 &&
2037				pos->alg_region.alg == alg &&
2038				pos->alg_region.type == type) {
2039			rslt = pos;
2040			break;
2041		}
2042	}
2043
2044	return rslt;
2045}
2046
2047int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
2048		      unsigned int alg, void *buf, size_t len)
2049{
2050	struct wm_coeff_ctl *ctl;
2051	struct snd_kcontrol *kcontrol;
2052	int ret;
2053
2054	ctl = wm_adsp_get_ctl(dsp, name, type, alg);
2055	if (!ctl)
2056		return -EINVAL;
 
2057
2058	if (len > ctl->len)
2059		return -EINVAL;
2060
2061	ret = wm_coeff_write_ctrl(ctl, buf, len);
2062
2063	kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl->name);
2064	snd_ctl_notify(dsp->component->card->snd_card,
2065		       SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id);
2066
2067	return ret;
2068}
2069EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
2070
2071int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
2072		     unsigned int alg, void *buf, size_t len)
2073{
2074	struct wm_coeff_ctl *ctl;
2075
2076	ctl = wm_adsp_get_ctl(dsp, name, type, alg);
2077	if (!ctl)
2078		return -EINVAL;
2079
2080	if (len > ctl->len)
2081		return -EINVAL;
 
 
2082
2083	return wm_coeff_read_ctrl(ctl, buf, len);
2084}
2085EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
2086
2087static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
2088				  const struct wm_adsp_alg_region *alg_region)
2089{
2090	struct wm_coeff_ctl *ctl;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2091
2092	list_for_each_entry(ctl, &dsp->ctl_list, list) {
2093		if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
2094		    alg_region->alg == ctl->alg_region.alg &&
2095		    alg_region->type == ctl->alg_region.type) {
2096			ctl->alg_region.base = alg_region->base;
2097		}
2098	}
2099}
2100
2101static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
2102			       const struct wm_adsp_region *mem,
2103			       unsigned int pos, unsigned int len)
2104{
2105	void *alg;
2106	unsigned int reg;
2107	int ret;
2108	__be32 val;
 
 
 
2109
2110	if (n_algs == 0) {
2111		adsp_err(dsp, "No algorithms\n");
2112		return ERR_PTR(-EINVAL);
2113	}
2114
2115	if (n_algs > 1024) {
2116		adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
2117		return ERR_PTR(-EINVAL);
 
 
 
 
 
 
 
 
 
 
2118	}
2119
2120	/* Read the terminator first to validate the length */
2121	reg = dsp->ops->region_to_reg(mem, pos + len);
2122
2123	ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
2124	if (ret != 0) {
2125		adsp_err(dsp, "Failed to read algorithm list end: %d\n",
2126			ret);
2127		return ERR_PTR(ret);
 
 
2128	}
2129
2130	if (be32_to_cpu(val) != 0xbedead)
2131		adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
2132			  reg, be32_to_cpu(val));
2133
2134	/* Convert length from DSP words to bytes */
2135	len *= sizeof(u32);
2136
2137	alg = kzalloc(len, GFP_KERNEL | GFP_DMA);
2138	if (!alg)
2139		return ERR_PTR(-ENOMEM);
2140
2141	reg = dsp->ops->region_to_reg(mem, pos);
2142
2143	ret = regmap_raw_read(dsp->regmap, reg, alg, len);
2144	if (ret != 0) {
2145		adsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
2146		kfree(alg);
2147		return ERR_PTR(ret);
2148	}
2149
2150	return alg;
2151}
2152
2153static struct wm_adsp_alg_region *
2154	wm_adsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id)
 
 
 
 
2155{
2156	struct wm_adsp_alg_region *alg_region;
 
 
2157
2158	list_for_each_entry(alg_region, &dsp->alg_regions, list) {
2159		if (id == alg_region->alg && type == alg_region->type)
2160			return alg_region;
2161	}
2162
2163	return NULL;
2164}
2165
2166static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
2167							int type, __be32 id,
2168							__be32 base)
2169{
2170	struct wm_adsp_alg_region *alg_region;
2171
2172	alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
2173	if (!alg_region)
2174		return ERR_PTR(-ENOMEM);
2175
2176	alg_region->type = type;
2177	alg_region->alg = be32_to_cpu(id);
2178	alg_region->base = be32_to_cpu(base);
2179
2180	list_add_tail(&alg_region->list, &dsp->alg_regions);
2181
2182	if (dsp->fw_ver > 0)
2183		wm_adsp_ctl_fixup_base(dsp, alg_region);
2184
2185	return alg_region;
2186}
2187
2188static void wm_adsp_free_alg_regions(struct wm_adsp *dsp)
2189{
2190	struct wm_adsp_alg_region *alg_region;
2191
2192	while (!list_empty(&dsp->alg_regions)) {
2193		alg_region = list_first_entry(&dsp->alg_regions,
2194					      struct wm_adsp_alg_region,
2195					      list);
2196		list_del(&alg_region->list);
2197		kfree(alg_region);
2198	}
2199}
2200
2201static void wmfw_parse_id_header(struct wm_adsp *dsp,
2202				 struct wmfw_id_hdr *fw, int nalgs)
2203{
2204	dsp->fw_id = be32_to_cpu(fw->id);
2205	dsp->fw_id_version = be32_to_cpu(fw->ver);
2206
2207	adsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n",
2208		  dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16,
2209		  (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
2210		  nalgs);
2211}
2212
2213static void wmfw_v3_parse_id_header(struct wm_adsp *dsp,
2214				    struct wmfw_v3_id_hdr *fw, int nalgs)
2215{
2216	dsp->fw_id = be32_to_cpu(fw->id);
2217	dsp->fw_id_version = be32_to_cpu(fw->ver);
2218	dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id);
2219
2220	adsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n",
2221		  dsp->fw_id, dsp->fw_vendor_id,
2222		  (dsp->fw_id_version & 0xff0000) >> 16,
2223		  (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
2224		  nalgs);
2225}
2226
2227static int wm_adsp_create_regions(struct wm_adsp *dsp, __be32 id, int nregions,
2228				int *type, __be32 *base)
2229{
2230	struct wm_adsp_alg_region *alg_region;
2231	int i;
2232
2233	for (i = 0; i < nregions; i++) {
2234		alg_region = wm_adsp_create_region(dsp, type[i], id, base[i]);
2235		if (IS_ERR(alg_region))
2236			return PTR_ERR(alg_region);
2237	}
2238
2239	return 0;
2240}
2241
2242static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
2243{
2244	struct wmfw_adsp1_id_hdr adsp1_id;
2245	struct wmfw_adsp1_alg_hdr *adsp1_alg;
2246	struct wm_adsp_alg_region *alg_region;
2247	const struct wm_adsp_region *mem;
2248	unsigned int pos, len;
2249	size_t n_algs;
2250	int i, ret;
2251
2252	mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
2253	if (WARN_ON(!mem))
2254		return -EINVAL;
2255
2256	ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
2257			      sizeof(adsp1_id));
2258	if (ret != 0) {
2259		adsp_err(dsp, "Failed to read algorithm info: %d\n",
2260			 ret);
2261		return ret;
2262	}
2263
2264	n_algs = be32_to_cpu(adsp1_id.n_algs);
2265
2266	wmfw_parse_id_header(dsp, &adsp1_id.fw, n_algs);
2267
2268	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
2269					   adsp1_id.fw.id, adsp1_id.zm);
2270	if (IS_ERR(alg_region))
2271		return PTR_ERR(alg_region);
2272
2273	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
2274					   adsp1_id.fw.id, adsp1_id.dm);
2275	if (IS_ERR(alg_region))
2276		return PTR_ERR(alg_region);
2277
2278	/* Calculate offset and length in DSP words */
2279	pos = sizeof(adsp1_id) / sizeof(u32);
2280	len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32);
2281
2282	adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
2283	if (IS_ERR(adsp1_alg))
2284		return PTR_ERR(adsp1_alg);
2285
2286	for (i = 0; i < n_algs; i++) {
2287		adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
2288			  i, be32_to_cpu(adsp1_alg[i].alg.id),
2289			  (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
2290			  (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
2291			  be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
2292			  be32_to_cpu(adsp1_alg[i].dm),
2293			  be32_to_cpu(adsp1_alg[i].zm));
2294
2295		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
2296						   adsp1_alg[i].alg.id,
2297						   adsp1_alg[i].dm);
2298		if (IS_ERR(alg_region)) {
2299			ret = PTR_ERR(alg_region);
2300			goto out;
2301		}
2302		if (dsp->fw_ver == 0) {
2303			if (i + 1 < n_algs) {
2304				len = be32_to_cpu(adsp1_alg[i + 1].dm);
2305				len -= be32_to_cpu(adsp1_alg[i].dm);
2306				len *= 4;
2307				wm_adsp_create_control(dsp, alg_region, 0,
2308						     len, NULL, 0, 0,
2309						     SNDRV_CTL_ELEM_TYPE_BYTES);
2310			} else {
2311				adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
2312					  be32_to_cpu(adsp1_alg[i].alg.id));
2313			}
2314		}
2315
2316		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
2317						   adsp1_alg[i].alg.id,
2318						   adsp1_alg[i].zm);
2319		if (IS_ERR(alg_region)) {
2320			ret = PTR_ERR(alg_region);
2321			goto out;
2322		}
2323		if (dsp->fw_ver == 0) {
2324			if (i + 1 < n_algs) {
2325				len = be32_to_cpu(adsp1_alg[i + 1].zm);
2326				len -= be32_to_cpu(adsp1_alg[i].zm);
2327				len *= 4;
2328				wm_adsp_create_control(dsp, alg_region, 0,
2329						     len, NULL, 0, 0,
2330						     SNDRV_CTL_ELEM_TYPE_BYTES);
2331			} else {
2332				adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
2333					  be32_to_cpu(adsp1_alg[i].alg.id));
2334			}
2335		}
2336	}
2337
2338out:
2339	kfree(adsp1_alg);
2340	return ret;
2341}
2342
2343static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
2344{
2345	struct wmfw_adsp2_id_hdr adsp2_id;
2346	struct wmfw_adsp2_alg_hdr *adsp2_alg;
2347	struct wm_adsp_alg_region *alg_region;
2348	const struct wm_adsp_region *mem;
2349	unsigned int pos, len;
2350	size_t n_algs;
2351	int i, ret;
2352
2353	mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
2354	if (WARN_ON(!mem))
2355		return -EINVAL;
2356
2357	ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
2358			      sizeof(adsp2_id));
2359	if (ret != 0) {
2360		adsp_err(dsp, "Failed to read algorithm info: %d\n",
2361			 ret);
2362		return ret;
2363	}
2364
2365	n_algs = be32_to_cpu(adsp2_id.n_algs);
2366
2367	wmfw_parse_id_header(dsp, &adsp2_id.fw, n_algs);
2368
2369	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
2370					   adsp2_id.fw.id, adsp2_id.xm);
2371	if (IS_ERR(alg_region))
2372		return PTR_ERR(alg_region);
2373
2374	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
2375					   adsp2_id.fw.id, adsp2_id.ym);
2376	if (IS_ERR(alg_region))
2377		return PTR_ERR(alg_region);
2378
2379	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
2380					   adsp2_id.fw.id, adsp2_id.zm);
2381	if (IS_ERR(alg_region))
2382		return PTR_ERR(alg_region);
2383
2384	/* Calculate offset and length in DSP words */
2385	pos = sizeof(adsp2_id) / sizeof(u32);
2386	len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32);
2387
2388	adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
2389	if (IS_ERR(adsp2_alg))
2390		return PTR_ERR(adsp2_alg);
2391
2392	for (i = 0; i < n_algs; i++) {
2393		adsp_info(dsp,
2394			  "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
2395			  i, be32_to_cpu(adsp2_alg[i].alg.id),
2396			  (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
2397			  (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
2398			  be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
2399			  be32_to_cpu(adsp2_alg[i].xm),
2400			  be32_to_cpu(adsp2_alg[i].ym),
2401			  be32_to_cpu(adsp2_alg[i].zm));
2402
2403		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
2404						   adsp2_alg[i].alg.id,
2405						   adsp2_alg[i].xm);
2406		if (IS_ERR(alg_region)) {
2407			ret = PTR_ERR(alg_region);
2408			goto out;
2409		}
2410		if (dsp->fw_ver == 0) {
2411			if (i + 1 < n_algs) {
2412				len = be32_to_cpu(adsp2_alg[i + 1].xm);
2413				len -= be32_to_cpu(adsp2_alg[i].xm);
2414				len *= 4;
2415				wm_adsp_create_control(dsp, alg_region, 0,
2416						     len, NULL, 0, 0,
2417						     SNDRV_CTL_ELEM_TYPE_BYTES);
2418			} else {
2419				adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
2420					  be32_to_cpu(adsp2_alg[i].alg.id));
2421			}
2422		}
2423
2424		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
2425						   adsp2_alg[i].alg.id,
2426						   adsp2_alg[i].ym);
2427		if (IS_ERR(alg_region)) {
2428			ret = PTR_ERR(alg_region);
2429			goto out;
2430		}
2431		if (dsp->fw_ver == 0) {
2432			if (i + 1 < n_algs) {
2433				len = be32_to_cpu(adsp2_alg[i + 1].ym);
2434				len -= be32_to_cpu(adsp2_alg[i].ym);
2435				len *= 4;
2436				wm_adsp_create_control(dsp, alg_region, 0,
2437						     len, NULL, 0, 0,
2438						     SNDRV_CTL_ELEM_TYPE_BYTES);
2439			} else {
2440				adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
2441					  be32_to_cpu(adsp2_alg[i].alg.id));
2442			}
2443		}
2444
2445		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
2446						   adsp2_alg[i].alg.id,
2447						   adsp2_alg[i].zm);
2448		if (IS_ERR(alg_region)) {
2449			ret = PTR_ERR(alg_region);
2450			goto out;
2451		}
2452		if (dsp->fw_ver == 0) {
2453			if (i + 1 < n_algs) {
2454				len = be32_to_cpu(adsp2_alg[i + 1].zm);
2455				len -= be32_to_cpu(adsp2_alg[i].zm);
2456				len *= 4;
2457				wm_adsp_create_control(dsp, alg_region, 0,
2458						     len, NULL, 0, 0,
2459						     SNDRV_CTL_ELEM_TYPE_BYTES);
2460			} else {
2461				adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
2462					  be32_to_cpu(adsp2_alg[i].alg.id));
2463			}
2464		}
2465	}
2466
2467out:
2468	kfree(adsp2_alg);
2469	return ret;
2470}
 
 
 
 
 
 
 
2471
2472static int wm_halo_create_regions(struct wm_adsp *dsp, __be32 id,
2473				  __be32 xm_base, __be32 ym_base)
2474{
2475	int types[] = {
2476		WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED,
2477		WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED
2478	};
2479	__be32 bases[] = { xm_base, xm_base, ym_base, ym_base };
2480
2481	return wm_adsp_create_regions(dsp, id, ARRAY_SIZE(types), types, bases);
2482}
2483
2484static int wm_halo_setup_algs(struct wm_adsp *dsp)
2485{
2486	struct wmfw_halo_id_hdr halo_id;
2487	struct wmfw_halo_alg_hdr *halo_alg;
2488	const struct wm_adsp_region *mem;
2489	unsigned int pos, len;
2490	size_t n_algs;
2491	int i, ret;
2492
2493	mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
2494	if (WARN_ON(!mem))
2495		return -EINVAL;
2496
2497	ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id,
2498			      sizeof(halo_id));
2499	if (ret != 0) {
2500		adsp_err(dsp, "Failed to read algorithm info: %d\n",
2501			 ret);
2502		return ret;
2503	}
2504
2505	n_algs = be32_to_cpu(halo_id.n_algs);
2506
2507	wmfw_v3_parse_id_header(dsp, &halo_id.fw, n_algs);
2508
2509	ret = wm_halo_create_regions(dsp, halo_id.fw.id,
2510				     halo_id.xm_base, halo_id.ym_base);
2511	if (ret)
2512		return ret;
2513
2514	/* Calculate offset and length in DSP words */
2515	pos = sizeof(halo_id) / sizeof(u32);
2516	len = (sizeof(*halo_alg) * n_algs) / sizeof(u32);
2517
2518	halo_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
2519	if (IS_ERR(halo_alg))
2520		return PTR_ERR(halo_alg);
2521
2522	for (i = 0; i < n_algs; i++) {
2523		adsp_info(dsp,
2524			  "%d: ID %x v%d.%d.%d XM@%x YM@%x\n",
2525			  i, be32_to_cpu(halo_alg[i].alg.id),
2526			  (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16,
2527			  (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8,
2528			  be32_to_cpu(halo_alg[i].alg.ver) & 0xff,
2529			  be32_to_cpu(halo_alg[i].xm_base),
2530			  be32_to_cpu(halo_alg[i].ym_base));
2531
2532		ret = wm_halo_create_regions(dsp, halo_alg[i].alg.id,
2533					     halo_alg[i].xm_base,
2534					     halo_alg[i].ym_base);
2535		if (ret)
2536			goto out;
2537	}
2538
2539out:
2540	kfree(halo_alg);
2541	return ret;
2542}
2543
2544static int wm_adsp_load_coeff(struct wm_adsp *dsp)
2545{
2546	LIST_HEAD(buf_list);
2547	struct regmap *regmap = dsp->regmap;
2548	struct wmfw_coeff_hdr *hdr;
2549	struct wmfw_coeff_item *blk;
2550	const struct firmware *firmware;
2551	const struct wm_adsp_region *mem;
2552	struct wm_adsp_alg_region *alg_region;
2553	const char *region_name;
2554	int ret, pos, blocks, type, offset, reg;
2555	char *file;
2556	struct wm_adsp_buf *buf;
2557
2558	file = kzalloc(PAGE_SIZE, GFP_KERNEL);
2559	if (file == NULL)
2560		return -ENOMEM;
2561
2562	snprintf(file, PAGE_SIZE, "%s-%s-%s.bin", dsp->part, dsp->fwf_name,
2563		 wm_adsp_fw[dsp->fw].file);
2564	file[PAGE_SIZE - 1] = '\0';
2565
2566	ret = request_firmware(&firmware, file, dsp->dev);
2567	if (ret != 0) {
2568		adsp_warn(dsp, "Failed to request '%s'\n", file);
2569		ret = 0;
2570		goto out;
2571	}
2572	ret = -EINVAL;
2573
2574	if (sizeof(*hdr) >= firmware->size) {
2575		adsp_err(dsp, "%s: file too short, %zu bytes\n",
2576			file, firmware->size);
2577		goto out_fw;
2578	}
2579
2580	hdr = (void *)&firmware->data[0];
2581	if (memcmp(hdr->magic, "WMDR", 4) != 0) {
2582		adsp_err(dsp, "%s: invalid magic\n", file);
2583		goto out_fw;
2584	}
2585
2586	switch (be32_to_cpu(hdr->rev) & 0xff) {
2587	case 1:
2588		break;
2589	default:
2590		adsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
2591			 file, be32_to_cpu(hdr->rev) & 0xff);
2592		ret = -EINVAL;
2593		goto out_fw;
2594	}
2595
2596	adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
2597		(le32_to_cpu(hdr->ver) >> 16) & 0xff,
2598		(le32_to_cpu(hdr->ver) >>  8) & 0xff,
2599		le32_to_cpu(hdr->ver) & 0xff);
2600
2601	pos = le32_to_cpu(hdr->len);
2602
2603	blocks = 0;
2604	while (pos < firmware->size &&
2605	       sizeof(*blk) < firmware->size - pos) {
2606		blk = (void *)(&firmware->data[pos]);
2607
2608		type = le16_to_cpu(blk->type);
2609		offset = le16_to_cpu(blk->offset);
2610
2611		adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
2612			 file, blocks, le32_to_cpu(blk->id),
2613			 (le32_to_cpu(blk->ver) >> 16) & 0xff,
2614			 (le32_to_cpu(blk->ver) >>  8) & 0xff,
2615			 le32_to_cpu(blk->ver) & 0xff);
2616		adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
2617			 file, blocks, le32_to_cpu(blk->len), offset, type);
2618
2619		reg = 0;
2620		region_name = "Unknown";
2621		switch (type) {
2622		case (WMFW_NAME_TEXT << 8):
2623		case (WMFW_INFO_TEXT << 8):
2624		case (WMFW_METADATA << 8):
2625			break;
2626		case (WMFW_ABSOLUTE << 8):
2627			/*
2628			 * Old files may use this for global
2629			 * coefficients.
2630			 */
2631			if (le32_to_cpu(blk->id) == dsp->fw_id &&
2632			    offset == 0) {
2633				region_name = "global coefficients";
2634				mem = wm_adsp_find_region(dsp, type);
2635				if (!mem) {
2636					adsp_err(dsp, "No ZM\n");
2637					break;
2638				}
2639				reg = dsp->ops->region_to_reg(mem, 0);
2640
2641			} else {
2642				region_name = "register";
2643				reg = offset;
2644			}
2645			break;
2646
2647		case WMFW_ADSP1_DM:
2648		case WMFW_ADSP1_ZM:
2649		case WMFW_ADSP2_XM:
2650		case WMFW_ADSP2_YM:
2651		case WMFW_HALO_XM_PACKED:
2652		case WMFW_HALO_YM_PACKED:
2653		case WMFW_HALO_PM_PACKED:
2654			adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
2655				 file, blocks, le32_to_cpu(blk->len),
2656				 type, le32_to_cpu(blk->id));
2657
2658			mem = wm_adsp_find_region(dsp, type);
2659			if (!mem) {
2660				adsp_err(dsp, "No base for region %x\n", type);
2661				break;
2662			}
2663
2664			alg_region = wm_adsp_find_alg_region(dsp, type,
2665						le32_to_cpu(blk->id));
2666			if (alg_region) {
2667				reg = alg_region->base;
2668				reg = dsp->ops->region_to_reg(mem, reg);
2669				reg += offset;
2670			} else {
2671				adsp_err(dsp, "No %x for algorithm %x\n",
2672					 type, le32_to_cpu(blk->id));
2673			}
2674			break;
2675
2676		default:
2677			adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
2678				 file, blocks, type, pos);
2679			break;
2680		}
2681
2682		if (reg) {
2683			if (le32_to_cpu(blk->len) >
2684			    firmware->size - pos - sizeof(*blk)) {
2685				adsp_err(dsp,
2686					 "%s.%d: %s region len %d bytes exceeds file length %zu\n",
2687					 file, blocks, region_name,
2688					 le32_to_cpu(blk->len),
2689					 firmware->size);
2690				ret = -EINVAL;
2691				goto out_fw;
2692			}
2693
2694			buf = wm_adsp_buf_alloc(blk->data,
2695						le32_to_cpu(blk->len),
2696						&buf_list);
2697			if (!buf) {
2698				adsp_err(dsp, "Out of memory\n");
2699				ret = -ENOMEM;
2700				goto out_fw;
2701			}
2702
2703			adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
2704				 file, blocks, le32_to_cpu(blk->len),
2705				 reg);
2706			ret = regmap_raw_write_async(regmap, reg, buf->buf,
2707						     le32_to_cpu(blk->len));
2708			if (ret != 0) {
2709				adsp_err(dsp,
2710					"%s.%d: Failed to write to %x in %s: %d\n",
2711					file, blocks, reg, region_name, ret);
2712			}
2713		}
2714
2715		pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
2716		blocks++;
2717	}
2718
2719	ret = regmap_async_complete(regmap);
2720	if (ret != 0)
2721		adsp_err(dsp, "Failed to complete async write: %d\n", ret);
2722
2723	if (pos > firmware->size)
2724		adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
2725			  file, blocks, pos - firmware->size);
2726
2727	wm_adsp_debugfs_save_binname(dsp, file);
2728
2729out_fw:
2730	regmap_async_complete(regmap);
2731	release_firmware(firmware);
2732	wm_adsp_buf_free(&buf_list);
2733out:
2734	kfree(file);
2735	return ret;
2736}
2737
2738static int wm_adsp_create_name(struct wm_adsp *dsp)
2739{
2740	char *p;
2741
2742	if (!dsp->name) {
2743		dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d",
2744					   dsp->num);
2745		if (!dsp->name)
2746			return -ENOMEM;
2747	}
2748
2749	if (!dsp->fwf_name) {
2750		p = devm_kstrdup(dsp->dev, dsp->name, GFP_KERNEL);
2751		if (!p)
2752			return -ENOMEM;
2753
2754		dsp->fwf_name = p;
2755		for (; *p != 0; ++p)
2756			*p = tolower(*p);
2757	}
2758
2759	return 0;
2760}
2761
2762static int wm_adsp_common_init(struct wm_adsp *dsp)
2763{
2764	int ret;
2765
2766	ret = wm_adsp_create_name(dsp);
 
 
2767	if (ret)
2768		return ret;
2769
2770	INIT_LIST_HEAD(&dsp->alg_regions);
2771	INIT_LIST_HEAD(&dsp->ctl_list);
2772	INIT_LIST_HEAD(&dsp->compr_list);
2773	INIT_LIST_HEAD(&dsp->buffer_list);
2774
2775	mutex_init(&dsp->pwr_lock);
2776
2777	return 0;
2778}
2779
2780int wm_adsp1_init(struct wm_adsp *dsp)
2781{
2782	dsp->ops = &wm_adsp1_ops;
2783
2784	return wm_adsp_common_init(dsp);
2785}
2786EXPORT_SYMBOL_GPL(wm_adsp1_init);
2787
2788int wm_adsp1_event(struct snd_soc_dapm_widget *w,
2789		   struct snd_kcontrol *kcontrol,
2790		   int event)
2791{
2792	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
2793	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
2794	struct wm_adsp *dsp = &dsps[w->shift];
2795	struct wm_coeff_ctl *ctl;
2796	int ret;
2797	unsigned int val;
 
 
2798
2799	dsp->component = component;
2800
2801	mutex_lock(&dsp->pwr_lock);
2802
2803	switch (event) {
2804	case SND_SOC_DAPM_POST_PMU:
2805		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2806				   ADSP1_SYS_ENA, ADSP1_SYS_ENA);
2807
2808		/*
2809		 * For simplicity set the DSP clock rate to be the
2810		 * SYSCLK rate rather than making it configurable.
2811		 */
2812		if (dsp->sysclk_reg) {
2813			ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
2814			if (ret != 0) {
2815				adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
2816				ret);
2817				goto err_mutex;
2818			}
2819
2820			val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift;
2821
2822			ret = regmap_update_bits(dsp->regmap,
2823						 dsp->base + ADSP1_CONTROL_31,
2824						 ADSP1_CLK_SEL_MASK, val);
2825			if (ret != 0) {
2826				adsp_err(dsp, "Failed to set clock rate: %d\n",
2827					 ret);
2828				goto err_mutex;
2829			}
2830		}
2831
2832		ret = wm_adsp_load(dsp);
2833		if (ret != 0)
2834			goto err_ena;
2835
2836		ret = wm_adsp1_setup_algs(dsp);
2837		if (ret != 0)
2838			goto err_ena;
2839
2840		ret = wm_adsp_load_coeff(dsp);
2841		if (ret != 0)
2842			goto err_ena;
2843
2844		/* Initialize caches for enabled and unset controls */
2845		ret = wm_coeff_init_control_caches(dsp);
2846		if (ret != 0)
2847			goto err_ena;
2848
2849		/* Sync set controls */
2850		ret = wm_coeff_sync_controls(dsp);
2851		if (ret != 0)
2852			goto err_ena;
2853
2854		dsp->booted = true;
2855
2856		/* Start the core running */
2857		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2858				   ADSP1_CORE_ENA | ADSP1_START,
2859				   ADSP1_CORE_ENA | ADSP1_START);
2860
2861		dsp->running = true;
 
 
 
 
 
 
 
2862		break;
2863
2864	case SND_SOC_DAPM_PRE_PMD:
2865		dsp->running = false;
2866		dsp->booted = false;
2867
2868		/* Halt the core */
2869		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2870				   ADSP1_CORE_ENA | ADSP1_START, 0);
2871
2872		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
2873				   ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
2874
2875		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2876				   ADSP1_SYS_ENA, 0);
2877
2878		list_for_each_entry(ctl, &dsp->ctl_list, list)
2879			ctl->enabled = 0;
2880
2881
2882		wm_adsp_free_alg_regions(dsp);
2883		break;
2884
2885	default:
2886		break;
2887	}
2888
2889	mutex_unlock(&dsp->pwr_lock);
2890
2891	return 0;
2892
2893err_ena:
2894	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2895			   ADSP1_SYS_ENA, 0);
2896err_mutex:
2897	mutex_unlock(&dsp->pwr_lock);
2898
2899	return ret;
2900}
2901EXPORT_SYMBOL_GPL(wm_adsp1_event);
2902
2903static int wm_adsp2v2_enable_core(struct wm_adsp *dsp)
2904{
2905	unsigned int val;
2906	int ret, count;
2907
2908	/* Wait for the RAM to start, should be near instantaneous */
2909	for (count = 0; count < 10; ++count) {
2910		ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
2911		if (ret != 0)
2912			return ret;
2913
2914		if (val & ADSP2_RAM_RDY)
2915			break;
2916
2917		usleep_range(250, 500);
2918	}
2919
2920	if (!(val & ADSP2_RAM_RDY)) {
2921		adsp_err(dsp, "Failed to start DSP RAM\n");
2922		return -EBUSY;
2923	}
2924
2925	adsp_dbg(dsp, "RAM ready after %d polls\n", count);
2926
2927	return 0;
2928}
2929
2930static int wm_adsp2_enable_core(struct wm_adsp *dsp)
2931{
2932	int ret;
2933
2934	ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
2935				       ADSP2_SYS_ENA, ADSP2_SYS_ENA);
2936	if (ret != 0)
2937		return ret;
2938
2939	return wm_adsp2v2_enable_core(dsp);
2940}
2941
2942static int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
2943{
2944	struct regmap *regmap = dsp->regmap;
2945	unsigned int code0, code1, lock_reg;
2946
2947	if (!(lock_regions & WM_ADSP2_REGION_ALL))
2948		return 0;
2949
2950	lock_regions &= WM_ADSP2_REGION_ALL;
2951	lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0;
2952
2953	while (lock_regions) {
2954		code0 = code1 = 0;
2955		if (lock_regions & BIT(0)) {
2956			code0 = ADSP2_LOCK_CODE_0;
2957			code1 = ADSP2_LOCK_CODE_1;
2958		}
2959		if (lock_regions & BIT(1)) {
2960			code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT;
2961			code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT;
2962		}
2963		regmap_write(regmap, lock_reg, code0);
2964		regmap_write(regmap, lock_reg, code1);
2965		lock_regions >>= 2;
2966		lock_reg += 2;
2967	}
2968
2969	return 0;
2970}
2971
2972static int wm_adsp2_enable_memory(struct wm_adsp *dsp)
2973{
2974	return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2975				  ADSP2_MEM_ENA, ADSP2_MEM_ENA);
2976}
2977
2978static void wm_adsp2_disable_memory(struct wm_adsp *dsp)
2979{
2980	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2981			   ADSP2_MEM_ENA, 0);
2982}
2983
2984static void wm_adsp2_disable_core(struct wm_adsp *dsp)
2985{
2986	regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
2987	regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
2988	regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
2989
2990	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2991			   ADSP2_SYS_ENA, 0);
2992}
2993
2994static void wm_adsp2v2_disable_core(struct wm_adsp *dsp)
2995{
2996	regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
2997	regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
2998	regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
2999}
3000
3001static void wm_adsp_boot_work(struct work_struct *work)
3002{
3003	struct wm_adsp *dsp = container_of(work,
3004					   struct wm_adsp,
3005					   boot_work);
3006	int ret;
3007
3008	mutex_lock(&dsp->pwr_lock);
3009
3010	if (dsp->ops->enable_memory) {
3011		ret = dsp->ops->enable_memory(dsp);
3012		if (ret != 0)
3013			goto err_mutex;
3014	}
3015
3016	if (dsp->ops->enable_core) {
3017		ret = dsp->ops->enable_core(dsp);
3018		if (ret != 0)
3019			goto err_mem;
3020	}
3021
3022	ret = wm_adsp_load(dsp);
3023	if (ret != 0)
3024		goto err_ena;
3025
3026	ret = dsp->ops->setup_algs(dsp);
3027	if (ret != 0)
3028		goto err_ena;
3029
3030	ret = wm_adsp_load_coeff(dsp);
3031	if (ret != 0)
3032		goto err_ena;
3033
3034	/* Initialize caches for enabled and unset controls */
3035	ret = wm_coeff_init_control_caches(dsp);
3036	if (ret != 0)
3037		goto err_ena;
3038
3039	if (dsp->ops->disable_core)
3040		dsp->ops->disable_core(dsp);
3041
3042	dsp->booted = true;
3043
3044	mutex_unlock(&dsp->pwr_lock);
3045
3046	return;
3047
3048err_ena:
3049	if (dsp->ops->disable_core)
3050		dsp->ops->disable_core(dsp);
3051err_mem:
3052	if (dsp->ops->disable_memory)
3053		dsp->ops->disable_memory(dsp);
3054err_mutex:
3055	mutex_unlock(&dsp->pwr_lock);
3056}
3057
3058static int wm_halo_configure_mpu(struct wm_adsp *dsp, unsigned int lock_regions)
3059{
3060	struct reg_sequence config[] = {
3061		{ dsp->base + HALO_MPU_LOCK_CONFIG,     0x5555 },
3062		{ dsp->base + HALO_MPU_LOCK_CONFIG,     0xAAAA },
3063		{ dsp->base + HALO_MPU_XMEM_ACCESS_0,   0xFFFFFFFF },
3064		{ dsp->base + HALO_MPU_YMEM_ACCESS_0,   0xFFFFFFFF },
3065		{ dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions },
3066		{ dsp->base + HALO_MPU_XREG_ACCESS_0,   lock_regions },
3067		{ dsp->base + HALO_MPU_YREG_ACCESS_0,   lock_regions },
3068		{ dsp->base + HALO_MPU_XMEM_ACCESS_1,   0xFFFFFFFF },
3069		{ dsp->base + HALO_MPU_YMEM_ACCESS_1,   0xFFFFFFFF },
3070		{ dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions },
3071		{ dsp->base + HALO_MPU_XREG_ACCESS_1,   lock_regions },
3072		{ dsp->base + HALO_MPU_YREG_ACCESS_1,   lock_regions },
3073		{ dsp->base + HALO_MPU_XMEM_ACCESS_2,   0xFFFFFFFF },
3074		{ dsp->base + HALO_MPU_YMEM_ACCESS_2,   0xFFFFFFFF },
3075		{ dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions },
3076		{ dsp->base + HALO_MPU_XREG_ACCESS_2,   lock_regions },
3077		{ dsp->base + HALO_MPU_YREG_ACCESS_2,   lock_regions },
3078		{ dsp->base + HALO_MPU_XMEM_ACCESS_3,   0xFFFFFFFF },
3079		{ dsp->base + HALO_MPU_YMEM_ACCESS_3,   0xFFFFFFFF },
3080		{ dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions },
3081		{ dsp->base + HALO_MPU_XREG_ACCESS_3,   lock_regions },
3082		{ dsp->base + HALO_MPU_YREG_ACCESS_3,   lock_regions },
3083		{ dsp->base + HALO_MPU_LOCK_CONFIG,     0 },
3084	};
3085
3086	return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config));
3087}
3088
3089int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq)
3090{
3091	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3092	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3093	struct wm_adsp *dsp = &dsps[w->shift];
3094	int ret;
3095
3096	ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING,
3097				 ADSP2_CLK_SEL_MASK,
3098				 freq << ADSP2_CLK_SEL_SHIFT);
3099	if (ret)
3100		adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
3101
3102	return ret;
3103}
3104EXPORT_SYMBOL_GPL(wm_adsp2_set_dspclk);
3105
3106int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
3107			   struct snd_ctl_elem_value *ucontrol)
3108{
3109	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
3110	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3111	struct soc_mixer_control *mc =
3112		(struct soc_mixer_control *)kcontrol->private_value;
3113	struct wm_adsp *dsp = &dsps[mc->shift - 1];
3114
3115	ucontrol->value.integer.value[0] = dsp->preloaded;
3116
3117	return 0;
3118}
3119EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get);
3120
3121int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
3122			   struct snd_ctl_elem_value *ucontrol)
3123{
3124	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
3125	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3126	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
3127	struct soc_mixer_control *mc =
3128		(struct soc_mixer_control *)kcontrol->private_value;
3129	struct wm_adsp *dsp = &dsps[mc->shift - 1];
3130	char preload[32];
3131
3132	snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
 
3133
3134	dsp->preloaded = ucontrol->value.integer.value[0];
3135
3136	if (ucontrol->value.integer.value[0])
3137		snd_soc_component_force_enable_pin(component, preload);
3138	else
3139		snd_soc_component_disable_pin(component, preload);
3140
3141	snd_soc_dapm_sync(dapm);
3142
3143	flush_work(&dsp->boot_work);
3144
3145	return 0;
 
 
 
 
 
 
 
3146}
3147EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
3148
3149static void wm_adsp_stop_watchdog(struct wm_adsp *dsp)
3150{
3151	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
3152			   ADSP2_WDT_ENA_MASK, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3153}
 
3154
3155static void wm_halo_stop_watchdog(struct wm_adsp *dsp)
3156{
3157	regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL,
3158			   HALO_WDT_EN_MASK, 0);
 
 
 
3159}
3160
3161int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
3162			struct snd_kcontrol *kcontrol, int event)
3163{
3164	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3165	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3166	struct wm_adsp *dsp = &dsps[w->shift];
3167	struct wm_coeff_ctl *ctl;
3168
3169	switch (event) {
3170	case SND_SOC_DAPM_PRE_PMU:
3171		queue_work(system_unbound_wq, &dsp->boot_work);
3172		break;
3173	case SND_SOC_DAPM_PRE_PMD:
3174		mutex_lock(&dsp->pwr_lock);
 
 
 
 
 
 
 
 
3175
3176		wm_adsp_debugfs_clear(dsp);
 
 
3177
3178		dsp->fw_id = 0;
3179		dsp->fw_id_version = 0;
3180
3181		dsp->booted = false;
 
3182
3183		if (dsp->ops->disable_memory)
3184			dsp->ops->disable_memory(dsp);
 
3185
3186		list_for_each_entry(ctl, &dsp->ctl_list, list)
3187			ctl->enabled = 0;
3188
3189		wm_adsp_free_alg_regions(dsp);
 
3190
3191		mutex_unlock(&dsp->pwr_lock);
 
 
3192
3193		adsp_dbg(dsp, "Shutdown complete\n");
3194		break;
3195	default:
3196		break;
3197	}
3198
3199	return 0;
3200}
3201EXPORT_SYMBOL_GPL(wm_adsp_early_event);
3202
3203static int wm_adsp2_start_core(struct wm_adsp *dsp)
3204{
3205	return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3206				 ADSP2_CORE_ENA | ADSP2_START,
3207				 ADSP2_CORE_ENA | ADSP2_START);
3208}
 
3209
3210static void wm_adsp2_stop_core(struct wm_adsp *dsp)
3211{
3212	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3213			   ADSP2_CORE_ENA | ADSP2_START, 0);
3214}
 
3215
3216int wm_adsp_event(struct snd_soc_dapm_widget *w,
3217		  struct snd_kcontrol *kcontrol, int event)
3218{
3219	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3220	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3221	struct wm_adsp *dsp = &dsps[w->shift];
3222	int ret;
3223
3224	switch (event) {
3225	case SND_SOC_DAPM_POST_PMU:
3226		flush_work(&dsp->boot_work);
3227
3228		mutex_lock(&dsp->pwr_lock);
3229
3230		if (!dsp->booted) {
3231			ret = -EIO;
3232			goto err;
3233		}
3234
3235		if (dsp->ops->enable_core) {
3236			ret = dsp->ops->enable_core(dsp);
3237			if (ret != 0)
3238				goto err;
3239		}
3240
3241		/* Sync set controls */
3242		ret = wm_coeff_sync_controls(dsp);
3243		if (ret != 0)
3244			goto err;
3245
3246		if (dsp->ops->lock_memory) {
3247			ret = dsp->ops->lock_memory(dsp, dsp->lock_regions);
3248			if (ret != 0) {
3249				adsp_err(dsp, "Error configuring MPU: %d\n",
3250					 ret);
3251				goto err;
3252			}
3253		}
3254
3255		if (dsp->ops->start_core) {
3256			ret = dsp->ops->start_core(dsp);
3257			if (ret != 0)
3258				goto err;
3259		}
3260
3261		if (wm_adsp_fw[dsp->fw].num_caps != 0) {
3262			ret = wm_adsp_buffer_init(dsp);
3263			if (ret < 0)
3264				goto err;
3265		}
3266
3267		dsp->running = true;
3268
3269		mutex_unlock(&dsp->pwr_lock);
3270		break;
3271
3272	case SND_SOC_DAPM_PRE_PMD:
3273		/* Tell the firmware to cleanup */
3274		wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN);
3275
3276		if (dsp->ops->stop_watchdog)
3277			dsp->ops->stop_watchdog(dsp);
3278
3279		/* Log firmware state, it can be useful for analysis */
3280		if (dsp->ops->show_fw_status)
3281			dsp->ops->show_fw_status(dsp);
3282
3283		mutex_lock(&dsp->pwr_lock);
3284
3285		dsp->running = false;
3286
3287		if (dsp->ops->stop_core)
3288			dsp->ops->stop_core(dsp);
3289		if (dsp->ops->disable_core)
3290			dsp->ops->disable_core(dsp);
3291
3292		if (wm_adsp_fw[dsp->fw].num_caps != 0)
3293			wm_adsp_buffer_free(dsp);
3294
3295		dsp->fatal_error = false;
3296
3297		mutex_unlock(&dsp->pwr_lock);
3298
3299		adsp_dbg(dsp, "Execution stopped\n");
3300		break;
3301
3302	default:
3303		break;
3304	}
3305
3306	return 0;
3307err:
3308	if (dsp->ops->stop_core)
3309		dsp->ops->stop_core(dsp);
3310	if (dsp->ops->disable_core)
3311		dsp->ops->disable_core(dsp);
3312	mutex_unlock(&dsp->pwr_lock);
3313	return ret;
3314}
3315EXPORT_SYMBOL_GPL(wm_adsp_event);
3316
3317static int wm_halo_start_core(struct wm_adsp *dsp)
3318{
3319	return regmap_update_bits(dsp->regmap,
3320				  dsp->base + HALO_CCM_CORE_CONTROL,
3321				  HALO_CORE_EN, HALO_CORE_EN);
3322}
3323
3324static void wm_halo_stop_core(struct wm_adsp *dsp)
3325{
3326	regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
3327			   HALO_CORE_EN, 0);
3328
3329	/* reset halo core with CORE_SOFT_RESET */
3330	regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET,
3331			   HALO_CORE_SOFT_RESET_MASK, 1);
3332}
3333
3334int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
3335{
3336	char preload[32];
3337
3338	snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
3339	snd_soc_component_disable_pin(component, preload);
 
 
3340
3341	wm_adsp2_init_debugfs(dsp, component);
3342
3343	dsp->component = component;
3344
3345	return 0;
3346}
3347EXPORT_SYMBOL_GPL(wm_adsp2_component_probe);
3348
3349int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component)
3350{
3351	wm_adsp2_cleanup_debugfs(dsp);
3352
3353	return 0;
3354}
3355EXPORT_SYMBOL_GPL(wm_adsp2_component_remove);
3356
3357int wm_adsp2_init(struct wm_adsp *dsp)
3358{
3359	int ret;
3360
3361	ret = wm_adsp_common_init(dsp);
 
 
 
 
 
3362	if (ret)
3363		return ret;
3364
3365	switch (dsp->rev) {
3366	case 0:
3367		/*
3368		 * Disable the DSP memory by default when in reset for a small
3369		 * power saving.
3370		 */
3371		ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3372					 ADSP2_MEM_ENA, 0);
3373		if (ret) {
3374			adsp_err(dsp,
3375				 "Failed to clear memory retention: %d\n", ret);
3376			return ret;
3377		}
3378
3379		dsp->ops = &wm_adsp2_ops[0];
3380		break;
3381	case 1:
3382		dsp->ops = &wm_adsp2_ops[1];
3383		break;
3384	default:
3385		dsp->ops = &wm_adsp2_ops[2];
3386		break;
3387	}
3388
3389	INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
3390
3391	return 0;
3392}
3393EXPORT_SYMBOL_GPL(wm_adsp2_init);
3394
3395int wm_halo_init(struct wm_adsp *dsp)
3396{
3397	int ret;
3398
3399	ret = wm_adsp_common_init(dsp);
 
 
 
 
 
3400	if (ret)
3401		return ret;
3402
3403	dsp->ops = &wm_halo_ops;
3404
3405	INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
3406
3407	return 0;
3408}
3409EXPORT_SYMBOL_GPL(wm_halo_init);
3410
3411void wm_adsp2_remove(struct wm_adsp *dsp)
3412{
3413	struct wm_coeff_ctl *ctl;
3414
3415	while (!list_empty(&dsp->ctl_list)) {
3416		ctl = list_first_entry(&dsp->ctl_list, struct wm_coeff_ctl,
3417					list);
3418		list_del(&ctl->list);
3419		wm_adsp_free_ctl_blk(ctl);
3420	}
3421}
3422EXPORT_SYMBOL_GPL(wm_adsp2_remove);
3423
3424static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
3425{
3426	return compr->buf != NULL;
3427}
3428
3429static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
3430{
3431	struct wm_adsp_compr_buf *buf = NULL, *tmp;
3432
3433	if (compr->dsp->fatal_error)
3434		return -EINVAL;
3435
3436	list_for_each_entry(tmp, &compr->dsp->buffer_list, list) {
3437		if (!tmp->name || !strcmp(compr->name, tmp->name)) {
3438			buf = tmp;
3439			break;
3440		}
3441	}
3442
3443	if (!buf)
3444		return -EINVAL;
3445
3446	compr->buf = buf;
3447	buf->compr = compr;
3448
3449	return 0;
3450}
3451
3452static void wm_adsp_compr_detach(struct wm_adsp_compr *compr)
3453{
3454	if (!compr)
3455		return;
3456
3457	/* Wake the poll so it can see buffer is no longer attached */
3458	if (compr->stream)
3459		snd_compr_fragment_elapsed(compr->stream);
3460
3461	if (wm_adsp_compr_attached(compr)) {
3462		compr->buf->compr = NULL;
3463		compr->buf = NULL;
3464	}
3465}
3466
3467int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
3468{
3469	struct wm_adsp_compr *compr, *tmp;
3470	struct snd_soc_pcm_runtime *rtd = stream->private_data;
3471	int ret = 0;
3472
3473	mutex_lock(&dsp->pwr_lock);
3474
3475	if (wm_adsp_fw[dsp->fw].num_caps == 0) {
3476		adsp_err(dsp, "%s: Firmware does not support compressed API\n",
3477			 asoc_rtd_to_codec(rtd, 0)->name);
3478		ret = -ENXIO;
3479		goto out;
3480	}
3481
3482	if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
3483		adsp_err(dsp, "%s: Firmware does not support stream direction\n",
3484			 asoc_rtd_to_codec(rtd, 0)->name);
3485		ret = -EINVAL;
3486		goto out;
3487	}
3488
3489	list_for_each_entry(tmp, &dsp->compr_list, list) {
3490		if (!strcmp(tmp->name, asoc_rtd_to_codec(rtd, 0)->name)) {
3491			adsp_err(dsp, "%s: Only a single stream supported per dai\n",
3492				 asoc_rtd_to_codec(rtd, 0)->name);
3493			ret = -EBUSY;
3494			goto out;
3495		}
3496	}
3497
3498	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
3499	if (!compr) {
3500		ret = -ENOMEM;
3501		goto out;
3502	}
3503
3504	compr->dsp = dsp;
3505	compr->stream = stream;
3506	compr->name = asoc_rtd_to_codec(rtd, 0)->name;
3507
3508	list_add_tail(&compr->list, &dsp->compr_list);
3509
3510	stream->runtime->private_data = compr;
3511
3512out:
3513	mutex_unlock(&dsp->pwr_lock);
3514
3515	return ret;
3516}
3517EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
3518
3519int wm_adsp_compr_free(struct snd_soc_component *component,
3520		       struct snd_compr_stream *stream)
3521{
3522	struct wm_adsp_compr *compr = stream->runtime->private_data;
3523	struct wm_adsp *dsp = compr->dsp;
3524
3525	mutex_lock(&dsp->pwr_lock);
3526
3527	wm_adsp_compr_detach(compr);
3528	list_del(&compr->list);
3529
3530	kfree(compr->raw_buf);
3531	kfree(compr);
3532
3533	mutex_unlock(&dsp->pwr_lock);
3534
3535	return 0;
3536}
3537EXPORT_SYMBOL_GPL(wm_adsp_compr_free);
3538
3539static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
3540				      struct snd_compr_params *params)
3541{
3542	struct wm_adsp_compr *compr = stream->runtime->private_data;
3543	struct wm_adsp *dsp = compr->dsp;
3544	const struct wm_adsp_fw_caps *caps;
3545	const struct snd_codec_desc *desc;
3546	int i, j;
3547
3548	if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE ||
3549	    params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE ||
3550	    params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS ||
3551	    params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS ||
3552	    params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) {
3553		compr_err(compr, "Invalid buffer fragsize=%d fragments=%d\n",
3554			  params->buffer.fragment_size,
3555			  params->buffer.fragments);
3556
3557		return -EINVAL;
3558	}
3559
3560	for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) {
3561		caps = &wm_adsp_fw[dsp->fw].caps[i];
3562		desc = &caps->desc;
3563
3564		if (caps->id != params->codec.id)
3565			continue;
3566
3567		if (stream->direction == SND_COMPRESS_PLAYBACK) {
3568			if (desc->max_ch < params->codec.ch_out)
3569				continue;
3570		} else {
3571			if (desc->max_ch < params->codec.ch_in)
3572				continue;
3573		}
3574
3575		if (!(desc->formats & (1 << params->codec.format)))
3576			continue;
3577
3578		for (j = 0; j < desc->num_sample_rates; ++j)
3579			if (desc->sample_rates[j] == params->codec.sample_rate)
3580				return 0;
3581	}
3582
3583	compr_err(compr, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
3584		  params->codec.id, params->codec.ch_in, params->codec.ch_out,
3585		  params->codec.sample_rate, params->codec.format);
3586	return -EINVAL;
3587}
3588
3589static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr)
3590{
3591	return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE;
3592}
3593
3594int wm_adsp_compr_set_params(struct snd_soc_component *component,
3595			     struct snd_compr_stream *stream,
3596			     struct snd_compr_params *params)
3597{
3598	struct wm_adsp_compr *compr = stream->runtime->private_data;
3599	unsigned int size;
3600	int ret;
3601
3602	ret = wm_adsp_compr_check_params(stream, params);
3603	if (ret)
3604		return ret;
3605
3606	compr->size = params->buffer;
3607
3608	compr_dbg(compr, "fragment_size=%d fragments=%d\n",
3609		  compr->size.fragment_size, compr->size.fragments);
3610
3611	size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
3612	compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
3613	if (!compr->raw_buf)
3614		return -ENOMEM;
3615
3616	compr->sample_rate = params->codec.sample_rate;
3617
3618	return 0;
3619}
3620EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
3621
3622int wm_adsp_compr_get_caps(struct snd_soc_component *component,
3623			   struct snd_compr_stream *stream,
3624			   struct snd_compr_caps *caps)
3625{
3626	struct wm_adsp_compr *compr = stream->runtime->private_data;
3627	int fw = compr->dsp->fw;
3628	int i;
3629
3630	if (wm_adsp_fw[fw].caps) {
3631		for (i = 0; i < wm_adsp_fw[fw].num_caps; i++)
3632			caps->codecs[i] = wm_adsp_fw[fw].caps[i].id;
3633
3634		caps->num_codecs = i;
3635		caps->direction = wm_adsp_fw[fw].compr_direction;
3636
3637		caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE;
3638		caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE;
3639		caps->min_fragments = WM_ADSP_MIN_FRAGMENTS;
3640		caps->max_fragments = WM_ADSP_MAX_FRAGMENTS;
3641	}
3642
3643	return 0;
3644}
3645EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
3646
3647static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type,
3648				   unsigned int mem_addr,
3649				   unsigned int num_words, u32 *data)
3650{
3651	struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
3652	unsigned int i, reg;
3653	int ret;
3654
3655	if (!mem)
3656		return -EINVAL;
3657
3658	reg = dsp->ops->region_to_reg(mem, mem_addr);
3659
3660	ret = regmap_raw_read(dsp->regmap, reg, data,
3661			      sizeof(*data) * num_words);
3662	if (ret < 0)
3663		return ret;
3664
3665	for (i = 0; i < num_words; ++i)
3666		data[i] = be32_to_cpu(data[i]) & 0x00ffffffu;
3667
3668	return 0;
3669}
3670
3671static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type,
3672					 unsigned int mem_addr, u32 *data)
3673{
3674	return wm_adsp_read_data_block(dsp, mem_type, mem_addr, 1, data);
3675}
3676
3677static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type,
3678				   unsigned int mem_addr, u32 data)
3679{
3680	struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
3681	unsigned int reg;
3682
3683	if (!mem)
3684		return -EINVAL;
3685
3686	reg = dsp->ops->region_to_reg(mem, mem_addr);
3687
3688	data = cpu_to_be32(data & 0x00ffffffu);
3689
3690	return regmap_raw_write(dsp->regmap, reg, &data, sizeof(data));
3691}
3692
3693static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
3694				      unsigned int field_offset, u32 *data)
3695{
3696	return wm_adsp_read_data_word(buf->dsp, buf->host_buf_mem_type,
3697				      buf->host_buf_ptr + field_offset, data);
3698}
3699
3700static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
3701				       unsigned int field_offset, u32 data)
3702{
3703	return wm_adsp_write_data_word(buf->dsp, buf->host_buf_mem_type,
3704				       buf->host_buf_ptr + field_offset, data);
3705}
3706
3707static void wm_adsp_remove_padding(u32 *buf, int nwords, int data_word_size)
3708{
3709	u8 *pack_in = (u8 *)buf;
3710	u8 *pack_out = (u8 *)buf;
3711	int i, j;
3712
3713	/* Remove the padding bytes from the data read from the DSP */
3714	for (i = 0; i < nwords; i++) {
3715		for (j = 0; j < data_word_size; j++)
3716			*pack_out++ = *pack_in++;
3717
3718		pack_in += sizeof(*buf) - data_word_size;
3719	}
3720}
3721
3722static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
3723{
3724	const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
3725	struct wm_adsp_buffer_region *region;
3726	u32 offset = 0;
3727	int i, ret;
3728
3729	buf->regions = kcalloc(caps->num_regions, sizeof(*buf->regions),
3730			       GFP_KERNEL);
3731	if (!buf->regions)
3732		return -ENOMEM;
3733
3734	for (i = 0; i < caps->num_regions; ++i) {
3735		region = &buf->regions[i];
3736
3737		region->offset = offset;
3738		region->mem_type = caps->region_defs[i].mem_type;
3739
3740		ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
3741					  &region->base_addr);
3742		if (ret < 0)
3743			return ret;
3744
3745		ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
3746					  &offset);
3747		if (ret < 0)
3748			return ret;
3749
3750		region->cumulative_size = offset;
3751
3752		compr_dbg(buf,
3753			  "region=%d type=%d base=%08x off=%08x size=%08x\n",
3754			  i, region->mem_type, region->base_addr,
3755			  region->offset, region->cumulative_size);
3756	}
3757
3758	return 0;
 
 
 
 
3759}
3760
3761static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf)
3762{
3763	buf->irq_count = 0xFFFFFFFF;
3764	buf->read_index = -1;
3765	buf->avail = 0;
3766}
3767
3768static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp)
3769{
3770	struct wm_adsp_compr_buf *buf;
3771
3772	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
3773	if (!buf)
3774		return NULL;
3775
3776	buf->dsp = dsp;
3777
3778	wm_adsp_buffer_clear(buf);
3779
3780	list_add_tail(&buf->list, &dsp->buffer_list);
3781
3782	return buf;
3783}
3784
3785static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
3786{
3787	struct wm_adsp_alg_region *alg_region;
3788	struct wm_adsp_compr_buf *buf;
3789	u32 xmalg, addr, magic;
3790	int i, ret;
3791
3792	alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
3793	if (!alg_region) {
3794		adsp_err(dsp, "No algorithm region found\n");
3795		return -EINVAL;
3796	}
3797
3798	buf = wm_adsp_buffer_alloc(dsp);
3799	if (!buf)
3800		return -ENOMEM;
3801
3802	xmalg = dsp->ops->sys_config_size / sizeof(__be32);
3803
3804	addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
3805	ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic);
3806	if (ret < 0)
3807		return ret;
3808
3809	if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
3810		return -ENODEV;
3811
 
 
 
 
3812	addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
3813	for (i = 0; i < 5; ++i) {
3814		ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr,
3815					     &buf->host_buf_ptr);
3816		if (ret < 0)
3817			return ret;
3818
3819		if (buf->host_buf_ptr)
3820			break;
3821
3822		usleep_range(1000, 2000);
3823	}
3824
3825	if (!buf->host_buf_ptr)
3826		return -EIO;
 
 
3827
3828	buf->host_buf_mem_type = WMFW_ADSP2_XM;
3829
3830	ret = wm_adsp_buffer_populate(buf);
3831	if (ret < 0)
3832		return ret;
 
 
3833
3834	compr_dbg(buf, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr);
3835
3836	return 0;
 
 
 
 
 
3837}
3838
3839static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
3840{
3841	struct wm_adsp_host_buf_coeff_v1 coeff_v1;
3842	struct wm_adsp_compr_buf *buf;
3843	unsigned int val, reg;
 
3844	int ret, i;
3845
3846	ret = wm_coeff_base_reg(ctl, &reg);
3847	if (ret)
3848		return ret;
3849
3850	for (i = 0; i < 5; ++i) {
3851		ret = regmap_raw_read(ctl->dsp->regmap, reg, &val, sizeof(val));
 
3852		if (ret < 0)
3853			return ret;
3854
3855		if (val)
3856			break;
3857
3858		usleep_range(1000, 2000);
3859	}
3860
3861	if (!val) {
3862		adsp_err(ctl->dsp, "Failed to acquire host buffer\n");
3863		return -EIO;
3864	}
3865
3866	buf = wm_adsp_buffer_alloc(ctl->dsp);
3867	if (!buf)
3868		return -ENOMEM;
3869
3870	buf->host_buf_mem_type = ctl->alg_region.type;
3871	buf->host_buf_ptr = be32_to_cpu(val);
3872
3873	ret = wm_adsp_buffer_populate(buf);
3874	if (ret < 0)
3875		return ret;
3876
3877	/*
3878	 * v0 host_buffer coefficients didn't have versioning, so if the
3879	 * control is one word, assume version 0.
3880	 */
3881	if (ctl->len == 4) {
3882		compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr);
3883		return 0;
3884	}
3885
3886	ret = regmap_raw_read(ctl->dsp->regmap, reg, &coeff_v1,
3887			      sizeof(coeff_v1));
3888	if (ret < 0)
3889		return ret;
3890
3891	coeff_v1.versions = be32_to_cpu(coeff_v1.versions);
3892	val = coeff_v1.versions & HOST_BUF_COEFF_COMPAT_VER_MASK;
3893	val >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
3894
3895	if (val > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) {
3896		adsp_err(ctl->dsp,
3897			 "Host buffer coeff ver %u > supported version %u\n",
3898			 val, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
3899		return -EINVAL;
 
3900	}
3901
3902	for (i = 0; i < ARRAY_SIZE(coeff_v1.name); i++)
3903		coeff_v1.name[i] = be32_to_cpu(coeff_v1.name[i]);
3904
3905	wm_adsp_remove_padding((u32 *)&coeff_v1.name,
3906			       ARRAY_SIZE(coeff_v1.name),
3907			       WM_ADSP_DATA_WORD_SIZE);
3908
3909	buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part,
3910			      (char *)&coeff_v1.name);
3911
3912	compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n",
3913		  buf->host_buf_ptr, val);
 
 
3914
3915	return val;
 
 
 
3916}
3917
3918static int wm_adsp_buffer_init(struct wm_adsp *dsp)
3919{
3920	struct wm_coeff_ctl *ctl;
3921	int ret;
3922
3923	list_for_each_entry(ctl, &dsp->ctl_list, list) {
3924		if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
3925			continue;
3926
3927		if (!ctl->enabled)
3928			continue;
3929
3930		ret = wm_adsp_buffer_parse_coeff(ctl);
3931		if (ret < 0) {
3932			adsp_err(dsp, "Failed to parse coeff: %d\n", ret);
3933			goto error;
3934		} else if (ret == 0) {
3935			/* Only one buffer supported for version 0 */
3936			return 0;
3937		}
3938	}
3939
3940	if (list_empty(&dsp->buffer_list)) {
3941		/* Fall back to legacy support */
3942		ret = wm_adsp_buffer_parse_legacy(dsp);
3943		if (ret) {
3944			adsp_err(dsp, "Failed to parse legacy: %d\n", ret);
3945			goto error;
3946		}
3947	}
3948
3949	return 0;
3950
3951error:
3952	wm_adsp_buffer_free(dsp);
3953	return ret;
3954}
3955
3956static int wm_adsp_buffer_free(struct wm_adsp *dsp)
3957{
3958	struct wm_adsp_compr_buf *buf, *tmp;
3959
3960	list_for_each_entry_safe(buf, tmp, &dsp->buffer_list, list) {
3961		wm_adsp_compr_detach(buf->compr);
3962
3963		kfree(buf->name);
3964		kfree(buf->regions);
3965		list_del(&buf->list);
3966		kfree(buf);
3967	}
3968
3969	return 0;
3970}
3971
3972static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf)
3973{
3974	int ret;
3975
3976	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
3977	if (ret < 0) {
3978		compr_err(buf, "Failed to check buffer error: %d\n", ret);
3979		return ret;
3980	}
3981	if (buf->error != 0) {
3982		compr_err(buf, "Buffer error occurred: %d\n", buf->error);
3983		return -EIO;
3984	}
3985
3986	return 0;
3987}
3988
3989int wm_adsp_compr_trigger(struct snd_soc_component *component,
3990			  struct snd_compr_stream *stream, int cmd)
3991{
3992	struct wm_adsp_compr *compr = stream->runtime->private_data;
3993	struct wm_adsp *dsp = compr->dsp;
3994	int ret = 0;
3995
3996	compr_dbg(compr, "Trigger: %d\n", cmd);
3997
3998	mutex_lock(&dsp->pwr_lock);
3999
4000	switch (cmd) {
4001	case SNDRV_PCM_TRIGGER_START:
4002		if (!wm_adsp_compr_attached(compr)) {
4003			ret = wm_adsp_compr_attach(compr);
4004			if (ret < 0) {
4005				compr_err(compr, "Failed to link buffer and stream: %d\n",
4006					  ret);
4007				break;
4008			}
4009		}
4010
4011		ret = wm_adsp_buffer_get_error(compr->buf);
4012		if (ret < 0)
4013			break;
4014
4015		/* Trigger the IRQ at one fragment of data */
4016		ret = wm_adsp_buffer_write(compr->buf,
4017					   HOST_BUFFER_FIELD(high_water_mark),
4018					   wm_adsp_compr_frag_words(compr));
4019		if (ret < 0) {
4020			compr_err(compr, "Failed to set high water mark: %d\n",
4021				  ret);
4022			break;
4023		}
4024		break;
4025	case SNDRV_PCM_TRIGGER_STOP:
4026		if (wm_adsp_compr_attached(compr))
4027			wm_adsp_buffer_clear(compr->buf);
4028		break;
4029	default:
4030		ret = -EINVAL;
4031		break;
4032	}
4033
4034	mutex_unlock(&dsp->pwr_lock);
4035
4036	return ret;
4037}
4038EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
4039
4040static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf)
4041{
4042	int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1;
4043
4044	return buf->regions[last_region].cumulative_size;
4045}
4046
4047static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
4048{
4049	u32 next_read_index, next_write_index;
4050	int write_index, read_index, avail;
4051	int ret;
4052
4053	/* Only sync read index if we haven't already read a valid index */
4054	if (buf->read_index < 0) {
4055		ret = wm_adsp_buffer_read(buf,
4056				HOST_BUFFER_FIELD(next_read_index),
4057				&next_read_index);
4058		if (ret < 0)
4059			return ret;
4060
4061		read_index = sign_extend32(next_read_index, 23);
4062
4063		if (read_index < 0) {
4064			compr_dbg(buf, "Avail check on unstarted stream\n");
4065			return 0;
4066		}
4067
4068		buf->read_index = read_index;
4069	}
4070
4071	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index),
4072			&next_write_index);
4073	if (ret < 0)
4074		return ret;
4075
4076	write_index = sign_extend32(next_write_index, 23);
4077
4078	avail = write_index - buf->read_index;
4079	if (avail < 0)
4080		avail += wm_adsp_buffer_size(buf);
4081
4082	compr_dbg(buf, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
4083		  buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE);
4084
4085	buf->avail = avail;
4086
4087	return 0;
4088}
4089
4090int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
4091{
4092	struct wm_adsp_compr_buf *buf;
4093	struct wm_adsp_compr *compr;
4094	int ret = 0;
4095
4096	mutex_lock(&dsp->pwr_lock);
4097
4098	if (list_empty(&dsp->buffer_list)) {
4099		ret = -ENODEV;
4100		goto out;
4101	}
4102
4103	adsp_dbg(dsp, "Handling buffer IRQ\n");
4104
4105	list_for_each_entry(buf, &dsp->buffer_list, list) {
4106		compr = buf->compr;
4107
4108		ret = wm_adsp_buffer_get_error(buf);
4109		if (ret < 0)
4110			goto out_notify; /* Wake poll to report error */
4111
4112		ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
4113					  &buf->irq_count);
4114		if (ret < 0) {
4115			compr_err(buf, "Failed to get irq_count: %d\n", ret);
4116			goto out;
4117		}
4118
4119		ret = wm_adsp_buffer_update_avail(buf);
4120		if (ret < 0) {
4121			compr_err(buf, "Error reading avail: %d\n", ret);
4122			goto out;
4123		}
4124
4125		if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2)
4126			ret = WM_ADSP_COMPR_VOICE_TRIGGER;
4127
4128out_notify:
4129		if (compr && compr->stream)
4130			snd_compr_fragment_elapsed(compr->stream);
4131	}
4132
4133out:
4134	mutex_unlock(&dsp->pwr_lock);
4135
4136	return ret;
4137}
4138EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq);
4139
4140static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
4141{
4142	if (buf->irq_count & 0x01)
4143		return 0;
4144
4145	compr_dbg(buf, "Enable IRQ(0x%x) for next fragment\n", buf->irq_count);
4146
4147	buf->irq_count |= 0x01;
4148
4149	return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack),
4150				    buf->irq_count);
4151}
4152
4153int wm_adsp_compr_pointer(struct snd_soc_component *component,
4154			  struct snd_compr_stream *stream,
4155			  struct snd_compr_tstamp *tstamp)
4156{
4157	struct wm_adsp_compr *compr = stream->runtime->private_data;
4158	struct wm_adsp *dsp = compr->dsp;
4159	struct wm_adsp_compr_buf *buf;
4160	int ret = 0;
4161
4162	compr_dbg(compr, "Pointer request\n");
4163
4164	mutex_lock(&dsp->pwr_lock);
4165
4166	buf = compr->buf;
4167
4168	if (dsp->fatal_error || !buf || buf->error) {
4169		snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
4170		ret = -EIO;
4171		goto out;
4172	}
4173
4174	if (buf->avail < wm_adsp_compr_frag_words(compr)) {
4175		ret = wm_adsp_buffer_update_avail(buf);
4176		if (ret < 0) {
4177			compr_err(compr, "Error reading avail: %d\n", ret);
4178			goto out;
4179		}
4180
4181		/*
4182		 * If we really have less than 1 fragment available tell the
4183		 * DSP to inform us once a whole fragment is available.
4184		 */
4185		if (buf->avail < wm_adsp_compr_frag_words(compr)) {
4186			ret = wm_adsp_buffer_get_error(buf);
4187			if (ret < 0) {
4188				if (buf->error)
4189					snd_compr_stop_error(stream,
4190							SNDRV_PCM_STATE_XRUN);
4191				goto out;
4192			}
4193
4194			ret = wm_adsp_buffer_reenable_irq(buf);
4195			if (ret < 0) {
4196				compr_err(compr, "Failed to re-enable buffer IRQ: %d\n",
4197					  ret);
4198				goto out;
4199			}
4200		}
4201	}
4202
4203	tstamp->copied_total = compr->copied_total;
4204	tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE;
4205	tstamp->sampling_rate = compr->sample_rate;
4206
4207out:
4208	mutex_unlock(&dsp->pwr_lock);
4209
4210	return ret;
4211}
4212EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
4213
4214static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
4215{
4216	struct wm_adsp_compr_buf *buf = compr->buf;
4217	unsigned int adsp_addr;
4218	int mem_type, nwords, max_read;
4219	int i, ret;
4220
4221	/* Calculate read parameters */
4222	for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
4223		if (buf->read_index < buf->regions[i].cumulative_size)
4224			break;
4225
4226	if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions)
4227		return -EINVAL;
4228
4229	mem_type = buf->regions[i].mem_type;
4230	adsp_addr = buf->regions[i].base_addr +
4231		    (buf->read_index - buf->regions[i].offset);
4232
4233	max_read = wm_adsp_compr_frag_words(compr);
4234	nwords = buf->regions[i].cumulative_size - buf->read_index;
4235
4236	if (nwords > target)
4237		nwords = target;
4238	if (nwords > buf->avail)
4239		nwords = buf->avail;
4240	if (nwords > max_read)
4241		nwords = max_read;
4242	if (!nwords)
4243		return 0;
4244
4245	/* Read data from DSP */
4246	ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr,
4247				      nwords, compr->raw_buf);
4248	if (ret < 0)
4249		return ret;
4250
4251	wm_adsp_remove_padding(compr->raw_buf, nwords, WM_ADSP_DATA_WORD_SIZE);
4252
4253	/* update read index to account for words read */
4254	buf->read_index += nwords;
4255	if (buf->read_index == wm_adsp_buffer_size(buf))
4256		buf->read_index = 0;
4257
4258	ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index),
4259				   buf->read_index);
4260	if (ret < 0)
4261		return ret;
4262
4263	/* update avail to account for words read */
4264	buf->avail -= nwords;
4265
4266	return nwords;
4267}
4268
4269static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
4270			      char __user *buf, size_t count)
4271{
4272	struct wm_adsp *dsp = compr->dsp;
4273	int ntotal = 0;
4274	int nwords, nbytes;
4275
4276	compr_dbg(compr, "Requested read of %zu bytes\n", count);
4277
4278	if (dsp->fatal_error || !compr->buf || compr->buf->error) {
4279		snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
4280		return -EIO;
4281	}
4282
4283	count /= WM_ADSP_DATA_WORD_SIZE;
4284
4285	do {
4286		nwords = wm_adsp_buffer_capture_block(compr, count);
4287		if (nwords < 0) {
4288			compr_err(compr, "Failed to capture block: %d\n",
4289				  nwords);
4290			return nwords;
4291		}
4292
4293		nbytes = nwords * WM_ADSP_DATA_WORD_SIZE;
4294
4295		compr_dbg(compr, "Read %d bytes\n", nbytes);
4296
4297		if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
4298			compr_err(compr, "Failed to copy data to user: %d, %d\n",
4299				  ntotal, nbytes);
4300			return -EFAULT;
4301		}
4302
4303		count -= nwords;
4304		ntotal += nbytes;
4305	} while (nwords > 0 && count > 0);
4306
4307	compr->copied_total += ntotal;
4308
4309	return ntotal;
4310}
4311
4312int wm_adsp_compr_copy(struct snd_soc_component *component,
4313		       struct snd_compr_stream *stream, char __user *buf,
4314		       size_t count)
4315{
4316	struct wm_adsp_compr *compr = stream->runtime->private_data;
4317	struct wm_adsp *dsp = compr->dsp;
4318	int ret;
4319
4320	mutex_lock(&dsp->pwr_lock);
4321
4322	if (stream->direction == SND_COMPRESS_CAPTURE)
4323		ret = wm_adsp_compr_read(compr, buf, count);
4324	else
4325		ret = -ENOTSUPP;
4326
4327	mutex_unlock(&dsp->pwr_lock);
4328
4329	return ret;
4330}
4331EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
4332
4333static void wm_adsp_fatal_error(struct wm_adsp *dsp)
4334{
 
4335	struct wm_adsp_compr *compr;
4336
4337	dsp->fatal_error = true;
4338
4339	list_for_each_entry(compr, &dsp->compr_list, list) {
4340		if (compr->stream)
4341			snd_compr_fragment_elapsed(compr->stream);
4342	}
4343}
4344
4345irqreturn_t wm_adsp2_bus_error(int irq, void *data)
4346{
4347	struct wm_adsp *dsp = (struct wm_adsp *)data;
4348	unsigned int val;
4349	struct regmap *regmap = dsp->regmap;
4350	int ret = 0;
4351
4352	mutex_lock(&dsp->pwr_lock);
4353
4354	ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val);
4355	if (ret) {
4356		adsp_err(dsp,
4357			"Failed to read Region Lock Ctrl register: %d\n", ret);
4358		goto error;
4359	}
4360
4361	if (val & ADSP2_WDT_TIMEOUT_STS_MASK) {
4362		adsp_err(dsp, "watchdog timeout error\n");
4363		dsp->ops->stop_watchdog(dsp);
4364		wm_adsp_fatal_error(dsp);
4365	}
4366
4367	if (val & (ADSP2_SLAVE_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) {
4368		if (val & ADSP2_SLAVE_ERR_MASK)
4369			adsp_err(dsp, "bus error: slave error\n");
4370		else
4371			adsp_err(dsp, "bus error: region lock error\n");
4372
4373		ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val);
4374		if (ret) {
4375			adsp_err(dsp,
4376				 "Failed to read Bus Err Addr register: %d\n",
4377				 ret);
4378			goto error;
4379		}
4380
4381		adsp_err(dsp, "bus error address = 0x%x\n",
4382			 val & ADSP2_BUS_ERR_ADDR_MASK);
4383
4384		ret = regmap_read(regmap,
4385				  dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR,
4386				  &val);
4387		if (ret) {
4388			adsp_err(dsp,
4389				 "Failed to read Pmem Xmem Err Addr register: %d\n",
4390				 ret);
4391			goto error;
4392		}
4393
4394		adsp_err(dsp, "xmem error address = 0x%x\n",
4395			 val & ADSP2_XMEM_ERR_ADDR_MASK);
4396		adsp_err(dsp, "pmem error address = 0x%x\n",
4397			 (val & ADSP2_PMEM_ERR_ADDR_MASK) >>
4398			 ADSP2_PMEM_ERR_ADDR_SHIFT);
4399	}
4400
4401	regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL,
4402			   ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT);
4403
4404error:
4405	mutex_unlock(&dsp->pwr_lock);
4406
4407	return IRQ_HANDLED;
4408}
4409EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
4410
4411irqreturn_t wm_halo_bus_error(int irq, void *data)
4412{
4413	struct wm_adsp *dsp = (struct wm_adsp *)data;
4414	struct regmap *regmap = dsp->regmap;
4415	unsigned int fault[6];
4416	struct reg_sequence clear[] = {
4417		{ dsp->base + HALO_MPU_XM_VIO_STATUS,     0x0 },
4418		{ dsp->base + HALO_MPU_YM_VIO_STATUS,     0x0 },
4419		{ dsp->base + HALO_MPU_PM_VIO_STATUS,     0x0 },
4420	};
4421	int ret;
4422
4423	mutex_lock(&dsp->pwr_lock);
4424
4425	ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1,
4426			  fault);
4427	if (ret) {
4428		adsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret);
4429		goto exit_unlock;
4430	}
4431
4432	adsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n",
4433		  *fault & HALO_AHBM_FLAGS_ERR_MASK,
4434		  (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >>
4435		  HALO_AHBM_CORE_ERR_ADDR_SHIFT);
4436
4437	ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0,
4438			  fault);
4439	if (ret) {
4440		adsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret);
4441		goto exit_unlock;
4442	}
4443
4444	adsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault);
4445
4446	ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR,
4447			       fault, ARRAY_SIZE(fault));
4448	if (ret) {
4449		adsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret);
4450		goto exit_unlock;
4451	}
4452
4453	adsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]);
4454	adsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]);
4455	adsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]);
4456
4457	ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear));
4458	if (ret)
4459		adsp_warn(dsp, "Failed to clear MPU status: %d\n", ret);
4460
4461exit_unlock:
4462	mutex_unlock(&dsp->pwr_lock);
4463
4464	return IRQ_HANDLED;
4465}
4466EXPORT_SYMBOL_GPL(wm_halo_bus_error);
4467
4468irqreturn_t wm_halo_wdt_expire(int irq, void *data)
4469{
4470	struct wm_adsp *dsp = data;
4471
4472	mutex_lock(&dsp->pwr_lock);
4473
4474	adsp_warn(dsp, "WDT Expiry Fault\n");
4475	dsp->ops->stop_watchdog(dsp);
4476	wm_adsp_fatal_error(dsp);
4477
4478	mutex_unlock(&dsp->pwr_lock);
4479
4480	return IRQ_HANDLED;
4481}
4482EXPORT_SYMBOL_GPL(wm_halo_wdt_expire);
4483
4484static struct wm_adsp_ops wm_adsp1_ops = {
4485	.validate_version = wm_adsp_validate_version,
4486	.parse_sizes = wm_adsp1_parse_sizes,
4487	.region_to_reg = wm_adsp_region_to_reg,
4488};
4489
4490static struct wm_adsp_ops wm_adsp2_ops[] = {
4491	{
4492		.sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
4493		.parse_sizes = wm_adsp2_parse_sizes,
4494		.validate_version = wm_adsp_validate_version,
4495		.setup_algs = wm_adsp2_setup_algs,
4496		.region_to_reg = wm_adsp_region_to_reg,
4497
4498		.show_fw_status = wm_adsp2_show_fw_status,
4499
4500		.enable_memory = wm_adsp2_enable_memory,
4501		.disable_memory = wm_adsp2_disable_memory,
4502
4503		.enable_core = wm_adsp2_enable_core,
4504		.disable_core = wm_adsp2_disable_core,
4505
4506		.start_core = wm_adsp2_start_core,
4507		.stop_core = wm_adsp2_stop_core,
4508
4509	},
4510	{
4511		.sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
4512		.parse_sizes = wm_adsp2_parse_sizes,
4513		.validate_version = wm_adsp_validate_version,
4514		.setup_algs = wm_adsp2_setup_algs,
4515		.region_to_reg = wm_adsp_region_to_reg,
4516
4517		.show_fw_status = wm_adsp2v2_show_fw_status,
4518
4519		.enable_memory = wm_adsp2_enable_memory,
4520		.disable_memory = wm_adsp2_disable_memory,
4521		.lock_memory = wm_adsp2_lock,
4522
4523		.enable_core = wm_adsp2v2_enable_core,
4524		.disable_core = wm_adsp2v2_disable_core,
4525
4526		.start_core = wm_adsp2_start_core,
4527		.stop_core = wm_adsp2_stop_core,
4528	},
4529	{
4530		.sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
4531		.parse_sizes = wm_adsp2_parse_sizes,
4532		.validate_version = wm_adsp_validate_version,
4533		.setup_algs = wm_adsp2_setup_algs,
4534		.region_to_reg = wm_adsp_region_to_reg,
4535
4536		.show_fw_status = wm_adsp2v2_show_fw_status,
4537		.stop_watchdog = wm_adsp_stop_watchdog,
4538
4539		.enable_memory = wm_adsp2_enable_memory,
4540		.disable_memory = wm_adsp2_disable_memory,
4541		.lock_memory = wm_adsp2_lock,
4542
4543		.enable_core = wm_adsp2v2_enable_core,
4544		.disable_core = wm_adsp2v2_disable_core,
4545
4546		.start_core = wm_adsp2_start_core,
4547		.stop_core = wm_adsp2_stop_core,
4548	},
4549};
4550
4551static struct wm_adsp_ops wm_halo_ops = {
4552	.sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr),
4553	.parse_sizes = wm_adsp2_parse_sizes,
4554	.validate_version = wm_halo_validate_version,
4555	.setup_algs = wm_halo_setup_algs,
4556	.region_to_reg = wm_halo_region_to_reg,
4557
4558	.show_fw_status = wm_halo_show_fw_status,
4559	.stop_watchdog = wm_halo_stop_watchdog,
4560
4561	.lock_memory = wm_halo_configure_mpu,
4562
4563	.start_core = wm_halo_start_core,
4564	.stop_core = wm_halo_stop_core,
4565};
4566
 
4567MODULE_LICENSE("GPL v2");