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 void sst_dsp_ipc_msg_tx(struct sst_dsp
*dsp
, u32 msg
)
250 sst_dsp_shim_write_unlocked(dsp
, SST_IPCX
, msg
| SST_IPCX_BUSY
);
251 trace_sst_ipc_msg_tx(msg
);
253 EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_tx
);
255 u32
sst_dsp_ipc_msg_rx(struct sst_dsp
*dsp
)
259 msg
= sst_dsp_shim_read_unlocked(dsp
, SST_IPCX
);
260 trace_sst_ipc_msg_rx(msg
);
264 EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_rx
);
266 int sst_dsp_mailbox_init(struct sst_dsp
*sst
, u32 inbox_offset
, size_t inbox_size
,
267 u32 outbox_offset
, size_t outbox_size
)
269 sst
->mailbox
.in_base
= sst
->addr
.lpe
+ inbox_offset
;
270 sst
->mailbox
.out_base
= sst
->addr
.lpe
+ outbox_offset
;
271 sst
->mailbox
.in_size
= inbox_size
;
272 sst
->mailbox
.out_size
= outbox_size
;
275 EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init
);
277 void sst_dsp_outbox_write(struct sst_dsp
*sst
, void *message
, size_t bytes
)
281 trace_sst_ipc_outbox_write(bytes
);
283 memcpy_toio(sst
->mailbox
.out_base
, message
, bytes
);
285 for (i
= 0; i
< bytes
; i
+= 4)
286 trace_sst_ipc_outbox_wdata(i
, *(u32
*)(message
+ i
));
288 EXPORT_SYMBOL_GPL(sst_dsp_outbox_write
);
290 void sst_dsp_outbox_read(struct sst_dsp
*sst
, void *message
, size_t bytes
)
294 trace_sst_ipc_outbox_read(bytes
);
296 memcpy_fromio(message
, sst
->mailbox
.out_base
, bytes
);
298 for (i
= 0; i
< bytes
; i
+= 4)
299 trace_sst_ipc_outbox_rdata(i
, *(u32
*)(message
+ i
));
301 EXPORT_SYMBOL_GPL(sst_dsp_outbox_read
);
303 void sst_dsp_inbox_write(struct sst_dsp
*sst
, void *message
, size_t bytes
)
307 trace_sst_ipc_inbox_write(bytes
);
309 memcpy_toio(sst
->mailbox
.in_base
, message
, bytes
);
311 for (i
= 0; i
< bytes
; i
+= 4)
312 trace_sst_ipc_inbox_wdata(i
, *(u32
*)(message
+ i
));
314 EXPORT_SYMBOL_GPL(sst_dsp_inbox_write
);
316 void sst_dsp_inbox_read(struct sst_dsp
*sst
, void *message
, size_t bytes
)
320 trace_sst_ipc_inbox_read(bytes
);
322 memcpy_fromio(message
, sst
->mailbox
.in_base
, bytes
);
324 for (i
= 0; i
< bytes
; i
+= 4)
325 trace_sst_ipc_inbox_rdata(i
, *(u32
*)(message
+ i
));
327 EXPORT_SYMBOL_GPL(sst_dsp_inbox_read
);
329 struct sst_dsp
*sst_dsp_new(struct device
*dev
,
330 struct sst_dsp_device
*sst_dev
, struct sst_pdata
*pdata
)
335 dev_dbg(dev
, "initialising audio DSP id 0x%x\n", pdata
->id
);
337 sst
= devm_kzalloc(dev
, sizeof(*sst
), GFP_KERNEL
);
341 spin_lock_init(&sst
->spinlock
);
342 mutex_init(&sst
->mutex
);
344 sst
->dma_dev
= pdata
->dma_dev
;
345 sst
->thread_context
= sst_dev
->thread_context
;
346 sst
->sst_dev
= sst_dev
;
348 sst
->irq
= pdata
->irq
;
349 sst
->ops
= sst_dev
->ops
;
351 INIT_LIST_HEAD(&sst
->used_block_list
);
352 INIT_LIST_HEAD(&sst
->free_block_list
);
353 INIT_LIST_HEAD(&sst
->module_list
);
354 INIT_LIST_HEAD(&sst
->fw_list
);
356 /* Initialise SST Audio DSP */
357 if (sst
->ops
->init
) {
358 err
= sst
->ops
->init(sst
, pdata
);
363 /* Register the ISR */
364 err
= request_threaded_irq(sst
->irq
, sst
->ops
->irq_handler
,
365 sst_dev
->thread
, IRQF_SHARED
, "AudioDSP", sst
);
377 EXPORT_SYMBOL_GPL(sst_dsp_new
);
379 void sst_dsp_free(struct sst_dsp
*sst
)
381 free_irq(sst
->irq
, sst
);
385 EXPORT_SYMBOL_GPL(sst_dsp_free
);
387 /* Module information */
388 MODULE_AUTHOR("Liam Girdwood");
389 MODULE_DESCRIPTION("Intel SST Core");
390 MODULE_LICENSE("GPL v2");