| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * wm_adsp.c -- Wolfson ADSP support |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright 2012 Wolfson Microelectronics plc |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 10 | | - * published by the Free Software Foundation. |
|---|
| 11 | 8 | */ |
|---|
| 12 | 9 | |
|---|
| 13 | 10 | #include <linux/ctype.h> |
|---|
| .. | .. |
|---|
| 45 | 42 | dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) |
|---|
| 46 | 43 | #define adsp_dbg(_dsp, fmt, ...) \ |
|---|
| 47 | 44 | dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) |
|---|
| 45 | + |
|---|
| 46 | +#define compr_err(_obj, fmt, ...) \ |
|---|
| 47 | + adsp_err(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \ |
|---|
| 48 | + ##__VA_ARGS__) |
|---|
| 49 | +#define compr_dbg(_obj, fmt, ...) \ |
|---|
| 50 | + adsp_dbg(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \ |
|---|
| 51 | + ##__VA_ARGS__) |
|---|
| 48 | 52 | |
|---|
| 49 | 53 | #define ADSP1_CONTROL_1 0x00 |
|---|
| 50 | 54 | #define ADSP1_CONTROL_2 0x02 |
|---|
| .. | .. |
|---|
| 195 | 199 | #define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR 0x7C |
|---|
| 196 | 200 | |
|---|
| 197 | 201 | #define ADSP2_REGION_LOCK_ERR_MASK 0x8000 |
|---|
| 198 | | -#define ADSP2_SLAVE_ERR_MASK 0x4000 |
|---|
| 202 | +#define ADSP2_ADDR_ERR_MASK 0x4000 |
|---|
| 199 | 203 | #define ADSP2_WDT_TIMEOUT_STS_MASK 0x2000 |
|---|
| 200 | 204 | #define ADSP2_CTRL_ERR_PAUSE_ENA 0x0002 |
|---|
| 201 | 205 | #define ADSP2_CTRL_ERR_EINT 0x0001 |
|---|
| .. | .. |
|---|
| 219 | 223 | * Event control messages |
|---|
| 220 | 224 | */ |
|---|
| 221 | 225 | #define WM_ADSP_FW_EVENT_SHUTDOWN 0x000001 |
|---|
| 226 | + |
|---|
| 227 | +/* |
|---|
| 228 | + * HALO system info |
|---|
| 229 | + */ |
|---|
| 230 | +#define HALO_AHBM_WINDOW_DEBUG_0 0x02040 |
|---|
| 231 | +#define HALO_AHBM_WINDOW_DEBUG_1 0x02044 |
|---|
| 232 | + |
|---|
| 233 | +/* |
|---|
| 234 | + * HALO core |
|---|
| 235 | + */ |
|---|
| 236 | +#define HALO_SCRATCH1 0x005c0 |
|---|
| 237 | +#define HALO_SCRATCH2 0x005c8 |
|---|
| 238 | +#define HALO_SCRATCH3 0x005d0 |
|---|
| 239 | +#define HALO_SCRATCH4 0x005d8 |
|---|
| 240 | +#define HALO_CCM_CORE_CONTROL 0x41000 |
|---|
| 241 | +#define HALO_CORE_SOFT_RESET 0x00010 |
|---|
| 242 | +#define HALO_WDT_CONTROL 0x47000 |
|---|
| 243 | + |
|---|
| 244 | +/* |
|---|
| 245 | + * HALO MPU banks |
|---|
| 246 | + */ |
|---|
| 247 | +#define HALO_MPU_XMEM_ACCESS_0 0x43000 |
|---|
| 248 | +#define HALO_MPU_YMEM_ACCESS_0 0x43004 |
|---|
| 249 | +#define HALO_MPU_WINDOW_ACCESS_0 0x43008 |
|---|
| 250 | +#define HALO_MPU_XREG_ACCESS_0 0x4300C |
|---|
| 251 | +#define HALO_MPU_YREG_ACCESS_0 0x43014 |
|---|
| 252 | +#define HALO_MPU_XMEM_ACCESS_1 0x43018 |
|---|
| 253 | +#define HALO_MPU_YMEM_ACCESS_1 0x4301C |
|---|
| 254 | +#define HALO_MPU_WINDOW_ACCESS_1 0x43020 |
|---|
| 255 | +#define HALO_MPU_XREG_ACCESS_1 0x43024 |
|---|
| 256 | +#define HALO_MPU_YREG_ACCESS_1 0x4302C |
|---|
| 257 | +#define HALO_MPU_XMEM_ACCESS_2 0x43030 |
|---|
| 258 | +#define HALO_MPU_YMEM_ACCESS_2 0x43034 |
|---|
| 259 | +#define HALO_MPU_WINDOW_ACCESS_2 0x43038 |
|---|
| 260 | +#define HALO_MPU_XREG_ACCESS_2 0x4303C |
|---|
| 261 | +#define HALO_MPU_YREG_ACCESS_2 0x43044 |
|---|
| 262 | +#define HALO_MPU_XMEM_ACCESS_3 0x43048 |
|---|
| 263 | +#define HALO_MPU_YMEM_ACCESS_3 0x4304C |
|---|
| 264 | +#define HALO_MPU_WINDOW_ACCESS_3 0x43050 |
|---|
| 265 | +#define HALO_MPU_XREG_ACCESS_3 0x43054 |
|---|
| 266 | +#define HALO_MPU_YREG_ACCESS_3 0x4305C |
|---|
| 267 | +#define HALO_MPU_XM_VIO_ADDR 0x43100 |
|---|
| 268 | +#define HALO_MPU_XM_VIO_STATUS 0x43104 |
|---|
| 269 | +#define HALO_MPU_YM_VIO_ADDR 0x43108 |
|---|
| 270 | +#define HALO_MPU_YM_VIO_STATUS 0x4310C |
|---|
| 271 | +#define HALO_MPU_PM_VIO_ADDR 0x43110 |
|---|
| 272 | +#define HALO_MPU_PM_VIO_STATUS 0x43114 |
|---|
| 273 | +#define HALO_MPU_LOCK_CONFIG 0x43140 |
|---|
| 274 | + |
|---|
| 275 | +/* |
|---|
| 276 | + * HALO_AHBM_WINDOW_DEBUG_1 |
|---|
| 277 | + */ |
|---|
| 278 | +#define HALO_AHBM_CORE_ERR_ADDR_MASK 0x0fffff00 |
|---|
| 279 | +#define HALO_AHBM_CORE_ERR_ADDR_SHIFT 8 |
|---|
| 280 | +#define HALO_AHBM_FLAGS_ERR_MASK 0x000000ff |
|---|
| 281 | + |
|---|
| 282 | +/* |
|---|
| 283 | + * HALO_CCM_CORE_CONTROL |
|---|
| 284 | + */ |
|---|
| 285 | +#define HALO_CORE_EN 0x00000001 |
|---|
| 286 | + |
|---|
| 287 | +/* |
|---|
| 288 | + * HALO_CORE_SOFT_RESET |
|---|
| 289 | + */ |
|---|
| 290 | +#define HALO_CORE_SOFT_RESET_MASK 0x00000001 |
|---|
| 291 | + |
|---|
| 292 | +/* |
|---|
| 293 | + * HALO_WDT_CONTROL |
|---|
| 294 | + */ |
|---|
| 295 | +#define HALO_WDT_EN_MASK 0x00000001 |
|---|
| 296 | + |
|---|
| 297 | +/* |
|---|
| 298 | + * HALO_MPU_?M_VIO_STATUS |
|---|
| 299 | + */ |
|---|
| 300 | +#define HALO_MPU_VIO_STS_MASK 0x007e0000 |
|---|
| 301 | +#define HALO_MPU_VIO_STS_SHIFT 17 |
|---|
| 302 | +#define HALO_MPU_VIO_ERR_WR_MASK 0x00008000 |
|---|
| 303 | +#define HALO_MPU_VIO_ERR_SRC_MASK 0x00007fff |
|---|
| 304 | +#define HALO_MPU_VIO_ERR_SRC_SHIFT 0 |
|---|
| 305 | + |
|---|
| 306 | +static struct wm_adsp_ops wm_adsp1_ops; |
|---|
| 307 | +static struct wm_adsp_ops wm_adsp2_ops[]; |
|---|
| 308 | +static struct wm_adsp_ops wm_halo_ops; |
|---|
| 222 | 309 | |
|---|
| 223 | 310 | struct wm_adsp_buf { |
|---|
| 224 | 311 | struct list_head list; |
|---|
| .. | .. |
|---|
| 268 | 355 | #define WM_ADSP_FW_ASR 7 |
|---|
| 269 | 356 | #define WM_ADSP_FW_TRACE 8 |
|---|
| 270 | 357 | #define WM_ADSP_FW_SPK_PROT 9 |
|---|
| 271 | | -#define WM_ADSP_FW_MISC 10 |
|---|
| 358 | +#define WM_ADSP_FW_SPK_CALI 10 |
|---|
| 359 | +#define WM_ADSP_FW_SPK_DIAG 11 |
|---|
| 360 | +#define WM_ADSP_FW_MISC 12 |
|---|
| 272 | 361 | |
|---|
| 273 | | -#define WM_ADSP_NUM_FW 11 |
|---|
| 362 | +#define WM_ADSP_NUM_FW 13 |
|---|
| 274 | 363 | |
|---|
| 275 | 364 | static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { |
|---|
| 276 | 365 | [WM_ADSP_FW_MBC_VSS] = "MBC/VSS", |
|---|
| .. | .. |
|---|
| 283 | 372 | [WM_ADSP_FW_ASR] = "ASR Assist", |
|---|
| 284 | 373 | [WM_ADSP_FW_TRACE] = "Dbg Trace", |
|---|
| 285 | 374 | [WM_ADSP_FW_SPK_PROT] = "Protection", |
|---|
| 375 | + [WM_ADSP_FW_SPK_CALI] = "Calibration", |
|---|
| 376 | + [WM_ADSP_FW_SPK_DIAG] = "Diagnostic", |
|---|
| 286 | 377 | [WM_ADSP_FW_MISC] = "Misc", |
|---|
| 287 | 378 | }; |
|---|
| 288 | 379 | |
|---|
| .. | .. |
|---|
| 299 | 390 | __be32 build_job_number; |
|---|
| 300 | 391 | }; |
|---|
| 301 | 392 | |
|---|
| 393 | +struct wm_halo_system_config_xm_hdr { |
|---|
| 394 | + __be32 halo_heartbeat; |
|---|
| 395 | + __be32 build_job_name[3]; |
|---|
| 396 | + __be32 build_job_number; |
|---|
| 397 | +}; |
|---|
| 398 | + |
|---|
| 302 | 399 | struct wm_adsp_alg_xm_struct { |
|---|
| 303 | 400 | __be32 magic; |
|---|
| 304 | 401 | __be32 smoothing; |
|---|
| .. | .. |
|---|
| 310 | 407 | __be64 smoothed_power; |
|---|
| 311 | 408 | }; |
|---|
| 312 | 409 | |
|---|
| 410 | +struct wm_adsp_host_buf_coeff_v1 { |
|---|
| 411 | + __be32 host_buf_ptr; /* Host buffer pointer */ |
|---|
| 412 | + __be32 versions; /* Version numbers */ |
|---|
| 413 | + __be32 name[4]; /* The buffer name */ |
|---|
| 414 | +}; |
|---|
| 415 | + |
|---|
| 313 | 416 | struct wm_adsp_buffer { |
|---|
| 314 | | - __be32 X_buf_base; /* XM base addr of first X area */ |
|---|
| 315 | | - __be32 X_buf_size; /* Size of 1st X area in words */ |
|---|
| 316 | | - __be32 X_buf_base2; /* XM base addr of 2nd X area */ |
|---|
| 317 | | - __be32 X_buf_brk; /* Total X size in words */ |
|---|
| 318 | | - __be32 Y_buf_base; /* YM base addr of Y area */ |
|---|
| 319 | | - __be32 wrap; /* Total size X and Y in words */ |
|---|
| 417 | + __be32 buf1_base; /* Base addr of first buffer area */ |
|---|
| 418 | + __be32 buf1_size; /* Size of buf1 area in DSP words */ |
|---|
| 419 | + __be32 buf2_base; /* Base addr of 2nd buffer area */ |
|---|
| 420 | + __be32 buf1_buf2_size; /* Size of buf1+buf2 in DSP words */ |
|---|
| 421 | + __be32 buf3_base; /* Base addr of buf3 area */ |
|---|
| 422 | + __be32 buf_total_size; /* Size of buf1+buf2+buf3 in DSP words */ |
|---|
| 320 | 423 | __be32 high_water_mark; /* Point at which IRQ is asserted */ |
|---|
| 321 | 424 | __be32 irq_count; /* bits 1-31 count IRQ assertions */ |
|---|
| 322 | 425 | __be32 irq_ack; /* acked IRQ count, bit 0 enables IRQ */ |
|---|
| .. | .. |
|---|
| 334 | 437 | struct wm_adsp_compr; |
|---|
| 335 | 438 | |
|---|
| 336 | 439 | struct wm_adsp_compr_buf { |
|---|
| 440 | + struct list_head list; |
|---|
| 337 | 441 | struct wm_adsp *dsp; |
|---|
| 338 | 442 | struct wm_adsp_compr *compr; |
|---|
| 339 | 443 | |
|---|
| .. | .. |
|---|
| 344 | 448 | u32 irq_count; |
|---|
| 345 | 449 | int read_index; |
|---|
| 346 | 450 | int avail; |
|---|
| 451 | + int host_buf_mem_type; |
|---|
| 452 | + |
|---|
| 453 | + char *name; |
|---|
| 347 | 454 | }; |
|---|
| 348 | 455 | |
|---|
| 349 | 456 | struct wm_adsp_compr { |
|---|
| 457 | + struct list_head list; |
|---|
| 350 | 458 | struct wm_adsp *dsp; |
|---|
| 351 | 459 | struct wm_adsp_compr_buf *buf; |
|---|
| 352 | 460 | |
|---|
| .. | .. |
|---|
| 357 | 465 | unsigned int copied_total; |
|---|
| 358 | 466 | |
|---|
| 359 | 467 | unsigned int sample_rate; |
|---|
| 468 | + |
|---|
| 469 | + const char *name; |
|---|
| 360 | 470 | }; |
|---|
| 361 | 471 | |
|---|
| 362 | 472 | #define WM_ADSP_DATA_WORD_SIZE 3 |
|---|
| .. | .. |
|---|
| 373 | 483 | |
|---|
| 374 | 484 | #define ALG_XM_FIELD(field) \ |
|---|
| 375 | 485 | (offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32)) |
|---|
| 486 | + |
|---|
| 487 | +#define HOST_BUF_COEFF_SUPPORTED_COMPAT_VER 1 |
|---|
| 488 | + |
|---|
| 489 | +#define HOST_BUF_COEFF_COMPAT_VER_MASK 0xFF00 |
|---|
| 490 | +#define HOST_BUF_COEFF_COMPAT_VER_SHIFT 8 |
|---|
| 376 | 491 | |
|---|
| 377 | 492 | static int wm_adsp_buffer_init(struct wm_adsp *dsp); |
|---|
| 378 | 493 | static int wm_adsp_buffer_free(struct wm_adsp *dsp); |
|---|
| .. | .. |
|---|
| 393 | 508 | static const struct wm_adsp_buffer_region_def default_regions[] = { |
|---|
| 394 | 509 | { |
|---|
| 395 | 510 | .mem_type = WMFW_ADSP2_XM, |
|---|
| 396 | | - .base_offset = HOST_BUFFER_FIELD(X_buf_base), |
|---|
| 397 | | - .size_offset = HOST_BUFFER_FIELD(X_buf_size), |
|---|
| 511 | + .base_offset = HOST_BUFFER_FIELD(buf1_base), |
|---|
| 512 | + .size_offset = HOST_BUFFER_FIELD(buf1_size), |
|---|
| 398 | 513 | }, |
|---|
| 399 | 514 | { |
|---|
| 400 | 515 | .mem_type = WMFW_ADSP2_XM, |
|---|
| 401 | | - .base_offset = HOST_BUFFER_FIELD(X_buf_base2), |
|---|
| 402 | | - .size_offset = HOST_BUFFER_FIELD(X_buf_brk), |
|---|
| 516 | + .base_offset = HOST_BUFFER_FIELD(buf2_base), |
|---|
| 517 | + .size_offset = HOST_BUFFER_FIELD(buf1_buf2_size), |
|---|
| 403 | 518 | }, |
|---|
| 404 | 519 | { |
|---|
| 405 | 520 | .mem_type = WMFW_ADSP2_YM, |
|---|
| 406 | | - .base_offset = HOST_BUFFER_FIELD(Y_buf_base), |
|---|
| 407 | | - .size_offset = HOST_BUFFER_FIELD(wrap), |
|---|
| 521 | + .base_offset = HOST_BUFFER_FIELD(buf3_base), |
|---|
| 522 | + .size_offset = HOST_BUFFER_FIELD(buf_total_size), |
|---|
| 408 | 523 | }, |
|---|
| 409 | 524 | }; |
|---|
| 410 | 525 | |
|---|
| .. | .. |
|---|
| 475 | 590 | .caps = trace_caps, |
|---|
| 476 | 591 | }, |
|---|
| 477 | 592 | [WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" }, |
|---|
| 593 | + [WM_ADSP_FW_SPK_CALI] = { .file = "spk-cali" }, |
|---|
| 594 | + [WM_ADSP_FW_SPK_DIAG] = { .file = "spk-diag" }, |
|---|
| 478 | 595 | [WM_ADSP_FW_MISC] = { .file = "misc" }, |
|---|
| 479 | 596 | }; |
|---|
| 480 | 597 | |
|---|
| .. | .. |
|---|
| 488 | 605 | struct wm_coeff_ctl { |
|---|
| 489 | 606 | const char *name; |
|---|
| 490 | 607 | const char *fw_name; |
|---|
| 608 | + /* Subname is needed to match with firmware */ |
|---|
| 609 | + const char *subname; |
|---|
| 610 | + unsigned int subname_len; |
|---|
| 491 | 611 | struct wm_adsp_alg_region alg_region; |
|---|
| 492 | 612 | struct wm_coeff_ctl_ops ops; |
|---|
| 493 | 613 | struct wm_adsp *dsp; |
|---|
| .. | .. |
|---|
| 507 | 627 | switch (type) { |
|---|
| 508 | 628 | case WMFW_ADSP1_PM: |
|---|
| 509 | 629 | return "PM"; |
|---|
| 630 | + case WMFW_HALO_PM_PACKED: |
|---|
| 631 | + return "PM_PACKED"; |
|---|
| 510 | 632 | case WMFW_ADSP1_DM: |
|---|
| 511 | 633 | return "DM"; |
|---|
| 512 | 634 | case WMFW_ADSP2_XM: |
|---|
| 513 | 635 | return "XM"; |
|---|
| 636 | + case WMFW_HALO_XM_PACKED: |
|---|
| 637 | + return "XM_PACKED"; |
|---|
| 514 | 638 | case WMFW_ADSP2_YM: |
|---|
| 515 | 639 | return "YM"; |
|---|
| 640 | + case WMFW_HALO_YM_PACKED: |
|---|
| 641 | + return "YM_PACKED"; |
|---|
| 516 | 642 | case WMFW_ADSP1_ZM: |
|---|
| 517 | 643 | return "ZM"; |
|---|
| 518 | 644 | default: |
|---|
| .. | .. |
|---|
| 611 | 737 | struct dentry *root = NULL; |
|---|
| 612 | 738 | int i; |
|---|
| 613 | 739 | |
|---|
| 614 | | - if (!component->debugfs_root) { |
|---|
| 615 | | - adsp_err(dsp, "No codec debugfs root\n"); |
|---|
| 616 | | - goto err; |
|---|
| 617 | | - } |
|---|
| 618 | | - |
|---|
| 619 | 740 | root = debugfs_create_dir(dsp->name, component->debugfs_root); |
|---|
| 620 | 741 | |
|---|
| 621 | | - if (!root) |
|---|
| 622 | | - goto err; |
|---|
| 742 | + debugfs_create_bool("booted", 0444, root, &dsp->booted); |
|---|
| 743 | + debugfs_create_bool("running", 0444, root, &dsp->running); |
|---|
| 744 | + debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id); |
|---|
| 745 | + debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version); |
|---|
| 623 | 746 | |
|---|
| 624 | | - if (!debugfs_create_bool("booted", 0444, root, &dsp->booted)) |
|---|
| 625 | | - goto err; |
|---|
| 626 | | - |
|---|
| 627 | | - if (!debugfs_create_bool("running", 0444, root, &dsp->running)) |
|---|
| 628 | | - goto err; |
|---|
| 629 | | - |
|---|
| 630 | | - if (!debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id)) |
|---|
| 631 | | - goto err; |
|---|
| 632 | | - |
|---|
| 633 | | - if (!debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version)) |
|---|
| 634 | | - goto err; |
|---|
| 635 | | - |
|---|
| 636 | | - for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) { |
|---|
| 637 | | - if (!debugfs_create_file(wm_adsp_debugfs_fops[i].name, |
|---|
| 638 | | - 0444, root, dsp, |
|---|
| 639 | | - &wm_adsp_debugfs_fops[i].fops)) |
|---|
| 640 | | - goto err; |
|---|
| 641 | | - } |
|---|
| 747 | + for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) |
|---|
| 748 | + debugfs_create_file(wm_adsp_debugfs_fops[i].name, 0444, root, |
|---|
| 749 | + dsp, &wm_adsp_debugfs_fops[i].fops); |
|---|
| 642 | 750 | |
|---|
| 643 | 751 | dsp->debugfs_root = root; |
|---|
| 644 | | - return; |
|---|
| 645 | | - |
|---|
| 646 | | -err: |
|---|
| 647 | | - debugfs_remove_recursive(root); |
|---|
| 648 | | - adsp_err(dsp, "Failed to create debugfs\n"); |
|---|
| 649 | 752 | } |
|---|
| 650 | 753 | |
|---|
| 651 | 754 | static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp) |
|---|
| .. | .. |
|---|
| 697 | 800 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
|---|
| 698 | 801 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
|---|
| 699 | 802 | struct wm_adsp *dsp = snd_soc_component_get_drvdata(component); |
|---|
| 700 | | - int ret = 0; |
|---|
| 803 | + int ret = 1; |
|---|
| 701 | 804 | |
|---|
| 702 | 805 | if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw) |
|---|
| 703 | 806 | return 0; |
|---|
| .. | .. |
|---|
| 707 | 810 | |
|---|
| 708 | 811 | mutex_lock(&dsp[e->shift_l].pwr_lock); |
|---|
| 709 | 812 | |
|---|
| 710 | | - if (dsp[e->shift_l].booted || dsp[e->shift_l].compr) |
|---|
| 813 | + if (dsp[e->shift_l].booted || !list_empty(&dsp[e->shift_l].compr_list)) |
|---|
| 711 | 814 | ret = -EBUSY; |
|---|
| 712 | 815 | else |
|---|
| 713 | 816 | dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0]; |
|---|
| .. | .. |
|---|
| 744 | 847 | static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem, |
|---|
| 745 | 848 | unsigned int offset) |
|---|
| 746 | 849 | { |
|---|
| 747 | | - if (WARN_ON(!mem)) |
|---|
| 748 | | - return offset; |
|---|
| 749 | 850 | switch (mem->type) { |
|---|
| 750 | 851 | case WMFW_ADSP1_PM: |
|---|
| 751 | 852 | return mem->base + (offset * 3); |
|---|
| 752 | 853 | case WMFW_ADSP1_DM: |
|---|
| 753 | | - return mem->base + (offset * 2); |
|---|
| 754 | 854 | case WMFW_ADSP2_XM: |
|---|
| 755 | | - return mem->base + (offset * 2); |
|---|
| 756 | 855 | case WMFW_ADSP2_YM: |
|---|
| 757 | | - return mem->base + (offset * 2); |
|---|
| 758 | 856 | case WMFW_ADSP1_ZM: |
|---|
| 759 | 857 | return mem->base + (offset * 2); |
|---|
| 760 | 858 | default: |
|---|
| .. | .. |
|---|
| 763 | 861 | } |
|---|
| 764 | 862 | } |
|---|
| 765 | 863 | |
|---|
| 766 | | -static void wm_adsp2_show_fw_status(struct wm_adsp *dsp) |
|---|
| 864 | +static unsigned int wm_halo_region_to_reg(struct wm_adsp_region const *mem, |
|---|
| 865 | + unsigned int offset) |
|---|
| 767 | 866 | { |
|---|
| 768 | | - unsigned int scratch[4]; |
|---|
| 769 | | - unsigned int addr = dsp->base + ADSP2_SCRATCH0; |
|---|
| 867 | + switch (mem->type) { |
|---|
| 868 | + case WMFW_ADSP2_XM: |
|---|
| 869 | + case WMFW_ADSP2_YM: |
|---|
| 870 | + return mem->base + (offset * 4); |
|---|
| 871 | + case WMFW_HALO_XM_PACKED: |
|---|
| 872 | + case WMFW_HALO_YM_PACKED: |
|---|
| 873 | + return (mem->base + (offset * 3)) & ~0x3; |
|---|
| 874 | + case WMFW_HALO_PM_PACKED: |
|---|
| 875 | + return mem->base + (offset * 5); |
|---|
| 876 | + default: |
|---|
| 877 | + WARN(1, "Unknown memory region type"); |
|---|
| 878 | + return offset; |
|---|
| 879 | + } |
|---|
| 880 | +} |
|---|
| 881 | + |
|---|
| 882 | +static void wm_adsp_read_fw_status(struct wm_adsp *dsp, |
|---|
| 883 | + int noffs, unsigned int *offs) |
|---|
| 884 | +{ |
|---|
| 770 | 885 | unsigned int i; |
|---|
| 771 | 886 | int ret; |
|---|
| 772 | 887 | |
|---|
| 773 | | - for (i = 0; i < ARRAY_SIZE(scratch); ++i) { |
|---|
| 774 | | - ret = regmap_read(dsp->regmap, addr + i, &scratch[i]); |
|---|
| 888 | + for (i = 0; i < noffs; ++i) { |
|---|
| 889 | + ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]); |
|---|
| 775 | 890 | if (ret) { |
|---|
| 776 | 891 | adsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret); |
|---|
| 777 | 892 | return; |
|---|
| 778 | 893 | } |
|---|
| 779 | 894 | } |
|---|
| 895 | +} |
|---|
| 896 | + |
|---|
| 897 | +static void wm_adsp2_show_fw_status(struct wm_adsp *dsp) |
|---|
| 898 | +{ |
|---|
| 899 | + unsigned int offs[] = { |
|---|
| 900 | + ADSP2_SCRATCH0, ADSP2_SCRATCH1, ADSP2_SCRATCH2, ADSP2_SCRATCH3, |
|---|
| 901 | + }; |
|---|
| 902 | + |
|---|
| 903 | + wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs); |
|---|
| 780 | 904 | |
|---|
| 781 | 905 | adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", |
|---|
| 782 | | - scratch[0], scratch[1], scratch[2], scratch[3]); |
|---|
| 906 | + offs[0], offs[1], offs[2], offs[3]); |
|---|
| 783 | 907 | } |
|---|
| 784 | 908 | |
|---|
| 785 | 909 | static void wm_adsp2v2_show_fw_status(struct wm_adsp *dsp) |
|---|
| 786 | 910 | { |
|---|
| 787 | | - unsigned int scratch[2]; |
|---|
| 788 | | - int ret; |
|---|
| 911 | + unsigned int offs[] = { ADSP2V2_SCRATCH0_1, ADSP2V2_SCRATCH2_3 }; |
|---|
| 789 | 912 | |
|---|
| 790 | | - ret = regmap_read(dsp->regmap, dsp->base + ADSP2V2_SCRATCH0_1, |
|---|
| 791 | | - &scratch[0]); |
|---|
| 792 | | - if (ret) { |
|---|
| 793 | | - adsp_err(dsp, "Failed to read SCRATCH0_1: %d\n", ret); |
|---|
| 794 | | - return; |
|---|
| 795 | | - } |
|---|
| 796 | | - |
|---|
| 797 | | - ret = regmap_read(dsp->regmap, dsp->base + ADSP2V2_SCRATCH2_3, |
|---|
| 798 | | - &scratch[1]); |
|---|
| 799 | | - if (ret) { |
|---|
| 800 | | - adsp_err(dsp, "Failed to read SCRATCH2_3: %d\n", ret); |
|---|
| 801 | | - return; |
|---|
| 802 | | - } |
|---|
| 913 | + wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs); |
|---|
| 803 | 914 | |
|---|
| 804 | 915 | adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", |
|---|
| 805 | | - scratch[0] & 0xFFFF, |
|---|
| 806 | | - scratch[0] >> 16, |
|---|
| 807 | | - scratch[1] & 0xFFFF, |
|---|
| 808 | | - scratch[1] >> 16); |
|---|
| 916 | + offs[0] & 0xFFFF, offs[0] >> 16, |
|---|
| 917 | + offs[1] & 0xFFFF, offs[1] >> 16); |
|---|
| 918 | +} |
|---|
| 919 | + |
|---|
| 920 | +static void wm_halo_show_fw_status(struct wm_adsp *dsp) |
|---|
| 921 | +{ |
|---|
| 922 | + unsigned int offs[] = { |
|---|
| 923 | + HALO_SCRATCH1, HALO_SCRATCH2, HALO_SCRATCH3, HALO_SCRATCH4, |
|---|
| 924 | + }; |
|---|
| 925 | + |
|---|
| 926 | + wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs); |
|---|
| 927 | + |
|---|
| 928 | + adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", |
|---|
| 929 | + offs[0], offs[1], offs[2], offs[3]); |
|---|
| 809 | 930 | } |
|---|
| 810 | 931 | |
|---|
| 811 | 932 | static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext) |
|---|
| .. | .. |
|---|
| 826 | 947 | return -EINVAL; |
|---|
| 827 | 948 | } |
|---|
| 828 | 949 | |
|---|
| 829 | | - *reg = wm_adsp_region_to_reg(mem, ctl->alg_region.base + ctl->offset); |
|---|
| 950 | + *reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset); |
|---|
| 830 | 951 | |
|---|
| 831 | 952 | return 0; |
|---|
| 832 | 953 | } |
|---|
| .. | .. |
|---|
| 915 | 1036 | return -ETIMEDOUT; |
|---|
| 916 | 1037 | } |
|---|
| 917 | 1038 | |
|---|
| 918 | | -static int wm_coeff_write_control(struct wm_coeff_ctl *ctl, |
|---|
| 919 | | - const void *buf, size_t len) |
|---|
| 1039 | +static int wm_coeff_write_ctrl_raw(struct wm_coeff_ctl *ctl, |
|---|
| 1040 | + const void *buf, size_t len) |
|---|
| 920 | 1041 | { |
|---|
| 921 | 1042 | struct wm_adsp *dsp = ctl->dsp; |
|---|
| 922 | 1043 | void *scratch; |
|---|
| .. | .. |
|---|
| 946 | 1067 | return 0; |
|---|
| 947 | 1068 | } |
|---|
| 948 | 1069 | |
|---|
| 1070 | +static int wm_coeff_write_ctrl(struct wm_coeff_ctl *ctl, |
|---|
| 1071 | + const void *buf, size_t len) |
|---|
| 1072 | +{ |
|---|
| 1073 | + int ret = 0; |
|---|
| 1074 | + |
|---|
| 1075 | + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) |
|---|
| 1076 | + ret = -EPERM; |
|---|
| 1077 | + else if (buf != ctl->cache) |
|---|
| 1078 | + memcpy(ctl->cache, buf, len); |
|---|
| 1079 | + |
|---|
| 1080 | + ctl->set = 1; |
|---|
| 1081 | + if (ctl->enabled && ctl->dsp->running) |
|---|
| 1082 | + ret = wm_coeff_write_ctrl_raw(ctl, buf, len); |
|---|
| 1083 | + |
|---|
| 1084 | + return ret; |
|---|
| 1085 | +} |
|---|
| 1086 | + |
|---|
| 949 | 1087 | static int wm_coeff_put(struct snd_kcontrol *kctl, |
|---|
| 950 | 1088 | struct snd_ctl_elem_value *ucontrol) |
|---|
| 951 | 1089 | { |
|---|
| .. | .. |
|---|
| 956 | 1094 | int ret = 0; |
|---|
| 957 | 1095 | |
|---|
| 958 | 1096 | mutex_lock(&ctl->dsp->pwr_lock); |
|---|
| 959 | | - |
|---|
| 960 | | - if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) |
|---|
| 961 | | - ret = -EPERM; |
|---|
| 962 | | - else |
|---|
| 963 | | - memcpy(ctl->cache, p, ctl->len); |
|---|
| 964 | | - |
|---|
| 965 | | - ctl->set = 1; |
|---|
| 966 | | - if (ctl->enabled && ctl->dsp->running) |
|---|
| 967 | | - ret = wm_coeff_write_control(ctl, p, ctl->len); |
|---|
| 968 | | - |
|---|
| 1097 | + ret = wm_coeff_write_ctrl(ctl, p, ctl->len); |
|---|
| 969 | 1098 | mutex_unlock(&ctl->dsp->pwr_lock); |
|---|
| 970 | 1099 | |
|---|
| 971 | 1100 | return ret; |
|---|
| .. | .. |
|---|
| 981 | 1110 | |
|---|
| 982 | 1111 | mutex_lock(&ctl->dsp->pwr_lock); |
|---|
| 983 | 1112 | |
|---|
| 984 | | - if (copy_from_user(ctl->cache, bytes, size)) { |
|---|
| 1113 | + if (copy_from_user(ctl->cache, bytes, size)) |
|---|
| 985 | 1114 | ret = -EFAULT; |
|---|
| 986 | | - } else { |
|---|
| 987 | | - ctl->set = 1; |
|---|
| 988 | | - if (ctl->enabled && ctl->dsp->running) |
|---|
| 989 | | - ret = wm_coeff_write_control(ctl, ctl->cache, size); |
|---|
| 990 | | - else if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) |
|---|
| 991 | | - ret = -EPERM; |
|---|
| 992 | | - } |
|---|
| 1115 | + else |
|---|
| 1116 | + ret = wm_coeff_write_ctrl(ctl, ctl->cache, size); |
|---|
| 993 | 1117 | |
|---|
| 994 | 1118 | mutex_unlock(&ctl->dsp->pwr_lock); |
|---|
| 995 | 1119 | |
|---|
| .. | .. |
|---|
| 1020 | 1144 | return ret; |
|---|
| 1021 | 1145 | } |
|---|
| 1022 | 1146 | |
|---|
| 1023 | | -static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, |
|---|
| 1024 | | - void *buf, size_t len) |
|---|
| 1147 | +static int wm_coeff_read_ctrl_raw(struct wm_coeff_ctl *ctl, |
|---|
| 1148 | + void *buf, size_t len) |
|---|
| 1025 | 1149 | { |
|---|
| 1026 | 1150 | struct wm_adsp *dsp = ctl->dsp; |
|---|
| 1027 | 1151 | void *scratch; |
|---|
| .. | .. |
|---|
| 1051 | 1175 | return 0; |
|---|
| 1052 | 1176 | } |
|---|
| 1053 | 1177 | |
|---|
| 1178 | +static int wm_coeff_read_ctrl(struct wm_coeff_ctl *ctl, void *buf, size_t len) |
|---|
| 1179 | +{ |
|---|
| 1180 | + int ret = 0; |
|---|
| 1181 | + |
|---|
| 1182 | + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { |
|---|
| 1183 | + if (ctl->enabled && ctl->dsp->running) |
|---|
| 1184 | + return wm_coeff_read_ctrl_raw(ctl, buf, len); |
|---|
| 1185 | + else |
|---|
| 1186 | + return -EPERM; |
|---|
| 1187 | + } else { |
|---|
| 1188 | + if (!ctl->flags && ctl->enabled && ctl->dsp->running) |
|---|
| 1189 | + ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len); |
|---|
| 1190 | + |
|---|
| 1191 | + if (buf != ctl->cache) |
|---|
| 1192 | + memcpy(buf, ctl->cache, len); |
|---|
| 1193 | + } |
|---|
| 1194 | + |
|---|
| 1195 | + return ret; |
|---|
| 1196 | +} |
|---|
| 1197 | + |
|---|
| 1054 | 1198 | static int wm_coeff_get(struct snd_kcontrol *kctl, |
|---|
| 1055 | 1199 | struct snd_ctl_elem_value *ucontrol) |
|---|
| 1056 | 1200 | { |
|---|
| .. | .. |
|---|
| 1058 | 1202 | (struct soc_bytes_ext *)kctl->private_value; |
|---|
| 1059 | 1203 | struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); |
|---|
| 1060 | 1204 | char *p = ucontrol->value.bytes.data; |
|---|
| 1061 | | - int ret = 0; |
|---|
| 1205 | + int ret; |
|---|
| 1062 | 1206 | |
|---|
| 1063 | 1207 | mutex_lock(&ctl->dsp->pwr_lock); |
|---|
| 1064 | | - |
|---|
| 1065 | | - if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { |
|---|
| 1066 | | - if (ctl->enabled && ctl->dsp->running) |
|---|
| 1067 | | - ret = wm_coeff_read_control(ctl, p, ctl->len); |
|---|
| 1068 | | - else |
|---|
| 1069 | | - ret = -EPERM; |
|---|
| 1070 | | - } else { |
|---|
| 1071 | | - if (!ctl->flags && ctl->enabled && ctl->dsp->running) |
|---|
| 1072 | | - ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len); |
|---|
| 1073 | | - |
|---|
| 1074 | | - memcpy(p, ctl->cache, ctl->len); |
|---|
| 1075 | | - } |
|---|
| 1076 | | - |
|---|
| 1208 | + ret = wm_coeff_read_ctrl(ctl, p, ctl->len); |
|---|
| 1077 | 1209 | mutex_unlock(&ctl->dsp->pwr_lock); |
|---|
| 1078 | 1210 | |
|---|
| 1079 | 1211 | return ret; |
|---|
| .. | .. |
|---|
| 1089 | 1221 | |
|---|
| 1090 | 1222 | mutex_lock(&ctl->dsp->pwr_lock); |
|---|
| 1091 | 1223 | |
|---|
| 1092 | | - if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { |
|---|
| 1093 | | - if (ctl->enabled && ctl->dsp->running) |
|---|
| 1094 | | - ret = wm_coeff_read_control(ctl, ctl->cache, size); |
|---|
| 1095 | | - else |
|---|
| 1096 | | - ret = -EPERM; |
|---|
| 1097 | | - } else { |
|---|
| 1098 | | - if (!ctl->flags && ctl->enabled && ctl->dsp->running) |
|---|
| 1099 | | - ret = wm_coeff_read_control(ctl, ctl->cache, size); |
|---|
| 1100 | | - } |
|---|
| 1224 | + ret = wm_coeff_read_ctrl(ctl, ctl->cache, size); |
|---|
| 1101 | 1225 | |
|---|
| 1102 | 1226 | if (!ret && copy_to_user(bytes, ctl->cache, size)) |
|---|
| 1103 | 1227 | ret = -EFAULT; |
|---|
| .. | .. |
|---|
| 1225 | 1349 | * created so we don't need to do anything. |
|---|
| 1226 | 1350 | */ |
|---|
| 1227 | 1351 | if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) { |
|---|
| 1228 | | - ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len); |
|---|
| 1352 | + ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len); |
|---|
| 1229 | 1353 | if (ret < 0) |
|---|
| 1230 | 1354 | return ret; |
|---|
| 1231 | 1355 | } |
|---|
| .. | .. |
|---|
| 1243 | 1367 | if (!ctl->enabled) |
|---|
| 1244 | 1368 | continue; |
|---|
| 1245 | 1369 | if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) { |
|---|
| 1246 | | - ret = wm_coeff_write_control(ctl, ctl->cache, ctl->len); |
|---|
| 1370 | + ret = wm_coeff_write_ctrl_raw(ctl, ctl->cache, |
|---|
| 1371 | + ctl->len); |
|---|
| 1247 | 1372 | if (ret < 0) |
|---|
| 1248 | 1373 | return ret; |
|---|
| 1249 | 1374 | } |
|---|
| .. | .. |
|---|
| 1287 | 1412 | { |
|---|
| 1288 | 1413 | kfree(ctl->cache); |
|---|
| 1289 | 1414 | kfree(ctl->name); |
|---|
| 1415 | + kfree(ctl->subname); |
|---|
| 1290 | 1416 | kfree(ctl); |
|---|
| 1291 | 1417 | } |
|---|
| 1292 | 1418 | |
|---|
| .. | .. |
|---|
| 1313 | 1439 | case 1: |
|---|
| 1314 | 1440 | snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x", |
|---|
| 1315 | 1441 | dsp->name, region_name, alg_region->alg); |
|---|
| 1442 | + subname = NULL; /* don't append subname */ |
|---|
| 1316 | 1443 | break; |
|---|
| 1317 | | - default: |
|---|
| 1318 | | - ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, |
|---|
| 1444 | + case 2: |
|---|
| 1445 | + ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, |
|---|
| 1319 | 1446 | "%s%c %.12s %x", dsp->name, *region_name, |
|---|
| 1320 | 1447 | wm_adsp_fw_text[dsp->fw], alg_region->alg); |
|---|
| 1448 | + break; |
|---|
| 1449 | + default: |
|---|
| 1450 | + ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, |
|---|
| 1451 | + "%s %.12s %x", dsp->name, |
|---|
| 1452 | + wm_adsp_fw_text[dsp->fw], alg_region->alg); |
|---|
| 1453 | + break; |
|---|
| 1454 | + } |
|---|
| 1455 | + |
|---|
| 1456 | + if (subname) { |
|---|
| 1457 | + int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2; |
|---|
| 1458 | + int skip = 0; |
|---|
| 1459 | + |
|---|
| 1460 | + if (dsp->component->name_prefix) |
|---|
| 1461 | + avail -= strlen(dsp->component->name_prefix) + 1; |
|---|
| 1321 | 1462 | |
|---|
| 1322 | 1463 | /* Truncate the subname from the start if it is too long */ |
|---|
| 1323 | | - if (subname) { |
|---|
| 1324 | | - int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2; |
|---|
| 1325 | | - int skip = 0; |
|---|
| 1464 | + if (subname_len > avail) |
|---|
| 1465 | + skip = subname_len - avail; |
|---|
| 1326 | 1466 | |
|---|
| 1327 | | - if (dsp->component->name_prefix) |
|---|
| 1328 | | - avail -= strlen(dsp->component->name_prefix) + 1; |
|---|
| 1329 | | - |
|---|
| 1330 | | - if (subname_len > avail) |
|---|
| 1331 | | - skip = subname_len - avail; |
|---|
| 1332 | | - |
|---|
| 1333 | | - snprintf(name + ret, |
|---|
| 1334 | | - SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s", |
|---|
| 1335 | | - subname_len - skip, subname + skip); |
|---|
| 1336 | | - } |
|---|
| 1337 | | - break; |
|---|
| 1467 | + snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, |
|---|
| 1468 | + " %.*s", subname_len - skip, subname + skip); |
|---|
| 1338 | 1469 | } |
|---|
| 1339 | 1470 | |
|---|
| 1340 | 1471 | list_for_each_entry(ctl, &dsp->ctl_list, list) { |
|---|
| .. | .. |
|---|
| 1355 | 1486 | ret = -ENOMEM; |
|---|
| 1356 | 1487 | goto err_ctl; |
|---|
| 1357 | 1488 | } |
|---|
| 1489 | + if (subname) { |
|---|
| 1490 | + ctl->subname_len = subname_len; |
|---|
| 1491 | + ctl->subname = kmemdup(subname, |
|---|
| 1492 | + strlen(subname) + 1, GFP_KERNEL); |
|---|
| 1493 | + if (!ctl->subname) { |
|---|
| 1494 | + ret = -ENOMEM; |
|---|
| 1495 | + goto err_ctl_name; |
|---|
| 1496 | + } |
|---|
| 1497 | + } |
|---|
| 1358 | 1498 | ctl->enabled = 1; |
|---|
| 1359 | 1499 | ctl->set = 0; |
|---|
| 1360 | 1500 | ctl->ops.xget = wm_coeff_get; |
|---|
| .. | .. |
|---|
| 1368 | 1508 | ctl->cache = kzalloc(ctl->len, GFP_KERNEL); |
|---|
| 1369 | 1509 | if (!ctl->cache) { |
|---|
| 1370 | 1510 | ret = -ENOMEM; |
|---|
| 1371 | | - goto err_ctl_name; |
|---|
| 1511 | + goto err_ctl_subname; |
|---|
| 1372 | 1512 | } |
|---|
| 1373 | 1513 | |
|---|
| 1374 | 1514 | list_add(&ctl->list, &dsp->ctl_list); |
|---|
| .. | .. |
|---|
| 1392 | 1532 | err_list_del: |
|---|
| 1393 | 1533 | list_del(&ctl->list); |
|---|
| 1394 | 1534 | kfree(ctl->cache); |
|---|
| 1535 | +err_ctl_subname: |
|---|
| 1536 | + kfree(ctl->subname); |
|---|
| 1395 | 1537 | err_ctl_name: |
|---|
| 1396 | 1538 | kfree(ctl->name); |
|---|
| 1397 | 1539 | err_ctl: |
|---|
| .. | .. |
|---|
| 1622 | 1764 | return 0; |
|---|
| 1623 | 1765 | } |
|---|
| 1624 | 1766 | |
|---|
| 1767 | +static unsigned int wm_adsp1_parse_sizes(struct wm_adsp *dsp, |
|---|
| 1768 | + const char * const file, |
|---|
| 1769 | + unsigned int pos, |
|---|
| 1770 | + const struct firmware *firmware) |
|---|
| 1771 | +{ |
|---|
| 1772 | + const struct wmfw_adsp1_sizes *adsp1_sizes; |
|---|
| 1773 | + |
|---|
| 1774 | + adsp1_sizes = (void *)&firmware->data[pos]; |
|---|
| 1775 | + |
|---|
| 1776 | + adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file, |
|---|
| 1777 | + le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm), |
|---|
| 1778 | + le32_to_cpu(adsp1_sizes->zm)); |
|---|
| 1779 | + |
|---|
| 1780 | + return pos + sizeof(*adsp1_sizes); |
|---|
| 1781 | +} |
|---|
| 1782 | + |
|---|
| 1783 | +static unsigned int wm_adsp2_parse_sizes(struct wm_adsp *dsp, |
|---|
| 1784 | + const char * const file, |
|---|
| 1785 | + unsigned int pos, |
|---|
| 1786 | + const struct firmware *firmware) |
|---|
| 1787 | +{ |
|---|
| 1788 | + const struct wmfw_adsp2_sizes *adsp2_sizes; |
|---|
| 1789 | + |
|---|
| 1790 | + adsp2_sizes = (void *)&firmware->data[pos]; |
|---|
| 1791 | + |
|---|
| 1792 | + adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file, |
|---|
| 1793 | + le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym), |
|---|
| 1794 | + le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm)); |
|---|
| 1795 | + |
|---|
| 1796 | + return pos + sizeof(*adsp2_sizes); |
|---|
| 1797 | +} |
|---|
| 1798 | + |
|---|
| 1799 | +static bool wm_adsp_validate_version(struct wm_adsp *dsp, unsigned int version) |
|---|
| 1800 | +{ |
|---|
| 1801 | + switch (version) { |
|---|
| 1802 | + case 0: |
|---|
| 1803 | + adsp_warn(dsp, "Deprecated file format %d\n", version); |
|---|
| 1804 | + return true; |
|---|
| 1805 | + case 1: |
|---|
| 1806 | + case 2: |
|---|
| 1807 | + return true; |
|---|
| 1808 | + default: |
|---|
| 1809 | + return false; |
|---|
| 1810 | + } |
|---|
| 1811 | +} |
|---|
| 1812 | + |
|---|
| 1813 | +static bool wm_halo_validate_version(struct wm_adsp *dsp, unsigned int version) |
|---|
| 1814 | +{ |
|---|
| 1815 | + switch (version) { |
|---|
| 1816 | + case 3: |
|---|
| 1817 | + return true; |
|---|
| 1818 | + default: |
|---|
| 1819 | + return false; |
|---|
| 1820 | + } |
|---|
| 1821 | +} |
|---|
| 1822 | + |
|---|
| 1625 | 1823 | static int wm_adsp_load(struct wm_adsp *dsp) |
|---|
| 1626 | 1824 | { |
|---|
| 1627 | 1825 | LIST_HEAD(buf_list); |
|---|
| .. | .. |
|---|
| 1630 | 1828 | unsigned int pos = 0; |
|---|
| 1631 | 1829 | const struct wmfw_header *header; |
|---|
| 1632 | 1830 | const struct wmfw_adsp1_sizes *adsp1_sizes; |
|---|
| 1633 | | - const struct wmfw_adsp2_sizes *adsp2_sizes; |
|---|
| 1634 | 1831 | const struct wmfw_footer *footer; |
|---|
| 1635 | 1832 | const struct wmfw_region *region; |
|---|
| 1636 | 1833 | const struct wm_adsp_region *mem; |
|---|
| .. | .. |
|---|
| 1639 | 1836 | struct wm_adsp_buf *buf; |
|---|
| 1640 | 1837 | unsigned int reg; |
|---|
| 1641 | 1838 | int regions = 0; |
|---|
| 1642 | | - int ret, offset, type, sizes; |
|---|
| 1839 | + int ret, offset, type; |
|---|
| 1643 | 1840 | |
|---|
| 1644 | 1841 | file = kzalloc(PAGE_SIZE, GFP_KERNEL); |
|---|
| 1645 | 1842 | if (file == NULL) |
|---|
| .. | .. |
|---|
| 1670 | 1867 | goto out_fw; |
|---|
| 1671 | 1868 | } |
|---|
| 1672 | 1869 | |
|---|
| 1673 | | - switch (header->ver) { |
|---|
| 1674 | | - case 0: |
|---|
| 1675 | | - adsp_warn(dsp, "%s: Depreciated file format %d\n", |
|---|
| 1676 | | - file, header->ver); |
|---|
| 1677 | | - break; |
|---|
| 1678 | | - case 1: |
|---|
| 1679 | | - case 2: |
|---|
| 1680 | | - break; |
|---|
| 1681 | | - default: |
|---|
| 1870 | + if (!dsp->ops->validate_version(dsp, header->ver)) { |
|---|
| 1682 | 1871 | adsp_err(dsp, "%s: unknown file format %d\n", |
|---|
| 1683 | 1872 | file, header->ver); |
|---|
| 1684 | 1873 | goto out_fw; |
|---|
| .. | .. |
|---|
| 1693 | 1882 | goto out_fw; |
|---|
| 1694 | 1883 | } |
|---|
| 1695 | 1884 | |
|---|
| 1696 | | - switch (dsp->type) { |
|---|
| 1697 | | - case WMFW_ADSP1: |
|---|
| 1698 | | - pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); |
|---|
| 1699 | | - adsp1_sizes = (void *)&(header[1]); |
|---|
| 1700 | | - footer = (void *)&(adsp1_sizes[1]); |
|---|
| 1701 | | - sizes = sizeof(*adsp1_sizes); |
|---|
| 1885 | + pos = sizeof(*header); |
|---|
| 1886 | + pos = dsp->ops->parse_sizes(dsp, file, pos, firmware); |
|---|
| 1702 | 1887 | |
|---|
| 1703 | | - adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", |
|---|
| 1704 | | - file, le32_to_cpu(adsp1_sizes->dm), |
|---|
| 1705 | | - le32_to_cpu(adsp1_sizes->pm), |
|---|
| 1706 | | - le32_to_cpu(adsp1_sizes->zm)); |
|---|
| 1707 | | - break; |
|---|
| 1888 | + footer = (void *)&firmware->data[pos]; |
|---|
| 1889 | + pos += sizeof(*footer); |
|---|
| 1708 | 1890 | |
|---|
| 1709 | | - case WMFW_ADSP2: |
|---|
| 1710 | | - pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer); |
|---|
| 1711 | | - adsp2_sizes = (void *)&(header[1]); |
|---|
| 1712 | | - footer = (void *)&(adsp2_sizes[1]); |
|---|
| 1713 | | - sizes = sizeof(*adsp2_sizes); |
|---|
| 1714 | | - |
|---|
| 1715 | | - adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", |
|---|
| 1716 | | - file, le32_to_cpu(adsp2_sizes->xm), |
|---|
| 1717 | | - le32_to_cpu(adsp2_sizes->ym), |
|---|
| 1718 | | - le32_to_cpu(adsp2_sizes->pm), |
|---|
| 1719 | | - le32_to_cpu(adsp2_sizes->zm)); |
|---|
| 1720 | | - break; |
|---|
| 1721 | | - |
|---|
| 1722 | | - default: |
|---|
| 1723 | | - WARN(1, "Unknown DSP type"); |
|---|
| 1724 | | - goto out_fw; |
|---|
| 1725 | | - } |
|---|
| 1726 | | - |
|---|
| 1727 | | - if (le32_to_cpu(header->len) != sizeof(*header) + |
|---|
| 1728 | | - sizes + sizeof(*footer)) { |
|---|
| 1891 | + if (le32_to_cpu(header->len) != pos) { |
|---|
| 1729 | 1892 | adsp_err(dsp, "%s: unexpected header length %d\n", |
|---|
| 1730 | 1893 | file, le32_to_cpu(header->len)); |
|---|
| 1731 | 1894 | goto out_fw; |
|---|
| .. | .. |
|---|
| 1742 | 1905 | text = NULL; |
|---|
| 1743 | 1906 | offset = le32_to_cpu(region->offset) & 0xffffff; |
|---|
| 1744 | 1907 | type = be32_to_cpu(region->type) & 0xff; |
|---|
| 1745 | | - mem = wm_adsp_find_region(dsp, type); |
|---|
| 1746 | 1908 | |
|---|
| 1747 | 1909 | switch (type) { |
|---|
| 1748 | 1910 | case WMFW_NAME_TEXT: |
|---|
| .. | .. |
|---|
| 1770 | 1932 | case WMFW_ADSP2_XM: |
|---|
| 1771 | 1933 | case WMFW_ADSP2_YM: |
|---|
| 1772 | 1934 | case WMFW_ADSP1_ZM: |
|---|
| 1935 | + case WMFW_HALO_PM_PACKED: |
|---|
| 1936 | + case WMFW_HALO_XM_PACKED: |
|---|
| 1937 | + case WMFW_HALO_YM_PACKED: |
|---|
| 1938 | + mem = wm_adsp_find_region(dsp, type); |
|---|
| 1939 | + if (!mem) { |
|---|
| 1940 | + adsp_err(dsp, "No region of type: %x\n", type); |
|---|
| 1941 | + ret = -EINVAL; |
|---|
| 1942 | + goto out_fw; |
|---|
| 1943 | + } |
|---|
| 1944 | + |
|---|
| 1773 | 1945 | region_name = wm_adsp_mem_region_name(type); |
|---|
| 1774 | | - reg = wm_adsp_region_to_reg(mem, offset); |
|---|
| 1946 | + reg = dsp->ops->region_to_reg(mem, offset); |
|---|
| 1775 | 1947 | break; |
|---|
| 1776 | 1948 | default: |
|---|
| 1777 | 1949 | adsp_warn(dsp, |
|---|
| .. | .. |
|---|
| 1850 | 2022 | return ret; |
|---|
| 1851 | 2023 | } |
|---|
| 1852 | 2024 | |
|---|
| 2025 | +/* |
|---|
| 2026 | + * Find wm_coeff_ctl with input name as its subname |
|---|
| 2027 | + * If not found, return NULL |
|---|
| 2028 | + */ |
|---|
| 2029 | +static struct wm_coeff_ctl *wm_adsp_get_ctl(struct wm_adsp *dsp, |
|---|
| 2030 | + const char *name, int type, |
|---|
| 2031 | + unsigned int alg) |
|---|
| 2032 | +{ |
|---|
| 2033 | + struct wm_coeff_ctl *pos, *rslt = NULL; |
|---|
| 2034 | + const char *fw_txt = wm_adsp_fw_text[dsp->fw]; |
|---|
| 2035 | + |
|---|
| 2036 | + list_for_each_entry(pos, &dsp->ctl_list, list) { |
|---|
| 2037 | + if (!pos->subname) |
|---|
| 2038 | + continue; |
|---|
| 2039 | + if (strncmp(pos->subname, name, pos->subname_len) == 0 && |
|---|
| 2040 | + strncmp(pos->fw_name, fw_txt, |
|---|
| 2041 | + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0 && |
|---|
| 2042 | + pos->alg_region.alg == alg && |
|---|
| 2043 | + pos->alg_region.type == type) { |
|---|
| 2044 | + rslt = pos; |
|---|
| 2045 | + break; |
|---|
| 2046 | + } |
|---|
| 2047 | + } |
|---|
| 2048 | + |
|---|
| 2049 | + return rslt; |
|---|
| 2050 | +} |
|---|
| 2051 | + |
|---|
| 2052 | +int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, |
|---|
| 2053 | + unsigned int alg, void *buf, size_t len) |
|---|
| 2054 | +{ |
|---|
| 2055 | + struct wm_coeff_ctl *ctl; |
|---|
| 2056 | + struct snd_kcontrol *kcontrol; |
|---|
| 2057 | + char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; |
|---|
| 2058 | + int ret; |
|---|
| 2059 | + |
|---|
| 2060 | + ctl = wm_adsp_get_ctl(dsp, name, type, alg); |
|---|
| 2061 | + if (!ctl) |
|---|
| 2062 | + return -EINVAL; |
|---|
| 2063 | + |
|---|
| 2064 | + if (len > ctl->len) |
|---|
| 2065 | + return -EINVAL; |
|---|
| 2066 | + |
|---|
| 2067 | + ret = wm_coeff_write_ctrl(ctl, buf, len); |
|---|
| 2068 | + if (ret) |
|---|
| 2069 | + return ret; |
|---|
| 2070 | + |
|---|
| 2071 | + if (ctl->flags & WMFW_CTL_FLAG_SYS) |
|---|
| 2072 | + return 0; |
|---|
| 2073 | + |
|---|
| 2074 | + if (dsp->component->name_prefix) |
|---|
| 2075 | + snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s", |
|---|
| 2076 | + dsp->component->name_prefix, ctl->name); |
|---|
| 2077 | + else |
|---|
| 2078 | + snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s", |
|---|
| 2079 | + ctl->name); |
|---|
| 2080 | + |
|---|
| 2081 | + kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl_name); |
|---|
| 2082 | + if (!kcontrol) { |
|---|
| 2083 | + adsp_err(dsp, "Can't find kcontrol %s\n", ctl_name); |
|---|
| 2084 | + return -EINVAL; |
|---|
| 2085 | + } |
|---|
| 2086 | + |
|---|
| 2087 | + snd_ctl_notify(dsp->component->card->snd_card, |
|---|
| 2088 | + SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id); |
|---|
| 2089 | + |
|---|
| 2090 | + return ret; |
|---|
| 2091 | +} |
|---|
| 2092 | +EXPORT_SYMBOL_GPL(wm_adsp_write_ctl); |
|---|
| 2093 | + |
|---|
| 2094 | +int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, |
|---|
| 2095 | + unsigned int alg, void *buf, size_t len) |
|---|
| 2096 | +{ |
|---|
| 2097 | + struct wm_coeff_ctl *ctl; |
|---|
| 2098 | + |
|---|
| 2099 | + ctl = wm_adsp_get_ctl(dsp, name, type, alg); |
|---|
| 2100 | + if (!ctl) |
|---|
| 2101 | + return -EINVAL; |
|---|
| 2102 | + |
|---|
| 2103 | + if (len > ctl->len) |
|---|
| 2104 | + return -EINVAL; |
|---|
| 2105 | + |
|---|
| 2106 | + return wm_coeff_read_ctrl(ctl, buf, len); |
|---|
| 2107 | +} |
|---|
| 2108 | +EXPORT_SYMBOL_GPL(wm_adsp_read_ctl); |
|---|
| 2109 | + |
|---|
| 1853 | 2110 | static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp, |
|---|
| 1854 | 2111 | const struct wm_adsp_alg_region *alg_region) |
|---|
| 1855 | 2112 | { |
|---|
| .. | .. |
|---|
| 1884 | 2141 | } |
|---|
| 1885 | 2142 | |
|---|
| 1886 | 2143 | /* Read the terminator first to validate the length */ |
|---|
| 1887 | | - reg = wm_adsp_region_to_reg(mem, pos + len); |
|---|
| 2144 | + reg = dsp->ops->region_to_reg(mem, pos + len); |
|---|
| 1888 | 2145 | |
|---|
| 1889 | 2146 | ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); |
|---|
| 1890 | 2147 | if (ret != 0) { |
|---|
| .. | .. |
|---|
| 1904 | 2161 | if (!alg) |
|---|
| 1905 | 2162 | return ERR_PTR(-ENOMEM); |
|---|
| 1906 | 2163 | |
|---|
| 1907 | | - reg = wm_adsp_region_to_reg(mem, pos); |
|---|
| 2164 | + reg = dsp->ops->region_to_reg(mem, pos); |
|---|
| 1908 | 2165 | |
|---|
| 1909 | 2166 | ret = regmap_raw_read(dsp->regmap, reg, alg, len); |
|---|
| 1910 | 2167 | if (ret != 0) { |
|---|
| .. | .. |
|---|
| 1964 | 2221 | } |
|---|
| 1965 | 2222 | } |
|---|
| 1966 | 2223 | |
|---|
| 2224 | +static void wmfw_parse_id_header(struct wm_adsp *dsp, |
|---|
| 2225 | + struct wmfw_id_hdr *fw, int nalgs) |
|---|
| 2226 | +{ |
|---|
| 2227 | + dsp->fw_id = be32_to_cpu(fw->id); |
|---|
| 2228 | + dsp->fw_id_version = be32_to_cpu(fw->ver); |
|---|
| 2229 | + |
|---|
| 2230 | + adsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n", |
|---|
| 2231 | + dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16, |
|---|
| 2232 | + (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, |
|---|
| 2233 | + nalgs); |
|---|
| 2234 | +} |
|---|
| 2235 | + |
|---|
| 2236 | +static void wmfw_v3_parse_id_header(struct wm_adsp *dsp, |
|---|
| 2237 | + struct wmfw_v3_id_hdr *fw, int nalgs) |
|---|
| 2238 | +{ |
|---|
| 2239 | + dsp->fw_id = be32_to_cpu(fw->id); |
|---|
| 2240 | + dsp->fw_id_version = be32_to_cpu(fw->ver); |
|---|
| 2241 | + dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id); |
|---|
| 2242 | + |
|---|
| 2243 | + adsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n", |
|---|
| 2244 | + dsp->fw_id, dsp->fw_vendor_id, |
|---|
| 2245 | + (dsp->fw_id_version & 0xff0000) >> 16, |
|---|
| 2246 | + (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, |
|---|
| 2247 | + nalgs); |
|---|
| 2248 | +} |
|---|
| 2249 | + |
|---|
| 2250 | +static int wm_adsp_create_regions(struct wm_adsp *dsp, __be32 id, int nregions, |
|---|
| 2251 | + int *type, __be32 *base) |
|---|
| 2252 | +{ |
|---|
| 2253 | + struct wm_adsp_alg_region *alg_region; |
|---|
| 2254 | + int i; |
|---|
| 2255 | + |
|---|
| 2256 | + for (i = 0; i < nregions; i++) { |
|---|
| 2257 | + alg_region = wm_adsp_create_region(dsp, type[i], id, base[i]); |
|---|
| 2258 | + if (IS_ERR(alg_region)) |
|---|
| 2259 | + return PTR_ERR(alg_region); |
|---|
| 2260 | + } |
|---|
| 2261 | + |
|---|
| 2262 | + return 0; |
|---|
| 2263 | +} |
|---|
| 2264 | + |
|---|
| 1967 | 2265 | static int wm_adsp1_setup_algs(struct wm_adsp *dsp) |
|---|
| 1968 | 2266 | { |
|---|
| 1969 | 2267 | struct wmfw_adsp1_id_hdr adsp1_id; |
|---|
| .. | .. |
|---|
| 1987 | 2285 | } |
|---|
| 1988 | 2286 | |
|---|
| 1989 | 2287 | n_algs = be32_to_cpu(adsp1_id.n_algs); |
|---|
| 1990 | | - dsp->fw_id = be32_to_cpu(adsp1_id.fw.id); |
|---|
| 1991 | | - adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", |
|---|
| 1992 | | - dsp->fw_id, |
|---|
| 1993 | | - (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16, |
|---|
| 1994 | | - (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8, |
|---|
| 1995 | | - be32_to_cpu(adsp1_id.fw.ver) & 0xff, |
|---|
| 1996 | | - n_algs); |
|---|
| 2288 | + |
|---|
| 2289 | + wmfw_parse_id_header(dsp, &adsp1_id.fw, n_algs); |
|---|
| 1997 | 2290 | |
|---|
| 1998 | 2291 | alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM, |
|---|
| 1999 | 2292 | adsp1_id.fw.id, adsp1_id.zm); |
|---|
| .. | .. |
|---|
| 2093 | 2386 | } |
|---|
| 2094 | 2387 | |
|---|
| 2095 | 2388 | n_algs = be32_to_cpu(adsp2_id.n_algs); |
|---|
| 2096 | | - dsp->fw_id = be32_to_cpu(adsp2_id.fw.id); |
|---|
| 2097 | | - dsp->fw_id_version = be32_to_cpu(adsp2_id.fw.ver); |
|---|
| 2098 | | - adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", |
|---|
| 2099 | | - dsp->fw_id, |
|---|
| 2100 | | - (dsp->fw_id_version & 0xff0000) >> 16, |
|---|
| 2101 | | - (dsp->fw_id_version & 0xff00) >> 8, |
|---|
| 2102 | | - dsp->fw_id_version & 0xff, |
|---|
| 2103 | | - n_algs); |
|---|
| 2389 | + |
|---|
| 2390 | + wmfw_parse_id_header(dsp, &adsp2_id.fw, n_algs); |
|---|
| 2104 | 2391 | |
|---|
| 2105 | 2392 | alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, |
|---|
| 2106 | 2393 | adsp2_id.fw.id, adsp2_id.xm); |
|---|
| .. | .. |
|---|
| 2205 | 2492 | return ret; |
|---|
| 2206 | 2493 | } |
|---|
| 2207 | 2494 | |
|---|
| 2495 | +static int wm_halo_create_regions(struct wm_adsp *dsp, __be32 id, |
|---|
| 2496 | + __be32 xm_base, __be32 ym_base) |
|---|
| 2497 | +{ |
|---|
| 2498 | + int types[] = { |
|---|
| 2499 | + WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED, |
|---|
| 2500 | + WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED |
|---|
| 2501 | + }; |
|---|
| 2502 | + __be32 bases[] = { xm_base, xm_base, ym_base, ym_base }; |
|---|
| 2503 | + |
|---|
| 2504 | + return wm_adsp_create_regions(dsp, id, ARRAY_SIZE(types), types, bases); |
|---|
| 2505 | +} |
|---|
| 2506 | + |
|---|
| 2507 | +static int wm_halo_setup_algs(struct wm_adsp *dsp) |
|---|
| 2508 | +{ |
|---|
| 2509 | + struct wmfw_halo_id_hdr halo_id; |
|---|
| 2510 | + struct wmfw_halo_alg_hdr *halo_alg; |
|---|
| 2511 | + const struct wm_adsp_region *mem; |
|---|
| 2512 | + unsigned int pos, len; |
|---|
| 2513 | + size_t n_algs; |
|---|
| 2514 | + int i, ret; |
|---|
| 2515 | + |
|---|
| 2516 | + mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); |
|---|
| 2517 | + if (WARN_ON(!mem)) |
|---|
| 2518 | + return -EINVAL; |
|---|
| 2519 | + |
|---|
| 2520 | + ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id, |
|---|
| 2521 | + sizeof(halo_id)); |
|---|
| 2522 | + if (ret != 0) { |
|---|
| 2523 | + adsp_err(dsp, "Failed to read algorithm info: %d\n", |
|---|
| 2524 | + ret); |
|---|
| 2525 | + return ret; |
|---|
| 2526 | + } |
|---|
| 2527 | + |
|---|
| 2528 | + n_algs = be32_to_cpu(halo_id.n_algs); |
|---|
| 2529 | + |
|---|
| 2530 | + wmfw_v3_parse_id_header(dsp, &halo_id.fw, n_algs); |
|---|
| 2531 | + |
|---|
| 2532 | + ret = wm_halo_create_regions(dsp, halo_id.fw.id, |
|---|
| 2533 | + halo_id.xm_base, halo_id.ym_base); |
|---|
| 2534 | + if (ret) |
|---|
| 2535 | + return ret; |
|---|
| 2536 | + |
|---|
| 2537 | + /* Calculate offset and length in DSP words */ |
|---|
| 2538 | + pos = sizeof(halo_id) / sizeof(u32); |
|---|
| 2539 | + len = (sizeof(*halo_alg) * n_algs) / sizeof(u32); |
|---|
| 2540 | + |
|---|
| 2541 | + halo_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len); |
|---|
| 2542 | + if (IS_ERR(halo_alg)) |
|---|
| 2543 | + return PTR_ERR(halo_alg); |
|---|
| 2544 | + |
|---|
| 2545 | + for (i = 0; i < n_algs; i++) { |
|---|
| 2546 | + adsp_info(dsp, |
|---|
| 2547 | + "%d: ID %x v%d.%d.%d XM@%x YM@%x\n", |
|---|
| 2548 | + i, be32_to_cpu(halo_alg[i].alg.id), |
|---|
| 2549 | + (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16, |
|---|
| 2550 | + (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8, |
|---|
| 2551 | + be32_to_cpu(halo_alg[i].alg.ver) & 0xff, |
|---|
| 2552 | + be32_to_cpu(halo_alg[i].xm_base), |
|---|
| 2553 | + be32_to_cpu(halo_alg[i].ym_base)); |
|---|
| 2554 | + |
|---|
| 2555 | + ret = wm_halo_create_regions(dsp, halo_alg[i].alg.id, |
|---|
| 2556 | + halo_alg[i].xm_base, |
|---|
| 2557 | + halo_alg[i].ym_base); |
|---|
| 2558 | + if (ret) |
|---|
| 2559 | + goto out; |
|---|
| 2560 | + } |
|---|
| 2561 | + |
|---|
| 2562 | +out: |
|---|
| 2563 | + kfree(halo_alg); |
|---|
| 2564 | + return ret; |
|---|
| 2565 | +} |
|---|
| 2566 | + |
|---|
| 2208 | 2567 | static int wm_adsp_load_coeff(struct wm_adsp *dsp) |
|---|
| 2209 | 2568 | { |
|---|
| 2210 | 2569 | LIST_HEAD(buf_list); |
|---|
| .. | .. |
|---|
| 2285 | 2644 | switch (type) { |
|---|
| 2286 | 2645 | case (WMFW_NAME_TEXT << 8): |
|---|
| 2287 | 2646 | case (WMFW_INFO_TEXT << 8): |
|---|
| 2647 | + case (WMFW_METADATA << 8): |
|---|
| 2288 | 2648 | break; |
|---|
| 2289 | 2649 | case (WMFW_ABSOLUTE << 8): |
|---|
| 2290 | 2650 | /* |
|---|
| .. | .. |
|---|
| 2299 | 2659 | adsp_err(dsp, "No ZM\n"); |
|---|
| 2300 | 2660 | break; |
|---|
| 2301 | 2661 | } |
|---|
| 2302 | | - reg = wm_adsp_region_to_reg(mem, 0); |
|---|
| 2662 | + reg = dsp->ops->region_to_reg(mem, 0); |
|---|
| 2303 | 2663 | |
|---|
| 2304 | 2664 | } else { |
|---|
| 2305 | 2665 | region_name = "register"; |
|---|
| .. | .. |
|---|
| 2311 | 2671 | case WMFW_ADSP1_ZM: |
|---|
| 2312 | 2672 | case WMFW_ADSP2_XM: |
|---|
| 2313 | 2673 | case WMFW_ADSP2_YM: |
|---|
| 2674 | + case WMFW_HALO_XM_PACKED: |
|---|
| 2675 | + case WMFW_HALO_YM_PACKED: |
|---|
| 2676 | + case WMFW_HALO_PM_PACKED: |
|---|
| 2314 | 2677 | adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", |
|---|
| 2315 | 2678 | file, blocks, le32_to_cpu(blk->len), |
|---|
| 2316 | 2679 | type, le32_to_cpu(blk->id)); |
|---|
| .. | .. |
|---|
| 2325 | 2688 | le32_to_cpu(blk->id)); |
|---|
| 2326 | 2689 | if (alg_region) { |
|---|
| 2327 | 2690 | reg = alg_region->base; |
|---|
| 2328 | | - reg = wm_adsp_region_to_reg(mem, reg); |
|---|
| 2691 | + reg = dsp->ops->region_to_reg(mem, reg); |
|---|
| 2329 | 2692 | reg += offset; |
|---|
| 2330 | 2693 | } else { |
|---|
| 2331 | 2694 | adsp_err(dsp, "No %x for algorithm %x\n", |
|---|
| .. | .. |
|---|
| 2419 | 2782 | return 0; |
|---|
| 2420 | 2783 | } |
|---|
| 2421 | 2784 | |
|---|
| 2422 | | -int wm_adsp1_init(struct wm_adsp *dsp) |
|---|
| 2785 | +static int wm_adsp_common_init(struct wm_adsp *dsp) |
|---|
| 2423 | 2786 | { |
|---|
| 2424 | 2787 | int ret; |
|---|
| 2425 | 2788 | |
|---|
| .. | .. |
|---|
| 2428 | 2791 | return ret; |
|---|
| 2429 | 2792 | |
|---|
| 2430 | 2793 | INIT_LIST_HEAD(&dsp->alg_regions); |
|---|
| 2794 | + INIT_LIST_HEAD(&dsp->ctl_list); |
|---|
| 2795 | + INIT_LIST_HEAD(&dsp->compr_list); |
|---|
| 2796 | + INIT_LIST_HEAD(&dsp->buffer_list); |
|---|
| 2431 | 2797 | |
|---|
| 2432 | 2798 | mutex_init(&dsp->pwr_lock); |
|---|
| 2433 | 2799 | |
|---|
| 2434 | 2800 | return 0; |
|---|
| 2801 | +} |
|---|
| 2802 | + |
|---|
| 2803 | +int wm_adsp1_init(struct wm_adsp *dsp) |
|---|
| 2804 | +{ |
|---|
| 2805 | + dsp->ops = &wm_adsp1_ops; |
|---|
| 2806 | + |
|---|
| 2807 | + return wm_adsp_common_init(dsp); |
|---|
| 2435 | 2808 | } |
|---|
| 2436 | 2809 | EXPORT_SYMBOL_GPL(wm_adsp1_init); |
|---|
| 2437 | 2810 | |
|---|
| .. | .. |
|---|
| 2550 | 2923 | } |
|---|
| 2551 | 2924 | EXPORT_SYMBOL_GPL(wm_adsp1_event); |
|---|
| 2552 | 2925 | |
|---|
| 2553 | | -static int wm_adsp2_ena(struct wm_adsp *dsp) |
|---|
| 2926 | +static int wm_adsp2v2_enable_core(struct wm_adsp *dsp) |
|---|
| 2554 | 2927 | { |
|---|
| 2555 | 2928 | unsigned int val; |
|---|
| 2556 | 2929 | int ret, count; |
|---|
| 2557 | | - |
|---|
| 2558 | | - switch (dsp->rev) { |
|---|
| 2559 | | - case 0: |
|---|
| 2560 | | - ret = regmap_update_bits_async(dsp->regmap, |
|---|
| 2561 | | - dsp->base + ADSP2_CONTROL, |
|---|
| 2562 | | - ADSP2_SYS_ENA, ADSP2_SYS_ENA); |
|---|
| 2563 | | - if (ret != 0) |
|---|
| 2564 | | - return ret; |
|---|
| 2565 | | - break; |
|---|
| 2566 | | - default: |
|---|
| 2567 | | - break; |
|---|
| 2568 | | - } |
|---|
| 2569 | 2930 | |
|---|
| 2570 | 2931 | /* Wait for the RAM to start, should be near instantaneous */ |
|---|
| 2571 | 2932 | for (count = 0; count < 10; ++count) { |
|---|
| .. | .. |
|---|
| 2589 | 2950 | return 0; |
|---|
| 2590 | 2951 | } |
|---|
| 2591 | 2952 | |
|---|
| 2592 | | -static void wm_adsp2_boot_work(struct work_struct *work) |
|---|
| 2953 | +static int wm_adsp2_enable_core(struct wm_adsp *dsp) |
|---|
| 2954 | +{ |
|---|
| 2955 | + int ret; |
|---|
| 2956 | + |
|---|
| 2957 | + ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL, |
|---|
| 2958 | + ADSP2_SYS_ENA, ADSP2_SYS_ENA); |
|---|
| 2959 | + if (ret != 0) |
|---|
| 2960 | + return ret; |
|---|
| 2961 | + |
|---|
| 2962 | + return wm_adsp2v2_enable_core(dsp); |
|---|
| 2963 | +} |
|---|
| 2964 | + |
|---|
| 2965 | +static int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions) |
|---|
| 2966 | +{ |
|---|
| 2967 | + struct regmap *regmap = dsp->regmap; |
|---|
| 2968 | + unsigned int code0, code1, lock_reg; |
|---|
| 2969 | + |
|---|
| 2970 | + if (!(lock_regions & WM_ADSP2_REGION_ALL)) |
|---|
| 2971 | + return 0; |
|---|
| 2972 | + |
|---|
| 2973 | + lock_regions &= WM_ADSP2_REGION_ALL; |
|---|
| 2974 | + lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0; |
|---|
| 2975 | + |
|---|
| 2976 | + while (lock_regions) { |
|---|
| 2977 | + code0 = code1 = 0; |
|---|
| 2978 | + if (lock_regions & BIT(0)) { |
|---|
| 2979 | + code0 = ADSP2_LOCK_CODE_0; |
|---|
| 2980 | + code1 = ADSP2_LOCK_CODE_1; |
|---|
| 2981 | + } |
|---|
| 2982 | + if (lock_regions & BIT(1)) { |
|---|
| 2983 | + code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT; |
|---|
| 2984 | + code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT; |
|---|
| 2985 | + } |
|---|
| 2986 | + regmap_write(regmap, lock_reg, code0); |
|---|
| 2987 | + regmap_write(regmap, lock_reg, code1); |
|---|
| 2988 | + lock_regions >>= 2; |
|---|
| 2989 | + lock_reg += 2; |
|---|
| 2990 | + } |
|---|
| 2991 | + |
|---|
| 2992 | + return 0; |
|---|
| 2993 | +} |
|---|
| 2994 | + |
|---|
| 2995 | +static int wm_adsp2_enable_memory(struct wm_adsp *dsp) |
|---|
| 2996 | +{ |
|---|
| 2997 | + return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
|---|
| 2998 | + ADSP2_MEM_ENA, ADSP2_MEM_ENA); |
|---|
| 2999 | +} |
|---|
| 3000 | + |
|---|
| 3001 | +static void wm_adsp2_disable_memory(struct wm_adsp *dsp) |
|---|
| 3002 | +{ |
|---|
| 3003 | + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
|---|
| 3004 | + ADSP2_MEM_ENA, 0); |
|---|
| 3005 | +} |
|---|
| 3006 | + |
|---|
| 3007 | +static void wm_adsp2_disable_core(struct wm_adsp *dsp) |
|---|
| 3008 | +{ |
|---|
| 3009 | + regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); |
|---|
| 3010 | + regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); |
|---|
| 3011 | + regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); |
|---|
| 3012 | + |
|---|
| 3013 | + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
|---|
| 3014 | + ADSP2_SYS_ENA, 0); |
|---|
| 3015 | +} |
|---|
| 3016 | + |
|---|
| 3017 | +static void wm_adsp2v2_disable_core(struct wm_adsp *dsp) |
|---|
| 3018 | +{ |
|---|
| 3019 | + regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); |
|---|
| 3020 | + regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); |
|---|
| 3021 | + regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0); |
|---|
| 3022 | +} |
|---|
| 3023 | + |
|---|
| 3024 | +static void wm_adsp_boot_work(struct work_struct *work) |
|---|
| 2593 | 3025 | { |
|---|
| 2594 | 3026 | struct wm_adsp *dsp = container_of(work, |
|---|
| 2595 | 3027 | struct wm_adsp, |
|---|
| .. | .. |
|---|
| 2598 | 3030 | |
|---|
| 2599 | 3031 | mutex_lock(&dsp->pwr_lock); |
|---|
| 2600 | 3032 | |
|---|
| 2601 | | - ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
|---|
| 2602 | | - ADSP2_MEM_ENA, ADSP2_MEM_ENA); |
|---|
| 2603 | | - if (ret != 0) |
|---|
| 2604 | | - goto err_mutex; |
|---|
| 3033 | + if (dsp->ops->enable_memory) { |
|---|
| 3034 | + ret = dsp->ops->enable_memory(dsp); |
|---|
| 3035 | + if (ret != 0) |
|---|
| 3036 | + goto err_mutex; |
|---|
| 3037 | + } |
|---|
| 2605 | 3038 | |
|---|
| 2606 | | - ret = wm_adsp2_ena(dsp); |
|---|
| 2607 | | - if (ret != 0) |
|---|
| 2608 | | - goto err_mem; |
|---|
| 3039 | + if (dsp->ops->enable_core) { |
|---|
| 3040 | + ret = dsp->ops->enable_core(dsp); |
|---|
| 3041 | + if (ret != 0) |
|---|
| 3042 | + goto err_mem; |
|---|
| 3043 | + } |
|---|
| 2609 | 3044 | |
|---|
| 2610 | 3045 | ret = wm_adsp_load(dsp); |
|---|
| 2611 | 3046 | if (ret != 0) |
|---|
| 2612 | 3047 | goto err_ena; |
|---|
| 2613 | 3048 | |
|---|
| 2614 | | - ret = wm_adsp2_setup_algs(dsp); |
|---|
| 3049 | + ret = dsp->ops->setup_algs(dsp); |
|---|
| 2615 | 3050 | if (ret != 0) |
|---|
| 2616 | 3051 | goto err_ena; |
|---|
| 2617 | 3052 | |
|---|
| .. | .. |
|---|
| 2624 | 3059 | if (ret != 0) |
|---|
| 2625 | 3060 | goto err_ena; |
|---|
| 2626 | 3061 | |
|---|
| 2627 | | - switch (dsp->rev) { |
|---|
| 2628 | | - case 0: |
|---|
| 2629 | | - /* Turn DSP back off until we are ready to run */ |
|---|
| 2630 | | - ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
|---|
| 2631 | | - ADSP2_SYS_ENA, 0); |
|---|
| 2632 | | - if (ret != 0) |
|---|
| 2633 | | - goto err_ena; |
|---|
| 2634 | | - break; |
|---|
| 2635 | | - default: |
|---|
| 2636 | | - break; |
|---|
| 2637 | | - } |
|---|
| 3062 | + if (dsp->ops->disable_core) |
|---|
| 3063 | + dsp->ops->disable_core(dsp); |
|---|
| 2638 | 3064 | |
|---|
| 2639 | 3065 | dsp->booted = true; |
|---|
| 2640 | 3066 | |
|---|
| .. | .. |
|---|
| 2643 | 3069 | return; |
|---|
| 2644 | 3070 | |
|---|
| 2645 | 3071 | err_ena: |
|---|
| 2646 | | - regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
|---|
| 2647 | | - ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); |
|---|
| 3072 | + if (dsp->ops->disable_core) |
|---|
| 3073 | + dsp->ops->disable_core(dsp); |
|---|
| 2648 | 3074 | err_mem: |
|---|
| 2649 | | - regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
|---|
| 2650 | | - ADSP2_MEM_ENA, 0); |
|---|
| 3075 | + if (dsp->ops->disable_memory) |
|---|
| 3076 | + dsp->ops->disable_memory(dsp); |
|---|
| 2651 | 3077 | err_mutex: |
|---|
| 2652 | 3078 | mutex_unlock(&dsp->pwr_lock); |
|---|
| 2653 | 3079 | } |
|---|
| 2654 | 3080 | |
|---|
| 2655 | | -static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq) |
|---|
| 3081 | +static int wm_halo_configure_mpu(struct wm_adsp *dsp, unsigned int lock_regions) |
|---|
| 2656 | 3082 | { |
|---|
| 3083 | + struct reg_sequence config[] = { |
|---|
| 3084 | + { dsp->base + HALO_MPU_LOCK_CONFIG, 0x5555 }, |
|---|
| 3085 | + { dsp->base + HALO_MPU_LOCK_CONFIG, 0xAAAA }, |
|---|
| 3086 | + { dsp->base + HALO_MPU_XMEM_ACCESS_0, 0xFFFFFFFF }, |
|---|
| 3087 | + { dsp->base + HALO_MPU_YMEM_ACCESS_0, 0xFFFFFFFF }, |
|---|
| 3088 | + { dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions }, |
|---|
| 3089 | + { dsp->base + HALO_MPU_XREG_ACCESS_0, lock_regions }, |
|---|
| 3090 | + { dsp->base + HALO_MPU_YREG_ACCESS_0, lock_regions }, |
|---|
| 3091 | + { dsp->base + HALO_MPU_XMEM_ACCESS_1, 0xFFFFFFFF }, |
|---|
| 3092 | + { dsp->base + HALO_MPU_YMEM_ACCESS_1, 0xFFFFFFFF }, |
|---|
| 3093 | + { dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions }, |
|---|
| 3094 | + { dsp->base + HALO_MPU_XREG_ACCESS_1, lock_regions }, |
|---|
| 3095 | + { dsp->base + HALO_MPU_YREG_ACCESS_1, lock_regions }, |
|---|
| 3096 | + { dsp->base + HALO_MPU_XMEM_ACCESS_2, 0xFFFFFFFF }, |
|---|
| 3097 | + { dsp->base + HALO_MPU_YMEM_ACCESS_2, 0xFFFFFFFF }, |
|---|
| 3098 | + { dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions }, |
|---|
| 3099 | + { dsp->base + HALO_MPU_XREG_ACCESS_2, lock_regions }, |
|---|
| 3100 | + { dsp->base + HALO_MPU_YREG_ACCESS_2, lock_regions }, |
|---|
| 3101 | + { dsp->base + HALO_MPU_XMEM_ACCESS_3, 0xFFFFFFFF }, |
|---|
| 3102 | + { dsp->base + HALO_MPU_YMEM_ACCESS_3, 0xFFFFFFFF }, |
|---|
| 3103 | + { dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions }, |
|---|
| 3104 | + { dsp->base + HALO_MPU_XREG_ACCESS_3, lock_regions }, |
|---|
| 3105 | + { dsp->base + HALO_MPU_YREG_ACCESS_3, lock_regions }, |
|---|
| 3106 | + { dsp->base + HALO_MPU_LOCK_CONFIG, 0 }, |
|---|
| 3107 | + }; |
|---|
| 3108 | + |
|---|
| 3109 | + return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config)); |
|---|
| 3110 | +} |
|---|
| 3111 | + |
|---|
| 3112 | +int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq) |
|---|
| 3113 | +{ |
|---|
| 3114 | + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); |
|---|
| 3115 | + struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); |
|---|
| 3116 | + struct wm_adsp *dsp = &dsps[w->shift]; |
|---|
| 2657 | 3117 | int ret; |
|---|
| 2658 | 3118 | |
|---|
| 2659 | | - switch (dsp->rev) { |
|---|
| 2660 | | - case 0: |
|---|
| 2661 | | - ret = regmap_update_bits_async(dsp->regmap, |
|---|
| 2662 | | - dsp->base + ADSP2_CLOCKING, |
|---|
| 2663 | | - ADSP2_CLK_SEL_MASK, |
|---|
| 2664 | | - freq << ADSP2_CLK_SEL_SHIFT); |
|---|
| 2665 | | - if (ret) { |
|---|
| 2666 | | - adsp_err(dsp, "Failed to set clock rate: %d\n", ret); |
|---|
| 2667 | | - return; |
|---|
| 2668 | | - } |
|---|
| 2669 | | - break; |
|---|
| 2670 | | - default: |
|---|
| 2671 | | - /* clock is handled by parent codec driver */ |
|---|
| 2672 | | - break; |
|---|
| 2673 | | - } |
|---|
| 3119 | + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING, |
|---|
| 3120 | + ADSP2_CLK_SEL_MASK, |
|---|
| 3121 | + freq << ADSP2_CLK_SEL_SHIFT); |
|---|
| 3122 | + if (ret) |
|---|
| 3123 | + adsp_err(dsp, "Failed to set clock rate: %d\n", ret); |
|---|
| 3124 | + |
|---|
| 3125 | + return ret; |
|---|
| 2674 | 3126 | } |
|---|
| 3127 | +EXPORT_SYMBOL_GPL(wm_adsp2_set_dspclk); |
|---|
| 2675 | 3128 | |
|---|
| 2676 | 3129 | int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol, |
|---|
| 2677 | 3130 | struct snd_ctl_elem_value *ucontrol) |
|---|
| .. | .. |
|---|
| 2718 | 3171 | |
|---|
| 2719 | 3172 | static void wm_adsp_stop_watchdog(struct wm_adsp *dsp) |
|---|
| 2720 | 3173 | { |
|---|
| 2721 | | - switch (dsp->rev) { |
|---|
| 2722 | | - case 0: |
|---|
| 2723 | | - case 1: |
|---|
| 2724 | | - return; |
|---|
| 2725 | | - default: |
|---|
| 2726 | | - regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG, |
|---|
| 2727 | | - ADSP2_WDT_ENA_MASK, 0); |
|---|
| 2728 | | - } |
|---|
| 3174 | + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG, |
|---|
| 3175 | + ADSP2_WDT_ENA_MASK, 0); |
|---|
| 2729 | 3176 | } |
|---|
| 2730 | 3177 | |
|---|
| 2731 | | -int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, |
|---|
| 2732 | | - struct snd_kcontrol *kcontrol, int event, |
|---|
| 2733 | | - unsigned int freq) |
|---|
| 3178 | +static void wm_halo_stop_watchdog(struct wm_adsp *dsp) |
|---|
| 3179 | +{ |
|---|
| 3180 | + regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL, |
|---|
| 3181 | + HALO_WDT_EN_MASK, 0); |
|---|
| 3182 | +} |
|---|
| 3183 | + |
|---|
| 3184 | +int wm_adsp_early_event(struct snd_soc_dapm_widget *w, |
|---|
| 3185 | + struct snd_kcontrol *kcontrol, int event) |
|---|
| 2734 | 3186 | { |
|---|
| 2735 | 3187 | struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); |
|---|
| 2736 | 3188 | struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); |
|---|
| .. | .. |
|---|
| 2739 | 3191 | |
|---|
| 2740 | 3192 | switch (event) { |
|---|
| 2741 | 3193 | case SND_SOC_DAPM_PRE_PMU: |
|---|
| 2742 | | - wm_adsp2_set_dspclk(dsp, freq); |
|---|
| 2743 | 3194 | queue_work(system_unbound_wq, &dsp->boot_work); |
|---|
| 2744 | 3195 | break; |
|---|
| 2745 | 3196 | case SND_SOC_DAPM_PRE_PMD: |
|---|
| .. | .. |
|---|
| 2752 | 3203 | |
|---|
| 2753 | 3204 | dsp->booted = false; |
|---|
| 2754 | 3205 | |
|---|
| 2755 | | - regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
|---|
| 2756 | | - ADSP2_MEM_ENA, 0); |
|---|
| 3206 | + if (dsp->ops->disable_memory) |
|---|
| 3207 | + dsp->ops->disable_memory(dsp); |
|---|
| 2757 | 3208 | |
|---|
| 2758 | 3209 | list_for_each_entry(ctl, &dsp->ctl_list, list) |
|---|
| 2759 | 3210 | ctl->enabled = 0; |
|---|
| .. | .. |
|---|
| 2770 | 3221 | |
|---|
| 2771 | 3222 | return 0; |
|---|
| 2772 | 3223 | } |
|---|
| 2773 | | -EXPORT_SYMBOL_GPL(wm_adsp2_early_event); |
|---|
| 3224 | +EXPORT_SYMBOL_GPL(wm_adsp_early_event); |
|---|
| 2774 | 3225 | |
|---|
| 2775 | | -int wm_adsp2_event(struct snd_soc_dapm_widget *w, |
|---|
| 2776 | | - struct snd_kcontrol *kcontrol, int event) |
|---|
| 3226 | +static int wm_adsp2_start_core(struct wm_adsp *dsp) |
|---|
| 3227 | +{ |
|---|
| 3228 | + return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
|---|
| 3229 | + ADSP2_CORE_ENA | ADSP2_START, |
|---|
| 3230 | + ADSP2_CORE_ENA | ADSP2_START); |
|---|
| 3231 | +} |
|---|
| 3232 | + |
|---|
| 3233 | +static void wm_adsp2_stop_core(struct wm_adsp *dsp) |
|---|
| 3234 | +{ |
|---|
| 3235 | + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
|---|
| 3236 | + ADSP2_CORE_ENA | ADSP2_START, 0); |
|---|
| 3237 | +} |
|---|
| 3238 | + |
|---|
| 3239 | +int wm_adsp_event(struct snd_soc_dapm_widget *w, |
|---|
| 3240 | + struct snd_kcontrol *kcontrol, int event) |
|---|
| 2777 | 3241 | { |
|---|
| 2778 | 3242 | struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); |
|---|
| 2779 | 3243 | struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); |
|---|
| .. | .. |
|---|
| 2791 | 3255 | goto err; |
|---|
| 2792 | 3256 | } |
|---|
| 2793 | 3257 | |
|---|
| 2794 | | - ret = wm_adsp2_ena(dsp); |
|---|
| 2795 | | - if (ret != 0) |
|---|
| 2796 | | - goto err; |
|---|
| 3258 | + if (dsp->ops->enable_core) { |
|---|
| 3259 | + ret = dsp->ops->enable_core(dsp); |
|---|
| 3260 | + if (ret != 0) |
|---|
| 3261 | + goto err; |
|---|
| 3262 | + } |
|---|
| 2797 | 3263 | |
|---|
| 2798 | 3264 | /* Sync set controls */ |
|---|
| 2799 | 3265 | ret = wm_coeff_sync_controls(dsp); |
|---|
| 2800 | 3266 | if (ret != 0) |
|---|
| 2801 | 3267 | goto err; |
|---|
| 2802 | 3268 | |
|---|
| 2803 | | - wm_adsp2_lock(dsp, dsp->lock_regions); |
|---|
| 3269 | + if (dsp->ops->lock_memory) { |
|---|
| 3270 | + ret = dsp->ops->lock_memory(dsp, dsp->lock_regions); |
|---|
| 3271 | + if (ret != 0) { |
|---|
| 3272 | + adsp_err(dsp, "Error configuring MPU: %d\n", |
|---|
| 3273 | + ret); |
|---|
| 3274 | + goto err; |
|---|
| 3275 | + } |
|---|
| 3276 | + } |
|---|
| 2804 | 3277 | |
|---|
| 2805 | | - ret = regmap_update_bits(dsp->regmap, |
|---|
| 2806 | | - dsp->base + ADSP2_CONTROL, |
|---|
| 2807 | | - ADSP2_CORE_ENA | ADSP2_START, |
|---|
| 2808 | | - ADSP2_CORE_ENA | ADSP2_START); |
|---|
| 2809 | | - if (ret != 0) |
|---|
| 2810 | | - goto err; |
|---|
| 3278 | + if (dsp->ops->start_core) { |
|---|
| 3279 | + ret = dsp->ops->start_core(dsp); |
|---|
| 3280 | + if (ret != 0) |
|---|
| 3281 | + goto err; |
|---|
| 3282 | + } |
|---|
| 2811 | 3283 | |
|---|
| 2812 | 3284 | if (wm_adsp_fw[dsp->fw].num_caps != 0) { |
|---|
| 2813 | 3285 | ret = wm_adsp_buffer_init(dsp); |
|---|
| .. | .. |
|---|
| 2818 | 3290 | dsp->running = true; |
|---|
| 2819 | 3291 | |
|---|
| 2820 | 3292 | mutex_unlock(&dsp->pwr_lock); |
|---|
| 2821 | | - |
|---|
| 2822 | 3293 | break; |
|---|
| 2823 | 3294 | |
|---|
| 2824 | 3295 | case SND_SOC_DAPM_PRE_PMD: |
|---|
| 2825 | 3296 | /* Tell the firmware to cleanup */ |
|---|
| 2826 | 3297 | wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN); |
|---|
| 2827 | 3298 | |
|---|
| 2828 | | - wm_adsp_stop_watchdog(dsp); |
|---|
| 3299 | + if (dsp->ops->stop_watchdog) |
|---|
| 3300 | + dsp->ops->stop_watchdog(dsp); |
|---|
| 2829 | 3301 | |
|---|
| 2830 | 3302 | /* Log firmware state, it can be useful for analysis */ |
|---|
| 2831 | | - switch (dsp->rev) { |
|---|
| 2832 | | - case 0: |
|---|
| 2833 | | - wm_adsp2_show_fw_status(dsp); |
|---|
| 2834 | | - break; |
|---|
| 2835 | | - default: |
|---|
| 2836 | | - wm_adsp2v2_show_fw_status(dsp); |
|---|
| 2837 | | - break; |
|---|
| 2838 | | - } |
|---|
| 3303 | + if (dsp->ops->show_fw_status) |
|---|
| 3304 | + dsp->ops->show_fw_status(dsp); |
|---|
| 2839 | 3305 | |
|---|
| 2840 | 3306 | mutex_lock(&dsp->pwr_lock); |
|---|
| 2841 | 3307 | |
|---|
| 2842 | 3308 | dsp->running = false; |
|---|
| 2843 | 3309 | |
|---|
| 2844 | | - regmap_update_bits(dsp->regmap, |
|---|
| 2845 | | - dsp->base + ADSP2_CONTROL, |
|---|
| 2846 | | - ADSP2_CORE_ENA | ADSP2_START, 0); |
|---|
| 2847 | | - |
|---|
| 2848 | | - /* Make sure DMAs are quiesced */ |
|---|
| 2849 | | - switch (dsp->rev) { |
|---|
| 2850 | | - case 0: |
|---|
| 2851 | | - regmap_write(dsp->regmap, |
|---|
| 2852 | | - dsp->base + ADSP2_RDMA_CONFIG_1, 0); |
|---|
| 2853 | | - regmap_write(dsp->regmap, |
|---|
| 2854 | | - dsp->base + ADSP2_WDMA_CONFIG_1, 0); |
|---|
| 2855 | | - regmap_write(dsp->regmap, |
|---|
| 2856 | | - dsp->base + ADSP2_WDMA_CONFIG_2, 0); |
|---|
| 2857 | | - |
|---|
| 2858 | | - regmap_update_bits(dsp->regmap, |
|---|
| 2859 | | - dsp->base + ADSP2_CONTROL, |
|---|
| 2860 | | - ADSP2_SYS_ENA, 0); |
|---|
| 2861 | | - break; |
|---|
| 2862 | | - default: |
|---|
| 2863 | | - regmap_write(dsp->regmap, |
|---|
| 2864 | | - dsp->base + ADSP2_RDMA_CONFIG_1, 0); |
|---|
| 2865 | | - regmap_write(dsp->regmap, |
|---|
| 2866 | | - dsp->base + ADSP2_WDMA_CONFIG_1, 0); |
|---|
| 2867 | | - regmap_write(dsp->regmap, |
|---|
| 2868 | | - dsp->base + ADSP2V2_WDMA_CONFIG_2, 0); |
|---|
| 2869 | | - break; |
|---|
| 2870 | | - } |
|---|
| 3310 | + if (dsp->ops->stop_core) |
|---|
| 3311 | + dsp->ops->stop_core(dsp); |
|---|
| 3312 | + if (dsp->ops->disable_core) |
|---|
| 3313 | + dsp->ops->disable_core(dsp); |
|---|
| 2871 | 3314 | |
|---|
| 2872 | 3315 | if (wm_adsp_fw[dsp->fw].num_caps != 0) |
|---|
| 2873 | 3316 | wm_adsp_buffer_free(dsp); |
|---|
| 3317 | + |
|---|
| 3318 | + dsp->fatal_error = false; |
|---|
| 2874 | 3319 | |
|---|
| 2875 | 3320 | mutex_unlock(&dsp->pwr_lock); |
|---|
| 2876 | 3321 | |
|---|
| .. | .. |
|---|
| 2883 | 3328 | |
|---|
| 2884 | 3329 | return 0; |
|---|
| 2885 | 3330 | err: |
|---|
| 2886 | | - regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
|---|
| 2887 | | - ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); |
|---|
| 3331 | + if (dsp->ops->stop_core) |
|---|
| 3332 | + dsp->ops->stop_core(dsp); |
|---|
| 3333 | + if (dsp->ops->disable_core) |
|---|
| 3334 | + dsp->ops->disable_core(dsp); |
|---|
| 2888 | 3335 | mutex_unlock(&dsp->pwr_lock); |
|---|
| 2889 | 3336 | return ret; |
|---|
| 2890 | 3337 | } |
|---|
| 2891 | | -EXPORT_SYMBOL_GPL(wm_adsp2_event); |
|---|
| 3338 | +EXPORT_SYMBOL_GPL(wm_adsp_event); |
|---|
| 3339 | + |
|---|
| 3340 | +static int wm_halo_start_core(struct wm_adsp *dsp) |
|---|
| 3341 | +{ |
|---|
| 3342 | + return regmap_update_bits(dsp->regmap, |
|---|
| 3343 | + dsp->base + HALO_CCM_CORE_CONTROL, |
|---|
| 3344 | + HALO_CORE_EN, HALO_CORE_EN); |
|---|
| 3345 | +} |
|---|
| 3346 | + |
|---|
| 3347 | +static void wm_halo_stop_core(struct wm_adsp *dsp) |
|---|
| 3348 | +{ |
|---|
| 3349 | + regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, |
|---|
| 3350 | + HALO_CORE_EN, 0); |
|---|
| 3351 | + |
|---|
| 3352 | + /* reset halo core with CORE_SOFT_RESET */ |
|---|
| 3353 | + regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET, |
|---|
| 3354 | + HALO_CORE_SOFT_RESET_MASK, 1); |
|---|
| 3355 | +} |
|---|
| 2892 | 3356 | |
|---|
| 2893 | 3357 | int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component) |
|---|
| 2894 | 3358 | { |
|---|
| .. | .. |
|---|
| 2917 | 3381 | { |
|---|
| 2918 | 3382 | int ret; |
|---|
| 2919 | 3383 | |
|---|
| 2920 | | - ret = wm_adsp_create_name(dsp); |
|---|
| 3384 | + ret = wm_adsp_common_init(dsp); |
|---|
| 2921 | 3385 | if (ret) |
|---|
| 2922 | 3386 | return ret; |
|---|
| 2923 | 3387 | |
|---|
| .. | .. |
|---|
| 2934 | 3398 | "Failed to clear memory retention: %d\n", ret); |
|---|
| 2935 | 3399 | return ret; |
|---|
| 2936 | 3400 | } |
|---|
| 3401 | + |
|---|
| 3402 | + dsp->ops = &wm_adsp2_ops[0]; |
|---|
| 3403 | + break; |
|---|
| 3404 | + case 1: |
|---|
| 3405 | + dsp->ops = &wm_adsp2_ops[1]; |
|---|
| 2937 | 3406 | break; |
|---|
| 2938 | 3407 | default: |
|---|
| 3408 | + dsp->ops = &wm_adsp2_ops[2]; |
|---|
| 2939 | 3409 | break; |
|---|
| 2940 | 3410 | } |
|---|
| 2941 | 3411 | |
|---|
| 2942 | | - INIT_LIST_HEAD(&dsp->alg_regions); |
|---|
| 2943 | | - INIT_LIST_HEAD(&dsp->ctl_list); |
|---|
| 2944 | | - INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work); |
|---|
| 2945 | | - |
|---|
| 2946 | | - mutex_init(&dsp->pwr_lock); |
|---|
| 3412 | + INIT_WORK(&dsp->boot_work, wm_adsp_boot_work); |
|---|
| 2947 | 3413 | |
|---|
| 2948 | 3414 | return 0; |
|---|
| 2949 | 3415 | } |
|---|
| 2950 | 3416 | EXPORT_SYMBOL_GPL(wm_adsp2_init); |
|---|
| 3417 | + |
|---|
| 3418 | +int wm_halo_init(struct wm_adsp *dsp) |
|---|
| 3419 | +{ |
|---|
| 3420 | + int ret; |
|---|
| 3421 | + |
|---|
| 3422 | + ret = wm_adsp_common_init(dsp); |
|---|
| 3423 | + if (ret) |
|---|
| 3424 | + return ret; |
|---|
| 3425 | + |
|---|
| 3426 | + dsp->ops = &wm_halo_ops; |
|---|
| 3427 | + |
|---|
| 3428 | + INIT_WORK(&dsp->boot_work, wm_adsp_boot_work); |
|---|
| 3429 | + |
|---|
| 3430 | + return 0; |
|---|
| 3431 | +} |
|---|
| 3432 | +EXPORT_SYMBOL_GPL(wm_halo_init); |
|---|
| 2951 | 3433 | |
|---|
| 2952 | 3434 | void wm_adsp2_remove(struct wm_adsp *dsp) |
|---|
| 2953 | 3435 | { |
|---|
| .. | .. |
|---|
| 2969 | 3451 | |
|---|
| 2970 | 3452 | static int wm_adsp_compr_attach(struct wm_adsp_compr *compr) |
|---|
| 2971 | 3453 | { |
|---|
| 2972 | | - /* |
|---|
| 2973 | | - * Note this will be more complex once each DSP can support multiple |
|---|
| 2974 | | - * streams |
|---|
| 2975 | | - */ |
|---|
| 2976 | | - if (!compr->dsp->buffer) |
|---|
| 3454 | + struct wm_adsp_compr_buf *buf = NULL, *tmp; |
|---|
| 3455 | + |
|---|
| 3456 | + if (compr->dsp->fatal_error) |
|---|
| 2977 | 3457 | return -EINVAL; |
|---|
| 2978 | 3458 | |
|---|
| 2979 | | - compr->buf = compr->dsp->buffer; |
|---|
| 2980 | | - compr->buf->compr = compr; |
|---|
| 3459 | + list_for_each_entry(tmp, &compr->dsp->buffer_list, list) { |
|---|
| 3460 | + if (!tmp->name || !strcmp(compr->name, tmp->name)) { |
|---|
| 3461 | + buf = tmp; |
|---|
| 3462 | + break; |
|---|
| 3463 | + } |
|---|
| 3464 | + } |
|---|
| 3465 | + |
|---|
| 3466 | + if (!buf) |
|---|
| 3467 | + return -EINVAL; |
|---|
| 3468 | + |
|---|
| 3469 | + compr->buf = buf; |
|---|
| 3470 | + buf->compr = compr; |
|---|
| 2981 | 3471 | |
|---|
| 2982 | 3472 | return 0; |
|---|
| 2983 | 3473 | } |
|---|
| .. | .. |
|---|
| 2999 | 3489 | |
|---|
| 3000 | 3490 | int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) |
|---|
| 3001 | 3491 | { |
|---|
| 3002 | | - struct wm_adsp_compr *compr; |
|---|
| 3492 | + struct wm_adsp_compr *compr, *tmp; |
|---|
| 3493 | + struct snd_soc_pcm_runtime *rtd = stream->private_data; |
|---|
| 3003 | 3494 | int ret = 0; |
|---|
| 3004 | 3495 | |
|---|
| 3005 | 3496 | mutex_lock(&dsp->pwr_lock); |
|---|
| 3006 | 3497 | |
|---|
| 3007 | 3498 | if (wm_adsp_fw[dsp->fw].num_caps == 0) { |
|---|
| 3008 | | - adsp_err(dsp, "Firmware does not support compressed API\n"); |
|---|
| 3499 | + adsp_err(dsp, "%s: Firmware does not support compressed API\n", |
|---|
| 3500 | + asoc_rtd_to_codec(rtd, 0)->name); |
|---|
| 3009 | 3501 | ret = -ENXIO; |
|---|
| 3010 | 3502 | goto out; |
|---|
| 3011 | 3503 | } |
|---|
| 3012 | 3504 | |
|---|
| 3013 | 3505 | if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) { |
|---|
| 3014 | | - adsp_err(dsp, "Firmware does not support stream direction\n"); |
|---|
| 3506 | + adsp_err(dsp, "%s: Firmware does not support stream direction\n", |
|---|
| 3507 | + asoc_rtd_to_codec(rtd, 0)->name); |
|---|
| 3015 | 3508 | ret = -EINVAL; |
|---|
| 3016 | 3509 | goto out; |
|---|
| 3017 | 3510 | } |
|---|
| 3018 | 3511 | |
|---|
| 3019 | | - if (dsp->compr) { |
|---|
| 3020 | | - /* It is expect this limitation will be removed in future */ |
|---|
| 3021 | | - adsp_err(dsp, "Only a single stream supported per DSP\n"); |
|---|
| 3022 | | - ret = -EBUSY; |
|---|
| 3023 | | - goto out; |
|---|
| 3512 | + list_for_each_entry(tmp, &dsp->compr_list, list) { |
|---|
| 3513 | + if (!strcmp(tmp->name, asoc_rtd_to_codec(rtd, 0)->name)) { |
|---|
| 3514 | + adsp_err(dsp, "%s: Only a single stream supported per dai\n", |
|---|
| 3515 | + asoc_rtd_to_codec(rtd, 0)->name); |
|---|
| 3516 | + ret = -EBUSY; |
|---|
| 3517 | + goto out; |
|---|
| 3518 | + } |
|---|
| 3024 | 3519 | } |
|---|
| 3025 | 3520 | |
|---|
| 3026 | 3521 | compr = kzalloc(sizeof(*compr), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 3031 | 3526 | |
|---|
| 3032 | 3527 | compr->dsp = dsp; |
|---|
| 3033 | 3528 | compr->stream = stream; |
|---|
| 3529 | + compr->name = asoc_rtd_to_codec(rtd, 0)->name; |
|---|
| 3034 | 3530 | |
|---|
| 3035 | | - dsp->compr = compr; |
|---|
| 3531 | + list_add_tail(&compr->list, &dsp->compr_list); |
|---|
| 3036 | 3532 | |
|---|
| 3037 | 3533 | stream->runtime->private_data = compr; |
|---|
| 3038 | 3534 | |
|---|
| .. | .. |
|---|
| 3043 | 3539 | } |
|---|
| 3044 | 3540 | EXPORT_SYMBOL_GPL(wm_adsp_compr_open); |
|---|
| 3045 | 3541 | |
|---|
| 3046 | | -int wm_adsp_compr_free(struct snd_compr_stream *stream) |
|---|
| 3542 | +int wm_adsp_compr_free(struct snd_soc_component *component, |
|---|
| 3543 | + struct snd_compr_stream *stream) |
|---|
| 3047 | 3544 | { |
|---|
| 3048 | 3545 | struct wm_adsp_compr *compr = stream->runtime->private_data; |
|---|
| 3049 | 3546 | struct wm_adsp *dsp = compr->dsp; |
|---|
| .. | .. |
|---|
| 3051 | 3548 | mutex_lock(&dsp->pwr_lock); |
|---|
| 3052 | 3549 | |
|---|
| 3053 | 3550 | wm_adsp_compr_detach(compr); |
|---|
| 3054 | | - dsp->compr = NULL; |
|---|
| 3551 | + list_del(&compr->list); |
|---|
| 3055 | 3552 | |
|---|
| 3056 | 3553 | kfree(compr->raw_buf); |
|---|
| 3057 | 3554 | kfree(compr); |
|---|
| .. | .. |
|---|
| 3076 | 3573 | params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS || |
|---|
| 3077 | 3574 | params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS || |
|---|
| 3078 | 3575 | params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) { |
|---|
| 3079 | | - adsp_err(dsp, "Invalid buffer fragsize=%d fragments=%d\n", |
|---|
| 3080 | | - params->buffer.fragment_size, |
|---|
| 3081 | | - params->buffer.fragments); |
|---|
| 3576 | + compr_err(compr, "Invalid buffer fragsize=%d fragments=%d\n", |
|---|
| 3577 | + params->buffer.fragment_size, |
|---|
| 3578 | + params->buffer.fragments); |
|---|
| 3082 | 3579 | |
|---|
| 3083 | 3580 | return -EINVAL; |
|---|
| 3084 | 3581 | } |
|---|
| .. | .. |
|---|
| 3106 | 3603 | return 0; |
|---|
| 3107 | 3604 | } |
|---|
| 3108 | 3605 | |
|---|
| 3109 | | - adsp_err(dsp, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n", |
|---|
| 3110 | | - params->codec.id, params->codec.ch_in, params->codec.ch_out, |
|---|
| 3111 | | - params->codec.sample_rate, params->codec.format); |
|---|
| 3606 | + compr_err(compr, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n", |
|---|
| 3607 | + params->codec.id, params->codec.ch_in, params->codec.ch_out, |
|---|
| 3608 | + params->codec.sample_rate, params->codec.format); |
|---|
| 3112 | 3609 | return -EINVAL; |
|---|
| 3113 | 3610 | } |
|---|
| 3114 | 3611 | |
|---|
| .. | .. |
|---|
| 3117 | 3614 | return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE; |
|---|
| 3118 | 3615 | } |
|---|
| 3119 | 3616 | |
|---|
| 3120 | | -int wm_adsp_compr_set_params(struct snd_compr_stream *stream, |
|---|
| 3617 | +int wm_adsp_compr_set_params(struct snd_soc_component *component, |
|---|
| 3618 | + struct snd_compr_stream *stream, |
|---|
| 3121 | 3619 | struct snd_compr_params *params) |
|---|
| 3122 | 3620 | { |
|---|
| 3123 | 3621 | struct wm_adsp_compr *compr = stream->runtime->private_data; |
|---|
| .. | .. |
|---|
| 3130 | 3628 | |
|---|
| 3131 | 3629 | compr->size = params->buffer; |
|---|
| 3132 | 3630 | |
|---|
| 3133 | | - adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n", |
|---|
| 3134 | | - compr->size.fragment_size, compr->size.fragments); |
|---|
| 3631 | + compr_dbg(compr, "fragment_size=%d fragments=%d\n", |
|---|
| 3632 | + compr->size.fragment_size, compr->size.fragments); |
|---|
| 3135 | 3633 | |
|---|
| 3136 | 3634 | size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf); |
|---|
| 3137 | 3635 | compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 3144 | 3642 | } |
|---|
| 3145 | 3643 | EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params); |
|---|
| 3146 | 3644 | |
|---|
| 3147 | | -int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, |
|---|
| 3645 | +int wm_adsp_compr_get_caps(struct snd_soc_component *component, |
|---|
| 3646 | + struct snd_compr_stream *stream, |
|---|
| 3148 | 3647 | struct snd_compr_caps *caps) |
|---|
| 3149 | 3648 | { |
|---|
| 3150 | 3649 | struct wm_adsp_compr *compr = stream->runtime->private_data; |
|---|
| .. | .. |
|---|
| 3179 | 3678 | if (!mem) |
|---|
| 3180 | 3679 | return -EINVAL; |
|---|
| 3181 | 3680 | |
|---|
| 3182 | | - reg = wm_adsp_region_to_reg(mem, mem_addr); |
|---|
| 3681 | + reg = dsp->ops->region_to_reg(mem, mem_addr); |
|---|
| 3183 | 3682 | |
|---|
| 3184 | 3683 | ret = regmap_raw_read(dsp->regmap, reg, data, |
|---|
| 3185 | 3684 | sizeof(*data) * num_words); |
|---|
| .. | .. |
|---|
| 3207 | 3706 | if (!mem) |
|---|
| 3208 | 3707 | return -EINVAL; |
|---|
| 3209 | 3708 | |
|---|
| 3210 | | - reg = wm_adsp_region_to_reg(mem, mem_addr); |
|---|
| 3709 | + reg = dsp->ops->region_to_reg(mem, mem_addr); |
|---|
| 3211 | 3710 | |
|---|
| 3212 | 3711 | data = cpu_to_be32(data & 0x00ffffffu); |
|---|
| 3213 | 3712 | |
|---|
| .. | .. |
|---|
| 3217 | 3716 | static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf, |
|---|
| 3218 | 3717 | unsigned int field_offset, u32 *data) |
|---|
| 3219 | 3718 | { |
|---|
| 3220 | | - return wm_adsp_read_data_word(buf->dsp, WMFW_ADSP2_XM, |
|---|
| 3719 | + return wm_adsp_read_data_word(buf->dsp, buf->host_buf_mem_type, |
|---|
| 3221 | 3720 | buf->host_buf_ptr + field_offset, data); |
|---|
| 3222 | 3721 | } |
|---|
| 3223 | 3722 | |
|---|
| 3224 | 3723 | static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf, |
|---|
| 3225 | 3724 | unsigned int field_offset, u32 data) |
|---|
| 3226 | 3725 | { |
|---|
| 3227 | | - return wm_adsp_write_data_word(buf->dsp, WMFW_ADSP2_XM, |
|---|
| 3726 | + return wm_adsp_write_data_word(buf->dsp, buf->host_buf_mem_type, |
|---|
| 3228 | 3727 | buf->host_buf_ptr + field_offset, data); |
|---|
| 3229 | 3728 | } |
|---|
| 3230 | 3729 | |
|---|
| 3231 | | -static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf) |
|---|
| 3730 | +static void wm_adsp_remove_padding(u32 *buf, int nwords, int data_word_size) |
|---|
| 3232 | 3731 | { |
|---|
| 3233 | | - struct wm_adsp_alg_region *alg_region; |
|---|
| 3234 | | - struct wm_adsp *dsp = buf->dsp; |
|---|
| 3235 | | - u32 xmalg, addr, magic; |
|---|
| 3236 | | - int i, ret; |
|---|
| 3732 | + u8 *pack_in = (u8 *)buf; |
|---|
| 3733 | + u8 *pack_out = (u8 *)buf; |
|---|
| 3734 | + int i, j; |
|---|
| 3237 | 3735 | |
|---|
| 3238 | | - alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id); |
|---|
| 3239 | | - xmalg = sizeof(struct wm_adsp_system_config_xm_hdr) / sizeof(__be32); |
|---|
| 3736 | + /* Remove the padding bytes from the data read from the DSP */ |
|---|
| 3737 | + for (i = 0; i < nwords; i++) { |
|---|
| 3738 | + for (j = 0; j < data_word_size; j++) |
|---|
| 3739 | + *pack_out++ = *pack_in++; |
|---|
| 3240 | 3740 | |
|---|
| 3241 | | - addr = alg_region->base + xmalg + ALG_XM_FIELD(magic); |
|---|
| 3242 | | - ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic); |
|---|
| 3243 | | - if (ret < 0) |
|---|
| 3244 | | - return ret; |
|---|
| 3245 | | - |
|---|
| 3246 | | - if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC) |
|---|
| 3247 | | - return -EINVAL; |
|---|
| 3248 | | - |
|---|
| 3249 | | - addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr); |
|---|
| 3250 | | - for (i = 0; i < 5; ++i) { |
|---|
| 3251 | | - ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, |
|---|
| 3252 | | - &buf->host_buf_ptr); |
|---|
| 3253 | | - if (ret < 0) |
|---|
| 3254 | | - return ret; |
|---|
| 3255 | | - |
|---|
| 3256 | | - if (buf->host_buf_ptr) |
|---|
| 3257 | | - break; |
|---|
| 3258 | | - |
|---|
| 3259 | | - usleep_range(1000, 2000); |
|---|
| 3741 | + pack_in += sizeof(*buf) - data_word_size; |
|---|
| 3260 | 3742 | } |
|---|
| 3261 | | - |
|---|
| 3262 | | - if (!buf->host_buf_ptr) |
|---|
| 3263 | | - return -EIO; |
|---|
| 3264 | | - |
|---|
| 3265 | | - adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr); |
|---|
| 3266 | | - |
|---|
| 3267 | | - return 0; |
|---|
| 3268 | | -} |
|---|
| 3269 | | - |
|---|
| 3270 | | -static struct wm_coeff_ctl * |
|---|
| 3271 | | -wm_adsp_find_host_buffer_ctrl(struct wm_adsp_compr_buf *buf) |
|---|
| 3272 | | -{ |
|---|
| 3273 | | - struct wm_adsp *dsp = buf->dsp; |
|---|
| 3274 | | - struct wm_coeff_ctl *ctl; |
|---|
| 3275 | | - |
|---|
| 3276 | | - list_for_each_entry(ctl, &dsp->ctl_list, list) { |
|---|
| 3277 | | - if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER) |
|---|
| 3278 | | - continue; |
|---|
| 3279 | | - |
|---|
| 3280 | | - if (!ctl->enabled) |
|---|
| 3281 | | - continue; |
|---|
| 3282 | | - |
|---|
| 3283 | | - return ctl; |
|---|
| 3284 | | - } |
|---|
| 3285 | | - |
|---|
| 3286 | | - return NULL; |
|---|
| 3287 | | -} |
|---|
| 3288 | | - |
|---|
| 3289 | | -static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf) |
|---|
| 3290 | | -{ |
|---|
| 3291 | | - struct wm_adsp *dsp = buf->dsp; |
|---|
| 3292 | | - struct wm_coeff_ctl *ctl; |
|---|
| 3293 | | - unsigned int reg; |
|---|
| 3294 | | - u32 val; |
|---|
| 3295 | | - int i, ret; |
|---|
| 3296 | | - |
|---|
| 3297 | | - ctl = wm_adsp_find_host_buffer_ctrl(buf); |
|---|
| 3298 | | - if (!ctl) |
|---|
| 3299 | | - return wm_adsp_legacy_host_buf_addr(buf); |
|---|
| 3300 | | - |
|---|
| 3301 | | - ret = wm_coeff_base_reg(ctl, ®); |
|---|
| 3302 | | - if (ret) |
|---|
| 3303 | | - return ret; |
|---|
| 3304 | | - |
|---|
| 3305 | | - for (i = 0; i < 5; ++i) { |
|---|
| 3306 | | - ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); |
|---|
| 3307 | | - if (ret < 0) |
|---|
| 3308 | | - return ret; |
|---|
| 3309 | | - |
|---|
| 3310 | | - if (val) |
|---|
| 3311 | | - break; |
|---|
| 3312 | | - |
|---|
| 3313 | | - usleep_range(1000, 2000); |
|---|
| 3314 | | - } |
|---|
| 3315 | | - |
|---|
| 3316 | | - if (!val) |
|---|
| 3317 | | - return -EIO; |
|---|
| 3318 | | - |
|---|
| 3319 | | - buf->host_buf_ptr = be32_to_cpu(val); |
|---|
| 3320 | | - adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr); |
|---|
| 3321 | | - |
|---|
| 3322 | | - return 0; |
|---|
| 3323 | 3743 | } |
|---|
| 3324 | 3744 | |
|---|
| 3325 | 3745 | static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf) |
|---|
| .. | .. |
|---|
| 3328 | 3748 | struct wm_adsp_buffer_region *region; |
|---|
| 3329 | 3749 | u32 offset = 0; |
|---|
| 3330 | 3750 | int i, ret; |
|---|
| 3751 | + |
|---|
| 3752 | + buf->regions = kcalloc(caps->num_regions, sizeof(*buf->regions), |
|---|
| 3753 | + GFP_KERNEL); |
|---|
| 3754 | + if (!buf->regions) |
|---|
| 3755 | + return -ENOMEM; |
|---|
| 3331 | 3756 | |
|---|
| 3332 | 3757 | for (i = 0; i < caps->num_regions; ++i) { |
|---|
| 3333 | 3758 | region = &buf->regions[i]; |
|---|
| .. | .. |
|---|
| 3347 | 3772 | |
|---|
| 3348 | 3773 | region->cumulative_size = offset; |
|---|
| 3349 | 3774 | |
|---|
| 3350 | | - adsp_dbg(buf->dsp, |
|---|
| 3351 | | - "region=%d type=%d base=%04x off=%04x size=%04x\n", |
|---|
| 3352 | | - i, region->mem_type, region->base_addr, |
|---|
| 3353 | | - region->offset, region->cumulative_size); |
|---|
| 3775 | + compr_dbg(buf, |
|---|
| 3776 | + "region=%d type=%d base=%08x off=%08x size=%08x\n", |
|---|
| 3777 | + i, region->mem_type, region->base_addr, |
|---|
| 3778 | + region->offset, region->cumulative_size); |
|---|
| 3354 | 3779 | } |
|---|
| 3355 | 3780 | |
|---|
| 3356 | 3781 | return 0; |
|---|
| .. | .. |
|---|
| 3363 | 3788 | buf->avail = 0; |
|---|
| 3364 | 3789 | } |
|---|
| 3365 | 3790 | |
|---|
| 3366 | | -static int wm_adsp_buffer_init(struct wm_adsp *dsp) |
|---|
| 3791 | +static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp) |
|---|
| 3367 | 3792 | { |
|---|
| 3368 | 3793 | struct wm_adsp_compr_buf *buf; |
|---|
| 3369 | | - int ret; |
|---|
| 3370 | 3794 | |
|---|
| 3371 | 3795 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); |
|---|
| 3372 | 3796 | if (!buf) |
|---|
| 3373 | | - return -ENOMEM; |
|---|
| 3797 | + return NULL; |
|---|
| 3374 | 3798 | |
|---|
| 3375 | 3799 | buf->dsp = dsp; |
|---|
| 3376 | 3800 | |
|---|
| 3377 | 3801 | wm_adsp_buffer_clear(buf); |
|---|
| 3378 | 3802 | |
|---|
| 3379 | | - ret = wm_adsp_buffer_locate(buf); |
|---|
| 3380 | | - if (ret < 0) { |
|---|
| 3381 | | - adsp_err(dsp, "Failed to acquire host buffer: %d\n", ret); |
|---|
| 3382 | | - goto err_buffer; |
|---|
| 3803 | + list_add_tail(&buf->list, &dsp->buffer_list); |
|---|
| 3804 | + |
|---|
| 3805 | + return buf; |
|---|
| 3806 | +} |
|---|
| 3807 | + |
|---|
| 3808 | +static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) |
|---|
| 3809 | +{ |
|---|
| 3810 | + struct wm_adsp_alg_region *alg_region; |
|---|
| 3811 | + struct wm_adsp_compr_buf *buf; |
|---|
| 3812 | + u32 xmalg, addr, magic; |
|---|
| 3813 | + int i, ret; |
|---|
| 3814 | + |
|---|
| 3815 | + alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id); |
|---|
| 3816 | + if (!alg_region) { |
|---|
| 3817 | + adsp_err(dsp, "No algorithm region found\n"); |
|---|
| 3818 | + return -EINVAL; |
|---|
| 3383 | 3819 | } |
|---|
| 3384 | 3820 | |
|---|
| 3385 | | - buf->regions = kcalloc(wm_adsp_fw[dsp->fw].caps->num_regions, |
|---|
| 3386 | | - sizeof(*buf->regions), GFP_KERNEL); |
|---|
| 3387 | | - if (!buf->regions) { |
|---|
| 3388 | | - ret = -ENOMEM; |
|---|
| 3389 | | - goto err_buffer; |
|---|
| 3821 | + buf = wm_adsp_buffer_alloc(dsp); |
|---|
| 3822 | + if (!buf) |
|---|
| 3823 | + return -ENOMEM; |
|---|
| 3824 | + |
|---|
| 3825 | + xmalg = dsp->ops->sys_config_size / sizeof(__be32); |
|---|
| 3826 | + |
|---|
| 3827 | + addr = alg_region->base + xmalg + ALG_XM_FIELD(magic); |
|---|
| 3828 | + ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic); |
|---|
| 3829 | + if (ret < 0) |
|---|
| 3830 | + return ret; |
|---|
| 3831 | + |
|---|
| 3832 | + if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC) |
|---|
| 3833 | + return -ENODEV; |
|---|
| 3834 | + |
|---|
| 3835 | + addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr); |
|---|
| 3836 | + for (i = 0; i < 5; ++i) { |
|---|
| 3837 | + ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, |
|---|
| 3838 | + &buf->host_buf_ptr); |
|---|
| 3839 | + if (ret < 0) |
|---|
| 3840 | + return ret; |
|---|
| 3841 | + |
|---|
| 3842 | + if (buf->host_buf_ptr) |
|---|
| 3843 | + break; |
|---|
| 3844 | + |
|---|
| 3845 | + usleep_range(1000, 2000); |
|---|
| 3390 | 3846 | } |
|---|
| 3847 | + |
|---|
| 3848 | + if (!buf->host_buf_ptr) |
|---|
| 3849 | + return -EIO; |
|---|
| 3850 | + |
|---|
| 3851 | + buf->host_buf_mem_type = WMFW_ADSP2_XM; |
|---|
| 3391 | 3852 | |
|---|
| 3392 | 3853 | ret = wm_adsp_buffer_populate(buf); |
|---|
| 3393 | | - if (ret < 0) { |
|---|
| 3394 | | - adsp_err(dsp, "Failed to populate host buffer: %d\n", ret); |
|---|
| 3395 | | - goto err_regions; |
|---|
| 3854 | + if (ret < 0) |
|---|
| 3855 | + return ret; |
|---|
| 3856 | + |
|---|
| 3857 | + compr_dbg(buf, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr); |
|---|
| 3858 | + |
|---|
| 3859 | + return 0; |
|---|
| 3860 | +} |
|---|
| 3861 | + |
|---|
| 3862 | +static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) |
|---|
| 3863 | +{ |
|---|
| 3864 | + struct wm_adsp_host_buf_coeff_v1 coeff_v1; |
|---|
| 3865 | + struct wm_adsp_compr_buf *buf; |
|---|
| 3866 | + unsigned int val, reg; |
|---|
| 3867 | + int ret, i; |
|---|
| 3868 | + |
|---|
| 3869 | + ret = wm_coeff_base_reg(ctl, ®); |
|---|
| 3870 | + if (ret) |
|---|
| 3871 | + return ret; |
|---|
| 3872 | + |
|---|
| 3873 | + for (i = 0; i < 5; ++i) { |
|---|
| 3874 | + ret = regmap_raw_read(ctl->dsp->regmap, reg, &val, sizeof(val)); |
|---|
| 3875 | + if (ret < 0) |
|---|
| 3876 | + return ret; |
|---|
| 3877 | + |
|---|
| 3878 | + if (val) |
|---|
| 3879 | + break; |
|---|
| 3880 | + |
|---|
| 3881 | + usleep_range(1000, 2000); |
|---|
| 3396 | 3882 | } |
|---|
| 3397 | 3883 | |
|---|
| 3398 | | - dsp->buffer = buf; |
|---|
| 3884 | + if (!val) { |
|---|
| 3885 | + adsp_err(ctl->dsp, "Failed to acquire host buffer\n"); |
|---|
| 3886 | + return -EIO; |
|---|
| 3887 | + } |
|---|
| 3888 | + |
|---|
| 3889 | + buf = wm_adsp_buffer_alloc(ctl->dsp); |
|---|
| 3890 | + if (!buf) |
|---|
| 3891 | + return -ENOMEM; |
|---|
| 3892 | + |
|---|
| 3893 | + buf->host_buf_mem_type = ctl->alg_region.type; |
|---|
| 3894 | + buf->host_buf_ptr = be32_to_cpu(val); |
|---|
| 3895 | + |
|---|
| 3896 | + ret = wm_adsp_buffer_populate(buf); |
|---|
| 3897 | + if (ret < 0) |
|---|
| 3898 | + return ret; |
|---|
| 3899 | + |
|---|
| 3900 | + /* |
|---|
| 3901 | + * v0 host_buffer coefficients didn't have versioning, so if the |
|---|
| 3902 | + * control is one word, assume version 0. |
|---|
| 3903 | + */ |
|---|
| 3904 | + if (ctl->len == 4) { |
|---|
| 3905 | + compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr); |
|---|
| 3906 | + return 0; |
|---|
| 3907 | + } |
|---|
| 3908 | + |
|---|
| 3909 | + ret = regmap_raw_read(ctl->dsp->regmap, reg, &coeff_v1, |
|---|
| 3910 | + sizeof(coeff_v1)); |
|---|
| 3911 | + if (ret < 0) |
|---|
| 3912 | + return ret; |
|---|
| 3913 | + |
|---|
| 3914 | + coeff_v1.versions = be32_to_cpu(coeff_v1.versions); |
|---|
| 3915 | + val = coeff_v1.versions & HOST_BUF_COEFF_COMPAT_VER_MASK; |
|---|
| 3916 | + val >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT; |
|---|
| 3917 | + |
|---|
| 3918 | + if (val > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) { |
|---|
| 3919 | + adsp_err(ctl->dsp, |
|---|
| 3920 | + "Host buffer coeff ver %u > supported version %u\n", |
|---|
| 3921 | + val, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER); |
|---|
| 3922 | + return -EINVAL; |
|---|
| 3923 | + } |
|---|
| 3924 | + |
|---|
| 3925 | + for (i = 0; i < ARRAY_SIZE(coeff_v1.name); i++) |
|---|
| 3926 | + coeff_v1.name[i] = be32_to_cpu(coeff_v1.name[i]); |
|---|
| 3927 | + |
|---|
| 3928 | + wm_adsp_remove_padding((u32 *)&coeff_v1.name, |
|---|
| 3929 | + ARRAY_SIZE(coeff_v1.name), |
|---|
| 3930 | + WM_ADSP_DATA_WORD_SIZE); |
|---|
| 3931 | + |
|---|
| 3932 | + buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part, |
|---|
| 3933 | + (char *)&coeff_v1.name); |
|---|
| 3934 | + |
|---|
| 3935 | + compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n", |
|---|
| 3936 | + buf->host_buf_ptr, val); |
|---|
| 3937 | + |
|---|
| 3938 | + return val; |
|---|
| 3939 | +} |
|---|
| 3940 | + |
|---|
| 3941 | +static int wm_adsp_buffer_init(struct wm_adsp *dsp) |
|---|
| 3942 | +{ |
|---|
| 3943 | + struct wm_coeff_ctl *ctl; |
|---|
| 3944 | + int ret; |
|---|
| 3945 | + |
|---|
| 3946 | + list_for_each_entry(ctl, &dsp->ctl_list, list) { |
|---|
| 3947 | + if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER) |
|---|
| 3948 | + continue; |
|---|
| 3949 | + |
|---|
| 3950 | + if (!ctl->enabled) |
|---|
| 3951 | + continue; |
|---|
| 3952 | + |
|---|
| 3953 | + ret = wm_adsp_buffer_parse_coeff(ctl); |
|---|
| 3954 | + if (ret < 0) { |
|---|
| 3955 | + adsp_err(dsp, "Failed to parse coeff: %d\n", ret); |
|---|
| 3956 | + goto error; |
|---|
| 3957 | + } else if (ret == 0) { |
|---|
| 3958 | + /* Only one buffer supported for version 0 */ |
|---|
| 3959 | + return 0; |
|---|
| 3960 | + } |
|---|
| 3961 | + } |
|---|
| 3962 | + |
|---|
| 3963 | + if (list_empty(&dsp->buffer_list)) { |
|---|
| 3964 | + /* Fall back to legacy support */ |
|---|
| 3965 | + ret = wm_adsp_buffer_parse_legacy(dsp); |
|---|
| 3966 | + if (ret) { |
|---|
| 3967 | + adsp_err(dsp, "Failed to parse legacy: %d\n", ret); |
|---|
| 3968 | + goto error; |
|---|
| 3969 | + } |
|---|
| 3970 | + } |
|---|
| 3399 | 3971 | |
|---|
| 3400 | 3972 | return 0; |
|---|
| 3401 | 3973 | |
|---|
| 3402 | | -err_regions: |
|---|
| 3403 | | - kfree(buf->regions); |
|---|
| 3404 | | -err_buffer: |
|---|
| 3405 | | - kfree(buf); |
|---|
| 3974 | +error: |
|---|
| 3975 | + wm_adsp_buffer_free(dsp); |
|---|
| 3406 | 3976 | return ret; |
|---|
| 3407 | 3977 | } |
|---|
| 3408 | 3978 | |
|---|
| 3409 | 3979 | static int wm_adsp_buffer_free(struct wm_adsp *dsp) |
|---|
| 3410 | 3980 | { |
|---|
| 3411 | | - if (dsp->buffer) { |
|---|
| 3412 | | - wm_adsp_compr_detach(dsp->buffer->compr); |
|---|
| 3981 | + struct wm_adsp_compr_buf *buf, *tmp; |
|---|
| 3413 | 3982 | |
|---|
| 3414 | | - kfree(dsp->buffer->regions); |
|---|
| 3415 | | - kfree(dsp->buffer); |
|---|
| 3983 | + list_for_each_entry_safe(buf, tmp, &dsp->buffer_list, list) { |
|---|
| 3984 | + wm_adsp_compr_detach(buf->compr); |
|---|
| 3416 | 3985 | |
|---|
| 3417 | | - dsp->buffer = NULL; |
|---|
| 3986 | + kfree(buf->name); |
|---|
| 3987 | + kfree(buf->regions); |
|---|
| 3988 | + list_del(&buf->list); |
|---|
| 3989 | + kfree(buf); |
|---|
| 3418 | 3990 | } |
|---|
| 3419 | 3991 | |
|---|
| 3420 | 3992 | return 0; |
|---|
| 3421 | 3993 | } |
|---|
| 3422 | 3994 | |
|---|
| 3423 | | -int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) |
|---|
| 3995 | +static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf) |
|---|
| 3996 | +{ |
|---|
| 3997 | + int ret; |
|---|
| 3998 | + |
|---|
| 3999 | + ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); |
|---|
| 4000 | + if (ret < 0) { |
|---|
| 4001 | + compr_err(buf, "Failed to check buffer error: %d\n", ret); |
|---|
| 4002 | + return ret; |
|---|
| 4003 | + } |
|---|
| 4004 | + if (buf->error != 0) { |
|---|
| 4005 | + compr_err(buf, "Buffer error occurred: %d\n", buf->error); |
|---|
| 4006 | + return -EIO; |
|---|
| 4007 | + } |
|---|
| 4008 | + |
|---|
| 4009 | + return 0; |
|---|
| 4010 | +} |
|---|
| 4011 | + |
|---|
| 4012 | +int wm_adsp_compr_trigger(struct snd_soc_component *component, |
|---|
| 4013 | + struct snd_compr_stream *stream, int cmd) |
|---|
| 3424 | 4014 | { |
|---|
| 3425 | 4015 | struct wm_adsp_compr *compr = stream->runtime->private_data; |
|---|
| 3426 | 4016 | struct wm_adsp *dsp = compr->dsp; |
|---|
| 3427 | 4017 | int ret = 0; |
|---|
| 3428 | 4018 | |
|---|
| 3429 | | - adsp_dbg(dsp, "Trigger: %d\n", cmd); |
|---|
| 4019 | + compr_dbg(compr, "Trigger: %d\n", cmd); |
|---|
| 3430 | 4020 | |
|---|
| 3431 | 4021 | mutex_lock(&dsp->pwr_lock); |
|---|
| 3432 | 4022 | |
|---|
| .. | .. |
|---|
| 3435 | 4025 | if (!wm_adsp_compr_attached(compr)) { |
|---|
| 3436 | 4026 | ret = wm_adsp_compr_attach(compr); |
|---|
| 3437 | 4027 | if (ret < 0) { |
|---|
| 3438 | | - adsp_err(dsp, "Failed to link buffer and stream: %d\n", |
|---|
| 3439 | | - ret); |
|---|
| 4028 | + compr_err(compr, "Failed to link buffer and stream: %d\n", |
|---|
| 4029 | + ret); |
|---|
| 3440 | 4030 | break; |
|---|
| 3441 | 4031 | } |
|---|
| 3442 | 4032 | } |
|---|
| 4033 | + |
|---|
| 4034 | + ret = wm_adsp_buffer_get_error(compr->buf); |
|---|
| 4035 | + if (ret < 0) |
|---|
| 4036 | + break; |
|---|
| 3443 | 4037 | |
|---|
| 3444 | 4038 | /* Trigger the IRQ at one fragment of data */ |
|---|
| 3445 | 4039 | ret = wm_adsp_buffer_write(compr->buf, |
|---|
| 3446 | 4040 | HOST_BUFFER_FIELD(high_water_mark), |
|---|
| 3447 | 4041 | wm_adsp_compr_frag_words(compr)); |
|---|
| 3448 | 4042 | if (ret < 0) { |
|---|
| 3449 | | - adsp_err(dsp, "Failed to set high water mark: %d\n", |
|---|
| 3450 | | - ret); |
|---|
| 4043 | + compr_err(compr, "Failed to set high water mark: %d\n", |
|---|
| 4044 | + ret); |
|---|
| 3451 | 4045 | break; |
|---|
| 3452 | 4046 | } |
|---|
| 3453 | 4047 | break; |
|---|
| .. | .. |
|---|
| 3490 | 4084 | read_index = sign_extend32(next_read_index, 23); |
|---|
| 3491 | 4085 | |
|---|
| 3492 | 4086 | if (read_index < 0) { |
|---|
| 3493 | | - adsp_dbg(buf->dsp, "Avail check on unstarted stream\n"); |
|---|
| 4087 | + compr_dbg(buf, "Avail check on unstarted stream\n"); |
|---|
| 3494 | 4088 | return 0; |
|---|
| 3495 | 4089 | } |
|---|
| 3496 | 4090 | |
|---|
| .. | .. |
|---|
| 3508 | 4102 | if (avail < 0) |
|---|
| 3509 | 4103 | avail += wm_adsp_buffer_size(buf); |
|---|
| 3510 | 4104 | |
|---|
| 3511 | | - adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n", |
|---|
| 3512 | | - buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE); |
|---|
| 4105 | + compr_dbg(buf, "readindex=0x%x, writeindex=0x%x, avail=%d\n", |
|---|
| 4106 | + buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE); |
|---|
| 3513 | 4107 | |
|---|
| 3514 | 4108 | buf->avail = avail; |
|---|
| 3515 | | - |
|---|
| 3516 | | - return 0; |
|---|
| 3517 | | -} |
|---|
| 3518 | | - |
|---|
| 3519 | | -static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf) |
|---|
| 3520 | | -{ |
|---|
| 3521 | | - int ret; |
|---|
| 3522 | | - |
|---|
| 3523 | | - ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); |
|---|
| 3524 | | - if (ret < 0) { |
|---|
| 3525 | | - adsp_err(buf->dsp, "Failed to check buffer error: %d\n", ret); |
|---|
| 3526 | | - return ret; |
|---|
| 3527 | | - } |
|---|
| 3528 | | - if (buf->error != 0) { |
|---|
| 3529 | | - adsp_err(buf->dsp, "Buffer error occurred: %d\n", buf->error); |
|---|
| 3530 | | - return -EIO; |
|---|
| 3531 | | - } |
|---|
| 3532 | 4109 | |
|---|
| 3533 | 4110 | return 0; |
|---|
| 3534 | 4111 | } |
|---|
| .. | .. |
|---|
| 3541 | 4118 | |
|---|
| 3542 | 4119 | mutex_lock(&dsp->pwr_lock); |
|---|
| 3543 | 4120 | |
|---|
| 3544 | | - buf = dsp->buffer; |
|---|
| 3545 | | - compr = dsp->compr; |
|---|
| 3546 | | - |
|---|
| 3547 | | - if (!buf) { |
|---|
| 4121 | + if (list_empty(&dsp->buffer_list)) { |
|---|
| 3548 | 4122 | ret = -ENODEV; |
|---|
| 3549 | 4123 | goto out; |
|---|
| 3550 | 4124 | } |
|---|
| 3551 | 4125 | |
|---|
| 3552 | 4126 | adsp_dbg(dsp, "Handling buffer IRQ\n"); |
|---|
| 3553 | 4127 | |
|---|
| 3554 | | - ret = wm_adsp_buffer_get_error(buf); |
|---|
| 3555 | | - if (ret < 0) |
|---|
| 3556 | | - goto out_notify; /* Wake poll to report error */ |
|---|
| 4128 | + list_for_each_entry(buf, &dsp->buffer_list, list) { |
|---|
| 4129 | + compr = buf->compr; |
|---|
| 3557 | 4130 | |
|---|
| 3558 | | - ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), |
|---|
| 3559 | | - &buf->irq_count); |
|---|
| 3560 | | - if (ret < 0) { |
|---|
| 3561 | | - adsp_err(dsp, "Failed to get irq_count: %d\n", ret); |
|---|
| 3562 | | - goto out; |
|---|
| 3563 | | - } |
|---|
| 4131 | + ret = wm_adsp_buffer_get_error(buf); |
|---|
| 4132 | + if (ret < 0) |
|---|
| 4133 | + goto out_notify; /* Wake poll to report error */ |
|---|
| 3564 | 4134 | |
|---|
| 3565 | | - ret = wm_adsp_buffer_update_avail(buf); |
|---|
| 3566 | | - if (ret < 0) { |
|---|
| 3567 | | - adsp_err(dsp, "Error reading avail: %d\n", ret); |
|---|
| 3568 | | - goto out; |
|---|
| 3569 | | - } |
|---|
| 4135 | + ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), |
|---|
| 4136 | + &buf->irq_count); |
|---|
| 4137 | + if (ret < 0) { |
|---|
| 4138 | + compr_err(buf, "Failed to get irq_count: %d\n", ret); |
|---|
| 4139 | + goto out; |
|---|
| 4140 | + } |
|---|
| 3570 | 4141 | |
|---|
| 3571 | | - if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2) |
|---|
| 3572 | | - ret = WM_ADSP_COMPR_VOICE_TRIGGER; |
|---|
| 4142 | + ret = wm_adsp_buffer_update_avail(buf); |
|---|
| 4143 | + if (ret < 0) { |
|---|
| 4144 | + compr_err(buf, "Error reading avail: %d\n", ret); |
|---|
| 4145 | + goto out; |
|---|
| 4146 | + } |
|---|
| 4147 | + |
|---|
| 4148 | + if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2) |
|---|
| 4149 | + ret = WM_ADSP_COMPR_VOICE_TRIGGER; |
|---|
| 3573 | 4150 | |
|---|
| 3574 | 4151 | out_notify: |
|---|
| 3575 | | - if (compr && compr->stream) |
|---|
| 3576 | | - snd_compr_fragment_elapsed(compr->stream); |
|---|
| 4152 | + if (compr && compr->stream) |
|---|
| 4153 | + snd_compr_fragment_elapsed(compr->stream); |
|---|
| 4154 | + } |
|---|
| 3577 | 4155 | |
|---|
| 3578 | 4156 | out: |
|---|
| 3579 | 4157 | mutex_unlock(&dsp->pwr_lock); |
|---|
| .. | .. |
|---|
| 3587 | 4165 | if (buf->irq_count & 0x01) |
|---|
| 3588 | 4166 | return 0; |
|---|
| 3589 | 4167 | |
|---|
| 3590 | | - adsp_dbg(buf->dsp, "Enable IRQ(0x%x) for next fragment\n", |
|---|
| 3591 | | - buf->irq_count); |
|---|
| 4168 | + compr_dbg(buf, "Enable IRQ(0x%x) for next fragment\n", buf->irq_count); |
|---|
| 3592 | 4169 | |
|---|
| 3593 | 4170 | buf->irq_count |= 0x01; |
|---|
| 3594 | 4171 | |
|---|
| .. | .. |
|---|
| 3596 | 4173 | buf->irq_count); |
|---|
| 3597 | 4174 | } |
|---|
| 3598 | 4175 | |
|---|
| 3599 | | -int wm_adsp_compr_pointer(struct snd_compr_stream *stream, |
|---|
| 4176 | +int wm_adsp_compr_pointer(struct snd_soc_component *component, |
|---|
| 4177 | + struct snd_compr_stream *stream, |
|---|
| 3600 | 4178 | struct snd_compr_tstamp *tstamp) |
|---|
| 3601 | 4179 | { |
|---|
| 3602 | 4180 | struct wm_adsp_compr *compr = stream->runtime->private_data; |
|---|
| .. | .. |
|---|
| 3604 | 4182 | struct wm_adsp_compr_buf *buf; |
|---|
| 3605 | 4183 | int ret = 0; |
|---|
| 3606 | 4184 | |
|---|
| 3607 | | - adsp_dbg(dsp, "Pointer request\n"); |
|---|
| 4185 | + compr_dbg(compr, "Pointer request\n"); |
|---|
| 3608 | 4186 | |
|---|
| 3609 | 4187 | mutex_lock(&dsp->pwr_lock); |
|---|
| 3610 | 4188 | |
|---|
| 3611 | 4189 | buf = compr->buf; |
|---|
| 3612 | 4190 | |
|---|
| 3613 | | - if (!compr->buf || compr->buf->error) { |
|---|
| 4191 | + if (dsp->fatal_error || !buf || buf->error) { |
|---|
| 3614 | 4192 | snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN); |
|---|
| 3615 | 4193 | ret = -EIO; |
|---|
| 3616 | 4194 | goto out; |
|---|
| .. | .. |
|---|
| 3619 | 4197 | if (buf->avail < wm_adsp_compr_frag_words(compr)) { |
|---|
| 3620 | 4198 | ret = wm_adsp_buffer_update_avail(buf); |
|---|
| 3621 | 4199 | if (ret < 0) { |
|---|
| 3622 | | - adsp_err(dsp, "Error reading avail: %d\n", ret); |
|---|
| 4200 | + compr_err(compr, "Error reading avail: %d\n", ret); |
|---|
| 3623 | 4201 | goto out; |
|---|
| 3624 | 4202 | } |
|---|
| 3625 | 4203 | |
|---|
| .. | .. |
|---|
| 3630 | 4208 | if (buf->avail < wm_adsp_compr_frag_words(compr)) { |
|---|
| 3631 | 4209 | ret = wm_adsp_buffer_get_error(buf); |
|---|
| 3632 | 4210 | if (ret < 0) { |
|---|
| 3633 | | - if (compr->buf->error) |
|---|
| 4211 | + if (buf->error) |
|---|
| 3634 | 4212 | snd_compr_stop_error(stream, |
|---|
| 3635 | 4213 | SNDRV_PCM_STATE_XRUN); |
|---|
| 3636 | 4214 | goto out; |
|---|
| .. | .. |
|---|
| 3638 | 4216 | |
|---|
| 3639 | 4217 | ret = wm_adsp_buffer_reenable_irq(buf); |
|---|
| 3640 | 4218 | if (ret < 0) { |
|---|
| 3641 | | - adsp_err(dsp, |
|---|
| 3642 | | - "Failed to re-enable buffer IRQ: %d\n", |
|---|
| 3643 | | - ret); |
|---|
| 4219 | + compr_err(compr, "Failed to re-enable buffer IRQ: %d\n", |
|---|
| 4220 | + ret); |
|---|
| 3644 | 4221 | goto out; |
|---|
| 3645 | 4222 | } |
|---|
| 3646 | 4223 | } |
|---|
| .. | .. |
|---|
| 3660 | 4237 | static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target) |
|---|
| 3661 | 4238 | { |
|---|
| 3662 | 4239 | struct wm_adsp_compr_buf *buf = compr->buf; |
|---|
| 3663 | | - u8 *pack_in = (u8 *)compr->raw_buf; |
|---|
| 3664 | | - u8 *pack_out = (u8 *)compr->raw_buf; |
|---|
| 3665 | 4240 | unsigned int adsp_addr; |
|---|
| 3666 | 4241 | int mem_type, nwords, max_read; |
|---|
| 3667 | | - int i, j, ret; |
|---|
| 4242 | + int i, ret; |
|---|
| 3668 | 4243 | |
|---|
| 3669 | 4244 | /* Calculate read parameters */ |
|---|
| 3670 | 4245 | for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i) |
|---|
| .. | .. |
|---|
| 3696 | 4271 | if (ret < 0) |
|---|
| 3697 | 4272 | return ret; |
|---|
| 3698 | 4273 | |
|---|
| 3699 | | - /* Remove the padding bytes from the data read from the DSP */ |
|---|
| 3700 | | - for (i = 0; i < nwords; i++) { |
|---|
| 3701 | | - for (j = 0; j < WM_ADSP_DATA_WORD_SIZE; j++) |
|---|
| 3702 | | - *pack_out++ = *pack_in++; |
|---|
| 3703 | | - |
|---|
| 3704 | | - pack_in += sizeof(*(compr->raw_buf)) - WM_ADSP_DATA_WORD_SIZE; |
|---|
| 3705 | | - } |
|---|
| 4274 | + wm_adsp_remove_padding(compr->raw_buf, nwords, WM_ADSP_DATA_WORD_SIZE); |
|---|
| 3706 | 4275 | |
|---|
| 3707 | 4276 | /* update read index to account for words read */ |
|---|
| 3708 | 4277 | buf->read_index += nwords; |
|---|
| .. | .. |
|---|
| 3727 | 4296 | int ntotal = 0; |
|---|
| 3728 | 4297 | int nwords, nbytes; |
|---|
| 3729 | 4298 | |
|---|
| 3730 | | - adsp_dbg(dsp, "Requested read of %zu bytes\n", count); |
|---|
| 4299 | + compr_dbg(compr, "Requested read of %zu bytes\n", count); |
|---|
| 3731 | 4300 | |
|---|
| 3732 | | - if (!compr->buf || compr->buf->error) { |
|---|
| 4301 | + if (dsp->fatal_error || !compr->buf || compr->buf->error) { |
|---|
| 3733 | 4302 | snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN); |
|---|
| 3734 | 4303 | return -EIO; |
|---|
| 3735 | 4304 | } |
|---|
| .. | .. |
|---|
| 3739 | 4308 | do { |
|---|
| 3740 | 4309 | nwords = wm_adsp_buffer_capture_block(compr, count); |
|---|
| 3741 | 4310 | if (nwords < 0) { |
|---|
| 3742 | | - adsp_err(dsp, "Failed to capture block: %d\n", nwords); |
|---|
| 4311 | + compr_err(compr, "Failed to capture block: %d\n", |
|---|
| 4312 | + nwords); |
|---|
| 3743 | 4313 | return nwords; |
|---|
| 3744 | 4314 | } |
|---|
| 3745 | 4315 | |
|---|
| 3746 | 4316 | nbytes = nwords * WM_ADSP_DATA_WORD_SIZE; |
|---|
| 3747 | 4317 | |
|---|
| 3748 | | - adsp_dbg(dsp, "Read %d bytes\n", nbytes); |
|---|
| 4318 | + compr_dbg(compr, "Read %d bytes\n", nbytes); |
|---|
| 3749 | 4319 | |
|---|
| 3750 | 4320 | if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) { |
|---|
| 3751 | | - adsp_err(dsp, "Failed to copy data to user: %d, %d\n", |
|---|
| 3752 | | - ntotal, nbytes); |
|---|
| 4321 | + compr_err(compr, "Failed to copy data to user: %d, %d\n", |
|---|
| 4322 | + ntotal, nbytes); |
|---|
| 3753 | 4323 | return -EFAULT; |
|---|
| 3754 | 4324 | } |
|---|
| 3755 | 4325 | |
|---|
| .. | .. |
|---|
| 3762 | 4332 | return ntotal; |
|---|
| 3763 | 4333 | } |
|---|
| 3764 | 4334 | |
|---|
| 3765 | | -int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf, |
|---|
| 4335 | +int wm_adsp_compr_copy(struct snd_soc_component *component, |
|---|
| 4336 | + struct snd_compr_stream *stream, char __user *buf, |
|---|
| 3766 | 4337 | size_t count) |
|---|
| 3767 | 4338 | { |
|---|
| 3768 | 4339 | struct wm_adsp_compr *compr = stream->runtime->private_data; |
|---|
| .. | .. |
|---|
| 3782 | 4353 | } |
|---|
| 3783 | 4354 | EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); |
|---|
| 3784 | 4355 | |
|---|
| 3785 | | -int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions) |
|---|
| 4356 | +static void wm_adsp_fatal_error(struct wm_adsp *dsp) |
|---|
| 3786 | 4357 | { |
|---|
| 3787 | | - struct regmap *regmap = dsp->regmap; |
|---|
| 3788 | | - unsigned int code0, code1, lock_reg; |
|---|
| 4358 | + struct wm_adsp_compr *compr; |
|---|
| 3789 | 4359 | |
|---|
| 3790 | | - if (!(lock_regions & WM_ADSP2_REGION_ALL)) |
|---|
| 3791 | | - return 0; |
|---|
| 4360 | + dsp->fatal_error = true; |
|---|
| 3792 | 4361 | |
|---|
| 3793 | | - lock_regions &= WM_ADSP2_REGION_ALL; |
|---|
| 3794 | | - lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0; |
|---|
| 3795 | | - |
|---|
| 3796 | | - while (lock_regions) { |
|---|
| 3797 | | - code0 = code1 = 0; |
|---|
| 3798 | | - if (lock_regions & BIT(0)) { |
|---|
| 3799 | | - code0 = ADSP2_LOCK_CODE_0; |
|---|
| 3800 | | - code1 = ADSP2_LOCK_CODE_1; |
|---|
| 3801 | | - } |
|---|
| 3802 | | - if (lock_regions & BIT(1)) { |
|---|
| 3803 | | - code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT; |
|---|
| 3804 | | - code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT; |
|---|
| 3805 | | - } |
|---|
| 3806 | | - regmap_write(regmap, lock_reg, code0); |
|---|
| 3807 | | - regmap_write(regmap, lock_reg, code1); |
|---|
| 3808 | | - lock_regions >>= 2; |
|---|
| 3809 | | - lock_reg += 2; |
|---|
| 4362 | + list_for_each_entry(compr, &dsp->compr_list, list) { |
|---|
| 4363 | + if (compr->stream) |
|---|
| 4364 | + snd_compr_fragment_elapsed(compr->stream); |
|---|
| 3810 | 4365 | } |
|---|
| 3811 | | - |
|---|
| 3812 | | - return 0; |
|---|
| 3813 | 4366 | } |
|---|
| 3814 | | -EXPORT_SYMBOL_GPL(wm_adsp2_lock); |
|---|
| 3815 | 4367 | |
|---|
| 3816 | | -irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp) |
|---|
| 4368 | +irqreturn_t wm_adsp2_bus_error(int irq, void *data) |
|---|
| 3817 | 4369 | { |
|---|
| 4370 | + struct wm_adsp *dsp = (struct wm_adsp *)data; |
|---|
| 3818 | 4371 | unsigned int val; |
|---|
| 3819 | 4372 | struct regmap *regmap = dsp->regmap; |
|---|
| 3820 | 4373 | int ret = 0; |
|---|
| .. | .. |
|---|
| 3830 | 4383 | |
|---|
| 3831 | 4384 | if (val & ADSP2_WDT_TIMEOUT_STS_MASK) { |
|---|
| 3832 | 4385 | adsp_err(dsp, "watchdog timeout error\n"); |
|---|
| 3833 | | - wm_adsp_stop_watchdog(dsp); |
|---|
| 4386 | + dsp->ops->stop_watchdog(dsp); |
|---|
| 4387 | + wm_adsp_fatal_error(dsp); |
|---|
| 3834 | 4388 | } |
|---|
| 3835 | 4389 | |
|---|
| 3836 | | - if (val & (ADSP2_SLAVE_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) { |
|---|
| 3837 | | - if (val & ADSP2_SLAVE_ERR_MASK) |
|---|
| 3838 | | - adsp_err(dsp, "bus error: slave error\n"); |
|---|
| 4390 | + if (val & (ADSP2_ADDR_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) { |
|---|
| 4391 | + if (val & ADSP2_ADDR_ERR_MASK) |
|---|
| 4392 | + adsp_err(dsp, "bus error: address error\n"); |
|---|
| 3839 | 4393 | else |
|---|
| 3840 | 4394 | adsp_err(dsp, "bus error: region lock error\n"); |
|---|
| 3841 | 4395 | |
|---|
| .. | .. |
|---|
| 3877 | 4431 | } |
|---|
| 3878 | 4432 | EXPORT_SYMBOL_GPL(wm_adsp2_bus_error); |
|---|
| 3879 | 4433 | |
|---|
| 4434 | +irqreturn_t wm_halo_bus_error(int irq, void *data) |
|---|
| 4435 | +{ |
|---|
| 4436 | + struct wm_adsp *dsp = (struct wm_adsp *)data; |
|---|
| 4437 | + struct regmap *regmap = dsp->regmap; |
|---|
| 4438 | + unsigned int fault[6]; |
|---|
| 4439 | + struct reg_sequence clear[] = { |
|---|
| 4440 | + { dsp->base + HALO_MPU_XM_VIO_STATUS, 0x0 }, |
|---|
| 4441 | + { dsp->base + HALO_MPU_YM_VIO_STATUS, 0x0 }, |
|---|
| 4442 | + { dsp->base + HALO_MPU_PM_VIO_STATUS, 0x0 }, |
|---|
| 4443 | + }; |
|---|
| 4444 | + int ret; |
|---|
| 4445 | + |
|---|
| 4446 | + mutex_lock(&dsp->pwr_lock); |
|---|
| 4447 | + |
|---|
| 4448 | + ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1, |
|---|
| 4449 | + fault); |
|---|
| 4450 | + if (ret) { |
|---|
| 4451 | + adsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret); |
|---|
| 4452 | + goto exit_unlock; |
|---|
| 4453 | + } |
|---|
| 4454 | + |
|---|
| 4455 | + adsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n", |
|---|
| 4456 | + *fault & HALO_AHBM_FLAGS_ERR_MASK, |
|---|
| 4457 | + (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >> |
|---|
| 4458 | + HALO_AHBM_CORE_ERR_ADDR_SHIFT); |
|---|
| 4459 | + |
|---|
| 4460 | + ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0, |
|---|
| 4461 | + fault); |
|---|
| 4462 | + if (ret) { |
|---|
| 4463 | + adsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret); |
|---|
| 4464 | + goto exit_unlock; |
|---|
| 4465 | + } |
|---|
| 4466 | + |
|---|
| 4467 | + adsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault); |
|---|
| 4468 | + |
|---|
| 4469 | + ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR, |
|---|
| 4470 | + fault, ARRAY_SIZE(fault)); |
|---|
| 4471 | + if (ret) { |
|---|
| 4472 | + adsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret); |
|---|
| 4473 | + goto exit_unlock; |
|---|
| 4474 | + } |
|---|
| 4475 | + |
|---|
| 4476 | + adsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]); |
|---|
| 4477 | + adsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]); |
|---|
| 4478 | + adsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]); |
|---|
| 4479 | + |
|---|
| 4480 | + ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear)); |
|---|
| 4481 | + if (ret) |
|---|
| 4482 | + adsp_warn(dsp, "Failed to clear MPU status: %d\n", ret); |
|---|
| 4483 | + |
|---|
| 4484 | +exit_unlock: |
|---|
| 4485 | + mutex_unlock(&dsp->pwr_lock); |
|---|
| 4486 | + |
|---|
| 4487 | + return IRQ_HANDLED; |
|---|
| 4488 | +} |
|---|
| 4489 | +EXPORT_SYMBOL_GPL(wm_halo_bus_error); |
|---|
| 4490 | + |
|---|
| 4491 | +irqreturn_t wm_halo_wdt_expire(int irq, void *data) |
|---|
| 4492 | +{ |
|---|
| 4493 | + struct wm_adsp *dsp = data; |
|---|
| 4494 | + |
|---|
| 4495 | + mutex_lock(&dsp->pwr_lock); |
|---|
| 4496 | + |
|---|
| 4497 | + adsp_warn(dsp, "WDT Expiry Fault\n"); |
|---|
| 4498 | + dsp->ops->stop_watchdog(dsp); |
|---|
| 4499 | + wm_adsp_fatal_error(dsp); |
|---|
| 4500 | + |
|---|
| 4501 | + mutex_unlock(&dsp->pwr_lock); |
|---|
| 4502 | + |
|---|
| 4503 | + return IRQ_HANDLED; |
|---|
| 4504 | +} |
|---|
| 4505 | +EXPORT_SYMBOL_GPL(wm_halo_wdt_expire); |
|---|
| 4506 | + |
|---|
| 4507 | +static struct wm_adsp_ops wm_adsp1_ops = { |
|---|
| 4508 | + .validate_version = wm_adsp_validate_version, |
|---|
| 4509 | + .parse_sizes = wm_adsp1_parse_sizes, |
|---|
| 4510 | + .region_to_reg = wm_adsp_region_to_reg, |
|---|
| 4511 | +}; |
|---|
| 4512 | + |
|---|
| 4513 | +static struct wm_adsp_ops wm_adsp2_ops[] = { |
|---|
| 4514 | + { |
|---|
| 4515 | + .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr), |
|---|
| 4516 | + .parse_sizes = wm_adsp2_parse_sizes, |
|---|
| 4517 | + .validate_version = wm_adsp_validate_version, |
|---|
| 4518 | + .setup_algs = wm_adsp2_setup_algs, |
|---|
| 4519 | + .region_to_reg = wm_adsp_region_to_reg, |
|---|
| 4520 | + |
|---|
| 4521 | + .show_fw_status = wm_adsp2_show_fw_status, |
|---|
| 4522 | + |
|---|
| 4523 | + .enable_memory = wm_adsp2_enable_memory, |
|---|
| 4524 | + .disable_memory = wm_adsp2_disable_memory, |
|---|
| 4525 | + |
|---|
| 4526 | + .enable_core = wm_adsp2_enable_core, |
|---|
| 4527 | + .disable_core = wm_adsp2_disable_core, |
|---|
| 4528 | + |
|---|
| 4529 | + .start_core = wm_adsp2_start_core, |
|---|
| 4530 | + .stop_core = wm_adsp2_stop_core, |
|---|
| 4531 | + |
|---|
| 4532 | + }, |
|---|
| 4533 | + { |
|---|
| 4534 | + .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr), |
|---|
| 4535 | + .parse_sizes = wm_adsp2_parse_sizes, |
|---|
| 4536 | + .validate_version = wm_adsp_validate_version, |
|---|
| 4537 | + .setup_algs = wm_adsp2_setup_algs, |
|---|
| 4538 | + .region_to_reg = wm_adsp_region_to_reg, |
|---|
| 4539 | + |
|---|
| 4540 | + .show_fw_status = wm_adsp2v2_show_fw_status, |
|---|
| 4541 | + |
|---|
| 4542 | + .enable_memory = wm_adsp2_enable_memory, |
|---|
| 4543 | + .disable_memory = wm_adsp2_disable_memory, |
|---|
| 4544 | + .lock_memory = wm_adsp2_lock, |
|---|
| 4545 | + |
|---|
| 4546 | + .enable_core = wm_adsp2v2_enable_core, |
|---|
| 4547 | + .disable_core = wm_adsp2v2_disable_core, |
|---|
| 4548 | + |
|---|
| 4549 | + .start_core = wm_adsp2_start_core, |
|---|
| 4550 | + .stop_core = wm_adsp2_stop_core, |
|---|
| 4551 | + }, |
|---|
| 4552 | + { |
|---|
| 4553 | + .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr), |
|---|
| 4554 | + .parse_sizes = wm_adsp2_parse_sizes, |
|---|
| 4555 | + .validate_version = wm_adsp_validate_version, |
|---|
| 4556 | + .setup_algs = wm_adsp2_setup_algs, |
|---|
| 4557 | + .region_to_reg = wm_adsp_region_to_reg, |
|---|
| 4558 | + |
|---|
| 4559 | + .show_fw_status = wm_adsp2v2_show_fw_status, |
|---|
| 4560 | + .stop_watchdog = wm_adsp_stop_watchdog, |
|---|
| 4561 | + |
|---|
| 4562 | + .enable_memory = wm_adsp2_enable_memory, |
|---|
| 4563 | + .disable_memory = wm_adsp2_disable_memory, |
|---|
| 4564 | + .lock_memory = wm_adsp2_lock, |
|---|
| 4565 | + |
|---|
| 4566 | + .enable_core = wm_adsp2v2_enable_core, |
|---|
| 4567 | + .disable_core = wm_adsp2v2_disable_core, |
|---|
| 4568 | + |
|---|
| 4569 | + .start_core = wm_adsp2_start_core, |
|---|
| 4570 | + .stop_core = wm_adsp2_stop_core, |
|---|
| 4571 | + }, |
|---|
| 4572 | +}; |
|---|
| 4573 | + |
|---|
| 4574 | +static struct wm_adsp_ops wm_halo_ops = { |
|---|
| 4575 | + .sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr), |
|---|
| 4576 | + .parse_sizes = wm_adsp2_parse_sizes, |
|---|
| 4577 | + .validate_version = wm_halo_validate_version, |
|---|
| 4578 | + .setup_algs = wm_halo_setup_algs, |
|---|
| 4579 | + .region_to_reg = wm_halo_region_to_reg, |
|---|
| 4580 | + |
|---|
| 4581 | + .show_fw_status = wm_halo_show_fw_status, |
|---|
| 4582 | + .stop_watchdog = wm_halo_stop_watchdog, |
|---|
| 4583 | + |
|---|
| 4584 | + .lock_memory = wm_halo_configure_mpu, |
|---|
| 4585 | + |
|---|
| 4586 | + .start_core = wm_halo_start_core, |
|---|
| 4587 | + .stop_core = wm_halo_stop_core, |
|---|
| 4588 | +}; |
|---|
| 4589 | + |
|---|
| 3880 | 4590 | MODULE_LICENSE("GPL v2"); |
|---|