Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.10.11.
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * cs_dsp.c  --  Cirrus Logic DSP firmware support
   4 *
   5 * Based on sound/soc/codecs/wm_adsp.c
   6 *
   7 * Copyright 2012 Wolfson Microelectronics plc
   8 * Copyright (C) 2015-2021 Cirrus Logic, Inc. and
   9 *                         Cirrus Logic International Semiconductor Ltd.
  10 */
  11
  12#include <linux/ctype.h>
  13#include <linux/debugfs.h>
  14#include <linux/delay.h>
  15#include <linux/module.h>
  16#include <linux/moduleparam.h>
  17#include <linux/seq_file.h>
  18#include <linux/slab.h>
  19#include <linux/vmalloc.h>
  20
  21#include <linux/firmware/cirrus/cs_dsp.h>
  22#include <linux/firmware/cirrus/wmfw.h>
  23
  24#define cs_dsp_err(_dsp, fmt, ...) \
  25	dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  26#define cs_dsp_warn(_dsp, fmt, ...) \
  27	dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  28#define cs_dsp_info(_dsp, fmt, ...) \
  29	dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  30#define cs_dsp_dbg(_dsp, fmt, ...) \
  31	dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
  32
  33#define ADSP1_CONTROL_1                   0x00
  34#define ADSP1_CONTROL_2                   0x02
  35#define ADSP1_CONTROL_3                   0x03
  36#define ADSP1_CONTROL_4                   0x04
  37#define ADSP1_CONTROL_5                   0x06
  38#define ADSP1_CONTROL_6                   0x07
  39#define ADSP1_CONTROL_7                   0x08
  40#define ADSP1_CONTROL_8                   0x09
  41#define ADSP1_CONTROL_9                   0x0A
  42#define ADSP1_CONTROL_10                  0x0B
  43#define ADSP1_CONTROL_11                  0x0C
  44#define ADSP1_CONTROL_12                  0x0D
  45#define ADSP1_CONTROL_13                  0x0F
  46#define ADSP1_CONTROL_14                  0x10
  47#define ADSP1_CONTROL_15                  0x11
  48#define ADSP1_CONTROL_16                  0x12
  49#define ADSP1_CONTROL_17                  0x13
  50#define ADSP1_CONTROL_18                  0x14
  51#define ADSP1_CONTROL_19                  0x16
  52#define ADSP1_CONTROL_20                  0x17
  53#define ADSP1_CONTROL_21                  0x18
  54#define ADSP1_CONTROL_22                  0x1A
  55#define ADSP1_CONTROL_23                  0x1B
  56#define ADSP1_CONTROL_24                  0x1C
  57#define ADSP1_CONTROL_25                  0x1E
  58#define ADSP1_CONTROL_26                  0x20
  59#define ADSP1_CONTROL_27                  0x21
  60#define ADSP1_CONTROL_28                  0x22
  61#define ADSP1_CONTROL_29                  0x23
  62#define ADSP1_CONTROL_30                  0x24
  63#define ADSP1_CONTROL_31                  0x26
  64
  65/*
  66 * ADSP1 Control 19
  67 */
  68#define ADSP1_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
  69#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
  70#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
  71
  72/*
  73 * ADSP1 Control 30
  74 */
  75#define ADSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
  76#define ADSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
  77#define ADSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
  78#define ADSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
  79#define ADSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
  80#define ADSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
  81#define ADSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
  82#define ADSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
  83#define ADSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
  84#define ADSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
  85#define ADSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
  86#define ADSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
  87#define ADSP1_START                       0x0001  /* DSP1_START */
  88#define ADSP1_START_MASK                  0x0001  /* DSP1_START */
  89#define ADSP1_START_SHIFT                      0  /* DSP1_START */
  90#define ADSP1_START_WIDTH                      1  /* DSP1_START */
  91
  92/*
  93 * ADSP1 Control 31
  94 */
  95#define ADSP1_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
  96#define ADSP1_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
  97#define ADSP1_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
  98
  99#define ADSP2_CONTROL                     0x0
 100#define ADSP2_CLOCKING                    0x1
 101#define ADSP2V2_CLOCKING                  0x2
 102#define ADSP2_STATUS1                     0x4
 103#define ADSP2_WDMA_CONFIG_1               0x30
 104#define ADSP2_WDMA_CONFIG_2               0x31
 105#define ADSP2V2_WDMA_CONFIG_2             0x32
 106#define ADSP2_RDMA_CONFIG_1               0x34
 107
 108#define ADSP2_SCRATCH0                    0x40
 109#define ADSP2_SCRATCH1                    0x41
 110#define ADSP2_SCRATCH2                    0x42
 111#define ADSP2_SCRATCH3                    0x43
 112
 113#define ADSP2V2_SCRATCH0_1                0x40
 114#define ADSP2V2_SCRATCH2_3                0x42
 115
 116/*
 117 * ADSP2 Control
 118 */
 119#define ADSP2_MEM_ENA                     0x0010  /* DSP1_MEM_ENA */
 120#define ADSP2_MEM_ENA_MASK                0x0010  /* DSP1_MEM_ENA */
 121#define ADSP2_MEM_ENA_SHIFT                    4  /* DSP1_MEM_ENA */
 122#define ADSP2_MEM_ENA_WIDTH                    1  /* DSP1_MEM_ENA */
 123#define ADSP2_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
 124#define ADSP2_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
 125#define ADSP2_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
 126#define ADSP2_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
 127#define ADSP2_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
 128#define ADSP2_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
 129#define ADSP2_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
 130#define ADSP2_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
 131#define ADSP2_START                       0x0001  /* DSP1_START */
 132#define ADSP2_START_MASK                  0x0001  /* DSP1_START */
 133#define ADSP2_START_SHIFT                      0  /* DSP1_START */
 134#define ADSP2_START_WIDTH                      1  /* DSP1_START */
 135
 136/*
 137 * ADSP2 clocking
 138 */
 139#define ADSP2_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
 140#define ADSP2_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
 141#define ADSP2_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
 142
 143/*
 144 * ADSP2V2 clocking
 145 */
 146#define ADSP2V2_CLK_SEL_MASK             0x70000  /* CLK_SEL_ENA */
 147#define ADSP2V2_CLK_SEL_SHIFT                 16  /* CLK_SEL_ENA */
 148#define ADSP2V2_CLK_SEL_WIDTH                  3  /* CLK_SEL_ENA */
 149
 150#define ADSP2V2_RATE_MASK                 0x7800  /* DSP_RATE */
 151#define ADSP2V2_RATE_SHIFT                    11  /* DSP_RATE */
 152#define ADSP2V2_RATE_WIDTH                     4  /* DSP_RATE */
 153
 154/*
 155 * ADSP2 Status 1
 156 */
 157#define ADSP2_RAM_RDY                     0x0001
 158#define ADSP2_RAM_RDY_MASK                0x0001
 159#define ADSP2_RAM_RDY_SHIFT                    0
 160#define ADSP2_RAM_RDY_WIDTH                    1
 161
 162/*
 163 * ADSP2 Lock support
 164 */
 165#define ADSP2_LOCK_CODE_0                    0x5555
 166#define ADSP2_LOCK_CODE_1                    0xAAAA
 167
 168#define ADSP2_WATCHDOG                       0x0A
 169#define ADSP2_BUS_ERR_ADDR                   0x52
 170#define ADSP2_REGION_LOCK_STATUS             0x64
 171#define ADSP2_LOCK_REGION_1_LOCK_REGION_0    0x66
 172#define ADSP2_LOCK_REGION_3_LOCK_REGION_2    0x68
 173#define ADSP2_LOCK_REGION_5_LOCK_REGION_4    0x6A
 174#define ADSP2_LOCK_REGION_7_LOCK_REGION_6    0x6C
 175#define ADSP2_LOCK_REGION_9_LOCK_REGION_8    0x6E
 176#define ADSP2_LOCK_REGION_CTRL               0x7A
 177#define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR    0x7C
 178
 179#define ADSP2_REGION_LOCK_ERR_MASK           0x8000
 180#define ADSP2_ADDR_ERR_MASK                  0x4000
 181#define ADSP2_WDT_TIMEOUT_STS_MASK           0x2000
 182#define ADSP2_CTRL_ERR_PAUSE_ENA             0x0002
 183#define ADSP2_CTRL_ERR_EINT                  0x0001
 184
 185#define ADSP2_BUS_ERR_ADDR_MASK              0x00FFFFFF
 186#define ADSP2_XMEM_ERR_ADDR_MASK             0x0000FFFF
 187#define ADSP2_PMEM_ERR_ADDR_MASK             0x7FFF0000
 188#define ADSP2_PMEM_ERR_ADDR_SHIFT            16
 189#define ADSP2_WDT_ENA_MASK                   0xFFFFFFFD
 190
 191#define ADSP2_LOCK_REGION_SHIFT              16
 192
 193/*
 194 * Event control messages
 195 */
 196#define CS_DSP_FW_EVENT_SHUTDOWN             0x000001
 197
 198/*
 199 * HALO system info
 200 */
 201#define HALO_AHBM_WINDOW_DEBUG_0             0x02040
 202#define HALO_AHBM_WINDOW_DEBUG_1             0x02044
 203
 204/*
 205 * HALO core
 206 */
 207#define HALO_SCRATCH1                        0x005c0
 208#define HALO_SCRATCH2                        0x005c8
 209#define HALO_SCRATCH3                        0x005d0
 210#define HALO_SCRATCH4                        0x005d8
 211#define HALO_CCM_CORE_CONTROL                0x41000
 212#define HALO_CORE_SOFT_RESET                 0x00010
 213#define HALO_WDT_CONTROL                     0x47000
 214
 215/*
 216 * HALO MPU banks
 217 */
 218#define HALO_MPU_XMEM_ACCESS_0               0x43000
 219#define HALO_MPU_YMEM_ACCESS_0               0x43004
 220#define HALO_MPU_WINDOW_ACCESS_0             0x43008
 221#define HALO_MPU_XREG_ACCESS_0               0x4300C
 222#define HALO_MPU_YREG_ACCESS_0               0x43014
 223#define HALO_MPU_XMEM_ACCESS_1               0x43018
 224#define HALO_MPU_YMEM_ACCESS_1               0x4301C
 225#define HALO_MPU_WINDOW_ACCESS_1             0x43020
 226#define HALO_MPU_XREG_ACCESS_1               0x43024
 227#define HALO_MPU_YREG_ACCESS_1               0x4302C
 228#define HALO_MPU_XMEM_ACCESS_2               0x43030
 229#define HALO_MPU_YMEM_ACCESS_2               0x43034
 230#define HALO_MPU_WINDOW_ACCESS_2             0x43038
 231#define HALO_MPU_XREG_ACCESS_2               0x4303C
 232#define HALO_MPU_YREG_ACCESS_2               0x43044
 233#define HALO_MPU_XMEM_ACCESS_3               0x43048
 234#define HALO_MPU_YMEM_ACCESS_3               0x4304C
 235#define HALO_MPU_WINDOW_ACCESS_3             0x43050
 236#define HALO_MPU_XREG_ACCESS_3               0x43054
 237#define HALO_MPU_YREG_ACCESS_3               0x4305C
 238#define HALO_MPU_XM_VIO_ADDR                 0x43100
 239#define HALO_MPU_XM_VIO_STATUS               0x43104
 240#define HALO_MPU_YM_VIO_ADDR                 0x43108
 241#define HALO_MPU_YM_VIO_STATUS               0x4310C
 242#define HALO_MPU_PM_VIO_ADDR                 0x43110
 243#define HALO_MPU_PM_VIO_STATUS               0x43114
 244#define HALO_MPU_LOCK_CONFIG                 0x43140
 245
 246/*
 247 * HALO_AHBM_WINDOW_DEBUG_1
 248 */
 249#define HALO_AHBM_CORE_ERR_ADDR_MASK         0x0fffff00
 250#define HALO_AHBM_CORE_ERR_ADDR_SHIFT                 8
 251#define HALO_AHBM_FLAGS_ERR_MASK             0x000000ff
 252
 253/*
 254 * HALO_CCM_CORE_CONTROL
 255 */
 256#define HALO_CORE_RESET                     0x00000200
 257#define HALO_CORE_EN                        0x00000001
 258
 259/*
 260 * HALO_CORE_SOFT_RESET
 261 */
 262#define HALO_CORE_SOFT_RESET_MASK           0x00000001
 263
 264/*
 265 * HALO_WDT_CONTROL
 266 */
 267#define HALO_WDT_EN_MASK                    0x00000001
 268
 269/*
 270 * HALO_MPU_?M_VIO_STATUS
 271 */
 272#define HALO_MPU_VIO_STS_MASK               0x007e0000
 273#define HALO_MPU_VIO_STS_SHIFT                      17
 274#define HALO_MPU_VIO_ERR_WR_MASK            0x00008000
 275#define HALO_MPU_VIO_ERR_SRC_MASK           0x00007fff
 276#define HALO_MPU_VIO_ERR_SRC_SHIFT                   0
 277
 278struct cs_dsp_ops {
 279	bool (*validate_version)(struct cs_dsp *dsp, unsigned int version);
 280	unsigned int (*parse_sizes)(struct cs_dsp *dsp,
 281				    const char * const file,
 282				    unsigned int pos,
 283				    const struct firmware *firmware);
 284	int (*setup_algs)(struct cs_dsp *dsp);
 285	unsigned int (*region_to_reg)(struct cs_dsp_region const *mem,
 286				      unsigned int offset);
 287
 288	void (*show_fw_status)(struct cs_dsp *dsp);
 289	void (*stop_watchdog)(struct cs_dsp *dsp);
 290
 291	int (*enable_memory)(struct cs_dsp *dsp);
 292	void (*disable_memory)(struct cs_dsp *dsp);
 293	int (*lock_memory)(struct cs_dsp *dsp, unsigned int lock_regions);
 294
 295	int (*enable_core)(struct cs_dsp *dsp);
 296	void (*disable_core)(struct cs_dsp *dsp);
 297
 298	int (*start_core)(struct cs_dsp *dsp);
 299	void (*stop_core)(struct cs_dsp *dsp);
 300};
 301
 302static const struct cs_dsp_ops cs_dsp_adsp1_ops;
 303static const struct cs_dsp_ops cs_dsp_adsp2_ops[];
 304static const struct cs_dsp_ops cs_dsp_halo_ops;
 305static const struct cs_dsp_ops cs_dsp_halo_ao_ops;
 306
 307struct cs_dsp_buf {
 308	struct list_head list;
 309	void *buf;
 310};
 311
 312static struct cs_dsp_buf *cs_dsp_buf_alloc(const void *src, size_t len,
 313					   struct list_head *list)
 314{
 315	struct cs_dsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
 316
 317	if (buf == NULL)
 318		return NULL;
 319
 320	buf->buf = vmalloc(len);
 321	if (!buf->buf) {
 322		kfree(buf);
 323		return NULL;
 324	}
 325	memcpy(buf->buf, src, len);
 326
 327	if (list)
 328		list_add_tail(&buf->list, list);
 329
 330	return buf;
 331}
 332
 333static void cs_dsp_buf_free(struct list_head *list)
 334{
 335	while (!list_empty(list)) {
 336		struct cs_dsp_buf *buf = list_first_entry(list,
 337							  struct cs_dsp_buf,
 338							  list);
 339		list_del(&buf->list);
 340		vfree(buf->buf);
 341		kfree(buf);
 342	}
 343}
 344
 345/**
 346 * cs_dsp_mem_region_name() - Return a name string for a memory type
 347 * @type: the memory type to match
 348 *
 349 * Return: A const string identifying the memory region.
 350 */
 351const char *cs_dsp_mem_region_name(unsigned int type)
 352{
 353	switch (type) {
 354	case WMFW_ADSP1_PM:
 355		return "PM";
 356	case WMFW_HALO_PM_PACKED:
 357		return "PM_PACKED";
 358	case WMFW_ADSP1_DM:
 359		return "DM";
 360	case WMFW_ADSP2_XM:
 361		return "XM";
 362	case WMFW_HALO_XM_PACKED:
 363		return "XM_PACKED";
 364	case WMFW_ADSP2_YM:
 365		return "YM";
 366	case WMFW_HALO_YM_PACKED:
 367		return "YM_PACKED";
 368	case WMFW_ADSP1_ZM:
 369		return "ZM";
 370	default:
 371		return NULL;
 372	}
 373}
 374EXPORT_SYMBOL_NS_GPL(cs_dsp_mem_region_name, FW_CS_DSP);
 375
 376#ifdef CONFIG_DEBUG_FS
 377static void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, const char *s)
 378{
 379	char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
 380
 381	kfree(dsp->wmfw_file_name);
 382	dsp->wmfw_file_name = tmp;
 383}
 384
 385static void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp, const char *s)
 386{
 387	char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
 388
 389	kfree(dsp->bin_file_name);
 390	dsp->bin_file_name = tmp;
 391}
 392
 393static void cs_dsp_debugfs_clear(struct cs_dsp *dsp)
 394{
 395	kfree(dsp->wmfw_file_name);
 396	kfree(dsp->bin_file_name);
 397	dsp->wmfw_file_name = NULL;
 398	dsp->bin_file_name = NULL;
 399}
 400
 401static ssize_t cs_dsp_debugfs_wmfw_read(struct file *file,
 402					char __user *user_buf,
 403					size_t count, loff_t *ppos)
 404{
 405	struct cs_dsp *dsp = file->private_data;
 406	ssize_t ret;
 407
 408	mutex_lock(&dsp->pwr_lock);
 409
 410	if (!dsp->wmfw_file_name || !dsp->booted)
 411		ret = 0;
 412	else
 413		ret = simple_read_from_buffer(user_buf, count, ppos,
 414					      dsp->wmfw_file_name,
 415					      strlen(dsp->wmfw_file_name));
 416
 417	mutex_unlock(&dsp->pwr_lock);
 418	return ret;
 419}
 420
 421static ssize_t cs_dsp_debugfs_bin_read(struct file *file,
 422				       char __user *user_buf,
 423				       size_t count, loff_t *ppos)
 424{
 425	struct cs_dsp *dsp = file->private_data;
 426	ssize_t ret;
 427
 428	mutex_lock(&dsp->pwr_lock);
 429
 430	if (!dsp->bin_file_name || !dsp->booted)
 431		ret = 0;
 432	else
 433		ret = simple_read_from_buffer(user_buf, count, ppos,
 434					      dsp->bin_file_name,
 435					      strlen(dsp->bin_file_name));
 436
 437	mutex_unlock(&dsp->pwr_lock);
 438	return ret;
 439}
 440
 441static const struct {
 442	const char *name;
 443	const struct file_operations fops;
 444} cs_dsp_debugfs_fops[] = {
 445	{
 446		.name = "wmfw_file_name",
 447		.fops = {
 448			.open = simple_open,
 449			.read = cs_dsp_debugfs_wmfw_read,
 450		},
 451	},
 452	{
 453		.name = "bin_file_name",
 454		.fops = {
 455			.open = simple_open,
 456			.read = cs_dsp_debugfs_bin_read,
 457		},
 458	},
 459};
 460
 461static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg,
 462				 unsigned int off);
 463
 464static int cs_dsp_debugfs_read_controls_show(struct seq_file *s, void *ignored)
 465{
 466	struct cs_dsp *dsp = s->private;
 467	struct cs_dsp_coeff_ctl *ctl;
 468	unsigned int reg;
 469
 470	list_for_each_entry(ctl, &dsp->ctl_list, list) {
 471		cs_dsp_coeff_base_reg(ctl, &reg, 0);
 472		seq_printf(s, "%22.*s: %#8zx %s:%08x %#8x %s %#8x %#4x %c%c%c%c %s %s\n",
 473			   ctl->subname_len, ctl->subname, ctl->len,
 474			   cs_dsp_mem_region_name(ctl->alg_region.type),
 475			   ctl->offset, reg, ctl->fw_name, ctl->alg_region.alg, ctl->type,
 476			   ctl->flags & WMFW_CTL_FLAG_VOLATILE ? 'V' : '-',
 477			   ctl->flags & WMFW_CTL_FLAG_SYS ? 'S' : '-',
 478			   ctl->flags & WMFW_CTL_FLAG_READABLE ? 'R' : '-',
 479			   ctl->flags & WMFW_CTL_FLAG_WRITEABLE ? 'W' : '-',
 480			   ctl->enabled ? "enabled" : "disabled",
 481			   ctl->set ? "dirty" : "clean");
 482	}
 483
 484	return 0;
 485}
 486DEFINE_SHOW_ATTRIBUTE(cs_dsp_debugfs_read_controls);
 487
 488/**
 489 * cs_dsp_init_debugfs() - Create and populate DSP representation in debugfs
 490 * @dsp: pointer to DSP structure
 491 * @debugfs_root: pointer to debugfs directory in which to create this DSP
 492 *                representation
 493 */
 494void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root)
 495{
 496	struct dentry *root = NULL;
 497	int i;
 498
 499	root = debugfs_create_dir(dsp->name, debugfs_root);
 500
 501	debugfs_create_bool("booted", 0444, root, &dsp->booted);
 502	debugfs_create_bool("running", 0444, root, &dsp->running);
 503	debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id);
 504	debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version);
 505
 506	for (i = 0; i < ARRAY_SIZE(cs_dsp_debugfs_fops); ++i)
 507		debugfs_create_file(cs_dsp_debugfs_fops[i].name, 0444, root,
 508				    dsp, &cs_dsp_debugfs_fops[i].fops);
 509
 510	debugfs_create_file("controls", 0444, root, dsp,
 511			    &cs_dsp_debugfs_read_controls_fops);
 512
 513	dsp->debugfs_root = root;
 514}
 515EXPORT_SYMBOL_NS_GPL(cs_dsp_init_debugfs, FW_CS_DSP);
 516
 517/**
 518 * cs_dsp_cleanup_debugfs() - Removes DSP representation from debugfs
 519 * @dsp: pointer to DSP structure
 520 */
 521void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
 522{
 523	cs_dsp_debugfs_clear(dsp);
 524	debugfs_remove_recursive(dsp->debugfs_root);
 525	dsp->debugfs_root = NULL;
 526}
 527EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, FW_CS_DSP);
 528#else
 529void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root)
 530{
 531}
 532EXPORT_SYMBOL_NS_GPL(cs_dsp_init_debugfs, FW_CS_DSP);
 533
 534void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
 535{
 536}
 537EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, FW_CS_DSP);
 538
 539static inline void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp,
 540						const char *s)
 541{
 542}
 543
 544static inline void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp,
 545					       const char *s)
 546{
 547}
 548
 549static inline void cs_dsp_debugfs_clear(struct cs_dsp *dsp)
 550{
 551}
 552#endif
 553
 554static const struct cs_dsp_region *cs_dsp_find_region(struct cs_dsp *dsp,
 555						      int type)
 556{
 557	int i;
 558
 559	for (i = 0; i < dsp->num_mems; i++)
 560		if (dsp->mem[i].type == type)
 561			return &dsp->mem[i];
 562
 563	return NULL;
 564}
 565
 566static unsigned int cs_dsp_region_to_reg(struct cs_dsp_region const *mem,
 567					 unsigned int offset)
 568{
 569	switch (mem->type) {
 570	case WMFW_ADSP1_PM:
 571		return mem->base + (offset * 3);
 572	case WMFW_ADSP1_DM:
 573	case WMFW_ADSP2_XM:
 574	case WMFW_ADSP2_YM:
 575	case WMFW_ADSP1_ZM:
 576		return mem->base + (offset * 2);
 577	default:
 578		WARN(1, "Unknown memory region type");
 579		return offset;
 580	}
 581}
 582
 583static unsigned int cs_dsp_halo_region_to_reg(struct cs_dsp_region const *mem,
 584					      unsigned int offset)
 585{
 586	switch (mem->type) {
 587	case WMFW_ADSP2_XM:
 588	case WMFW_ADSP2_YM:
 589		return mem->base + (offset * 4);
 590	case WMFW_HALO_XM_PACKED:
 591	case WMFW_HALO_YM_PACKED:
 592		return (mem->base + (offset * 3)) & ~0x3;
 593	case WMFW_HALO_PM_PACKED:
 594		return mem->base + (offset * 5);
 595	default:
 596		WARN(1, "Unknown memory region type");
 597		return offset;
 598	}
 599}
 600
 601static void cs_dsp_read_fw_status(struct cs_dsp *dsp,
 602				  int noffs, unsigned int *offs)
 603{
 604	unsigned int i;
 605	int ret;
 606
 607	for (i = 0; i < noffs; ++i) {
 608		ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]);
 609		if (ret) {
 610			cs_dsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret);
 611			return;
 612		}
 613	}
 614}
 615
 616static void cs_dsp_adsp2_show_fw_status(struct cs_dsp *dsp)
 617{
 618	unsigned int offs[] = {
 619		ADSP2_SCRATCH0, ADSP2_SCRATCH1, ADSP2_SCRATCH2, ADSP2_SCRATCH3,
 620	};
 621
 622	cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
 623
 624	cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
 625		   offs[0], offs[1], offs[2], offs[3]);
 626}
 627
 628static void cs_dsp_adsp2v2_show_fw_status(struct cs_dsp *dsp)
 629{
 630	unsigned int offs[] = { ADSP2V2_SCRATCH0_1, ADSP2V2_SCRATCH2_3 };
 631
 632	cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
 633
 634	cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
 635		   offs[0] & 0xFFFF, offs[0] >> 16,
 636		   offs[1] & 0xFFFF, offs[1] >> 16);
 637}
 638
 639static void cs_dsp_halo_show_fw_status(struct cs_dsp *dsp)
 640{
 641	unsigned int offs[] = {
 642		HALO_SCRATCH1, HALO_SCRATCH2, HALO_SCRATCH3, HALO_SCRATCH4,
 643	};
 644
 645	cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
 646
 647	cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
 648		   offs[0], offs[1], offs[2], offs[3]);
 649}
 650
 651static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg,
 652				 unsigned int off)
 653{
 654	const struct cs_dsp_alg_region *alg_region = &ctl->alg_region;
 655	struct cs_dsp *dsp = ctl->dsp;
 656	const struct cs_dsp_region *mem;
 657
 658	mem = cs_dsp_find_region(dsp, alg_region->type);
 659	if (!mem) {
 660		cs_dsp_err(dsp, "No base for region %x\n",
 661			   alg_region->type);
 662		return -EINVAL;
 663	}
 664
 665	*reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset + off);
 666
 667	return 0;
 668}
 669
 670/**
 671 * cs_dsp_coeff_write_acked_control() - Sends event_id to the acked control
 672 * @ctl: pointer to acked coefficient control
 673 * @event_id: the value to write to the given acked control
 674 *
 675 * Once the value has been written to the control the function shall block
 676 * until the running firmware acknowledges the write or timeout is exceeded.
 677 *
 678 * Must be called with pwr_lock held.
 679 *
 680 * Return: Zero for success, a negative number on error.
 681 */
 682int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int event_id)
 683{
 684	struct cs_dsp *dsp = ctl->dsp;
 685	__be32 val = cpu_to_be32(event_id);
 686	unsigned int reg;
 687	int i, ret;
 688
 689	lockdep_assert_held(&dsp->pwr_lock);
 690
 691	if (!dsp->running)
 692		return -EPERM;
 693
 694	ret = cs_dsp_coeff_base_reg(ctl, &reg, 0);
 695	if (ret)
 696		return ret;
 697
 698	cs_dsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n",
 699		   event_id, ctl->alg_region.alg,
 700		   cs_dsp_mem_region_name(ctl->alg_region.type), ctl->offset);
 701
 702	ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
 703	if (ret) {
 704		cs_dsp_err(dsp, "Failed to write %x: %d\n", reg, ret);
 705		return ret;
 706	}
 707
 708	/*
 709	 * Poll for ack, we initially poll at ~1ms intervals for firmwares
 710	 * that respond quickly, then go to ~10ms polls. A firmware is unlikely
 711	 * to ack instantly so we do the first 1ms delay before reading the
 712	 * control to avoid a pointless bus transaction
 713	 */
 714	for (i = 0; i < CS_DSP_ACKED_CTL_TIMEOUT_MS;) {
 715		switch (i) {
 716		case 0 ... CS_DSP_ACKED_CTL_N_QUICKPOLLS - 1:
 717			usleep_range(1000, 2000);
 718			i++;
 719			break;
 720		default:
 721			usleep_range(10000, 20000);
 722			i += 10;
 723			break;
 724		}
 725
 726		ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
 727		if (ret) {
 728			cs_dsp_err(dsp, "Failed to read %x: %d\n", reg, ret);
 729			return ret;
 730		}
 731
 732		if (val == 0) {
 733			cs_dsp_dbg(dsp, "Acked control ACKED at poll %u\n", i);
 734			return 0;
 735		}
 736	}
 737
 738	cs_dsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n",
 739		    reg, ctl->alg_region.alg,
 740		    cs_dsp_mem_region_name(ctl->alg_region.type),
 741		    ctl->offset);
 742
 743	return -ETIMEDOUT;
 744}
 745EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_write_acked_control, FW_CS_DSP);
 746
 747static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
 748				       unsigned int off, const void *buf, size_t len)
 749{
 750	struct cs_dsp *dsp = ctl->dsp;
 751	void *scratch;
 752	int ret;
 753	unsigned int reg;
 754
 755	ret = cs_dsp_coeff_base_reg(ctl, &reg, off);
 756	if (ret)
 757		return ret;
 758
 759	scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);
 760	if (!scratch)
 761		return -ENOMEM;
 762
 763	ret = regmap_raw_write(dsp->regmap, reg, scratch,
 764			       len);
 765	if (ret) {
 766		cs_dsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
 767			   len, reg, ret);
 768		kfree(scratch);
 769		return ret;
 770	}
 771	cs_dsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg);
 772
 773	kfree(scratch);
 774
 775	return 0;
 776}
 777
 778/**
 779 * cs_dsp_coeff_write_ctrl() - Writes the given buffer to the given coefficient control
 780 * @ctl: pointer to coefficient control
 781 * @off: word offset at which data should be written
 782 * @buf: the buffer to write to the given control
 783 * @len: the length of the buffer in bytes
 784 *
 785 * Must be called with pwr_lock held.
 786 *
 787 * Return: < 0 on error, 1 when the control value changed and 0 when it has not.
 788 */
 789int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl,
 790			    unsigned int off, const void *buf, size_t len)
 791{
 792	int ret = 0;
 793
 794	if (!ctl)
 795		return -ENOENT;
 796
 797	lockdep_assert_held(&ctl->dsp->pwr_lock);
 798
 799	if (len + off * sizeof(u32) > ctl->len)
 800		return -EINVAL;
 801
 802	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
 803		ret = -EPERM;
 804	} else if (buf != ctl->cache) {
 805		if (memcmp(ctl->cache + off * sizeof(u32), buf, len))
 806			memcpy(ctl->cache + off * sizeof(u32), buf, len);
 807		else
 808			return 0;
 809	}
 810
 811	ctl->set = 1;
 812	if (ctl->enabled && ctl->dsp->running)
 813		ret = cs_dsp_coeff_write_ctrl_raw(ctl, off, buf, len);
 814
 815	if (ret < 0)
 816		return ret;
 817
 818	return 1;
 819}
 820EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_write_ctrl, FW_CS_DSP);
 821
 822static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
 823				      unsigned int off, void *buf, size_t len)
 824{
 825	struct cs_dsp *dsp = ctl->dsp;
 826	void *scratch;
 827	int ret;
 828	unsigned int reg;
 829
 830	ret = cs_dsp_coeff_base_reg(ctl, &reg, off);
 831	if (ret)
 832		return ret;
 833
 834	scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);
 835	if (!scratch)
 836		return -ENOMEM;
 837
 838	ret = regmap_raw_read(dsp->regmap, reg, scratch, len);
 839	if (ret) {
 840		cs_dsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
 841			   len, reg, ret);
 842		kfree(scratch);
 843		return ret;
 844	}
 845	cs_dsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg);
 846
 847	memcpy(buf, scratch, len);
 848	kfree(scratch);
 849
 850	return 0;
 851}
 852
 853/**
 854 * cs_dsp_coeff_read_ctrl() - Reads the given coefficient control into the given buffer
 855 * @ctl: pointer to coefficient control
 856 * @off: word offset at which data should be read
 857 * @buf: the buffer to store to the given control
 858 * @len: the length of the buffer in bytes
 859 *
 860 * Must be called with pwr_lock held.
 861 *
 862 * Return: Zero for success, a negative number on error.
 863 */
 864int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl,
 865			   unsigned int off, void *buf, size_t len)
 866{
 867	int ret = 0;
 868
 869	if (!ctl)
 870		return -ENOENT;
 871
 872	lockdep_assert_held(&ctl->dsp->pwr_lock);
 873
 874	if (len + off * sizeof(u32) > ctl->len)
 875		return -EINVAL;
 876
 877	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
 878		if (ctl->enabled && ctl->dsp->running)
 879			return cs_dsp_coeff_read_ctrl_raw(ctl, off, buf, len);
 880		else
 881			return -EPERM;
 882	} else {
 883		if (!ctl->flags && ctl->enabled && ctl->dsp->running)
 884			ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len);
 885
 886		if (buf != ctl->cache)
 887			memcpy(buf, ctl->cache + off * sizeof(u32), len);
 888	}
 889
 890	return ret;
 891}
 892EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_read_ctrl, FW_CS_DSP);
 893
 894static int cs_dsp_coeff_init_control_caches(struct cs_dsp *dsp)
 895{
 896	struct cs_dsp_coeff_ctl *ctl;
 897	int ret;
 898
 899	list_for_each_entry(ctl, &dsp->ctl_list, list) {
 900		if (!ctl->enabled || ctl->set)
 901			continue;
 902		if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
 903			continue;
 904
 905		/*
 906		 * For readable controls populate the cache from the DSP memory.
 907		 * For non-readable controls the cache was zero-filled when
 908		 * created so we don't need to do anything.
 909		 */
 910		if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) {
 911			ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len);
 912			if (ret < 0)
 913				return ret;
 914		}
 915	}
 916
 917	return 0;
 918}
 919
 920static int cs_dsp_coeff_sync_controls(struct cs_dsp *dsp)
 921{
 922	struct cs_dsp_coeff_ctl *ctl;
 923	int ret;
 924
 925	list_for_each_entry(ctl, &dsp->ctl_list, list) {
 926		if (!ctl->enabled)
 927			continue;
 928		if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
 929			ret = cs_dsp_coeff_write_ctrl_raw(ctl, 0, ctl->cache,
 930							  ctl->len);
 931			if (ret < 0)
 932				return ret;
 933		}
 934	}
 935
 936	return 0;
 937}
 938
 939static void cs_dsp_signal_event_controls(struct cs_dsp *dsp,
 940					 unsigned int event)
 941{
 942	struct cs_dsp_coeff_ctl *ctl;
 943	int ret;
 944
 945	list_for_each_entry(ctl, &dsp->ctl_list, list) {
 946		if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT)
 947			continue;
 948
 949		if (!ctl->enabled)
 950			continue;
 951
 952		ret = cs_dsp_coeff_write_acked_control(ctl, event);
 953		if (ret)
 954			cs_dsp_warn(dsp,
 955				    "Failed to send 0x%x event to alg 0x%x (%d)\n",
 956				    event, ctl->alg_region.alg, ret);
 957	}
 958}
 959
 960static void cs_dsp_free_ctl_blk(struct cs_dsp_coeff_ctl *ctl)
 961{
 962	kfree(ctl->cache);
 963	kfree(ctl->subname);
 964	kfree(ctl);
 965}
 966
 967static int cs_dsp_create_control(struct cs_dsp *dsp,
 968				 const struct cs_dsp_alg_region *alg_region,
 969				 unsigned int offset, unsigned int len,
 970				 const char *subname, unsigned int subname_len,
 971				 unsigned int flags, unsigned int type)
 972{
 973	struct cs_dsp_coeff_ctl *ctl;
 974	int ret;
 975
 976	list_for_each_entry(ctl, &dsp->ctl_list, list) {
 977		if (ctl->fw_name == dsp->fw_name &&
 978		    ctl->alg_region.alg == alg_region->alg &&
 979		    ctl->alg_region.type == alg_region->type) {
 980			if ((!subname && !ctl->subname) ||
 981			    (subname && (ctl->subname_len == subname_len) &&
 982			     !strncmp(ctl->subname, subname, ctl->subname_len))) {
 983				if (!ctl->enabled)
 984					ctl->enabled = 1;
 985				return 0;
 986			}
 987		}
 988	}
 989
 990	ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
 991	if (!ctl)
 992		return -ENOMEM;
 993
 994	ctl->fw_name = dsp->fw_name;
 995	ctl->alg_region = *alg_region;
 996	if (subname && dsp->fw_ver >= 2) {
 997		ctl->subname_len = subname_len;
 998		ctl->subname = kasprintf(GFP_KERNEL, "%.*s", subname_len, subname);
 999		if (!ctl->subname) {
1000			ret = -ENOMEM;
1001			goto err_ctl;
1002		}
1003	}
1004	ctl->enabled = 1;
1005	ctl->set = 0;
1006	ctl->dsp = dsp;
1007
1008	ctl->flags = flags;
1009	ctl->type = type;
1010	ctl->offset = offset;
1011	ctl->len = len;
1012	ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
1013	if (!ctl->cache) {
1014		ret = -ENOMEM;
1015		goto err_ctl_subname;
1016	}
1017
1018	list_add(&ctl->list, &dsp->ctl_list);
1019
1020	if (dsp->client_ops->control_add) {
1021		ret = dsp->client_ops->control_add(ctl);
1022		if (ret)
1023			goto err_list_del;
1024	}
1025
1026	return 0;
1027
1028err_list_del:
1029	list_del(&ctl->list);
1030	kfree(ctl->cache);
1031err_ctl_subname:
1032	kfree(ctl->subname);
1033err_ctl:
1034	kfree(ctl);
1035
1036	return ret;
1037}
1038
1039struct cs_dsp_coeff_parsed_alg {
1040	int id;
1041	const u8 *name;
1042	int name_len;
1043	int ncoeff;
1044};
1045
1046struct cs_dsp_coeff_parsed_coeff {
1047	int offset;
1048	int mem_type;
1049	const u8 *name;
1050	int name_len;
1051	unsigned int ctl_type;
1052	int flags;
1053	int len;
1054};
1055
1056static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
1057{
1058	int length;
1059
1060	switch (bytes) {
1061	case 1:
1062		length = **pos;
1063		break;
1064	case 2:
1065		length = le16_to_cpu(*((__le16 *)*pos));
1066		break;
1067	default:
1068		return 0;
1069	}
1070
1071	if (str)
1072		*str = *pos + bytes;
1073
1074	*pos += ((length + bytes) + 3) & ~0x03;
1075
1076	return length;
1077}
1078
1079static int cs_dsp_coeff_parse_int(int bytes, const u8 **pos)
1080{
1081	int val = 0;
1082
1083	switch (bytes) {
1084	case 2:
1085		val = le16_to_cpu(*((__le16 *)*pos));
1086		break;
1087	case 4:
1088		val = le32_to_cpu(*((__le32 *)*pos));
1089		break;
1090	default:
1091		break;
1092	}
1093
1094	*pos += bytes;
1095
1096	return val;
1097}
1098
1099static inline void cs_dsp_coeff_parse_alg(struct cs_dsp *dsp, const u8 **data,
1100					  struct cs_dsp_coeff_parsed_alg *blk)
1101{
1102	const struct wmfw_adsp_alg_data *raw;
1103
1104	switch (dsp->fw_ver) {
1105	case 0:
1106	case 1:
1107		raw = (const struct wmfw_adsp_alg_data *)*data;
1108		*data = raw->data;
1109
1110		blk->id = le32_to_cpu(raw->id);
1111		blk->name = raw->name;
1112		blk->name_len = strlen(raw->name);
1113		blk->ncoeff = le32_to_cpu(raw->ncoeff);
1114		break;
1115	default:
1116		blk->id = cs_dsp_coeff_parse_int(sizeof(raw->id), data);
1117		blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), data,
1118							  &blk->name);
1119		cs_dsp_coeff_parse_string(sizeof(u16), data, NULL);
1120		blk->ncoeff = cs_dsp_coeff_parse_int(sizeof(raw->ncoeff), data);
1121		break;
1122	}
1123
1124	cs_dsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
1125	cs_dsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
1126	cs_dsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
1127}
1128
1129static inline void cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, const u8 **data,
1130					    struct cs_dsp_coeff_parsed_coeff *blk)
1131{
1132	const struct wmfw_adsp_coeff_data *raw;
1133	const u8 *tmp;
1134	int length;
1135
1136	switch (dsp->fw_ver) {
1137	case 0:
1138	case 1:
1139		raw = (const struct wmfw_adsp_coeff_data *)*data;
1140		*data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
1141
1142		blk->offset = le16_to_cpu(raw->hdr.offset);
1143		blk->mem_type = le16_to_cpu(raw->hdr.type);
1144		blk->name = raw->name;
1145		blk->name_len = strlen(raw->name);
1146		blk->ctl_type = le16_to_cpu(raw->ctl_type);
1147		blk->flags = le16_to_cpu(raw->flags);
1148		blk->len = le32_to_cpu(raw->len);
1149		break;
1150	default:
1151		tmp = *data;
1152		blk->offset = cs_dsp_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
1153		blk->mem_type = cs_dsp_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
1154		length = cs_dsp_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
1155		blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp,
1156							  &blk->name);
1157		cs_dsp_coeff_parse_string(sizeof(u8), &tmp, NULL);
1158		cs_dsp_coeff_parse_string(sizeof(u16), &tmp, NULL);
1159		blk->ctl_type = cs_dsp_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
1160		blk->flags = cs_dsp_coeff_parse_int(sizeof(raw->flags), &tmp);
1161		blk->len = cs_dsp_coeff_parse_int(sizeof(raw->len), &tmp);
1162
1163		*data = *data + sizeof(raw->hdr) + length;
1164		break;
1165	}
1166
1167	cs_dsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
1168	cs_dsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
1169	cs_dsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
1170	cs_dsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
1171	cs_dsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
1172	cs_dsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
1173}
1174
1175static int cs_dsp_check_coeff_flags(struct cs_dsp *dsp,
1176				    const struct cs_dsp_coeff_parsed_coeff *coeff_blk,
1177				    unsigned int f_required,
1178				    unsigned int f_illegal)
1179{
1180	if ((coeff_blk->flags & f_illegal) ||
1181	    ((coeff_blk->flags & f_required) != f_required)) {
1182		cs_dsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n",
1183			   coeff_blk->flags, coeff_blk->ctl_type);
1184		return -EINVAL;
1185	}
1186
1187	return 0;
1188}
1189
1190static int cs_dsp_parse_coeff(struct cs_dsp *dsp,
1191			      const struct wmfw_region *region)
1192{
1193	struct cs_dsp_alg_region alg_region = {};
1194	struct cs_dsp_coeff_parsed_alg alg_blk;
1195	struct cs_dsp_coeff_parsed_coeff coeff_blk;
1196	const u8 *data = region->data;
1197	int i, ret;
1198
1199	cs_dsp_coeff_parse_alg(dsp, &data, &alg_blk);
1200	for (i = 0; i < alg_blk.ncoeff; i++) {
1201		cs_dsp_coeff_parse_coeff(dsp, &data, &coeff_blk);
1202
1203		switch (coeff_blk.ctl_type) {
1204		case WMFW_CTL_TYPE_BYTES:
1205			break;
1206		case WMFW_CTL_TYPE_ACKED:
1207			if (coeff_blk.flags & WMFW_CTL_FLAG_SYS)
1208				continue;	/* ignore */
1209
1210			ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk,
1211						       WMFW_CTL_FLAG_VOLATILE |
1212						       WMFW_CTL_FLAG_WRITEABLE |
1213						       WMFW_CTL_FLAG_READABLE,
1214						       0);
1215			if (ret)
1216				return -EINVAL;
1217			break;
1218		case WMFW_CTL_TYPE_HOSTEVENT:
1219		case WMFW_CTL_TYPE_FWEVENT:
1220			ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk,
1221						       WMFW_CTL_FLAG_SYS |
1222						       WMFW_CTL_FLAG_VOLATILE |
1223						       WMFW_CTL_FLAG_WRITEABLE |
1224						       WMFW_CTL_FLAG_READABLE,
1225						       0);
1226			if (ret)
1227				return -EINVAL;
1228			break;
1229		case WMFW_CTL_TYPE_HOST_BUFFER:
1230			ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk,
1231						       WMFW_CTL_FLAG_SYS |
1232						       WMFW_CTL_FLAG_VOLATILE |
1233						       WMFW_CTL_FLAG_READABLE,
1234						       0);
1235			if (ret)
1236				return -EINVAL;
1237			break;
1238		default:
1239			cs_dsp_err(dsp, "Unknown control type: %d\n",
1240				   coeff_blk.ctl_type);
1241			return -EINVAL;
1242		}
1243
1244		alg_region.type = coeff_blk.mem_type;
1245		alg_region.alg = alg_blk.id;
1246
1247		ret = cs_dsp_create_control(dsp, &alg_region,
1248					    coeff_blk.offset,
1249					    coeff_blk.len,
1250					    coeff_blk.name,
1251					    coeff_blk.name_len,
1252					    coeff_blk.flags,
1253					    coeff_blk.ctl_type);
1254		if (ret < 0)
1255			cs_dsp_err(dsp, "Failed to create control: %.*s, %d\n",
1256				   coeff_blk.name_len, coeff_blk.name, ret);
1257	}
1258
1259	return 0;
1260}
1261
1262static unsigned int cs_dsp_adsp1_parse_sizes(struct cs_dsp *dsp,
1263					     const char * const file,
1264					     unsigned int pos,
1265					     const struct firmware *firmware)
1266{
1267	const struct wmfw_adsp1_sizes *adsp1_sizes;
1268
1269	adsp1_sizes = (void *)&firmware->data[pos];
1270
1271	cs_dsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file,
1272		   le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm),
1273		   le32_to_cpu(adsp1_sizes->zm));
1274
1275	return pos + sizeof(*adsp1_sizes);
1276}
1277
1278static unsigned int cs_dsp_adsp2_parse_sizes(struct cs_dsp *dsp,
1279					     const char * const file,
1280					     unsigned int pos,
1281					     const struct firmware *firmware)
1282{
1283	const struct wmfw_adsp2_sizes *adsp2_sizes;
1284
1285	adsp2_sizes = (void *)&firmware->data[pos];
1286
1287	cs_dsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file,
1288		   le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym),
1289		   le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm));
1290
1291	return pos + sizeof(*adsp2_sizes);
1292}
1293
1294static bool cs_dsp_validate_version(struct cs_dsp *dsp, unsigned int version)
1295{
1296	switch (version) {
1297	case 0:
1298		cs_dsp_warn(dsp, "Deprecated file format %d\n", version);
1299		return true;
1300	case 1:
1301	case 2:
1302		return true;
1303	default:
1304		return false;
1305	}
1306}
1307
1308static bool cs_dsp_halo_validate_version(struct cs_dsp *dsp, unsigned int version)
1309{
1310	switch (version) {
1311	case 3:
1312		return true;
1313	default:
1314		return false;
1315	}
1316}
1317
1318static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
1319		       const char *file)
1320{
1321	LIST_HEAD(buf_list);
1322	struct regmap *regmap = dsp->regmap;
1323	unsigned int pos = 0;
1324	const struct wmfw_header *header;
1325	const struct wmfw_adsp1_sizes *adsp1_sizes;
1326	const struct wmfw_footer *footer;
1327	const struct wmfw_region *region;
1328	const struct cs_dsp_region *mem;
1329	const char *region_name;
1330	char *text = NULL;
1331	struct cs_dsp_buf *buf;
1332	unsigned int reg;
1333	int regions = 0;
1334	int ret, offset, type;
1335
1336	if (!firmware)
1337		return 0;
1338
1339	ret = -EINVAL;
1340
1341	pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
1342	if (pos >= firmware->size) {
1343		cs_dsp_err(dsp, "%s: file too short, %zu bytes\n",
1344			   file, firmware->size);
1345		goto out_fw;
1346	}
1347
1348	header = (void *)&firmware->data[0];
1349
1350	if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
1351		cs_dsp_err(dsp, "%s: invalid magic\n", file);
1352		goto out_fw;
1353	}
1354
1355	if (!dsp->ops->validate_version(dsp, header->ver)) {
1356		cs_dsp_err(dsp, "%s: unknown file format %d\n",
1357			   file, header->ver);
1358		goto out_fw;
1359	}
1360
1361	cs_dsp_info(dsp, "Firmware version: %d\n", header->ver);
1362	dsp->fw_ver = header->ver;
1363
1364	if (header->core != dsp->type) {
1365		cs_dsp_err(dsp, "%s: invalid core %d != %d\n",
1366			   file, header->core, dsp->type);
1367		goto out_fw;
1368	}
1369
1370	pos = sizeof(*header);
1371	pos = dsp->ops->parse_sizes(dsp, file, pos, firmware);
1372
1373	footer = (void *)&firmware->data[pos];
1374	pos += sizeof(*footer);
1375
1376	if (le32_to_cpu(header->len) != pos) {
1377		cs_dsp_err(dsp, "%s: unexpected header length %d\n",
1378			   file, le32_to_cpu(header->len));
1379		goto out_fw;
1380	}
1381
1382	cs_dsp_dbg(dsp, "%s: timestamp %llu\n", file,
1383		   le64_to_cpu(footer->timestamp));
1384
1385	while (pos < firmware->size &&
1386	       sizeof(*region) < firmware->size - pos) {
1387		region = (void *)&(firmware->data[pos]);
1388		region_name = "Unknown";
1389		reg = 0;
1390		text = NULL;
1391		offset = le32_to_cpu(region->offset) & 0xffffff;
1392		type = be32_to_cpu(region->type) & 0xff;
1393
1394		switch (type) {
1395		case WMFW_NAME_TEXT:
1396			region_name = "Firmware name";
1397			text = kzalloc(le32_to_cpu(region->len) + 1,
1398				       GFP_KERNEL);
1399			break;
1400		case WMFW_ALGORITHM_DATA:
1401			region_name = "Algorithm";
1402			ret = cs_dsp_parse_coeff(dsp, region);
1403			if (ret != 0)
1404				goto out_fw;
1405			break;
1406		case WMFW_INFO_TEXT:
1407			region_name = "Information";
1408			text = kzalloc(le32_to_cpu(region->len) + 1,
1409				       GFP_KERNEL);
1410			break;
1411		case WMFW_ABSOLUTE:
1412			region_name = "Absolute";
1413			reg = offset;
1414			break;
1415		case WMFW_ADSP1_PM:
1416		case WMFW_ADSP1_DM:
1417		case WMFW_ADSP2_XM:
1418		case WMFW_ADSP2_YM:
1419		case WMFW_ADSP1_ZM:
1420		case WMFW_HALO_PM_PACKED:
1421		case WMFW_HALO_XM_PACKED:
1422		case WMFW_HALO_YM_PACKED:
1423			mem = cs_dsp_find_region(dsp, type);
1424			if (!mem) {
1425				cs_dsp_err(dsp, "No region of type: %x\n", type);
1426				ret = -EINVAL;
1427				goto out_fw;
1428			}
1429
1430			region_name = cs_dsp_mem_region_name(type);
1431			reg = dsp->ops->region_to_reg(mem, offset);
1432			break;
1433		default:
1434			cs_dsp_warn(dsp,
1435				    "%s.%d: Unknown region type %x at %d(%x)\n",
1436				    file, regions, type, pos, pos);
1437			break;
1438		}
1439
1440		cs_dsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
1441			   regions, le32_to_cpu(region->len), offset,
1442			   region_name);
1443
1444		if (le32_to_cpu(region->len) >
1445		    firmware->size - pos - sizeof(*region)) {
1446			cs_dsp_err(dsp,
1447				   "%s.%d: %s region len %d bytes exceeds file length %zu\n",
1448				   file, regions, region_name,
1449				   le32_to_cpu(region->len), firmware->size);
1450			ret = -EINVAL;
1451			goto out_fw;
1452		}
1453
1454		if (text) {
1455			memcpy(text, region->data, le32_to_cpu(region->len));
1456			cs_dsp_info(dsp, "%s: %s\n", file, text);
1457			kfree(text);
1458			text = NULL;
1459		}
1460
1461		if (reg) {
1462			buf = cs_dsp_buf_alloc(region->data,
1463					       le32_to_cpu(region->len),
1464					       &buf_list);
1465			if (!buf) {
1466				cs_dsp_err(dsp, "Out of memory\n");
1467				ret = -ENOMEM;
1468				goto out_fw;
1469			}
1470
1471			ret = regmap_raw_write_async(regmap, reg, buf->buf,
1472						     le32_to_cpu(region->len));
1473			if (ret != 0) {
1474				cs_dsp_err(dsp,
1475					   "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
1476					   file, regions,
1477					   le32_to_cpu(region->len), offset,
1478					   region_name, ret);
1479				goto out_fw;
1480			}
1481		}
1482
1483		pos += le32_to_cpu(region->len) + sizeof(*region);
1484		regions++;
1485	}
1486
1487	ret = regmap_async_complete(regmap);
1488	if (ret != 0) {
1489		cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret);
1490		goto out_fw;
1491	}
1492
1493	if (pos > firmware->size)
1494		cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
1495			    file, regions, pos - firmware->size);
1496
1497	cs_dsp_debugfs_save_wmfwname(dsp, file);
1498
1499out_fw:
1500	regmap_async_complete(regmap);
1501	cs_dsp_buf_free(&buf_list);
1502	kfree(text);
1503
1504	return ret;
1505}
1506
1507/**
1508 * cs_dsp_get_ctl() - Finds a matching coefficient control
1509 * @dsp: pointer to DSP structure
1510 * @name: pointer to string to match with a control's subname
1511 * @type: the algorithm type to match
1512 * @alg: the algorithm id to match
1513 *
1514 * Find cs_dsp_coeff_ctl with input name as its subname
1515 *
1516 * Return: pointer to the control on success, NULL if not found
1517 */
1518struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, int type,
1519					unsigned int alg)
1520{
1521	struct cs_dsp_coeff_ctl *pos, *rslt = NULL;
1522
1523	lockdep_assert_held(&dsp->pwr_lock);
1524
1525	list_for_each_entry(pos, &dsp->ctl_list, list) {
1526		if (!pos->subname)
1527			continue;
1528		if (strncmp(pos->subname, name, pos->subname_len) == 0 &&
1529		    pos->fw_name == dsp->fw_name &&
1530		    pos->alg_region.alg == alg &&
1531		    pos->alg_region.type == type) {
1532			rslt = pos;
1533			break;
1534		}
1535	}
1536
1537	return rslt;
1538}
1539EXPORT_SYMBOL_NS_GPL(cs_dsp_get_ctl, FW_CS_DSP);
1540
1541static void cs_dsp_ctl_fixup_base(struct cs_dsp *dsp,
1542				  const struct cs_dsp_alg_region *alg_region)
1543{
1544	struct cs_dsp_coeff_ctl *ctl;
1545
1546	list_for_each_entry(ctl, &dsp->ctl_list, list) {
1547		if (ctl->fw_name == dsp->fw_name &&
1548		    alg_region->alg == ctl->alg_region.alg &&
1549		    alg_region->type == ctl->alg_region.type) {
1550			ctl->alg_region.base = alg_region->base;
1551		}
1552	}
1553}
1554
1555static void *cs_dsp_read_algs(struct cs_dsp *dsp, size_t n_algs,
1556			      const struct cs_dsp_region *mem,
1557			      unsigned int pos, unsigned int len)
1558{
1559	void *alg;
1560	unsigned int reg;
1561	int ret;
1562	__be32 val;
1563
1564	if (n_algs == 0) {
1565		cs_dsp_err(dsp, "No algorithms\n");
1566		return ERR_PTR(-EINVAL);
1567	}
1568
1569	if (n_algs > 1024) {
1570		cs_dsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
1571		return ERR_PTR(-EINVAL);
1572	}
1573
1574	/* Read the terminator first to validate the length */
1575	reg = dsp->ops->region_to_reg(mem, pos + len);
1576
1577	ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
1578	if (ret != 0) {
1579		cs_dsp_err(dsp, "Failed to read algorithm list end: %d\n",
1580			   ret);
1581		return ERR_PTR(ret);
1582	}
1583
1584	if (be32_to_cpu(val) != 0xbedead)
1585		cs_dsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
1586			    reg, be32_to_cpu(val));
1587
1588	/* Convert length from DSP words to bytes */
1589	len *= sizeof(u32);
1590
1591	alg = kzalloc(len, GFP_KERNEL | GFP_DMA);
1592	if (!alg)
1593		return ERR_PTR(-ENOMEM);
1594
1595	reg = dsp->ops->region_to_reg(mem, pos);
1596
1597	ret = regmap_raw_read(dsp->regmap, reg, alg, len);
1598	if (ret != 0) {
1599		cs_dsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
1600		kfree(alg);
1601		return ERR_PTR(ret);
1602	}
1603
1604	return alg;
1605}
1606
1607/**
1608 * cs_dsp_find_alg_region() - Finds a matching algorithm region
1609 * @dsp: pointer to DSP structure
1610 * @type: the algorithm type to match
1611 * @id: the algorithm id to match
1612 *
1613 * Return: Pointer to matching algorithm region, or NULL if not found.
1614 */
1615struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp,
1616						 int type, unsigned int id)
1617{
1618	struct cs_dsp_alg_region *alg_region;
1619
1620	lockdep_assert_held(&dsp->pwr_lock);
1621
1622	list_for_each_entry(alg_region, &dsp->alg_regions, list) {
1623		if (id == alg_region->alg && type == alg_region->type)
1624			return alg_region;
1625	}
1626
1627	return NULL;
1628}
1629EXPORT_SYMBOL_NS_GPL(cs_dsp_find_alg_region, FW_CS_DSP);
1630
1631static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp,
1632						      int type, __be32 id,
1633						      __be32 ver, __be32 base)
1634{
1635	struct cs_dsp_alg_region *alg_region;
1636
1637	alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
1638	if (!alg_region)
1639		return ERR_PTR(-ENOMEM);
1640
1641	alg_region->type = type;
1642	alg_region->alg = be32_to_cpu(id);
1643	alg_region->ver = be32_to_cpu(ver);
1644	alg_region->base = be32_to_cpu(base);
1645
1646	list_add_tail(&alg_region->list, &dsp->alg_regions);
1647
1648	if (dsp->fw_ver > 0)
1649		cs_dsp_ctl_fixup_base(dsp, alg_region);
1650
1651	return alg_region;
1652}
1653
1654static void cs_dsp_free_alg_regions(struct cs_dsp *dsp)
1655{
1656	struct cs_dsp_alg_region *alg_region;
1657
1658	while (!list_empty(&dsp->alg_regions)) {
1659		alg_region = list_first_entry(&dsp->alg_regions,
1660					      struct cs_dsp_alg_region,
1661					      list);
1662		list_del(&alg_region->list);
1663		kfree(alg_region);
1664	}
1665}
1666
1667static void cs_dsp_parse_wmfw_id_header(struct cs_dsp *dsp,
1668					struct wmfw_id_hdr *fw, int nalgs)
1669{
1670	dsp->fw_id = be32_to_cpu(fw->id);
1671	dsp->fw_id_version = be32_to_cpu(fw->ver);
1672
1673	cs_dsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n",
1674		    dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16,
1675		    (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
1676		    nalgs);
1677}
1678
1679static void cs_dsp_parse_wmfw_v3_id_header(struct cs_dsp *dsp,
1680					   struct wmfw_v3_id_hdr *fw, int nalgs)
1681{
1682	dsp->fw_id = be32_to_cpu(fw->id);
1683	dsp->fw_id_version = be32_to_cpu(fw->ver);
1684	dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id);
1685
1686	cs_dsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n",
1687		    dsp->fw_id, dsp->fw_vendor_id,
1688		    (dsp->fw_id_version & 0xff0000) >> 16,
1689		    (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
1690		    nalgs);
1691}
1692
1693static int cs_dsp_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver,
1694				 int nregions, const int *type, __be32 *base)
1695{
1696	struct cs_dsp_alg_region *alg_region;
1697	int i;
1698
1699	for (i = 0; i < nregions; i++) {
1700		alg_region = cs_dsp_create_region(dsp, type[i], id, ver, base[i]);
1701		if (IS_ERR(alg_region))
1702			return PTR_ERR(alg_region);
1703	}
1704
1705	return 0;
1706}
1707
1708static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp)
1709{
1710	struct wmfw_adsp1_id_hdr adsp1_id;
1711	struct wmfw_adsp1_alg_hdr *adsp1_alg;
1712	struct cs_dsp_alg_region *alg_region;
1713	const struct cs_dsp_region *mem;
1714	unsigned int pos, len;
1715	size_t n_algs;
1716	int i, ret;
1717
1718	mem = cs_dsp_find_region(dsp, WMFW_ADSP1_DM);
1719	if (WARN_ON(!mem))
1720		return -EINVAL;
1721
1722	ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
1723			      sizeof(adsp1_id));
1724	if (ret != 0) {
1725		cs_dsp_err(dsp, "Failed to read algorithm info: %d\n",
1726			   ret);
1727		return ret;
1728	}
1729
1730	n_algs = be32_to_cpu(adsp1_id.n_algs);
1731
1732	cs_dsp_parse_wmfw_id_header(dsp, &adsp1_id.fw, n_algs);
1733
1734	alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM,
1735					  adsp1_id.fw.id, adsp1_id.fw.ver,
1736					  adsp1_id.zm);
1737	if (IS_ERR(alg_region))
1738		return PTR_ERR(alg_region);
1739
1740	alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM,
1741					  adsp1_id.fw.id, adsp1_id.fw.ver,
1742					  adsp1_id.dm);
1743	if (IS_ERR(alg_region))
1744		return PTR_ERR(alg_region);
1745
1746	/* Calculate offset and length in DSP words */
1747	pos = sizeof(adsp1_id) / sizeof(u32);
1748	len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32);
1749
1750	adsp1_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len);
1751	if (IS_ERR(adsp1_alg))
1752		return PTR_ERR(adsp1_alg);
1753
1754	for (i = 0; i < n_algs; i++) {
1755		cs_dsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
1756			    i, be32_to_cpu(adsp1_alg[i].alg.id),
1757			    (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
1758			    (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
1759			    be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
1760			    be32_to_cpu(adsp1_alg[i].dm),
1761			    be32_to_cpu(adsp1_alg[i].zm));
1762
1763		alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM,
1764						  adsp1_alg[i].alg.id,
1765						  adsp1_alg[i].alg.ver,
1766						  adsp1_alg[i].dm);
1767		if (IS_ERR(alg_region)) {
1768			ret = PTR_ERR(alg_region);
1769			goto out;
1770		}
1771		if (dsp->fw_ver == 0) {
1772			if (i + 1 < n_algs) {
1773				len = be32_to_cpu(adsp1_alg[i + 1].dm);
1774				len -= be32_to_cpu(adsp1_alg[i].dm);
1775				len *= 4;
1776				cs_dsp_create_control(dsp, alg_region, 0,
1777						      len, NULL, 0, 0,
1778						      WMFW_CTL_TYPE_BYTES);
1779			} else {
1780				cs_dsp_warn(dsp, "Missing length info for region DM with ID %x\n",
1781					    be32_to_cpu(adsp1_alg[i].alg.id));
1782			}
1783		}
1784
1785		alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM,
1786						  adsp1_alg[i].alg.id,
1787						  adsp1_alg[i].alg.ver,
1788						  adsp1_alg[i].zm);
1789		if (IS_ERR(alg_region)) {
1790			ret = PTR_ERR(alg_region);
1791			goto out;
1792		}
1793		if (dsp->fw_ver == 0) {
1794			if (i + 1 < n_algs) {
1795				len = be32_to_cpu(adsp1_alg[i + 1].zm);
1796				len -= be32_to_cpu(adsp1_alg[i].zm);
1797				len *= 4;
1798				cs_dsp_create_control(dsp, alg_region, 0,
1799						      len, NULL, 0, 0,
1800						      WMFW_CTL_TYPE_BYTES);
1801			} else {
1802				cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1803					    be32_to_cpu(adsp1_alg[i].alg.id));
1804			}
1805		}
1806	}
1807
1808out:
1809	kfree(adsp1_alg);
1810	return ret;
1811}
1812
1813static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp)
1814{
1815	struct wmfw_adsp2_id_hdr adsp2_id;
1816	struct wmfw_adsp2_alg_hdr *adsp2_alg;
1817	struct cs_dsp_alg_region *alg_region;
1818	const struct cs_dsp_region *mem;
1819	unsigned int pos, len;
1820	size_t n_algs;
1821	int i, ret;
1822
1823	mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM);
1824	if (WARN_ON(!mem))
1825		return -EINVAL;
1826
1827	ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
1828			      sizeof(adsp2_id));
1829	if (ret != 0) {
1830		cs_dsp_err(dsp, "Failed to read algorithm info: %d\n",
1831			   ret);
1832		return ret;
1833	}
1834
1835	n_algs = be32_to_cpu(adsp2_id.n_algs);
1836
1837	cs_dsp_parse_wmfw_id_header(dsp, &adsp2_id.fw, n_algs);
1838
1839	alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM,
1840					  adsp2_id.fw.id, adsp2_id.fw.ver,
1841					  adsp2_id.xm);
1842	if (IS_ERR(alg_region))
1843		return PTR_ERR(alg_region);
1844
1845	alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM,
1846					  adsp2_id.fw.id, adsp2_id.fw.ver,
1847					  adsp2_id.ym);
1848	if (IS_ERR(alg_region))
1849		return PTR_ERR(alg_region);
1850
1851	alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM,
1852					  adsp2_id.fw.id, adsp2_id.fw.ver,
1853					  adsp2_id.zm);
1854	if (IS_ERR(alg_region))
1855		return PTR_ERR(alg_region);
1856
1857	/* Calculate offset and length in DSP words */
1858	pos = sizeof(adsp2_id) / sizeof(u32);
1859	len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32);
1860
1861	adsp2_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len);
1862	if (IS_ERR(adsp2_alg))
1863		return PTR_ERR(adsp2_alg);
1864
1865	for (i = 0; i < n_algs; i++) {
1866		cs_dsp_dbg(dsp,
1867			   "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
1868			   i, be32_to_cpu(adsp2_alg[i].alg.id),
1869			   (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
1870			   (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
1871			   be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
1872			   be32_to_cpu(adsp2_alg[i].xm),
1873			   be32_to_cpu(adsp2_alg[i].ym),
1874			   be32_to_cpu(adsp2_alg[i].zm));
1875
1876		alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM,
1877						  adsp2_alg[i].alg.id,
1878						  adsp2_alg[i].alg.ver,
1879						  adsp2_alg[i].xm);
1880		if (IS_ERR(alg_region)) {
1881			ret = PTR_ERR(alg_region);
1882			goto out;
1883		}
1884		if (dsp->fw_ver == 0) {
1885			if (i + 1 < n_algs) {
1886				len = be32_to_cpu(adsp2_alg[i + 1].xm);
1887				len -= be32_to_cpu(adsp2_alg[i].xm);
1888				len *= 4;
1889				cs_dsp_create_control(dsp, alg_region, 0,
1890						      len, NULL, 0, 0,
1891						      WMFW_CTL_TYPE_BYTES);
1892			} else {
1893				cs_dsp_warn(dsp, "Missing length info for region XM with ID %x\n",
1894					    be32_to_cpu(adsp2_alg[i].alg.id));
1895			}
1896		}
1897
1898		alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM,
1899						  adsp2_alg[i].alg.id,
1900						  adsp2_alg[i].alg.ver,
1901						  adsp2_alg[i].ym);
1902		if (IS_ERR(alg_region)) {
1903			ret = PTR_ERR(alg_region);
1904			goto out;
1905		}
1906		if (dsp->fw_ver == 0) {
1907			if (i + 1 < n_algs) {
1908				len = be32_to_cpu(adsp2_alg[i + 1].ym);
1909				len -= be32_to_cpu(adsp2_alg[i].ym);
1910				len *= 4;
1911				cs_dsp_create_control(dsp, alg_region, 0,
1912						      len, NULL, 0, 0,
1913						      WMFW_CTL_TYPE_BYTES);
1914			} else {
1915				cs_dsp_warn(dsp, "Missing length info for region YM with ID %x\n",
1916					    be32_to_cpu(adsp2_alg[i].alg.id));
1917			}
1918		}
1919
1920		alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM,
1921						  adsp2_alg[i].alg.id,
1922						  adsp2_alg[i].alg.ver,
1923						  adsp2_alg[i].zm);
1924		if (IS_ERR(alg_region)) {
1925			ret = PTR_ERR(alg_region);
1926			goto out;
1927		}
1928		if (dsp->fw_ver == 0) {
1929			if (i + 1 < n_algs) {
1930				len = be32_to_cpu(adsp2_alg[i + 1].zm);
1931				len -= be32_to_cpu(adsp2_alg[i].zm);
1932				len *= 4;
1933				cs_dsp_create_control(dsp, alg_region, 0,
1934						      len, NULL, 0, 0,
1935						      WMFW_CTL_TYPE_BYTES);
1936			} else {
1937				cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1938					    be32_to_cpu(adsp2_alg[i].alg.id));
1939			}
1940		}
1941	}
1942
1943out:
1944	kfree(adsp2_alg);
1945	return ret;
1946}
1947
1948static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver,
1949				      __be32 xm_base, __be32 ym_base)
1950{
1951	static const int types[] = {
1952		WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED,
1953		WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED
1954	};
1955	__be32 bases[] = { xm_base, xm_base, ym_base, ym_base };
1956
1957	return cs_dsp_create_regions(dsp, id, ver, ARRAY_SIZE(types), types, bases);
1958}
1959
1960static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp)
1961{
1962	struct wmfw_halo_id_hdr halo_id;
1963	struct wmfw_halo_alg_hdr *halo_alg;
1964	const struct cs_dsp_region *mem;
1965	unsigned int pos, len;
1966	size_t n_algs;
1967	int i, ret;
1968
1969	mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM);
1970	if (WARN_ON(!mem))
1971		return -EINVAL;
1972
1973	ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id,
1974			      sizeof(halo_id));
1975	if (ret != 0) {
1976		cs_dsp_err(dsp, "Failed to read algorithm info: %d\n",
1977			   ret);
1978		return ret;
1979	}
1980
1981	n_algs = be32_to_cpu(halo_id.n_algs);
1982
1983	cs_dsp_parse_wmfw_v3_id_header(dsp, &halo_id.fw, n_algs);
1984
1985	ret = cs_dsp_halo_create_regions(dsp, halo_id.fw.id, halo_id.fw.ver,
1986					 halo_id.xm_base, halo_id.ym_base);
1987	if (ret)
1988		return ret;
1989
1990	/* Calculate offset and length in DSP words */
1991	pos = sizeof(halo_id) / sizeof(u32);
1992	len = (sizeof(*halo_alg) * n_algs) / sizeof(u32);
1993
1994	halo_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len);
1995	if (IS_ERR(halo_alg))
1996		return PTR_ERR(halo_alg);
1997
1998	for (i = 0; i < n_algs; i++) {
1999		cs_dsp_dbg(dsp,
2000			   "%d: ID %x v%d.%d.%d XM@%x YM@%x\n",
2001			   i, be32_to_cpu(halo_alg[i].alg.id),
2002			   (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16,
2003			   (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8,
2004			   be32_to_cpu(halo_alg[i].alg.ver) & 0xff,
2005			   be32_to_cpu(halo_alg[i].xm_base),
2006			   be32_to_cpu(halo_alg[i].ym_base));
2007
2008		ret = cs_dsp_halo_create_regions(dsp, halo_alg[i].alg.id,
2009						 halo_alg[i].alg.ver,
2010						 halo_alg[i].xm_base,
2011						 halo_alg[i].ym_base);
2012		if (ret)
2013			goto out;
2014	}
2015
2016out:
2017	kfree(halo_alg);
2018	return ret;
2019}
2020
2021static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware,
2022			     const char *file)
2023{
2024	LIST_HEAD(buf_list);
2025	struct regmap *regmap = dsp->regmap;
2026	struct wmfw_coeff_hdr *hdr;
2027	struct wmfw_coeff_item *blk;
2028	const struct cs_dsp_region *mem;
2029	struct cs_dsp_alg_region *alg_region;
2030	const char *region_name;
2031	int ret, pos, blocks, type, offset, reg, version;
2032	char *text = NULL;
2033	struct cs_dsp_buf *buf;
2034
2035	if (!firmware)
2036		return 0;
2037
2038	ret = -EINVAL;
2039
2040	if (sizeof(*hdr) >= firmware->size) {
2041		cs_dsp_err(dsp, "%s: coefficient file too short, %zu bytes\n",
2042			   file, firmware->size);
2043		goto out_fw;
2044	}
2045
2046	hdr = (void *)&firmware->data[0];
2047	if (memcmp(hdr->magic, "WMDR", 4) != 0) {
2048		cs_dsp_err(dsp, "%s: invalid coefficient magic\n", file);
2049		goto out_fw;
2050	}
2051
2052	switch (be32_to_cpu(hdr->rev) & 0xff) {
2053	case 1:
2054	case 2:
2055		break;
2056	default:
2057		cs_dsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
2058			   file, be32_to_cpu(hdr->rev) & 0xff);
2059		ret = -EINVAL;
2060		goto out_fw;
2061	}
2062
2063	cs_dsp_info(dsp, "%s: v%d.%d.%d\n", file,
2064		    (le32_to_cpu(hdr->ver) >> 16) & 0xff,
2065		    (le32_to_cpu(hdr->ver) >>  8) & 0xff,
2066		    le32_to_cpu(hdr->ver) & 0xff);
2067
2068	pos = le32_to_cpu(hdr->len);
2069
2070	blocks = 0;
2071	while (pos < firmware->size &&
2072	       sizeof(*blk) < firmware->size - pos) {
2073		blk = (void *)(&firmware->data[pos]);
2074
2075		type = le16_to_cpu(blk->type);
2076		offset = le16_to_cpu(blk->offset);
2077		version = le32_to_cpu(blk->ver) >> 8;
2078
2079		cs_dsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
2080			   file, blocks, le32_to_cpu(blk->id),
2081			   (le32_to_cpu(blk->ver) >> 16) & 0xff,
2082			   (le32_to_cpu(blk->ver) >>  8) & 0xff,
2083			   le32_to_cpu(blk->ver) & 0xff);
2084		cs_dsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
2085			   file, blocks, le32_to_cpu(blk->len), offset, type);
2086
2087		reg = 0;
2088		region_name = "Unknown";
2089		switch (type) {
2090		case (WMFW_NAME_TEXT << 8):
2091			text = kzalloc(le32_to_cpu(blk->len) + 1, GFP_KERNEL);
2092			break;
2093		case (WMFW_INFO_TEXT << 8):
2094		case (WMFW_METADATA << 8):
2095			break;
2096		case (WMFW_ABSOLUTE << 8):
2097			/*
2098			 * Old files may use this for global
2099			 * coefficients.
2100			 */
2101			if (le32_to_cpu(blk->id) == dsp->fw_id &&
2102			    offset == 0) {
2103				region_name = "global coefficients";
2104				mem = cs_dsp_find_region(dsp, type);
2105				if (!mem) {
2106					cs_dsp_err(dsp, "No ZM\n");
2107					break;
2108				}
2109				reg = dsp->ops->region_to_reg(mem, 0);
2110
2111			} else {
2112				region_name = "register";
2113				reg = offset;
2114			}
2115			break;
2116
2117		case WMFW_ADSP1_DM:
2118		case WMFW_ADSP1_ZM:
2119		case WMFW_ADSP2_XM:
2120		case WMFW_ADSP2_YM:
2121		case WMFW_HALO_XM_PACKED:
2122		case WMFW_HALO_YM_PACKED:
2123		case WMFW_HALO_PM_PACKED:
2124			cs_dsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
2125				   file, blocks, le32_to_cpu(blk->len),
2126				   type, le32_to_cpu(blk->id));
2127
2128			region_name = cs_dsp_mem_region_name(type);
2129			mem = cs_dsp_find_region(dsp, type);
2130			if (!mem) {
2131				cs_dsp_err(dsp, "No base for region %x\n", type);
2132				break;
2133			}
2134
2135			alg_region = cs_dsp_find_alg_region(dsp, type,
2136							    le32_to_cpu(blk->id));
2137			if (alg_region) {
2138				if (version != alg_region->ver)
2139					cs_dsp_warn(dsp,
2140						    "Algorithm coefficient version %d.%d.%d but expected %d.%d.%d\n",
2141						   (version >> 16) & 0xFF,
2142						   (version >> 8) & 0xFF,
2143						   version & 0xFF,
2144						   (alg_region->ver >> 16) & 0xFF,
2145						   (alg_region->ver >> 8) & 0xFF,
2146						   alg_region->ver & 0xFF);
2147
2148				reg = alg_region->base;
2149				reg = dsp->ops->region_to_reg(mem, reg);
2150				reg += offset;
2151			} else {
2152				cs_dsp_err(dsp, "No %s for algorithm %x\n",
2153					   region_name, le32_to_cpu(blk->id));
2154			}
2155			break;
2156
2157		default:
2158			cs_dsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
2159				   file, blocks, type, pos);
2160			break;
2161		}
2162
2163		if (text) {
2164			memcpy(text, blk->data, le32_to_cpu(blk->len));
2165			cs_dsp_info(dsp, "%s: %s\n", dsp->fw_name, text);
2166			kfree(text);
2167			text = NULL;
2168		}
2169
2170		if (reg) {
2171			if (le32_to_cpu(blk->len) >
2172			    firmware->size - pos - sizeof(*blk)) {
2173				cs_dsp_err(dsp,
2174					   "%s.%d: %s region len %d bytes exceeds file length %zu\n",
2175					   file, blocks, region_name,
2176					   le32_to_cpu(blk->len),
2177					   firmware->size);
2178				ret = -EINVAL;
2179				goto out_fw;
2180			}
2181
2182			buf = cs_dsp_buf_alloc(blk->data,
2183					       le32_to_cpu(blk->len),
2184					       &buf_list);
2185			if (!buf) {
2186				cs_dsp_err(dsp, "Out of memory\n");
2187				ret = -ENOMEM;
2188				goto out_fw;
2189			}
2190
2191			cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
2192				   file, blocks, le32_to_cpu(blk->len),
2193				   reg);
2194			ret = regmap_raw_write_async(regmap, reg, buf->buf,
2195						     le32_to_cpu(blk->len));
2196			if (ret != 0) {
2197				cs_dsp_err(dsp,
2198					   "%s.%d: Failed to write to %x in %s: %d\n",
2199					   file, blocks, reg, region_name, ret);
2200			}
2201		}
2202
2203		pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
2204		blocks++;
2205	}
2206
2207	ret = regmap_async_complete(regmap);
2208	if (ret != 0)
2209		cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret);
2210
2211	if (pos > firmware->size)
2212		cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
2213			    file, blocks, pos - firmware->size);
2214
2215	cs_dsp_debugfs_save_binname(dsp, file);
2216
2217out_fw:
2218	regmap_async_complete(regmap);
2219	cs_dsp_buf_free(&buf_list);
2220	kfree(text);
2221	return ret;
2222}
2223
2224static int cs_dsp_create_name(struct cs_dsp *dsp)
2225{
2226	if (!dsp->name) {
2227		dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d",
2228					   dsp->num);
2229		if (!dsp->name)
2230			return -ENOMEM;
2231	}
2232
2233	return 0;
2234}
2235
2236static int cs_dsp_common_init(struct cs_dsp *dsp)
2237{
2238	int ret;
2239
2240	ret = cs_dsp_create_name(dsp);
2241	if (ret)
2242		return ret;
2243
2244	INIT_LIST_HEAD(&dsp->alg_regions);
2245	INIT_LIST_HEAD(&dsp->ctl_list);
2246
2247	mutex_init(&dsp->pwr_lock);
2248
2249	return 0;
2250}
2251
2252/**
2253 * cs_dsp_adsp1_init() - Initialise a cs_dsp structure representing a ADSP1 device
2254 * @dsp: pointer to DSP structure
2255 *
2256 * Return: Zero for success, a negative number on error.
2257 */
2258int cs_dsp_adsp1_init(struct cs_dsp *dsp)
2259{
2260	dsp->ops = &cs_dsp_adsp1_ops;
2261
2262	return cs_dsp_common_init(dsp);
2263}
2264EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_init, FW_CS_DSP);
2265
2266/**
2267 * cs_dsp_adsp1_power_up() - Load and start the named firmware
2268 * @dsp: pointer to DSP structure
2269 * @wmfw_firmware: the firmware to be sent
2270 * @wmfw_filename: file name of firmware to be sent
2271 * @coeff_firmware: the coefficient data to be sent
2272 * @coeff_filename: file name of coefficient to data be sent
2273 * @fw_name: the user-friendly firmware name
2274 *
2275 * Return: Zero for success, a negative number on error.
2276 */
2277int cs_dsp_adsp1_power_up(struct cs_dsp *dsp,
2278			  const struct firmware *wmfw_firmware, char *wmfw_filename,
2279			  const struct firmware *coeff_firmware, char *coeff_filename,
2280			  const char *fw_name)
2281{
2282	unsigned int val;
2283	int ret;
2284
2285	mutex_lock(&dsp->pwr_lock);
2286
2287	dsp->fw_name = fw_name;
2288
2289	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2290			   ADSP1_SYS_ENA, ADSP1_SYS_ENA);
2291
2292	/*
2293	 * For simplicity set the DSP clock rate to be the
2294	 * SYSCLK rate rather than making it configurable.
2295	 */
2296	if (dsp->sysclk_reg) {
2297		ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
2298		if (ret != 0) {
2299			cs_dsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
2300			goto err_mutex;
2301		}
2302
2303		val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift;
2304
2305		ret = regmap_update_bits(dsp->regmap,
2306					 dsp->base + ADSP1_CONTROL_31,
2307					 ADSP1_CLK_SEL_MASK, val);
2308		if (ret != 0) {
2309			cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret);
2310			goto err_mutex;
2311		}
2312	}
2313
2314	ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename);
2315	if (ret != 0)
2316		goto err_ena;
2317
2318	ret = cs_dsp_adsp1_setup_algs(dsp);
2319	if (ret != 0)
2320		goto err_ena;
2321
2322	ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename);
2323	if (ret != 0)
2324		goto err_ena;
2325
2326	/* Initialize caches for enabled and unset controls */
2327	ret = cs_dsp_coeff_init_control_caches(dsp);
2328	if (ret != 0)
2329		goto err_ena;
2330
2331	/* Sync set controls */
2332	ret = cs_dsp_coeff_sync_controls(dsp);
2333	if (ret != 0)
2334		goto err_ena;
2335
2336	dsp->booted = true;
2337
2338	/* Start the core running */
2339	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2340			   ADSP1_CORE_ENA | ADSP1_START,
2341			   ADSP1_CORE_ENA | ADSP1_START);
2342
2343	dsp->running = true;
2344
2345	mutex_unlock(&dsp->pwr_lock);
2346
2347	return 0;
2348
2349err_ena:
2350	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2351			   ADSP1_SYS_ENA, 0);
2352err_mutex:
2353	mutex_unlock(&dsp->pwr_lock);
2354	return ret;
2355}
2356EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_up, FW_CS_DSP);
2357
2358/**
2359 * cs_dsp_adsp1_power_down() - Halts the DSP
2360 * @dsp: pointer to DSP structure
2361 */
2362void cs_dsp_adsp1_power_down(struct cs_dsp *dsp)
2363{
2364	struct cs_dsp_coeff_ctl *ctl;
2365
2366	mutex_lock(&dsp->pwr_lock);
2367
2368	dsp->running = false;
2369	dsp->booted = false;
2370
2371	/* Halt the core */
2372	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2373			   ADSP1_CORE_ENA | ADSP1_START, 0);
2374
2375	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
2376			   ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
2377
2378	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2379			   ADSP1_SYS_ENA, 0);
2380
2381	list_for_each_entry(ctl, &dsp->ctl_list, list)
2382		ctl->enabled = 0;
2383
2384	cs_dsp_free_alg_regions(dsp);
2385
2386	mutex_unlock(&dsp->pwr_lock);
2387}
2388EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_down, FW_CS_DSP);
2389
2390static int cs_dsp_adsp2v2_enable_core(struct cs_dsp *dsp)
2391{
2392	unsigned int val;
2393	int ret, count;
2394
2395	/* Wait for the RAM to start, should be near instantaneous */
2396	for (count = 0; count < 10; ++count) {
2397		ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
2398		if (ret != 0)
2399			return ret;
2400
2401		if (val & ADSP2_RAM_RDY)
2402			break;
2403
2404		usleep_range(250, 500);
2405	}
2406
2407	if (!(val & ADSP2_RAM_RDY)) {
2408		cs_dsp_err(dsp, "Failed to start DSP RAM\n");
2409		return -EBUSY;
2410	}
2411
2412	cs_dsp_dbg(dsp, "RAM ready after %d polls\n", count);
2413
2414	return 0;
2415}
2416
2417static int cs_dsp_adsp2_enable_core(struct cs_dsp *dsp)
2418{
2419	int ret;
2420
2421	ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
2422				       ADSP2_SYS_ENA, ADSP2_SYS_ENA);
2423	if (ret != 0)
2424		return ret;
2425
2426	return cs_dsp_adsp2v2_enable_core(dsp);
2427}
2428
2429static int cs_dsp_adsp2_lock(struct cs_dsp *dsp, unsigned int lock_regions)
2430{
2431	struct regmap *regmap = dsp->regmap;
2432	unsigned int code0, code1, lock_reg;
2433
2434	if (!(lock_regions & CS_ADSP2_REGION_ALL))
2435		return 0;
2436
2437	lock_regions &= CS_ADSP2_REGION_ALL;
2438	lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0;
2439
2440	while (lock_regions) {
2441		code0 = code1 = 0;
2442		if (lock_regions & BIT(0)) {
2443			code0 = ADSP2_LOCK_CODE_0;
2444			code1 = ADSP2_LOCK_CODE_1;
2445		}
2446		if (lock_regions & BIT(1)) {
2447			code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT;
2448			code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT;
2449		}
2450		regmap_write(regmap, lock_reg, code0);
2451		regmap_write(regmap, lock_reg, code1);
2452		lock_regions >>= 2;
2453		lock_reg += 2;
2454	}
2455
2456	return 0;
2457}
2458
2459static int cs_dsp_adsp2_enable_memory(struct cs_dsp *dsp)
2460{
2461	return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2462				  ADSP2_MEM_ENA, ADSP2_MEM_ENA);
2463}
2464
2465static void cs_dsp_adsp2_disable_memory(struct cs_dsp *dsp)
2466{
2467	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2468			   ADSP2_MEM_ENA, 0);
2469}
2470
2471static void cs_dsp_adsp2_disable_core(struct cs_dsp *dsp)
2472{
2473	regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
2474	regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
2475	regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
2476
2477	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2478			   ADSP2_SYS_ENA, 0);
2479}
2480
2481static void cs_dsp_adsp2v2_disable_core(struct cs_dsp *dsp)
2482{
2483	regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
2484	regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
2485	regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
2486}
2487
2488static int cs_dsp_halo_configure_mpu(struct cs_dsp *dsp, unsigned int lock_regions)
2489{
2490	struct reg_sequence config[] = {
2491		{ dsp->base + HALO_MPU_LOCK_CONFIG,     0x5555 },
2492		{ dsp->base + HALO_MPU_LOCK_CONFIG,     0xAAAA },
2493		{ dsp->base + HALO_MPU_XMEM_ACCESS_0,   0xFFFFFFFF },
2494		{ dsp->base + HALO_MPU_YMEM_ACCESS_0,   0xFFFFFFFF },
2495		{ dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions },
2496		{ dsp->base + HALO_MPU_XREG_ACCESS_0,   lock_regions },
2497		{ dsp->base + HALO_MPU_YREG_ACCESS_0,   lock_regions },
2498		{ dsp->base + HALO_MPU_XMEM_ACCESS_1,   0xFFFFFFFF },
2499		{ dsp->base + HALO_MPU_YMEM_ACCESS_1,   0xFFFFFFFF },
2500		{ dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions },
2501		{ dsp->base + HALO_MPU_XREG_ACCESS_1,   lock_regions },
2502		{ dsp->base + HALO_MPU_YREG_ACCESS_1,   lock_regions },
2503		{ dsp->base + HALO_MPU_XMEM_ACCESS_2,   0xFFFFFFFF },
2504		{ dsp->base + HALO_MPU_YMEM_ACCESS_2,   0xFFFFFFFF },
2505		{ dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions },
2506		{ dsp->base + HALO_MPU_XREG_ACCESS_2,   lock_regions },
2507		{ dsp->base + HALO_MPU_YREG_ACCESS_2,   lock_regions },
2508		{ dsp->base + HALO_MPU_XMEM_ACCESS_3,   0xFFFFFFFF },
2509		{ dsp->base + HALO_MPU_YMEM_ACCESS_3,   0xFFFFFFFF },
2510		{ dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions },
2511		{ dsp->base + HALO_MPU_XREG_ACCESS_3,   lock_regions },
2512		{ dsp->base + HALO_MPU_YREG_ACCESS_3,   lock_regions },
2513		{ dsp->base + HALO_MPU_LOCK_CONFIG,     0 },
2514	};
2515
2516	return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config));
2517}
2518
2519/**
2520 * cs_dsp_set_dspclk() - Applies the given frequency to the given cs_dsp
2521 * @dsp: pointer to DSP structure
2522 * @freq: clock rate to set
2523 *
2524 * This is only for use on ADSP2 cores.
2525 *
2526 * Return: Zero for success, a negative number on error.
2527 */
2528int cs_dsp_set_dspclk(struct cs_dsp *dsp, unsigned int freq)
2529{
2530	int ret;
2531
2532	ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING,
2533				 ADSP2_CLK_SEL_MASK,
2534				 freq << ADSP2_CLK_SEL_SHIFT);
2535	if (ret)
2536		cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret);
2537
2538	return ret;
2539}
2540EXPORT_SYMBOL_NS_GPL(cs_dsp_set_dspclk, FW_CS_DSP);
2541
2542static void cs_dsp_stop_watchdog(struct cs_dsp *dsp)
2543{
2544	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
2545			   ADSP2_WDT_ENA_MASK, 0);
2546}
2547
2548static void cs_dsp_halo_stop_watchdog(struct cs_dsp *dsp)
2549{
2550	regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL,
2551			   HALO_WDT_EN_MASK, 0);
2552}
2553
2554/**
2555 * cs_dsp_power_up() - Downloads firmware to the DSP
2556 * @dsp: pointer to DSP structure
2557 * @wmfw_firmware: the firmware to be sent
2558 * @wmfw_filename: file name of firmware to be sent
2559 * @coeff_firmware: the coefficient data to be sent
2560 * @coeff_filename: file name of coefficient to data be sent
2561 * @fw_name: the user-friendly firmware name
2562 *
2563 * This function is used on ADSP2 and Halo DSP cores, it powers-up the DSP core
2564 * and downloads the firmware but does not start the firmware running. The
2565 * cs_dsp booted flag will be set once completed and if the core has a low-power
2566 * memory retention mode it will be put into this state after the firmware is
2567 * downloaded.
2568 *
2569 * Return: Zero for success, a negative number on error.
2570 */
2571int cs_dsp_power_up(struct cs_dsp *dsp,
2572		    const struct firmware *wmfw_firmware, char *wmfw_filename,
2573		    const struct firmware *coeff_firmware, char *coeff_filename,
2574		    const char *fw_name)
2575{
2576	int ret;
2577
2578	mutex_lock(&dsp->pwr_lock);
2579
2580	dsp->fw_name = fw_name;
2581
2582	if (dsp->ops->enable_memory) {
2583		ret = dsp->ops->enable_memory(dsp);
2584		if (ret != 0)
2585			goto err_mutex;
2586	}
2587
2588	if (dsp->ops->enable_core) {
2589		ret = dsp->ops->enable_core(dsp);
2590		if (ret != 0)
2591			goto err_mem;
2592	}
2593
2594	ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename);
2595	if (ret != 0)
2596		goto err_ena;
2597
2598	ret = dsp->ops->setup_algs(dsp);
2599	if (ret != 0)
2600		goto err_ena;
2601
2602	ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename);
2603	if (ret != 0)
2604		goto err_ena;
2605
2606	/* Initialize caches for enabled and unset controls */
2607	ret = cs_dsp_coeff_init_control_caches(dsp);
2608	if (ret != 0)
2609		goto err_ena;
2610
2611	if (dsp->ops->disable_core)
2612		dsp->ops->disable_core(dsp);
2613
2614	dsp->booted = true;
2615
2616	mutex_unlock(&dsp->pwr_lock);
2617
2618	return 0;
2619err_ena:
2620	if (dsp->ops->disable_core)
2621		dsp->ops->disable_core(dsp);
2622err_mem:
2623	if (dsp->ops->disable_memory)
2624		dsp->ops->disable_memory(dsp);
2625err_mutex:
2626	mutex_unlock(&dsp->pwr_lock);
2627
2628	return ret;
2629}
2630EXPORT_SYMBOL_NS_GPL(cs_dsp_power_up, FW_CS_DSP);
2631
2632/**
2633 * cs_dsp_power_down() - Powers-down the DSP
2634 * @dsp: pointer to DSP structure
2635 *
2636 * cs_dsp_stop() must have been called before this function. The core will be
2637 * fully powered down and so the memory will not be retained.
2638 */
2639void cs_dsp_power_down(struct cs_dsp *dsp)
2640{
2641	struct cs_dsp_coeff_ctl *ctl;
2642
2643	mutex_lock(&dsp->pwr_lock);
2644
2645	cs_dsp_debugfs_clear(dsp);
2646
2647	dsp->fw_id = 0;
2648	dsp->fw_id_version = 0;
2649
2650	dsp->booted = false;
2651
2652	if (dsp->ops->disable_memory)
2653		dsp->ops->disable_memory(dsp);
2654
2655	list_for_each_entry(ctl, &dsp->ctl_list, list)
2656		ctl->enabled = 0;
2657
2658	cs_dsp_free_alg_regions(dsp);
2659
2660	mutex_unlock(&dsp->pwr_lock);
2661
2662	cs_dsp_dbg(dsp, "Shutdown complete\n");
2663}
2664EXPORT_SYMBOL_NS_GPL(cs_dsp_power_down, FW_CS_DSP);
2665
2666static int cs_dsp_adsp2_start_core(struct cs_dsp *dsp)
2667{
2668	return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2669				  ADSP2_CORE_ENA | ADSP2_START,
2670				  ADSP2_CORE_ENA | ADSP2_START);
2671}
2672
2673static void cs_dsp_adsp2_stop_core(struct cs_dsp *dsp)
2674{
2675	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2676			   ADSP2_CORE_ENA | ADSP2_START, 0);
2677}
2678
2679/**
2680 * cs_dsp_run() - Starts the firmware running
2681 * @dsp: pointer to DSP structure
2682 *
2683 * cs_dsp_power_up() must have previously been called successfully.
2684 *
2685 * Return: Zero for success, a negative number on error.
2686 */
2687int cs_dsp_run(struct cs_dsp *dsp)
2688{
2689	int ret;
2690
2691	mutex_lock(&dsp->pwr_lock);
2692
2693	if (!dsp->booted) {
2694		ret = -EIO;
2695		goto err;
2696	}
2697
2698	if (dsp->ops->enable_core) {
2699		ret = dsp->ops->enable_core(dsp);
2700		if (ret != 0)
2701			goto err;
2702	}
2703
2704	if (dsp->client_ops->pre_run) {
2705		ret = dsp->client_ops->pre_run(dsp);
2706		if (ret)
2707			goto err;
2708	}
2709
2710	/* Sync set controls */
2711	ret = cs_dsp_coeff_sync_controls(dsp);
2712	if (ret != 0)
2713		goto err;
2714
2715	if (dsp->ops->lock_memory) {
2716		ret = dsp->ops->lock_memory(dsp, dsp->lock_regions);
2717		if (ret != 0) {
2718			cs_dsp_err(dsp, "Error configuring MPU: %d\n", ret);
2719			goto err;
2720		}
2721	}
2722
2723	if (dsp->ops->start_core) {
2724		ret = dsp->ops->start_core(dsp);
2725		if (ret != 0)
2726			goto err;
2727	}
2728
2729	dsp->running = true;
2730
2731	if (dsp->client_ops->post_run) {
2732		ret = dsp->client_ops->post_run(dsp);
2733		if (ret)
2734			goto err;
2735	}
2736
2737	mutex_unlock(&dsp->pwr_lock);
2738
2739	return 0;
2740
2741err:
2742	if (dsp->ops->stop_core)
2743		dsp->ops->stop_core(dsp);
2744	if (dsp->ops->disable_core)
2745		dsp->ops->disable_core(dsp);
2746	mutex_unlock(&dsp->pwr_lock);
2747
2748	return ret;
2749}
2750EXPORT_SYMBOL_NS_GPL(cs_dsp_run, FW_CS_DSP);
2751
2752/**
2753 * cs_dsp_stop() - Stops the firmware
2754 * @dsp: pointer to DSP structure
2755 *
2756 * Memory will not be disabled so firmware will remain loaded.
2757 */
2758void cs_dsp_stop(struct cs_dsp *dsp)
2759{
2760	/* Tell the firmware to cleanup */
2761	cs_dsp_signal_event_controls(dsp, CS_DSP_FW_EVENT_SHUTDOWN);
2762
2763	if (dsp->ops->stop_watchdog)
2764		dsp->ops->stop_watchdog(dsp);
2765
2766	/* Log firmware state, it can be useful for analysis */
2767	if (dsp->ops->show_fw_status)
2768		dsp->ops->show_fw_status(dsp);
2769
2770	mutex_lock(&dsp->pwr_lock);
2771
2772	if (dsp->client_ops->pre_stop)
2773		dsp->client_ops->pre_stop(dsp);
2774
2775	dsp->running = false;
2776
2777	if (dsp->ops->stop_core)
2778		dsp->ops->stop_core(dsp);
2779	if (dsp->ops->disable_core)
2780		dsp->ops->disable_core(dsp);
2781
2782	if (dsp->client_ops->post_stop)
2783		dsp->client_ops->post_stop(dsp);
2784
2785	mutex_unlock(&dsp->pwr_lock);
2786
2787	cs_dsp_dbg(dsp, "Execution stopped\n");
2788}
2789EXPORT_SYMBOL_NS_GPL(cs_dsp_stop, FW_CS_DSP);
2790
2791static int cs_dsp_halo_start_core(struct cs_dsp *dsp)
2792{
2793	int ret;
2794
2795	ret = regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
2796				 HALO_CORE_RESET | HALO_CORE_EN,
2797				 HALO_CORE_RESET | HALO_CORE_EN);
2798	if (ret)
2799		return ret;
2800
2801	return regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
2802				  HALO_CORE_RESET, 0);
2803}
2804
2805static void cs_dsp_halo_stop_core(struct cs_dsp *dsp)
2806{
2807	regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
2808			   HALO_CORE_EN, 0);
2809
2810	/* reset halo core with CORE_SOFT_RESET */
2811	regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET,
2812			   HALO_CORE_SOFT_RESET_MASK, 1);
2813}
2814
2815/**
2816 * cs_dsp_adsp2_init() - Initialise a cs_dsp structure representing a ADSP2 core
2817 * @dsp: pointer to DSP structure
2818 *
2819 * Return: Zero for success, a negative number on error.
2820 */
2821int cs_dsp_adsp2_init(struct cs_dsp *dsp)
2822{
2823	int ret;
2824
2825	switch (dsp->rev) {
2826	case 0:
2827		/*
2828		 * Disable the DSP memory by default when in reset for a small
2829		 * power saving.
2830		 */
2831		ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2832					 ADSP2_MEM_ENA, 0);
2833		if (ret) {
2834			cs_dsp_err(dsp,
2835				   "Failed to clear memory retention: %d\n", ret);
2836			return ret;
2837		}
2838
2839		dsp->ops = &cs_dsp_adsp2_ops[0];
2840		break;
2841	case 1:
2842		dsp->ops = &cs_dsp_adsp2_ops[1];
2843		break;
2844	default:
2845		dsp->ops = &cs_dsp_adsp2_ops[2];
2846		break;
2847	}
2848
2849	return cs_dsp_common_init(dsp);
2850}
2851EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_init, FW_CS_DSP);
2852
2853/**
2854 * cs_dsp_halo_init() - Initialise a cs_dsp structure representing a HALO Core DSP
2855 * @dsp: pointer to DSP structure
2856 *
2857 * Return: Zero for success, a negative number on error.
2858 */
2859int cs_dsp_halo_init(struct cs_dsp *dsp)
2860{
2861	if (dsp->no_core_startstop)
2862		dsp->ops = &cs_dsp_halo_ao_ops;
2863	else
2864		dsp->ops = &cs_dsp_halo_ops;
2865
2866	return cs_dsp_common_init(dsp);
2867}
2868EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_init, FW_CS_DSP);
2869
2870/**
2871 * cs_dsp_remove() - Clean a cs_dsp before deletion
2872 * @dsp: pointer to DSP structure
2873 */
2874void cs_dsp_remove(struct cs_dsp *dsp)
2875{
2876	struct cs_dsp_coeff_ctl *ctl;
2877
2878	while (!list_empty(&dsp->ctl_list)) {
2879		ctl = list_first_entry(&dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
2880
2881		if (dsp->client_ops->control_remove)
2882			dsp->client_ops->control_remove(ctl);
2883
2884		list_del(&ctl->list);
2885		cs_dsp_free_ctl_blk(ctl);
2886	}
2887}
2888EXPORT_SYMBOL_NS_GPL(cs_dsp_remove, FW_CS_DSP);
2889
2890/**
2891 * cs_dsp_read_raw_data_block() - Reads a block of data from DSP memory
2892 * @dsp: pointer to DSP structure
2893 * @mem_type: the type of DSP memory containing the data to be read
2894 * @mem_addr: the address of the data within the memory region
2895 * @num_words: the length of the data to read
2896 * @data: a buffer to store the fetched data
2897 *
2898 * If this is used to read unpacked 24-bit memory, each 24-bit DSP word will
2899 * occupy 32-bits in data (MSbyte will be 0). This padding can be removed using
2900 * cs_dsp_remove_padding()
2901 *
2902 * Return: Zero for success, a negative number on error.
2903 */
2904int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr,
2905			       unsigned int num_words, __be32 *data)
2906{
2907	struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type);
2908	unsigned int reg;
2909	int ret;
2910
2911	lockdep_assert_held(&dsp->pwr_lock);
2912
2913	if (!mem)
2914		return -EINVAL;
2915
2916	reg = dsp->ops->region_to_reg(mem, mem_addr);
2917
2918	ret = regmap_raw_read(dsp->regmap, reg, data,
2919			      sizeof(*data) * num_words);
2920	if (ret < 0)
2921		return ret;
2922
2923	return 0;
2924}
2925EXPORT_SYMBOL_NS_GPL(cs_dsp_read_raw_data_block, FW_CS_DSP);
2926
2927/**
2928 * cs_dsp_read_data_word() - Reads a word from DSP memory
2929 * @dsp: pointer to DSP structure
2930 * @mem_type: the type of DSP memory containing the data to be read
2931 * @mem_addr: the address of the data within the memory region
2932 * @data: a buffer to store the fetched data
2933 *
2934 * Return: Zero for success, a negative number on error.
2935 */
2936int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 *data)
2937{
2938	__be32 raw;
2939	int ret;
2940
2941	ret = cs_dsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw);
2942	if (ret < 0)
2943		return ret;
2944
2945	*data = be32_to_cpu(raw) & 0x00ffffffu;
2946
2947	return 0;
2948}
2949EXPORT_SYMBOL_NS_GPL(cs_dsp_read_data_word, FW_CS_DSP);
2950
2951/**
2952 * cs_dsp_write_data_word() - Writes a word to DSP memory
2953 * @dsp: pointer to DSP structure
2954 * @mem_type: the type of DSP memory containing the data to be written
2955 * @mem_addr: the address of the data within the memory region
2956 * @data: the data to be written
2957 *
2958 * Return: Zero for success, a negative number on error.
2959 */
2960int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 data)
2961{
2962	struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type);
2963	__be32 val = cpu_to_be32(data & 0x00ffffffu);
2964	unsigned int reg;
2965
2966	lockdep_assert_held(&dsp->pwr_lock);
2967
2968	if (!mem)
2969		return -EINVAL;
2970
2971	reg = dsp->ops->region_to_reg(mem, mem_addr);
2972
2973	return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
2974}
2975EXPORT_SYMBOL_NS_GPL(cs_dsp_write_data_word, FW_CS_DSP);
2976
2977/**
2978 * cs_dsp_remove_padding() - Convert unpacked words to packed bytes
2979 * @buf: buffer containing DSP words read from DSP memory
2980 * @nwords: number of words to convert
2981 *
2982 * DSP words from the register map have pad bytes and the data bytes
2983 * are in swapped order. This swaps to the native endian order and
2984 * strips the pad bytes.
2985 */
2986void cs_dsp_remove_padding(u32 *buf, int nwords)
2987{
2988	const __be32 *pack_in = (__be32 *)buf;
2989	u8 *pack_out = (u8 *)buf;
2990	int i;
2991
2992	for (i = 0; i < nwords; i++) {
2993		u32 word = be32_to_cpu(*pack_in++);
2994		*pack_out++ = (u8)word;
2995		*pack_out++ = (u8)(word >> 8);
2996		*pack_out++ = (u8)(word >> 16);
2997	}
2998}
2999EXPORT_SYMBOL_NS_GPL(cs_dsp_remove_padding, FW_CS_DSP);
3000
3001/**
3002 * cs_dsp_adsp2_bus_error() - Handle a DSP bus error interrupt
3003 * @dsp: pointer to DSP structure
3004 *
3005 * The firmware and DSP state will be logged for future analysis.
3006 */
3007void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp)
3008{
3009	unsigned int val;
3010	struct regmap *regmap = dsp->regmap;
3011	int ret = 0;
3012
3013	mutex_lock(&dsp->pwr_lock);
3014
3015	ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val);
3016	if (ret) {
3017		cs_dsp_err(dsp,
3018			   "Failed to read Region Lock Ctrl register: %d\n", ret);
3019		goto error;
3020	}
3021
3022	if (val & ADSP2_WDT_TIMEOUT_STS_MASK) {
3023		cs_dsp_err(dsp, "watchdog timeout error\n");
3024		dsp->ops->stop_watchdog(dsp);
3025		if (dsp->client_ops->watchdog_expired)
3026			dsp->client_ops->watchdog_expired(dsp);
3027	}
3028
3029	if (val & (ADSP2_ADDR_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) {
3030		if (val & ADSP2_ADDR_ERR_MASK)
3031			cs_dsp_err(dsp, "bus error: address error\n");
3032		else
3033			cs_dsp_err(dsp, "bus error: region lock error\n");
3034
3035		ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val);
3036		if (ret) {
3037			cs_dsp_err(dsp,
3038				   "Failed to read Bus Err Addr register: %d\n",
3039				   ret);
3040			goto error;
3041		}
3042
3043		cs_dsp_err(dsp, "bus error address = 0x%x\n",
3044			   val & ADSP2_BUS_ERR_ADDR_MASK);
3045
3046		ret = regmap_read(regmap,
3047				  dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR,
3048				  &val);
3049		if (ret) {
3050			cs_dsp_err(dsp,
3051				   "Failed to read Pmem Xmem Err Addr register: %d\n",
3052				   ret);
3053			goto error;
3054		}
3055
3056		cs_dsp_err(dsp, "xmem error address = 0x%x\n",
3057			   val & ADSP2_XMEM_ERR_ADDR_MASK);
3058		cs_dsp_err(dsp, "pmem error address = 0x%x\n",
3059			   (val & ADSP2_PMEM_ERR_ADDR_MASK) >>
3060			   ADSP2_PMEM_ERR_ADDR_SHIFT);
3061	}
3062
3063	regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL,
3064			   ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT);
3065
3066error:
3067	mutex_unlock(&dsp->pwr_lock);
3068}
3069EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_bus_error, FW_CS_DSP);
3070
3071/**
3072 * cs_dsp_halo_bus_error() - Handle a DSP bus error interrupt
3073 * @dsp: pointer to DSP structure
3074 *
3075 * The firmware and DSP state will be logged for future analysis.
3076 */
3077void cs_dsp_halo_bus_error(struct cs_dsp *dsp)
3078{
3079	struct regmap *regmap = dsp->regmap;
3080	unsigned int fault[6];
3081	struct reg_sequence clear[] = {
3082		{ dsp->base + HALO_MPU_XM_VIO_STATUS,     0x0 },
3083		{ dsp->base + HALO_MPU_YM_VIO_STATUS,     0x0 },
3084		{ dsp->base + HALO_MPU_PM_VIO_STATUS,     0x0 },
3085	};
3086	int ret;
3087
3088	mutex_lock(&dsp->pwr_lock);
3089
3090	ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1,
3091			  fault);
3092	if (ret) {
3093		cs_dsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret);
3094		goto exit_unlock;
3095	}
3096
3097	cs_dsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n",
3098		    *fault & HALO_AHBM_FLAGS_ERR_MASK,
3099		    (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >>
3100		    HALO_AHBM_CORE_ERR_ADDR_SHIFT);
3101
3102	ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0,
3103			  fault);
3104	if (ret) {
3105		cs_dsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret);
3106		goto exit_unlock;
3107	}
3108
3109	cs_dsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault);
3110
3111	ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR,
3112			       fault, ARRAY_SIZE(fault));
3113	if (ret) {
3114		cs_dsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret);
3115		goto exit_unlock;
3116	}
3117
3118	cs_dsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]);
3119	cs_dsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]);
3120	cs_dsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]);
3121
3122	ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear));
3123	if (ret)
3124		cs_dsp_warn(dsp, "Failed to clear MPU status: %d\n", ret);
3125
3126exit_unlock:
3127	mutex_unlock(&dsp->pwr_lock);
3128}
3129EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_bus_error, FW_CS_DSP);
3130
3131/**
3132 * cs_dsp_halo_wdt_expire() - Handle DSP watchdog expiry
3133 * @dsp: pointer to DSP structure
3134 *
3135 * This is logged for future analysis.
3136 */
3137void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp)
3138{
3139	mutex_lock(&dsp->pwr_lock);
3140
3141	cs_dsp_warn(dsp, "WDT Expiry Fault\n");
3142
3143	dsp->ops->stop_watchdog(dsp);
3144	if (dsp->client_ops->watchdog_expired)
3145		dsp->client_ops->watchdog_expired(dsp);
3146
3147	mutex_unlock(&dsp->pwr_lock);
3148}
3149EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_wdt_expire, FW_CS_DSP);
3150
3151static const struct cs_dsp_ops cs_dsp_adsp1_ops = {
3152	.validate_version = cs_dsp_validate_version,
3153	.parse_sizes = cs_dsp_adsp1_parse_sizes,
3154	.region_to_reg = cs_dsp_region_to_reg,
3155};
3156
3157static const struct cs_dsp_ops cs_dsp_adsp2_ops[] = {
3158	{
3159		.parse_sizes = cs_dsp_adsp2_parse_sizes,
3160		.validate_version = cs_dsp_validate_version,
3161		.setup_algs = cs_dsp_adsp2_setup_algs,
3162		.region_to_reg = cs_dsp_region_to_reg,
3163
3164		.show_fw_status = cs_dsp_adsp2_show_fw_status,
3165
3166		.enable_memory = cs_dsp_adsp2_enable_memory,
3167		.disable_memory = cs_dsp_adsp2_disable_memory,
3168
3169		.enable_core = cs_dsp_adsp2_enable_core,
3170		.disable_core = cs_dsp_adsp2_disable_core,
3171
3172		.start_core = cs_dsp_adsp2_start_core,
3173		.stop_core = cs_dsp_adsp2_stop_core,
3174
3175	},
3176	{
3177		.parse_sizes = cs_dsp_adsp2_parse_sizes,
3178		.validate_version = cs_dsp_validate_version,
3179		.setup_algs = cs_dsp_adsp2_setup_algs,
3180		.region_to_reg = cs_dsp_region_to_reg,
3181
3182		.show_fw_status = cs_dsp_adsp2v2_show_fw_status,
3183
3184		.enable_memory = cs_dsp_adsp2_enable_memory,
3185		.disable_memory = cs_dsp_adsp2_disable_memory,
3186		.lock_memory = cs_dsp_adsp2_lock,
3187
3188		.enable_core = cs_dsp_adsp2v2_enable_core,
3189		.disable_core = cs_dsp_adsp2v2_disable_core,
3190
3191		.start_core = cs_dsp_adsp2_start_core,
3192		.stop_core = cs_dsp_adsp2_stop_core,
3193	},
3194	{
3195		.parse_sizes = cs_dsp_adsp2_parse_sizes,
3196		.validate_version = cs_dsp_validate_version,
3197		.setup_algs = cs_dsp_adsp2_setup_algs,
3198		.region_to_reg = cs_dsp_region_to_reg,
3199
3200		.show_fw_status = cs_dsp_adsp2v2_show_fw_status,
3201		.stop_watchdog = cs_dsp_stop_watchdog,
3202
3203		.enable_memory = cs_dsp_adsp2_enable_memory,
3204		.disable_memory = cs_dsp_adsp2_disable_memory,
3205		.lock_memory = cs_dsp_adsp2_lock,
3206
3207		.enable_core = cs_dsp_adsp2v2_enable_core,
3208		.disable_core = cs_dsp_adsp2v2_disable_core,
3209
3210		.start_core = cs_dsp_adsp2_start_core,
3211		.stop_core = cs_dsp_adsp2_stop_core,
3212	},
3213};
3214
3215static const struct cs_dsp_ops cs_dsp_halo_ops = {
3216	.parse_sizes = cs_dsp_adsp2_parse_sizes,
3217	.validate_version = cs_dsp_halo_validate_version,
3218	.setup_algs = cs_dsp_halo_setup_algs,
3219	.region_to_reg = cs_dsp_halo_region_to_reg,
3220
3221	.show_fw_status = cs_dsp_halo_show_fw_status,
3222	.stop_watchdog = cs_dsp_halo_stop_watchdog,
3223
3224	.lock_memory = cs_dsp_halo_configure_mpu,
3225
3226	.start_core = cs_dsp_halo_start_core,
3227	.stop_core = cs_dsp_halo_stop_core,
3228};
3229
3230static const struct cs_dsp_ops cs_dsp_halo_ao_ops = {
3231	.parse_sizes = cs_dsp_adsp2_parse_sizes,
3232	.validate_version = cs_dsp_halo_validate_version,
3233	.setup_algs = cs_dsp_halo_setup_algs,
3234	.region_to_reg = cs_dsp_halo_region_to_reg,
3235	.show_fw_status = cs_dsp_halo_show_fw_status,
3236};
3237
3238/**
3239 * cs_dsp_chunk_write() - Format data to a DSP memory chunk
3240 * @ch: Pointer to the chunk structure
3241 * @nbits: Number of bits to write
3242 * @val: Value to write
3243 *
3244 * This function sequentially writes values into the format required for DSP
3245 * memory, it handles both inserting of the padding bytes and converting to
3246 * big endian. Note that data is only committed to the chunk when a whole DSP
3247 * words worth of data is available.
3248 *
3249 * Return: Zero for success, a negative number on error.
3250 */
3251int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val)
3252{
3253	int nwrite, i;
3254
3255	nwrite = min(CS_DSP_DATA_WORD_BITS - ch->cachebits, nbits);
3256
3257	ch->cache <<= nwrite;
3258	ch->cache |= val >> (nbits - nwrite);
3259	ch->cachebits += nwrite;
3260	nbits -= nwrite;
3261
3262	if (ch->cachebits == CS_DSP_DATA_WORD_BITS) {
3263		if (cs_dsp_chunk_end(ch))
3264			return -ENOSPC;
3265
3266		ch->cache &= 0xFFFFFF;
3267		for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE)
3268			*ch->data++ = (ch->cache & 0xFF000000) >> CS_DSP_DATA_WORD_BITS;
3269
3270		ch->bytes += sizeof(ch->cache);
3271		ch->cachebits = 0;
3272	}
3273
3274	if (nbits)
3275		return cs_dsp_chunk_write(ch, nbits, val);
3276
3277	return 0;
3278}
3279EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_write, FW_CS_DSP);
3280
3281/**
3282 * cs_dsp_chunk_flush() - Pad remaining data with zero and commit to chunk
3283 * @ch: Pointer to the chunk structure
3284 *
3285 * As cs_dsp_chunk_write only writes data when a whole DSP word is ready to
3286 * be written out it is possible that some data will remain in the cache, this
3287 * function will pad that data with zeros upto a whole DSP word and write out.
3288 *
3289 * Return: Zero for success, a negative number on error.
3290 */
3291int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch)
3292{
3293	if (!ch->cachebits)
3294		return 0;
3295
3296	return cs_dsp_chunk_write(ch, CS_DSP_DATA_WORD_BITS - ch->cachebits, 0);
3297}
3298EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_flush, FW_CS_DSP);
3299
3300/**
3301 * cs_dsp_chunk_read() - Parse data from a DSP memory chunk
3302 * @ch: Pointer to the chunk structure
3303 * @nbits: Number of bits to read
3304 *
3305 * This function sequentially reads values from a DSP memory formatted buffer,
3306 * it handles both removing of the padding bytes and converting from big endian.
3307 *
3308 * Return: A negative number is returned on error, otherwise the read value.
3309 */
3310int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits)
3311{
3312	int nread, i;
3313	u32 result;
3314
3315	if (!ch->cachebits) {
3316		if (cs_dsp_chunk_end(ch))
3317			return -ENOSPC;
3318
3319		ch->cache = 0;
3320		ch->cachebits = CS_DSP_DATA_WORD_BITS;
3321
3322		for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE)
3323			ch->cache |= *ch->data++;
3324
3325		ch->bytes += sizeof(ch->cache);
3326	}
3327
3328	nread = min(ch->cachebits, nbits);
3329	nbits -= nread;
3330
3331	result = ch->cache >> ((sizeof(ch->cache) * BITS_PER_BYTE) - nread);
3332	ch->cache <<= nread;
3333	ch->cachebits -= nread;
3334
3335	if (nbits)
3336		result = (result << nbits) | cs_dsp_chunk_read(ch, nbits);
3337
3338	return result;
3339}
3340EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_read, FW_CS_DSP);
3341
3342MODULE_DESCRIPTION("Cirrus Logic DSP Support");
3343MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
3344MODULE_LICENSE("GPL v2");