1 // SPDX-License-Identifier: GPL-2.0-only
3 * Intel Smart Sound Technology (SST) DSP Core Driver
5 * Copyright (C) 2013, Intel Corporation. All rights reserved.
8 #include <linux/slab.h>
9 #include <linux/export.h>
10 #include <linux/interrupt.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/io-64-nonatomic-lo-hi.h>
14 #include <linux/delay.h>
17 #include "sst-dsp-priv.h"
19 #define CREATE_TRACE_POINTS
20 #include <trace/events/intel-sst.h>
22 /* Internal generic low-level SST IO functions - can be overidden */
23 void sst_shim32_write(void __iomem
*addr
, u32 offset
, u32 value
)
25 writel(value
, addr
+ offset
);
27 EXPORT_SYMBOL_GPL(sst_shim32_write
);
29 u32
sst_shim32_read(void __iomem
*addr
, u32 offset
)
31 return readl(addr
+ offset
);
33 EXPORT_SYMBOL_GPL(sst_shim32_read
);
35 void sst_shim32_write64(void __iomem
*addr
, u32 offset
, u64 value
)
37 writeq(value
, addr
+ offset
);
39 EXPORT_SYMBOL_GPL(sst_shim32_write64
);
41 u64
sst_shim32_read64(void __iomem
*addr
, u32 offset
)
43 return readq(addr
+ offset
);
45 EXPORT_SYMBOL_GPL(sst_shim32_read64
);
48 void sst_dsp_shim_write(struct sst_dsp
*sst
, u32 offset
, u32 value
)
52 spin_lock_irqsave(&sst
->spinlock
, flags
);
53 sst
->ops
->write(sst
->addr
.shim
, offset
, value
);
54 spin_unlock_irqrestore(&sst
->spinlock
, flags
);
56 EXPORT_SYMBOL_GPL(sst_dsp_shim_write
);
58 u32
sst_dsp_shim_read(struct sst_dsp
*sst
, u32 offset
)
63 spin_lock_irqsave(&sst
->spinlock
, flags
);
64 val
= sst
->ops
->read(sst
->addr
.shim
, offset
);
65 spin_unlock_irqrestore(&sst
->spinlock
, flags
);
69 EXPORT_SYMBOL_GPL(sst_dsp_shim_read
);
71 void sst_dsp_shim_write_unlocked(struct sst_dsp
*sst
, u32 offset
, u32 value
)
73 sst
->ops
->write(sst
->addr
.shim
, offset
, value
);
75 EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked
);
77 u32
sst_dsp_shim_read_unlocked(struct sst_dsp
*sst
, u32 offset
)
79 return sst
->ops
->read(sst
->addr
.shim
, offset
);
81 EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked
);
83 int sst_dsp_shim_update_bits_unlocked(struct sst_dsp
*sst
, u32 offset
,
87 unsigned int old
, new;
90 ret
= sst_dsp_shim_read_unlocked(sst
, offset
);
93 new = (old
& (~mask
)) | (value
& mask
);
95 change
= (old
!= new);
97 sst_dsp_shim_write_unlocked(sst
, offset
, new);
101 EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked
);
103 /* This is for registers bits with attribute RWC */
104 void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp
*sst
, u32 offset
,
107 unsigned int old
, new;
110 ret
= sst_dsp_shim_read_unlocked(sst
, offset
);
113 new = (old
& (~mask
)) | (value
& mask
);
115 sst_dsp_shim_write_unlocked(sst
, offset
, new);
117 EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced_unlocked
);
119 int sst_dsp_shim_update_bits(struct sst_dsp
*sst
, u32 offset
,
125 spin_lock_irqsave(&sst
->spinlock
, flags
);
126 change
= sst_dsp_shim_update_bits_unlocked(sst
, offset
, mask
, value
);
127 spin_unlock_irqrestore(&sst
->spinlock
, flags
);
130 EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits
);
132 /* This is for registers bits with attribute RWC */
133 void sst_dsp_shim_update_bits_forced(struct sst_dsp
*sst
, u32 offset
,
138 spin_lock_irqsave(&sst
->spinlock
, flags
);
139 sst_dsp_shim_update_bits_forced_unlocked(sst
, offset
, mask
, value
);
140 spin_unlock_irqrestore(&sst
->spinlock
, flags
);
142 EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced
);
144 int sst_dsp_register_poll(struct sst_dsp
*ctx
, u32 offset
, u32 mask
,
145 u32 target
, u32 time
, char *operation
)
148 unsigned long timeout
;
152 * split the loop into sleeps of varying resolution. more accurately,
153 * the range of wakeups are:
154 * Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms.
155 * Phase 2:( 5ms to 10ms) : min sleep 0.5ms; max sleep 10ms
156 * (usleep_range (500, 1000) and usleep_range(5000, 10000) are
157 * both possible in this phase depending on whether k > 10 or not).
158 * Phase 3: (beyond 10 ms) min sleep 5ms; max sleep 10ms.
161 timeout
= jiffies
+ msecs_to_jiffies(time
);
162 while ((((reg
= sst_dsp_shim_read_unlocked(ctx
, offset
)) & mask
) != target
)
163 && time_before(jiffies
, timeout
)) {
168 usleep_range(s
, 2*s
);
171 if ((reg
& mask
) == target
) {
172 dev_dbg(ctx
->dev
, "FW Poll Status: reg=%#x %s successful\n",
178 dev_dbg(ctx
->dev
, "FW Poll Status: reg=%#x %s timedout\n",
182 EXPORT_SYMBOL_GPL(sst_dsp_register_poll
);
184 int sst_dsp_mailbox_init(struct sst_dsp
*sst
, u32 inbox_offset
, size_t inbox_size
,
185 u32 outbox_offset
, size_t outbox_size
)
187 sst
->mailbox
.in_base
= sst
->addr
.lpe
+ inbox_offset
;
188 sst
->mailbox
.out_base
= sst
->addr
.lpe
+ outbox_offset
;
189 sst
->mailbox
.in_size
= inbox_size
;
190 sst
->mailbox
.out_size
= outbox_size
;
193 EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init
);
195 void sst_dsp_outbox_write(struct sst_dsp
*sst
, void *message
, size_t bytes
)
199 trace_sst_ipc_outbox_write(bytes
);
201 memcpy_toio(sst
->mailbox
.out_base
, message
, bytes
);
203 for (i
= 0; i
< bytes
; i
+= 4)
204 trace_sst_ipc_outbox_wdata(i
, *(u32
*)(message
+ i
));
206 EXPORT_SYMBOL_GPL(sst_dsp_outbox_write
);
208 void sst_dsp_outbox_read(struct sst_dsp
*sst
, void *message
, size_t bytes
)
212 trace_sst_ipc_outbox_read(bytes
);
214 memcpy_fromio(message
, sst
->mailbox
.out_base
, bytes
);
216 for (i
= 0; i
< bytes
; i
+= 4)
217 trace_sst_ipc_outbox_rdata(i
, *(u32
*)(message
+ i
));
219 EXPORT_SYMBOL_GPL(sst_dsp_outbox_read
);
221 void sst_dsp_inbox_write(struct sst_dsp
*sst
, void *message
, size_t bytes
)
225 trace_sst_ipc_inbox_write(bytes
);
227 memcpy_toio(sst
->mailbox
.in_base
, message
, bytes
);
229 for (i
= 0; i
< bytes
; i
+= 4)
230 trace_sst_ipc_inbox_wdata(i
, *(u32
*)(message
+ i
));
232 EXPORT_SYMBOL_GPL(sst_dsp_inbox_write
);
234 void sst_dsp_inbox_read(struct sst_dsp
*sst
, void *message
, size_t bytes
)
238 trace_sst_ipc_inbox_read(bytes
);
240 memcpy_fromio(message
, sst
->mailbox
.in_base
, bytes
);
242 for (i
= 0; i
< bytes
; i
+= 4)
243 trace_sst_ipc_inbox_rdata(i
, *(u32
*)(message
+ i
));
245 EXPORT_SYMBOL_GPL(sst_dsp_inbox_read
);
247 /* Module information */
248 MODULE_AUTHOR("Liam Girdwood");
249 MODULE_DESCRIPTION("Intel SST Core");
250 MODULE_LICENSE("GPL v2");