blob: d2b5724b463ffbe857ae7406f9022a0e9bddde06 [file] [log] [blame]
Thomas Gleixner8e8e69d2019-05-29 07:17:59 -07001// SPDX-License-Identifier: GPL-2.0-only
Jeeja KPdf203a42015-06-11 14:11:49 +05302/*
3 * hdac-ext-stream.c - HD-audio extended stream operations.
4 *
5 * Copyright (C) 2015 Intel Corp
6 * Author: Jeeja KP <jeeja.kp@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
Jeeja KPdf203a42015-06-11 14:11:49 +05309 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10 */
11
12#include <linux/delay.h>
Vinod Koule7a34842015-06-17 11:20:16 +053013#include <linux/slab.h>
Jeeja KPdf203a42015-06-11 14:11:49 +053014#include <sound/pcm.h>
15#include <sound/hda_register.h>
16#include <sound/hdaudio_ext.h>
17
18/**
19 * snd_hdac_ext_stream_init - initialize each stream (aka device)
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050020 * @bus: HD-audio core bus
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -060021 * @hext_stream: HD-audio ext core stream object to initialize
Jeeja KPdf203a42015-06-11 14:11:49 +053022 * @idx: stream index number
23 * @direction: stream direction (SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE)
24 * @tag: the tag id to assign
25 *
26 * initialize the stream, if ppcap is enabled then init those and then
27 * invoke hdac stream initialization routine
28 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050029void snd_hdac_ext_stream_init(struct hdac_bus *bus,
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -060030 struct hdac_ext_stream *hext_stream,
31 int idx, int direction, int tag)
Jeeja KPdf203a42015-06-11 14:11:49 +053032{
Vinod Koulec8ae572016-08-04 15:46:01 +053033 if (bus->ppcap) {
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -060034 hext_stream->pphc_addr = bus->ppcap + AZX_PPHC_BASE +
Jeeja KPdf203a42015-06-11 14:11:49 +053035 AZX_PPHC_INTERVAL * idx;
36
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -060037 hext_stream->pplc_addr = bus->ppcap + AZX_PPLC_BASE +
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050038 AZX_PPLC_MULTI * bus->num_streams +
Jeeja KPdf203a42015-06-11 14:11:49 +053039 AZX_PPLC_INTERVAL * idx;
40 }
41
Vinod Koulec8ae572016-08-04 15:46:01 +053042 if (bus->spbcap) {
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -060043 hext_stream->spib_addr = bus->spbcap + AZX_SPB_BASE +
Jeeja KPee8bc4d2015-08-21 21:36:20 +053044 AZX_SPB_INTERVAL * idx +
45 AZX_SPB_SPIB;
46
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -060047 hext_stream->fifo_addr = bus->spbcap + AZX_SPB_BASE +
Jeeja KPee8bc4d2015-08-21 21:36:20 +053048 AZX_SPB_INTERVAL * idx +
49 AZX_SPB_MAXFIFO;
50 }
51
Vinod Koulec8ae572016-08-04 15:46:01 +053052 if (bus->drsmcap)
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -060053 hext_stream->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE +
Jeeja KPa9c48f72015-12-18 15:11:59 +053054 AZX_DRSM_INTERVAL * idx;
55
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -060056 hext_stream->decoupled = false;
57 snd_hdac_stream_init(bus, &hext_stream->hstream, idx, direction, tag);
Jeeja KPdf203a42015-06-11 14:11:49 +053058}
59EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init);
60
61/**
Vinod Koule7a34842015-06-17 11:20:16 +053062 * snd_hdac_ext_stream_init_all - create and initialize the stream objects
63 * for an extended hda bus
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050064 * @bus: HD-audio core bus
Vinod Koule7a34842015-06-17 11:20:16 +053065 * @start_idx: start index for streams
66 * @num_stream: number of streams to initialize
67 * @dir: direction of streams
68 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050069int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -060070 int num_stream, int dir)
Vinod Koule7a34842015-06-17 11:20:16 +053071{
72 int stream_tag = 0;
73 int i, tag, idx = start_idx;
74
75 for (i = 0; i < num_stream; i++) {
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -060076 struct hdac_ext_stream *hext_stream =
77 kzalloc(sizeof(*hext_stream), GFP_KERNEL);
78 if (!hext_stream)
Vinod Koule7a34842015-06-17 11:20:16 +053079 return -ENOMEM;
80 tag = ++stream_tag;
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -060081 snd_hdac_ext_stream_init(bus, hext_stream, idx, dir, tag);
Vinod Koule7a34842015-06-17 11:20:16 +053082 idx++;
83 }
84
85 return 0;
86
87}
88EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init_all);
89
90/**
91 * snd_hdac_stream_free_all - free hdac extended stream objects
92 *
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050093 * @bus: HD-audio core bus
Vinod Koule7a34842015-06-17 11:20:16 +053094 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050095void snd_hdac_stream_free_all(struct hdac_bus *bus)
Vinod Koule7a34842015-06-17 11:20:16 +053096{
Vinod Koul4a6c5e62016-03-15 16:39:23 +053097 struct hdac_stream *s, *_s;
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -060098 struct hdac_ext_stream *hext_stream;
Vinod Koule7a34842015-06-17 11:20:16 +053099
Vinod Koul4a6c5e62016-03-15 16:39:23 +0530100 list_for_each_entry_safe(s, _s, &bus->stream_list, list) {
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600101 hext_stream = stream_to_hdac_ext_stream(s);
102 snd_hdac_ext_stream_decouple(bus, hext_stream, false);
Vinod Koule7a34842015-06-17 11:20:16 +0530103 list_del(&s->list);
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600104 kfree(hext_stream);
Vinod Koule7a34842015-06-17 11:20:16 +0530105 }
106}
107EXPORT_SYMBOL_GPL(snd_hdac_stream_free_all);
108
Pierre-Louis Bossart868ddfc2021-09-24 14:24:16 -0500109void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus,
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600110 struct hdac_ext_stream *hext_stream,
Pierre-Louis Bossart868ddfc2021-09-24 14:24:16 -0500111 bool decouple)
Jeeja KPdf203a42015-06-11 14:11:49 +0530112{
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600113 struct hdac_stream *hstream = &hext_stream->hstream;
Jeeja KP09a8bf82017-01-02 12:44:28 +0530114 u32 val;
115 int mask = AZX_PPCTL_PROCEN(hstream->index);
Jeeja KPdf203a42015-06-11 14:11:49 +0530116
Jeeja KP09a8bf82017-01-02 12:44:28 +0530117 val = readw(bus->ppcap + AZX_REG_PP_PPCTL) & mask;
118
119 if (decouple && !val)
120 snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, mask);
121 else if (!decouple && val)
122 snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, 0);
123
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600124 hext_stream->decoupled = decouple;
Pierre-Louis Bossart868ddfc2021-09-24 14:24:16 -0500125}
126EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple_locked);
127
128/**
129 * snd_hdac_ext_stream_decouple - decouple the hdac stream
130 * @bus: HD-audio core bus
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600131 * @hext_stream: HD-audio ext core stream object to initialize
Pierre-Louis Bossart868ddfc2021-09-24 14:24:16 -0500132 * @decouple: flag to decouple
133 */
134void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600135 struct hdac_ext_stream *hext_stream, bool decouple)
Pierre-Louis Bossart868ddfc2021-09-24 14:24:16 -0500136{
137 spin_lock_irq(&bus->reg_lock);
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600138 snd_hdac_ext_stream_decouple_locked(bus, hext_stream, decouple);
Jeeja KPdf203a42015-06-11 14:11:49 +0530139 spin_unlock_irq(&bus->reg_lock);
140}
141EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple);
142
143/**
Pierre-Louis Bossart3531ba22021-03-01 11:46:17 -0600144 * snd_hdac_ext_link_stream_start - start a stream
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600145 * @hext_stream: HD-audio ext core stream to start
Jeeja KPdf203a42015-06-11 14:11:49 +0530146 */
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600147void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hext_stream)
Jeeja KPdf203a42015-06-11 14:11:49 +0530148{
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600149 snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL,
Keyon Jief7c50fa2018-09-03 10:47:09 +0800150 AZX_PPLCCTL_RUN, AZX_PPLCCTL_RUN);
Jeeja KPdf203a42015-06-11 14:11:49 +0530151}
152EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_start);
153
154/**
155 * snd_hdac_ext_link_stream_clear - stop a stream DMA
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600156 * @hext_stream: HD-audio ext core stream to stop
Jeeja KPdf203a42015-06-11 14:11:49 +0530157 */
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600158void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hext_stream)
Jeeja KPdf203a42015-06-11 14:11:49 +0530159{
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600160 snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL, AZX_PPLCCTL_RUN, 0);
Jeeja KPdf203a42015-06-11 14:11:49 +0530161}
162EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_clear);
163
164/**
165 * snd_hdac_ext_link_stream_reset - reset a stream
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600166 * @hext_stream: HD-audio ext core stream to reset
Jeeja KPdf203a42015-06-11 14:11:49 +0530167 */
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600168void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream)
Jeeja KPdf203a42015-06-11 14:11:49 +0530169{
170 unsigned char val;
171 int timeout;
172
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600173 snd_hdac_ext_link_stream_clear(hext_stream);
Jeeja KPdf203a42015-06-11 14:11:49 +0530174
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600175 snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL,
Keyon Jief7c50fa2018-09-03 10:47:09 +0800176 AZX_PPLCCTL_STRST, AZX_PPLCCTL_STRST);
Jeeja KPdf203a42015-06-11 14:11:49 +0530177 udelay(3);
178 timeout = 50;
179 do {
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600180 val = readl(hext_stream->pplc_addr + AZX_REG_PPLCCTL) &
Jeeja KPdf203a42015-06-11 14:11:49 +0530181 AZX_PPLCCTL_STRST;
182 if (val)
183 break;
184 udelay(3);
185 } while (--timeout);
186 val &= ~AZX_PPLCCTL_STRST;
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600187 writel(val, hext_stream->pplc_addr + AZX_REG_PPLCCTL);
Jeeja KPdf203a42015-06-11 14:11:49 +0530188 udelay(3);
189
190 timeout = 50;
191 /* waiting for hardware to report that the stream is out of reset */
192 do {
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600193 val = readl(hext_stream->pplc_addr + AZX_REG_PPLCCTL) & AZX_PPLCCTL_STRST;
Jeeja KPdf203a42015-06-11 14:11:49 +0530194 if (!val)
195 break;
196 udelay(3);
197 } while (--timeout);
198
199}
200EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_reset);
201
202/**
203 * snd_hdac_ext_link_stream_setup - set up the SD for streaming
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600204 * @hext_stream: HD-audio ext core stream to set up
Jeeja KPdf203a42015-06-11 14:11:49 +0530205 * @fmt: stream format
206 */
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600207int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt)
Jeeja KPdf203a42015-06-11 14:11:49 +0530208{
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600209 struct hdac_stream *hstream = &hext_stream->hstream;
Jeeja KPdf203a42015-06-11 14:11:49 +0530210 unsigned int val;
211
212 /* make sure the run bit is zero for SD */
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600213 snd_hdac_ext_link_stream_clear(hext_stream);
Jeeja KPdf203a42015-06-11 14:11:49 +0530214 /* program the stream_tag */
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600215 val = readl(hext_stream->pplc_addr + AZX_REG_PPLCCTL);
Jeeja KPdf203a42015-06-11 14:11:49 +0530216 val = (val & ~AZX_PPLCCTL_STRM_MASK) |
217 (hstream->stream_tag << AZX_PPLCCTL_STRM_SHIFT);
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600218 writel(val, hext_stream->pplc_addr + AZX_REG_PPLCCTL);
Jeeja KPdf203a42015-06-11 14:11:49 +0530219
220 /* program the stream format */
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600221 writew(fmt, hext_stream->pplc_addr + AZX_REG_PPLCFMT);
Jeeja KPdf203a42015-06-11 14:11:49 +0530222
223 return 0;
224}
225EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_setup);
226
227/**
228 * snd_hdac_ext_link_set_stream_id - maps stream id to link output
229 * @link: HD-audio ext link to set up
230 * @stream: stream id
231 */
232void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600233 int stream)
Jeeja KPdf203a42015-06-11 14:11:49 +0530234{
Subhransu S. Prusty88b19962015-10-05 15:09:48 +0100235 snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream);
Jeeja KPdf203a42015-06-11 14:11:49 +0530236}
237EXPORT_SYMBOL_GPL(snd_hdac_ext_link_set_stream_id);
238
239/**
240 * snd_hdac_ext_link_clear_stream_id - maps stream id to link output
241 * @link: HD-audio ext link to set up
242 * @stream: stream id
243 */
244void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
245 int stream)
246{
Keyon Jief7c50fa2018-09-03 10:47:09 +0800247 snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0);
Jeeja KPdf203a42015-06-11 14:11:49 +0530248}
249EXPORT_SYMBOL_GPL(snd_hdac_ext_link_clear_stream_id);
250
251static struct hdac_ext_stream *
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500252hdac_ext_link_stream_assign(struct hdac_bus *bus,
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600253 struct snd_pcm_substream *substream)
Jeeja KPdf203a42015-06-11 14:11:49 +0530254{
255 struct hdac_ext_stream *res = NULL;
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600256 struct hdac_stream *hstream = NULL;
Jeeja KPdf203a42015-06-11 14:11:49 +0530257
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500258 if (!bus->ppcap) {
259 dev_err(bus->dev, "stream type not supported\n");
Jeeja KPdf203a42015-06-11 14:11:49 +0530260 return NULL;
261 }
262
Pierre-Louis Bossart868ddfc2021-09-24 14:24:16 -0500263 spin_lock_irq(&bus->reg_lock);
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600264 list_for_each_entry(hstream, &bus->stream_list, list) {
265 struct hdac_ext_stream *hext_stream = container_of(hstream,
266 struct hdac_ext_stream,
267 hstream);
268 if (hstream->direction != substream->stream)
Jeeja KPdf203a42015-06-11 14:11:49 +0530269 continue;
270
271 /* check if decoupled stream and not in use is available */
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600272 if (hext_stream->decoupled && !hext_stream->link_locked) {
273 res = hext_stream;
Jeeja KPdf203a42015-06-11 14:11:49 +0530274 break;
275 }
276
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600277 if (!hext_stream->link_locked) {
278 snd_hdac_ext_stream_decouple_locked(bus, hext_stream, true);
279 res = hext_stream;
Jeeja KPdf203a42015-06-11 14:11:49 +0530280 break;
281 }
282 }
283 if (res) {
Jeeja KPdf203a42015-06-11 14:11:49 +0530284 res->link_locked = 1;
285 res->link_substream = substream;
Jeeja KPdf203a42015-06-11 14:11:49 +0530286 }
Pierre-Louis Bossart868ddfc2021-09-24 14:24:16 -0500287 spin_unlock_irq(&bus->reg_lock);
Jeeja KPdf203a42015-06-11 14:11:49 +0530288 return res;
289}
290
291static struct hdac_ext_stream *
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500292hdac_ext_host_stream_assign(struct hdac_bus *bus,
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600293 struct snd_pcm_substream *substream)
Jeeja KPdf203a42015-06-11 14:11:49 +0530294{
295 struct hdac_ext_stream *res = NULL;
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600296 struct hdac_stream *hstream = NULL;
Jeeja KPdf203a42015-06-11 14:11:49 +0530297
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500298 if (!bus->ppcap) {
299 dev_err(bus->dev, "stream type not supported\n");
Jeeja KPdf203a42015-06-11 14:11:49 +0530300 return NULL;
301 }
302
Pierre-Louis Bossart868ddfc2021-09-24 14:24:16 -0500303 spin_lock_irq(&bus->reg_lock);
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600304 list_for_each_entry(hstream, &bus->stream_list, list) {
305 struct hdac_ext_stream *hext_stream = container_of(hstream,
306 struct hdac_ext_stream,
307 hstream);
308 if (hstream->direction != substream->stream)
Jeeja KPdf203a42015-06-11 14:11:49 +0530309 continue;
310
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600311 if (!hstream->opened) {
312 if (!hext_stream->decoupled)
313 snd_hdac_ext_stream_decouple_locked(bus, hext_stream, true);
314 res = hext_stream;
Jeeja KPdf203a42015-06-11 14:11:49 +0530315 break;
316 }
317 }
318 if (res) {
Jeeja KPdf203a42015-06-11 14:11:49 +0530319 res->hstream.opened = 1;
320 res->hstream.running = 0;
Jeeja KPdf203a42015-06-11 14:11:49 +0530321 res->hstream.substream = substream;
Jeeja KPdf203a42015-06-11 14:11:49 +0530322 }
Pierre-Louis Bossart868ddfc2021-09-24 14:24:16 -0500323 spin_unlock_irq(&bus->reg_lock);
Jeeja KPdf203a42015-06-11 14:11:49 +0530324
325 return res;
326}
327
328/**
329 * snd_hdac_ext_stream_assign - assign a stream for the PCM
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500330 * @bus: HD-audio core bus
Jeeja KPdf203a42015-06-11 14:11:49 +0530331 * @substream: PCM substream to assign
332 * @type: type of stream (coupled, host or link stream)
333 *
334 * This assigns the stream based on the type (coupled/host/link), for the
335 * given PCM substream, assigns it and returns the stream object
336 *
337 * coupled: Looks for an unused stream
338 * host: Looks for an unused decoupled host stream
339 * link: Looks for an unused decoupled link stream
340 *
341 * If no stream is free, returns NULL. The function tries to keep using
342 * the same stream object when it's used beforehand. when a stream is
343 * decoupled, it becomes a host stream and link stream.
344 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500345struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
Jeeja KPdf203a42015-06-11 14:11:49 +0530346 struct snd_pcm_substream *substream,
347 int type)
348{
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600349 struct hdac_ext_stream *hext_stream = NULL;
350 struct hdac_stream *hstream = NULL;
Jeeja KPdf203a42015-06-11 14:11:49 +0530351
352 switch (type) {
353 case HDAC_EXT_STREAM_TYPE_COUPLED:
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600354 hstream = snd_hdac_stream_assign(bus, substream);
355 if (hstream)
356 hext_stream = container_of(hstream,
357 struct hdac_ext_stream,
358 hstream);
359 return hext_stream;
Jeeja KPdf203a42015-06-11 14:11:49 +0530360
361 case HDAC_EXT_STREAM_TYPE_HOST:
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500362 return hdac_ext_host_stream_assign(bus, substream);
Jeeja KPdf203a42015-06-11 14:11:49 +0530363
364 case HDAC_EXT_STREAM_TYPE_LINK:
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500365 return hdac_ext_link_stream_assign(bus, substream);
Jeeja KPdf203a42015-06-11 14:11:49 +0530366
367 default:
368 return NULL;
369 }
370}
371EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_assign);
372
373/**
374 * snd_hdac_ext_stream_release - release the assigned stream
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600375 * @hext_stream: HD-audio ext core stream to release
Jeeja KPdf203a42015-06-11 14:11:49 +0530376 * @type: type of stream (coupled, host or link stream)
377 *
378 * Release the stream that has been assigned by snd_hdac_ext_stream_assign().
379 */
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600380void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type)
Jeeja KPdf203a42015-06-11 14:11:49 +0530381{
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600382 struct hdac_bus *bus = hext_stream->hstream.bus;
Jeeja KPdf203a42015-06-11 14:11:49 +0530383
384 switch (type) {
385 case HDAC_EXT_STREAM_TYPE_COUPLED:
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600386 snd_hdac_stream_release(&hext_stream->hstream);
Jeeja KPdf203a42015-06-11 14:11:49 +0530387 break;
388
389 case HDAC_EXT_STREAM_TYPE_HOST:
Pierre-Louis Bossart868ddfc2021-09-24 14:24:16 -0500390 spin_lock_irq(&bus->reg_lock);
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600391 if (hext_stream->decoupled && !hext_stream->link_locked)
392 snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false);
Pierre-Louis Bossart868ddfc2021-09-24 14:24:16 -0500393 spin_unlock_irq(&bus->reg_lock);
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600394 snd_hdac_stream_release(&hext_stream->hstream);
Jeeja KPdf203a42015-06-11 14:11:49 +0530395 break;
396
397 case HDAC_EXT_STREAM_TYPE_LINK:
Jeeja KPdf203a42015-06-11 14:11:49 +0530398 spin_lock_irq(&bus->reg_lock);
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600399 if (hext_stream->decoupled && !hext_stream->hstream.opened)
400 snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false);
401 hext_stream->link_locked = 0;
402 hext_stream->link_substream = NULL;
Jeeja KPdf203a42015-06-11 14:11:49 +0530403 spin_unlock_irq(&bus->reg_lock);
404 break;
405
406 default:
407 dev_dbg(bus->dev, "Invalid type %d\n", type);
408 }
409
410}
411EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release);
412
413/**
414 * snd_hdac_ext_stream_spbcap_enable - enable SPIB for a stream
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500415 * @bus: HD-audio core bus
Jeeja KPdf203a42015-06-11 14:11:49 +0530416 * @enable: flag to enable/disable SPIB
417 * @index: stream index for which SPIB need to be enabled
418 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500419void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus,
Jeeja KPdf203a42015-06-11 14:11:49 +0530420 bool enable, int index)
421{
422 u32 mask = 0;
Jeeja KPdf203a42015-06-11 14:11:49 +0530423
Vinod Koulec8ae572016-08-04 15:46:01 +0530424 if (!bus->spbcap) {
Colin Ian King36176312016-09-16 17:36:05 +0100425 dev_err(bus->dev, "Address of SPB capability is NULL\n");
Jeeja KPdf203a42015-06-11 14:11:49 +0530426 return;
427 }
428
429 mask |= (1 << index);
430
Jeeja KPdf203a42015-06-11 14:11:49 +0530431 if (enable)
Keyon Jief7c50fa2018-09-03 10:47:09 +0800432 snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 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
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600441 * @hext_stream: hdac_ext_stream
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530442 * @value: spib value to set
443 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500444int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus,
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600445 struct hdac_ext_stream *hext_stream, u32 value)
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530446{
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
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600453 writel(value, hext_stream->spib_addr);
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530454
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
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600462 * @hext_stream: hdac_ext_stream
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530463 *
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,
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600467 struct hdac_ext_stream *hext_stream)
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530468{
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
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600475 return readl(hext_stream->fifo_addr);
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530476}
Vinod Koul54d1d2f2015-08-23 11:52:50 +0530477EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_get_spbmaxfifo);
Jeeja KPee8bc4d2015-08-21 21:36:20 +0530478
Jeeja KPa9c48f72015-12-18 15:11:59 +0530479/**
480 * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500481 * @bus: HD-audio core bus
Jeeja KPa9c48f72015-12-18 15:11:59 +0530482 * @enable: flag to enable/disable DRSM
483 * @index: stream index for which DRSM need to be enabled
484 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500485void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus,
Jeeja KPa9c48f72015-12-18 15:11:59 +0530486 bool enable, int index)
487{
488 u32 mask = 0;
Jeeja KPa9c48f72015-12-18 15:11:59 +0530489
Vinod Koulec8ae572016-08-04 15:46:01 +0530490 if (!bus->drsmcap) {
Colin Ian King36176312016-09-16 17:36:05 +0100491 dev_err(bus->dev, "Address of DRSM capability is NULL\n");
Jeeja KPa9c48f72015-12-18 15:11:59 +0530492 return;
493 }
494
495 mask |= (1 << index);
496
Jeeja KPa9c48f72015-12-18 15:11:59 +0530497 if (enable)
Keyon Jief7c50fa2018-09-03 10:47:09 +0800498 snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask);
Jeeja KPa9c48f72015-12-18 15:11:59 +0530499 else
Vinod Koulec8ae572016-08-04 15:46:01 +0530500 snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
Jeeja KPa9c48f72015-12-18 15:11:59 +0530501}
502EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
503
504/**
505 * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500506 * @bus: HD-audio core bus
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600507 * @hext_stream: hdac_ext_stream
Jeeja KPa9c48f72015-12-18 15:11:59 +0530508 * @value: dpib value to set
509 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500510int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus,
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600511 struct hdac_ext_stream *hext_stream, u32 value)
Jeeja KPa9c48f72015-12-18 15:11:59 +0530512{
Jeeja KPa9c48f72015-12-18 15:11:59 +0530513
Vinod Koulec8ae572016-08-04 15:46:01 +0530514 if (!bus->drsmcap) {
Colin Ian King36176312016-09-16 17:36:05 +0100515 dev_err(bus->dev, "Address of DRSM capability is NULL\n");
Jeeja KPa9c48f72015-12-18 15:11:59 +0530516 return -EINVAL;
517 }
518
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600519 writel(value, hext_stream->dpibr_addr);
Jeeja KPa9c48f72015-12-18 15:11:59 +0530520
521 return 0;
522}
523EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr);
524
525/**
526 * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600527 * @hext_stream: hdac_ext_stream
Jeeja KPa9c48f72015-12-18 15:11:59 +0530528 * @value: lpib value to set
529 */
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600530int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *hext_stream, u32 value)
Jeeja KPa9c48f72015-12-18 15:11:59 +0530531{
Pierre-Louis Bossart0f7e5ee2021-12-16 17:11:28 -0600532 snd_hdac_stream_writel(&hext_stream->hstream, SD_LPIB, value);
Jeeja KPa9c48f72015-12-18 15:11:59 +0530533
534 return 0;
535}
536EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib);