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