root/sound/soc/intel/common/sst-dsp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sst_shim32_write
  2. sst_shim32_read
  3. sst_shim32_write64
  4. sst_shim32_read64
  5. _sst_memcpy_toio_32
  6. _sst_memcpy_fromio_32
  7. sst_memcpy_toio_32
  8. sst_memcpy_fromio_32
  9. sst_dsp_shim_write
  10. sst_dsp_shim_read
  11. sst_dsp_shim_write64
  12. sst_dsp_shim_read64
  13. sst_dsp_shim_write_unlocked
  14. sst_dsp_shim_read_unlocked
  15. sst_dsp_shim_write64_unlocked
  16. sst_dsp_shim_read64_unlocked
  17. sst_dsp_shim_update_bits_unlocked
  18. sst_dsp_shim_update_bits64_unlocked
  19. sst_dsp_shim_update_bits_forced_unlocked
  20. sst_dsp_shim_update_bits
  21. sst_dsp_shim_update_bits64
  22. sst_dsp_shim_update_bits_forced
  23. sst_dsp_register_poll
  24. sst_dsp_dump
  25. sst_dsp_reset
  26. sst_dsp_boot
  27. sst_dsp_wake
  28. sst_dsp_sleep
  29. sst_dsp_stall
  30. sst_dsp_ipc_msg_tx
  31. sst_dsp_ipc_msg_rx
  32. sst_dsp_mailbox_init
  33. sst_dsp_outbox_write
  34. sst_dsp_outbox_read
  35. sst_dsp_inbox_write
  36. sst_dsp_inbox_read

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

/* [<][>][^][v][top][bottom][index][help] */