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 case SST_BYT_ACPI_ID
:
121 val
= sst_shim_read64(sst
->shim
, addr
);
127 void write_shim_data(struct intel_sst_drv
*sst
, int addr
,
128 unsigned long long data
)
130 switch (sst
->dev_id
) {
131 case SST_MRFLD_PCI_ID
:
132 case SST_BYT_ACPI_ID
:
133 sst_shim_write64(sst
->shim
, addr
, (u64
) data
);
139 * sst_wait_timeout - wait on event for timeout
141 * @sst_drv_ctx: Driver context
142 * @block: Driver block to wait on
144 * This function waits with a timeout value (and is not interruptible) on a
147 int sst_wait_timeout(struct intel_sst_drv
*sst_drv_ctx
, struct sst_block
*block
)
153 * Observed that FW processes the alloc msg and replies even
154 * before the alloc thread has finished execution
156 dev_dbg(sst_drv_ctx
->dev
,
157 "waiting for condition %x ipc %d drv_id %d\n",
158 block
->condition
, block
->msg_id
, block
->drv_id
);
159 if (wait_event_timeout(sst_drv_ctx
->wait_queue
,
161 msecs_to_jiffies(SST_BLOCK_TIMEOUT
))) {
163 dev_dbg(sst_drv_ctx
->dev
, "Event wake %x\n",
165 dev_dbg(sst_drv_ctx
->dev
, "message ret: %d\n",
167 retval
= -block
->ret_code
;
170 dev_err(sst_drv_ctx
->dev
,
171 "Wait timed-out condition:%#x, msg_id:%#x fw_state %#x\n",
172 block
->condition
, block
->msg_id
, sst_drv_ctx
->sst_state
);
173 sst_drv_ctx
->sst_state
= SST_RESET
;
181 * sst_create_ipc_msg - create a IPC message
184 * @large: large or short message
186 * this function allocates structures to send a large or short
187 * message to the firmware
189 int sst_create_ipc_msg(struct ipc_post
**arg
, bool large
)
191 struct ipc_post
*msg
;
193 msg
= kzalloc(sizeof(struct ipc_post
), GFP_ATOMIC
);
197 msg
->mailbox_data
= kzalloc(SST_MAILBOX_SIZE
, GFP_ATOMIC
);
198 if (!msg
->mailbox_data
) {
203 msg
->mailbox_data
= NULL
;
205 msg
->is_large
= large
;
211 * sst_create_block_and_ipc_msg - Creates IPC message and sst block
212 * @arg: passed to sst_create_ipc_message API
213 * @large: large or short message
214 * @sst_drv_ctx: sst driver context
215 * @block: return block allocated
217 * @drv_id: stream id or private id
219 int sst_create_block_and_ipc_msg(struct ipc_post
**arg
, bool large
,
220 struct intel_sst_drv
*sst_drv_ctx
, struct sst_block
**block
,
221 u32 msg_id
, u32 drv_id
)
225 retval
= sst_create_ipc_msg(arg
, large
);
228 *block
= sst_create_block(sst_drv_ctx
, msg_id
, drv_id
);
229 if (*block
== NULL
) {
237 * sst_clean_stream - clean the stream context
239 * @stream: stream structure
241 * this function resets the stream contexts
242 * should be called in free
244 void sst_clean_stream(struct stream_info
*stream
)
246 stream
->status
= STREAM_UN_INIT
;
247 stream
->prev
= STREAM_UN_INIT
;
248 mutex_lock(&stream
->lock
);
249 stream
->cumm_bytes
= 0;
250 mutex_unlock(&stream
->lock
);
253 int sst_prepare_and_post_msg(struct intel_sst_drv
*sst
,
254 int task_id
, int ipc_msg
, int cmd_id
, int pipe_id
,
255 size_t mbox_data_len
, const void *mbox_data
, void **data
,
256 bool large
, bool fill_dsp
, bool sync
, bool response
)
258 struct ipc_post
*msg
= NULL
;
259 struct ipc_dsp_hdr dsp_hdr
;
260 struct sst_block
*block
;
263 pvt_id
= sst_assign_pvt_id(sst
);
268 ret
= sst_create_block_and_ipc_msg(
269 &msg
, large
, sst
, &block
, ipc_msg
, pvt_id
);
271 ret
= sst_create_ipc_msg(&msg
, large
);
274 test_and_clear_bit(pvt_id
, &sst
->pvt_id
);
278 dev_dbg(sst
->dev
, "pvt_id = %d, pipe id = %d, task = %d ipc_msg: %d\n",
279 pvt_id
, pipe_id
, task_id
, ipc_msg
);
280 sst_fill_header_mrfld(&msg
->mrfld_header
, ipc_msg
,
281 task_id
, large
, pvt_id
);
282 msg
->mrfld_header
.p
.header_low_payload
= sizeof(dsp_hdr
) + mbox_data_len
;
283 msg
->mrfld_header
.p
.header_high
.part
.res_rqd
= !sync
;
284 dev_dbg(sst
->dev
, "header:%x\n",
285 msg
->mrfld_header
.p
.header_high
.full
);
286 dev_dbg(sst
->dev
, "response rqd: %x",
287 msg
->mrfld_header
.p
.header_high
.part
.res_rqd
);
288 dev_dbg(sst
->dev
, "msg->mrfld_header.p.header_low_payload:%d",
289 msg
->mrfld_header
.p
.header_low_payload
);
291 sst_fill_header_dsp(&dsp_hdr
, cmd_id
, pipe_id
, mbox_data_len
);
292 memcpy(msg
->mailbox_data
, &dsp_hdr
, sizeof(dsp_hdr
));
294 memcpy(msg
->mailbox_data
+ sizeof(dsp_hdr
),
295 mbox_data
, mbox_data_len
);
300 sst
->ops
->post_message(sst
, msg
, true);
302 sst_add_to_dispatch_list_and_post(sst
, msg
);
305 ret
= sst_wait_timeout(sst
, block
);
308 } else if(block
->data
) {
311 *data
= kzalloc(block
->size
, GFP_KERNEL
);
316 memcpy(data
, (void *) block
->data
, block
->size
);
321 sst_free_block(sst
, block
);
322 test_and_clear_bit(pvt_id
, &sst
->pvt_id
);
326 int sst_pm_runtime_put(struct intel_sst_drv
*sst_drv
)
330 pm_runtime_mark_last_busy(sst_drv
->dev
);
331 ret
= pm_runtime_put_autosuspend(sst_drv
->dev
);
337 void sst_fill_header_mrfld(union ipc_header_mrfld
*header
,
338 int msg
, int task_id
, int large
, int drv_id
)
341 header
->p
.header_high
.part
.msg_id
= msg
;
342 header
->p
.header_high
.part
.task_id
= task_id
;
343 header
->p
.header_high
.part
.large
= large
;
344 header
->p
.header_high
.part
.drv_id
= drv_id
;
345 header
->p
.header_high
.part
.done
= 0;
346 header
->p
.header_high
.part
.busy
= 1;
347 header
->p
.header_high
.part
.res_rqd
= 1;
350 void sst_fill_header_dsp(struct ipc_dsp_hdr
*dsp
, int msg
,
351 int pipe_id
, int len
)
354 dsp
->mod_index_id
= 0xff;
355 dsp
->pipe_id
= pipe_id
;
360 #define SST_MAX_BLOCKS 15
362 * sst_assign_pvt_id - assign a pvt id for stream
364 * @sst_drv_ctx : driver context
366 * this function assigns a private id for calls that dont have stream
367 * context yet, should be called with lock held
368 * uses bits for the id, and finds first free bits and assigns that
370 int sst_assign_pvt_id(struct intel_sst_drv
*drv
)
374 spin_lock(&drv
->block_lock
);
375 /* find first zero index from lsb */
376 local
= ffz(drv
->pvt_id
);
377 dev_dbg(drv
->dev
, "pvt_id assigned --> %d\n", local
);
378 if (local
>= SST_MAX_BLOCKS
){
379 spin_unlock(&drv
->block_lock
);
380 dev_err(drv
->dev
, "PVT _ID error: no free id blocks ");
383 /* toggle the index */
384 change_bit(local
, &drv
->pvt_id
);
385 spin_unlock(&drv
->block_lock
);
389 void sst_init_stream(struct stream_info
*stream
,
390 int codec
, int sst_id
, int ops
, u8 slot
)
392 stream
->status
= STREAM_INIT
;
393 stream
->prev
= STREAM_UN_INIT
;
397 int sst_validate_strid(
398 struct intel_sst_drv
*sst_drv_ctx
, int str_id
)
400 if (str_id
<= 0 || str_id
> sst_drv_ctx
->info
.max_streams
) {
401 dev_err(sst_drv_ctx
->dev
,
402 "SST ERR: invalid stream id : %d, max %d\n",
403 str_id
, sst_drv_ctx
->info
.max_streams
);
410 struct stream_info
*get_stream_info(
411 struct intel_sst_drv
*sst_drv_ctx
, int str_id
)
413 if (sst_validate_strid(sst_drv_ctx
, str_id
))
415 return &sst_drv_ctx
->streams
[str_id
];
418 int get_stream_id_mrfld(struct intel_sst_drv
*sst_drv_ctx
,
423 for (i
= 1; i
<= sst_drv_ctx
->info
.max_streams
; i
++)
424 if (pipe_id
== sst_drv_ctx
->streams
[i
].pipe_id
)
427 dev_dbg(sst_drv_ctx
->dev
, "no such pipe_id(%u)", pipe_id
);
431 u32
relocate_imr_addr_mrfld(u32 base_addr
)
433 /* Get the difference from 512MB aligned base addr */
434 /* relocate the base */
435 base_addr
= MRFLD_FW_VIRTUAL_BASE
+ (base_addr
% (512 * 1024 * 1024));
438 EXPORT_SYMBOL_GPL(relocate_imr_addr_mrfld
);
440 void sst_add_to_dispatch_list_and_post(struct intel_sst_drv
*sst
,
441 struct ipc_post
*msg
)
443 unsigned long irq_flags
;
445 spin_lock_irqsave(&sst
->ipc_spin_lock
, irq_flags
);
446 list_add_tail(&msg
->node
, &sst
->ipc_dispatch_list
);
447 spin_unlock_irqrestore(&sst
->ipc_spin_lock
, irq_flags
);
448 sst
->ops
->post_message(sst
, NULL
, false);