cachepc-linux

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

cs_dsp.c (84252B)


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