Lines Matching +full:blk +full:- +full:ctrl

1 // SPDX-License-Identifier: GPL-2.0-only
3 * cs_dsp.c -- Cirrus Logic DSP firmware support
8 * Copyright (C) 2015-2021 Cirrus Logic, Inc. and
26 dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
28 dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
30 dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
32 dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
69 #define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
70 #define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
71 #define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
332 buf->buf = vmalloc(len); in cs_dsp_buf_alloc()
333 if (!buf->buf) { in cs_dsp_buf_alloc()
337 memcpy(buf->buf, src, len); in cs_dsp_buf_alloc()
340 list_add_tail(&buf->list, list); in cs_dsp_buf_alloc()
351 list_del(&buf->list); in cs_dsp_buf_free()
352 vfree(buf->buf); in cs_dsp_buf_free()
358 * cs_dsp_mem_region_name() - Return a name string for a memory type
393 kfree(dsp->wmfw_file_name); in cs_dsp_debugfs_save_wmfwname()
394 dsp->wmfw_file_name = tmp; in cs_dsp_debugfs_save_wmfwname()
401 kfree(dsp->bin_file_name); in cs_dsp_debugfs_save_binname()
402 dsp->bin_file_name = tmp; in cs_dsp_debugfs_save_binname()
407 kfree(dsp->wmfw_file_name); in cs_dsp_debugfs_clear()
408 kfree(dsp->bin_file_name); in cs_dsp_debugfs_clear()
409 dsp->wmfw_file_name = NULL; in cs_dsp_debugfs_clear()
410 dsp->bin_file_name = NULL; in cs_dsp_debugfs_clear()
417 struct cs_dsp *dsp = file->private_data; in cs_dsp_debugfs_wmfw_read()
420 mutex_lock(&dsp->pwr_lock); in cs_dsp_debugfs_wmfw_read()
422 if (!dsp->wmfw_file_name || !dsp->booted) in cs_dsp_debugfs_wmfw_read()
426 dsp->wmfw_file_name, in cs_dsp_debugfs_wmfw_read()
427 strlen(dsp->wmfw_file_name)); in cs_dsp_debugfs_wmfw_read()
429 mutex_unlock(&dsp->pwr_lock); in cs_dsp_debugfs_wmfw_read()
437 struct cs_dsp *dsp = file->private_data; in cs_dsp_debugfs_bin_read()
440 mutex_lock(&dsp->pwr_lock); in cs_dsp_debugfs_bin_read()
442 if (!dsp->bin_file_name || !dsp->booted) in cs_dsp_debugfs_bin_read()
446 dsp->bin_file_name, in cs_dsp_debugfs_bin_read()
447 strlen(dsp->bin_file_name)); in cs_dsp_debugfs_bin_read()
449 mutex_unlock(&dsp->pwr_lock); in cs_dsp_debugfs_bin_read()
478 struct cs_dsp *dsp = s->private; in cs_dsp_debugfs_read_controls_show()
482 list_for_each_entry(ctl, &dsp->ctl_list, list) { in cs_dsp_debugfs_read_controls_show()
485 ctl->subname_len, ctl->subname, ctl->len, in cs_dsp_debugfs_read_controls_show()
486 cs_dsp_mem_region_name(ctl->alg_region.type), in cs_dsp_debugfs_read_controls_show()
487 ctl->offset, reg, ctl->fw_name, ctl->alg_region.alg, ctl->type, in cs_dsp_debugfs_read_controls_show()
488 ctl->flags & WMFW_CTL_FLAG_VOLATILE ? 'V' : '-', in cs_dsp_debugfs_read_controls_show()
489 ctl->flags & WMFW_CTL_FLAG_SYS ? 'S' : '-', in cs_dsp_debugfs_read_controls_show()
490 ctl->flags & WMFW_CTL_FLAG_READABLE ? 'R' : '-', in cs_dsp_debugfs_read_controls_show()
491 ctl->flags & WMFW_CTL_FLAG_WRITEABLE ? 'W' : '-', in cs_dsp_debugfs_read_controls_show()
492 ctl->enabled ? "enabled" : "disabled", in cs_dsp_debugfs_read_controls_show()
493 ctl->set ? "dirty" : "clean"); in cs_dsp_debugfs_read_controls_show()
501 * cs_dsp_init_debugfs() - Create and populate DSP representation in debugfs
511 root = debugfs_create_dir(dsp->name, debugfs_root); in cs_dsp_init_debugfs()
513 debugfs_create_bool("booted", 0444, root, &dsp->booted); in cs_dsp_init_debugfs()
514 debugfs_create_bool("running", 0444, root, &dsp->running); in cs_dsp_init_debugfs()
515 debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id); in cs_dsp_init_debugfs()
516 debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version); in cs_dsp_init_debugfs()
525 dsp->debugfs_root = root; in cs_dsp_init_debugfs()
530 * cs_dsp_cleanup_debugfs() - Removes DSP representation from debugfs
536 debugfs_remove_recursive(dsp->debugfs_root); in cs_dsp_cleanup_debugfs()
537 dsp->debugfs_root = ERR_PTR(-ENODEV); in cs_dsp_cleanup_debugfs()
571 for (i = 0; i < dsp->num_mems; i++) in cs_dsp_find_region()
572 if (dsp->mem[i].type == type) in cs_dsp_find_region()
573 return &dsp->mem[i]; in cs_dsp_find_region()
581 switch (mem->type) { in cs_dsp_region_to_reg()
583 return mem->base + (offset * 3); in cs_dsp_region_to_reg()
588 return mem->base + (offset * 2); in cs_dsp_region_to_reg()
598 switch (mem->type) { in cs_dsp_halo_region_to_reg()
601 return mem->base + (offset * 4); in cs_dsp_halo_region_to_reg()
604 return (mem->base + (offset * 3)) & ~0x3; in cs_dsp_halo_region_to_reg()
606 return mem->base + (offset * 5); in cs_dsp_halo_region_to_reg()
620 ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]); in cs_dsp_read_fw_status()
666 const struct cs_dsp_alg_region *alg_region = &ctl->alg_region; in cs_dsp_coeff_base_reg()
667 struct cs_dsp *dsp = ctl->dsp; in cs_dsp_coeff_base_reg()
670 mem = cs_dsp_find_region(dsp, alg_region->type); in cs_dsp_coeff_base_reg()
673 alg_region->type); in cs_dsp_coeff_base_reg()
674 return -EINVAL; in cs_dsp_coeff_base_reg()
677 *reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset + off); in cs_dsp_coeff_base_reg()
683 * cs_dsp_coeff_write_acked_control() - Sends event_id to the acked control
696 struct cs_dsp *dsp = ctl->dsp; in cs_dsp_coeff_write_acked_control()
701 lockdep_assert_held(&dsp->pwr_lock); in cs_dsp_coeff_write_acked_control()
703 if (!dsp->running) in cs_dsp_coeff_write_acked_control()
704 return -EPERM; in cs_dsp_coeff_write_acked_control()
711 event_id, ctl->alg_region.alg, in cs_dsp_coeff_write_acked_control()
712 cs_dsp_mem_region_name(ctl->alg_region.type), ctl->offset); in cs_dsp_coeff_write_acked_control()
714 ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val)); in cs_dsp_coeff_write_acked_control()
728 case 0 ... CS_DSP_ACKED_CTL_N_QUICKPOLLS - 1: in cs_dsp_coeff_write_acked_control()
738 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); in cs_dsp_coeff_write_acked_control()
751 reg, ctl->alg_region.alg, in cs_dsp_coeff_write_acked_control()
752 cs_dsp_mem_region_name(ctl->alg_region.type), in cs_dsp_coeff_write_acked_control()
753 ctl->offset); in cs_dsp_coeff_write_acked_control()
755 return -ETIMEDOUT; in cs_dsp_coeff_write_acked_control()
762 struct cs_dsp *dsp = ctl->dsp; in cs_dsp_coeff_write_ctrl_raw()
773 return -ENOMEM; in cs_dsp_coeff_write_ctrl_raw()
775 ret = regmap_raw_write(dsp->regmap, reg, scratch, in cs_dsp_coeff_write_ctrl_raw()
791 * cs_dsp_coeff_write_ctrl() - Writes the given buffer to the given coefficient control
807 return -ENOENT; in cs_dsp_coeff_write_ctrl()
809 lockdep_assert_held(&ctl->dsp->pwr_lock); in cs_dsp_coeff_write_ctrl()
811 if (ctl->flags && !(ctl->flags & WMFW_CTL_FLAG_WRITEABLE)) in cs_dsp_coeff_write_ctrl()
812 return -EPERM; in cs_dsp_coeff_write_ctrl()
814 if (len + off * sizeof(u32) > ctl->len) in cs_dsp_coeff_write_ctrl()
815 return -EINVAL; in cs_dsp_coeff_write_ctrl()
817 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { in cs_dsp_coeff_write_ctrl()
818 ret = -EPERM; in cs_dsp_coeff_write_ctrl()
819 } else if (buf != ctl->cache) { in cs_dsp_coeff_write_ctrl()
820 if (memcmp(ctl->cache + off * sizeof(u32), buf, len)) in cs_dsp_coeff_write_ctrl()
821 memcpy(ctl->cache + off * sizeof(u32), buf, len); in cs_dsp_coeff_write_ctrl()
826 ctl->set = 1; in cs_dsp_coeff_write_ctrl()
827 if (ctl->enabled && ctl->dsp->running) in cs_dsp_coeff_write_ctrl()
838 * cs_dsp_coeff_lock_and_write_ctrl() - Writes the given buffer to the given coefficient control
851 struct cs_dsp *dsp = ctl->dsp; in cs_dsp_coeff_lock_and_write_ctrl()
854 lockdep_assert_not_held(&dsp->pwr_lock); in cs_dsp_coeff_lock_and_write_ctrl()
856 mutex_lock(&dsp->pwr_lock); in cs_dsp_coeff_lock_and_write_ctrl()
858 mutex_unlock(&dsp->pwr_lock); in cs_dsp_coeff_lock_and_write_ctrl()
867 struct cs_dsp *dsp = ctl->dsp; in cs_dsp_coeff_read_ctrl_raw()
878 return -ENOMEM; in cs_dsp_coeff_read_ctrl_raw()
880 ret = regmap_raw_read(dsp->regmap, reg, scratch, len); in cs_dsp_coeff_read_ctrl_raw()
896 * cs_dsp_coeff_read_ctrl() - Reads the given coefficient control into the given buffer
912 return -ENOENT; in cs_dsp_coeff_read_ctrl()
914 lockdep_assert_held(&ctl->dsp->pwr_lock); in cs_dsp_coeff_read_ctrl()
916 if (len + off * sizeof(u32) > ctl->len) in cs_dsp_coeff_read_ctrl()
917 return -EINVAL; in cs_dsp_coeff_read_ctrl()
919 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { in cs_dsp_coeff_read_ctrl()
920 if (ctl->enabled && ctl->dsp->running) in cs_dsp_coeff_read_ctrl()
923 return -EPERM; in cs_dsp_coeff_read_ctrl()
925 if (!ctl->flags && ctl->enabled && ctl->dsp->running) in cs_dsp_coeff_read_ctrl()
926 ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len); in cs_dsp_coeff_read_ctrl()
928 if (buf != ctl->cache) in cs_dsp_coeff_read_ctrl()
929 memcpy(buf, ctl->cache + off * sizeof(u32), len); in cs_dsp_coeff_read_ctrl()
937 * cs_dsp_coeff_lock_and_read_ctrl() - Reads the given coefficient control into the given buffer
950 struct cs_dsp *dsp = ctl->dsp; in cs_dsp_coeff_lock_and_read_ctrl()
953 lockdep_assert_not_held(&dsp->pwr_lock); in cs_dsp_coeff_lock_and_read_ctrl()
955 mutex_lock(&dsp->pwr_lock); in cs_dsp_coeff_lock_and_read_ctrl()
957 mutex_unlock(&dsp->pwr_lock); in cs_dsp_coeff_lock_and_read_ctrl()
968 list_for_each_entry(ctl, &dsp->ctl_list, list) { in cs_dsp_coeff_init_control_caches()
969 if (!ctl->enabled || ctl->set) in cs_dsp_coeff_init_control_caches()
971 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) in cs_dsp_coeff_init_control_caches()
976 * For non-readable controls the cache was zero-filled when in cs_dsp_coeff_init_control_caches()
979 if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) { in cs_dsp_coeff_init_control_caches()
980 ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len); in cs_dsp_coeff_init_control_caches()
994 list_for_each_entry(ctl, &dsp->ctl_list, list) { in cs_dsp_coeff_sync_controls()
995 if (!ctl->enabled) in cs_dsp_coeff_sync_controls()
997 if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) { in cs_dsp_coeff_sync_controls()
998 ret = cs_dsp_coeff_write_ctrl_raw(ctl, 0, ctl->cache, in cs_dsp_coeff_sync_controls()
999 ctl->len); in cs_dsp_coeff_sync_controls()
1014 list_for_each_entry(ctl, &dsp->ctl_list, list) { in cs_dsp_signal_event_controls()
1015 if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT) in cs_dsp_signal_event_controls()
1018 if (!ctl->enabled) in cs_dsp_signal_event_controls()
1025 event, ctl->alg_region.alg, ret); in cs_dsp_signal_event_controls()
1031 kfree(ctl->cache); in cs_dsp_free_ctl_blk()
1032 kfree(ctl->subname); in cs_dsp_free_ctl_blk()
1045 list_for_each_entry(ctl, &dsp->ctl_list, list) { in cs_dsp_create_control()
1046 if (ctl->fw_name == dsp->fw_name && in cs_dsp_create_control()
1047 ctl->alg_region.alg == alg_region->alg && in cs_dsp_create_control()
1048 ctl->alg_region.type == alg_region->type) { in cs_dsp_create_control()
1049 if ((!subname && !ctl->subname) || in cs_dsp_create_control()
1050 (subname && (ctl->subname_len == subname_len) && in cs_dsp_create_control()
1051 !strncmp(ctl->subname, subname, ctl->subname_len))) { in cs_dsp_create_control()
1052 if (!ctl->enabled) in cs_dsp_create_control()
1053 ctl->enabled = 1; in cs_dsp_create_control()
1061 return -ENOMEM; in cs_dsp_create_control()
1063 ctl->fw_name = dsp->fw_name; in cs_dsp_create_control()
1064 ctl->alg_region = *alg_region; in cs_dsp_create_control()
1065 if (subname && dsp->wmfw_ver >= 2) { in cs_dsp_create_control()
1066 ctl->subname_len = subname_len; in cs_dsp_create_control()
1067 ctl->subname = kasprintf(GFP_KERNEL, "%.*s", subname_len, subname); in cs_dsp_create_control()
1068 if (!ctl->subname) { in cs_dsp_create_control()
1069 ret = -ENOMEM; in cs_dsp_create_control()
1073 ctl->enabled = 1; in cs_dsp_create_control()
1074 ctl->set = 0; in cs_dsp_create_control()
1075 ctl->dsp = dsp; in cs_dsp_create_control()
1077 ctl->flags = flags; in cs_dsp_create_control()
1078 ctl->type = type; in cs_dsp_create_control()
1079 ctl->offset = offset; in cs_dsp_create_control()
1080 ctl->len = len; in cs_dsp_create_control()
1081 ctl->cache = kzalloc(ctl->len, GFP_KERNEL); in cs_dsp_create_control()
1082 if (!ctl->cache) { in cs_dsp_create_control()
1083 ret = -ENOMEM; in cs_dsp_create_control()
1087 list_add(&ctl->list, &dsp->ctl_list); in cs_dsp_create_control()
1089 if (dsp->client_ops->control_add) { in cs_dsp_create_control()
1090 ret = dsp->client_ops->control_add(ctl); in cs_dsp_create_control()
1098 list_del(&ctl->list); in cs_dsp_create_control()
1099 kfree(ctl->cache); in cs_dsp_create_control()
1101 kfree(ctl->subname); in cs_dsp_create_control()
1183 struct cs_dsp_coeff_parsed_alg *blk) in cs_dsp_coeff_parse_alg() argument
1186 unsigned int data_len = le32_to_cpu(region->len); in cs_dsp_coeff_parse_alg()
1190 raw = (const struct wmfw_adsp_alg_data *)region->data; in cs_dsp_coeff_parse_alg()
1192 switch (dsp->wmfw_ver) { in cs_dsp_coeff_parse_alg()
1196 return -EOVERFLOW; in cs_dsp_coeff_parse_alg()
1198 blk->id = le32_to_cpu(raw->id); in cs_dsp_coeff_parse_alg()
1199 blk->name = raw->name; in cs_dsp_coeff_parse_alg()
1200 blk->name_len = strnlen(raw->name, ARRAY_SIZE(raw->name)); in cs_dsp_coeff_parse_alg()
1201 blk->ncoeff = le32_to_cpu(raw->ncoeff); in cs_dsp_coeff_parse_alg()
1206 if (sizeof(raw->id) > data_len) in cs_dsp_coeff_parse_alg()
1207 return -EOVERFLOW; in cs_dsp_coeff_parse_alg()
1209 tmp = region->data; in cs_dsp_coeff_parse_alg()
1210 blk->id = cs_dsp_coeff_parse_int(sizeof(raw->id), &tmp); in cs_dsp_coeff_parse_alg()
1211 pos = tmp - region->data; in cs_dsp_coeff_parse_alg()
1213 tmp = &region->data[pos]; in cs_dsp_coeff_parse_alg()
1214 blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp, data_len - pos, in cs_dsp_coeff_parse_alg()
1215 &blk->name); in cs_dsp_coeff_parse_alg()
1217 return -EOVERFLOW; in cs_dsp_coeff_parse_alg()
1219 pos = tmp - region->data; in cs_dsp_coeff_parse_alg()
1220 cs_dsp_coeff_parse_string(sizeof(u16), &tmp, data_len - pos, NULL); in cs_dsp_coeff_parse_alg()
1222 return -EOVERFLOW; in cs_dsp_coeff_parse_alg()
1224 pos = tmp - region->data; in cs_dsp_coeff_parse_alg()
1225 if (sizeof(raw->ncoeff) > (data_len - pos)) in cs_dsp_coeff_parse_alg()
1226 return -EOVERFLOW; in cs_dsp_coeff_parse_alg()
1228 blk->ncoeff = cs_dsp_coeff_parse_int(sizeof(raw->ncoeff), &tmp); in cs_dsp_coeff_parse_alg()
1229 pos += sizeof(raw->ncoeff); in cs_dsp_coeff_parse_alg()
1233 if ((int)blk->ncoeff < 0) in cs_dsp_coeff_parse_alg()
1234 return -EOVERFLOW; in cs_dsp_coeff_parse_alg()
1236 cs_dsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); in cs_dsp_coeff_parse_alg()
1237 cs_dsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); in cs_dsp_coeff_parse_alg()
1238 cs_dsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff); in cs_dsp_coeff_parse_alg()
1246 struct cs_dsp_coeff_parsed_coeff *blk) in cs_dsp_coeff_parse_coeff() argument
1249 unsigned int data_len = le32_to_cpu(region->len); in cs_dsp_coeff_parse_coeff()
1253 raw = (const struct wmfw_adsp_coeff_data *)&region->data[pos]; in cs_dsp_coeff_parse_coeff()
1254 if (sizeof(raw->hdr) > (data_len - pos)) in cs_dsp_coeff_parse_coeff()
1255 return -EOVERFLOW; in cs_dsp_coeff_parse_coeff()
1257 blk_len = le32_to_cpu(raw->hdr.size); in cs_dsp_coeff_parse_coeff()
1259 return -EOVERFLOW; in cs_dsp_coeff_parse_coeff()
1261 if (blk_len > (data_len - pos - sizeof(raw->hdr))) in cs_dsp_coeff_parse_coeff()
1262 return -EOVERFLOW; in cs_dsp_coeff_parse_coeff()
1264 blk_end_pos = pos + sizeof(raw->hdr) + blk_len; in cs_dsp_coeff_parse_coeff()
1266 blk->offset = le16_to_cpu(raw->hdr.offset); in cs_dsp_coeff_parse_coeff()
1267 blk->mem_type = le16_to_cpu(raw->hdr.type); in cs_dsp_coeff_parse_coeff()
1269 switch (dsp->wmfw_ver) { in cs_dsp_coeff_parse_coeff()
1272 if (sizeof(*raw) > (data_len - pos)) in cs_dsp_coeff_parse_coeff()
1273 return -EOVERFLOW; in cs_dsp_coeff_parse_coeff()
1275 blk->name = raw->name; in cs_dsp_coeff_parse_coeff()
1276 blk->name_len = strnlen(raw->name, ARRAY_SIZE(raw->name)); in cs_dsp_coeff_parse_coeff()
1277 blk->ctl_type = le16_to_cpu(raw->ctl_type); in cs_dsp_coeff_parse_coeff()
1278 blk->flags = le16_to_cpu(raw->flags); in cs_dsp_coeff_parse_coeff()
1279 blk->len = le32_to_cpu(raw->len); in cs_dsp_coeff_parse_coeff()
1282 pos += sizeof(raw->hdr); in cs_dsp_coeff_parse_coeff()
1283 tmp = &region->data[pos]; in cs_dsp_coeff_parse_coeff()
1284 blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp, data_len - pos, in cs_dsp_coeff_parse_coeff()
1285 &blk->name); in cs_dsp_coeff_parse_coeff()
1287 return -EOVERFLOW; in cs_dsp_coeff_parse_coeff()
1289 pos = tmp - region->data; in cs_dsp_coeff_parse_coeff()
1290 cs_dsp_coeff_parse_string(sizeof(u8), &tmp, data_len - pos, NULL); in cs_dsp_coeff_parse_coeff()
1292 return -EOVERFLOW; in cs_dsp_coeff_parse_coeff()
1294 pos = tmp - region->data; in cs_dsp_coeff_parse_coeff()
1295 cs_dsp_coeff_parse_string(sizeof(u16), &tmp, data_len - pos, NULL); in cs_dsp_coeff_parse_coeff()
1297 return -EOVERFLOW; in cs_dsp_coeff_parse_coeff()
1299 pos = tmp - region->data; in cs_dsp_coeff_parse_coeff()
1300 if (sizeof(raw->ctl_type) + sizeof(raw->flags) + sizeof(raw->len) > in cs_dsp_coeff_parse_coeff()
1301 (data_len - pos)) in cs_dsp_coeff_parse_coeff()
1302 return -EOVERFLOW; in cs_dsp_coeff_parse_coeff()
1304 blk->ctl_type = cs_dsp_coeff_parse_int(sizeof(raw->ctl_type), &tmp); in cs_dsp_coeff_parse_coeff()
1305 pos += sizeof(raw->ctl_type); in cs_dsp_coeff_parse_coeff()
1306 blk->flags = cs_dsp_coeff_parse_int(sizeof(raw->flags), &tmp); in cs_dsp_coeff_parse_coeff()
1307 pos += sizeof(raw->flags); in cs_dsp_coeff_parse_coeff()
1308 blk->len = cs_dsp_coeff_parse_int(sizeof(raw->len), &tmp); in cs_dsp_coeff_parse_coeff()
1312 cs_dsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type); in cs_dsp_coeff_parse_coeff()
1313 cs_dsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset); in cs_dsp_coeff_parse_coeff()
1314 cs_dsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name); in cs_dsp_coeff_parse_coeff()
1315 cs_dsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags); in cs_dsp_coeff_parse_coeff()
1316 cs_dsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type); in cs_dsp_coeff_parse_coeff()
1317 cs_dsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); in cs_dsp_coeff_parse_coeff()
1327 if ((coeff_blk->flags & f_illegal) || in cs_dsp_check_coeff_flags()
1328 ((coeff_blk->flags & f_required) != f_required)) { in cs_dsp_check_coeff_flags()
1330 coeff_blk->flags, coeff_blk->ctl_type); in cs_dsp_check_coeff_flags()
1331 return -EINVAL; in cs_dsp_check_coeff_flags()
1367 return -EINVAL; in cs_dsp_parse_coeff()
1378 return -EINVAL; in cs_dsp_parse_coeff()
1387 return -EINVAL; in cs_dsp_parse_coeff()
1392 return -EINVAL; in cs_dsp_parse_coeff()
1420 adsp1_sizes = (void *)&firmware->data[pos]; in cs_dsp_adsp1_parse_sizes()
1421 if (sizeof(*adsp1_sizes) > firmware->size - pos) { in cs_dsp_adsp1_parse_sizes()
1427 le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm), in cs_dsp_adsp1_parse_sizes()
1428 le32_to_cpu(adsp1_sizes->zm)); in cs_dsp_adsp1_parse_sizes()
1440 adsp2_sizes = (void *)&firmware->data[pos]; in cs_dsp_adsp2_parse_sizes()
1441 if (sizeof(*adsp2_sizes) > firmware->size - pos) { in cs_dsp_adsp2_parse_sizes()
1447 le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym), in cs_dsp_adsp2_parse_sizes()
1448 le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm)); in cs_dsp_adsp2_parse_sizes()
1481 struct regmap *regmap = dsp->regmap; in cs_dsp_load()
1496 ret = -EINVAL; in cs_dsp_load()
1498 if (sizeof(*header) >= firmware->size) { in cs_dsp_load()
1499 ret = -EOVERFLOW; in cs_dsp_load()
1503 header = (void *)&firmware->data[0]; in cs_dsp_load()
1505 if (memcmp(&header->magic[0], "WMFW", 4) != 0) { in cs_dsp_load()
1510 if (!dsp->ops->validate_version(dsp, header->ver)) { in cs_dsp_load()
1512 file, header->ver); in cs_dsp_load()
1516 dsp->wmfw_ver = header->ver; in cs_dsp_load()
1518 if (header->core != dsp->type) { in cs_dsp_load()
1520 file, header->core, dsp->type); in cs_dsp_load()
1525 pos = dsp->ops->parse_sizes(dsp, file, pos, firmware); in cs_dsp_load()
1526 if ((pos == 0) || (sizeof(*footer) > firmware->size - pos)) { in cs_dsp_load()
1527 ret = -EOVERFLOW; in cs_dsp_load()
1531 footer = (void *)&firmware->data[pos]; in cs_dsp_load()
1534 if (le32_to_cpu(header->len) != pos) { in cs_dsp_load()
1535 ret = -EOVERFLOW; in cs_dsp_load()
1539 cs_dsp_info(dsp, "%s: format %d timestamp %#llx\n", file, header->ver, in cs_dsp_load()
1540 le64_to_cpu(footer->timestamp)); in cs_dsp_load()
1542 while (pos < firmware->size) { in cs_dsp_load()
1544 if (sizeof(*region) > firmware->size - pos) { in cs_dsp_load()
1545 ret = -EOVERFLOW; in cs_dsp_load()
1549 region = (void *)&(firmware->data[pos]); in cs_dsp_load()
1551 if (le32_to_cpu(region->len) > firmware->size - pos - sizeof(*region)) { in cs_dsp_load()
1552 ret = -EOVERFLOW; in cs_dsp_load()
1558 offset = le32_to_cpu(region->offset) & 0xffffff; in cs_dsp_load()
1559 type = be32_to_cpu(region->type) & 0xff; in cs_dsp_load()
1566 min(le32_to_cpu(region->len), 100), region->data); in cs_dsp_load()
1589 ret = -EINVAL; in cs_dsp_load()
1594 reg = dsp->ops->region_to_reg(mem, offset); in cs_dsp_load()
1604 regions, le32_to_cpu(region->len), offset, in cs_dsp_load()
1608 buf = cs_dsp_buf_alloc(region->data, in cs_dsp_load()
1609 le32_to_cpu(region->len), in cs_dsp_load()
1613 ret = -ENOMEM; in cs_dsp_load()
1617 ret = regmap_raw_write(regmap, reg, buf->buf, in cs_dsp_load()
1618 le32_to_cpu(region->len)); in cs_dsp_load()
1623 le32_to_cpu(region->len), offset, in cs_dsp_load()
1629 pos += le32_to_cpu(region->len) + sizeof(*region); in cs_dsp_load()
1633 if (pos > firmware->size) in cs_dsp_load()
1635 file, regions, pos - firmware->size); in cs_dsp_load()
1643 if (ret == -EOVERFLOW) in cs_dsp_load()
1650 * cs_dsp_get_ctl() - Finds a matching coefficient control
1665 lockdep_assert_held(&dsp->pwr_lock); in cs_dsp_get_ctl()
1667 list_for_each_entry(pos, &dsp->ctl_list, list) { in cs_dsp_get_ctl()
1668 if (!pos->subname) in cs_dsp_get_ctl()
1670 if (strncmp(pos->subname, name, pos->subname_len) == 0 && in cs_dsp_get_ctl()
1671 pos->fw_name == dsp->fw_name && in cs_dsp_get_ctl()
1672 pos->alg_region.alg == alg && in cs_dsp_get_ctl()
1673 pos->alg_region.type == type) { in cs_dsp_get_ctl()
1688 list_for_each_entry(ctl, &dsp->ctl_list, list) { in cs_dsp_ctl_fixup_base()
1689 if (ctl->fw_name == dsp->fw_name && in cs_dsp_ctl_fixup_base()
1690 alg_region->alg == ctl->alg_region.alg && in cs_dsp_ctl_fixup_base()
1691 alg_region->type == ctl->alg_region.type) { in cs_dsp_ctl_fixup_base()
1692 ctl->alg_region.base = alg_region->base; in cs_dsp_ctl_fixup_base()
1708 return ERR_PTR(-EINVAL); in cs_dsp_read_algs()
1713 return ERR_PTR(-EINVAL); in cs_dsp_read_algs()
1717 reg = dsp->ops->region_to_reg(mem, pos + len); in cs_dsp_read_algs()
1719 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); in cs_dsp_read_algs()
1735 return ERR_PTR(-ENOMEM); in cs_dsp_read_algs()
1737 reg = dsp->ops->region_to_reg(mem, pos); in cs_dsp_read_algs()
1739 ret = regmap_raw_read(dsp->regmap, reg, alg, len); in cs_dsp_read_algs()
1750 * cs_dsp_find_alg_region() - Finds a matching algorithm region
1762 lockdep_assert_held(&dsp->pwr_lock); in cs_dsp_find_alg_region()
1764 list_for_each_entry(item, &dsp->alg_regions, list) { in cs_dsp_find_alg_region()
1765 if (id == item->alg_region.alg && type == item->alg_region.type) in cs_dsp_find_alg_region()
1766 return &item->alg_region; in cs_dsp_find_alg_region()
1781 return ERR_PTR(-ENOMEM); in cs_dsp_create_region()
1783 item->alg_region.type = type; in cs_dsp_create_region()
1784 item->alg_region.alg = be32_to_cpu(id); in cs_dsp_create_region()
1785 item->alg_region.ver = be32_to_cpu(ver); in cs_dsp_create_region()
1786 item->alg_region.base = be32_to_cpu(base); in cs_dsp_create_region()
1788 list_add_tail(&item->list, &dsp->alg_regions); in cs_dsp_create_region()
1790 if (dsp->wmfw_ver > 0) in cs_dsp_create_region()
1791 cs_dsp_ctl_fixup_base(dsp, &item->alg_region); in cs_dsp_create_region()
1793 return &item->alg_region; in cs_dsp_create_region()
1800 while (!list_empty(&dsp->alg_regions)) { in cs_dsp_free_alg_regions()
1801 item = list_first_entry(&dsp->alg_regions, in cs_dsp_free_alg_regions()
1804 list_del(&item->list); in cs_dsp_free_alg_regions()
1812 dsp->fw_id = be32_to_cpu(fw->id); in cs_dsp_parse_wmfw_id_header()
1813 dsp->fw_id_version = be32_to_cpu(fw->ver); in cs_dsp_parse_wmfw_id_header()
1816 dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16, in cs_dsp_parse_wmfw_id_header()
1817 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, in cs_dsp_parse_wmfw_id_header()
1824 dsp->fw_id = be32_to_cpu(fw->id); in cs_dsp_parse_wmfw_v3_id_header()
1825 dsp->fw_id_version = be32_to_cpu(fw->ver); in cs_dsp_parse_wmfw_v3_id_header()
1826 dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id); in cs_dsp_parse_wmfw_v3_id_header()
1829 dsp->fw_id, dsp->fw_vendor_id, in cs_dsp_parse_wmfw_v3_id_header()
1830 (dsp->fw_id_version & 0xff0000) >> 16, in cs_dsp_parse_wmfw_v3_id_header()
1831 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, in cs_dsp_parse_wmfw_v3_id_header()
1862 return -EINVAL; in cs_dsp_adsp1_setup_algs()
1864 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id, in cs_dsp_adsp1_setup_algs()
1913 if (dsp->wmfw_ver == 0) { in cs_dsp_adsp1_setup_algs()
1916 len -= be32_to_cpu(adsp1_alg[i].dm); in cs_dsp_adsp1_setup_algs()
1935 if (dsp->wmfw_ver == 0) { in cs_dsp_adsp1_setup_algs()
1938 len -= be32_to_cpu(adsp1_alg[i].zm); in cs_dsp_adsp1_setup_algs()
1967 return -EINVAL; in cs_dsp_adsp2_setup_algs()
1969 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id, in cs_dsp_adsp2_setup_algs()
2026 if (dsp->wmfw_ver == 0) { in cs_dsp_adsp2_setup_algs()
2029 len -= be32_to_cpu(adsp2_alg[i].xm); in cs_dsp_adsp2_setup_algs()
2048 if (dsp->wmfw_ver == 0) { in cs_dsp_adsp2_setup_algs()
2051 len -= be32_to_cpu(adsp2_alg[i].ym); in cs_dsp_adsp2_setup_algs()
2070 if (dsp->wmfw_ver == 0) { in cs_dsp_adsp2_setup_algs()
2073 len -= be32_to_cpu(adsp2_alg[i].zm); in cs_dsp_adsp2_setup_algs()
2113 return -EINVAL; in cs_dsp_halo_setup_algs()
2115 ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id, in cs_dsp_halo_setup_algs()
2167 struct regmap *regmap = dsp->regmap; in cs_dsp_load_coeff()
2169 struct wmfw_coeff_item *blk; in cs_dsp_load_coeff() local
2179 ret = -EINVAL; in cs_dsp_load_coeff()
2181 if (sizeof(*hdr) >= firmware->size) { in cs_dsp_load_coeff()
2183 file, firmware->size); in cs_dsp_load_coeff()
2187 hdr = (void *)&firmware->data[0]; in cs_dsp_load_coeff()
2188 if (memcmp(hdr->magic, "WMDR", 4) != 0) { in cs_dsp_load_coeff()
2193 switch (be32_to_cpu(hdr->rev) & 0xff) { in cs_dsp_load_coeff()
2199 file, be32_to_cpu(hdr->rev) & 0xff); in cs_dsp_load_coeff()
2200 ret = -EINVAL; in cs_dsp_load_coeff()
2205 (le32_to_cpu(hdr->ver) >> 16) & 0xff, in cs_dsp_load_coeff()
2206 (le32_to_cpu(hdr->ver) >> 8) & 0xff, in cs_dsp_load_coeff()
2207 le32_to_cpu(hdr->ver) & 0xff); in cs_dsp_load_coeff()
2209 pos = le32_to_cpu(hdr->len); in cs_dsp_load_coeff()
2212 while (pos < firmware->size) { in cs_dsp_load_coeff()
2214 if (sizeof(*blk) > firmware->size - pos) { in cs_dsp_load_coeff()
2215 ret = -EOVERFLOW; in cs_dsp_load_coeff()
2219 blk = (void *)(&firmware->data[pos]); in cs_dsp_load_coeff()
2221 if (le32_to_cpu(blk->len) > firmware->size - pos - sizeof(*blk)) { in cs_dsp_load_coeff()
2222 ret = -EOVERFLOW; in cs_dsp_load_coeff()
2226 type = le16_to_cpu(blk->type); in cs_dsp_load_coeff()
2227 offset = le16_to_cpu(blk->offset); in cs_dsp_load_coeff()
2228 version = le32_to_cpu(blk->ver) >> 8; in cs_dsp_load_coeff()
2231 file, blocks, le32_to_cpu(blk->id), in cs_dsp_load_coeff()
2232 (le32_to_cpu(blk->ver) >> 16) & 0xff, in cs_dsp_load_coeff()
2233 (le32_to_cpu(blk->ver) >> 8) & 0xff, in cs_dsp_load_coeff()
2234 le32_to_cpu(blk->ver) & 0xff); in cs_dsp_load_coeff()
2236 file, blocks, le32_to_cpu(blk->len), offset, type); in cs_dsp_load_coeff()
2242 cs_dsp_info(dsp, "%s: %.*s\n", dsp->fw_name, in cs_dsp_load_coeff()
2243 min(le32_to_cpu(blk->len), 100), blk->data); in cs_dsp_load_coeff()
2253 if (le32_to_cpu(blk->id) == dsp->fw_id && in cs_dsp_load_coeff()
2261 reg = dsp->ops->region_to_reg(mem, 0); in cs_dsp_load_coeff()
2277 file, blocks, le32_to_cpu(blk->len), in cs_dsp_load_coeff()
2278 type, le32_to_cpu(blk->id)); in cs_dsp_load_coeff()
2288 le32_to_cpu(blk->id)); in cs_dsp_load_coeff()
2290 if (version != alg_region->ver) in cs_dsp_load_coeff()
2296 (alg_region->ver >> 16) & 0xFF, in cs_dsp_load_coeff()
2297 (alg_region->ver >> 8) & 0xFF, in cs_dsp_load_coeff()
2298 alg_region->ver & 0xFF); in cs_dsp_load_coeff()
2300 reg = alg_region->base; in cs_dsp_load_coeff()
2301 reg = dsp->ops->region_to_reg(mem, reg); in cs_dsp_load_coeff()
2305 region_name, le32_to_cpu(blk->id)); in cs_dsp_load_coeff()
2316 buf = cs_dsp_buf_alloc(blk->data, in cs_dsp_load_coeff()
2317 le32_to_cpu(blk->len), in cs_dsp_load_coeff()
2321 ret = -ENOMEM; in cs_dsp_load_coeff()
2326 file, blocks, le32_to_cpu(blk->len), in cs_dsp_load_coeff()
2328 ret = regmap_raw_write(regmap, reg, buf->buf, in cs_dsp_load_coeff()
2329 le32_to_cpu(blk->len)); in cs_dsp_load_coeff()
2337 pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03; in cs_dsp_load_coeff()
2341 if (pos > firmware->size) in cs_dsp_load_coeff()
2343 file, blocks, pos - firmware->size); in cs_dsp_load_coeff()
2351 if (ret == -EOVERFLOW) in cs_dsp_load_coeff()
2359 if (!dsp->name) { in cs_dsp_create_name()
2360 dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d", in cs_dsp_create_name()
2361 dsp->num); in cs_dsp_create_name()
2362 if (!dsp->name) in cs_dsp_create_name()
2363 return -ENOMEM; in cs_dsp_create_name()
2377 INIT_LIST_HEAD(&dsp->alg_regions); in cs_dsp_common_init()
2378 INIT_LIST_HEAD(&dsp->ctl_list); in cs_dsp_common_init()
2380 mutex_init(&dsp->pwr_lock); in cs_dsp_common_init()
2384 dsp->debugfs_root = ERR_PTR(-ENODEV); in cs_dsp_common_init()
2391 * cs_dsp_adsp1_init() - Initialise a cs_dsp structure representing a ADSP1 device
2398 dsp->ops = &cs_dsp_adsp1_ops; in cs_dsp_adsp1_init()
2405 * cs_dsp_adsp1_power_up() - Load and start the named firmware
2411 * @fw_name: the user-friendly firmware name
2423 mutex_lock(&dsp->pwr_lock); in cs_dsp_adsp1_power_up()
2425 dsp->fw_name = fw_name; in cs_dsp_adsp1_power_up()
2427 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, in cs_dsp_adsp1_power_up()
2434 if (dsp->sysclk_reg) { in cs_dsp_adsp1_power_up()
2435 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); in cs_dsp_adsp1_power_up()
2441 val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift; in cs_dsp_adsp1_power_up()
2443 ret = regmap_update_bits(dsp->regmap, in cs_dsp_adsp1_power_up()
2444 dsp->base + ADSP1_CONTROL_31, in cs_dsp_adsp1_power_up()
2474 dsp->booted = true; in cs_dsp_adsp1_power_up()
2477 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, in cs_dsp_adsp1_power_up()
2481 dsp->running = true; in cs_dsp_adsp1_power_up()
2483 mutex_unlock(&dsp->pwr_lock); in cs_dsp_adsp1_power_up()
2488 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, in cs_dsp_adsp1_power_up()
2491 mutex_unlock(&dsp->pwr_lock); in cs_dsp_adsp1_power_up()
2497 * cs_dsp_adsp1_power_down() - Halts the DSP
2504 mutex_lock(&dsp->pwr_lock); in cs_dsp_adsp1_power_down()
2506 dsp->running = false; in cs_dsp_adsp1_power_down()
2507 dsp->booted = false; in cs_dsp_adsp1_power_down()
2510 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, in cs_dsp_adsp1_power_down()
2513 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, in cs_dsp_adsp1_power_down()
2516 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, in cs_dsp_adsp1_power_down()
2519 list_for_each_entry(ctl, &dsp->ctl_list, list) in cs_dsp_adsp1_power_down()
2520 ctl->enabled = 0; in cs_dsp_adsp1_power_down()
2524 mutex_unlock(&dsp->pwr_lock); in cs_dsp_adsp1_power_down()
2535 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val); in cs_dsp_adsp2v2_enable_core()
2547 return -EBUSY; in cs_dsp_adsp2v2_enable_core()
2559 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, in cs_dsp_adsp2_enable_core()
2569 struct regmap *regmap = dsp->regmap; in cs_dsp_adsp2_lock()
2576 lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0; in cs_dsp_adsp2_lock()
2599 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, in cs_dsp_adsp2_enable_memory()
2605 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, in cs_dsp_adsp2_disable_memory()
2611 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); in cs_dsp_adsp2_disable_core()
2612 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); in cs_dsp_adsp2_disable_core()
2613 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); in cs_dsp_adsp2_disable_core()
2615 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, in cs_dsp_adsp2_disable_core()
2621 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); in cs_dsp_adsp2v2_disable_core()
2622 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); in cs_dsp_adsp2v2_disable_core()
2623 regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0); in cs_dsp_adsp2v2_disable_core()
2629 { dsp->base + HALO_MPU_LOCK_CONFIG, 0x5555 }, in cs_dsp_halo_configure_mpu()
2630 { dsp->base + HALO_MPU_LOCK_CONFIG, 0xAAAA }, in cs_dsp_halo_configure_mpu()
2631 { dsp->base + HALO_MPU_XMEM_ACCESS_0, 0xFFFFFFFF }, in cs_dsp_halo_configure_mpu()
2632 { dsp->base + HALO_MPU_YMEM_ACCESS_0, 0xFFFFFFFF }, in cs_dsp_halo_configure_mpu()
2633 { dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions }, in cs_dsp_halo_configure_mpu()
2634 { dsp->base + HALO_MPU_XREG_ACCESS_0, lock_regions }, in cs_dsp_halo_configure_mpu()
2635 { dsp->base + HALO_MPU_YREG_ACCESS_0, lock_regions }, in cs_dsp_halo_configure_mpu()
2636 { dsp->base + HALO_MPU_XMEM_ACCESS_1, 0xFFFFFFFF }, in cs_dsp_halo_configure_mpu()
2637 { dsp->base + HALO_MPU_YMEM_ACCESS_1, 0xFFFFFFFF }, in cs_dsp_halo_configure_mpu()
2638 { dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions }, in cs_dsp_halo_configure_mpu()
2639 { dsp->base + HALO_MPU_XREG_ACCESS_1, lock_regions }, in cs_dsp_halo_configure_mpu()
2640 { dsp->base + HALO_MPU_YREG_ACCESS_1, lock_regions }, in cs_dsp_halo_configure_mpu()
2641 { dsp->base + HALO_MPU_XMEM_ACCESS_2, 0xFFFFFFFF }, in cs_dsp_halo_configure_mpu()
2642 { dsp->base + HALO_MPU_YMEM_ACCESS_2, 0xFFFFFFFF }, in cs_dsp_halo_configure_mpu()
2643 { dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions }, in cs_dsp_halo_configure_mpu()
2644 { dsp->base + HALO_MPU_XREG_ACCESS_2, lock_regions }, in cs_dsp_halo_configure_mpu()
2645 { dsp->base + HALO_MPU_YREG_ACCESS_2, lock_regions }, in cs_dsp_halo_configure_mpu()
2646 { dsp->base + HALO_MPU_XMEM_ACCESS_3, 0xFFFFFFFF }, in cs_dsp_halo_configure_mpu()
2647 { dsp->base + HALO_MPU_YMEM_ACCESS_3, 0xFFFFFFFF }, in cs_dsp_halo_configure_mpu()
2648 { dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions }, in cs_dsp_halo_configure_mpu()
2649 { dsp->base + HALO_MPU_XREG_ACCESS_3, lock_regions }, in cs_dsp_halo_configure_mpu()
2650 { dsp->base + HALO_MPU_YREG_ACCESS_3, lock_regions }, in cs_dsp_halo_configure_mpu()
2651 { dsp->base + HALO_MPU_LOCK_CONFIG, 0 }, in cs_dsp_halo_configure_mpu()
2654 return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config)); in cs_dsp_halo_configure_mpu()
2658 * cs_dsp_set_dspclk() - Applies the given frequency to the given cs_dsp
2670 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING, in cs_dsp_set_dspclk()
2682 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG, in cs_dsp_stop_watchdog()
2688 regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL, in cs_dsp_halo_stop_watchdog()
2693 * cs_dsp_power_up() - Downloads firmware to the DSP
2699 * @fw_name: the user-friendly firmware name
2701 * This function is used on ADSP2 and Halo DSP cores, it powers-up the DSP core
2703 * cs_dsp booted flag will be set once completed and if the core has a low-power
2716 mutex_lock(&dsp->pwr_lock); in cs_dsp_power_up()
2718 dsp->fw_name = fw_name; in cs_dsp_power_up()
2720 if (dsp->ops->enable_memory) { in cs_dsp_power_up()
2721 ret = dsp->ops->enable_memory(dsp); in cs_dsp_power_up()
2726 if (dsp->ops->enable_core) { in cs_dsp_power_up()
2727 ret = dsp->ops->enable_core(dsp); in cs_dsp_power_up()
2736 ret = dsp->ops->setup_algs(dsp); in cs_dsp_power_up()
2749 if (dsp->ops->disable_core) in cs_dsp_power_up()
2750 dsp->ops->disable_core(dsp); in cs_dsp_power_up()
2752 dsp->booted = true; in cs_dsp_power_up()
2754 mutex_unlock(&dsp->pwr_lock); in cs_dsp_power_up()
2758 if (dsp->ops->disable_core) in cs_dsp_power_up()
2759 dsp->ops->disable_core(dsp); in cs_dsp_power_up()
2761 if (dsp->ops->disable_memory) in cs_dsp_power_up()
2762 dsp->ops->disable_memory(dsp); in cs_dsp_power_up()
2764 mutex_unlock(&dsp->pwr_lock); in cs_dsp_power_up()
2771 * cs_dsp_power_down() - Powers-down the DSP
2781 mutex_lock(&dsp->pwr_lock); in cs_dsp_power_down()
2785 dsp->fw_id = 0; in cs_dsp_power_down()
2786 dsp->fw_id_version = 0; in cs_dsp_power_down()
2788 dsp->booted = false; in cs_dsp_power_down()
2790 if (dsp->ops->disable_memory) in cs_dsp_power_down()
2791 dsp->ops->disable_memory(dsp); in cs_dsp_power_down()
2793 list_for_each_entry(ctl, &dsp->ctl_list, list) in cs_dsp_power_down()
2794 ctl->enabled = 0; in cs_dsp_power_down()
2798 mutex_unlock(&dsp->pwr_lock); in cs_dsp_power_down()
2806 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, in cs_dsp_adsp2_start_core()
2813 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, in cs_dsp_adsp2_stop_core()
2818 * cs_dsp_run() - Starts the firmware running
2829 mutex_lock(&dsp->pwr_lock); in cs_dsp_run()
2831 if (!dsp->booted) { in cs_dsp_run()
2832 ret = -EIO; in cs_dsp_run()
2836 if (dsp->ops->enable_core) { in cs_dsp_run()
2837 ret = dsp->ops->enable_core(dsp); in cs_dsp_run()
2842 if (dsp->client_ops->pre_run) { in cs_dsp_run()
2843 ret = dsp->client_ops->pre_run(dsp); in cs_dsp_run()
2853 if (dsp->ops->lock_memory) { in cs_dsp_run()
2854 ret = dsp->ops->lock_memory(dsp, dsp->lock_regions); in cs_dsp_run()
2861 if (dsp->ops->start_core) { in cs_dsp_run()
2862 ret = dsp->ops->start_core(dsp); in cs_dsp_run()
2867 dsp->running = true; in cs_dsp_run()
2869 if (dsp->client_ops->post_run) { in cs_dsp_run()
2870 ret = dsp->client_ops->post_run(dsp); in cs_dsp_run()
2875 mutex_unlock(&dsp->pwr_lock); in cs_dsp_run()
2880 if (dsp->ops->stop_core) in cs_dsp_run()
2881 dsp->ops->stop_core(dsp); in cs_dsp_run()
2882 if (dsp->ops->disable_core) in cs_dsp_run()
2883 dsp->ops->disable_core(dsp); in cs_dsp_run()
2884 mutex_unlock(&dsp->pwr_lock); in cs_dsp_run()
2891 * cs_dsp_stop() - Stops the firmware
2901 if (dsp->ops->stop_watchdog) in cs_dsp_stop()
2902 dsp->ops->stop_watchdog(dsp); in cs_dsp_stop()
2905 if (dsp->ops->show_fw_status) in cs_dsp_stop()
2906 dsp->ops->show_fw_status(dsp); in cs_dsp_stop()
2908 mutex_lock(&dsp->pwr_lock); in cs_dsp_stop()
2910 if (dsp->client_ops->pre_stop) in cs_dsp_stop()
2911 dsp->client_ops->pre_stop(dsp); in cs_dsp_stop()
2913 dsp->running = false; in cs_dsp_stop()
2915 if (dsp->ops->stop_core) in cs_dsp_stop()
2916 dsp->ops->stop_core(dsp); in cs_dsp_stop()
2917 if (dsp->ops->disable_core) in cs_dsp_stop()
2918 dsp->ops->disable_core(dsp); in cs_dsp_stop()
2920 if (dsp->client_ops->post_stop) in cs_dsp_stop()
2921 dsp->client_ops->post_stop(dsp); in cs_dsp_stop()
2923 mutex_unlock(&dsp->pwr_lock); in cs_dsp_stop()
2933 ret = regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, in cs_dsp_halo_start_core()
2939 return regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, in cs_dsp_halo_start_core()
2945 regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, in cs_dsp_halo_stop_core()
2949 regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET, in cs_dsp_halo_stop_core()
2954 * cs_dsp_adsp2_init() - Initialise a cs_dsp structure representing a ADSP2 core
2963 switch (dsp->rev) { in cs_dsp_adsp2_init()
2969 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, in cs_dsp_adsp2_init()
2977 dsp->ops = &cs_dsp_adsp2_ops[0]; in cs_dsp_adsp2_init()
2980 dsp->ops = &cs_dsp_adsp2_ops[1]; in cs_dsp_adsp2_init()
2983 dsp->ops = &cs_dsp_adsp2_ops[2]; in cs_dsp_adsp2_init()
2992 * cs_dsp_halo_init() - Initialise a cs_dsp structure representing a HALO Core DSP
2999 if (dsp->no_core_startstop) in cs_dsp_halo_init()
3000 dsp->ops = &cs_dsp_halo_ao_ops; in cs_dsp_halo_init()
3002 dsp->ops = &cs_dsp_halo_ops; in cs_dsp_halo_init()
3009 * cs_dsp_remove() - Clean a cs_dsp before deletion
3016 while (!list_empty(&dsp->ctl_list)) { in cs_dsp_remove()
3017 ctl = list_first_entry(&dsp->ctl_list, struct cs_dsp_coeff_ctl, list); in cs_dsp_remove()
3019 if (dsp->client_ops->control_remove) in cs_dsp_remove()
3020 dsp->client_ops->control_remove(ctl); in cs_dsp_remove()
3022 list_del(&ctl->list); in cs_dsp_remove()
3029 * cs_dsp_read_raw_data_block() - Reads a block of data from DSP memory
3036 * If this is used to read unpacked 24-bit memory, each 24-bit DSP word will
3037 * occupy 32-bits in data (MSbyte will be 0). This padding can be removed using
3049 lockdep_assert_held(&dsp->pwr_lock); in cs_dsp_read_raw_data_block()
3052 return -EINVAL; in cs_dsp_read_raw_data_block()
3054 reg = dsp->ops->region_to_reg(mem, mem_addr); in cs_dsp_read_raw_data_block()
3056 ret = regmap_raw_read(dsp->regmap, reg, data, in cs_dsp_read_raw_data_block()
3066 * cs_dsp_read_data_word() - Reads a word from DSP memory
3090 * cs_dsp_write_data_word() - Writes a word to DSP memory
3104 lockdep_assert_held(&dsp->pwr_lock); in cs_dsp_write_data_word()
3107 return -EINVAL; in cs_dsp_write_data_word()
3109 reg = dsp->ops->region_to_reg(mem, mem_addr); in cs_dsp_write_data_word()
3111 return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val)); in cs_dsp_write_data_word()
3116 * cs_dsp_remove_padding() - Convert unpacked words to packed bytes
3140 * cs_dsp_adsp2_bus_error() - Handle a DSP bus error interrupt
3148 struct regmap *regmap = dsp->regmap; in cs_dsp_adsp2_bus_error()
3151 mutex_lock(&dsp->pwr_lock); in cs_dsp_adsp2_bus_error()
3153 ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val); in cs_dsp_adsp2_bus_error()
3156 "Failed to read Region Lock Ctrl register: %d\n", ret); in cs_dsp_adsp2_bus_error()
3162 dsp->ops->stop_watchdog(dsp); in cs_dsp_adsp2_bus_error()
3163 if (dsp->client_ops->watchdog_expired) in cs_dsp_adsp2_bus_error()
3164 dsp->client_ops->watchdog_expired(dsp); in cs_dsp_adsp2_bus_error()
3173 ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val); in cs_dsp_adsp2_bus_error()
3185 dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR, in cs_dsp_adsp2_bus_error()
3201 regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, in cs_dsp_adsp2_bus_error()
3205 mutex_unlock(&dsp->pwr_lock); in cs_dsp_adsp2_bus_error()
3210 * cs_dsp_halo_bus_error() - Handle a DSP bus error interrupt
3217 struct regmap *regmap = dsp->regmap; in cs_dsp_halo_bus_error()
3220 { dsp->base + HALO_MPU_XM_VIO_STATUS, 0x0 }, in cs_dsp_halo_bus_error()
3221 { dsp->base + HALO_MPU_YM_VIO_STATUS, 0x0 }, in cs_dsp_halo_bus_error()
3222 { dsp->base + HALO_MPU_PM_VIO_STATUS, 0x0 }, in cs_dsp_halo_bus_error()
3226 mutex_lock(&dsp->pwr_lock); in cs_dsp_halo_bus_error()
3228 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1, in cs_dsp_halo_bus_error()
3240 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0, in cs_dsp_halo_bus_error()
3249 ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR, in cs_dsp_halo_bus_error()
3260 ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear)); in cs_dsp_halo_bus_error()
3265 mutex_unlock(&dsp->pwr_lock); in cs_dsp_halo_bus_error()
3270 * cs_dsp_halo_wdt_expire() - Handle DSP watchdog expiry
3277 mutex_lock(&dsp->pwr_lock); in cs_dsp_halo_wdt_expire()
3281 dsp->ops->stop_watchdog(dsp); in cs_dsp_halo_wdt_expire()
3282 if (dsp->client_ops->watchdog_expired) in cs_dsp_halo_wdt_expire()
3283 dsp->client_ops->watchdog_expired(dsp); in cs_dsp_halo_wdt_expire()
3285 mutex_unlock(&dsp->pwr_lock); in cs_dsp_halo_wdt_expire()
3377 * cs_dsp_chunk_write() - Format data to a DSP memory chunk
3393 nwrite = min(CS_DSP_DATA_WORD_BITS - ch->cachebits, nbits); in cs_dsp_chunk_write()
3395 ch->cache <<= nwrite; in cs_dsp_chunk_write()
3396 ch->cache |= val >> (nbits - nwrite); in cs_dsp_chunk_write()
3397 ch->cachebits += nwrite; in cs_dsp_chunk_write()
3398 nbits -= nwrite; in cs_dsp_chunk_write()
3400 if (ch->cachebits == CS_DSP_DATA_WORD_BITS) { in cs_dsp_chunk_write()
3402 return -ENOSPC; in cs_dsp_chunk_write()
3404 ch->cache &= 0xFFFFFF; in cs_dsp_chunk_write()
3405 for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE) in cs_dsp_chunk_write()
3406 *ch->data++ = (ch->cache & 0xFF000000) >> CS_DSP_DATA_WORD_BITS; in cs_dsp_chunk_write()
3408 ch->bytes += sizeof(ch->cache); in cs_dsp_chunk_write()
3409 ch->cachebits = 0; in cs_dsp_chunk_write()
3420 * cs_dsp_chunk_flush() - Pad remaining data with zero and commit to chunk
3431 if (!ch->cachebits) in cs_dsp_chunk_flush()
3434 return cs_dsp_chunk_write(ch, CS_DSP_DATA_WORD_BITS - ch->cachebits, 0); in cs_dsp_chunk_flush()
3439 * cs_dsp_chunk_read() - Parse data from a DSP memory chunk
3453 if (!ch->cachebits) { in cs_dsp_chunk_read()
3455 return -ENOSPC; in cs_dsp_chunk_read()
3457 ch->cache = 0; in cs_dsp_chunk_read()
3458 ch->cachebits = CS_DSP_DATA_WORD_BITS; in cs_dsp_chunk_read()
3460 for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE) in cs_dsp_chunk_read()
3461 ch->cache |= *ch->data++; in cs_dsp_chunk_read()
3463 ch->bytes += sizeof(ch->cache); in cs_dsp_chunk_read()
3466 nread = min(ch->cachebits, nbits); in cs_dsp_chunk_read()
3467 nbits -= nread; in cs_dsp_chunk_read()
3469 result = ch->cache >> ((sizeof(ch->cache) * BITS_PER_BYTE) - nread); in cs_dsp_chunk_read()
3470 ch->cache <<= nread; in cs_dsp_chunk_read()
3471 ch->cachebits -= nread; in cs_dsp_chunk_read()
3493 list_for_each_entry_safe(op, op_tmp, &wseq->ops, list) { in cs_dsp_wseq_clear()
3494 list_del(&op->list); in cs_dsp_wseq_clear()
3495 devm_kfree(dsp->dev, op); in cs_dsp_wseq_clear()
3506 if (!wseq->ctl) { in cs_dsp_populate_wseq()
3508 return -EINVAL; in cs_dsp_populate_wseq()
3511 words = kzalloc(wseq->ctl->len, GFP_KERNEL); in cs_dsp_populate_wseq()
3513 return -ENOMEM; in cs_dsp_populate_wseq()
3515 ret = cs_dsp_coeff_read_ctrl(wseq->ctl, 0, words, wseq->ctl->len); in cs_dsp_populate_wseq()
3517 cs_dsp_err(dsp, "Failed to read %s: %d\n", wseq->ctl->subname, ret); in cs_dsp_populate_wseq()
3521 INIT_LIST_HEAD(&wseq->ops); in cs_dsp_populate_wseq()
3523 chunk = cs_dsp_chunk(words, wseq->ctl->len); in cs_dsp_populate_wseq()
3526 op = devm_kzalloc(dsp->dev, sizeof(*op), GFP_KERNEL); in cs_dsp_populate_wseq()
3528 ret = -ENOMEM; in cs_dsp_populate_wseq()
3532 op->offset = cs_dsp_chunk_bytes(&chunk); in cs_dsp_populate_wseq()
3533 op->operation = cs_dsp_chunk_read(&chunk, 8); in cs_dsp_populate_wseq()
3535 switch (op->operation) { in cs_dsp_populate_wseq()
3537 op->data = WSEQ_END_OF_SCRIPT; in cs_dsp_populate_wseq()
3540 op->data = cs_dsp_chunk_read(&chunk, 16); in cs_dsp_populate_wseq()
3543 op->address = cs_dsp_chunk_read(&chunk, 8); in cs_dsp_populate_wseq()
3544 op->data = cs_dsp_chunk_read(&chunk, 32); in cs_dsp_populate_wseq()
3548 op->address = cs_dsp_chunk_read(&chunk, 24); in cs_dsp_populate_wseq()
3549 op->data = cs_dsp_chunk_read(&chunk, 16); in cs_dsp_populate_wseq()
3552 op->address = cs_dsp_chunk_read(&chunk, 32); in cs_dsp_populate_wseq()
3553 op->data = cs_dsp_chunk_read(&chunk, 32); in cs_dsp_populate_wseq()
3556 ret = -EINVAL; in cs_dsp_populate_wseq()
3557 cs_dsp_err(dsp, "Unsupported op: %X\n", op->operation); in cs_dsp_populate_wseq()
3558 devm_kfree(dsp->dev, op); in cs_dsp_populate_wseq()
3562 list_add_tail(&op->list, &wseq->ops); in cs_dsp_populate_wseq()
3564 if (op->operation == CS_DSP_WSEQ_END) in cs_dsp_populate_wseq()
3568 if (op && op->operation != CS_DSP_WSEQ_END) { in cs_dsp_populate_wseq()
3569 cs_dsp_err(dsp, "%s missing end terminator\n", wseq->ctl->subname); in cs_dsp_populate_wseq()
3570 ret = -ENOENT; in cs_dsp_populate_wseq()
3580 * cs_dsp_wseq_init() - Initialize write sequences contained within the loaded DSP firmware
3591 lockdep_assert_held(&dsp->pwr_lock); in cs_dsp_wseq_init()
3611 if (op->operation == op_code && op->address == addr) in cs_dsp_wseq_find_op()
3619 * cs_dsp_wseq_write() - Add or update an entry in a write sequence
3646 op_new = cs_dsp_wseq_find_op(addr, op_code, &wseq->ops); in cs_dsp_wseq_write()
3650 op_end = cs_dsp_wseq_find_op(0, CS_DSP_WSEQ_END, &wseq->ops); in cs_dsp_wseq_write()
3652 cs_dsp_err(dsp, "Missing terminator for %s\n", wseq->ctl->subname); in cs_dsp_wseq_write()
3653 return -EINVAL; in cs_dsp_wseq_write()
3656 op_new = devm_kzalloc(dsp->dev, sizeof(*op_new), GFP_KERNEL); in cs_dsp_wseq_write()
3658 return -ENOMEM; in cs_dsp_wseq_write()
3660 op_new->operation = op_code; in cs_dsp_wseq_write()
3661 op_new->address = addr; in cs_dsp_wseq_write()
3662 op_new->offset = op_end->offset; in cs_dsp_wseq_write()
3666 op_new->data = data; in cs_dsp_wseq_write()
3669 cs_dsp_chunk_write(&chunk, 8, op_new->operation); in cs_dsp_wseq_write()
3673 cs_dsp_chunk_write(&chunk, 32, op_new->address); in cs_dsp_wseq_write()
3674 cs_dsp_chunk_write(&chunk, 32, op_new->data); in cs_dsp_wseq_write()
3678 cs_dsp_chunk_write(&chunk, 24, op_new->address); in cs_dsp_wseq_write()
3679 cs_dsp_chunk_write(&chunk, 16, op_new->data); in cs_dsp_wseq_write()
3682 ret = -EINVAL; in cs_dsp_wseq_write()
3690 if (wseq->ctl->len - op_end->offset < new_op_size) { in cs_dsp_wseq_write()
3691 cs_dsp_err(dsp, "Not enough memory in %s for entry\n", wseq->ctl->subname); in cs_dsp_wseq_write()
3692 ret = -E2BIG; in cs_dsp_wseq_write()
3696 op_end->offset += new_op_size; in cs_dsp_wseq_write()
3698 ret = cs_dsp_coeff_write_ctrl(wseq->ctl, op_end->offset / sizeof(u32), in cs_dsp_wseq_write()
3699 &op_end->data, sizeof(u32)); in cs_dsp_wseq_write()
3703 list_add_tail(&op_new->list, &op_end->list); in cs_dsp_wseq_write()
3706 ret = cs_dsp_coeff_write_ctrl(wseq->ctl, op_new->offset / sizeof(u32), in cs_dsp_wseq_write()
3714 devm_kfree(dsp->dev, op_new); in cs_dsp_wseq_write()
3721 * cs_dsp_wseq_multi_write() - Add or update multiple entries in a write sequence
3724 * @reg_seq: List of address-data pairs
3725 * @num_regs: Number of address-data pairs
3731 * This function calls cs_dsp_wseq_write() for multiple address-data pairs.