File Index
Files and directories
Sign in
FILE

cs_dsp.c

File preview with syntax highlighting.

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