blob: 1bd27576db98d50cc12382c209c3938fe9fe5e14 [file] [log] [blame]
Jeeja KPdf203a42015-06-11 14:11:49 +05301/*
2 * hdac-ext-stream.c - HD-audio extended stream operations.
3 *
4 * Copyright (C) 2015 Intel Corp
5 * Author: Jeeja KP <jeeja.kp@intel.com>
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18 */
19
20#include <linux/delay.h>
Vinod Koule7a34842015-06-17 11:20:16 +053021#include <linux/slab.h>
Jeeja KPdf203a42015-06-11 14:11:49 +053022#include <sound/pcm.h>
23#include <sound/hda_register.h>
24#include <sound/hdaudio_ext.h>
25
26/**
27 * snd_hdac_ext_stream_init - initialize each stream (aka device)
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050028 * @bus: HD-audio core bus
Jeeja KPdf203a42015-06-11 14:11:49 +053029 * @stream: HD-audio ext core stream object to initialize
30 * @idx: stream index number
31 * @direction: stream direction (SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE)
32 * @tag: the tag id to assign
33 *
34 * initialize the stream, if ppcap is enabled then init those and then
35 * invoke hdac stream initialization routine
36 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050037void snd_hdac_ext_stream_init(struct hdac_bus *bus,
Jeeja KPdf203a42015-06-11 14:11:49 +053038 struct hdac_ext_stream *stream,
39 int idx, int direction, int tag)
40{
Vinod Koulec8ae572016-08-04 15:46:01 +053041 if (bus->ppcap) {
42 stream->pphc_addr = bus->ppcap + AZX_PPHC_BASE +
Jeeja KPdf203a42015-06-11 14:11:49 +053043 AZX_PPHC_INTERVAL * idx;
44
Vinod Koulec8ae572016-08-04 15:46:01 +053045 stream->pplc_addr = bus->ppcap + AZX_PPLC_BASE +
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050046 AZX_PPLC_MULTI * bus->num_streams +
Jeeja KPdf203a42015-06-11 14:11:49 +053047 AZX_PPLC_INTERVAL * idx;
48 }
49
Vinod Koulec8ae572016-08-04 15:46:01 +053050 if (bus->spbcap) {
51 stream->spib_addr = bus->spbcap + AZX_SPB_BASE +
Jeeja KPee8bc4d2015-08-21 21:36:20 +053052 AZX_SPB_INTERVAL * idx +
53 AZX_SPB_SPIB;
54
Vinod Koulec8ae572016-08-04 15:46:01 +053055 stream->fifo_addr = bus->spbcap + AZX_SPB_BASE +
Jeeja KPee8bc4d2015-08-21 21:36:20 +053056 AZX_SPB_INTERVAL * idx +
57 AZX_SPB_MAXFIFO;
58 }
59
Vinod Koulec8ae572016-08-04 15:46:01 +053060 if (bus->drsmcap)
61 stream->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE +
Jeeja KPa9c48f72015-12-18 15:11:59 +053062 AZX_DRSM_INTERVAL * idx;
63
Jeeja KPdf203a42015-06-11 14:11:49 +053064 stream->decoupled = false;
65 snd_hdac_stream_init(bus, &stream->hstream, idx, direction, tag);
66}
67EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init);
68
69/**
Vinod Koule7a34842015-06-17 11:20:16 +053070 * snd_hdac_ext_stream_init_all - create and initialize the stream objects
71 * for an extended hda bus
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050072 * @bus: HD-audio core bus
Vinod Koule7a34842015-06-17 11:20:16 +053073 * @start_idx: start index for streams
74 * @num_stream: number of streams to initialize
75 * @dir: direction of streams
76 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050077int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
Vinod Koule7a34842015-06-17 11:20:16 +053078 int num_stream, int dir)
79{
80 int stream_tag = 0;
81 int i, tag, idx = start_idx;
82
83 for (i = 0; i < num_stream; i++) {
84 struct hdac_ext_stream *stream =
85 kzalloc(sizeof(*stream), GFP_KERNEL);
86 if (!stream)
87 return -ENOMEM;
88 tag = ++stream_tag;
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050089 snd_hdac_ext_stream_init(bus, stream, idx, dir, tag);
Vinod Koule7a34842015-06-17 11:20:16 +053090 idx++;
91 }
92
93 return 0;
94
95}
96EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init_all);
97
98/**
99 * snd_hdac_stream_free_all - free hdac extended stream objects
100 *
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500101 * @bus: HD-audio core bus
Vinod Koule7a34842015-06-17 11:20:16 +0530102 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500103void snd_hdac_stream_free_all(struct hdac_bus *bus)
Vinod Koule7a34842015-06-17 11:20:16 +0530104{
Vinod Koul4a6c5e62016-03-15 16:39:23 +0530105 struct hdac_stream *s, *_s;
Vinod Koule7a34842015-06-17 11:20:16 +0530106 struct hdac_ext_stream *stream;
Vinod Koule7a34842015-06-17 11:20:16 +0530107
Vinod Koul4a6c5e62016-03-15 16:39:23 +0530108 list_for_each_entry_safe(s, _s, &bus->stream_list, list) {
Vinod Koule7a34842015-06-17 11:20:16 +0530109 stream = stream_to_hdac_ext_stream(s);
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500110 snd_hdac_ext_stream_decouple(bus, stream, false);
Vinod Koule7a34842015-06-17 11:20:16 +0530111 list_del(&s->list);
112 kfree(stream);
113 }
114}
115EXPORT_SYMBOL_GPL(snd_hdac_stream_free_all);
116
117/**
Jeeja KPdf203a42015-06-11 14:11:49 +0530118 * snd_hdac_ext_stream_decouple - decouple the hdac stream
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500119 * @bus: HD-audio core bus
Jeeja KPdf203a42015-06-11 14:11:49 +0530120 * @stream: HD-audio ext core stream object to initialize
121 * @decouple: flag to decouple
122 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500123void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
Jeeja KPdf203a42015-06-11 14:11:49 +0530124 struct hdac_ext_stream *stream, bool decouple)
125{
126 struct hdac_stream *hstream = &stream->hstream;
Jeeja KP09a8bf82017-01-02 12:44:28 +0530127 u32 val;
128 int mask = AZX_PPCTL_PROCEN(hstream->index);
Jeeja KPdf203a42015-06-11 14:11:49 +0530129
130 spin_lock_irq(&bus->reg_lock);
Jeeja KP09a8bf82017-01-02 12:44:28 +0530131 val = readw(bus->ppcap + AZX_REG_PP_PPCTL) & mask;
132
133 if (decouple && !val)
134 snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, mask);
135 else if (!decouple && val)
136 snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, 0);
137
Jeeja KPdf203a42015-06-11 14:11:49 +0530138 stream->decoupled = decouple;
139 spin_unlock_irq(&bus->reg_lock);
140}
141EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple);
142
143/**
144 * snd_hdac_ext_linkstream_start - start a stream
145 * @stream: HD-audio ext core stream to start
146 */
147void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *stream)
148{
149 snd_hdac_updatel(stream->pplc_addr, AZX_REG_PPLCCTL, 0, AZX_PPLCCTL_RUN);
150}
151EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_start);
152
153/**
154 * snd_hdac_ext_link_stream_clear - stop a stream DMA
155 * @stream: HD-audio ext core stream to stop
156 */
157void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *stream)
158{
159 snd_hdac_updatel(stream->pplc_addr, AZX_REG_PPLCCTL, AZX_PPLCCTL_RUN, 0);
160}
161EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_clear);
162
163/**
164 * snd_hdac_ext_link_stream_reset - reset a stream
165 * @stream: HD-audio ext core stream to reset
166 */
167void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *stream)
168{
169 unsigned char val;
170 int timeout;
171
172 snd_hdac_ext_link_stream_clear(stream);
173
174 snd_hdac_updatel(stream->pplc_addr, AZX_REG_PPLCCTL, 0, AZX_PPLCCTL_STRST);
175 udelay(3);
176 timeout = 50;
177 do {
178 val = readl(stream->pplc_addr + AZX_REG_PPLCCTL) &
179 AZX_PPLCCTL_STRST;
180 if (val)
181 break;
182 udelay(3);
183 } while (--timeout);
184 val &= ~AZX_PPLCCTL_STRST;
185 writel(val, stream->pplc_addr + AZX_REG_PPLCCTL);
186 udelay(3);
187
188 timeout = 50;
189 /* waiting for hardware to report that the stream is out of reset */
190 do {
191 val = readl(stream->pplc_addr + AZX_REG_PPLCCTL) & AZX_PPLCCTL_STRST;
192 if (!val)
193 break;
194 udelay(3);
195 } while (--timeout);
196
197}
198EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_reset);
199
200/**
201 * snd_hdac_ext_link_stream_setup - set up the SD for streaming
202 * @stream: HD-audio ext core stream to set up
203 * @fmt: stream format
204 */
205int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *stream, int fmt)
206{
207 struct hdac_stream *hstream = &stream->hstream;
208 unsigned int val;
209
210 /* make sure the run bit is zero for SD */
211 snd_hdac_ext_link_stream_clear(stream);
212 /* program the stream_tag */
213 val = readl(stream->pplc_addr + AZX_REG_PPLCCTL);
214 val = (val & ~AZX_PPLCCTL_STRM_MASK) |
215 (hstream->stream_tag << AZX_PPLCCTL_STRM_SHIFT);
216 writel(val, stream->pplc_addr + AZX_REG_PPLCCTL);
217
218 /* program the stream format */
219 writew(fmt, stream->pplc_addr + AZX_REG_PPLCFMT);
220
221 return 0;
222}
223EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_setup);
224
225/**
226 * snd_hdac_ext_link_set_stream_id - maps stream id to link output
227 * @link: HD-audio ext link to set up
228 * @stream: stream id
229 */
230void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
231 int stream)
232{
Subhransu S. Prusty88b19962015-10-05 15:09:48 +0100233 snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream);
Jeeja KPdf203a42015-06-11 14:11:49 +0530234}
235EXPORT_SYMBOL_GPL(snd_hdac_ext_link_set_stream_id);
236
237/**
238 * snd_hdac_ext_link_clear_stream_id - maps stream id to link output
239 * @link: HD-audio ext link to set up
240 * @stream: stream id
241 */
242void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
243 int stream)
244{
245 snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, 0, (1 << stream));
246}
247EXPORT_SYMBOL_GPL(snd_hdac_ext_link_clear_stream_id);
248
249static struct hdac_ext_stream *
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500250hdac_ext_link_stream_assign(struct hdac_bus *bus,
Jeeja KPdf203a42015-06-11 14:11:49 +0530251 struct snd_pcm_substream *substream)
252{
253 struct hdac_ext_stream *res = NULL;
254 struct hdac_stream *stream = NULL;
Jeeja KPdf203a42015-06-11 14:11:49 +0530255
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500256 if (!bus->ppcap) {
257 dev_err(bus->dev, "stream type not supported\n");
Jeeja KPdf203a42015-06-11 14:11:49 +0530258 return NULL;
259 }
260
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500261 list_for_each_entry(stream, &bus->stream_list, list) {
Jeeja KPdf203a42015-06-11 14:11:49 +0530262 struct hdac_ext_stream *hstream = container_of(stream,
263 struct hdac_ext_stream,
264 hstream);
265 if (stream->direction != substream->stream)
266 continue;
267
268 /* check if decoupled stream and not in use is available */
269 if (hstream->decoupled && !hstream->link_locked) {
270 res = hstream;
271 break;
272 }
273
274 if (!hstream->link_locked) {
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500275 snd_hdac_ext_stream_decouple(bus, hstream, true);
Jeeja KPdf203a42015-06-11 14:11:49 +0530276 res = hstream;
277 break;
278 }
279 }
280 if (res) {
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500281 spin_lock_irq(&bus->reg_lock);
Jeeja KPdf203a42015-06-11 14:11:49 +0530282 res->link_locked = 1;
283 res->link_substream = substream;
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500284 spin_unlock_irq(&bus->reg_lock);
Jeeja KPdf203a42015-06-11 14:11:49 +0530285 }
286 return res;
287}
288
289static struct hdac_ext_stream *
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500290hdac_ext_host_stream_assign(struct hdac_bus *bus,
Jeeja KPdf203a42015-06-11 14:11:49 +0530291 struct snd_pcm_substream *substream)
292{
293 struct hdac_ext_stream *res = NULL;
294 struct hdac_stream *stream = NULL;
Jeeja KPdf203a42015-06-11 14:11:49 +0530295
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500296 if (!bus->ppcap) {
297 dev_err(bus->dev, "stream type not supported\n");
Jeeja KPdf203a42015-06-11 14:11:49 +0530298 return NULL;
299 }
300
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500301 list_for_each_entry(stream, &bus->stream_list, list) {
Jeeja KPdf203a42015-06-11 14:11:49 +0530302 struct hdac_ext_stream *hstream = container_of(stream,
303 struct hdac_ext_stream,
304 hstream);
305 if (stream->direction != substream->stream)
306 continue;
307
Jeeja KP9b06dc92015-08-04 09:28:38 +0530308 if (!stream->opened) {
Jeeja KPdf203a42015-06-11 14:11:49 +0530309 if (!hstream->decoupled)
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500310 snd_hdac_ext_stream_decouple(bus, hstream, true);
Jeeja KPdf203a42015-06-11 14:11:49 +0530311 res = hstream;
312 break;
313 }
314 }
315 if (res) {
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500316 spin_lock_irq(&bus->reg_lock);
Jeeja KPdf203a42015-06-11 14:11:49 +0530317 res->hstream.opened = 1;
318 res->hstream.running = 0;
Jeeja KPdf203a42015-06-11 14:11:49 +0530319 res->hstream.substream = substream;
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500320 spin_unlock_irq(&bus->reg_lock);
Jeeja KPdf203a42015-06-11 14:11:49 +0530321 }
322
323 return res;
324}
325
326/**
327 * snd_hdac_ext_stream_assign - assign a stream for the PCM
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500328 * @bus: HD-audio core bus
Jeeja KPdf203a42015-06-11 14:11:49 +0530329 * @substream: PCM substream to assign
330 * @type: type of stream (coupled, host or link stream)
331 *
332 * This assigns the stream based on the type (coupled/host/link), for the
333 * given PCM substream, assigns it and returns the stream object
334 *
335 * coupled: Looks for an unused stream
336 * host: Looks for an unused decoupled host stream
337 * link: Looks for an unused decoupled link stream
338 *
339 * If no stream is free, returns NULL. The function tries to keep using
340 * the same stream object when it's used beforehand. when a stream is
341 * decoupled, it becomes a host stream and link stream.
342 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500343struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
Jeeja KPdf203a42015-06-11 14:11:49 +0530344 struct snd_pcm_substream *substream,
345 int type)
346{
347 struct hdac_ext_stream *hstream = NULL;
348 struct hdac_stream *stream = NULL;
Jeeja KPdf203a42015-06-11 14:11:49 +0530349
350 switch (type) {
351 case HDAC_EXT_STREAM_TYPE_COUPLED:
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500352 stream = snd_hdac_stream_assign(bus, substream);
Jeeja KPdf203a42015-06-11 14:11:49 +0530353 if (stream)
354 hstream = container_of(stream,
355 struct hdac_ext_stream, hstream);
356 return hstream;
357
358 case HDAC_EXT_STREAM_TYPE_HOST:
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500359 return hdac_ext_host_stream_assign(bus, substream);
Jeeja KPdf203a42015-06-11 14:11:49 +0530360
361 case HDAC_EXT_STREAM_TYPE_LINK:
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500362 return hdac_ext_link_stream_assign(bus, substream);
Jeeja KPdf203a42015-06-11 14:11:49 +0530363
364 default:
365 return NULL;
366 }
367}
368EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_assign);
369
370/**
371 * snd_hdac_ext_stream_release - release the assigned stream
372 * @stream: HD-audio ext core stream to release
373 * @type: type of stream (coupled, host or link stream)
374 *
375 * Release the stream that has been assigned by snd_hdac_ext_stream_assign().
376 */
377void snd_hdac_ext_stream_release(struct hdac_ext_stream *stream, int type)
378{
379 struct hdac_bus *bus = stream->hstream.bus;
Jeeja KPdf203a42015-06-11 14:11:49 +0530380
381 switch (type) {
382 case HDAC_EXT_STREAM_TYPE_COUPLED:
383 snd_hdac_stream_release(&stream->hstream);
384 break;
385
386 case HDAC_EXT_STREAM_TYPE_HOST:
Jeeja KPa04267f2015-10-05 15:09:49 +0100387 if (stream->decoupled && !stream->link_locked)
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500388 snd_hdac_ext_stream_decouple(bus, stream, false);
Jeeja KPa04267f2015-10-05 15:09:49 +0100389 snd_hdac_stream_release(&stream->hstream);
Jeeja KPdf203a42015-06-11 14:11:49 +0530390 break;
391
392 case HDAC_EXT_STREAM_TYPE_LINK:
Jeeja KPa04267f2015-10-05 15:09:49 +0100393 if (stream->decoupled && !stream->hstream.opened)
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500394 snd_hdac_ext_stream_decouple(bus, stream, false);
Jeeja KPdf203a42015-06-11 14:11:49 +0530395 spin_lock_irq(&bus->reg_lock);
396 stream->link_locked = 0;
397 stream->link_substream = NULL;
398 spin_unlock_irq(&bus->reg_lock);
399 break;
400
401 default:
402 dev_dbg(bus->dev, "Invalid type %d\n", type);
403 }
404
405}
406EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release);
407
408/**
409 * snd_hdac_ext_stream_spbcap_enable - enable SPIB for a stream
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500410 * @bus: HD-audio core bus
Jeeja KPdf203a42015-06-11 14:11:49 +0530411 * @enable: flag to enable/disable SPIB
412 * @index: stream index for which SPIB need to be enabled
413 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500414void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus,
Jeeja KPdf203a42015-06-11 14:11:49 +0530415 bool enable, int index)
416{
417 u32 mask = 0;
418 u32 register_mask = 0;
Jeeja KPdf203a42015-06-11 14:11:49 +0530419
Vinod Koulec8ae572016-08-04 15:46:01 +0530420 if (!bus->spbcap) {
Colin Ian King36176312016-09-16 17:36:05 +0100421 dev_err(bus->dev, "Address of SPB capability is NULL\n");
Jeeja KPdf203a42015-06-11 14:11:49 +0530422 return;
423 }
424
425 mask |= (1 << index);
426
Vinod Koulec8ae572016-08-04 15:46:01 +0530427 register_mask = readl(bus->spbcap + AZX_REG_SPB_SPBFCCTL);
Jeeja KPdf203a42015-06-11 14:11:49 +0530428
429 mask |= register_mask;
430
431 if (enable)
Vinod Koulec8ae572016-08-04 15:46:01 +0530432 snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask);
Jeeja KPdf203a42015-06-11 14:11:49 +0530433 else
Vinod Koulec8ae572016-08-04 15:46:01 +0530434 snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0);
Jeeja KPdf203a42015-06-11 14:11:49 +0530435}
436EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable);
437
438/**
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530439 * snd_hdac_ext_stream_set_spib - sets the spib value of a stream
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500440 * @bus: HD-audio core bus
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530441 * @stream: hdac_ext_stream
442 * @value: spib value to set
443 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500444int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus,
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530445 struct hdac_ext_stream *stream, u32 value)
446{
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530447
Vinod Koulec8ae572016-08-04 15:46:01 +0530448 if (!bus->spbcap) {
Colin Ian King36176312016-09-16 17:36:05 +0100449 dev_err(bus->dev, "Address of SPB capability is NULL\n");
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530450 return -EINVAL;
451 }
452
453 writel(value, stream->spib_addr);
454
455 return 0;
456}
457EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_spib);
458
459/**
Vinod Koul54d1d2f2015-08-23 11:52:50 +0530460 * snd_hdac_ext_stream_get_spbmaxfifo - gets the spib value of a stream
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500461 * @bus: HD-audio core bus
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530462 * @stream: hdac_ext_stream
463 *
464 * Return maxfifo for the stream
465 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500466int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus,
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530467 struct hdac_ext_stream *stream)
468{
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530469
Vinod Koulec8ae572016-08-04 15:46:01 +0530470 if (!bus->spbcap) {
Colin Ian King36176312016-09-16 17:36:05 +0100471 dev_err(bus->dev, "Address of SPB capability is NULL\n");
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530472 return -EINVAL;
473 }
474
475 return readl(stream->fifo_addr);
476}
Vinod Koul54d1d2f2015-08-23 11:52:50 +0530477EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_get_spbmaxfifo);
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530478
479
480/**
Jeeja KPdf203a42015-06-11 14:11:49 +0530481 * snd_hdac_ext_stop_streams - stop all stream if running
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500482 * @bus: HD-audio core bus
Jeeja KPdf203a42015-06-11 14:11:49 +0530483 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500484void snd_hdac_ext_stop_streams(struct hdac_bus *bus)
Jeeja KPdf203a42015-06-11 14:11:49 +0530485{
Jeeja KPdf203a42015-06-11 14:11:49 +0530486 struct hdac_stream *stream;
487
488 if (bus->chip_init) {
489 list_for_each_entry(stream, &bus->stream_list, list)
490 snd_hdac_stream_stop(stream);
491 snd_hdac_bus_stop_chip(bus);
492 }
493}
494EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams);
Jeeja KPa9c48f72015-12-18 15:11:59 +0530495
496/**
497 * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500498 * @bus: HD-audio core bus
Jeeja KPa9c48f72015-12-18 15:11:59 +0530499 * @enable: flag to enable/disable DRSM
500 * @index: stream index for which DRSM need to be enabled
501 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500502void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus,
Jeeja KPa9c48f72015-12-18 15:11:59 +0530503 bool enable, int index)
504{
505 u32 mask = 0;
506 u32 register_mask = 0;
Jeeja KPa9c48f72015-12-18 15:11:59 +0530507
Vinod Koulec8ae572016-08-04 15:46:01 +0530508 if (!bus->drsmcap) {
Colin Ian King36176312016-09-16 17:36:05 +0100509 dev_err(bus->dev, "Address of DRSM capability is NULL\n");
Jeeja KPa9c48f72015-12-18 15:11:59 +0530510 return;
511 }
512
513 mask |= (1 << index);
514
Vinod Koulec8ae572016-08-04 15:46:01 +0530515 register_mask = readl(bus->drsmcap + AZX_REG_SPB_SPBFCCTL);
Jeeja KPa9c48f72015-12-18 15:11:59 +0530516
517 mask |= register_mask;
518
519 if (enable)
Vinod Koulec8ae572016-08-04 15:46:01 +0530520 snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, 0, mask);
Jeeja KPa9c48f72015-12-18 15:11:59 +0530521 else
Vinod Koulec8ae572016-08-04 15:46:01 +0530522 snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
Jeeja KPa9c48f72015-12-18 15:11:59 +0530523}
524EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
525
526/**
527 * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500528 * @bus: HD-audio core bus
Jeeja KPa9c48f72015-12-18 15:11:59 +0530529 * @stream: hdac_ext_stream
530 * @value: dpib value to set
531 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500532int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus,
Jeeja KPa9c48f72015-12-18 15:11:59 +0530533 struct hdac_ext_stream *stream, u32 value)
534{
Jeeja KPa9c48f72015-12-18 15:11:59 +0530535
Vinod Koulec8ae572016-08-04 15:46:01 +0530536 if (!bus->drsmcap) {
Colin Ian King36176312016-09-16 17:36:05 +0100537 dev_err(bus->dev, "Address of DRSM capability is NULL\n");
Jeeja KPa9c48f72015-12-18 15:11:59 +0530538 return -EINVAL;
539 }
540
541 writel(value, stream->dpibr_addr);
542
543 return 0;
544}
545EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr);
546
547/**
548 * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500549 * @bus: HD-audio core bus
Jeeja KPa9c48f72015-12-18 15:11:59 +0530550 * @stream: hdac_ext_stream
551 * @value: lpib value to set
552 */
553int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value)
554{
555 snd_hdac_stream_writel(&stream->hstream, SD_LPIB, value);
556
557 return 0;
558}
559EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib);