]>
git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - sound/soc/intel/sst/sst_pvt.c
9a5df193651653fc5ba7a1813de319f2601fd206
2 * sst_pvt.c - Intel SST Driver for audio engine
4 * Copyright (C) 2008-14 Intel Corp
5 * Authors: Vinod Koul <vinod.koul@intel.com>
6 * Harsha Priya <priya.harsha@intel.com>
7 * Dharageswari R <dharageswari.r@intel.com>
8 * KP Jeeja <jeeja.kp@intel.com>
9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2 of the License.
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22 #include <linux/kobject.h>
23 #include <linux/pci.h>
25 #include <linux/firmware.h>
26 #include <linux/pm_runtime.h>
27 #include <linux/sched.h>
28 #include <linux/delay.h>
29 #include <sound/asound.h>
30 #include <sound/core.h>
31 #include <sound/pcm.h>
32 #include <sound/soc.h>
33 #include <sound/compress_driver.h>
34 #include <asm/platform_sst_audio.h>
35 #include "../sst-mfld-platform.h"
37 #include "../sst-dsp.h"
39 int sst_shim_write(void __iomem
*addr
, int offset
, int value
)
41 writel(value
, addr
+ offset
);
45 u32
sst_shim_read(void __iomem
*addr
, int offset
)
47 return readl(addr
+ offset
);
50 u64
sst_reg_read64(void __iomem
*addr
, int offset
)
54 memcpy_fromio(&val
, addr
+ offset
, sizeof(val
));
59 int sst_shim_write64(void __iomem
*addr
, int offset
, u64 value
)
61 memcpy_toio(addr
+ offset
, &value
, sizeof(value
));
65 u64
sst_shim_read64(void __iomem
*addr
, int offset
)
69 memcpy_fromio(&val
, addr
+ offset
, sizeof(val
));
73 void sst_set_fw_state_locked(
74 struct intel_sst_drv
*sst_drv_ctx
, int sst_state
)
76 mutex_lock(&sst_drv_ctx
->sst_lock
);
77 sst_drv_ctx
->sst_state
= sst_state
;
78 mutex_unlock(&sst_drv_ctx
->sst_lock
);
82 * sst_wait_interruptible - wait on event
84 * @sst_drv_ctx: Driver context
85 * @block: Driver block to wait on
87 * This function waits without a timeout (and is interruptable) for a
90 int sst_wait_interruptible(struct intel_sst_drv
*sst_drv_ctx
,
91 struct sst_block
*block
)
95 if (!wait_event_interruptible(sst_drv_ctx
->wait_queue
,
98 if (block
->ret_code
< 0) {
99 dev_err(sst_drv_ctx
->dev
,
100 "stream failed %d\n", block
->ret_code
);
103 dev_dbg(sst_drv_ctx
->dev
, "event up\n");
107 dev_err(sst_drv_ctx
->dev
, "signal interrupted\n");
114 unsigned long long read_shim_data(struct intel_sst_drv
*sst
, int addr
)
116 unsigned long long val
= 0;
118 switch (sst
->dev_id
) {
119 case SST_MRFLD_PCI_ID
:
120 val
= sst_shim_read64(sst
->shim
, addr
);
126 void write_shim_data(struct intel_sst_drv
*sst
, int addr
,
127 unsigned long long data
)
129 switch (sst
->dev_id
) {
130 case SST_MRFLD_PCI_ID
:
131 sst_shim_write64(sst
->shim
, addr
, (u64
) data
);
137 * sst_wait_timeout - wait on event for timeout
139 * @sst_drv_ctx: Driver context
140 * @block: Driver block to wait on
142 * This function waits with a timeout value (and is not interruptible) on a
145 int sst_wait_timeout(struct intel_sst_drv
*sst_drv_ctx
, struct sst_block
*block
)
151 * Observed that FW processes the alloc msg and replies even
152 * before the alloc thread has finished execution
154 dev_dbg(sst_drv_ctx
->dev
,
155 "waiting for condition %x ipc %d drv_id %d\n",
156 block
->condition
, block
->msg_id
, block
->drv_id
);
157 if (wait_event_timeout(sst_drv_ctx
->wait_queue
,
159 msecs_to_jiffies(SST_BLOCK_TIMEOUT
))) {
161 dev_dbg(sst_drv_ctx
->dev
, "Event wake %x\n",
163 dev_dbg(sst_drv_ctx
->dev
, "message ret: %d\n",
165 retval
= -block
->ret_code
;
168 dev_err(sst_drv_ctx
->dev
,
169 "Wait timed-out condition:%#x, msg_id:%#x fw_state %#x\n",
170 block
->condition
, block
->msg_id
, sst_drv_ctx
->sst_state
);
171 sst_drv_ctx
->sst_state
= SST_RESET
;
179 * sst_create_ipc_msg - create a IPC message
182 * @large: large or short message
184 * this function allocates structures to send a large or short
185 * message to the firmware
187 int sst_create_ipc_msg(struct ipc_post
**arg
, bool large
)
189 struct ipc_post
*msg
;
191 msg
= kzalloc(sizeof(struct ipc_post
), GFP_ATOMIC
);
195 msg
->mailbox_data
= kzalloc(SST_MAILBOX_SIZE
, GFP_ATOMIC
);
196 if (!msg
->mailbox_data
) {
201 msg
->mailbox_data
= NULL
;
203 msg
->is_large
= large
;
209 * sst_create_block_and_ipc_msg - Creates IPC message and sst block
210 * @arg: passed to sst_create_ipc_message API
211 * @large: large or short message
212 * @sst_drv_ctx: sst driver context
213 * @block: return block allocated
215 * @drv_id: stream id or private id
217 int sst_create_block_and_ipc_msg(struct ipc_post
**arg
, bool large
,
218 struct intel_sst_drv
*sst_drv_ctx
, struct sst_block
**block
,
219 u32 msg_id
, u32 drv_id
)
223 retval
= sst_create_ipc_msg(arg
, large
);
226 *block
= sst_create_block(sst_drv_ctx
, msg_id
, drv_id
);
227 if (*block
== NULL
) {
235 * sst_clean_stream - clean the stream context
237 * @stream: stream structure
239 * this function resets the stream contexts
240 * should be called in free
242 void sst_clean_stream(struct stream_info
*stream
)
244 stream
->status
= STREAM_UN_INIT
;
245 stream
->prev
= STREAM_UN_INIT
;
246 mutex_lock(&stream
->lock
);
247 stream
->cumm_bytes
= 0;
248 mutex_unlock(&stream
->lock
);
251 int sst_prepare_and_post_msg(struct intel_sst_drv
*sst
,
252 int task_id
, int ipc_msg
, int cmd_id
, int pipe_id
,
253 size_t mbox_data_len
, const void *mbox_data
, void **data
,
254 bool large
, bool fill_dsp
, bool sync
, bool response
)
256 struct ipc_post
*msg
= NULL
;
257 struct ipc_dsp_hdr dsp_hdr
;
258 struct sst_block
*block
;
261 pvt_id
= sst_assign_pvt_id(sst
);
266 ret
= sst_create_block_and_ipc_msg(
267 &msg
, large
, sst
, &block
, ipc_msg
, pvt_id
);
269 ret
= sst_create_ipc_msg(&msg
, large
);
272 test_and_clear_bit(pvt_id
, &sst
->pvt_id
);
276 dev_dbg(sst
->dev
, "pvt_id = %d, pipe id = %d, task = %d ipc_msg: %d\n",
277 pvt_id
, pipe_id
, task_id
, ipc_msg
);
278 sst_fill_header_mrfld(&msg
->mrfld_header
, ipc_msg
,
279 task_id
, large
, pvt_id
);
280 msg
->mrfld_header
.p
.header_low_payload
= sizeof(dsp_hdr
) + mbox_data_len
;
281 msg
->mrfld_header
.p
.header_high
.part
.res_rqd
= !sync
;
282 dev_dbg(sst
->dev
, "header:%x\n",
283 msg
->mrfld_header
.p
.header_high
.full
);
284 dev_dbg(sst
->dev
, "response rqd: %x",
285 msg
->mrfld_header
.p
.header_high
.part
.res_rqd
);
286 dev_dbg(sst
->dev
, "msg->mrfld_header.p.header_low_payload:%d",
287 msg
->mrfld_header
.p
.header_low_payload
);
289 sst_fill_header_dsp(&dsp_hdr
, cmd_id
, pipe_id
, mbox_data_len
);
290 memcpy(msg
->mailbox_data
, &dsp_hdr
, sizeof(dsp_hdr
));
292 memcpy(msg
->mailbox_data
+ sizeof(dsp_hdr
),
293 mbox_data
, mbox_data_len
);
298 sst
->ops
->post_message(sst
, msg
, true);
300 sst_add_to_dispatch_list_and_post(sst
, msg
);
303 ret
= sst_wait_timeout(sst
, block
);
306 } else if(block
->data
) {
309 *data
= kzalloc(block
->size
, GFP_KERNEL
);
314 memcpy(data
, (void *) block
->data
, block
->size
);
319 sst_free_block(sst
, block
);
320 test_and_clear_bit(pvt_id
, &sst
->pvt_id
);
324 int sst_pm_runtime_put(struct intel_sst_drv
*sst_drv
)
328 pm_runtime_mark_last_busy(sst_drv
->dev
);
329 ret
= pm_runtime_put_autosuspend(sst_drv
->dev
);
335 void sst_fill_header_mrfld(union ipc_header_mrfld
*header
,
336 int msg
, int task_id
, int large
, int drv_id
)
339 header
->p
.header_high
.part
.msg_id
= msg
;
340 header
->p
.header_high
.part
.task_id
= task_id
;
341 header
->p
.header_high
.part
.large
= large
;
342 header
->p
.header_high
.part
.drv_id
= drv_id
;
343 header
->p
.header_high
.part
.done
= 0;
344 header
->p
.header_high
.part
.busy
= 1;
345 header
->p
.header_high
.part
.res_rqd
= 1;
348 void sst_fill_header_dsp(struct ipc_dsp_hdr
*dsp
, int msg
,
349 int pipe_id
, int len
)
352 dsp
->mod_index_id
= 0xff;
353 dsp
->pipe_id
= pipe_id
;
358 #define SST_MAX_BLOCKS 15
360 * sst_assign_pvt_id - assign a pvt id for stream
362 * @sst_drv_ctx : driver context
364 * this function assigns a private id for calls that dont have stream
365 * context yet, should be called with lock held
366 * uses bits for the id, and finds first free bits and assigns that
368 int sst_assign_pvt_id(struct intel_sst_drv
*drv
)
372 spin_lock(&drv
->block_lock
);
373 /* find first zero index from lsb */
374 local
= ffz(drv
->pvt_id
);
375 dev_dbg(drv
->dev
, "pvt_id assigned --> %d\n", local
);
376 if (local
>= SST_MAX_BLOCKS
){
377 spin_unlock(&drv
->block_lock
);
378 dev_err(drv
->dev
, "PVT _ID error: no free id blocks ");
381 /* toggle the index */
382 change_bit(local
, &drv
->pvt_id
);
383 spin_unlock(&drv
->block_lock
);
387 void sst_init_stream(struct stream_info
*stream
,
388 int codec
, int sst_id
, int ops
, u8 slot
)
390 stream
->status
= STREAM_INIT
;
391 stream
->prev
= STREAM_UN_INIT
;
395 int sst_validate_strid(
396 struct intel_sst_drv
*sst_drv_ctx
, int str_id
)
398 if (str_id
<= 0 || str_id
> sst_drv_ctx
->info
.max_streams
) {
399 dev_err(sst_drv_ctx
->dev
,
400 "SST ERR: invalid stream id : %d, max %d\n",
401 str_id
, sst_drv_ctx
->info
.max_streams
);
408 struct stream_info
*get_stream_info(
409 struct intel_sst_drv
*sst_drv_ctx
, int str_id
)
411 if (sst_validate_strid(sst_drv_ctx
, str_id
))
413 return &sst_drv_ctx
->streams
[str_id
];
416 int get_stream_id_mrfld(struct intel_sst_drv
*sst_drv_ctx
,
421 for (i
= 1; i
<= sst_drv_ctx
->info
.max_streams
; i
++)
422 if (pipe_id
== sst_drv_ctx
->streams
[i
].pipe_id
)
425 dev_dbg(sst_drv_ctx
->dev
, "no such pipe_id(%u)", pipe_id
);
429 u32
relocate_imr_addr_mrfld(u32 base_addr
)
431 /* Get the difference from 512MB aligned base addr */
432 /* relocate the base */
433 base_addr
= MRFLD_FW_VIRTUAL_BASE
+ (base_addr
% (512 * 1024 * 1024));
436 EXPORT_SYMBOL_GPL(relocate_imr_addr_mrfld
);
438 void sst_add_to_dispatch_list_and_post(struct intel_sst_drv
*sst
,
439 struct ipc_post
*msg
)
441 unsigned long irq_flags
;
443 spin_lock_irqsave(&sst
->ipc_spin_lock
, irq_flags
);
444 list_add_tail(&msg
->node
, &sst
->ipc_dispatch_list
);
445 spin_unlock_irqrestore(&sst
->ipc_spin_lock
, irq_flags
);
446 sst
->ops
->post_message(sst
, NULL
, false);