Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * cs_dsp.c  --  Cirrus Logic DSP firmware support
0004  *
0005  * Based on sound/soc/codecs/wm_adsp.c
0006  *
0007  * Copyright 2012 Wolfson Microelectronics plc
0008  * Copyright (C) 2015-2021 Cirrus Logic, Inc. and
0009  *                         Cirrus Logic International Semiconductor Ltd.
0010  */
0011 
0012 #include <linux/ctype.h>
0013 #include <linux/debugfs.h>
0014 #include <linux/delay.h>
0015 #include <linux/module.h>
0016 #include <linux/moduleparam.h>
0017 #include <linux/slab.h>
0018 #include <linux/vmalloc.h>
0019 
0020 #include <linux/firmware/cirrus/cs_dsp.h>
0021 #include <linux/firmware/cirrus/wmfw.h>
0022 
0023 #define cs_dsp_err(_dsp, fmt, ...) \
0024     dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
0025 #define cs_dsp_warn(_dsp, fmt, ...) \
0026     dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
0027 #define cs_dsp_info(_dsp, fmt, ...) \
0028     dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
0029 #define cs_dsp_dbg(_dsp, fmt, ...) \
0030     dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
0031 
0032 #define ADSP1_CONTROL_1                   0x00
0033 #define ADSP1_CONTROL_2                   0x02
0034 #define ADSP1_CONTROL_3                   0x03
0035 #define ADSP1_CONTROL_4                   0x04
0036 #define ADSP1_CONTROL_5                   0x06
0037 #define ADSP1_CONTROL_6                   0x07
0038 #define ADSP1_CONTROL_7                   0x08
0039 #define ADSP1_CONTROL_8                   0x09
0040 #define ADSP1_CONTROL_9                   0x0A
0041 #define ADSP1_CONTROL_10                  0x0B
0042 #define ADSP1_CONTROL_11                  0x0C
0043 #define ADSP1_CONTROL_12                  0x0D
0044 #define ADSP1_CONTROL_13                  0x0F
0045 #define ADSP1_CONTROL_14                  0x10
0046 #define ADSP1_CONTROL_15                  0x11
0047 #define ADSP1_CONTROL_16                  0x12
0048 #define ADSP1_CONTROL_17                  0x13
0049 #define ADSP1_CONTROL_18                  0x14
0050 #define ADSP1_CONTROL_19                  0x16
0051 #define ADSP1_CONTROL_20                  0x17
0052 #define ADSP1_CONTROL_21                  0x18
0053 #define ADSP1_CONTROL_22                  0x1A
0054 #define ADSP1_CONTROL_23                  0x1B
0055 #define ADSP1_CONTROL_24                  0x1C
0056 #define ADSP1_CONTROL_25                  0x1E
0057 #define ADSP1_CONTROL_26                  0x20
0058 #define ADSP1_CONTROL_27                  0x21
0059 #define ADSP1_CONTROL_28                  0x22
0060 #define ADSP1_CONTROL_29                  0x23
0061 #define ADSP1_CONTROL_30                  0x24
0062 #define ADSP1_CONTROL_31                  0x26
0063 
0064 /*
0065  * ADSP1 Control 19
0066  */
0067 #define ADSP1_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
0068 #define ADSP1_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
0069 #define ADSP1_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
0070 
0071 /*
0072  * ADSP1 Control 30
0073  */
0074 #define ADSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
0075 #define ADSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
0076 #define ADSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
0077 #define ADSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
0078 #define ADSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
0079 #define ADSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
0080 #define ADSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
0081 #define ADSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
0082 #define ADSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
0083 #define ADSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
0084 #define ADSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
0085 #define ADSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
0086 #define ADSP1_START                       0x0001  /* DSP1_START */
0087 #define ADSP1_START_MASK                  0x0001  /* DSP1_START */
0088 #define ADSP1_START_SHIFT                      0  /* DSP1_START */
0089 #define ADSP1_START_WIDTH                      1  /* DSP1_START */
0090 
0091 /*
0092  * ADSP1 Control 31
0093  */
0094 #define ADSP1_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
0095 #define ADSP1_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
0096 #define ADSP1_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
0097 
0098 #define ADSP2_CONTROL                     0x0
0099 #define ADSP2_CLOCKING                    0x1
0100 #define ADSP2V2_CLOCKING                  0x2
0101 #define ADSP2_STATUS1                     0x4
0102 #define ADSP2_WDMA_CONFIG_1               0x30
0103 #define ADSP2_WDMA_CONFIG_2               0x31
0104 #define ADSP2V2_WDMA_CONFIG_2             0x32
0105 #define ADSP2_RDMA_CONFIG_1               0x34
0106 
0107 #define ADSP2_SCRATCH0                    0x40
0108 #define ADSP2_SCRATCH1                    0x41
0109 #define ADSP2_SCRATCH2                    0x42
0110 #define ADSP2_SCRATCH3                    0x43
0111 
0112 #define ADSP2V2_SCRATCH0_1                0x40
0113 #define ADSP2V2_SCRATCH2_3                0x42
0114 
0115 /*
0116  * ADSP2 Control
0117  */
0118 #define ADSP2_MEM_ENA                     0x0010  /* DSP1_MEM_ENA */
0119 #define ADSP2_MEM_ENA_MASK                0x0010  /* DSP1_MEM_ENA */
0120 #define ADSP2_MEM_ENA_SHIFT                    4  /* DSP1_MEM_ENA */
0121 #define ADSP2_MEM_ENA_WIDTH                    1  /* DSP1_MEM_ENA */
0122 #define ADSP2_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
0123 #define ADSP2_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
0124 #define ADSP2_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
0125 #define ADSP2_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
0126 #define ADSP2_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
0127 #define ADSP2_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
0128 #define ADSP2_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
0129 #define ADSP2_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
0130 #define ADSP2_START                       0x0001  /* DSP1_START */
0131 #define ADSP2_START_MASK                  0x0001  /* DSP1_START */
0132 #define ADSP2_START_SHIFT                      0  /* DSP1_START */
0133 #define ADSP2_START_WIDTH                      1  /* DSP1_START */
0134 
0135 /*
0136  * ADSP2 clocking
0137  */
0138 #define ADSP2_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
0139 #define ADSP2_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
0140 #define ADSP2_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
0141 
0142 /*
0143  * ADSP2V2 clocking
0144  */
0145 #define ADSP2V2_CLK_SEL_MASK             0x70000  /* CLK_SEL_ENA */
0146 #define ADSP2V2_CLK_SEL_SHIFT                 16  /* CLK_SEL_ENA */
0147 #define ADSP2V2_CLK_SEL_WIDTH                  3  /* CLK_SEL_ENA */
0148 
0149 #define ADSP2V2_RATE_MASK                 0x7800  /* DSP_RATE */
0150 #define ADSP2V2_RATE_SHIFT                    11  /* DSP_RATE */
0151 #define ADSP2V2_RATE_WIDTH                     4  /* DSP_RATE */
0152 
0153 /*
0154  * ADSP2 Status 1
0155  */
0156 #define ADSP2_RAM_RDY                     0x0001
0157 #define ADSP2_RAM_RDY_MASK                0x0001
0158 #define ADSP2_RAM_RDY_SHIFT                    0
0159 #define ADSP2_RAM_RDY_WIDTH                    1
0160 
0161 /*
0162  * ADSP2 Lock support
0163  */
0164 #define ADSP2_LOCK_CODE_0                    0x5555
0165 #define ADSP2_LOCK_CODE_1                    0xAAAA
0166 
0167 #define ADSP2_WATCHDOG                       0x0A
0168 #define ADSP2_BUS_ERR_ADDR                   0x52
0169 #define ADSP2_REGION_LOCK_STATUS             0x64
0170 #define ADSP2_LOCK_REGION_1_LOCK_REGION_0    0x66
0171 #define ADSP2_LOCK_REGION_3_LOCK_REGION_2    0x68
0172 #define ADSP2_LOCK_REGION_5_LOCK_REGION_4    0x6A
0173 #define ADSP2_LOCK_REGION_7_LOCK_REGION_6    0x6C
0174 #define ADSP2_LOCK_REGION_9_LOCK_REGION_8    0x6E
0175 #define ADSP2_LOCK_REGION_CTRL               0x7A
0176 #define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR    0x7C
0177 
0178 #define ADSP2_REGION_LOCK_ERR_MASK           0x8000
0179 #define ADSP2_ADDR_ERR_MASK                  0x4000
0180 #define ADSP2_WDT_TIMEOUT_STS_MASK           0x2000
0181 #define ADSP2_CTRL_ERR_PAUSE_ENA             0x0002
0182 #define ADSP2_CTRL_ERR_EINT                  0x0001
0183 
0184 #define ADSP2_BUS_ERR_ADDR_MASK              0x00FFFFFF
0185 #define ADSP2_XMEM_ERR_ADDR_MASK             0x0000FFFF
0186 #define ADSP2_PMEM_ERR_ADDR_MASK             0x7FFF0000
0187 #define ADSP2_PMEM_ERR_ADDR_SHIFT            16
0188 #define ADSP2_WDT_ENA_MASK                   0xFFFFFFFD
0189 
0190 #define ADSP2_LOCK_REGION_SHIFT              16
0191 
0192 /*
0193  * Event control messages
0194  */
0195 #define CS_DSP_FW_EVENT_SHUTDOWN             0x000001
0196 
0197 /*
0198  * HALO system info
0199  */
0200 #define HALO_AHBM_WINDOW_DEBUG_0             0x02040
0201 #define HALO_AHBM_WINDOW_DEBUG_1             0x02044
0202 
0203 /*
0204  * HALO core
0205  */
0206 #define HALO_SCRATCH1                        0x005c0
0207 #define HALO_SCRATCH2                        0x005c8
0208 #define HALO_SCRATCH3                        0x005d0
0209 #define HALO_SCRATCH4                        0x005d8
0210 #define HALO_CCM_CORE_CONTROL                0x41000
0211 #define HALO_CORE_SOFT_RESET                 0x00010
0212 #define HALO_WDT_CONTROL                     0x47000
0213 
0214 /*
0215  * HALO MPU banks
0216  */
0217 #define HALO_MPU_XMEM_ACCESS_0               0x43000
0218 #define HALO_MPU_YMEM_ACCESS_0               0x43004
0219 #define HALO_MPU_WINDOW_ACCESS_0             0x43008
0220 #define HALO_MPU_XREG_ACCESS_0               0x4300C
0221 #define HALO_MPU_YREG_ACCESS_0               0x43014
0222 #define HALO_MPU_XMEM_ACCESS_1               0x43018
0223 #define HALO_MPU_YMEM_ACCESS_1               0x4301C
0224 #define HALO_MPU_WINDOW_ACCESS_1             0x43020
0225 #define HALO_MPU_XREG_ACCESS_1               0x43024
0226 #define HALO_MPU_YREG_ACCESS_1               0x4302C
0227 #define HALO_MPU_XMEM_ACCESS_2               0x43030
0228 #define HALO_MPU_YMEM_ACCESS_2               0x43034
0229 #define HALO_MPU_WINDOW_ACCESS_2             0x43038
0230 #define HALO_MPU_XREG_ACCESS_2               0x4303C
0231 #define HALO_MPU_YREG_ACCESS_2               0x43044
0232 #define HALO_MPU_XMEM_ACCESS_3               0x43048
0233 #define HALO_MPU_YMEM_ACCESS_3               0x4304C
0234 #define HALO_MPU_WINDOW_ACCESS_3             0x43050
0235 #define HALO_MPU_XREG_ACCESS_3               0x43054
0236 #define HALO_MPU_YREG_ACCESS_3               0x4305C
0237 #define HALO_MPU_XM_VIO_ADDR                 0x43100
0238 #define HALO_MPU_XM_VIO_STATUS               0x43104
0239 #define HALO_MPU_YM_VIO_ADDR                 0x43108
0240 #define HALO_MPU_YM_VIO_STATUS               0x4310C
0241 #define HALO_MPU_PM_VIO_ADDR                 0x43110
0242 #define HALO_MPU_PM_VIO_STATUS               0x43114
0243 #define HALO_MPU_LOCK_CONFIG                 0x43140
0244 
0245 /*
0246  * HALO_AHBM_WINDOW_DEBUG_1
0247  */
0248 #define HALO_AHBM_CORE_ERR_ADDR_MASK         0x0fffff00
0249 #define HALO_AHBM_CORE_ERR_ADDR_SHIFT                 8
0250 #define HALO_AHBM_FLAGS_ERR_MASK             0x000000ff
0251 
0252 /*
0253  * HALO_CCM_CORE_CONTROL
0254  */
0255 #define HALO_CORE_RESET                     0x00000200
0256 #define HALO_CORE_EN                        0x00000001
0257 
0258 /*
0259  * HALO_CORE_SOFT_RESET
0260  */
0261 #define HALO_CORE_SOFT_RESET_MASK           0x00000001
0262 
0263 /*
0264  * HALO_WDT_CONTROL
0265  */
0266 #define HALO_WDT_EN_MASK                    0x00000001
0267 
0268 /*
0269  * HALO_MPU_?M_VIO_STATUS
0270  */
0271 #define HALO_MPU_VIO_STS_MASK               0x007e0000
0272 #define HALO_MPU_VIO_STS_SHIFT                      17
0273 #define HALO_MPU_VIO_ERR_WR_MASK            0x00008000
0274 #define HALO_MPU_VIO_ERR_SRC_MASK           0x00007fff
0275 #define HALO_MPU_VIO_ERR_SRC_SHIFT                   0
0276 
0277 struct cs_dsp_ops {
0278     bool (*validate_version)(struct cs_dsp *dsp, unsigned int version);
0279     unsigned int (*parse_sizes)(struct cs_dsp *dsp,
0280                     const char * const file,
0281                     unsigned int pos,
0282                     const struct firmware *firmware);
0283     int (*setup_algs)(struct cs_dsp *dsp);
0284     unsigned int (*region_to_reg)(struct cs_dsp_region const *mem,
0285                       unsigned int offset);
0286 
0287     void (*show_fw_status)(struct cs_dsp *dsp);
0288     void (*stop_watchdog)(struct cs_dsp *dsp);
0289 
0290     int (*enable_memory)(struct cs_dsp *dsp);
0291     void (*disable_memory)(struct cs_dsp *dsp);
0292     int (*lock_memory)(struct cs_dsp *dsp, unsigned int lock_regions);
0293 
0294     int (*enable_core)(struct cs_dsp *dsp);
0295     void (*disable_core)(struct cs_dsp *dsp);
0296 
0297     int (*start_core)(struct cs_dsp *dsp);
0298     void (*stop_core)(struct cs_dsp *dsp);
0299 };
0300 
0301 static const struct cs_dsp_ops cs_dsp_adsp1_ops;
0302 static const struct cs_dsp_ops cs_dsp_adsp2_ops[];
0303 static const struct cs_dsp_ops cs_dsp_halo_ops;
0304 
0305 struct cs_dsp_buf {
0306     struct list_head list;
0307     void *buf;
0308 };
0309 
0310 static struct cs_dsp_buf *cs_dsp_buf_alloc(const void *src, size_t len,
0311                        struct list_head *list)
0312 {
0313     struct cs_dsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
0314 
0315     if (buf == NULL)
0316         return NULL;
0317 
0318     buf->buf = vmalloc(len);
0319     if (!buf->buf) {
0320         kfree(buf);
0321         return NULL;
0322     }
0323     memcpy(buf->buf, src, len);
0324 
0325     if (list)
0326         list_add_tail(&buf->list, list);
0327 
0328     return buf;
0329 }
0330 
0331 static void cs_dsp_buf_free(struct list_head *list)
0332 {
0333     while (!list_empty(list)) {
0334         struct cs_dsp_buf *buf = list_first_entry(list,
0335                               struct cs_dsp_buf,
0336                               list);
0337         list_del(&buf->list);
0338         vfree(buf->buf);
0339         kfree(buf);
0340     }
0341 }
0342 
0343 /**
0344  * cs_dsp_mem_region_name() - Return a name string for a memory type
0345  * @type: the memory type to match
0346  *
0347  * Return: A const string identifying the memory region.
0348  */
0349 const char *cs_dsp_mem_region_name(unsigned int type)
0350 {
0351     switch (type) {
0352     case WMFW_ADSP1_PM:
0353         return "PM";
0354     case WMFW_HALO_PM_PACKED:
0355         return "PM_PACKED";
0356     case WMFW_ADSP1_DM:
0357         return "DM";
0358     case WMFW_ADSP2_XM:
0359         return "XM";
0360     case WMFW_HALO_XM_PACKED:
0361         return "XM_PACKED";
0362     case WMFW_ADSP2_YM:
0363         return "YM";
0364     case WMFW_HALO_YM_PACKED:
0365         return "YM_PACKED";
0366     case WMFW_ADSP1_ZM:
0367         return "ZM";
0368     default:
0369         return NULL;
0370     }
0371 }
0372 EXPORT_SYMBOL_GPL(cs_dsp_mem_region_name);
0373 
0374 #ifdef CONFIG_DEBUG_FS
0375 static void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, const char *s)
0376 {
0377     char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
0378 
0379     kfree(dsp->wmfw_file_name);
0380     dsp->wmfw_file_name = tmp;
0381 }
0382 
0383 static void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp, const char *s)
0384 {
0385     char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
0386 
0387     kfree(dsp->bin_file_name);
0388     dsp->bin_file_name = tmp;
0389 }
0390 
0391 static void cs_dsp_debugfs_clear(struct cs_dsp *dsp)
0392 {
0393     kfree(dsp->wmfw_file_name);
0394     kfree(dsp->bin_file_name);
0395     dsp->wmfw_file_name = NULL;
0396     dsp->bin_file_name = NULL;
0397 }
0398 
0399 static ssize_t cs_dsp_debugfs_wmfw_read(struct file *file,
0400                     char __user *user_buf,
0401                     size_t count, loff_t *ppos)
0402 {
0403     struct cs_dsp *dsp = file->private_data;
0404     ssize_t ret;
0405 
0406     mutex_lock(&dsp->pwr_lock);
0407 
0408     if (!dsp->wmfw_file_name || !dsp->booted)
0409         ret = 0;
0410     else
0411         ret = simple_read_from_buffer(user_buf, count, ppos,
0412                           dsp->wmfw_file_name,
0413                           strlen(dsp->wmfw_file_name));
0414 
0415     mutex_unlock(&dsp->pwr_lock);
0416     return ret;
0417 }
0418 
0419 static ssize_t cs_dsp_debugfs_bin_read(struct file *file,
0420                        char __user *user_buf,
0421                        size_t count, loff_t *ppos)
0422 {
0423     struct cs_dsp *dsp = file->private_data;
0424     ssize_t ret;
0425 
0426     mutex_lock(&dsp->pwr_lock);
0427 
0428     if (!dsp->bin_file_name || !dsp->booted)
0429         ret = 0;
0430     else
0431         ret = simple_read_from_buffer(user_buf, count, ppos,
0432                           dsp->bin_file_name,
0433                           strlen(dsp->bin_file_name));
0434 
0435     mutex_unlock(&dsp->pwr_lock);
0436     return ret;
0437 }
0438 
0439 static const struct {
0440     const char *name;
0441     const struct file_operations fops;
0442 } cs_dsp_debugfs_fops[] = {
0443     {
0444         .name = "wmfw_file_name",
0445         .fops = {
0446             .open = simple_open,
0447             .read = cs_dsp_debugfs_wmfw_read,
0448         },
0449     },
0450     {
0451         .name = "bin_file_name",
0452         .fops = {
0453             .open = simple_open,
0454             .read = cs_dsp_debugfs_bin_read,
0455         },
0456     },
0457 };
0458 
0459 /**
0460  * cs_dsp_init_debugfs() - Create and populate DSP representation in debugfs
0461  * @dsp: pointer to DSP structure
0462  * @debugfs_root: pointer to debugfs directory in which to create this DSP
0463  *                representation
0464  */
0465 void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root)
0466 {
0467     struct dentry *root = NULL;
0468     int i;
0469 
0470     root = debugfs_create_dir(dsp->name, debugfs_root);
0471 
0472     debugfs_create_bool("booted", 0444, root, &dsp->booted);
0473     debugfs_create_bool("running", 0444, root, &dsp->running);
0474     debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id);
0475     debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version);
0476 
0477     for (i = 0; i < ARRAY_SIZE(cs_dsp_debugfs_fops); ++i)
0478         debugfs_create_file(cs_dsp_debugfs_fops[i].name, 0444, root,
0479                     dsp, &cs_dsp_debugfs_fops[i].fops);
0480 
0481     dsp->debugfs_root = root;
0482 }
0483 EXPORT_SYMBOL_GPL(cs_dsp_init_debugfs);
0484 
0485 /**
0486  * cs_dsp_cleanup_debugfs() - Removes DSP representation from debugfs
0487  * @dsp: pointer to DSP structure
0488  */
0489 void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
0490 {
0491     cs_dsp_debugfs_clear(dsp);
0492     debugfs_remove_recursive(dsp->debugfs_root);
0493     dsp->debugfs_root = NULL;
0494 }
0495 EXPORT_SYMBOL_GPL(cs_dsp_cleanup_debugfs);
0496 #else
0497 void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root)
0498 {
0499 }
0500 EXPORT_SYMBOL_GPL(cs_dsp_init_debugfs);
0501 
0502 void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
0503 {
0504 }
0505 EXPORT_SYMBOL_GPL(cs_dsp_cleanup_debugfs);
0506 
0507 static inline void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp,
0508                         const char *s)
0509 {
0510 }
0511 
0512 static inline void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp,
0513                            const char *s)
0514 {
0515 }
0516 
0517 static inline void cs_dsp_debugfs_clear(struct cs_dsp *dsp)
0518 {
0519 }
0520 #endif
0521 
0522 static const struct cs_dsp_region *cs_dsp_find_region(struct cs_dsp *dsp,
0523                               int type)
0524 {
0525     int i;
0526 
0527     for (i = 0; i < dsp->num_mems; i++)
0528         if (dsp->mem[i].type == type)
0529             return &dsp->mem[i];
0530 
0531     return NULL;
0532 }
0533 
0534 static unsigned int cs_dsp_region_to_reg(struct cs_dsp_region const *mem,
0535                      unsigned int offset)
0536 {
0537     switch (mem->type) {
0538     case WMFW_ADSP1_PM:
0539         return mem->base + (offset * 3);
0540     case WMFW_ADSP1_DM:
0541     case WMFW_ADSP2_XM:
0542     case WMFW_ADSP2_YM:
0543     case WMFW_ADSP1_ZM:
0544         return mem->base + (offset * 2);
0545     default:
0546         WARN(1, "Unknown memory region type");
0547         return offset;
0548     }
0549 }
0550 
0551 static unsigned int cs_dsp_halo_region_to_reg(struct cs_dsp_region const *mem,
0552                           unsigned int offset)
0553 {
0554     switch (mem->type) {
0555     case WMFW_ADSP2_XM:
0556     case WMFW_ADSP2_YM:
0557         return mem->base + (offset * 4);
0558     case WMFW_HALO_XM_PACKED:
0559     case WMFW_HALO_YM_PACKED:
0560         return (mem->base + (offset * 3)) & ~0x3;
0561     case WMFW_HALO_PM_PACKED:
0562         return mem->base + (offset * 5);
0563     default:
0564         WARN(1, "Unknown memory region type");
0565         return offset;
0566     }
0567 }
0568 
0569 static void cs_dsp_read_fw_status(struct cs_dsp *dsp,
0570                   int noffs, unsigned int *offs)
0571 {
0572     unsigned int i;
0573     int ret;
0574 
0575     for (i = 0; i < noffs; ++i) {
0576         ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]);
0577         if (ret) {
0578             cs_dsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret);
0579             return;
0580         }
0581     }
0582 }
0583 
0584 static void cs_dsp_adsp2_show_fw_status(struct cs_dsp *dsp)
0585 {
0586     unsigned int offs[] = {
0587         ADSP2_SCRATCH0, ADSP2_SCRATCH1, ADSP2_SCRATCH2, ADSP2_SCRATCH3,
0588     };
0589 
0590     cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
0591 
0592     cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
0593            offs[0], offs[1], offs[2], offs[3]);
0594 }
0595 
0596 static void cs_dsp_adsp2v2_show_fw_status(struct cs_dsp *dsp)
0597 {
0598     unsigned int offs[] = { ADSP2V2_SCRATCH0_1, ADSP2V2_SCRATCH2_3 };
0599 
0600     cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
0601 
0602     cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
0603            offs[0] & 0xFFFF, offs[0] >> 16,
0604            offs[1] & 0xFFFF, offs[1] >> 16);
0605 }
0606 
0607 static void cs_dsp_halo_show_fw_status(struct cs_dsp *dsp)
0608 {
0609     unsigned int offs[] = {
0610         HALO_SCRATCH1, HALO_SCRATCH2, HALO_SCRATCH3, HALO_SCRATCH4,
0611     };
0612 
0613     cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
0614 
0615     cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
0616            offs[0], offs[1], offs[2], offs[3]);
0617 }
0618 
0619 static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg,
0620                  unsigned int off)
0621 {
0622     const struct cs_dsp_alg_region *alg_region = &ctl->alg_region;
0623     struct cs_dsp *dsp = ctl->dsp;
0624     const struct cs_dsp_region *mem;
0625 
0626     mem = cs_dsp_find_region(dsp, alg_region->type);
0627     if (!mem) {
0628         cs_dsp_err(dsp, "No base for region %x\n",
0629                alg_region->type);
0630         return -EINVAL;
0631     }
0632 
0633     *reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset + off);
0634 
0635     return 0;
0636 }
0637 
0638 /**
0639  * cs_dsp_coeff_write_acked_control() - Sends event_id to the acked control
0640  * @ctl: pointer to acked coefficient control
0641  * @event_id: the value to write to the given acked control
0642  *
0643  * Once the value has been written to the control the function shall block
0644  * until the running firmware acknowledges the write or timeout is exceeded.
0645  *
0646  * Must be called with pwr_lock held.
0647  *
0648  * Return: Zero for success, a negative number on error.
0649  */
0650 int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int event_id)
0651 {
0652     struct cs_dsp *dsp = ctl->dsp;
0653     __be32 val = cpu_to_be32(event_id);
0654     unsigned int reg;
0655     int i, ret;
0656 
0657     lockdep_assert_held(&dsp->pwr_lock);
0658 
0659     if (!dsp->running)
0660         return -EPERM;
0661 
0662     ret = cs_dsp_coeff_base_reg(ctl, &reg, 0);
0663     if (ret)
0664         return ret;
0665 
0666     cs_dsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n",
0667            event_id, ctl->alg_region.alg,
0668            cs_dsp_mem_region_name(ctl->alg_region.type), ctl->offset);
0669 
0670     ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
0671     if (ret) {
0672         cs_dsp_err(dsp, "Failed to write %x: %d\n", reg, ret);
0673         return ret;
0674     }
0675 
0676     /*
0677      * Poll for ack, we initially poll at ~1ms intervals for firmwares
0678      * that respond quickly, then go to ~10ms polls. A firmware is unlikely
0679      * to ack instantly so we do the first 1ms delay before reading the
0680      * control to avoid a pointless bus transaction
0681      */
0682     for (i = 0; i < CS_DSP_ACKED_CTL_TIMEOUT_MS;) {
0683         switch (i) {
0684         case 0 ... CS_DSP_ACKED_CTL_N_QUICKPOLLS - 1:
0685             usleep_range(1000, 2000);
0686             i++;
0687             break;
0688         default:
0689             usleep_range(10000, 20000);
0690             i += 10;
0691             break;
0692         }
0693 
0694         ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
0695         if (ret) {
0696             cs_dsp_err(dsp, "Failed to read %x: %d\n", reg, ret);
0697             return ret;
0698         }
0699 
0700         if (val == 0) {
0701             cs_dsp_dbg(dsp, "Acked control ACKED at poll %u\n", i);
0702             return 0;
0703         }
0704     }
0705 
0706     cs_dsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n",
0707             reg, ctl->alg_region.alg,
0708             cs_dsp_mem_region_name(ctl->alg_region.type),
0709             ctl->offset);
0710 
0711     return -ETIMEDOUT;
0712 }
0713 EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_acked_control);
0714 
0715 static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
0716                        unsigned int off, const void *buf, size_t len)
0717 {
0718     struct cs_dsp *dsp = ctl->dsp;
0719     void *scratch;
0720     int ret;
0721     unsigned int reg;
0722 
0723     ret = cs_dsp_coeff_base_reg(ctl, &reg, off);
0724     if (ret)
0725         return ret;
0726 
0727     scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);
0728     if (!scratch)
0729         return -ENOMEM;
0730 
0731     ret = regmap_raw_write(dsp->regmap, reg, scratch,
0732                    len);
0733     if (ret) {
0734         cs_dsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
0735                len, reg, ret);
0736         kfree(scratch);
0737         return ret;
0738     }
0739     cs_dsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg);
0740 
0741     kfree(scratch);
0742 
0743     return 0;
0744 }
0745 
0746 /**
0747  * cs_dsp_coeff_write_ctrl() - Writes the given buffer to the given coefficient control
0748  * @ctl: pointer to coefficient control
0749  * @off: word offset at which data should be written
0750  * @buf: the buffer to write to the given control
0751  * @len: the length of the buffer in bytes
0752  *
0753  * Must be called with pwr_lock held.
0754  *
0755  * Return: Zero for success, a negative number on error.
0756  */
0757 int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl,
0758                 unsigned int off, const void *buf, size_t len)
0759 {
0760     int ret = 0;
0761 
0762     if (!ctl)
0763         return -ENOENT;
0764 
0765     lockdep_assert_held(&ctl->dsp->pwr_lock);
0766 
0767     if (len + off * sizeof(u32) > ctl->len)
0768         return -EINVAL;
0769 
0770     if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
0771         ret = -EPERM;
0772     else if (buf != ctl->cache)
0773         memcpy(ctl->cache + off * sizeof(u32), buf, len);
0774 
0775     ctl->set = 1;
0776     if (ctl->enabled && ctl->dsp->running)
0777         ret = cs_dsp_coeff_write_ctrl_raw(ctl, off, buf, len);
0778 
0779     return ret;
0780 }
0781 EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_ctrl);
0782 
0783 static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
0784                       unsigned int off, void *buf, size_t len)
0785 {
0786     struct cs_dsp *dsp = ctl->dsp;
0787     void *scratch;
0788     int ret;
0789     unsigned int reg;
0790 
0791     ret = cs_dsp_coeff_base_reg(ctl, &reg, off);
0792     if (ret)
0793         return ret;
0794 
0795     scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);
0796     if (!scratch)
0797         return -ENOMEM;
0798 
0799     ret = regmap_raw_read(dsp->regmap, reg, scratch, len);
0800     if (ret) {
0801         cs_dsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
0802                len, reg, ret);
0803         kfree(scratch);
0804         return ret;
0805     }
0806     cs_dsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg);
0807 
0808     memcpy(buf, scratch, len);
0809     kfree(scratch);
0810 
0811     return 0;
0812 }
0813 
0814 /**
0815  * cs_dsp_coeff_read_ctrl() - Reads the given coefficient control into the given buffer
0816  * @ctl: pointer to coefficient control
0817  * @off: word offset at which data should be read
0818  * @buf: the buffer to store to the given control
0819  * @len: the length of the buffer in bytes
0820  *
0821  * Must be called with pwr_lock held.
0822  *
0823  * Return: Zero for success, a negative number on error.
0824  */
0825 int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl,
0826                unsigned int off, void *buf, size_t len)
0827 {
0828     int ret = 0;
0829 
0830     if (!ctl)
0831         return -ENOENT;
0832 
0833     lockdep_assert_held(&ctl->dsp->pwr_lock);
0834 
0835     if (len + off * sizeof(u32) > ctl->len)
0836         return -EINVAL;
0837 
0838     if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
0839         if (ctl->enabled && ctl->dsp->running)
0840             return cs_dsp_coeff_read_ctrl_raw(ctl, off, buf, len);
0841         else
0842             return -EPERM;
0843     } else {
0844         if (!ctl->flags && ctl->enabled && ctl->dsp->running)
0845             ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len);
0846 
0847         if (buf != ctl->cache)
0848             memcpy(buf, ctl->cache + off * sizeof(u32), len);
0849     }
0850 
0851     return ret;
0852 }
0853 EXPORT_SYMBOL_GPL(cs_dsp_coeff_read_ctrl);
0854 
0855 static int cs_dsp_coeff_init_control_caches(struct cs_dsp *dsp)
0856 {
0857     struct cs_dsp_coeff_ctl *ctl;
0858     int ret;
0859 
0860     list_for_each_entry(ctl, &dsp->ctl_list, list) {
0861         if (!ctl->enabled || ctl->set)
0862             continue;
0863         if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
0864             continue;
0865 
0866         /*
0867          * For readable controls populate the cache from the DSP memory.
0868          * For non-readable controls the cache was zero-filled when
0869          * created so we don't need to do anything.
0870          */
0871         if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) {
0872             ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len);
0873             if (ret < 0)
0874                 return ret;
0875         }
0876     }
0877 
0878     return 0;
0879 }
0880 
0881 static int cs_dsp_coeff_sync_controls(struct cs_dsp *dsp)
0882 {
0883     struct cs_dsp_coeff_ctl *ctl;
0884     int ret;
0885 
0886     list_for_each_entry(ctl, &dsp->ctl_list, list) {
0887         if (!ctl->enabled)
0888             continue;
0889         if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
0890             ret = cs_dsp_coeff_write_ctrl_raw(ctl, 0, ctl->cache,
0891                               ctl->len);
0892             if (ret < 0)
0893                 return ret;
0894         }
0895     }
0896 
0897     return 0;
0898 }
0899 
0900 static void cs_dsp_signal_event_controls(struct cs_dsp *dsp,
0901                      unsigned int event)
0902 {
0903     struct cs_dsp_coeff_ctl *ctl;
0904     int ret;
0905 
0906     list_for_each_entry(ctl, &dsp->ctl_list, list) {
0907         if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT)
0908             continue;
0909 
0910         if (!ctl->enabled)
0911             continue;
0912 
0913         ret = cs_dsp_coeff_write_acked_control(ctl, event);
0914         if (ret)
0915             cs_dsp_warn(dsp,
0916                     "Failed to send 0x%x event to alg 0x%x (%d)\n",
0917                     event, ctl->alg_region.alg, ret);
0918     }
0919 }
0920 
0921 static void cs_dsp_free_ctl_blk(struct cs_dsp_coeff_ctl *ctl)
0922 {
0923     kfree(ctl->cache);
0924     kfree(ctl->subname);
0925     kfree(ctl);
0926 }
0927 
0928 static int cs_dsp_create_control(struct cs_dsp *dsp,
0929                  const struct cs_dsp_alg_region *alg_region,
0930                  unsigned int offset, unsigned int len,
0931                  const char *subname, unsigned int subname_len,
0932                  unsigned int flags, unsigned int type)
0933 {
0934     struct cs_dsp_coeff_ctl *ctl;
0935     int ret;
0936 
0937     list_for_each_entry(ctl, &dsp->ctl_list, list) {
0938         if (ctl->fw_name == dsp->fw_name &&
0939             ctl->alg_region.alg == alg_region->alg &&
0940             ctl->alg_region.type == alg_region->type) {
0941             if ((!subname && !ctl->subname) ||
0942                 (subname && !strncmp(ctl->subname, subname, ctl->subname_len))) {
0943                 if (!ctl->enabled)
0944                     ctl->enabled = 1;
0945                 return 0;
0946             }
0947         }
0948     }
0949 
0950     ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
0951     if (!ctl)
0952         return -ENOMEM;
0953 
0954     ctl->fw_name = dsp->fw_name;
0955     ctl->alg_region = *alg_region;
0956     if (subname && dsp->fw_ver >= 2) {
0957         ctl->subname_len = subname_len;
0958         ctl->subname = kasprintf(GFP_KERNEL, "%.*s", subname_len, subname);
0959         if (!ctl->subname) {
0960             ret = -ENOMEM;
0961             goto err_ctl;
0962         }
0963     }
0964     ctl->enabled = 1;
0965     ctl->set = 0;
0966     ctl->dsp = dsp;
0967 
0968     ctl->flags = flags;
0969     ctl->type = type;
0970     ctl->offset = offset;
0971     ctl->len = len;
0972     ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
0973     if (!ctl->cache) {
0974         ret = -ENOMEM;
0975         goto err_ctl_subname;
0976     }
0977 
0978     list_add(&ctl->list, &dsp->ctl_list);
0979 
0980     if (dsp->client_ops->control_add) {
0981         ret = dsp->client_ops->control_add(ctl);
0982         if (ret)
0983             goto err_list_del;
0984     }
0985 
0986     return 0;
0987 
0988 err_list_del:
0989     list_del(&ctl->list);
0990     kfree(ctl->cache);
0991 err_ctl_subname:
0992     kfree(ctl->subname);
0993 err_ctl:
0994     kfree(ctl);
0995 
0996     return ret;
0997 }
0998 
0999 struct cs_dsp_coeff_parsed_alg {
1000     int id;
1001     const u8 *name;
1002     int name_len;
1003     int ncoeff;
1004 };
1005 
1006 struct 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 
1016 static 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 
1039 static 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 
1059 static 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 
1089 static 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 
1135 static 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 
1150 static 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 
1222 static 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 
1238 static 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 
1254 static 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 
1268 static 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 
1278 static 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 
1456 out_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  */
1475 struct 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 }
1496 EXPORT_SYMBOL_GPL(cs_dsp_get_ctl);
1497 
1498 static 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 
1512 static 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  */
1572 struct 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 }
1586 EXPORT_SYMBOL_GPL(cs_dsp_find_alg_region);
1587 
1588 static 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 
1611 static 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 
1624 static 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 
1636 static 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 
1650 static 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 
1665 static 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 
1765 out:
1766     kfree(adsp1_alg);
1767     return ret;
1768 }
1769 
1770 static 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 
1900 out:
1901     kfree(adsp2_alg);
1902     return ret;
1903 }
1904 
1905 static 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 
1917 static 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 
1973 out:
1974     kfree(halo_alg);
1975     return ret;
1976 }
1977 
1978 static 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 
2173 out_fw:
2174     regmap_async_complete(regmap);
2175     cs_dsp_buf_free(&buf_list);
2176     kfree(text);
2177     return ret;
2178 }
2179 
2180 static 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 
2192 static 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  */
2214 int 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 }
2220 EXPORT_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  */
2233 int 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 
2305 err_ena:
2306     regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2307                ADSP1_SYS_ENA, 0);
2308 err_mutex:
2309     mutex_unlock(&dsp->pwr_lock);
2310     return ret;
2311 }
2312 EXPORT_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  */
2318 void 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 }
2344 EXPORT_SYMBOL_GPL(cs_dsp_adsp1_power_down);
2345 
2346 static 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 
2373 static 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 
2385 static 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 
2415 static 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 
2421 static 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 
2427 static 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 
2437 static 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 
2444 static 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  */
2484 int 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 }
2496 EXPORT_SYMBOL_GPL(cs_dsp_set_dspclk);
2497 
2498 static 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 
2504 static 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  */
2527 int 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;
2575 err_ena:
2576     if (dsp->ops->disable_core)
2577         dsp->ops->disable_core(dsp);
2578 err_mem:
2579     if (dsp->ops->disable_memory)
2580         dsp->ops->disable_memory(dsp);
2581 err_mutex:
2582     mutex_unlock(&dsp->pwr_lock);
2583 
2584     return ret;
2585 }
2586 EXPORT_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  */
2595 void 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 }
2620 EXPORT_SYMBOL_GPL(cs_dsp_power_down);
2621 
2622 static 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 
2629 static 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  */
2643 int 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 
2697 err:
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 }
2706 EXPORT_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  */
2714 void 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     if (dsp->client_ops->pre_stop)
2729         dsp->client_ops->pre_stop(dsp);
2730 
2731     dsp->running = false;
2732 
2733     if (dsp->ops->stop_core)
2734         dsp->ops->stop_core(dsp);
2735     if (dsp->ops->disable_core)
2736         dsp->ops->disable_core(dsp);
2737 
2738     if (dsp->client_ops->post_stop)
2739         dsp->client_ops->post_stop(dsp);
2740 
2741     mutex_unlock(&dsp->pwr_lock);
2742 
2743     cs_dsp_dbg(dsp, "Execution stopped\n");
2744 }
2745 EXPORT_SYMBOL_GPL(cs_dsp_stop);
2746 
2747 static int cs_dsp_halo_start_core(struct cs_dsp *dsp)
2748 {
2749     int ret;
2750 
2751     ret = regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
2752                  HALO_CORE_RESET | HALO_CORE_EN,
2753                  HALO_CORE_RESET | HALO_CORE_EN);
2754     if (ret)
2755         return ret;
2756 
2757     return regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
2758                   HALO_CORE_RESET, 0);
2759 }
2760 
2761 static void cs_dsp_halo_stop_core(struct cs_dsp *dsp)
2762 {
2763     regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
2764                HALO_CORE_EN, 0);
2765 
2766     /* reset halo core with CORE_SOFT_RESET */
2767     regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET,
2768                HALO_CORE_SOFT_RESET_MASK, 1);
2769 }
2770 
2771 /**
2772  * cs_dsp_adsp2_init() - Initialise a cs_dsp structure representing a ADSP2 core
2773  * @dsp: pointer to DSP structure
2774  *
2775  * Return: Zero for success, a negative number on error.
2776  */
2777 int cs_dsp_adsp2_init(struct cs_dsp *dsp)
2778 {
2779     int ret;
2780 
2781     switch (dsp->rev) {
2782     case 0:
2783         /*
2784          * Disable the DSP memory by default when in reset for a small
2785          * power saving.
2786          */
2787         ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2788                      ADSP2_MEM_ENA, 0);
2789         if (ret) {
2790             cs_dsp_err(dsp,
2791                    "Failed to clear memory retention: %d\n", ret);
2792             return ret;
2793         }
2794 
2795         dsp->ops = &cs_dsp_adsp2_ops[0];
2796         break;
2797     case 1:
2798         dsp->ops = &cs_dsp_adsp2_ops[1];
2799         break;
2800     default:
2801         dsp->ops = &cs_dsp_adsp2_ops[2];
2802         break;
2803     }
2804 
2805     return cs_dsp_common_init(dsp);
2806 }
2807 EXPORT_SYMBOL_GPL(cs_dsp_adsp2_init);
2808 
2809 /**
2810  * cs_dsp_halo_init() - Initialise a cs_dsp structure representing a HALO Core DSP
2811  * @dsp: pointer to DSP structure
2812  *
2813  * Return: Zero for success, a negative number on error.
2814  */
2815 int cs_dsp_halo_init(struct cs_dsp *dsp)
2816 {
2817     dsp->ops = &cs_dsp_halo_ops;
2818 
2819     return cs_dsp_common_init(dsp);
2820 }
2821 EXPORT_SYMBOL_GPL(cs_dsp_halo_init);
2822 
2823 /**
2824  * cs_dsp_remove() - Clean a cs_dsp before deletion
2825  * @dsp: pointer to DSP structure
2826  */
2827 void cs_dsp_remove(struct cs_dsp *dsp)
2828 {
2829     struct cs_dsp_coeff_ctl *ctl;
2830 
2831     while (!list_empty(&dsp->ctl_list)) {
2832         ctl = list_first_entry(&dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
2833 
2834         if (dsp->client_ops->control_remove)
2835             dsp->client_ops->control_remove(ctl);
2836 
2837         list_del(&ctl->list);
2838         cs_dsp_free_ctl_blk(ctl);
2839     }
2840 }
2841 EXPORT_SYMBOL_GPL(cs_dsp_remove);
2842 
2843 /**
2844  * cs_dsp_read_raw_data_block() - Reads a block of data from DSP memory
2845  * @dsp: pointer to DSP structure
2846  * @mem_type: the type of DSP memory containing the data to be read
2847  * @mem_addr: the address of the data within the memory region
2848  * @num_words: the length of the data to read
2849  * @data: a buffer to store the fetched data
2850  *
2851  * If this is used to read unpacked 24-bit memory, each 24-bit DSP word will
2852  * occupy 32-bits in data (MSbyte will be 0). This padding can be removed using
2853  * cs_dsp_remove_padding()
2854  *
2855  * Return: Zero for success, a negative number on error.
2856  */
2857 int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr,
2858                    unsigned int num_words, __be32 *data)
2859 {
2860     struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type);
2861     unsigned int reg;
2862     int ret;
2863 
2864     lockdep_assert_held(&dsp->pwr_lock);
2865 
2866     if (!mem)
2867         return -EINVAL;
2868 
2869     reg = dsp->ops->region_to_reg(mem, mem_addr);
2870 
2871     ret = regmap_raw_read(dsp->regmap, reg, data,
2872                   sizeof(*data) * num_words);
2873     if (ret < 0)
2874         return ret;
2875 
2876     return 0;
2877 }
2878 EXPORT_SYMBOL_GPL(cs_dsp_read_raw_data_block);
2879 
2880 /**
2881  * cs_dsp_read_data_word() - Reads a word from DSP memory
2882  * @dsp: pointer to DSP structure
2883  * @mem_type: the type of DSP memory containing the data to be read
2884  * @mem_addr: the address of the data within the memory region
2885  * @data: a buffer to store the fetched data
2886  *
2887  * Return: Zero for success, a negative number on error.
2888  */
2889 int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 *data)
2890 {
2891     __be32 raw;
2892     int ret;
2893 
2894     ret = cs_dsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw);
2895     if (ret < 0)
2896         return ret;
2897 
2898     *data = be32_to_cpu(raw) & 0x00ffffffu;
2899 
2900     return 0;
2901 }
2902 EXPORT_SYMBOL_GPL(cs_dsp_read_data_word);
2903 
2904 /**
2905  * cs_dsp_write_data_word() - Writes a word to DSP memory
2906  * @dsp: pointer to DSP structure
2907  * @mem_type: the type of DSP memory containing the data to be written
2908  * @mem_addr: the address of the data within the memory region
2909  * @data: the data to be written
2910  *
2911  * Return: Zero for success, a negative number on error.
2912  */
2913 int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 data)
2914 {
2915     struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type);
2916     __be32 val = cpu_to_be32(data & 0x00ffffffu);
2917     unsigned int reg;
2918 
2919     lockdep_assert_held(&dsp->pwr_lock);
2920 
2921     if (!mem)
2922         return -EINVAL;
2923 
2924     reg = dsp->ops->region_to_reg(mem, mem_addr);
2925 
2926     return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
2927 }
2928 EXPORT_SYMBOL_GPL(cs_dsp_write_data_word);
2929 
2930 /**
2931  * cs_dsp_remove_padding() - Convert unpacked words to packed bytes
2932  * @buf: buffer containing DSP words read from DSP memory
2933  * @nwords: number of words to convert
2934  *
2935  * DSP words from the register map have pad bytes and the data bytes
2936  * are in swapped order. This swaps to the native endian order and
2937  * strips the pad bytes.
2938  */
2939 void cs_dsp_remove_padding(u32 *buf, int nwords)
2940 {
2941     const __be32 *pack_in = (__be32 *)buf;
2942     u8 *pack_out = (u8 *)buf;
2943     int i;
2944 
2945     for (i = 0; i < nwords; i++) {
2946         u32 word = be32_to_cpu(*pack_in++);
2947         *pack_out++ = (u8)word;
2948         *pack_out++ = (u8)(word >> 8);
2949         *pack_out++ = (u8)(word >> 16);
2950     }
2951 }
2952 EXPORT_SYMBOL_GPL(cs_dsp_remove_padding);
2953 
2954 /**
2955  * cs_dsp_adsp2_bus_error() - Handle a DSP bus error interrupt
2956  * @dsp: pointer to DSP structure
2957  *
2958  * The firmware and DSP state will be logged for future analysis.
2959  */
2960 void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp)
2961 {
2962     unsigned int val;
2963     struct regmap *regmap = dsp->regmap;
2964     int ret = 0;
2965 
2966     mutex_lock(&dsp->pwr_lock);
2967 
2968     ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val);
2969     if (ret) {
2970         cs_dsp_err(dsp,
2971                "Failed to read Region Lock Ctrl register: %d\n", ret);
2972         goto error;
2973     }
2974 
2975     if (val & ADSP2_WDT_TIMEOUT_STS_MASK) {
2976         cs_dsp_err(dsp, "watchdog timeout error\n");
2977         dsp->ops->stop_watchdog(dsp);
2978         if (dsp->client_ops->watchdog_expired)
2979             dsp->client_ops->watchdog_expired(dsp);
2980     }
2981 
2982     if (val & (ADSP2_ADDR_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) {
2983         if (val & ADSP2_ADDR_ERR_MASK)
2984             cs_dsp_err(dsp, "bus error: address error\n");
2985         else
2986             cs_dsp_err(dsp, "bus error: region lock error\n");
2987 
2988         ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val);
2989         if (ret) {
2990             cs_dsp_err(dsp,
2991                    "Failed to read Bus Err Addr register: %d\n",
2992                    ret);
2993             goto error;
2994         }
2995 
2996         cs_dsp_err(dsp, "bus error address = 0x%x\n",
2997                val & ADSP2_BUS_ERR_ADDR_MASK);
2998 
2999         ret = regmap_read(regmap,
3000                   dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR,
3001                   &val);
3002         if (ret) {
3003             cs_dsp_err(dsp,
3004                    "Failed to read Pmem Xmem Err Addr register: %d\n",
3005                    ret);
3006             goto error;
3007         }
3008 
3009         cs_dsp_err(dsp, "xmem error address = 0x%x\n",
3010                val & ADSP2_XMEM_ERR_ADDR_MASK);
3011         cs_dsp_err(dsp, "pmem error address = 0x%x\n",
3012                (val & ADSP2_PMEM_ERR_ADDR_MASK) >>
3013                ADSP2_PMEM_ERR_ADDR_SHIFT);
3014     }
3015 
3016     regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL,
3017                ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT);
3018 
3019 error:
3020     mutex_unlock(&dsp->pwr_lock);
3021 }
3022 EXPORT_SYMBOL_GPL(cs_dsp_adsp2_bus_error);
3023 
3024 /**
3025  * cs_dsp_halo_bus_error() - Handle a DSP bus error interrupt
3026  * @dsp: pointer to DSP structure
3027  *
3028  * The firmware and DSP state will be logged for future analysis.
3029  */
3030 void cs_dsp_halo_bus_error(struct cs_dsp *dsp)
3031 {
3032     struct regmap *regmap = dsp->regmap;
3033     unsigned int fault[6];
3034     struct reg_sequence clear[] = {
3035         { dsp->base + HALO_MPU_XM_VIO_STATUS,     0x0 },
3036         { dsp->base + HALO_MPU_YM_VIO_STATUS,     0x0 },
3037         { dsp->base + HALO_MPU_PM_VIO_STATUS,     0x0 },
3038     };
3039     int ret;
3040 
3041     mutex_lock(&dsp->pwr_lock);
3042 
3043     ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1,
3044               fault);
3045     if (ret) {
3046         cs_dsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret);
3047         goto exit_unlock;
3048     }
3049 
3050     cs_dsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n",
3051             *fault & HALO_AHBM_FLAGS_ERR_MASK,
3052             (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >>
3053             HALO_AHBM_CORE_ERR_ADDR_SHIFT);
3054 
3055     ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0,
3056               fault);
3057     if (ret) {
3058         cs_dsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret);
3059         goto exit_unlock;
3060     }
3061 
3062     cs_dsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault);
3063 
3064     ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR,
3065                    fault, ARRAY_SIZE(fault));
3066     if (ret) {
3067         cs_dsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret);
3068         goto exit_unlock;
3069     }
3070 
3071     cs_dsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]);
3072     cs_dsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]);
3073     cs_dsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]);
3074 
3075     ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear));
3076     if (ret)
3077         cs_dsp_warn(dsp, "Failed to clear MPU status: %d\n", ret);
3078 
3079 exit_unlock:
3080     mutex_unlock(&dsp->pwr_lock);
3081 }
3082 EXPORT_SYMBOL_GPL(cs_dsp_halo_bus_error);
3083 
3084 /**
3085  * cs_dsp_halo_wdt_expire() - Handle DSP watchdog expiry
3086  * @dsp: pointer to DSP structure
3087  *
3088  * This is logged for future analysis.
3089  */
3090 void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp)
3091 {
3092     mutex_lock(&dsp->pwr_lock);
3093 
3094     cs_dsp_warn(dsp, "WDT Expiry Fault\n");
3095 
3096     dsp->ops->stop_watchdog(dsp);
3097     if (dsp->client_ops->watchdog_expired)
3098         dsp->client_ops->watchdog_expired(dsp);
3099 
3100     mutex_unlock(&dsp->pwr_lock);
3101 }
3102 EXPORT_SYMBOL_GPL(cs_dsp_halo_wdt_expire);
3103 
3104 static const struct cs_dsp_ops cs_dsp_adsp1_ops = {
3105     .validate_version = cs_dsp_validate_version,
3106     .parse_sizes = cs_dsp_adsp1_parse_sizes,
3107     .region_to_reg = cs_dsp_region_to_reg,
3108 };
3109 
3110 static const struct cs_dsp_ops cs_dsp_adsp2_ops[] = {
3111     {
3112         .parse_sizes = cs_dsp_adsp2_parse_sizes,
3113         .validate_version = cs_dsp_validate_version,
3114         .setup_algs = cs_dsp_adsp2_setup_algs,
3115         .region_to_reg = cs_dsp_region_to_reg,
3116 
3117         .show_fw_status = cs_dsp_adsp2_show_fw_status,
3118 
3119         .enable_memory = cs_dsp_adsp2_enable_memory,
3120         .disable_memory = cs_dsp_adsp2_disable_memory,
3121 
3122         .enable_core = cs_dsp_adsp2_enable_core,
3123         .disable_core = cs_dsp_adsp2_disable_core,
3124 
3125         .start_core = cs_dsp_adsp2_start_core,
3126         .stop_core = cs_dsp_adsp2_stop_core,
3127 
3128     },
3129     {
3130         .parse_sizes = cs_dsp_adsp2_parse_sizes,
3131         .validate_version = cs_dsp_validate_version,
3132         .setup_algs = cs_dsp_adsp2_setup_algs,
3133         .region_to_reg = cs_dsp_region_to_reg,
3134 
3135         .show_fw_status = cs_dsp_adsp2v2_show_fw_status,
3136 
3137         .enable_memory = cs_dsp_adsp2_enable_memory,
3138         .disable_memory = cs_dsp_adsp2_disable_memory,
3139         .lock_memory = cs_dsp_adsp2_lock,
3140 
3141         .enable_core = cs_dsp_adsp2v2_enable_core,
3142         .disable_core = cs_dsp_adsp2v2_disable_core,
3143 
3144         .start_core = cs_dsp_adsp2_start_core,
3145         .stop_core = cs_dsp_adsp2_stop_core,
3146     },
3147     {
3148         .parse_sizes = cs_dsp_adsp2_parse_sizes,
3149         .validate_version = cs_dsp_validate_version,
3150         .setup_algs = cs_dsp_adsp2_setup_algs,
3151         .region_to_reg = cs_dsp_region_to_reg,
3152 
3153         .show_fw_status = cs_dsp_adsp2v2_show_fw_status,
3154         .stop_watchdog = cs_dsp_stop_watchdog,
3155 
3156         .enable_memory = cs_dsp_adsp2_enable_memory,
3157         .disable_memory = cs_dsp_adsp2_disable_memory,
3158         .lock_memory = cs_dsp_adsp2_lock,
3159 
3160         .enable_core = cs_dsp_adsp2v2_enable_core,
3161         .disable_core = cs_dsp_adsp2v2_disable_core,
3162 
3163         .start_core = cs_dsp_adsp2_start_core,
3164         .stop_core = cs_dsp_adsp2_stop_core,
3165     },
3166 };
3167 
3168 static const struct cs_dsp_ops cs_dsp_halo_ops = {
3169     .parse_sizes = cs_dsp_adsp2_parse_sizes,
3170     .validate_version = cs_dsp_halo_validate_version,
3171     .setup_algs = cs_dsp_halo_setup_algs,
3172     .region_to_reg = cs_dsp_halo_region_to_reg,
3173 
3174     .show_fw_status = cs_dsp_halo_show_fw_status,
3175     .stop_watchdog = cs_dsp_halo_stop_watchdog,
3176 
3177     .lock_memory = cs_dsp_halo_configure_mpu,
3178 
3179     .start_core = cs_dsp_halo_start_core,
3180     .stop_core = cs_dsp_halo_stop_core,
3181 };
3182 
3183 /**
3184  * cs_dsp_chunk_write() - Format data to a DSP memory chunk
3185  * @ch: Pointer to the chunk structure
3186  * @nbits: Number of bits to write
3187  * @val: Value to write
3188  *
3189  * This function sequentially writes values into the format required for DSP
3190  * memory, it handles both inserting of the padding bytes and converting to
3191  * big endian. Note that data is only committed to the chunk when a whole DSP
3192  * words worth of data is available.
3193  *
3194  * Return: Zero for success, a negative number on error.
3195  */
3196 int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val)
3197 {
3198     int nwrite, i;
3199 
3200     nwrite = min(CS_DSP_DATA_WORD_BITS - ch->cachebits, nbits);
3201 
3202     ch->cache <<= nwrite;
3203     ch->cache |= val >> (nbits - nwrite);
3204     ch->cachebits += nwrite;
3205     nbits -= nwrite;
3206 
3207     if (ch->cachebits == CS_DSP_DATA_WORD_BITS) {
3208         if (cs_dsp_chunk_end(ch))
3209             return -ENOSPC;
3210 
3211         ch->cache &= 0xFFFFFF;
3212         for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE)
3213             *ch->data++ = (ch->cache & 0xFF000000) >> CS_DSP_DATA_WORD_BITS;
3214 
3215         ch->bytes += sizeof(ch->cache);
3216         ch->cachebits = 0;
3217     }
3218 
3219     if (nbits)
3220         return cs_dsp_chunk_write(ch, nbits, val);
3221 
3222     return 0;
3223 }
3224 EXPORT_SYMBOL_GPL(cs_dsp_chunk_write);
3225 
3226 /**
3227  * cs_dsp_chunk_flush() - Pad remaining data with zero and commit to chunk
3228  * @ch: Pointer to the chunk structure
3229  *
3230  * As cs_dsp_chunk_write only writes data when a whole DSP word is ready to
3231  * be written out it is possible that some data will remain in the cache, this
3232  * function will pad that data with zeros upto a whole DSP word and write out.
3233  *
3234  * Return: Zero for success, a negative number on error.
3235  */
3236 int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch)
3237 {
3238     if (!ch->cachebits)
3239         return 0;
3240 
3241     return cs_dsp_chunk_write(ch, CS_DSP_DATA_WORD_BITS - ch->cachebits, 0);
3242 }
3243 EXPORT_SYMBOL_GPL(cs_dsp_chunk_flush);
3244 
3245 /**
3246  * cs_dsp_chunk_read() - Parse data from a DSP memory chunk
3247  * @ch: Pointer to the chunk structure
3248  * @nbits: Number of bits to read
3249  *
3250  * This function sequentially reads values from a DSP memory formatted buffer,
3251  * it handles both removing of the padding bytes and converting from big endian.
3252  *
3253  * Return: A negative number is returned on error, otherwise the read value.
3254  */
3255 int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits)
3256 {
3257     int nread, i;
3258     u32 result;
3259 
3260     if (!ch->cachebits) {
3261         if (cs_dsp_chunk_end(ch))
3262             return -ENOSPC;
3263 
3264         ch->cache = 0;
3265         ch->cachebits = CS_DSP_DATA_WORD_BITS;
3266 
3267         for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE)
3268             ch->cache |= *ch->data++;
3269 
3270         ch->bytes += sizeof(ch->cache);
3271     }
3272 
3273     nread = min(ch->cachebits, nbits);
3274     nbits -= nread;
3275 
3276     result = ch->cache >> ((sizeof(ch->cache) * BITS_PER_BYTE) - nread);
3277     ch->cache <<= nread;
3278     ch->cachebits -= nread;
3279 
3280     if (nbits)
3281         result = (result << nbits) | cs_dsp_chunk_read(ch, nbits);
3282 
3283     return result;
3284 }
3285 EXPORT_SYMBOL_GPL(cs_dsp_chunk_read);
3286 
3287 MODULE_DESCRIPTION("Cirrus Logic DSP Support");
3288 MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
3289 MODULE_LICENSE("GPL v2");