2 * Intel Smart Sound Technology (SST) DSP Core Driver
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
17 #include <linux/slab.h>
18 #include <linux/export.h>
19 #include <linux/interrupt.h>
20 #include <linux/module.h>
21 #include <linux/platform_device.h>
25 #include "sst-dsp-priv.h"
27 #define CREATE_TRACE_POINTS
28 #include <trace/events/intel-sst.h>
30 /* Internal generic low-level SST IO functions - can be overidden */
31 void sst_shim32_write(void __iomem
*addr
, u32 offset
, u32 value
)
33 writel(value
, addr
+ offset
);
35 EXPORT_SYMBOL_GPL(sst_shim32_write
);
37 u32
sst_shim32_read(void __iomem
*addr
, u32 offset
)
39 return readl(addr
+ offset
);
41 EXPORT_SYMBOL_GPL(sst_shim32_read
);
43 void sst_shim32_write64(void __iomem
*addr
, u32 offset
, u64 value
)
45 memcpy_toio(addr
+ offset
, &value
, sizeof(value
));
47 EXPORT_SYMBOL_GPL(sst_shim32_write64
);
49 u64
sst_shim32_read64(void __iomem
*addr
, u32 offset
)
53 memcpy_fromio(&val
, addr
+ offset
, sizeof(val
));
56 EXPORT_SYMBOL_GPL(sst_shim32_read64
);
58 static inline void _sst_memcpy_toio_32(volatile u32 __iomem
*dest
,
59 u32
*src
, size_t bytes
)
61 int i
, words
= bytes
>> 2;
63 for (i
= 0; i
< words
; i
++)
64 writel(src
[i
], dest
+ i
);
67 static inline void _sst_memcpy_fromio_32(u32
*dest
,
68 const volatile __iomem u32
*src
, size_t bytes
)
70 int i
, words
= bytes
>> 2;
72 for (i
= 0; i
< words
; i
++)
73 dest
[i
] = readl(src
+ i
);
76 void sst_memcpy_toio_32(struct sst_dsp
*sst
,
77 void __iomem
*dest
, void *src
, size_t bytes
)
79 _sst_memcpy_toio_32(dest
, src
, bytes
);
81 EXPORT_SYMBOL_GPL(sst_memcpy_toio_32
);
83 void sst_memcpy_fromio_32(struct sst_dsp
*sst
, void *dest
,
84 void __iomem
*src
, size_t bytes
)
86 _sst_memcpy_fromio_32(dest
, src
, bytes
);
88 EXPORT_SYMBOL_GPL(sst_memcpy_fromio_32
);
91 void sst_dsp_shim_write(struct sst_dsp
*sst
, u32 offset
, u32 value
)
95 spin_lock_irqsave(&sst
->spinlock
, flags
);
96 sst
->ops
->write(sst
->addr
.shim
, offset
, value
);
97 spin_unlock_irqrestore(&sst
->spinlock
, flags
);
99 EXPORT_SYMBOL_GPL(sst_dsp_shim_write
);
101 u32
sst_dsp_shim_read(struct sst_dsp
*sst
, u32 offset
)
106 spin_lock_irqsave(&sst
->spinlock
, flags
);
107 val
= sst
->ops
->read(sst
->addr
.shim
, offset
);
108 spin_unlock_irqrestore(&sst
->spinlock
, flags
);
112 EXPORT_SYMBOL_GPL(sst_dsp_shim_read
);
114 void sst_dsp_shim_write64(struct sst_dsp
*sst
, u32 offset
, u64 value
)
118 spin_lock_irqsave(&sst
->spinlock
, flags
);
119 sst
->ops
->write64(sst
->addr
.shim
, offset
, value
);
120 spin_unlock_irqrestore(&sst
->spinlock
, flags
);
122 EXPORT_SYMBOL_GPL(sst_dsp_shim_write64
);
124 u64
sst_dsp_shim_read64(struct sst_dsp
*sst
, u32 offset
)
129 spin_lock_irqsave(&sst
->spinlock
, flags
);
130 val
= sst
->ops
->read64(sst
->addr
.shim
, offset
);
131 spin_unlock_irqrestore(&sst
->spinlock
, flags
);
135 EXPORT_SYMBOL_GPL(sst_dsp_shim_read64
);
137 void sst_dsp_shim_write_unlocked(struct sst_dsp
*sst
, u32 offset
, u32 value
)
139 sst
->ops
->write(sst
->addr
.shim
, offset
, value
);
141 EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked
);
143 u32
sst_dsp_shim_read_unlocked(struct sst_dsp
*sst
, u32 offset
)
145 return sst
->ops
->read(sst
->addr
.shim
, offset
);
147 EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked
);
149 void sst_dsp_shim_write64_unlocked(struct sst_dsp
*sst
, u32 offset
, u64 value
)
151 sst
->ops
->write64(sst
->addr
.shim
, offset
, value
);
153 EXPORT_SYMBOL_GPL(sst_dsp_shim_write64_unlocked
);
155 u64
sst_dsp_shim_read64_unlocked(struct sst_dsp
*sst
, u32 offset
)
157 return sst
->ops
->read64(sst
->addr
.shim
, offset
);
159 EXPORT_SYMBOL_GPL(sst_dsp_shim_read64_unlocked
);
161 int sst_dsp_shim_update_bits_unlocked(struct sst_dsp
*sst
, u32 offset
,
165 unsigned int old
, new;
168 ret
= sst_dsp_shim_read_unlocked(sst
, offset
);
171 new = (old
& (~mask
)) | (value
& mask
);
173 change
= (old
!= new);
175 sst_dsp_shim_write_unlocked(sst
, offset
, new);
179 EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked
);
181 int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp
*sst
, u32 offset
,
187 old
= sst_dsp_shim_read64_unlocked(sst
, offset
);
189 new = (old
& (~mask
)) | (value
& mask
);
191 change
= (old
!= new);
193 sst_dsp_shim_write64_unlocked(sst
, offset
, new);
197 EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked
);
199 int sst_dsp_shim_update_bits(struct sst_dsp
*sst
, u32 offset
,
205 spin_lock_irqsave(&sst
->spinlock
, flags
);
206 change
= sst_dsp_shim_update_bits_unlocked(sst
, offset
, mask
, value
);
207 spin_unlock_irqrestore(&sst
->spinlock
, flags
);
210 EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits
);
212 int sst_dsp_shim_update_bits64(struct sst_dsp
*sst
, u32 offset
,
218 spin_lock_irqsave(&sst
->spinlock
, flags
);
219 change
= sst_dsp_shim_update_bits64_unlocked(sst
, offset
, mask
, value
);
220 spin_unlock_irqrestore(&sst
->spinlock
, flags
);
223 EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64
);
225 void sst_dsp_dump(struct sst_dsp
*sst
)
230 EXPORT_SYMBOL_GPL(sst_dsp_dump
);
232 void sst_dsp_reset(struct sst_dsp
*sst
)
235 sst
->ops
->reset(sst
);
237 EXPORT_SYMBOL_GPL(sst_dsp_reset
);
239 int sst_dsp_boot(struct sst_dsp
*sst
)
246 EXPORT_SYMBOL_GPL(sst_dsp_boot
);
248 int sst_dsp_wake(struct sst_dsp
*sst
)
251 return sst
->ops
->wake(sst
);
255 EXPORT_SYMBOL_GPL(sst_dsp_wake
);
257 void sst_dsp_sleep(struct sst_dsp
*sst
)
260 sst
->ops
->sleep(sst
);
262 EXPORT_SYMBOL_GPL(sst_dsp_sleep
);
264 void sst_dsp_stall(struct sst_dsp
*sst
)
267 sst
->ops
->stall(sst
);
269 EXPORT_SYMBOL_GPL(sst_dsp_stall
);
271 void sst_dsp_ipc_msg_tx(struct sst_dsp
*dsp
, u32 msg
)
273 sst_dsp_shim_write_unlocked(dsp
, SST_IPCX
, msg
| SST_IPCX_BUSY
);
274 trace_sst_ipc_msg_tx(msg
);
276 EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_tx
);
278 u32
sst_dsp_ipc_msg_rx(struct sst_dsp
*dsp
)
282 msg
= sst_dsp_shim_read_unlocked(dsp
, SST_IPCX
);
283 trace_sst_ipc_msg_rx(msg
);
287 EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_rx
);
289 int sst_dsp_mailbox_init(struct sst_dsp
*sst
, u32 inbox_offset
, size_t inbox_size
,
290 u32 outbox_offset
, size_t outbox_size
)
292 sst
->mailbox
.in_base
= sst
->addr
.lpe
+ inbox_offset
;
293 sst
->mailbox
.out_base
= sst
->addr
.lpe
+ outbox_offset
;
294 sst
->mailbox
.in_size
= inbox_size
;
295 sst
->mailbox
.out_size
= outbox_size
;
298 EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init
);
300 void sst_dsp_outbox_write(struct sst_dsp
*sst
, void *message
, size_t bytes
)
304 trace_sst_ipc_outbox_write(bytes
);
306 memcpy_toio(sst
->mailbox
.out_base
, message
, bytes
);
308 for (i
= 0; i
< bytes
; i
+= 4)
309 trace_sst_ipc_outbox_wdata(i
, *(u32
*)(message
+ i
));
311 EXPORT_SYMBOL_GPL(sst_dsp_outbox_write
);
313 void sst_dsp_outbox_read(struct sst_dsp
*sst
, void *message
, size_t bytes
)
317 trace_sst_ipc_outbox_read(bytes
);
319 memcpy_fromio(message
, sst
->mailbox
.out_base
, bytes
);
321 for (i
= 0; i
< bytes
; i
+= 4)
322 trace_sst_ipc_outbox_rdata(i
, *(u32
*)(message
+ i
));
324 EXPORT_SYMBOL_GPL(sst_dsp_outbox_read
);
326 void sst_dsp_inbox_write(struct sst_dsp
*sst
, void *message
, size_t bytes
)
330 trace_sst_ipc_inbox_write(bytes
);
332 memcpy_toio(sst
->mailbox
.in_base
, message
, bytes
);
334 for (i
= 0; i
< bytes
; i
+= 4)
335 trace_sst_ipc_inbox_wdata(i
, *(u32
*)(message
+ i
));
337 EXPORT_SYMBOL_GPL(sst_dsp_inbox_write
);
339 void sst_dsp_inbox_read(struct sst_dsp
*sst
, void *message
, size_t bytes
)
343 trace_sst_ipc_inbox_read(bytes
);
345 memcpy_fromio(message
, sst
->mailbox
.in_base
, bytes
);
347 for (i
= 0; i
< bytes
; i
+= 4)
348 trace_sst_ipc_inbox_rdata(i
, *(u32
*)(message
+ i
));
350 EXPORT_SYMBOL_GPL(sst_dsp_inbox_read
);
352 struct sst_dsp
*sst_dsp_new(struct device
*dev
,
353 struct sst_dsp_device
*sst_dev
, struct sst_pdata
*pdata
)
358 dev_dbg(dev
, "initialising audio DSP id 0x%x\n", pdata
->id
);
360 sst
= devm_kzalloc(dev
, sizeof(*sst
), GFP_KERNEL
);
364 spin_lock_init(&sst
->spinlock
);
365 mutex_init(&sst
->mutex
);
367 sst
->dma_dev
= pdata
->dma_dev
;
368 sst
->thread_context
= sst_dev
->thread_context
;
369 sst
->sst_dev
= sst_dev
;
371 sst
->irq
= pdata
->irq
;
372 sst
->ops
= sst_dev
->ops
;
374 INIT_LIST_HEAD(&sst
->used_block_list
);
375 INIT_LIST_HEAD(&sst
->free_block_list
);
376 INIT_LIST_HEAD(&sst
->module_list
);
377 INIT_LIST_HEAD(&sst
->fw_list
);
378 INIT_LIST_HEAD(&sst
->scratch_block_list
);
380 /* Initialise SST Audio DSP */
381 if (sst
->ops
->init
) {
382 err
= sst
->ops
->init(sst
, pdata
);
387 /* Register the ISR */
388 err
= request_threaded_irq(sst
->irq
, sst
->ops
->irq_handler
,
389 sst_dev
->thread
, IRQF_SHARED
, "AudioDSP", sst
);
393 err
= sst_dma_new(sst
);
395 dev_warn(dev
, "sst_dma_new failed %d\n", err
);
405 EXPORT_SYMBOL_GPL(sst_dsp_new
);
407 void sst_dsp_free(struct sst_dsp
*sst
)
409 free_irq(sst
->irq
, sst
);
414 sst_dma_free(sst
->dma
);
416 EXPORT_SYMBOL_GPL(sst_dsp_free
);
418 /* Module information */
419 MODULE_AUTHOR("Liam Girdwood");
420 MODULE_DESCRIPTION("Intel SST Core");
421 MODULE_LICENSE("GPL v2");