aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2016-01-10 07:13:34 -0500
committerMark Brown <broonie@kernel.org>2016-01-10 07:13:34 -0500
commit648e3a5bdddf8e7ad9c27450ac368b8bccd807a5 (patch)
treef5db76d41d4c691a8d4417f0385d5f1b8c9b6b63
parent15b914476bf24185534a59fb8e149d465ff79c59 (diff)
parent6706a19747eb693ff35ce140f5cbee66dcfec0c4 (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.h9
-rw-r--r--include/sound/hdaudio_ext.h15
-rw-r--r--sound/hda/ext/hdac_ext_controller.c29
-rw-r--r--sound/hda/ext/hdac_ext_stream.c72
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 */
17struct hdac_ext_bus { 18struct 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);
117int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus, 126int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
118 struct hdac_ext_stream *stream); 127 struct hdac_ext_stream *stream);
128void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
129 bool enable, int index);
130int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
131 struct hdac_ext_stream *stream, u32 value);
132int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value);
119 133
120void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hstream); 134void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hstream);
121void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hstream); 135void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hstream);
@@ -133,6 +147,7 @@ struct hdac_ext_link {
133 147
134int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link); 148int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link);
135int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link); 149int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link);
150int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus);
136int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus); 151int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus);
137void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, 152void 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)
282EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down); 288EXPORT_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 */
294int 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}
309EXPORT_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}
499EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams); 504EXPORT_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 */
512void 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}
535EXPORT_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 */
543int 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}
557EXPORT_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 */
565int 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}
571EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib);