| .. | .. |
|---|
| 8 | 8 | |
|---|
| 9 | 9 | #include <linux/device.h> |
|---|
| 10 | 10 | #include <linux/interrupt.h> |
|---|
| 11 | +#include <linux/io.h> |
|---|
| 11 | 12 | #include <linux/pm_runtime.h> |
|---|
| 12 | 13 | #include <linux/timecounter.h> |
|---|
| 13 | 14 | #include <sound/core.h> |
|---|
| .. | .. |
|---|
| 79 | 80 | |
|---|
| 80 | 81 | /* misc flags */ |
|---|
| 81 | 82 | atomic_t in_pm; /* suspend/resume being performed */ |
|---|
| 82 | | - bool link_power_control:1; |
|---|
| 83 | 83 | |
|---|
| 84 | 84 | /* sysfs */ |
|---|
| 85 | + struct mutex widget_lock; |
|---|
| 85 | 86 | struct hdac_widget_tree *widgets; |
|---|
| 86 | 87 | |
|---|
| 87 | 88 | /* regmap */ |
|---|
| 88 | 89 | struct regmap *regmap; |
|---|
| 90 | + struct mutex regmap_lock; |
|---|
| 89 | 91 | struct snd_array vendor_verbs; |
|---|
| 90 | 92 | bool lazy_cache:1; /* don't wake up for writes */ |
|---|
| 91 | 93 | bool caps_overwriting:1; /* caps overwrite being in process */ |
|---|
| .. | .. |
|---|
| 97 | 99 | HDA_DEV_CORE, |
|---|
| 98 | 100 | HDA_DEV_LEGACY, |
|---|
| 99 | 101 | HDA_DEV_ASOC, |
|---|
| 102 | +}; |
|---|
| 103 | + |
|---|
| 104 | +enum { |
|---|
| 105 | + SND_SKL_PCI_BIND_AUTO, /* automatic selection based on pci class */ |
|---|
| 106 | + SND_SKL_PCI_BIND_LEGACY,/* bind only with legacy driver */ |
|---|
| 107 | + SND_SKL_PCI_BIND_ASOC /* bind only with ASoC driver */ |
|---|
| 100 | 108 | }; |
|---|
| 101 | 109 | |
|---|
| 102 | 110 | /* direction */ |
|---|
| .. | .. |
|---|
| 114 | 122 | int snd_hdac_device_set_chip_name(struct hdac_device *codec, const char *name); |
|---|
| 115 | 123 | int snd_hdac_codec_modalias(struct hdac_device *hdac, char *buf, size_t size); |
|---|
| 116 | 124 | |
|---|
| 117 | | -int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs); |
|---|
| 125 | +int snd_hdac_refresh_widgets(struct hdac_device *codec); |
|---|
| 118 | 126 | |
|---|
| 119 | | -unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, |
|---|
| 120 | | - unsigned int verb, unsigned int parm); |
|---|
| 121 | | -int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd, |
|---|
| 122 | | - unsigned int flags, unsigned int *res); |
|---|
| 123 | 127 | int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid, |
|---|
| 124 | 128 | unsigned int verb, unsigned int parm, unsigned int *res); |
|---|
| 125 | 129 | int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm, |
|---|
| .. | .. |
|---|
| 203 | 207 | static inline int snd_hdac_keep_power_up(struct hdac_device *codec) { return 0; } |
|---|
| 204 | 208 | static inline void snd_hdac_enter_pm(struct hdac_device *codec) {} |
|---|
| 205 | 209 | static inline void snd_hdac_leave_pm(struct hdac_device *codec) {} |
|---|
| 206 | | -static inline bool snd_hdac_is_in_pm(struct hdac_device *codec) { return 0; } |
|---|
| 207 | | -static inline bool snd_hdac_is_power_on(struct hdac_device *codec) { return 1; } |
|---|
| 210 | +static inline bool snd_hdac_is_in_pm(struct hdac_device *codec) { return false; } |
|---|
| 211 | +static inline bool snd_hdac_is_power_on(struct hdac_device *codec) { return true; } |
|---|
| 208 | 212 | #endif |
|---|
| 209 | 213 | |
|---|
| 210 | 214 | /* |
|---|
| .. | .. |
|---|
| 237 | 241 | /* get a response from the last command */ |
|---|
| 238 | 242 | int (*get_response)(struct hdac_bus *bus, unsigned int addr, |
|---|
| 239 | 243 | unsigned int *res); |
|---|
| 240 | | - /* control the link power */ |
|---|
| 241 | | - int (*link_power)(struct hdac_bus *bus, bool enable); |
|---|
| 242 | 244 | }; |
|---|
| 243 | 245 | |
|---|
| 244 | 246 | /* |
|---|
| .. | .. |
|---|
| 247 | 249 | struct hdac_ext_bus_ops { |
|---|
| 248 | 250 | int (*hdev_attach)(struct hdac_device *hdev); |
|---|
| 249 | 251 | int (*hdev_detach)(struct hdac_device *hdev); |
|---|
| 250 | | -}; |
|---|
| 251 | | - |
|---|
| 252 | | -/* |
|---|
| 253 | | - * Lowlevel I/O operators |
|---|
| 254 | | - */ |
|---|
| 255 | | -struct hdac_io_ops { |
|---|
| 256 | | - /* mapped register accesses */ |
|---|
| 257 | | - void (*reg_writel)(u32 value, u32 __iomem *addr); |
|---|
| 258 | | - u32 (*reg_readl)(u32 __iomem *addr); |
|---|
| 259 | | - void (*reg_writew)(u16 value, u16 __iomem *addr); |
|---|
| 260 | | - u16 (*reg_readw)(u16 __iomem *addr); |
|---|
| 261 | | - void (*reg_writeb)(u8 value, u8 __iomem *addr); |
|---|
| 262 | | - u8 (*reg_readb)(u8 __iomem *addr); |
|---|
| 263 | | - /* Allocation ops */ |
|---|
| 264 | | - int (*dma_alloc_pages)(struct hdac_bus *bus, int type, size_t size, |
|---|
| 265 | | - struct snd_dma_buffer *buf); |
|---|
| 266 | | - void (*dma_free_pages)(struct hdac_bus *bus, |
|---|
| 267 | | - struct snd_dma_buffer *buf); |
|---|
| 268 | 252 | }; |
|---|
| 269 | 253 | |
|---|
| 270 | 254 | #define HDA_UNSOL_QUEUE_SIZE 64 |
|---|
| .. | .. |
|---|
| 294 | 278 | * @num_streams: streams supported |
|---|
| 295 | 279 | * @idx: HDA link index |
|---|
| 296 | 280 | * @hlink_list: link list of HDA links |
|---|
| 297 | | - * @lock: lock for link mgmt |
|---|
| 281 | + * @lock: lock for link and display power mgmt |
|---|
| 298 | 282 | * @cmd_dma_state: state of cmd DMAs: CORB and RIRB |
|---|
| 299 | 283 | */ |
|---|
| 300 | 284 | struct hdac_bus { |
|---|
| 301 | 285 | struct device *dev; |
|---|
| 302 | 286 | const struct hdac_bus_ops *ops; |
|---|
| 303 | | - const struct hdac_io_ops *io_ops; |
|---|
| 304 | 287 | const struct hdac_ext_bus_ops *ext_ops; |
|---|
| 305 | 288 | |
|---|
| 306 | 289 | /* h/w resources */ |
|---|
| .. | .. |
|---|
| 336 | 319 | struct hdac_rb corb; |
|---|
| 337 | 320 | struct hdac_rb rirb; |
|---|
| 338 | 321 | unsigned int last_cmd[HDA_MAX_CODECS]; /* last sent command */ |
|---|
| 322 | + wait_queue_head_t rirb_wq; |
|---|
| 339 | 323 | |
|---|
| 340 | 324 | /* CORB/RIRB and position buffers */ |
|---|
| 341 | 325 | struct snd_dma_buffer rb; |
|---|
| 342 | 326 | struct snd_dma_buffer posbuf; |
|---|
| 327 | + int dma_type; /* SNDRV_DMA_TYPE_XXX for CORB/RIRB */ |
|---|
| 343 | 328 | |
|---|
| 344 | 329 | /* hdac_stream linked list */ |
|---|
| 345 | 330 | struct list_head stream_list; |
|---|
| .. | .. |
|---|
| 348 | 333 | bool chip_init:1; /* h/w initialized */ |
|---|
| 349 | 334 | |
|---|
| 350 | 335 | /* behavior flags */ |
|---|
| 336 | + bool aligned_mmio:1; /* aligned MMIO access */ |
|---|
| 351 | 337 | bool sync_write:1; /* sync after verb write */ |
|---|
| 352 | 338 | bool use_posbuf:1; /* use position buffer */ |
|---|
| 353 | 339 | bool snoop:1; /* enable snooping */ |
|---|
| 354 | 340 | bool align_bdle_4k:1; /* BDLE align 4K boundary */ |
|---|
| 355 | 341 | bool reverse_assign:1; /* assign devices in reverse order */ |
|---|
| 356 | 342 | bool corbrp_self_clear:1; /* CORBRP clears itself after reset */ |
|---|
| 343 | + bool polling_mode:1; |
|---|
| 344 | + bool needs_damn_long_delay:1; |
|---|
| 345 | + |
|---|
| 346 | + int poll_count; |
|---|
| 357 | 347 | |
|---|
| 358 | 348 | int bdl_pos_adj; /* BDL position adjustment */ |
|---|
| 349 | + |
|---|
| 350 | + /* delay time in us for dma stop */ |
|---|
| 351 | + unsigned int dma_stop_delay; |
|---|
| 359 | 352 | |
|---|
| 360 | 353 | /* locks */ |
|---|
| 361 | 354 | spinlock_t reg_lock; |
|---|
| 362 | 355 | struct mutex cmd_mutex; |
|---|
| 356 | + struct mutex lock; |
|---|
| 363 | 357 | |
|---|
| 364 | 358 | /* DRM component interface */ |
|---|
| 365 | 359 | struct drm_audio_component *audio_component; |
|---|
| 366 | | - int drm_power_refcount; |
|---|
| 360 | + long display_power_status; |
|---|
| 361 | + unsigned long display_power_active; |
|---|
| 367 | 362 | |
|---|
| 368 | 363 | /* parameters required for enhanced capabilities */ |
|---|
| 369 | 364 | int num_streams; |
|---|
| 370 | 365 | int idx; |
|---|
| 371 | 366 | |
|---|
| 367 | + /* link management */ |
|---|
| 372 | 368 | struct list_head hlink_list; |
|---|
| 373 | | - |
|---|
| 374 | | - struct mutex lock; |
|---|
| 375 | 369 | bool cmd_dma_state; |
|---|
| 376 | 370 | |
|---|
| 371 | + /* factor used to derive STRIPE control value */ |
|---|
| 372 | + unsigned int sdo_limit; |
|---|
| 377 | 373 | }; |
|---|
| 378 | 374 | |
|---|
| 379 | 375 | int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, |
|---|
| 380 | | - const struct hdac_bus_ops *ops, |
|---|
| 381 | | - const struct hdac_io_ops *io_ops); |
|---|
| 376 | + const struct hdac_bus_ops *ops); |
|---|
| 382 | 377 | void snd_hdac_bus_exit(struct hdac_bus *bus); |
|---|
| 383 | | -int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr, |
|---|
| 384 | | - unsigned int cmd, unsigned int *res); |
|---|
| 385 | 378 | int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr, |
|---|
| 386 | 379 | unsigned int cmd, unsigned int *res); |
|---|
| 387 | | -void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex); |
|---|
| 388 | | - |
|---|
| 389 | | -int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec); |
|---|
| 390 | | -void snd_hdac_bus_remove_device(struct hdac_bus *bus, |
|---|
| 391 | | - struct hdac_device *codec); |
|---|
| 392 | 380 | |
|---|
| 393 | 381 | static inline void snd_hdac_codec_link_up(struct hdac_device *codec) |
|---|
| 394 | 382 | { |
|---|
| .. | .. |
|---|
| 404 | 392 | int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, |
|---|
| 405 | 393 | unsigned int *res); |
|---|
| 406 | 394 | int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus); |
|---|
| 407 | | -int snd_hdac_link_power(struct hdac_device *codec, bool enable); |
|---|
| 408 | 395 | |
|---|
| 409 | 396 | bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset); |
|---|
| 410 | 397 | void snd_hdac_bus_stop_chip(struct hdac_bus *bus); |
|---|
| .. | .. |
|---|
| 422 | 409 | int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus); |
|---|
| 423 | 410 | void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus); |
|---|
| 424 | 411 | |
|---|
| 412 | +#ifdef CONFIG_SND_HDA_ALIGNED_MMIO |
|---|
| 413 | +unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask); |
|---|
| 414 | +void snd_hdac_aligned_write(unsigned int val, void __iomem *addr, |
|---|
| 415 | + unsigned int mask); |
|---|
| 416 | +#define snd_hdac_aligned_mmio(bus) (bus)->aligned_mmio |
|---|
| 417 | +#else |
|---|
| 418 | +#define snd_hdac_aligned_mmio(bus) false |
|---|
| 419 | +#define snd_hdac_aligned_read(addr, mask) 0 |
|---|
| 420 | +#define snd_hdac_aligned_write(val, addr, mask) do {} while (0) |
|---|
| 421 | +#endif |
|---|
| 422 | + |
|---|
| 423 | +static inline void snd_hdac_reg_writeb(struct hdac_bus *bus, void __iomem *addr, |
|---|
| 424 | + u8 val) |
|---|
| 425 | +{ |
|---|
| 426 | + if (snd_hdac_aligned_mmio(bus)) |
|---|
| 427 | + snd_hdac_aligned_write(val, addr, 0xff); |
|---|
| 428 | + else |
|---|
| 429 | + writeb(val, addr); |
|---|
| 430 | +} |
|---|
| 431 | + |
|---|
| 432 | +static inline void snd_hdac_reg_writew(struct hdac_bus *bus, void __iomem *addr, |
|---|
| 433 | + u16 val) |
|---|
| 434 | +{ |
|---|
| 435 | + if (snd_hdac_aligned_mmio(bus)) |
|---|
| 436 | + snd_hdac_aligned_write(val, addr, 0xffff); |
|---|
| 437 | + else |
|---|
| 438 | + writew(val, addr); |
|---|
| 439 | +} |
|---|
| 440 | + |
|---|
| 441 | +static inline u8 snd_hdac_reg_readb(struct hdac_bus *bus, void __iomem *addr) |
|---|
| 442 | +{ |
|---|
| 443 | + return snd_hdac_aligned_mmio(bus) ? |
|---|
| 444 | + snd_hdac_aligned_read(addr, 0xff) : readb(addr); |
|---|
| 445 | +} |
|---|
| 446 | + |
|---|
| 447 | +static inline u16 snd_hdac_reg_readw(struct hdac_bus *bus, void __iomem *addr) |
|---|
| 448 | +{ |
|---|
| 449 | + return snd_hdac_aligned_mmio(bus) ? |
|---|
| 450 | + snd_hdac_aligned_read(addr, 0xffff) : readw(addr); |
|---|
| 451 | +} |
|---|
| 452 | + |
|---|
| 453 | +#define snd_hdac_reg_writel(bus, addr, val) writel(val, addr) |
|---|
| 454 | +#define snd_hdac_reg_readl(bus, addr) readl(addr) |
|---|
| 455 | + |
|---|
| 425 | 456 | /* |
|---|
| 426 | 457 | * macros for easy use |
|---|
| 427 | 458 | */ |
|---|
| 428 | 459 | #define _snd_hdac_chip_writeb(chip, reg, value) \ |
|---|
| 429 | | - ((chip)->io_ops->reg_writeb(value, (chip)->remap_addr + (reg))) |
|---|
| 460 | + snd_hdac_reg_writeb(chip, (chip)->remap_addr + (reg), value) |
|---|
| 430 | 461 | #define _snd_hdac_chip_readb(chip, reg) \ |
|---|
| 431 | | - ((chip)->io_ops->reg_readb((chip)->remap_addr + (reg))) |
|---|
| 462 | + snd_hdac_reg_readb(chip, (chip)->remap_addr + (reg)) |
|---|
| 432 | 463 | #define _snd_hdac_chip_writew(chip, reg, value) \ |
|---|
| 433 | | - ((chip)->io_ops->reg_writew(value, (chip)->remap_addr + (reg))) |
|---|
| 464 | + snd_hdac_reg_writew(chip, (chip)->remap_addr + (reg), value) |
|---|
| 434 | 465 | #define _snd_hdac_chip_readw(chip, reg) \ |
|---|
| 435 | | - ((chip)->io_ops->reg_readw((chip)->remap_addr + (reg))) |
|---|
| 466 | + snd_hdac_reg_readw(chip, (chip)->remap_addr + (reg)) |
|---|
| 436 | 467 | #define _snd_hdac_chip_writel(chip, reg, value) \ |
|---|
| 437 | | - ((chip)->io_ops->reg_writel(value, (chip)->remap_addr + (reg))) |
|---|
| 468 | + snd_hdac_reg_writel(chip, (chip)->remap_addr + (reg), value) |
|---|
| 438 | 469 | #define _snd_hdac_chip_readl(chip, reg) \ |
|---|
| 439 | | - ((chip)->io_ops->reg_readl((chip)->remap_addr + (reg))) |
|---|
| 470 | + snd_hdac_reg_readl(chip, (chip)->remap_addr + (reg)) |
|---|
| 440 | 471 | |
|---|
| 441 | 472 | /* read/write a register, pass without AZX_REG_ prefix */ |
|---|
| 442 | 473 | #define snd_hdac_chip_writel(chip, reg, value) \ |
|---|
| .. | .. |
|---|
| 485 | 516 | struct snd_pcm_substream *substream; /* assigned substream, |
|---|
| 486 | 517 | * set in PCM open |
|---|
| 487 | 518 | */ |
|---|
| 519 | + struct snd_compr_stream *cstream; |
|---|
| 488 | 520 | unsigned int format_val; /* format value to be set in the |
|---|
| 489 | 521 | * controller and the codec |
|---|
| 490 | 522 | */ |
|---|
| .. | .. |
|---|
| 497 | 529 | bool prepared:1; |
|---|
| 498 | 530 | bool no_period_wakeup:1; |
|---|
| 499 | 531 | bool locked:1; |
|---|
| 532 | + bool stripe:1; /* apply stripe control */ |
|---|
| 500 | 533 | |
|---|
| 534 | + u64 curr_pos; |
|---|
| 501 | 535 | /* timestamp */ |
|---|
| 502 | 536 | unsigned long start_wallclk; /* start + minimum wallclk */ |
|---|
| 503 | 537 | unsigned long period_wallclk; /* wallclk for period */ |
|---|
| .. | .. |
|---|
| 528 | 562 | void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start); |
|---|
| 529 | 563 | void snd_hdac_stream_clear(struct hdac_stream *azx_dev); |
|---|
| 530 | 564 | void snd_hdac_stream_stop(struct hdac_stream *azx_dev); |
|---|
| 565 | +void snd_hdac_stop_streams(struct hdac_bus *bus); |
|---|
| 566 | +void snd_hdac_stop_streams_and_chip(struct hdac_bus *bus); |
|---|
| 531 | 567 | void snd_hdac_stream_reset(struct hdac_stream *azx_dev); |
|---|
| 532 | 568 | void snd_hdac_stream_sync_trigger(struct hdac_stream *azx_dev, bool set, |
|---|
| 533 | 569 | unsigned int streams, unsigned int reg); |
|---|
| .. | .. |
|---|
| 535 | 571 | unsigned int streams); |
|---|
| 536 | 572 | void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev, |
|---|
| 537 | 573 | unsigned int streams); |
|---|
| 574 | +int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus, |
|---|
| 575 | + struct snd_pcm_substream *substream); |
|---|
| 576 | + |
|---|
| 538 | 577 | /* |
|---|
| 539 | 578 | * macros for easy use |
|---|
| 540 | 579 | */ |
|---|
| 541 | | -#define _snd_hdac_stream_write(type, dev, reg, value) \ |
|---|
| 542 | | - ((dev)->bus->io_ops->reg_write ## type(value, (dev)->sd_addr + (reg))) |
|---|
| 543 | | -#define _snd_hdac_stream_read(type, dev, reg) \ |
|---|
| 544 | | - ((dev)->bus->io_ops->reg_read ## type((dev)->sd_addr + (reg))) |
|---|
| 545 | | - |
|---|
| 546 | 580 | /* read/write a register, pass without AZX_REG_ prefix */ |
|---|
| 547 | 581 | #define snd_hdac_stream_writel(dev, reg, value) \ |
|---|
| 548 | | - _snd_hdac_stream_write(l, dev, AZX_REG_ ## reg, value) |
|---|
| 582 | + snd_hdac_reg_writel((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg, value) |
|---|
| 549 | 583 | #define snd_hdac_stream_writew(dev, reg, value) \ |
|---|
| 550 | | - _snd_hdac_stream_write(w, dev, AZX_REG_ ## reg, value) |
|---|
| 584 | + snd_hdac_reg_writew((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg, value) |
|---|
| 551 | 585 | #define snd_hdac_stream_writeb(dev, reg, value) \ |
|---|
| 552 | | - _snd_hdac_stream_write(b, dev, AZX_REG_ ## reg, value) |
|---|
| 586 | + snd_hdac_reg_writeb((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg, value) |
|---|
| 553 | 587 | #define snd_hdac_stream_readl(dev, reg) \ |
|---|
| 554 | | - _snd_hdac_stream_read(l, dev, AZX_REG_ ## reg) |
|---|
| 588 | + snd_hdac_reg_readl((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg) |
|---|
| 555 | 589 | #define snd_hdac_stream_readw(dev, reg) \ |
|---|
| 556 | | - _snd_hdac_stream_read(w, dev, AZX_REG_ ## reg) |
|---|
| 590 | + snd_hdac_reg_readw((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg) |
|---|
| 557 | 591 | #define snd_hdac_stream_readb(dev, reg) \ |
|---|
| 558 | | - _snd_hdac_stream_read(b, dev, AZX_REG_ ## reg) |
|---|
| 592 | + snd_hdac_reg_readb((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg) |
|---|
| 559 | 593 | |
|---|
| 560 | 594 | /* update a register, pass without AZX_REG_ prefix */ |
|---|
| 561 | 595 | #define snd_hdac_stream_updatel(dev, reg, mask, val) \ |
|---|