1 /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 /* 3 * This file is provided under a dual BSD/GPLv2 license. When using or 4 * redistributing this file, you may do so under either license. 5 * 6 * Copyright(c) 2018 Intel Corporation. All rights reserved. 7 * 8 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> 9 */ 10 11 #ifndef __SOUND_SOC_SOF_IO_H 12 #define __SOUND_SOC_SOF_IO_H 13 14 #include <linux/device.h> 15 #include <linux/interrupt.h> 16 #include <linux/kernel.h> 17 #include <linux/types.h> 18 #include <sound/pcm.h> 19 #include "sof-priv.h" 20 21 #define sof_ops(sdev) \ 22 ((sdev)->pdata->desc->ops) 23 24 /* Mandatory operations are verified during probing */ 25 26 /* init */ 27 static inline int snd_sof_probe(struct snd_sof_dev *sdev) 28 { 29 return sof_ops(sdev)->probe(sdev); 30 } 31 32 static inline int snd_sof_remove(struct snd_sof_dev *sdev) 33 { 34 if (sof_ops(sdev)->remove) 35 return sof_ops(sdev)->remove(sdev); 36 37 return 0; 38 } 39 40 /* control */ 41 42 /* 43 * snd_sof_dsp_run returns the core mask of the cores that are available 44 * after successful fw boot 45 */ 46 static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev) 47 { 48 return sof_ops(sdev)->run(sdev); 49 } 50 51 static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev, unsigned int core_mask) 52 { 53 if (sof_ops(sdev)->stall) 54 return sof_ops(sdev)->stall(sdev, core_mask); 55 56 return 0; 57 } 58 59 static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev) 60 { 61 if (sof_ops(sdev)->reset) 62 return sof_ops(sdev)->reset(sdev); 63 64 return 0; 65 } 66 67 /* dsp core power up/power down */ 68 static inline int snd_sof_dsp_core_power_up(struct snd_sof_dev *sdev, 69 unsigned int core_mask) 70 { 71 if (sof_ops(sdev)->core_power_up) 72 return sof_ops(sdev)->core_power_up(sdev, core_mask); 73 74 return 0; 75 } 76 77 static inline int snd_sof_dsp_core_power_down(struct snd_sof_dev *sdev, 78 unsigned int core_mask) 79 { 80 if (sof_ops(sdev)->core_power_down) 81 return sof_ops(sdev)->core_power_down(sdev, core_mask); 82 83 return 0; 84 } 85 86 /* pre/post fw load */ 87 static inline int snd_sof_dsp_pre_fw_run(struct snd_sof_dev *sdev) 88 { 89 if (sof_ops(sdev)->pre_fw_run) 90 return sof_ops(sdev)->pre_fw_run(sdev); 91 92 return 0; 93 } 94 95 static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev) 96 { 97 if (sof_ops(sdev)->post_fw_run) 98 return sof_ops(sdev)->post_fw_run(sdev); 99 100 return 0; 101 } 102 103 /* parse platform specific extended manifest */ 104 static inline int snd_sof_dsp_parse_platform_ext_manifest(struct snd_sof_dev *sdev, 105 const struct sof_ext_man_elem_header *hdr) 106 { 107 if (sof_ops(sdev)->parse_platform_ext_manifest) 108 return sof_ops(sdev)->parse_platform_ext_manifest(sdev, hdr); 109 110 return 0; 111 } 112 113 /* misc */ 114 115 /** 116 * snd_sof_dsp_get_bar_index - Maps a section type with a BAR index 117 * 118 * @sdev: sof device 119 * @type: section type as described by snd_sof_fw_blk_type 120 * 121 * Returns the corresponding BAR index (a positive integer) or -EINVAL 122 * in case there is no mapping 123 */ 124 static inline int snd_sof_dsp_get_bar_index(struct snd_sof_dev *sdev, u32 type) 125 { 126 if (sof_ops(sdev)->get_bar_index) 127 return sof_ops(sdev)->get_bar_index(sdev, type); 128 129 return sdev->mmio_bar; 130 } 131 132 static inline int snd_sof_dsp_get_mailbox_offset(struct snd_sof_dev *sdev) 133 { 134 if (sof_ops(sdev)->get_mailbox_offset) 135 return sof_ops(sdev)->get_mailbox_offset(sdev); 136 137 dev_err(sdev->dev, "error: %s not defined\n", __func__); 138 return -ENOTSUPP; 139 } 140 141 static inline int snd_sof_dsp_get_window_offset(struct snd_sof_dev *sdev, 142 u32 id) 143 { 144 if (sof_ops(sdev)->get_window_offset) 145 return sof_ops(sdev)->get_window_offset(sdev, id); 146 147 dev_err(sdev->dev, "error: %s not defined\n", __func__); 148 return -ENOTSUPP; 149 } 150 /* power management */ 151 static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) 152 { 153 if (sof_ops(sdev)->resume) 154 return sof_ops(sdev)->resume(sdev); 155 156 return 0; 157 } 158 159 static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev, 160 u32 target_state) 161 { 162 if (sof_ops(sdev)->suspend) 163 return sof_ops(sdev)->suspend(sdev, target_state); 164 165 return 0; 166 } 167 168 static inline int snd_sof_dsp_runtime_resume(struct snd_sof_dev *sdev) 169 { 170 if (sof_ops(sdev)->runtime_resume) 171 return sof_ops(sdev)->runtime_resume(sdev); 172 173 return 0; 174 } 175 176 static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev) 177 { 178 if (sof_ops(sdev)->runtime_suspend) 179 return sof_ops(sdev)->runtime_suspend(sdev); 180 181 return 0; 182 } 183 184 static inline int snd_sof_dsp_runtime_idle(struct snd_sof_dev *sdev) 185 { 186 if (sof_ops(sdev)->runtime_idle) 187 return sof_ops(sdev)->runtime_idle(sdev); 188 189 return 0; 190 } 191 192 static inline int snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev) 193 { 194 if (sof_ops(sdev)->set_hw_params_upon_resume) 195 return sof_ops(sdev)->set_hw_params_upon_resume(sdev); 196 return 0; 197 } 198 199 static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq) 200 { 201 if (sof_ops(sdev)->set_clk) 202 return sof_ops(sdev)->set_clk(sdev, freq); 203 204 return 0; 205 } 206 207 static inline int 208 snd_sof_dsp_set_power_state(struct snd_sof_dev *sdev, 209 const struct sof_dsp_power_state *target_state) 210 { 211 if (sof_ops(sdev)->set_power_state) 212 return sof_ops(sdev)->set_power_state(sdev, target_state); 213 214 /* D0 substate is not supported, do nothing here. */ 215 return 0; 216 } 217 218 /* debug */ 219 static inline void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags) 220 { 221 if (sof_ops(sdev)->dbg_dump) 222 return sof_ops(sdev)->dbg_dump(sdev, flags); 223 } 224 225 static inline void snd_sof_ipc_dump(struct snd_sof_dev *sdev) 226 { 227 if (sof_ops(sdev)->ipc_dump) 228 return sof_ops(sdev)->ipc_dump(sdev); 229 } 230 231 /* register IO */ 232 static inline void snd_sof_dsp_write(struct snd_sof_dev *sdev, u32 bar, 233 u32 offset, u32 value) 234 { 235 if (sof_ops(sdev)->write) { 236 sof_ops(sdev)->write(sdev, sdev->bar[bar] + offset, value); 237 return; 238 } 239 240 dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); 241 } 242 243 static inline void snd_sof_dsp_write64(struct snd_sof_dev *sdev, u32 bar, 244 u32 offset, u64 value) 245 { 246 if (sof_ops(sdev)->write64) { 247 sof_ops(sdev)->write64(sdev, sdev->bar[bar] + offset, value); 248 return; 249 } 250 251 dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); 252 } 253 254 static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar, 255 u32 offset) 256 { 257 if (sof_ops(sdev)->read) 258 return sof_ops(sdev)->read(sdev, sdev->bar[bar] + offset); 259 260 dev_err(sdev->dev, "error: %s not defined\n", __func__); 261 return -ENOTSUPP; 262 } 263 264 static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, 265 u32 offset) 266 { 267 if (sof_ops(sdev)->read64) 268 return sof_ops(sdev)->read64(sdev, sdev->bar[bar] + offset); 269 270 dev_err(sdev->dev, "error: %s not defined\n", __func__); 271 return -ENOTSUPP; 272 } 273 274 /* block IO */ 275 static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, u32 bar, 276 u32 offset, void *dest, size_t bytes) 277 { 278 sof_ops(sdev)->block_read(sdev, bar, offset, dest, bytes); 279 } 280 281 static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, u32 bar, 282 u32 offset, void *src, size_t bytes) 283 { 284 sof_ops(sdev)->block_write(sdev, bar, offset, src, bytes); 285 } 286 287 /* ipc */ 288 static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev, 289 struct snd_sof_ipc_msg *msg) 290 { 291 return sof_ops(sdev)->send_msg(sdev, msg); 292 } 293 294 /* host DMA trace */ 295 static inline int snd_sof_dma_trace_init(struct snd_sof_dev *sdev, 296 u32 *stream_tag) 297 { 298 if (sof_ops(sdev)->trace_init) 299 return sof_ops(sdev)->trace_init(sdev, stream_tag); 300 301 return 0; 302 } 303 304 static inline int snd_sof_dma_trace_release(struct snd_sof_dev *sdev) 305 { 306 if (sof_ops(sdev)->trace_release) 307 return sof_ops(sdev)->trace_release(sdev); 308 309 return 0; 310 } 311 312 static inline int snd_sof_dma_trace_trigger(struct snd_sof_dev *sdev, int cmd) 313 { 314 if (sof_ops(sdev)->trace_trigger) 315 return sof_ops(sdev)->trace_trigger(sdev, cmd); 316 317 return 0; 318 } 319 320 /* host PCM ops */ 321 static inline int 322 snd_sof_pcm_platform_open(struct snd_sof_dev *sdev, 323 struct snd_pcm_substream *substream) 324 { 325 if (sof_ops(sdev) && sof_ops(sdev)->pcm_open) 326 return sof_ops(sdev)->pcm_open(sdev, substream); 327 328 return 0; 329 } 330 331 /* disconnect pcm substream to a host stream */ 332 static inline int 333 snd_sof_pcm_platform_close(struct snd_sof_dev *sdev, 334 struct snd_pcm_substream *substream) 335 { 336 if (sof_ops(sdev) && sof_ops(sdev)->pcm_close) 337 return sof_ops(sdev)->pcm_close(sdev, substream); 338 339 return 0; 340 } 341 342 /* host stream hw params */ 343 static inline int 344 snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev, 345 struct snd_pcm_substream *substream, 346 struct snd_pcm_hw_params *params, 347 struct sof_ipc_stream_params *ipc_params) 348 { 349 if (sof_ops(sdev) && sof_ops(sdev)->pcm_hw_params) 350 return sof_ops(sdev)->pcm_hw_params(sdev, substream, 351 params, ipc_params); 352 353 return 0; 354 } 355 356 /* host stream hw free */ 357 static inline int 358 snd_sof_pcm_platform_hw_free(struct snd_sof_dev *sdev, 359 struct snd_pcm_substream *substream) 360 { 361 if (sof_ops(sdev) && sof_ops(sdev)->pcm_hw_free) 362 return sof_ops(sdev)->pcm_hw_free(sdev, substream); 363 364 return 0; 365 } 366 367 /* host stream trigger */ 368 static inline int 369 snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev, 370 struct snd_pcm_substream *substream, int cmd) 371 { 372 if (sof_ops(sdev) && sof_ops(sdev)->pcm_trigger) 373 return sof_ops(sdev)->pcm_trigger(sdev, substream, cmd); 374 375 return 0; 376 } 377 378 /* host DSP message data */ 379 static inline void snd_sof_ipc_msg_data(struct snd_sof_dev *sdev, 380 struct snd_pcm_substream *substream, 381 void *p, size_t sz) 382 { 383 sof_ops(sdev)->ipc_msg_data(sdev, substream, p, sz); 384 } 385 386 /* host configure DSP HW parameters */ 387 static inline int 388 snd_sof_ipc_pcm_params(struct snd_sof_dev *sdev, 389 struct snd_pcm_substream *substream, 390 const struct sof_ipc_pcm_params_reply *reply) 391 { 392 return sof_ops(sdev)->ipc_pcm_params(sdev, substream, reply); 393 } 394 395 /* host stream pointer */ 396 static inline snd_pcm_uframes_t 397 snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev, 398 struct snd_pcm_substream *substream) 399 { 400 if (sof_ops(sdev) && sof_ops(sdev)->pcm_pointer) 401 return sof_ops(sdev)->pcm_pointer(sdev, substream); 402 403 return 0; 404 } 405 406 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) 407 static inline int 408 snd_sof_probe_compr_assign(struct snd_sof_dev *sdev, 409 struct snd_compr_stream *cstream, struct snd_soc_dai *dai) 410 { 411 return sof_ops(sdev)->probe_assign(sdev, cstream, dai); 412 } 413 414 static inline int 415 snd_sof_probe_compr_free(struct snd_sof_dev *sdev, 416 struct snd_compr_stream *cstream, struct snd_soc_dai *dai) 417 { 418 return sof_ops(sdev)->probe_free(sdev, cstream, dai); 419 } 420 421 static inline int 422 snd_sof_probe_compr_set_params(struct snd_sof_dev *sdev, 423 struct snd_compr_stream *cstream, 424 struct snd_compr_params *params, struct snd_soc_dai *dai) 425 { 426 return sof_ops(sdev)->probe_set_params(sdev, cstream, params, dai); 427 } 428 429 static inline int 430 snd_sof_probe_compr_trigger(struct snd_sof_dev *sdev, 431 struct snd_compr_stream *cstream, int cmd, 432 struct snd_soc_dai *dai) 433 { 434 return sof_ops(sdev)->probe_trigger(sdev, cstream, cmd, dai); 435 } 436 437 static inline int 438 snd_sof_probe_compr_pointer(struct snd_sof_dev *sdev, 439 struct snd_compr_stream *cstream, 440 struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai) 441 { 442 if (sof_ops(sdev) && sof_ops(sdev)->probe_pointer) 443 return sof_ops(sdev)->probe_pointer(sdev, cstream, tstamp, dai); 444 445 return 0; 446 } 447 #endif 448 449 /* machine driver */ 450 static inline int 451 snd_sof_machine_register(struct snd_sof_dev *sdev, void *pdata) 452 { 453 if (sof_ops(sdev) && sof_ops(sdev)->machine_register) 454 return sof_ops(sdev)->machine_register(sdev, pdata); 455 456 return 0; 457 } 458 459 static inline void 460 snd_sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata) 461 { 462 if (sof_ops(sdev) && sof_ops(sdev)->machine_unregister) 463 sof_ops(sdev)->machine_unregister(sdev, pdata); 464 } 465 466 static inline void 467 snd_sof_machine_select(struct snd_sof_dev *sdev) 468 { 469 if (sof_ops(sdev) && sof_ops(sdev)->machine_select) 470 sof_ops(sdev)->machine_select(sdev); 471 } 472 473 static inline void 474 snd_sof_set_mach_params(const struct snd_soc_acpi_mach *mach, 475 struct device *dev) 476 { 477 struct snd_sof_dev *sdev = dev_get_drvdata(dev); 478 479 if (sof_ops(sdev) && sof_ops(sdev)->set_mach_params) 480 sof_ops(sdev)->set_mach_params(mach, dev); 481 } 482 483 static inline const struct snd_sof_dsp_ops 484 *sof_get_ops(const struct sof_dev_desc *d, 485 const struct sof_ops_table mach_ops[], int asize) 486 { 487 int i; 488 489 for (i = 0; i < asize; i++) { 490 if (d == mach_ops[i].desc) 491 return mach_ops[i].ops; 492 } 493 494 /* not found */ 495 return NULL; 496 } 497 498 /** 499 * snd_sof_dsp_register_poll_timeout - Periodically poll an address 500 * until a condition is met or a timeout occurs 501 * @op: accessor function (takes @addr as its only argument) 502 * @addr: Address to poll 503 * @val: Variable to read the value into 504 * @cond: Break condition (usually involving @val) 505 * @sleep_us: Maximum time to sleep between reads in us (0 506 * tight-loops). Should be less than ~20ms since usleep_range 507 * is used (see Documentation/timers/timers-howto.rst). 508 * @timeout_us: Timeout in us, 0 means never timeout 509 * 510 * Returns 0 on success and -ETIMEDOUT upon a timeout. In either 511 * case, the last read value at @addr is stored in @val. Must not 512 * be called from atomic context if sleep_us or timeout_us are used. 513 * 514 * This is modelled after the readx_poll_timeout macros in linux/iopoll.h. 515 */ 516 #define snd_sof_dsp_read_poll_timeout(sdev, bar, offset, val, cond, sleep_us, timeout_us) \ 517 ({ \ 518 u64 __timeout_us = (timeout_us); \ 519 unsigned long __sleep_us = (sleep_us); \ 520 ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \ 521 might_sleep_if((__sleep_us) != 0); \ 522 for (;;) { \ 523 (val) = snd_sof_dsp_read(sdev, bar, offset); \ 524 if (cond) { \ 525 dev_dbg(sdev->dev, \ 526 "FW Poll Status: reg=%#x successful\n", (val)); \ 527 break; \ 528 } \ 529 if (__timeout_us && \ 530 ktime_compare(ktime_get(), __timeout) > 0) { \ 531 (val) = snd_sof_dsp_read(sdev, bar, offset); \ 532 dev_dbg(sdev->dev, \ 533 "FW Poll Status: reg=%#x timedout\n", (val)); \ 534 break; \ 535 } \ 536 if (__sleep_us) \ 537 usleep_range((__sleep_us >> 2) + 1, __sleep_us); \ 538 } \ 539 (cond) ? 0 : -ETIMEDOUT; \ 540 }) 541 542 /* This is for registers bits with attribute RWC */ 543 bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, 544 u32 mask, u32 value); 545 546 bool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, 547 u32 offset, u32 mask, u32 value); 548 549 bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, 550 u32 offset, u64 mask, u64 value); 551 552 bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, 553 u32 mask, u32 value); 554 555 bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, 556 u32 offset, u64 mask, u64 value); 557 558 void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, 559 u32 offset, u32 mask, u32 value); 560 561 int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, 562 u32 mask, u32 target, u32 timeout_ms, 563 u32 interval_us); 564 565 void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset); 566 #endif 567