aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/hdaudio_ext.h13
-rw-r--r--sound/hda/ext/hdac_ext_bus.c3
-rw-r--r--sound/hda/ext/hdac_ext_controller.c66
3 files changed, 82 insertions, 0 deletions
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h
index 07fa59237feb..b9593b201599 100644
--- a/include/sound/hdaudio_ext.h
+++ b/include/sound/hdaudio_ext.h
@@ -14,6 +14,8 @@
14 * @gtscap: gts capabilities pointer 14 * @gtscap: gts capabilities pointer
15 * @drsmcap: dma resume capabilities pointer 15 * @drsmcap: dma resume capabilities pointer
16 * @hlink_list: link list of HDA links 16 * @hlink_list: link list of HDA links
17 * @lock: lock for link mgmt
18 * @cmd_dma_state: state of cmd DMAs: CORB and RIRB
17 */ 19 */
18struct hdac_ext_bus { 20struct hdac_ext_bus {
19 struct hdac_bus bus; 21 struct hdac_bus bus;
@@ -27,6 +29,9 @@ struct hdac_ext_bus {
27 void __iomem *drsmcap; 29 void __iomem *drsmcap;
28 30
29 struct list_head hlink_list; 31 struct list_head hlink_list;
32
33 struct mutex lock;
34 bool cmd_dma_state;
30}; 35};
31 36
32int snd_hdac_ext_bus_init(struct hdac_ext_bus *sbus, struct device *dev, 37int snd_hdac_ext_bus_init(struct hdac_ext_bus *sbus, struct device *dev,
@@ -142,6 +147,9 @@ struct hdac_ext_link {
142 void __iomem *ml_addr; /* link output stream reg pointer */ 147 void __iomem *ml_addr; /* link output stream reg pointer */
143 u32 lcaps; /* link capablities */ 148 u32 lcaps; /* link capablities */
144 u16 lsdiid; /* link sdi identifier */ 149 u16 lsdiid; /* link sdi identifier */
150
151 int ref_count;
152
145 struct list_head list; 153 struct list_head list;
146}; 154};
147 155
@@ -154,6 +162,11 @@ void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
154void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link, 162void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
155 int stream); 163 int stream);
156 164
165int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus,
166 struct hdac_ext_link *link);
167int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
168 struct hdac_ext_link *link);
169
157/* update register macro */ 170/* update register macro */
158#define snd_hdac_updatel(addr, reg, mask, val) \ 171#define snd_hdac_updatel(addr, reg, mask, val) \
159 writel(((readl(addr + reg) & ~(mask)) | (val)), \ 172 writel(((readl(addr + reg) & ~(mask)) | (val)), \
diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c
index 2433f7c81472..3b7ae24900fd 100644
--- a/sound/hda/ext/hdac_ext_bus.c
+++ b/sound/hda/ext/hdac_ext_bus.c
@@ -105,6 +105,9 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev,
105 INIT_LIST_HEAD(&ebus->hlink_list); 105 INIT_LIST_HEAD(&ebus->hlink_list);
106 ebus->idx = idx++; 106 ebus->idx = idx++;
107 107
108 mutex_init(&ebus->lock);
109 ebus->cmd_dma_state = true;
110
108 return 0; 111 return 0;
109} 112}
110EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init); 113EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init);
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c
index 548cc1e4114b..860f8cad6602 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/ext/hdac_ext_controller.c
@@ -186,6 +186,9 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
186 hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP); 186 hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP);
187 hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); 187 hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID);
188 188
189 /* since link in On, update the ref */
190 hlink->ref_count = 1;
191
189 list_add_tail(&hlink->list, &ebus->hlink_list); 192 list_add_tail(&hlink->list, &ebus->hlink_list);
190 } 193 }
191 194
@@ -327,3 +330,66 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus)
327 return 0; 330 return 0;
328} 331}
329EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all); 332EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all);
333
334int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus,
335 struct hdac_ext_link *link)
336{
337 int ret = 0;
338
339 mutex_lock(&ebus->lock);
340
341 /*
342 * if we move from 0 to 1, count will be 1 so power up this link
343 * as well, also check the dma status and trigger that
344 */
345 if (++link->ref_count == 1) {
346 if (!ebus->cmd_dma_state) {
347 snd_hdac_bus_init_cmd_io(&ebus->bus);
348 ebus->cmd_dma_state = true;
349 }
350
351 ret = snd_hdac_ext_bus_link_power_up(link);
352 }
353
354 mutex_unlock(&ebus->lock);
355 return ret;
356}
357EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get);
358
359int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
360 struct hdac_ext_link *link)
361{
362 int ret = 0;
363 struct hdac_ext_link *hlink;
364 bool link_up = false;
365
366 mutex_lock(&ebus->lock);
367
368 /*
369 * if we move from 1 to 0, count will be 0
370 * so power down this link as well
371 */
372 if (--link->ref_count == 0) {
373 ret = snd_hdac_ext_bus_link_power_down(link);
374
375 /*
376 * now check if all links are off, if so turn off
377 * cmd dma as well
378 */
379 list_for_each_entry(hlink, &ebus->hlink_list, list) {
380 if (hlink->ref_count) {
381 link_up = true;
382 break;
383 }
384 }
385
386 if (!link_up) {
387 snd_hdac_bus_stop_cmd_io(&ebus->bus);
388 ebus->cmd_dma_state = false;
389 }
390 }
391
392 mutex_unlock(&ebus->lock);
393 return ret;
394}
395EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put);