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 "../../common/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");
115 * sst_wait_timeout - wait on event for timeout
117 * @sst_drv_ctx: Driver context
118 * @block: Driver block to wait on
120 * This function waits with a timeout value (and is not interruptible) on a
123 int sst_wait_timeout(struct intel_sst_drv
*sst_drv_ctx
, struct sst_block
*block
)
129 * Observed that FW processes the alloc msg and replies even
130 * before the alloc thread has finished execution
132 dev_dbg(sst_drv_ctx
->dev
,
133 "waiting for condition %x ipc %d drv_id %d\n",
134 block
->condition
, block
->msg_id
, block
->drv_id
);
135 if (wait_event_timeout(sst_drv_ctx
->wait_queue
,
137 msecs_to_jiffies(SST_BLOCK_TIMEOUT
))) {
139 dev_dbg(sst_drv_ctx
->dev
, "Event wake %x\n",
141 dev_dbg(sst_drv_ctx
->dev
, "message ret: %d\n",
143 retval
= -block
->ret_code
;
146 dev_err(sst_drv_ctx
->dev
,
147 "Wait timed-out condition:%#x, msg_id:%#x fw_state %#x\n",
148 block
->condition
, block
->msg_id
, sst_drv_ctx
->sst_state
);
149 sst_drv_ctx
->sst_state
= SST_RESET
;
157 * sst_create_ipc_msg - create a IPC message
160 * @large: large or short message
162 * this function allocates structures to send a large or short
163 * message to the firmware
165 int sst_create_ipc_msg(struct ipc_post
**arg
, bool large
)
167 struct ipc_post
*msg
;
169 msg
= kzalloc(sizeof(struct ipc_post
), GFP_ATOMIC
);
173 msg
->mailbox_data
= kzalloc(SST_MAILBOX_SIZE
, GFP_ATOMIC
);
174 if (!msg
->mailbox_data
) {
179 msg
->mailbox_data
= NULL
;
181 msg
->is_large
= large
;
187 * sst_create_block_and_ipc_msg - Creates IPC message and sst block
188 * @arg: passed to sst_create_ipc_message API
189 * @large: large or short message
190 * @sst_drv_ctx: sst driver context
191 * @block: return block allocated
193 * @drv_id: stream id or private id
195 int sst_create_block_and_ipc_msg(struct ipc_post
**arg
, bool large
,
196 struct intel_sst_drv
*sst_drv_ctx
, struct sst_block
**block
,
197 u32 msg_id
, u32 drv_id
)
201 retval
= sst_create_ipc_msg(arg
, large
);
204 *block
= sst_create_block(sst_drv_ctx
, msg_id
, drv_id
);
205 if (*block
== NULL
) {
213 * sst_clean_stream - clean the stream context
215 * @stream: stream structure
217 * this function resets the stream contexts
218 * should be called in free
220 void sst_clean_stream(struct stream_info
*stream
)
222 stream
->status
= STREAM_UN_INIT
;
223 stream
->prev
= STREAM_UN_INIT
;
224 mutex_lock(&stream
->lock
);
225 stream
->cumm_bytes
= 0;
226 mutex_unlock(&stream
->lock
);
229 int sst_prepare_and_post_msg(struct intel_sst_drv
*sst
,
230 int task_id
, int ipc_msg
, int cmd_id
, int pipe_id
,
231 size_t mbox_data_len
, const void *mbox_data
, void **data
,
232 bool large
, bool fill_dsp
, bool sync
, bool response
)
234 struct ipc_post
*msg
= NULL
;
235 struct ipc_dsp_hdr dsp_hdr
;
236 struct sst_block
*block
;
239 pvt_id
= sst_assign_pvt_id(sst
);
244 ret
= sst_create_block_and_ipc_msg(
245 &msg
, large
, sst
, &block
, ipc_msg
, pvt_id
);
247 ret
= sst_create_ipc_msg(&msg
, large
);
250 test_and_clear_bit(pvt_id
, &sst
->pvt_id
);
254 dev_dbg(sst
->dev
, "pvt_id = %d, pipe id = %d, task = %d ipc_msg: %d\n",
255 pvt_id
, pipe_id
, task_id
, ipc_msg
);
256 sst_fill_header_mrfld(&msg
->mrfld_header
, ipc_msg
,
257 task_id
, large
, pvt_id
);
258 msg
->mrfld_header
.p
.header_low_payload
= sizeof(dsp_hdr
) + mbox_data_len
;
259 msg
->mrfld_header
.p
.header_high
.part
.res_rqd
= !sync
;
260 dev_dbg(sst
->dev
, "header:%x\n",
261 msg
->mrfld_header
.p
.header_high
.full
);
262 dev_dbg(sst
->dev
, "response rqd: %x",
263 msg
->mrfld_header
.p
.header_high
.part
.res_rqd
);
264 dev_dbg(sst
->dev
, "msg->mrfld_header.p.header_low_payload:%d",
265 msg
->mrfld_header
.p
.header_low_payload
);
267 sst_fill_header_dsp(&dsp_hdr
, cmd_id
, pipe_id
, mbox_data_len
);
268 memcpy(msg
->mailbox_data
, &dsp_hdr
, sizeof(dsp_hdr
));
270 memcpy(msg
->mailbox_data
+ sizeof(dsp_hdr
),
271 mbox_data
, mbox_data_len
);
276 sst
->ops
->post_message(sst
, msg
, true);
278 sst_add_to_dispatch_list_and_post(sst
, msg
);
281 ret
= sst_wait_timeout(sst
, block
);
284 } else if(block
->data
) {
287 *data
= kzalloc(block
->size
, GFP_KERNEL
);
292 memcpy(data
, (void *) block
->data
, block
->size
);
297 sst_free_block(sst
, block
);
298 test_and_clear_bit(pvt_id
, &sst
->pvt_id
);
302 int sst_pm_runtime_put(struct intel_sst_drv
*sst_drv
)
306 pm_runtime_mark_last_busy(sst_drv
->dev
);
307 ret
= pm_runtime_put_autosuspend(sst_drv
->dev
);
313 void sst_fill_header_mrfld(union ipc_header_mrfld
*header
,
314 int msg
, int task_id
, int large
, int drv_id
)
317 header
->p
.header_high
.part
.msg_id
= msg
;
318 header
->p
.header_high
.part
.task_id
= task_id
;
319 header
->p
.header_high
.part
.large
= large
;
320 header
->p
.header_high
.part
.drv_id
= drv_id
;
321 header
->p
.header_high
.part
.done
= 0;
322 header
->p
.header_high
.part
.busy
= 1;
323 header
->p
.header_high
.part
.res_rqd
= 1;
326 void sst_fill_header_dsp(struct ipc_dsp_hdr
*dsp
, int msg
,
327 int pipe_id
, int len
)
330 dsp
->mod_index_id
= 0xff;
331 dsp
->pipe_id
= pipe_id
;
336 #define SST_MAX_BLOCKS 15
338 * sst_assign_pvt_id - assign a pvt id for stream
340 * @sst_drv_ctx : driver context
342 * this function assigns a private id for calls that dont have stream
343 * context yet, should be called with lock held
344 * uses bits for the id, and finds first free bits and assigns that
346 int sst_assign_pvt_id(struct intel_sst_drv
*drv
)
350 spin_lock(&drv
->block_lock
);
351 /* find first zero index from lsb */
352 local
= ffz(drv
->pvt_id
);
353 dev_dbg(drv
->dev
, "pvt_id assigned --> %d\n", local
);
354 if (local
>= SST_MAX_BLOCKS
){
355 spin_unlock(&drv
->block_lock
);
356 dev_err(drv
->dev
, "PVT _ID error: no free id blocks ");
359 /* toggle the index */
360 change_bit(local
, &drv
->pvt_id
);
361 spin_unlock(&drv
->block_lock
);
365 void sst_init_stream(struct stream_info
*stream
,
366 int codec
, int sst_id
, int ops
, u8 slot
)
368 stream
->status
= STREAM_INIT
;
369 stream
->prev
= STREAM_UN_INIT
;
373 int sst_validate_strid(
374 struct intel_sst_drv
*sst_drv_ctx
, int str_id
)
376 if (str_id
<= 0 || str_id
> sst_drv_ctx
->info
.max_streams
) {
377 dev_err(sst_drv_ctx
->dev
,
378 "SST ERR: invalid stream id : %d, max %d\n",
379 str_id
, sst_drv_ctx
->info
.max_streams
);
386 struct stream_info
*get_stream_info(
387 struct intel_sst_drv
*sst_drv_ctx
, int str_id
)
389 if (sst_validate_strid(sst_drv_ctx
, str_id
))
391 return &sst_drv_ctx
->streams
[str_id
];
394 int get_stream_id_mrfld(struct intel_sst_drv
*sst_drv_ctx
,
399 for (i
= 1; i
<= sst_drv_ctx
->info
.max_streams
; i
++)
400 if (pipe_id
== sst_drv_ctx
->streams
[i
].pipe_id
)
403 dev_dbg(sst_drv_ctx
->dev
, "no such pipe_id(%u)", pipe_id
);
407 u32
relocate_imr_addr_mrfld(u32 base_addr
)
409 /* Get the difference from 512MB aligned base addr */
410 /* relocate the base */
411 base_addr
= MRFLD_FW_VIRTUAL_BASE
+ (base_addr
% (512 * 1024 * 1024));
414 EXPORT_SYMBOL_GPL(relocate_imr_addr_mrfld
);
416 void sst_add_to_dispatch_list_and_post(struct intel_sst_drv
*sst
,
417 struct ipc_post
*msg
)
419 unsigned long irq_flags
;
421 spin_lock_irqsave(&sst
->ipc_spin_lock
, irq_flags
);
422 list_add_tail(&msg
->node
, &sst
->ipc_dispatch_list
);
423 spin_unlock_irqrestore(&sst
->ipc_spin_lock
, irq_flags
);
424 sst
->ops
->post_message(sst
, NULL
, false);
This page took 0.07815 seconds and 6 git commands to generate.