diff options
author | Mark Brown <broonie@kernel.org> | 2016-01-10 07:13:34 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-01-10 07:13:34 -0500 |
commit | 648e3a5bdddf8e7ad9c27450ac368b8bccd807a5 (patch) | |
tree | f5db76d41d4c691a8d4417f0385d5f1b8c9b6b63 | |
parent | 15b914476bf24185534a59fb8e149d465ff79c59 (diff) | |
parent | 6706a19747eb693ff35ce140f5cbee66dcfec0c4 (diff) |
Merge branch 'topic/hdac' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-intel
-rw-r--r-- | include/sound/hda_register.h | 9 | ||||
-rw-r--r-- | include/sound/hdaudio_ext.h | 15 | ||||
-rw-r--r-- | sound/hda/ext/hdac_ext_controller.c | 29 | ||||
-rw-r--r-- | sound/hda/ext/hdac_ext_stream.c | 72 |
4 files changed, 124 insertions, 1 deletions
diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index 94dc6a9772e0..ff1aecf325e8 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h | |||
@@ -233,6 +233,15 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
233 | #define AZX_MLCTL_SPA (1<<16) | 233 | #define AZX_MLCTL_SPA (1<<16) |
234 | #define AZX_MLCTL_CPA 23 | 234 | #define AZX_MLCTL_CPA 23 |
235 | 235 | ||
236 | |||
237 | /* registers for DMA Resume Capability Structure */ | ||
238 | #define AZX_DRSM_CAP_ID 0x5 | ||
239 | #define AZX_REG_DRSM_CTL 0x4 | ||
240 | /* Base used to calculate the iterating register offset */ | ||
241 | #define AZX_DRSM_BASE 0x08 | ||
242 | /* Interval used to calculate the iterating register offset */ | ||
243 | #define AZX_DRSM_INTERVAL 0x08 | ||
244 | |||
236 | /* | 245 | /* |
237 | * helpers to read the stream position | 246 | * helpers to read the stream position |
238 | */ | 247 | */ |
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index 425af0674557..07fa59237feb 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h | |||
@@ -12,6 +12,7 @@ | |||
12 | * @spbcap: SPIB capabilities pointer | 12 | * @spbcap: SPIB capabilities pointer |
13 | * @mlcap: MultiLink capabilities pointer | 13 | * @mlcap: MultiLink capabilities pointer |
14 | * @gtscap: gts capabilities pointer | 14 | * @gtscap: gts capabilities pointer |
15 | * @drsmcap: dma resume capabilities pointer | ||
15 | * @hlink_list: link list of HDA links | 16 | * @hlink_list: link list of HDA links |
16 | */ | 17 | */ |
17 | struct hdac_ext_bus { | 18 | struct hdac_ext_bus { |
@@ -23,6 +24,7 @@ struct hdac_ext_bus { | |||
23 | void __iomem *spbcap; | 24 | void __iomem *spbcap; |
24 | void __iomem *mlcap; | 25 | void __iomem *mlcap; |
25 | void __iomem *gtscap; | 26 | void __iomem *gtscap; |
27 | void __iomem *drsmcap; | ||
26 | 28 | ||
27 | struct list_head hlink_list; | 29 | struct list_head hlink_list; |
28 | }; | 30 | }; |
@@ -72,6 +74,9 @@ enum hdac_ext_stream_type { | |||
72 | * @pplc_addr: processing pipe link stream pointer | 74 | * @pplc_addr: processing pipe link stream pointer |
73 | * @spib_addr: software position in buffers stream pointer | 75 | * @spib_addr: software position in buffers stream pointer |
74 | * @fifo_addr: software position Max fifos stream pointer | 76 | * @fifo_addr: software position Max fifos stream pointer |
77 | * @dpibr_addr: DMA position in buffer resume pointer | ||
78 | * @dpib: DMA position in buffer | ||
79 | * @lpib: Linear position in buffer | ||
75 | * @decoupled: stream host and link is decoupled | 80 | * @decoupled: stream host and link is decoupled |
76 | * @link_locked: link is locked | 81 | * @link_locked: link is locked |
77 | * @link_prepared: link is prepared | 82 | * @link_prepared: link is prepared |
@@ -86,6 +91,10 @@ struct hdac_ext_stream { | |||
86 | void __iomem *spib_addr; | 91 | void __iomem *spib_addr; |
87 | void __iomem *fifo_addr; | 92 | void __iomem *fifo_addr; |
88 | 93 | ||
94 | void __iomem *dpibr_addr; | ||
95 | |||
96 | u32 dpib; | ||
97 | u32 lpib; | ||
89 | bool decoupled:1; | 98 | bool decoupled:1; |
90 | bool link_locked:1; | 99 | bool link_locked:1; |
91 | bool link_prepared; | 100 | bool link_prepared; |
@@ -116,6 +125,11 @@ int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus, | |||
116 | struct hdac_ext_stream *stream, u32 value); | 125 | struct hdac_ext_stream *stream, u32 value); |
117 | int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus, | 126 | int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus, |
118 | struct hdac_ext_stream *stream); | 127 | struct hdac_ext_stream *stream); |
128 | void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus, | ||
129 | bool enable, int index); | ||
130 | int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus, | ||
131 | struct hdac_ext_stream *stream, u32 value); | ||
132 | int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value); | ||
119 | 133 | ||
120 | void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hstream); | 134 | void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hstream); |
121 | void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hstream); | 135 | void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hstream); |
@@ -133,6 +147,7 @@ struct hdac_ext_link { | |||
133 | 147 | ||
134 | int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link); | 148 | int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link); |
135 | int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link); | 149 | int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link); |
150 | int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus); | ||
136 | int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus); | 151 | int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus); |
137 | void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, | 152 | void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, |
138 | int stream); | 153 | int stream); |
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 63215b17247c..548cc1e4114b 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c | |||
@@ -77,6 +77,12 @@ int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus) | |||
77 | ebus->spbcap = bus->remap_addr + offset; | 77 | ebus->spbcap = bus->remap_addr + offset; |
78 | break; | 78 | break; |
79 | 79 | ||
80 | case AZX_DRSM_CAP_ID: | ||
81 | /* DMA resume capability found, handler function */ | ||
82 | dev_dbg(bus->dev, "Found DRSM capability\n"); | ||
83 | ebus->drsmcap = bus->remap_addr + offset; | ||
84 | break; | ||
85 | |||
80 | default: | 86 | default: |
81 | dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap); | 87 | dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap); |
82 | break; | 88 | break; |
@@ -240,7 +246,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) | |||
240 | int mask = (1 << AZX_MLCTL_CPA); | 246 | int mask = (1 << AZX_MLCTL_CPA); |
241 | 247 | ||
242 | udelay(3); | 248 | udelay(3); |
243 | timeout = 50; | 249 | timeout = 150; |
244 | 250 | ||
245 | do { | 251 | do { |
246 | val = readl(link->ml_addr + AZX_REG_ML_LCTL); | 252 | val = readl(link->ml_addr + AZX_REG_ML_LCTL); |
@@ -282,6 +288,27 @@ int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link) | |||
282 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down); | 288 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down); |
283 | 289 | ||
284 | /** | 290 | /** |
291 | * snd_hdac_ext_bus_link_power_up_all -power up all hda link | ||
292 | * @ebus: HD-audio extended bus | ||
293 | */ | ||
294 | int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus) | ||
295 | { | ||
296 | struct hdac_ext_link *hlink = NULL; | ||
297 | int ret; | ||
298 | |||
299 | list_for_each_entry(hlink, &ebus->hlink_list, list) { | ||
300 | snd_hdac_updatel(hlink->ml_addr, | ||
301 | AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA); | ||
302 | ret = check_hdac_link_power_active(hlink, true); | ||
303 | if (ret < 0) | ||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up_all); | ||
310 | |||
311 | /** | ||
285 | * snd_hdac_ext_bus_link_power_down_all -power down all hda link | 312 | * snd_hdac_ext_bus_link_power_down_all -power down all hda link |
286 | * @ebus: HD-audio extended bus | 313 | * @ebus: HD-audio extended bus |
287 | */ | 314 | */ |
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index cb89ec7c8147..023cc4cad5c1 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c | |||
@@ -59,6 +59,10 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus, | |||
59 | AZX_SPB_MAXFIFO; | 59 | AZX_SPB_MAXFIFO; |
60 | } | 60 | } |
61 | 61 | ||
62 | if (ebus->drsmcap) | ||
63 | stream->dpibr_addr = ebus->drsmcap + AZX_DRSM_BASE + | ||
64 | AZX_DRSM_INTERVAL * idx; | ||
65 | |||
62 | stream->decoupled = false; | 66 | stream->decoupled = false; |
63 | snd_hdac_stream_init(bus, &stream->hstream, idx, direction, tag); | 67 | snd_hdac_stream_init(bus, &stream->hstream, idx, direction, tag); |
64 | } | 68 | } |
@@ -107,6 +111,7 @@ void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus) | |||
107 | while (!list_empty(&bus->stream_list)) { | 111 | while (!list_empty(&bus->stream_list)) { |
108 | s = list_first_entry(&bus->stream_list, struct hdac_stream, list); | 112 | s = list_first_entry(&bus->stream_list, struct hdac_stream, list); |
109 | stream = stream_to_hdac_ext_stream(s); | 113 | stream = stream_to_hdac_ext_stream(s); |
114 | snd_hdac_ext_stream_decouple(ebus, stream, false); | ||
110 | list_del(&s->list); | 115 | list_del(&s->list); |
111 | kfree(stream); | 116 | kfree(stream); |
112 | } | 117 | } |
@@ -497,3 +502,70 @@ void snd_hdac_ext_stop_streams(struct hdac_ext_bus *ebus) | |||
497 | } | 502 | } |
498 | } | 503 | } |
499 | EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams); | 504 | EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams); |
505 | |||
506 | /** | ||
507 | * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream | ||
508 | * @ebus: HD-audio ext core bus | ||
509 | * @enable: flag to enable/disable DRSM | ||
510 | * @index: stream index for which DRSM need to be enabled | ||
511 | */ | ||
512 | void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus, | ||
513 | bool enable, int index) | ||
514 | { | ||
515 | u32 mask = 0; | ||
516 | u32 register_mask = 0; | ||
517 | struct hdac_bus *bus = &ebus->bus; | ||
518 | |||
519 | if (!ebus->drsmcap) { | ||
520 | dev_err(bus->dev, "Address of DRSM capability is NULL"); | ||
521 | return; | ||
522 | } | ||
523 | |||
524 | mask |= (1 << index); | ||
525 | |||
526 | register_mask = readl(ebus->drsmcap + AZX_REG_SPB_SPBFCCTL); | ||
527 | |||
528 | mask |= register_mask; | ||
529 | |||
530 | if (enable) | ||
531 | snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, 0, mask); | ||
532 | else | ||
533 | snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); | ||
534 | } | ||
535 | EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable); | ||
536 | |||
537 | /** | ||
538 | * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream | ||
539 | * @ebus: HD-audio ext core bus | ||
540 | * @stream: hdac_ext_stream | ||
541 | * @value: dpib value to set | ||
542 | */ | ||
543 | int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus, | ||
544 | struct hdac_ext_stream *stream, u32 value) | ||
545 | { | ||
546 | struct hdac_bus *bus = &ebus->bus; | ||
547 | |||
548 | if (!ebus->drsmcap) { | ||
549 | dev_err(bus->dev, "Address of DRSM capability is NULL"); | ||
550 | return -EINVAL; | ||
551 | } | ||
552 | |||
553 | writel(value, stream->dpibr_addr); | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr); | ||
558 | |||
559 | /** | ||
560 | * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream | ||
561 | * @ebus: HD-audio ext core bus | ||
562 | * @stream: hdac_ext_stream | ||
563 | * @value: lpib value to set | ||
564 | */ | ||
565 | int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value) | ||
566 | { | ||
567 | snd_hdac_stream_writel(&stream->hstream, SD_LPIB, value); | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib); | ||