Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.8-rc2 412 lines 9.9 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Intel Smart Sound Technology (SST) DSP Core Driver 4 * 5 * Copyright (C) 2013, Intel Corporation. All rights reserved. 6 */ 7 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> 15 16#include "sst-dsp.h" 17#include "sst-dsp-priv.h" 18 19#define CREATE_TRACE_POINTS 20#include <trace/events/intel-sst.h> 21 22/* Internal generic low-level SST IO functions - can be overidden */ 23void sst_shim32_write(void __iomem *addr, u32 offset, u32 value) 24{ 25 writel(value, addr + offset); 26} 27EXPORT_SYMBOL_GPL(sst_shim32_write); 28 29u32 sst_shim32_read(void __iomem *addr, u32 offset) 30{ 31 return readl(addr + offset); 32} 33EXPORT_SYMBOL_GPL(sst_shim32_read); 34 35void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value) 36{ 37 writeq(value, addr + offset); 38} 39EXPORT_SYMBOL_GPL(sst_shim32_write64); 40 41u64 sst_shim32_read64(void __iomem *addr, u32 offset) 42{ 43 return readq(addr + offset); 44} 45EXPORT_SYMBOL_GPL(sst_shim32_read64); 46 47static inline void _sst_memcpy_toio_32(volatile u32 __iomem *dest, 48 u32 *src, size_t bytes) 49{ 50 int i, words = bytes >> 2; 51 52 for (i = 0; i < words; i++) 53 writel(src[i], dest + i); 54} 55 56static inline void _sst_memcpy_fromio_32(u32 *dest, 57 const volatile __iomem u32 *src, size_t bytes) 58{ 59 int i, words = bytes >> 2; 60 61 for (i = 0; i < words; i++) 62 dest[i] = readl(src + i); 63} 64 65void sst_memcpy_toio_32(struct sst_dsp *sst, 66 void __iomem *dest, void *src, size_t bytes) 67{ 68 _sst_memcpy_toio_32(dest, src, bytes); 69} 70EXPORT_SYMBOL_GPL(sst_memcpy_toio_32); 71 72void sst_memcpy_fromio_32(struct sst_dsp *sst, void *dest, 73 void __iomem *src, size_t bytes) 74{ 75 _sst_memcpy_fromio_32(dest, src, bytes); 76} 77EXPORT_SYMBOL_GPL(sst_memcpy_fromio_32); 78 79/* Public API */ 80void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value) 81{ 82 unsigned long flags; 83 84 spin_lock_irqsave(&sst->spinlock, flags); 85 sst->ops->write(sst->addr.shim, offset, value); 86 spin_unlock_irqrestore(&sst->spinlock, flags); 87} 88EXPORT_SYMBOL_GPL(sst_dsp_shim_write); 89 90u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset) 91{ 92 unsigned long flags; 93 u32 val; 94 95 spin_lock_irqsave(&sst->spinlock, flags); 96 val = sst->ops->read(sst->addr.shim, offset); 97 spin_unlock_irqrestore(&sst->spinlock, flags); 98 99 return val; 100} 101EXPORT_SYMBOL_GPL(sst_dsp_shim_read); 102 103void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value) 104{ 105 unsigned long flags; 106 107 spin_lock_irqsave(&sst->spinlock, flags); 108 sst->ops->write64(sst->addr.shim, offset, value); 109 spin_unlock_irqrestore(&sst->spinlock, flags); 110} 111EXPORT_SYMBOL_GPL(sst_dsp_shim_write64); 112 113u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset) 114{ 115 unsigned long flags; 116 u64 val; 117 118 spin_lock_irqsave(&sst->spinlock, flags); 119 val = sst->ops->read64(sst->addr.shim, offset); 120 spin_unlock_irqrestore(&sst->spinlock, flags); 121 122 return val; 123} 124EXPORT_SYMBOL_GPL(sst_dsp_shim_read64); 125 126void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value) 127{ 128 sst->ops->write(sst->addr.shim, offset, value); 129} 130EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked); 131 132u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset) 133{ 134 return sst->ops->read(sst->addr.shim, offset); 135} 136EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked); 137 138void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value) 139{ 140 sst->ops->write64(sst->addr.shim, offset, value); 141} 142EXPORT_SYMBOL_GPL(sst_dsp_shim_write64_unlocked); 143 144u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset) 145{ 146 return sst->ops->read64(sst->addr.shim, offset); 147} 148EXPORT_SYMBOL_GPL(sst_dsp_shim_read64_unlocked); 149 150int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset, 151 u32 mask, u32 value) 152{ 153 bool change; 154 unsigned int old, new; 155 u32 ret; 156 157 ret = sst_dsp_shim_read_unlocked(sst, offset); 158 159 old = ret; 160 new = (old & (~mask)) | (value & mask); 161 162 change = (old != new); 163 if (change) 164 sst_dsp_shim_write_unlocked(sst, offset, new); 165 166 return change; 167} 168EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked); 169 170int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset, 171 u64 mask, u64 value) 172{ 173 bool change; 174 u64 old, new; 175 176 old = sst_dsp_shim_read64_unlocked(sst, offset); 177 178 new = (old & (~mask)) | (value & mask); 179 180 change = (old != new); 181 if (change) 182 sst_dsp_shim_write64_unlocked(sst, offset, new); 183 184 return change; 185} 186EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked); 187 188/* This is for registers bits with attribute RWC */ 189void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset, 190 u32 mask, u32 value) 191{ 192 unsigned int old, new; 193 u32 ret; 194 195 ret = sst_dsp_shim_read_unlocked(sst, offset); 196 197 old = ret; 198 new = (old & (~mask)) | (value & mask); 199 200 sst_dsp_shim_write_unlocked(sst, offset, new); 201} 202EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced_unlocked); 203 204int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, 205 u32 mask, u32 value) 206{ 207 unsigned long flags; 208 bool change; 209 210 spin_lock_irqsave(&sst->spinlock, flags); 211 change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value); 212 spin_unlock_irqrestore(&sst->spinlock, flags); 213 return change; 214} 215EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits); 216 217int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset, 218 u64 mask, u64 value) 219{ 220 unsigned long flags; 221 bool change; 222 223 spin_lock_irqsave(&sst->spinlock, flags); 224 change = sst_dsp_shim_update_bits64_unlocked(sst, offset, mask, value); 225 spin_unlock_irqrestore(&sst->spinlock, flags); 226 return change; 227} 228EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64); 229 230/* This is for registers bits with attribute RWC */ 231void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset, 232 u32 mask, u32 value) 233{ 234 unsigned long flags; 235 236 spin_lock_irqsave(&sst->spinlock, flags); 237 sst_dsp_shim_update_bits_forced_unlocked(sst, offset, mask, value); 238 spin_unlock_irqrestore(&sst->spinlock, flags); 239} 240EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced); 241 242int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, 243 u32 target, u32 time, char *operation) 244{ 245 u32 reg; 246 unsigned long timeout; 247 int k = 0, s = 500; 248 249 /* 250 * split the loop into sleeps of varying resolution. more accurately, 251 * the range of wakeups are: 252 * Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms. 253 * Phase 2:( 5ms to 10ms) : min sleep 0.5ms; max sleep 10ms 254 * (usleep_range (500, 1000) and usleep_range(5000, 10000) are 255 * both possible in this phase depending on whether k > 10 or not). 256 * Phase 3: (beyond 10 ms) min sleep 5ms; max sleep 10ms. 257 */ 258 259 timeout = jiffies + msecs_to_jiffies(time); 260 while ((((reg = sst_dsp_shim_read_unlocked(ctx, offset)) & mask) != target) 261 && time_before(jiffies, timeout)) { 262 k++; 263 if (k > 10) 264 s = 5000; 265 266 usleep_range(s, 2*s); 267 } 268 269 if ((reg & mask) == target) { 270 dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n", 271 reg, operation); 272 273 return 0; 274 } 275 276 dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s timedout\n", 277 reg, operation); 278 return -ETIME; 279} 280EXPORT_SYMBOL_GPL(sst_dsp_register_poll); 281 282void sst_dsp_dump(struct sst_dsp *sst) 283{ 284 if (sst->ops->dump) 285 sst->ops->dump(sst); 286} 287EXPORT_SYMBOL_GPL(sst_dsp_dump); 288 289void sst_dsp_reset(struct sst_dsp *sst) 290{ 291 if (sst->ops->reset) 292 sst->ops->reset(sst); 293} 294EXPORT_SYMBOL_GPL(sst_dsp_reset); 295 296int sst_dsp_boot(struct sst_dsp *sst) 297{ 298 if (sst->ops->boot) 299 sst->ops->boot(sst); 300 301 return 0; 302} 303EXPORT_SYMBOL_GPL(sst_dsp_boot); 304 305int sst_dsp_wake(struct sst_dsp *sst) 306{ 307 if (sst->ops->wake) 308 return sst->ops->wake(sst); 309 310 return 0; 311} 312EXPORT_SYMBOL_GPL(sst_dsp_wake); 313 314void sst_dsp_sleep(struct sst_dsp *sst) 315{ 316 if (sst->ops->sleep) 317 sst->ops->sleep(sst); 318} 319EXPORT_SYMBOL_GPL(sst_dsp_sleep); 320 321void sst_dsp_stall(struct sst_dsp *sst) 322{ 323 if (sst->ops->stall) 324 sst->ops->stall(sst); 325} 326EXPORT_SYMBOL_GPL(sst_dsp_stall); 327 328void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg) 329{ 330 sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY); 331 trace_sst_ipc_msg_tx(msg); 332} 333EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_tx); 334 335u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp) 336{ 337 u32 msg; 338 339 msg = sst_dsp_shim_read_unlocked(dsp, SST_IPCX); 340 trace_sst_ipc_msg_rx(msg); 341 342 return msg; 343} 344EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_rx); 345 346int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size, 347 u32 outbox_offset, size_t outbox_size) 348{ 349 sst->mailbox.in_base = sst->addr.lpe + inbox_offset; 350 sst->mailbox.out_base = sst->addr.lpe + outbox_offset; 351 sst->mailbox.in_size = inbox_size; 352 sst->mailbox.out_size = outbox_size; 353 return 0; 354} 355EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init); 356 357void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes) 358{ 359 u32 i; 360 361 trace_sst_ipc_outbox_write(bytes); 362 363 memcpy_toio(sst->mailbox.out_base, message, bytes); 364 365 for (i = 0; i < bytes; i += 4) 366 trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i)); 367} 368EXPORT_SYMBOL_GPL(sst_dsp_outbox_write); 369 370void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes) 371{ 372 u32 i; 373 374 trace_sst_ipc_outbox_read(bytes); 375 376 memcpy_fromio(message, sst->mailbox.out_base, bytes); 377 378 for (i = 0; i < bytes; i += 4) 379 trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i)); 380} 381EXPORT_SYMBOL_GPL(sst_dsp_outbox_read); 382 383void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes) 384{ 385 u32 i; 386 387 trace_sst_ipc_inbox_write(bytes); 388 389 memcpy_toio(sst->mailbox.in_base, message, bytes); 390 391 for (i = 0; i < bytes; i += 4) 392 trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i)); 393} 394EXPORT_SYMBOL_GPL(sst_dsp_inbox_write); 395 396void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes) 397{ 398 u32 i; 399 400 trace_sst_ipc_inbox_read(bytes); 401 402 memcpy_fromio(message, sst->mailbox.in_base, bytes); 403 404 for (i = 0; i < bytes; i += 4) 405 trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i)); 406} 407EXPORT_SYMBOL_GPL(sst_dsp_inbox_read); 408 409/* Module information */ 410MODULE_AUTHOR("Liam Girdwood"); 411MODULE_DESCRIPTION("Intel SST Core"); 412MODULE_LICENSE("GPL v2");