ASoC: Intel: create baytrail folder and move baytrail platform files in
authorJie Yang <yang.jie@intel.com>
Thu, 2 Apr 2015 07:37:03 +0000 (15:37 +0800)
committerMark Brown <broonie@kernel.org>
Mon, 6 Apr 2015 16:49:45 +0000 (17:49 +0100)
Restructure the sound/soc/intel/ directory: create baytrail folder, and move
sst baytrail platform files here.

Signed-off-by: Jie Yang <yang.jie@intel.com>
Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/intel/Makefile
sound/soc/intel/baytrail/Makefile [new file with mode: 0644]
sound/soc/intel/baytrail/sst-baytrail-dsp.c [new file with mode: 0644]
sound/soc/intel/baytrail/sst-baytrail-ipc.c [new file with mode: 0644]
sound/soc/intel/baytrail/sst-baytrail-ipc.h [new file with mode: 0644]
sound/soc/intel/baytrail/sst-baytrail-pcm.c [new file with mode: 0644]
sound/soc/intel/sst-baytrail-dsp.c [deleted file]
sound/soc/intel/sst-baytrail-ipc.c [deleted file]
sound/soc/intel/sst-baytrail-ipc.h [deleted file]
sound/soc/intel/sst-baytrail-pcm.c [deleted file]

index ac0248f100ff0fdbdb9dc4e30da2377b26ba49e5..62de82af670367af94ce9ceea872ca78c61525a9 100644 (file)
@@ -10,10 +10,7 @@ obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o
 
 # Platform Support
 obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/
-snd-soc-sst-baytrail-pcm-objs := \
-       sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o
-
-obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o
+obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/
 
 # Machine support
 obj-$(CONFIG_SND_SOC_INTEL_SST) += boards/
diff --git a/sound/soc/intel/baytrail/Makefile b/sound/soc/intel/baytrail/Makefile
new file mode 100644 (file)
index 0000000..488408c
--- /dev/null
@@ -0,0 +1,4 @@
+snd-soc-sst-baytrail-pcm-objs := \
+               sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o
+
+obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o
diff --git a/sound/soc/intel/baytrail/sst-baytrail-dsp.c b/sound/soc/intel/baytrail/sst-baytrail-dsp.c
new file mode 100644 (file)
index 0000000..01d023c
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * Intel Baytrail SST DSP driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+#include "sst-baytrail-ipc.h"
+
+#define SST_BYT_FW_SIGNATURE_SIZE      4
+#define SST_BYT_FW_SIGN                        "$SST"
+
+#define SST_BYT_IRAM_OFFSET    0xC0000
+#define SST_BYT_DRAM_OFFSET    0x100000
+#define SST_BYT_SHIM_OFFSET    0x140000
+
+enum sst_ram_type {
+       SST_BYT_IRAM    = 1,
+       SST_BYT_DRAM    = 2,
+       SST_BYT_CACHE   = 3,
+};
+
+struct dma_block_info {
+       enum sst_ram_type       type;   /* IRAM/DRAM */
+       u32                     size;   /* Bytes */
+       u32                     ram_offset; /* Offset in I/DRAM */
+       u32                     rsvd;   /* Reserved field */
+};
+
+struct fw_header {
+       unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
+       u32 file_size; /* size of fw minus this header */
+       u32 modules; /*  # of modules */
+       u32 file_format; /* version of header format */
+       u32 reserved[4];
+};
+
+struct sst_byt_fw_module_header {
+       unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
+       u32 mod_size; /* size of module */
+       u32 blocks; /* # of blocks */
+       u32 type; /* codec type, pp lib */
+       u32 entry_point;
+};
+
+static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
+                               struct sst_byt_fw_module_header *module)
+{
+       struct dma_block_info *block;
+       struct sst_module *mod;
+       struct sst_module_template template;
+       int count;
+
+       memset(&template, 0, sizeof(template));
+       template.id = module->type;
+       template.entry = module->entry_point;
+
+       mod = sst_module_new(fw, &template, NULL);
+       if (mod == NULL)
+               return -ENOMEM;
+
+       block = (void *)module + sizeof(*module);
+
+       for (count = 0; count < module->blocks; count++) {
+
+               if (block->size <= 0) {
+                       dev_err(dsp->dev, "block %d size invalid\n", count);
+                       return -EINVAL;
+               }
+
+               switch (block->type) {
+               case SST_BYT_IRAM:
+                       mod->offset = block->ram_offset +
+                                           dsp->addr.iram_offset;
+                       mod->type = SST_MEM_IRAM;
+                       break;
+               case SST_BYT_DRAM:
+                       mod->offset = block->ram_offset +
+                                           dsp->addr.dram_offset;
+                       mod->type = SST_MEM_DRAM;
+                       break;
+               case SST_BYT_CACHE:
+                       mod->offset = block->ram_offset +
+                                           (dsp->addr.fw_ext - dsp->addr.lpe);
+                       mod->type = SST_MEM_CACHE;
+                       break;
+               default:
+                       dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n",
+                               block->type, count);
+                       return -EINVAL;
+               }
+
+               mod->size = block->size;
+               mod->data = (void *)block + sizeof(*block);
+
+               sst_module_alloc_blocks(mod);
+
+               block = (void *)block + sizeof(*block) + block->size;
+       }
+       return 0;
+}
+
+static int sst_byt_parse_fw_image(struct sst_fw *sst_fw)
+{
+       struct fw_header *header;
+       struct sst_byt_fw_module_header *module;
+       struct sst_dsp *dsp = sst_fw->dsp;
+       int ret, count;
+
+       /* Read the header information from the data pointer */
+       header = (struct fw_header *)sst_fw->dma_buf;
+
+       /* verify FW */
+       if ((strncmp(header->signature, SST_BYT_FW_SIGN, 4) != 0) ||
+           (sst_fw->size != header->file_size + sizeof(*header))) {
+               /* Invalid FW signature */
+               dev_err(dsp->dev, "Invalid FW sign/filesize mismatch\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dsp->dev,
+               "header sign=%4s size=0x%x modules=0x%x fmt=0x%x size=%zu\n",
+               header->signature, header->file_size, header->modules,
+               header->file_format, sizeof(*header));
+
+       module = (void *)sst_fw->dma_buf + sizeof(*header);
+       for (count = 0; count < header->modules; count++) {
+               /* module */
+               ret = sst_byt_parse_module(dsp, sst_fw, module);
+               if (ret < 0) {
+                       dev_err(dsp->dev, "invalid module %d\n", count);
+                       return ret;
+               }
+               module = (void *)module + sizeof(*module) + module->mod_size;
+       }
+
+       return 0;
+}
+
+static void sst_byt_dump_shim(struct sst_dsp *sst)
+{
+       int i;
+       u64 reg;
+
+       for (i = 0; i <= 0xF0; i += 8) {
+               reg = sst_dsp_shim_read64_unlocked(sst, i);
+               if (reg)
+                       dev_dbg(sst->dev, "shim 0x%2.2x value 0x%16.16llx\n",
+                               i, reg);
+       }
+
+       for (i = 0x00; i <= 0xff; i += 4) {
+               reg = readl(sst->addr.pci_cfg + i);
+               if (reg)
+                       dev_dbg(sst->dev, "pci 0x%2.2x value 0x%8.8x\n",
+                               i, (u32)reg);
+       }
+}
+
+static irqreturn_t sst_byt_irq(int irq, void *context)
+{
+       struct sst_dsp *sst = (struct sst_dsp *) context;
+       u64 isrx;
+       irqreturn_t ret = IRQ_NONE;
+
+       spin_lock(&sst->spinlock);
+
+       isrx = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
+       if (isrx & SST_ISRX_DONE) {
+               /* ADSP has processed the message request from IA */
+               sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCX,
+                                                   SST_BYT_IPCX_DONE, 0);
+               ret = IRQ_WAKE_THREAD;
+       }
+       if (isrx & SST_BYT_ISRX_REQUEST) {
+               /* mask message request from ADSP and do processing later */
+               sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
+                                                   SST_BYT_IMRX_REQUEST,
+                                                   SST_BYT_IMRX_REQUEST);
+               ret = IRQ_WAKE_THREAD;
+       }
+
+       spin_unlock(&sst->spinlock);
+
+       return ret;
+}
+
+static void sst_byt_boot(struct sst_dsp *sst)
+{
+       int tries = 10;
+
+       /*
+        * save the physical address of extended firmware block in the first
+        * 4 bytes of the mailbox
+        */
+       memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
+              &sst->pdata->fw_base, sizeof(u32));
+
+       /* release stall and wait to unstall */
+       sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_STALL, 0x0);
+       while (tries--) {
+               if (!(sst_dsp_shim_read64(sst, SST_CSR) &
+                     SST_BYT_CSR_PWAITMODE))
+                       break;
+               msleep(100);
+       }
+       if (tries < 0) {
+               dev_err(sst->dev, "unable to start DSP\n");
+               sst_byt_dump_shim(sst);
+       }
+}
+
+static void sst_byt_reset(struct sst_dsp *sst)
+{
+       /* put DSP into reset, set reset vector and stall */
+       sst_dsp_shim_update_bits64(sst, SST_CSR,
+               SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL,
+               SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL);
+
+       udelay(10);
+
+       /* take DSP out of reset and keep stalled for FW loading */
+       sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_RST, 0);
+}
+
+struct sst_adsp_memregion {
+       u32 start;
+       u32 end;
+       int blocks;
+       enum sst_mem_type type;
+};
+
+/* BYT test stuff */
+static const struct sst_adsp_memregion byt_region[] = {
+       {0xC0000, 0x100000, 8, SST_MEM_IRAM}, /* I-SRAM - 8 * 32kB */
+       {0x100000, 0x140000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
+};
+
+static int sst_byt_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+       sst->addr.lpe_base = pdata->lpe_base;
+       sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size);
+       if (!sst->addr.lpe)
+               return -ENODEV;
+
+       /* ADSP PCI MMIO config space */
+       sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size);
+       if (!sst->addr.pci_cfg) {
+               iounmap(sst->addr.lpe);
+               return -ENODEV;
+       }
+
+       /* SST Extended FW allocation */
+       sst->addr.fw_ext = ioremap(pdata->fw_base, pdata->fw_size);
+       if (!sst->addr.fw_ext) {
+               iounmap(sst->addr.pci_cfg);
+               iounmap(sst->addr.lpe);
+               return -ENODEV;
+       }
+
+       /* SST Shim */
+       sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset;
+
+       sst_dsp_mailbox_init(sst, SST_BYT_MAILBOX_OFFSET + 0x204,
+                            SST_BYT_IPC_MAX_PAYLOAD_SIZE,
+                            SST_BYT_MAILBOX_OFFSET,
+                            SST_BYT_IPC_MAX_PAYLOAD_SIZE);
+
+       sst->irq = pdata->irq;
+
+       return 0;
+}
+
+static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+       const struct sst_adsp_memregion *region;
+       struct device *dev;
+       int ret = -ENODEV, i, j, region_count;
+       u32 offset, size;
+
+       dev = sst->dev;
+
+       switch (sst->id) {
+       case SST_DEV_ID_BYT:
+               region = byt_region;
+               region_count = ARRAY_SIZE(byt_region);
+               sst->addr.iram_offset = SST_BYT_IRAM_OFFSET;
+               sst->addr.dram_offset = SST_BYT_DRAM_OFFSET;
+               sst->addr.shim_offset = SST_BYT_SHIM_OFFSET;
+               break;
+       default:
+               dev_err(dev, "failed to get mem resources\n");
+               return ret;
+       }
+
+       ret = sst_byt_resource_map(sst, pdata);
+       if (ret < 0) {
+               dev_err(dev, "failed to map resources\n");
+               return ret;
+       }
+
+       ret = dma_coerce_mask_and_coherent(sst->dma_dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+
+       /* enable Interrupt from both sides */
+       sst_dsp_shim_update_bits64(sst, SST_IMRX, 0x3, 0x0);
+       sst_dsp_shim_update_bits64(sst, SST_IMRD, 0x3, 0x0);
+
+       /* register DSP memory blocks - ideally we should get this from ACPI */
+       for (i = 0; i < region_count; i++) {
+               offset = region[i].start;
+               size = (region[i].end - region[i].start) / region[i].blocks;
+
+               /* register individual memory blocks */
+               for (j = 0; j < region[i].blocks; j++) {
+                       sst_mem_block_register(sst, offset, size,
+                                              region[i].type, NULL, j, sst);
+                       offset += size;
+               }
+       }
+
+       return 0;
+}
+
+static void sst_byt_free(struct sst_dsp *sst)
+{
+       sst_mem_block_unregister_all(sst);
+       iounmap(sst->addr.lpe);
+       iounmap(sst->addr.pci_cfg);
+       iounmap(sst->addr.fw_ext);
+}
+
+struct sst_ops sst_byt_ops = {
+       .reset = sst_byt_reset,
+       .boot = sst_byt_boot,
+       .write = sst_shim32_write,
+       .read = sst_shim32_read,
+       .write64 = sst_shim32_write64,
+       .read64 = sst_shim32_read64,
+       .ram_read = sst_memcpy_fromio_32,
+       .ram_write = sst_memcpy_toio_32,
+       .irq_handler = sst_byt_irq,
+       .init = sst_byt_init,
+       .free = sst_byt_free,
+       .parse_fw = sst_byt_parse_fw_image,
+};
diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c
new file mode 100644 (file)
index 0000000..aabb9b0
--- /dev/null
@@ -0,0 +1,983 @@
+/*
+ * Intel Baytrail SST IPC Support
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/kthread.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+
+#include "sst-baytrail-ipc.h"
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+
+/* IPC message timeout */
+#define IPC_TIMEOUT_MSECS      300
+#define IPC_BOOT_MSECS         200
+
+#define IPC_EMPTY_LIST_SIZE    8
+
+/* IPC header bits */
+#define IPC_HEADER_MSG_ID_MASK 0xff
+#define IPC_HEADER_MSG_ID(x)   ((x) & IPC_HEADER_MSG_ID_MASK)
+#define IPC_HEADER_STR_ID_SHIFT        8
+#define IPC_HEADER_STR_ID_MASK 0x1f
+#define IPC_HEADER_STR_ID(x)   (((x) & 0x1f) << IPC_HEADER_STR_ID_SHIFT)
+#define IPC_HEADER_LARGE_SHIFT 13
+#define IPC_HEADER_LARGE(x)    (((x) & 0x1) << IPC_HEADER_LARGE_SHIFT)
+#define IPC_HEADER_DATA_SHIFT  16
+#define IPC_HEADER_DATA_MASK   0x3fff
+#define IPC_HEADER_DATA(x)     (((x) & 0x3fff) << IPC_HEADER_DATA_SHIFT)
+
+/* mask for differentiating between notification and reply message */
+#define IPC_NOTIFICATION       (0x1 << 7)
+
+/* I2L Stream config/control msgs */
+#define IPC_IA_ALLOC_STREAM    0x20
+#define IPC_IA_FREE_STREAM     0x21
+#define IPC_IA_PAUSE_STREAM    0x24
+#define IPC_IA_RESUME_STREAM   0x25
+#define IPC_IA_DROP_STREAM     0x26
+#define IPC_IA_START_STREAM    0x30
+
+/* notification messages */
+#define IPC_IA_FW_INIT_CMPLT   0x81
+#define IPC_SST_PERIOD_ELAPSED 0x97
+
+/* IPC messages between host and ADSP */
+struct sst_byt_address_info {
+       u32 addr;
+       u32 size;
+} __packed;
+
+struct sst_byt_str_type {
+       u8 codec_type;
+       u8 str_type;
+       u8 operation;
+       u8 protected_str;
+       u8 time_slots;
+       u8 reserved;
+       u16 result;
+} __packed;
+
+struct sst_byt_pcm_params {
+       u8 num_chan;
+       u8 pcm_wd_sz;
+       u8 use_offload_path;
+       u8 reserved;
+       u32 sfreq;
+       u8 channel_map[8];
+} __packed;
+
+struct sst_byt_frames_info {
+       u16 num_entries;
+       u16 rsrvd;
+       u32 frag_size;
+       struct sst_byt_address_info ring_buf_info[8];
+} __packed;
+
+struct sst_byt_alloc_params {
+       struct sst_byt_str_type str_type;
+       struct sst_byt_pcm_params pcm_params;
+       struct sst_byt_frames_info frame_info;
+} __packed;
+
+struct sst_byt_alloc_response {
+       struct sst_byt_str_type str_type;
+       u8 reserved[88];
+} __packed;
+
+struct sst_byt_start_stream_params {
+       u32 byte_offset;
+} __packed;
+
+struct sst_byt_tstamp {
+       u64 ring_buffer_counter;
+       u64 hardware_counter;
+       u64 frames_decoded;
+       u64 bytes_decoded;
+       u64 bytes_copied;
+       u32 sampling_frequency;
+       u32 channel_peak[8];
+} __packed;
+
+struct sst_byt_fw_version {
+       u8 build;
+       u8 minor;
+       u8 major;
+       u8 type;
+} __packed;
+
+struct sst_byt_fw_build_info {
+       u8 date[16];
+       u8 time[16];
+} __packed;
+
+struct sst_byt_fw_init {
+       struct sst_byt_fw_version fw_version;
+       struct sst_byt_fw_build_info build_info;
+       u16 result;
+       u8 module_id;
+       u8 debug_info;
+} __packed;
+
+/* driver internal IPC message structure */
+struct ipc_message {
+       struct list_head list;
+       u64 header;
+
+       /* direction wrt host CPU */
+       char tx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE];
+       size_t tx_size;
+       char rx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE];
+       size_t rx_size;
+
+       wait_queue_head_t waitq;
+       bool complete;
+       bool wait;
+       int errno;
+};
+
+struct sst_byt_stream;
+struct sst_byt;
+
+/* stream infomation */
+struct sst_byt_stream {
+       struct list_head node;
+
+       /* configuration */
+       struct sst_byt_alloc_params request;
+       struct sst_byt_alloc_response reply;
+
+       /* runtime info */
+       struct sst_byt *byt;
+       int str_id;
+       bool commited;
+       bool running;
+
+       /* driver callback */
+       u32 (*notify_position)(struct sst_byt_stream *stream, void *data);
+       void *pdata;
+};
+
+/* SST Baytrail IPC data */
+struct sst_byt {
+       struct device *dev;
+       struct sst_dsp *dsp;
+
+       /* stream */
+       struct list_head stream_list;
+
+       /* boot */
+       wait_queue_head_t boot_wait;
+       bool boot_complete;
+       struct sst_fw *fw;
+
+       /* IPC messaging */
+       struct list_head tx_list;
+       struct list_head rx_list;
+       struct list_head empty_list;
+       wait_queue_head_t wait_txq;
+       struct task_struct *tx_thread;
+       struct kthread_worker kworker;
+       struct kthread_work kwork;
+       struct ipc_message *msg;
+};
+
+static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id)
+{
+       u64 header;
+
+       header = IPC_HEADER_MSG_ID(msg_id) |
+                IPC_HEADER_STR_ID(str_id) |
+                IPC_HEADER_LARGE(large) |
+                IPC_HEADER_DATA(data) |
+                SST_BYT_IPCX_BUSY;
+
+       return header;
+}
+
+static inline u16 sst_byt_header_msg_id(u64 header)
+{
+       return header & IPC_HEADER_MSG_ID_MASK;
+}
+
+static inline u8 sst_byt_header_str_id(u64 header)
+{
+       return (header >> IPC_HEADER_STR_ID_SHIFT) & IPC_HEADER_STR_ID_MASK;
+}
+
+static inline u16 sst_byt_header_data(u64 header)
+{
+       return (header >> IPC_HEADER_DATA_SHIFT) & IPC_HEADER_DATA_MASK;
+}
+
+static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt,
+                                                int stream_id)
+{
+       struct sst_byt_stream *stream;
+
+       list_for_each_entry(stream, &byt->stream_list, node) {
+               if (stream->str_id == stream_id)
+                       return stream;
+       }
+
+       return NULL;
+}
+
+static void sst_byt_ipc_shim_dbg(struct sst_byt *byt, const char *text)
+{
+       struct sst_dsp *sst = byt->dsp;
+       u64 isr, ipcd, imrx, ipcx;
+
+       ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX);
+       isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
+       ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
+       imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX);
+
+       dev_err(byt->dev,
+               "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n",
+               text, ipcx, isr, ipcd, imrx);
+}
+
+/* locks held by caller */
+static struct ipc_message *sst_byt_msg_get_empty(struct sst_byt *byt)
+{
+       struct ipc_message *msg = NULL;
+
+       if (!list_empty(&byt->empty_list)) {
+               msg = list_first_entry(&byt->empty_list,
+                                      struct ipc_message, list);
+               list_del(&msg->list);
+       }
+
+       return msg;
+}
+
+static void sst_byt_ipc_tx_msgs(struct kthread_work *work)
+{
+       struct sst_byt *byt =
+               container_of(work, struct sst_byt, kwork);
+       struct ipc_message *msg;
+       u64 ipcx;
+       unsigned long flags;
+
+       spin_lock_irqsave(&byt->dsp->spinlock, flags);
+       if (list_empty(&byt->tx_list)) {
+               spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+               return;
+       }
+
+       /* if the DSP is busy we will TX messages after IRQ */
+       ipcx = sst_dsp_shim_read64_unlocked(byt->dsp, SST_IPCX);
+       if (ipcx & SST_BYT_IPCX_BUSY) {
+               spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+               return;
+       }
+
+       msg = list_first_entry(&byt->tx_list, struct ipc_message, list);
+
+       list_move(&msg->list, &byt->rx_list);
+
+       /* send the message */
+       if (msg->header & IPC_HEADER_LARGE(true))
+               sst_dsp_outbox_write(byt->dsp, msg->tx_data, msg->tx_size);
+       sst_dsp_shim_write64_unlocked(byt->dsp, SST_IPCX, msg->header);
+
+       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+}
+
+static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt,
+                                                struct ipc_message *msg)
+{
+       msg->complete = true;
+
+       if (!msg->wait)
+               list_add_tail(&msg->list, &byt->empty_list);
+       else
+               wake_up(&msg->waitq);
+}
+
+static void sst_byt_drop_all(struct sst_byt *byt)
+{
+       struct ipc_message *msg, *tmp;
+       unsigned long flags;
+
+       /* drop all TX and Rx messages before we stall + reset DSP */
+       spin_lock_irqsave(&byt->dsp->spinlock, flags);
+       list_for_each_entry_safe(msg, tmp, &byt->tx_list, list) {
+               list_move(&msg->list, &byt->empty_list);
+       }
+
+       list_for_each_entry_safe(msg, tmp, &byt->rx_list, list) {
+               list_move(&msg->list, &byt->empty_list);
+       }
+
+       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+}
+
+static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg,
+                               void *rx_data)
+{
+       unsigned long flags;
+       int ret;
+
+       /* wait for DSP completion */
+       ret = wait_event_timeout(msg->waitq, msg->complete,
+                                msecs_to_jiffies(IPC_TIMEOUT_MSECS));
+
+       spin_lock_irqsave(&byt->dsp->spinlock, flags);
+       if (ret == 0) {
+               list_del(&msg->list);
+               sst_byt_ipc_shim_dbg(byt, "message timeout");
+
+               ret = -ETIMEDOUT;
+       } else {
+
+               /* copy the data returned from DSP */
+               if (msg->rx_size)
+                       memcpy(rx_data, msg->rx_data, msg->rx_size);
+               ret = msg->errno;
+       }
+
+       list_add_tail(&msg->list, &byt->empty_list);
+       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+       return ret;
+}
+
+static int sst_byt_ipc_tx_message(struct sst_byt *byt, u64 header,
+                                 void *tx_data, size_t tx_bytes,
+                                 void *rx_data, size_t rx_bytes, int wait)
+{
+       unsigned long flags;
+       struct ipc_message *msg;
+
+       spin_lock_irqsave(&byt->dsp->spinlock, flags);
+
+       msg = sst_byt_msg_get_empty(byt);
+       if (msg == NULL) {
+               spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+               return -EBUSY;
+       }
+
+       msg->header = header;
+       msg->tx_size = tx_bytes;
+       msg->rx_size = rx_bytes;
+       msg->wait = wait;
+       msg->errno = 0;
+       msg->complete = false;
+
+       if (tx_bytes) {
+               /* msg content = lower 32-bit of the header + data */
+               *(u32 *)msg->tx_data = (u32)(header & (u32)-1);
+               memcpy(msg->tx_data + sizeof(u32), tx_data, tx_bytes);
+               msg->tx_size += sizeof(u32);
+       }
+
+       list_add_tail(&msg->list, &byt->tx_list);
+       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+
+       queue_kthread_work(&byt->kworker, &byt->kwork);
+
+       if (wait)
+               return sst_byt_tx_wait_done(byt, msg, rx_data);
+       else
+               return 0;
+}
+
+static inline int sst_byt_ipc_tx_msg_wait(struct sst_byt *byt, u64 header,
+                                         void *tx_data, size_t tx_bytes,
+                                         void *rx_data, size_t rx_bytes)
+{
+       return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes,
+                                     rx_data, rx_bytes, 1);
+}
+
+static inline int sst_byt_ipc_tx_msg_nowait(struct sst_byt *byt, u64 header,
+                                               void *tx_data, size_t tx_bytes)
+{
+       return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes,
+                                     NULL, 0, 0);
+}
+
+static struct ipc_message *sst_byt_reply_find_msg(struct sst_byt *byt,
+                                                 u64 header)
+{
+       struct ipc_message *msg = NULL, *_msg;
+       u64 mask;
+
+       /* match reply to message sent based on msg and stream IDs */
+       mask = IPC_HEADER_MSG_ID_MASK |
+              IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT;
+       header &= mask;
+
+       if (list_empty(&byt->rx_list)) {
+               dev_err(byt->dev,
+                       "ipc: rx list is empty but received 0x%llx\n", header);
+               goto out;
+       }
+
+       list_for_each_entry(_msg, &byt->rx_list, list) {
+               if ((_msg->header & mask) == header) {
+                       msg = _msg;
+                       break;
+               }
+       }
+
+out:
+       return msg;
+}
+
+static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg)
+{
+       struct sst_byt_stream *stream;
+       u64 header = msg->header;
+       u8 stream_id = sst_byt_header_str_id(header);
+       u8 stream_msg = sst_byt_header_msg_id(header);
+
+       stream = sst_byt_get_stream(byt, stream_id);
+       if (stream == NULL)
+               return;
+
+       switch (stream_msg) {
+       case IPC_IA_DROP_STREAM:
+       case IPC_IA_PAUSE_STREAM:
+       case IPC_IA_FREE_STREAM:
+               stream->running = false;
+               break;
+       case IPC_IA_START_STREAM:
+       case IPC_IA_RESUME_STREAM:
+               stream->running = true;
+               break;
+       }
+}
+
+static int sst_byt_process_reply(struct sst_byt *byt, u64 header)
+{
+       struct ipc_message *msg;
+
+       msg = sst_byt_reply_find_msg(byt, header);
+       if (msg == NULL)
+               return 1;
+
+       if (header & IPC_HEADER_LARGE(true)) {
+               msg->rx_size = sst_byt_header_data(header);
+               sst_dsp_inbox_read(byt->dsp, msg->rx_data, msg->rx_size);
+       }
+
+       /* update any stream states */
+       sst_byt_stream_update(byt, msg);
+
+       list_del(&msg->list);
+       /* wake up */
+       sst_byt_tx_msg_reply_complete(byt, msg);
+
+       return 1;
+}
+
+static void sst_byt_fw_ready(struct sst_byt *byt, u64 header)
+{
+       dev_dbg(byt->dev, "ipc: DSP is ready 0x%llX\n", header);
+
+       byt->boot_complete = true;
+       wake_up(&byt->boot_wait);
+}
+
+static int sst_byt_process_notification(struct sst_byt *byt,
+                                       unsigned long *flags)
+{
+       struct sst_dsp *sst = byt->dsp;
+       struct sst_byt_stream *stream;
+       u64 header;
+       u8 msg_id, stream_id;
+       int handled = 1;
+
+       header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
+       msg_id = sst_byt_header_msg_id(header);
+
+       switch (msg_id) {
+       case IPC_SST_PERIOD_ELAPSED:
+               stream_id = sst_byt_header_str_id(header);
+               stream = sst_byt_get_stream(byt, stream_id);
+               if (stream && stream->running && stream->notify_position) {
+                       spin_unlock_irqrestore(&sst->spinlock, *flags);
+                       stream->notify_position(stream, stream->pdata);
+                       spin_lock_irqsave(&sst->spinlock, *flags);
+               }
+               break;
+       case IPC_IA_FW_INIT_CMPLT:
+               sst_byt_fw_ready(byt, header);
+               break;
+       }
+
+       return handled;
+}
+
+static irqreturn_t sst_byt_irq_thread(int irq, void *context)
+{
+       struct sst_dsp *sst = (struct sst_dsp *) context;
+       struct sst_byt *byt = sst_dsp_get_thread_context(sst);
+       u64 header;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+
+       header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
+       if (header & SST_BYT_IPCD_BUSY) {
+               if (header & IPC_NOTIFICATION) {
+                       /* message from ADSP */
+                       sst_byt_process_notification(byt, &flags);
+               } else {
+                       /* reply from ADSP */
+                       sst_byt_process_reply(byt, header);
+               }
+               /*
+                * clear IPCD BUSY bit and set DONE bit. Tell DSP we have
+                * processed the message and can accept new. Clear data part
+                * of the header
+                */
+               sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCD,
+                       SST_BYT_IPCD_DONE | SST_BYT_IPCD_BUSY |
+                       IPC_HEADER_DATA(IPC_HEADER_DATA_MASK),
+                       SST_BYT_IPCD_DONE);
+               /* unmask message request interrupts */
+               sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
+                       SST_BYT_IMRX_REQUEST, 0);
+       }
+
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       /* continue to send any remaining messages... */
+       queue_kthread_work(&byt->kworker, &byt->kwork);
+
+       return IRQ_HANDLED;
+}
+
+/* stream API */
+struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
+       u32 (*notify_position)(struct sst_byt_stream *stream, void *data),
+       void *data)
+{
+       struct sst_byt_stream *stream;
+       struct sst_dsp *sst = byt->dsp;
+       unsigned long flags;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (stream == NULL)
+               return NULL;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       list_add(&stream->node, &byt->stream_list);
+       stream->notify_position = notify_position;
+       stream->pdata = data;
+       stream->byt = byt;
+       stream->str_id = id;
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       return stream;
+}
+
+int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
+                           int bits)
+{
+       stream->request.pcm_params.pcm_wd_sz = bits;
+       return 0;
+}
+
+int sst_byt_stream_set_channels(struct sst_byt *byt,
+                               struct sst_byt_stream *stream, u8 channels)
+{
+       stream->request.pcm_params.num_chan = channels;
+       return 0;
+}
+
+int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
+                           unsigned int rate)
+{
+       stream->request.pcm_params.sfreq = rate;
+       return 0;
+}
+
+/* stream sonfiguration */
+int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
+                       int codec_type, int stream_type, int operation)
+{
+       stream->request.str_type.codec_type = codec_type;
+       stream->request.str_type.str_type = stream_type;
+       stream->request.str_type.operation = operation;
+       stream->request.str_type.time_slots = 0xc;
+
+       return 0;
+}
+
+int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
+                         uint32_t buffer_addr, uint32_t buffer_size)
+{
+       stream->request.frame_info.num_entries = 1;
+       stream->request.frame_info.ring_buf_info[0].addr = buffer_addr;
+       stream->request.frame_info.ring_buf_info[0].size = buffer_size;
+       /* calculate bytes per 4 ms fragment */
+       stream->request.frame_info.frag_size =
+               stream->request.pcm_params.sfreq *
+               stream->request.pcm_params.num_chan *
+               stream->request.pcm_params.pcm_wd_sz / 8 *
+               4 / 1000;
+       return 0;
+}
+
+int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       struct sst_byt_alloc_params *str_req = &stream->request;
+       struct sst_byt_alloc_response *reply = &stream->reply;
+       u64 header;
+       int ret;
+
+       header = sst_byt_header(IPC_IA_ALLOC_STREAM,
+                               sizeof(*str_req) + sizeof(u32),
+                               true, stream->str_id);
+       ret = sst_byt_ipc_tx_msg_wait(byt, header, str_req, sizeof(*str_req),
+                                     reply, sizeof(*reply));
+       if (ret < 0) {
+               dev_err(byt->dev, "ipc: error stream commit failed\n");
+               return ret;
+       }
+
+       stream->commited = true;
+
+       return 0;
+}
+
+int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       u64 header;
+       int ret = 0;
+       struct sst_dsp *sst = byt->dsp;
+       unsigned long flags;
+
+       if (!stream->commited)
+               goto out;
+
+       header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id);
+       ret = sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0);
+       if (ret < 0) {
+               dev_err(byt->dev, "ipc: free stream %d failed\n",
+                       stream->str_id);
+               return -EAGAIN;
+       }
+
+       stream->commited = false;
+out:
+       spin_lock_irqsave(&sst->spinlock, flags);
+       list_del(&stream->node);
+       kfree(stream);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       return ret;
+}
+
+static int sst_byt_stream_operations(struct sst_byt *byt, int type,
+                                    int stream_id, int wait)
+{
+       u64 header;
+
+       header = sst_byt_header(type, 0, false, stream_id);
+       if (wait)
+               return sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0);
+       else
+               return sst_byt_ipc_tx_msg_nowait(byt, header, NULL, 0);
+}
+
+/* stream ALSA trigger operations */
+int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
+                        u32 start_offset)
+{
+       struct sst_byt_start_stream_params start_stream;
+       void *tx_msg;
+       size_t size;
+       u64 header;
+       int ret;
+
+       start_stream.byte_offset = start_offset;
+       header = sst_byt_header(IPC_IA_START_STREAM,
+                               sizeof(start_stream) + sizeof(u32),
+                               true, stream->str_id);
+       tx_msg = &start_stream;
+       size = sizeof(start_stream);
+
+       ret = sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size);
+       if (ret < 0)
+               dev_err(byt->dev, "ipc: error failed to start stream %d\n",
+                       stream->str_id);
+
+       return ret;
+}
+
+int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       int ret;
+
+       /* don't stop streams that are not commited */
+       if (!stream->commited)
+               return 0;
+
+       ret = sst_byt_stream_operations(byt, IPC_IA_DROP_STREAM,
+                                       stream->str_id, 0);
+       if (ret < 0)
+               dev_err(byt->dev, "ipc: error failed to stop stream %d\n",
+                       stream->str_id);
+       return ret;
+}
+
+int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       int ret;
+
+       ret = sst_byt_stream_operations(byt, IPC_IA_PAUSE_STREAM,
+                                       stream->str_id, 0);
+       if (ret < 0)
+               dev_err(byt->dev, "ipc: error failed to pause stream %d\n",
+                       stream->str_id);
+
+       return ret;
+}
+
+int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       int ret;
+
+       ret = sst_byt_stream_operations(byt, IPC_IA_RESUME_STREAM,
+                                       stream->str_id, 0);
+       if (ret < 0)
+               dev_err(byt->dev, "ipc: error failed to resume stream %d\n",
+                       stream->str_id);
+
+       return ret;
+}
+
+int sst_byt_get_dsp_position(struct sst_byt *byt,
+                            struct sst_byt_stream *stream, int buffer_size)
+{
+       struct sst_dsp *sst = byt->dsp;
+       struct sst_byt_tstamp fw_tstamp;
+       u8 str_id = stream->str_id;
+       u32 tstamp_offset;
+
+       tstamp_offset = SST_BYT_TIMESTAMP_OFFSET + str_id * sizeof(fw_tstamp);
+       memcpy_fromio(&fw_tstamp,
+                     sst->addr.lpe + tstamp_offset, sizeof(fw_tstamp));
+
+       return do_div(fw_tstamp.ring_buffer_counter, buffer_size);
+}
+
+static int msg_empty_list_init(struct sst_byt *byt)
+{
+       struct ipc_message *msg;
+       int i;
+
+       byt->msg = kzalloc(sizeof(*msg) * IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
+       if (byt->msg == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
+               init_waitqueue_head(&byt->msg[i].waitq);
+               list_add(&byt->msg[i].list, &byt->empty_list);
+       }
+
+       return 0;
+}
+
+struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt)
+{
+       return byt->dsp;
+}
+
+static struct sst_dsp_device byt_dev = {
+       .thread = sst_byt_irq_thread,
+       .ops = &sst_byt_ops,
+};
+
+int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt = pdata->dsp;
+
+       dev_dbg(byt->dev, "dsp reset\n");
+       sst_dsp_reset(byt->dsp);
+       sst_byt_drop_all(byt);
+       dev_dbg(byt->dev, "dsp in reset\n");
+
+       dev_dbg(byt->dev, "free all blocks and unload fw\n");
+       sst_fw_unload(byt->fw);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_late);
+
+int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt = pdata->dsp;
+       int ret;
+
+       dev_dbg(byt->dev, "reload dsp fw\n");
+
+       sst_dsp_reset(byt->dsp);
+
+       ret = sst_fw_reload(byt->fw);
+       if (ret <  0) {
+               dev_err(dev, "error: failed to reload firmware\n");
+               return ret;
+       }
+
+       /* wait for DSP boot completion */
+       byt->boot_complete = false;
+       sst_dsp_boot(byt->dsp);
+       dev_dbg(byt->dev, "dsp booting...\n");
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_boot);
+
+int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt = pdata->dsp;
+       int err;
+
+       dev_dbg(byt->dev, "wait for dsp reboot\n");
+
+       err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
+                                msecs_to_jiffies(IPC_BOOT_MSECS));
+       if (err == 0) {
+               dev_err(byt->dev, "ipc: error DSP boot timeout\n");
+               return -EIO;
+       }
+
+       dev_dbg(byt->dev, "dsp rebooted\n");
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready);
+
+int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt;
+       struct sst_fw *byt_sst_fw;
+       struct sst_byt_fw_init init;
+       int err;
+
+       dev_dbg(dev, "initialising Byt DSP IPC\n");
+
+       byt = devm_kzalloc(dev, sizeof(*byt), GFP_KERNEL);
+       if (byt == NULL)
+               return -ENOMEM;
+
+       byt->dev = dev;
+       INIT_LIST_HEAD(&byt->stream_list);
+       INIT_LIST_HEAD(&byt->tx_list);
+       INIT_LIST_HEAD(&byt->rx_list);
+       INIT_LIST_HEAD(&byt->empty_list);
+       init_waitqueue_head(&byt->boot_wait);
+       init_waitqueue_head(&byt->wait_txq);
+
+       err = msg_empty_list_init(byt);
+       if (err < 0)
+               return -ENOMEM;
+
+       /* start the IPC message thread */
+       init_kthread_worker(&byt->kworker);
+       byt->tx_thread = kthread_run(kthread_worker_fn,
+                                    &byt->kworker, "%s",
+                                    dev_name(byt->dev));
+       if (IS_ERR(byt->tx_thread)) {
+               err = PTR_ERR(byt->tx_thread);
+               dev_err(byt->dev, "error failed to create message TX task\n");
+               goto err_free_msg;
+       }
+       init_kthread_work(&byt->kwork, sst_byt_ipc_tx_msgs);
+
+       byt_dev.thread_context = byt;
+
+       /* init SST shim */
+       byt->dsp = sst_dsp_new(dev, &byt_dev, pdata);
+       if (byt->dsp == NULL) {
+               err = -ENODEV;
+               goto dsp_err;
+       }
+
+       /* keep the DSP in reset state for base FW loading */
+       sst_dsp_reset(byt->dsp);
+
+       byt_sst_fw = sst_fw_new(byt->dsp, pdata->fw, byt);
+       if (byt_sst_fw  == NULL) {
+               err = -ENODEV;
+               dev_err(dev, "error: failed to load firmware\n");
+               goto fw_err;
+       }
+
+       /* wait for DSP boot completion */
+       sst_dsp_boot(byt->dsp);
+       err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
+                                msecs_to_jiffies(IPC_BOOT_MSECS));
+       if (err == 0) {
+               err = -EIO;
+               dev_err(byt->dev, "ipc: error DSP boot timeout\n");
+               goto boot_err;
+       }
+
+       /* show firmware information */
+       sst_dsp_inbox_read(byt->dsp, &init, sizeof(init));
+       dev_info(byt->dev, "FW version: %02x.%02x.%02x.%02x\n",
+                init.fw_version.major, init.fw_version.minor,
+                init.fw_version.build, init.fw_version.type);
+       dev_info(byt->dev, "Build type: %x\n", init.fw_version.type);
+       dev_info(byt->dev, "Build date: %s %s\n",
+                init.build_info.date, init.build_info.time);
+
+       pdata->dsp = byt;
+       byt->fw = byt_sst_fw;
+
+       return 0;
+
+boot_err:
+       sst_dsp_reset(byt->dsp);
+       sst_fw_free(byt_sst_fw);
+fw_err:
+       sst_dsp_free(byt->dsp);
+dsp_err:
+       kthread_stop(byt->tx_thread);
+err_free_msg:
+       kfree(byt->msg);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_init);
+
+void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt = pdata->dsp;
+
+       sst_dsp_reset(byt->dsp);
+       sst_fw_free_all(byt->dsp);
+       sst_dsp_free(byt->dsp);
+       kthread_stop(byt->tx_thread);
+       kfree(byt->msg);
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_free);
diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.h b/sound/soc/intel/baytrail/sst-baytrail-ipc.h
new file mode 100644 (file)
index 0000000..8faff6d
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Intel Baytrail SST IPC Support
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __SST_BYT_IPC_H
+#define __SST_BYT_IPC_H
+
+#include <linux/types.h>
+
+struct sst_byt;
+struct sst_byt_stream;
+struct sst_pdata;
+extern struct sst_ops sst_byt_ops;
+
+
+#define SST_BYT_MAILBOX_OFFSET         0x144000
+#define SST_BYT_TIMESTAMP_OFFSET       (SST_BYT_MAILBOX_OFFSET + 0x800)
+
+/**
+ * Upfront defined maximum message size that is
+ * expected by the in/out communication pipes in FW.
+ */
+#define SST_BYT_IPC_MAX_PAYLOAD_SIZE   200
+
+/* stream API */
+struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
+       uint32_t (*get_write_position)(struct sst_byt_stream *stream,
+                                      void *data),
+       void *data);
+
+/* stream configuration */
+int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
+                           int bits);
+int sst_byt_stream_set_channels(struct sst_byt *byt,
+                               struct sst_byt_stream *stream, u8 channels);
+int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
+                           unsigned int rate);
+int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
+                       int codec_type, int stream_type, int operation);
+int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
+                         uint32_t buffer_addr, uint32_t buffer_size);
+int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream);
+
+/* stream ALSA trigger operations */
+int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
+                        u32 start_offset);
+int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream);
+
+int sst_byt_get_dsp_position(struct sst_byt *byt,
+                            struct sst_byt_stream *stream, int buffer_size);
+
+/* init */
+int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
+void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
+struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
+int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata);
+int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata);
+int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata);
+
+#endif
diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
new file mode 100644 (file)
index 0000000..79547be
--- /dev/null
@@ -0,0 +1,505 @@
+/*
+ * Intel Baytrail SST PCM Support
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "sst-baytrail-ipc.h"
+#include "../common/sst-dsp-priv.h"
+#include "../common/sst-dsp.h"
+
+#define BYT_PCM_COUNT          2
+
+static const struct snd_pcm_hardware sst_byt_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_INTERLEAVED |
+                                 SNDRV_PCM_INFO_PAUSE |
+                                 SNDRV_PCM_INFO_RESUME,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
+                                 SNDRV_PCM_FMTBIT_S24_LE,
+       .period_bytes_min       = 384,
+       .period_bytes_max       = 48000,
+       .periods_min            = 2,
+       .periods_max            = 250,
+       .buffer_bytes_max       = 96000,
+};
+
+/* private data for each PCM DSP stream */
+struct sst_byt_pcm_data {
+       struct sst_byt_stream *stream;
+       struct snd_pcm_substream *substream;
+       struct mutex mutex;
+
+       /* latest DSP DMA hw pointer */
+       u32 hw_ptr;
+
+       struct work_struct work;
+};
+
+/* private data for the driver */
+struct sst_byt_priv_data {
+       /* runtime DSP */
+       struct sst_byt *byt;
+
+       /* DAI data */
+       struct sst_byt_pcm_data pcm[BYT_PCM_COUNT];
+
+       /* flag indicating is stream context restore needed after suspend */
+       bool restore_stream;
+};
+
+/* this may get called several times by oss emulation */
+static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+       struct sst_byt *byt = pdata->byt;
+       u32 rate, bits;
+       u8 channels;
+       int ret, playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+
+       dev_dbg(rtd->dev, "PCM: hw_params, pcm_data %p\n", pcm_data);
+
+       ret = sst_byt_stream_type(byt, pcm_data->stream,
+                                 1, 1, !playback);
+       if (ret < 0) {
+               dev_err(rtd->dev, "failed to set stream format %d\n", ret);
+               return ret;
+       }
+
+       rate = params_rate(params);
+       ret = sst_byt_stream_set_rate(byt, pcm_data->stream, rate);
+       if (ret < 0) {
+               dev_err(rtd->dev, "could not set rate %d\n", rate);
+               return ret;
+       }
+
+       bits = snd_pcm_format_width(params_format(params));
+       ret = sst_byt_stream_set_bits(byt, pcm_data->stream, bits);
+       if (ret < 0) {
+               dev_err(rtd->dev, "could not set formats %d\n",
+                       params_rate(params));
+               return ret;
+       }
+
+       channels = (u8)(params_channels(params) & 0xF);
+       ret = sst_byt_stream_set_channels(byt, pcm_data->stream, channels);
+       if (ret < 0) {
+               dev_err(rtd->dev, "could not set channels %d\n",
+                       params_rate(params));
+               return ret;
+       }
+
+       snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+
+       ret = sst_byt_stream_buffer(byt, pcm_data->stream,
+                                   substream->dma_buffer.addr,
+                                   params_buffer_bytes(params));
+       if (ret < 0) {
+               dev_err(rtd->dev, "PCM: failed to set DMA buffer %d\n", ret);
+               return ret;
+       }
+
+       ret = sst_byt_stream_commit(byt, pcm_data->stream);
+       if (ret < 0) {
+               dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       dev_dbg(rtd->dev, "PCM: hw_free\n");
+       snd_pcm_lib_free_pages(substream);
+
+       return 0;
+}
+
+static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+       struct sst_byt *byt = pdata->byt;
+       int ret;
+
+       /* commit stream using existing stream params */
+       ret = sst_byt_stream_commit(byt, pcm_data->stream);
+       if (ret < 0) {
+               dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
+               return ret;
+       }
+
+       sst_byt_stream_start(byt, pcm_data->stream, pcm_data->hw_ptr);
+
+       dev_dbg(rtd->dev, "stream context restored at offset %d\n",
+               pcm_data->hw_ptr);
+
+       return 0;
+}
+
+static void sst_byt_pcm_work(struct work_struct *work)
+{
+       struct sst_byt_pcm_data *pcm_data =
+               container_of(work, struct sst_byt_pcm_data, work);
+
+       if (snd_pcm_running(pcm_data->substream))
+               sst_byt_pcm_restore_stream_context(pcm_data->substream);
+}
+
+static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+       struct sst_byt *byt = pdata->byt;
+
+       dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               pcm_data->hw_ptr = 0;
+               sst_byt_stream_start(byt, pcm_data->stream, 0);
+               break;
+       case SNDRV_PCM_TRIGGER_RESUME:
+               if (pdata->restore_stream == true)
+                       schedule_work(&pcm_data->work);
+               else
+                       sst_byt_stream_resume(byt, pcm_data->stream);
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               sst_byt_stream_resume(byt, pcm_data->stream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               sst_byt_stream_stop(byt, pcm_data->stream);
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               pdata->restore_stream = false;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               sst_byt_stream_pause(byt, pcm_data->stream);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
+{
+       struct sst_byt_pcm_data *pcm_data = data;
+       struct snd_pcm_substream *substream = pcm_data->substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt *byt = pdata->byt;
+       u32 pos, hw_pos;
+
+       hw_pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
+                                         snd_pcm_lib_buffer_bytes(substream));
+       pcm_data->hw_ptr = hw_pos;
+       pos = frames_to_bytes(runtime,
+                             (runtime->control->appl_ptr %
+                              runtime->buffer_size));
+
+       dev_dbg(rtd->dev, "PCM: App/DMA pointer %u/%u bytes\n", pos, hw_pos);
+
+       snd_pcm_period_elapsed(substream);
+       return pos;
+}
+
+static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+
+       dev_dbg(rtd->dev, "PCM: DMA pointer %u bytes\n", pcm_data->hw_ptr);
+
+       return bytes_to_frames(runtime, pcm_data->hw_ptr);
+}
+
+static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+       struct sst_byt *byt = pdata->byt;
+
+       dev_dbg(rtd->dev, "PCM: open\n");
+
+       mutex_lock(&pcm_data->mutex);
+
+       pcm_data->substream = substream;
+
+       snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware);
+
+       pcm_data->stream = sst_byt_stream_new(byt, substream->stream + 1,
+                                             byt_notify_pointer, pcm_data);
+       if (pcm_data->stream == NULL) {
+               dev_err(rtd->dev, "failed to create stream\n");
+               mutex_unlock(&pcm_data->mutex);
+               return -EINVAL;
+       }
+
+       mutex_unlock(&pcm_data->mutex);
+       return 0;
+}
+
+static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+       struct sst_byt *byt = pdata->byt;
+       int ret;
+
+       dev_dbg(rtd->dev, "PCM: close\n");
+
+       cancel_work_sync(&pcm_data->work);
+       mutex_lock(&pcm_data->mutex);
+       ret = sst_byt_stream_free(byt, pcm_data->stream);
+       if (ret < 0) {
+               dev_dbg(rtd->dev, "Free stream fail\n");
+               goto out;
+       }
+       pcm_data->stream = NULL;
+
+out:
+       mutex_unlock(&pcm_data->mutex);
+       return ret;
+}
+
+static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
+                           struct vm_area_struct *vma)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       dev_dbg(rtd->dev, "PCM: mmap\n");
+       return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+static struct snd_pcm_ops sst_byt_pcm_ops = {
+       .open           = sst_byt_pcm_open,
+       .close          = sst_byt_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = sst_byt_pcm_hw_params,
+       .hw_free        = sst_byt_pcm_hw_free,
+       .trigger        = sst_byt_pcm_trigger,
+       .pointer        = sst_byt_pcm_pointer,
+       .mmap           = sst_byt_pcm_mmap,
+};
+
+static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       size_t size;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct sst_pdata *pdata = dev_get_platdata(platform->dev);
+       int ret = 0;
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
+           pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+               size = sst_byt_pcm_hardware.buffer_bytes_max;
+               ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
+                                                           SNDRV_DMA_TYPE_DEV,
+                                                           pdata->dma_dev,
+                                                           size, size);
+               if (ret) {
+                       dev_err(rtd->dev, "dma buffer allocation failed %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+static struct snd_soc_dai_driver byt_dais[] = {
+       {
+               .name  = "Baytrail PCM",
+               .playback = {
+                       .stream_name = "System Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S24_3LE |
+                                  SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .capture = {
+                       .stream_name = "Analog Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+       },
+};
+
+static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
+{
+       struct sst_pdata *plat_data = dev_get_platdata(platform->dev);
+       struct sst_byt_priv_data *priv_data;
+       int i;
+
+       if (!plat_data)
+               return -ENODEV;
+
+       priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data),
+                                GFP_KERNEL);
+       priv_data->byt = plat_data->dsp;
+       snd_soc_platform_set_drvdata(platform, priv_data);
+
+       for (i = 0; i < BYT_PCM_COUNT; i++) {
+               mutex_init(&priv_data->pcm[i].mutex);
+               INIT_WORK(&priv_data->pcm[i].work, sst_byt_pcm_work);
+       }
+
+       return 0;
+}
+
+static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
+{
+       return 0;
+}
+
+static struct snd_soc_platform_driver byt_soc_platform = {
+       .probe          = sst_byt_pcm_probe,
+       .remove         = sst_byt_pcm_remove,
+       .ops            = &sst_byt_pcm_ops,
+       .pcm_new        = sst_byt_pcm_new,
+};
+
+static const struct snd_soc_component_driver byt_dai_component = {
+       .name           = "byt-dai",
+};
+
+#ifdef CONFIG_PM
+static int sst_byt_pcm_dev_suspend_late(struct device *dev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+       struct sst_byt_priv_data *priv_data = dev_get_drvdata(dev);
+       int ret;
+
+       dev_dbg(dev, "suspending late\n");
+
+       ret = sst_byt_dsp_suspend_late(dev, sst_pdata);
+       if (ret < 0) {
+               dev_err(dev, "failed to suspend %d\n", ret);
+               return ret;
+       }
+
+       priv_data->restore_stream = true;
+
+       return ret;
+}
+
+static int sst_byt_pcm_dev_resume_early(struct device *dev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+       int ret;
+
+       dev_dbg(dev, "resume early\n");
+
+       /* load fw and boot DSP */
+       ret = sst_byt_dsp_boot(dev, sst_pdata);
+       if (ret)
+               return ret;
+
+       /* wait for FW to finish booting */
+       return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
+}
+
+static const struct dev_pm_ops sst_byt_pm_ops = {
+       .suspend_late = sst_byt_pcm_dev_suspend_late,
+       .resume_early = sst_byt_pcm_dev_resume_early,
+};
+
+#define SST_BYT_PM_OPS (&sst_byt_pm_ops)
+#else
+#define SST_BYT_PM_OPS NULL
+#endif
+
+static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+       int ret;
+
+       ret = sst_byt_dsp_init(&pdev->dev, sst_pdata);
+       if (ret < 0)
+               return -ENODEV;
+
+       ret = snd_soc_register_platform(&pdev->dev, &byt_soc_platform);
+       if (ret < 0)
+               goto err_plat;
+
+       ret = snd_soc_register_component(&pdev->dev, &byt_dai_component,
+                                        byt_dais, ARRAY_SIZE(byt_dais));
+       if (ret < 0)
+               goto err_comp;
+
+       return 0;
+
+err_comp:
+       snd_soc_unregister_platform(&pdev->dev);
+err_plat:
+       sst_byt_dsp_free(&pdev->dev, sst_pdata);
+       return ret;
+}
+
+static int sst_byt_pcm_dev_remove(struct platform_device *pdev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+
+       snd_soc_unregister_platform(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
+       sst_byt_dsp_free(&pdev->dev, sst_pdata);
+
+       return 0;
+}
+
+static struct platform_driver sst_byt_pcm_driver = {
+       .driver = {
+               .name = "baytrail-pcm-audio",
+               .pm = SST_BYT_PM_OPS,
+       },
+
+       .probe = sst_byt_pcm_dev_probe,
+       .remove = sst_byt_pcm_dev_remove,
+};
+module_platform_driver(sst_byt_pcm_driver);
+
+MODULE_AUTHOR("Jarkko Nikula");
+MODULE_DESCRIPTION("Baytrail PCM");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:baytrail-pcm-audio");
diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c
deleted file mode 100644 (file)
index 5a9e567..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Intel Baytrail SST DSP driver
- * Copyright (c) 2014, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#include <linux/firmware.h>
-
-#include "sst-dsp.h"
-#include "sst-dsp-priv.h"
-#include "sst-baytrail-ipc.h"
-
-#define SST_BYT_FW_SIGNATURE_SIZE      4
-#define SST_BYT_FW_SIGN                        "$SST"
-
-#define SST_BYT_IRAM_OFFSET    0xC0000
-#define SST_BYT_DRAM_OFFSET    0x100000
-#define SST_BYT_SHIM_OFFSET    0x140000
-
-enum sst_ram_type {
-       SST_BYT_IRAM    = 1,
-       SST_BYT_DRAM    = 2,
-       SST_BYT_CACHE   = 3,
-};
-
-struct dma_block_info {
-       enum sst_ram_type       type;   /* IRAM/DRAM */
-       u32                     size;   /* Bytes */
-       u32                     ram_offset; /* Offset in I/DRAM */
-       u32                     rsvd;   /* Reserved field */
-};
-
-struct fw_header {
-       unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
-       u32 file_size; /* size of fw minus this header */
-       u32 modules; /*  # of modules */
-       u32 file_format; /* version of header format */
-       u32 reserved[4];
-};
-
-struct sst_byt_fw_module_header {
-       unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
-       u32 mod_size; /* size of module */
-       u32 blocks; /* # of blocks */
-       u32 type; /* codec type, pp lib */
-       u32 entry_point;
-};
-
-static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
-                               struct sst_byt_fw_module_header *module)
-{
-       struct dma_block_info *block;
-       struct sst_module *mod;
-       struct sst_module_template template;
-       int count;
-
-       memset(&template, 0, sizeof(template));
-       template.id = module->type;
-       template.entry = module->entry_point;
-
-       mod = sst_module_new(fw, &template, NULL);
-       if (mod == NULL)
-               return -ENOMEM;
-
-       block = (void *)module + sizeof(*module);
-
-       for (count = 0; count < module->blocks; count++) {
-
-               if (block->size <= 0) {
-                       dev_err(dsp->dev, "block %d size invalid\n", count);
-                       return -EINVAL;
-               }
-
-               switch (block->type) {
-               case SST_BYT_IRAM:
-                       mod->offset = block->ram_offset +
-                                           dsp->addr.iram_offset;
-                       mod->type = SST_MEM_IRAM;
-                       break;
-               case SST_BYT_DRAM:
-                       mod->offset = block->ram_offset +
-                                           dsp->addr.dram_offset;
-                       mod->type = SST_MEM_DRAM;
-                       break;
-               case SST_BYT_CACHE:
-                       mod->offset = block->ram_offset +
-                                           (dsp->addr.fw_ext - dsp->addr.lpe);
-                       mod->type = SST_MEM_CACHE;
-                       break;
-               default:
-                       dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n",
-                               block->type, count);
-                       return -EINVAL;
-               }
-
-               mod->size = block->size;
-               mod->data = (void *)block + sizeof(*block);
-
-               sst_module_alloc_blocks(mod);
-
-               block = (void *)block + sizeof(*block) + block->size;
-       }
-       return 0;
-}
-
-static int sst_byt_parse_fw_image(struct sst_fw *sst_fw)
-{
-       struct fw_header *header;
-       struct sst_byt_fw_module_header *module;
-       struct sst_dsp *dsp = sst_fw->dsp;
-       int ret, count;
-
-       /* Read the header information from the data pointer */
-       header = (struct fw_header *)sst_fw->dma_buf;
-
-       /* verify FW */
-       if ((strncmp(header->signature, SST_BYT_FW_SIGN, 4) != 0) ||
-           (sst_fw->size != header->file_size + sizeof(*header))) {
-               /* Invalid FW signature */
-               dev_err(dsp->dev, "Invalid FW sign/filesize mismatch\n");
-               return -EINVAL;
-       }
-
-       dev_dbg(dsp->dev,
-               "header sign=%4s size=0x%x modules=0x%x fmt=0x%x size=%zu\n",
-               header->signature, header->file_size, header->modules,
-               header->file_format, sizeof(*header));
-
-       module = (void *)sst_fw->dma_buf + sizeof(*header);
-       for (count = 0; count < header->modules; count++) {
-               /* module */
-               ret = sst_byt_parse_module(dsp, sst_fw, module);
-               if (ret < 0) {
-                       dev_err(dsp->dev, "invalid module %d\n", count);
-                       return ret;
-               }
-               module = (void *)module + sizeof(*module) + module->mod_size;
-       }
-
-       return 0;
-}
-
-static void sst_byt_dump_shim(struct sst_dsp *sst)
-{
-       int i;
-       u64 reg;
-
-       for (i = 0; i <= 0xF0; i += 8) {
-               reg = sst_dsp_shim_read64_unlocked(sst, i);
-               if (reg)
-                       dev_dbg(sst->dev, "shim 0x%2.2x value 0x%16.16llx\n",
-                               i, reg);
-       }
-
-       for (i = 0x00; i <= 0xff; i += 4) {
-               reg = readl(sst->addr.pci_cfg + i);
-               if (reg)
-                       dev_dbg(sst->dev, "pci 0x%2.2x value 0x%8.8x\n",
-                               i, (u32)reg);
-       }
-}
-
-static irqreturn_t sst_byt_irq(int irq, void *context)
-{
-       struct sst_dsp *sst = (struct sst_dsp *) context;
-       u64 isrx;
-       irqreturn_t ret = IRQ_NONE;
-
-       spin_lock(&sst->spinlock);
-
-       isrx = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
-       if (isrx & SST_ISRX_DONE) {
-               /* ADSP has processed the message request from IA */
-               sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCX,
-                                                   SST_BYT_IPCX_DONE, 0);
-               ret = IRQ_WAKE_THREAD;
-       }
-       if (isrx & SST_BYT_ISRX_REQUEST) {
-               /* mask message request from ADSP and do processing later */
-               sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
-                                                   SST_BYT_IMRX_REQUEST,
-                                                   SST_BYT_IMRX_REQUEST);
-               ret = IRQ_WAKE_THREAD;
-       }
-
-       spin_unlock(&sst->spinlock);
-
-       return ret;
-}
-
-static void sst_byt_boot(struct sst_dsp *sst)
-{
-       int tries = 10;
-
-       /*
-        * save the physical address of extended firmware block in the first
-        * 4 bytes of the mailbox
-        */
-       memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
-              &sst->pdata->fw_base, sizeof(u32));
-
-       /* release stall and wait to unstall */
-       sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_STALL, 0x0);
-       while (tries--) {
-               if (!(sst_dsp_shim_read64(sst, SST_CSR) &
-                     SST_BYT_CSR_PWAITMODE))
-                       break;
-               msleep(100);
-       }
-       if (tries < 0) {
-               dev_err(sst->dev, "unable to start DSP\n");
-               sst_byt_dump_shim(sst);
-       }
-}
-
-static void sst_byt_reset(struct sst_dsp *sst)
-{
-       /* put DSP into reset, set reset vector and stall */
-       sst_dsp_shim_update_bits64(sst, SST_CSR,
-               SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL,
-               SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL);
-
-       udelay(10);
-
-       /* take DSP out of reset and keep stalled for FW loading */
-       sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_RST, 0);
-}
-
-struct sst_adsp_memregion {
-       u32 start;
-       u32 end;
-       int blocks;
-       enum sst_mem_type type;
-};
-
-/* BYT test stuff */
-static const struct sst_adsp_memregion byt_region[] = {
-       {0xC0000, 0x100000, 8, SST_MEM_IRAM}, /* I-SRAM - 8 * 32kB */
-       {0x100000, 0x140000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
-};
-
-static int sst_byt_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata)
-{
-       sst->addr.lpe_base = pdata->lpe_base;
-       sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size);
-       if (!sst->addr.lpe)
-               return -ENODEV;
-
-       /* ADSP PCI MMIO config space */
-       sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size);
-       if (!sst->addr.pci_cfg) {
-               iounmap(sst->addr.lpe);
-               return -ENODEV;
-       }
-
-       /* SST Extended FW allocation */
-       sst->addr.fw_ext = ioremap(pdata->fw_base, pdata->fw_size);
-       if (!sst->addr.fw_ext) {
-               iounmap(sst->addr.pci_cfg);
-               iounmap(sst->addr.lpe);
-               return -ENODEV;
-       }
-
-       /* SST Shim */
-       sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset;
-
-       sst_dsp_mailbox_init(sst, SST_BYT_MAILBOX_OFFSET + 0x204,
-                            SST_BYT_IPC_MAX_PAYLOAD_SIZE,
-                            SST_BYT_MAILBOX_OFFSET,
-                            SST_BYT_IPC_MAX_PAYLOAD_SIZE);
-
-       sst->irq = pdata->irq;
-
-       return 0;
-}
-
-static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)
-{
-       const struct sst_adsp_memregion *region;
-       struct device *dev;
-       int ret = -ENODEV, i, j, region_count;
-       u32 offset, size;
-
-       dev = sst->dev;
-
-       switch (sst->id) {
-       case SST_DEV_ID_BYT:
-               region = byt_region;
-               region_count = ARRAY_SIZE(byt_region);
-               sst->addr.iram_offset = SST_BYT_IRAM_OFFSET;
-               sst->addr.dram_offset = SST_BYT_DRAM_OFFSET;
-               sst->addr.shim_offset = SST_BYT_SHIM_OFFSET;
-               break;
-       default:
-               dev_err(dev, "failed to get mem resources\n");
-               return ret;
-       }
-
-       ret = sst_byt_resource_map(sst, pdata);
-       if (ret < 0) {
-               dev_err(dev, "failed to map resources\n");
-               return ret;
-       }
-
-       ret = dma_coerce_mask_and_coherent(sst->dma_dev, DMA_BIT_MASK(32));
-       if (ret)
-               return ret;
-
-       /* enable Interrupt from both sides */
-       sst_dsp_shim_update_bits64(sst, SST_IMRX, 0x3, 0x0);
-       sst_dsp_shim_update_bits64(sst, SST_IMRD, 0x3, 0x0);
-
-       /* register DSP memory blocks - ideally we should get this from ACPI */
-       for (i = 0; i < region_count; i++) {
-               offset = region[i].start;
-               size = (region[i].end - region[i].start) / region[i].blocks;
-
-               /* register individual memory blocks */
-               for (j = 0; j < region[i].blocks; j++) {
-                       sst_mem_block_register(sst, offset, size,
-                                              region[i].type, NULL, j, sst);
-                       offset += size;
-               }
-       }
-
-       return 0;
-}
-
-static void sst_byt_free(struct sst_dsp *sst)
-{
-       sst_mem_block_unregister_all(sst);
-       iounmap(sst->addr.lpe);
-       iounmap(sst->addr.pci_cfg);
-       iounmap(sst->addr.fw_ext);
-}
-
-struct sst_ops sst_byt_ops = {
-       .reset = sst_byt_reset,
-       .boot = sst_byt_boot,
-       .write = sst_shim32_write,
-       .read = sst_shim32_read,
-       .write64 = sst_shim32_write64,
-       .read64 = sst_shim32_read64,
-       .ram_read = sst_memcpy_fromio_32,
-       .ram_write = sst_memcpy_toio_32,
-       .irq_handler = sst_byt_irq,
-       .init = sst_byt_init,
-       .free = sst_byt_free,
-       .parse_fw = sst_byt_parse_fw_image,
-};
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c
deleted file mode 100644 (file)
index b4ad98c..0000000
+++ /dev/null
@@ -1,983 +0,0 @@
-/*
- * Intel Baytrail SST IPC Support
- * Copyright (c) 2014, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/kthread.h>
-#include <linux/firmware.h>
-#include <linux/io.h>
-#include <asm/div64.h>
-
-#include "sst-baytrail-ipc.h"
-#include "sst-dsp.h"
-#include "sst-dsp-priv.h"
-
-/* IPC message timeout */
-#define IPC_TIMEOUT_MSECS      300
-#define IPC_BOOT_MSECS         200
-
-#define IPC_EMPTY_LIST_SIZE    8
-
-/* IPC header bits */
-#define IPC_HEADER_MSG_ID_MASK 0xff
-#define IPC_HEADER_MSG_ID(x)   ((x) & IPC_HEADER_MSG_ID_MASK)
-#define IPC_HEADER_STR_ID_SHIFT        8
-#define IPC_HEADER_STR_ID_MASK 0x1f
-#define IPC_HEADER_STR_ID(x)   (((x) & 0x1f) << IPC_HEADER_STR_ID_SHIFT)
-#define IPC_HEADER_LARGE_SHIFT 13
-#define IPC_HEADER_LARGE(x)    (((x) & 0x1) << IPC_HEADER_LARGE_SHIFT)
-#define IPC_HEADER_DATA_SHIFT  16
-#define IPC_HEADER_DATA_MASK   0x3fff
-#define IPC_HEADER_DATA(x)     (((x) & 0x3fff) << IPC_HEADER_DATA_SHIFT)
-
-/* mask for differentiating between notification and reply message */
-#define IPC_NOTIFICATION       (0x1 << 7)
-
-/* I2L Stream config/control msgs */
-#define IPC_IA_ALLOC_STREAM    0x20
-#define IPC_IA_FREE_STREAM     0x21
-#define IPC_IA_PAUSE_STREAM    0x24
-#define IPC_IA_RESUME_STREAM   0x25
-#define IPC_IA_DROP_STREAM     0x26
-#define IPC_IA_START_STREAM    0x30
-
-/* notification messages */
-#define IPC_IA_FW_INIT_CMPLT   0x81
-#define IPC_SST_PERIOD_ELAPSED 0x97
-
-/* IPC messages between host and ADSP */
-struct sst_byt_address_info {
-       u32 addr;
-       u32 size;
-} __packed;
-
-struct sst_byt_str_type {
-       u8 codec_type;
-       u8 str_type;
-       u8 operation;
-       u8 protected_str;
-       u8 time_slots;
-       u8 reserved;
-       u16 result;
-} __packed;
-
-struct sst_byt_pcm_params {
-       u8 num_chan;
-       u8 pcm_wd_sz;
-       u8 use_offload_path;
-       u8 reserved;
-       u32 sfreq;
-       u8 channel_map[8];
-} __packed;
-
-struct sst_byt_frames_info {
-       u16 num_entries;
-       u16 rsrvd;
-       u32 frag_size;
-       struct sst_byt_address_info ring_buf_info[8];
-} __packed;
-
-struct sst_byt_alloc_params {
-       struct sst_byt_str_type str_type;
-       struct sst_byt_pcm_params pcm_params;
-       struct sst_byt_frames_info frame_info;
-} __packed;
-
-struct sst_byt_alloc_response {
-       struct sst_byt_str_type str_type;
-       u8 reserved[88];
-} __packed;
-
-struct sst_byt_start_stream_params {
-       u32 byte_offset;
-} __packed;
-
-struct sst_byt_tstamp {
-       u64 ring_buffer_counter;
-       u64 hardware_counter;
-       u64 frames_decoded;
-       u64 bytes_decoded;
-       u64 bytes_copied;
-       u32 sampling_frequency;
-       u32 channel_peak[8];
-} __packed;
-
-struct sst_byt_fw_version {
-       u8 build;
-       u8 minor;
-       u8 major;
-       u8 type;
-} __packed;
-
-struct sst_byt_fw_build_info {
-       u8 date[16];
-       u8 time[16];
-} __packed;
-
-struct sst_byt_fw_init {
-       struct sst_byt_fw_version fw_version;
-       struct sst_byt_fw_build_info build_info;
-       u16 result;
-       u8 module_id;
-       u8 debug_info;
-} __packed;
-
-/* driver internal IPC message structure */
-struct ipc_message {
-       struct list_head list;
-       u64 header;
-
-       /* direction wrt host CPU */
-       char tx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE];
-       size_t tx_size;
-       char rx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE];
-       size_t rx_size;
-
-       wait_queue_head_t waitq;
-       bool complete;
-       bool wait;
-       int errno;
-};
-
-struct sst_byt_stream;
-struct sst_byt;
-
-/* stream infomation */
-struct sst_byt_stream {
-       struct list_head node;
-
-       /* configuration */
-       struct sst_byt_alloc_params request;
-       struct sst_byt_alloc_response reply;
-
-       /* runtime info */
-       struct sst_byt *byt;
-       int str_id;
-       bool commited;
-       bool running;
-
-       /* driver callback */
-       u32 (*notify_position)(struct sst_byt_stream *stream, void *data);
-       void *pdata;
-};
-
-/* SST Baytrail IPC data */
-struct sst_byt {
-       struct device *dev;
-       struct sst_dsp *dsp;
-
-       /* stream */
-       struct list_head stream_list;
-
-       /* boot */
-       wait_queue_head_t boot_wait;
-       bool boot_complete;
-       struct sst_fw *fw;
-
-       /* IPC messaging */
-       struct list_head tx_list;
-       struct list_head rx_list;
-       struct list_head empty_list;
-       wait_queue_head_t wait_txq;
-       struct task_struct *tx_thread;
-       struct kthread_worker kworker;
-       struct kthread_work kwork;
-       struct ipc_message *msg;
-};
-
-static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id)
-{
-       u64 header;
-
-       header = IPC_HEADER_MSG_ID(msg_id) |
-                IPC_HEADER_STR_ID(str_id) |
-                IPC_HEADER_LARGE(large) |
-                IPC_HEADER_DATA(data) |
-                SST_BYT_IPCX_BUSY;
-
-       return header;
-}
-
-static inline u16 sst_byt_header_msg_id(u64 header)
-{
-       return header & IPC_HEADER_MSG_ID_MASK;
-}
-
-static inline u8 sst_byt_header_str_id(u64 header)
-{
-       return (header >> IPC_HEADER_STR_ID_SHIFT) & IPC_HEADER_STR_ID_MASK;
-}
-
-static inline u16 sst_byt_header_data(u64 header)
-{
-       return (header >> IPC_HEADER_DATA_SHIFT) & IPC_HEADER_DATA_MASK;
-}
-
-static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt,
-                                                int stream_id)
-{
-       struct sst_byt_stream *stream;
-
-       list_for_each_entry(stream, &byt->stream_list, node) {
-               if (stream->str_id == stream_id)
-                       return stream;
-       }
-
-       return NULL;
-}
-
-static void sst_byt_ipc_shim_dbg(struct sst_byt *byt, const char *text)
-{
-       struct sst_dsp *sst = byt->dsp;
-       u64 isr, ipcd, imrx, ipcx;
-
-       ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX);
-       isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
-       ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
-       imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX);
-
-       dev_err(byt->dev,
-               "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n",
-               text, ipcx, isr, ipcd, imrx);
-}
-
-/* locks held by caller */
-static struct ipc_message *sst_byt_msg_get_empty(struct sst_byt *byt)
-{
-       struct ipc_message *msg = NULL;
-
-       if (!list_empty(&byt->empty_list)) {
-               msg = list_first_entry(&byt->empty_list,
-                                      struct ipc_message, list);
-               list_del(&msg->list);
-       }
-
-       return msg;
-}
-
-static void sst_byt_ipc_tx_msgs(struct kthread_work *work)
-{
-       struct sst_byt *byt =
-               container_of(work, struct sst_byt, kwork);
-       struct ipc_message *msg;
-       u64 ipcx;
-       unsigned long flags;
-
-       spin_lock_irqsave(&byt->dsp->spinlock, flags);
-       if (list_empty(&byt->tx_list)) {
-               spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-               return;
-       }
-
-       /* if the DSP is busy we will TX messages after IRQ */
-       ipcx = sst_dsp_shim_read64_unlocked(byt->dsp, SST_IPCX);
-       if (ipcx & SST_BYT_IPCX_BUSY) {
-               spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-               return;
-       }
-
-       msg = list_first_entry(&byt->tx_list, struct ipc_message, list);
-
-       list_move(&msg->list, &byt->rx_list);
-
-       /* send the message */
-       if (msg->header & IPC_HEADER_LARGE(true))
-               sst_dsp_outbox_write(byt->dsp, msg->tx_data, msg->tx_size);
-       sst_dsp_shim_write64_unlocked(byt->dsp, SST_IPCX, msg->header);
-
-       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-}
-
-static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt,
-                                                struct ipc_message *msg)
-{
-       msg->complete = true;
-
-       if (!msg->wait)
-               list_add_tail(&msg->list, &byt->empty_list);
-       else
-               wake_up(&msg->waitq);
-}
-
-static void sst_byt_drop_all(struct sst_byt *byt)
-{
-       struct ipc_message *msg, *tmp;
-       unsigned long flags;
-
-       /* drop all TX and Rx messages before we stall + reset DSP */
-       spin_lock_irqsave(&byt->dsp->spinlock, flags);
-       list_for_each_entry_safe(msg, tmp, &byt->tx_list, list) {
-               list_move(&msg->list, &byt->empty_list);
-       }
-
-       list_for_each_entry_safe(msg, tmp, &byt->rx_list, list) {
-               list_move(&msg->list, &byt->empty_list);
-       }
-
-       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-}
-
-static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg,
-                               void *rx_data)
-{
-       unsigned long flags;
-       int ret;
-
-       /* wait for DSP completion */
-       ret = wait_event_timeout(msg->waitq, msg->complete,
-                                msecs_to_jiffies(IPC_TIMEOUT_MSECS));
-
-       spin_lock_irqsave(&byt->dsp->spinlock, flags);
-       if (ret == 0) {
-               list_del(&msg->list);
-               sst_byt_ipc_shim_dbg(byt, "message timeout");
-
-               ret = -ETIMEDOUT;
-       } else {
-
-               /* copy the data returned from DSP */
-               if (msg->rx_size)
-                       memcpy(rx_data, msg->rx_data, msg->rx_size);
-               ret = msg->errno;
-       }
-
-       list_add_tail(&msg->list, &byt->empty_list);
-       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-       return ret;
-}
-
-static int sst_byt_ipc_tx_message(struct sst_byt *byt, u64 header,
-                                 void *tx_data, size_t tx_bytes,
-                                 void *rx_data, size_t rx_bytes, int wait)
-{
-       unsigned long flags;
-       struct ipc_message *msg;
-
-       spin_lock_irqsave(&byt->dsp->spinlock, flags);
-
-       msg = sst_byt_msg_get_empty(byt);
-       if (msg == NULL) {
-               spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-               return -EBUSY;
-       }
-
-       msg->header = header;
-       msg->tx_size = tx_bytes;
-       msg->rx_size = rx_bytes;
-       msg->wait = wait;
-       msg->errno = 0;
-       msg->complete = false;
-
-       if (tx_bytes) {
-               /* msg content = lower 32-bit of the header + data */
-               *(u32 *)msg->tx_data = (u32)(header & (u32)-1);
-               memcpy(msg->tx_data + sizeof(u32), tx_data, tx_bytes);
-               msg->tx_size += sizeof(u32);
-       }
-
-       list_add_tail(&msg->list, &byt->tx_list);
-       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-
-       queue_kthread_work(&byt->kworker, &byt->kwork);
-
-       if (wait)
-               return sst_byt_tx_wait_done(byt, msg, rx_data);
-       else
-               return 0;
-}
-
-static inline int sst_byt_ipc_tx_msg_wait(struct sst_byt *byt, u64 header,
-                                         void *tx_data, size_t tx_bytes,
-                                         void *rx_data, size_t rx_bytes)
-{
-       return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes,
-                                     rx_data, rx_bytes, 1);
-}
-
-static inline int sst_byt_ipc_tx_msg_nowait(struct sst_byt *byt, u64 header,
-                                               void *tx_data, size_t tx_bytes)
-{
-       return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes,
-                                     NULL, 0, 0);
-}
-
-static struct ipc_message *sst_byt_reply_find_msg(struct sst_byt *byt,
-                                                 u64 header)
-{
-       struct ipc_message *msg = NULL, *_msg;
-       u64 mask;
-
-       /* match reply to message sent based on msg and stream IDs */
-       mask = IPC_HEADER_MSG_ID_MASK |
-              IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT;
-       header &= mask;
-
-       if (list_empty(&byt->rx_list)) {
-               dev_err(byt->dev,
-                       "ipc: rx list is empty but received 0x%llx\n", header);
-               goto out;
-       }
-
-       list_for_each_entry(_msg, &byt->rx_list, list) {
-               if ((_msg->header & mask) == header) {
-                       msg = _msg;
-                       break;
-               }
-       }
-
-out:
-       return msg;
-}
-
-static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg)
-{
-       struct sst_byt_stream *stream;
-       u64 header = msg->header;
-       u8 stream_id = sst_byt_header_str_id(header);
-       u8 stream_msg = sst_byt_header_msg_id(header);
-
-       stream = sst_byt_get_stream(byt, stream_id);
-       if (stream == NULL)
-               return;
-
-       switch (stream_msg) {
-       case IPC_IA_DROP_STREAM:
-       case IPC_IA_PAUSE_STREAM:
-       case IPC_IA_FREE_STREAM:
-               stream->running = false;
-               break;
-       case IPC_IA_START_STREAM:
-       case IPC_IA_RESUME_STREAM:
-               stream->running = true;
-               break;
-       }
-}
-
-static int sst_byt_process_reply(struct sst_byt *byt, u64 header)
-{
-       struct ipc_message *msg;
-
-       msg = sst_byt_reply_find_msg(byt, header);
-       if (msg == NULL)
-               return 1;
-
-       if (header & IPC_HEADER_LARGE(true)) {
-               msg->rx_size = sst_byt_header_data(header);
-               sst_dsp_inbox_read(byt->dsp, msg->rx_data, msg->rx_size);
-       }
-
-       /* update any stream states */
-       sst_byt_stream_update(byt, msg);
-
-       list_del(&msg->list);
-       /* wake up */
-       sst_byt_tx_msg_reply_complete(byt, msg);
-
-       return 1;
-}
-
-static void sst_byt_fw_ready(struct sst_byt *byt, u64 header)
-{
-       dev_dbg(byt->dev, "ipc: DSP is ready 0x%llX\n", header);
-
-       byt->boot_complete = true;
-       wake_up(&byt->boot_wait);
-}
-
-static int sst_byt_process_notification(struct sst_byt *byt,
-                                       unsigned long *flags)
-{
-       struct sst_dsp *sst = byt->dsp;
-       struct sst_byt_stream *stream;
-       u64 header;
-       u8 msg_id, stream_id;
-       int handled = 1;
-
-       header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
-       msg_id = sst_byt_header_msg_id(header);
-
-       switch (msg_id) {
-       case IPC_SST_PERIOD_ELAPSED:
-               stream_id = sst_byt_header_str_id(header);
-               stream = sst_byt_get_stream(byt, stream_id);
-               if (stream && stream->running && stream->notify_position) {
-                       spin_unlock_irqrestore(&sst->spinlock, *flags);
-                       stream->notify_position(stream, stream->pdata);
-                       spin_lock_irqsave(&sst->spinlock, *flags);
-               }
-               break;
-       case IPC_IA_FW_INIT_CMPLT:
-               sst_byt_fw_ready(byt, header);
-               break;
-       }
-
-       return handled;
-}
-
-static irqreturn_t sst_byt_irq_thread(int irq, void *context)
-{
-       struct sst_dsp *sst = (struct sst_dsp *) context;
-       struct sst_byt *byt = sst_dsp_get_thread_context(sst);
-       u64 header;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sst->spinlock, flags);
-
-       header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
-       if (header & SST_BYT_IPCD_BUSY) {
-               if (header & IPC_NOTIFICATION) {
-                       /* message from ADSP */
-                       sst_byt_process_notification(byt, &flags);
-               } else {
-                       /* reply from ADSP */
-                       sst_byt_process_reply(byt, header);
-               }
-               /*
-                * clear IPCD BUSY bit and set DONE bit. Tell DSP we have
-                * processed the message and can accept new. Clear data part
-                * of the header
-                */
-               sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCD,
-                       SST_BYT_IPCD_DONE | SST_BYT_IPCD_BUSY |
-                       IPC_HEADER_DATA(IPC_HEADER_DATA_MASK),
-                       SST_BYT_IPCD_DONE);
-               /* unmask message request interrupts */
-               sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
-                       SST_BYT_IMRX_REQUEST, 0);
-       }
-
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-
-       /* continue to send any remaining messages... */
-       queue_kthread_work(&byt->kworker, &byt->kwork);
-
-       return IRQ_HANDLED;
-}
-
-/* stream API */
-struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
-       u32 (*notify_position)(struct sst_byt_stream *stream, void *data),
-       void *data)
-{
-       struct sst_byt_stream *stream;
-       struct sst_dsp *sst = byt->dsp;
-       unsigned long flags;
-
-       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
-       if (stream == NULL)
-               return NULL;
-
-       spin_lock_irqsave(&sst->spinlock, flags);
-       list_add(&stream->node, &byt->stream_list);
-       stream->notify_position = notify_position;
-       stream->pdata = data;
-       stream->byt = byt;
-       stream->str_id = id;
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-
-       return stream;
-}
-
-int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
-                           int bits)
-{
-       stream->request.pcm_params.pcm_wd_sz = bits;
-       return 0;
-}
-
-int sst_byt_stream_set_channels(struct sst_byt *byt,
-                               struct sst_byt_stream *stream, u8 channels)
-{
-       stream->request.pcm_params.num_chan = channels;
-       return 0;
-}
-
-int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
-                           unsigned int rate)
-{
-       stream->request.pcm_params.sfreq = rate;
-       return 0;
-}
-
-/* stream sonfiguration */
-int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
-                       int codec_type, int stream_type, int operation)
-{
-       stream->request.str_type.codec_type = codec_type;
-       stream->request.str_type.str_type = stream_type;
-       stream->request.str_type.operation = operation;
-       stream->request.str_type.time_slots = 0xc;
-
-       return 0;
-}
-
-int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
-                         uint32_t buffer_addr, uint32_t buffer_size)
-{
-       stream->request.frame_info.num_entries = 1;
-       stream->request.frame_info.ring_buf_info[0].addr = buffer_addr;
-       stream->request.frame_info.ring_buf_info[0].size = buffer_size;
-       /* calculate bytes per 4 ms fragment */
-       stream->request.frame_info.frag_size =
-               stream->request.pcm_params.sfreq *
-               stream->request.pcm_params.num_chan *
-               stream->request.pcm_params.pcm_wd_sz / 8 *
-               4 / 1000;
-       return 0;
-}
-
-int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream)
-{
-       struct sst_byt_alloc_params *str_req = &stream->request;
-       struct sst_byt_alloc_response *reply = &stream->reply;
-       u64 header;
-       int ret;
-
-       header = sst_byt_header(IPC_IA_ALLOC_STREAM,
-                               sizeof(*str_req) + sizeof(u32),
-                               true, stream->str_id);
-       ret = sst_byt_ipc_tx_msg_wait(byt, header, str_req, sizeof(*str_req),
-                                     reply, sizeof(*reply));
-       if (ret < 0) {
-               dev_err(byt->dev, "ipc: error stream commit failed\n");
-               return ret;
-       }
-
-       stream->commited = true;
-
-       return 0;
-}
-
-int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
-{
-       u64 header;
-       int ret = 0;
-       struct sst_dsp *sst = byt->dsp;
-       unsigned long flags;
-
-       if (!stream->commited)
-               goto out;
-
-       header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id);
-       ret = sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0);
-       if (ret < 0) {
-               dev_err(byt->dev, "ipc: free stream %d failed\n",
-                       stream->str_id);
-               return -EAGAIN;
-       }
-
-       stream->commited = false;
-out:
-       spin_lock_irqsave(&sst->spinlock, flags);
-       list_del(&stream->node);
-       kfree(stream);
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-
-       return ret;
-}
-
-static int sst_byt_stream_operations(struct sst_byt *byt, int type,
-                                    int stream_id, int wait)
-{
-       u64 header;
-
-       header = sst_byt_header(type, 0, false, stream_id);
-       if (wait)
-               return sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0);
-       else
-               return sst_byt_ipc_tx_msg_nowait(byt, header, NULL, 0);
-}
-
-/* stream ALSA trigger operations */
-int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
-                        u32 start_offset)
-{
-       struct sst_byt_start_stream_params start_stream;
-       void *tx_msg;
-       size_t size;
-       u64 header;
-       int ret;
-
-       start_stream.byte_offset = start_offset;
-       header = sst_byt_header(IPC_IA_START_STREAM,
-                               sizeof(start_stream) + sizeof(u32),
-                               true, stream->str_id);
-       tx_msg = &start_stream;
-       size = sizeof(start_stream);
-
-       ret = sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size);
-       if (ret < 0)
-               dev_err(byt->dev, "ipc: error failed to start stream %d\n",
-                       stream->str_id);
-
-       return ret;
-}
-
-int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream)
-{
-       int ret;
-
-       /* don't stop streams that are not commited */
-       if (!stream->commited)
-               return 0;
-
-       ret = sst_byt_stream_operations(byt, IPC_IA_DROP_STREAM,
-                                       stream->str_id, 0);
-       if (ret < 0)
-               dev_err(byt->dev, "ipc: error failed to stop stream %d\n",
-                       stream->str_id);
-       return ret;
-}
-
-int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream)
-{
-       int ret;
-
-       ret = sst_byt_stream_operations(byt, IPC_IA_PAUSE_STREAM,
-                                       stream->str_id, 0);
-       if (ret < 0)
-               dev_err(byt->dev, "ipc: error failed to pause stream %d\n",
-                       stream->str_id);
-
-       return ret;
-}
-
-int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream)
-{
-       int ret;
-
-       ret = sst_byt_stream_operations(byt, IPC_IA_RESUME_STREAM,
-                                       stream->str_id, 0);
-       if (ret < 0)
-               dev_err(byt->dev, "ipc: error failed to resume stream %d\n",
-                       stream->str_id);
-
-       return ret;
-}
-
-int sst_byt_get_dsp_position(struct sst_byt *byt,
-                            struct sst_byt_stream *stream, int buffer_size)
-{
-       struct sst_dsp *sst = byt->dsp;
-       struct sst_byt_tstamp fw_tstamp;
-       u8 str_id = stream->str_id;
-       u32 tstamp_offset;
-
-       tstamp_offset = SST_BYT_TIMESTAMP_OFFSET + str_id * sizeof(fw_tstamp);
-       memcpy_fromio(&fw_tstamp,
-                     sst->addr.lpe + tstamp_offset, sizeof(fw_tstamp));
-
-       return do_div(fw_tstamp.ring_buffer_counter, buffer_size);
-}
-
-static int msg_empty_list_init(struct sst_byt *byt)
-{
-       struct ipc_message *msg;
-       int i;
-
-       byt->msg = kzalloc(sizeof(*msg) * IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
-       if (byt->msg == NULL)
-               return -ENOMEM;
-
-       for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
-               init_waitqueue_head(&byt->msg[i].waitq);
-               list_add(&byt->msg[i].list, &byt->empty_list);
-       }
-
-       return 0;
-}
-
-struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt)
-{
-       return byt->dsp;
-}
-
-static struct sst_dsp_device byt_dev = {
-       .thread = sst_byt_irq_thread,
-       .ops = &sst_byt_ops,
-};
-
-int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_byt *byt = pdata->dsp;
-
-       dev_dbg(byt->dev, "dsp reset\n");
-       sst_dsp_reset(byt->dsp);
-       sst_byt_drop_all(byt);
-       dev_dbg(byt->dev, "dsp in reset\n");
-
-       dev_dbg(byt->dev, "free all blocks and unload fw\n");
-       sst_fw_unload(byt->fw);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_late);
-
-int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_byt *byt = pdata->dsp;
-       int ret;
-
-       dev_dbg(byt->dev, "reload dsp fw\n");
-
-       sst_dsp_reset(byt->dsp);
-
-       ret = sst_fw_reload(byt->fw);
-       if (ret <  0) {
-               dev_err(dev, "error: failed to reload firmware\n");
-               return ret;
-       }
-
-       /* wait for DSP boot completion */
-       byt->boot_complete = false;
-       sst_dsp_boot(byt->dsp);
-       dev_dbg(byt->dev, "dsp booting...\n");
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_byt_dsp_boot);
-
-int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_byt *byt = pdata->dsp;
-       int err;
-
-       dev_dbg(byt->dev, "wait for dsp reboot\n");
-
-       err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
-                                msecs_to_jiffies(IPC_BOOT_MSECS));
-       if (err == 0) {
-               dev_err(byt->dev, "ipc: error DSP boot timeout\n");
-               return -EIO;
-       }
-
-       dev_dbg(byt->dev, "dsp rebooted\n");
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready);
-
-int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_byt *byt;
-       struct sst_fw *byt_sst_fw;
-       struct sst_byt_fw_init init;
-       int err;
-
-       dev_dbg(dev, "initialising Byt DSP IPC\n");
-
-       byt = devm_kzalloc(dev, sizeof(*byt), GFP_KERNEL);
-       if (byt == NULL)
-               return -ENOMEM;
-
-       byt->dev = dev;
-       INIT_LIST_HEAD(&byt->stream_list);
-       INIT_LIST_HEAD(&byt->tx_list);
-       INIT_LIST_HEAD(&byt->rx_list);
-       INIT_LIST_HEAD(&byt->empty_list);
-       init_waitqueue_head(&byt->boot_wait);
-       init_waitqueue_head(&byt->wait_txq);
-
-       err = msg_empty_list_init(byt);
-       if (err < 0)
-               return -ENOMEM;
-
-       /* start the IPC message thread */
-       init_kthread_worker(&byt->kworker);
-       byt->tx_thread = kthread_run(kthread_worker_fn,
-                                    &byt->kworker, "%s",
-                                    dev_name(byt->dev));
-       if (IS_ERR(byt->tx_thread)) {
-               err = PTR_ERR(byt->tx_thread);
-               dev_err(byt->dev, "error failed to create message TX task\n");
-               goto err_free_msg;
-       }
-       init_kthread_work(&byt->kwork, sst_byt_ipc_tx_msgs);
-
-       byt_dev.thread_context = byt;
-
-       /* init SST shim */
-       byt->dsp = sst_dsp_new(dev, &byt_dev, pdata);
-       if (byt->dsp == NULL) {
-               err = -ENODEV;
-               goto dsp_err;
-       }
-
-       /* keep the DSP in reset state for base FW loading */
-       sst_dsp_reset(byt->dsp);
-
-       byt_sst_fw = sst_fw_new(byt->dsp, pdata->fw, byt);
-       if (byt_sst_fw  == NULL) {
-               err = -ENODEV;
-               dev_err(dev, "error: failed to load firmware\n");
-               goto fw_err;
-       }
-
-       /* wait for DSP boot completion */
-       sst_dsp_boot(byt->dsp);
-       err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
-                                msecs_to_jiffies(IPC_BOOT_MSECS));
-       if (err == 0) {
-               err = -EIO;
-               dev_err(byt->dev, "ipc: error DSP boot timeout\n");
-               goto boot_err;
-       }
-
-       /* show firmware information */
-       sst_dsp_inbox_read(byt->dsp, &init, sizeof(init));
-       dev_info(byt->dev, "FW version: %02x.%02x.%02x.%02x\n",
-                init.fw_version.major, init.fw_version.minor,
-                init.fw_version.build, init.fw_version.type);
-       dev_info(byt->dev, "Build type: %x\n", init.fw_version.type);
-       dev_info(byt->dev, "Build date: %s %s\n",
-                init.build_info.date, init.build_info.time);
-
-       pdata->dsp = byt;
-       byt->fw = byt_sst_fw;
-
-       return 0;
-
-boot_err:
-       sst_dsp_reset(byt->dsp);
-       sst_fw_free(byt_sst_fw);
-fw_err:
-       sst_dsp_free(byt->dsp);
-dsp_err:
-       kthread_stop(byt->tx_thread);
-err_free_msg:
-       kfree(byt->msg);
-
-       return err;
-}
-EXPORT_SYMBOL_GPL(sst_byt_dsp_init);
-
-void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_byt *byt = pdata->dsp;
-
-       sst_dsp_reset(byt->dsp);
-       sst_fw_free_all(byt->dsp);
-       sst_dsp_free(byt->dsp);
-       kthread_stop(byt->tx_thread);
-       kfree(byt->msg);
-}
-EXPORT_SYMBOL_GPL(sst_byt_dsp_free);
diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/sst-baytrail-ipc.h
deleted file mode 100644 (file)
index 8faff6d..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Intel Baytrail SST IPC Support
- * Copyright (c) 2014, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#ifndef __SST_BYT_IPC_H
-#define __SST_BYT_IPC_H
-
-#include <linux/types.h>
-
-struct sst_byt;
-struct sst_byt_stream;
-struct sst_pdata;
-extern struct sst_ops sst_byt_ops;
-
-
-#define SST_BYT_MAILBOX_OFFSET         0x144000
-#define SST_BYT_TIMESTAMP_OFFSET       (SST_BYT_MAILBOX_OFFSET + 0x800)
-
-/**
- * Upfront defined maximum message size that is
- * expected by the in/out communication pipes in FW.
- */
-#define SST_BYT_IPC_MAX_PAYLOAD_SIZE   200
-
-/* stream API */
-struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
-       uint32_t (*get_write_position)(struct sst_byt_stream *stream,
-                                      void *data),
-       void *data);
-
-/* stream configuration */
-int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
-                           int bits);
-int sst_byt_stream_set_channels(struct sst_byt *byt,
-                               struct sst_byt_stream *stream, u8 channels);
-int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
-                           unsigned int rate);
-int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
-                       int codec_type, int stream_type, int operation);
-int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
-                         uint32_t buffer_addr, uint32_t buffer_size);
-int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream);
-int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream);
-
-/* stream ALSA trigger operations */
-int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
-                        u32 start_offset);
-int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream);
-int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream);
-int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream);
-
-int sst_byt_get_dsp_position(struct sst_byt *byt,
-                            struct sst_byt_stream *stream, int buffer_size);
-
-/* init */
-int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
-void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
-struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
-int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata);
-int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata);
-int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata);
-
-#endif
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c
deleted file mode 100644 (file)
index 224c49c..0000000
+++ /dev/null
@@ -1,505 +0,0 @@
-/*
- * Intel Baytrail SST PCM Support
- * Copyright (c) 2014, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include "sst-baytrail-ipc.h"
-#include "sst-dsp-priv.h"
-#include "sst-dsp.h"
-
-#define BYT_PCM_COUNT          2
-
-static const struct snd_pcm_hardware sst_byt_pcm_hardware = {
-       .info                   = SNDRV_PCM_INFO_MMAP |
-                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                 SNDRV_PCM_INFO_INTERLEAVED |
-                                 SNDRV_PCM_INFO_PAUSE |
-                                 SNDRV_PCM_INFO_RESUME,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
-                                 SNDRV_PCM_FMTBIT_S24_LE,
-       .period_bytes_min       = 384,
-       .period_bytes_max       = 48000,
-       .periods_min            = 2,
-       .periods_max            = 250,
-       .buffer_bytes_max       = 96000,
-};
-
-/* private data for each PCM DSP stream */
-struct sst_byt_pcm_data {
-       struct sst_byt_stream *stream;
-       struct snd_pcm_substream *substream;
-       struct mutex mutex;
-
-       /* latest DSP DMA hw pointer */
-       u32 hw_ptr;
-
-       struct work_struct work;
-};
-
-/* private data for the driver */
-struct sst_byt_priv_data {
-       /* runtime DSP */
-       struct sst_byt *byt;
-
-       /* DAI data */
-       struct sst_byt_pcm_data pcm[BYT_PCM_COUNT];
-
-       /* flag indicating is stream context restore needed after suspend */
-       bool restore_stream;
-};
-
-/* this may get called several times by oss emulation */
-static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
-       struct sst_byt *byt = pdata->byt;
-       u32 rate, bits;
-       u8 channels;
-       int ret, playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-
-       dev_dbg(rtd->dev, "PCM: hw_params, pcm_data %p\n", pcm_data);
-
-       ret = sst_byt_stream_type(byt, pcm_data->stream,
-                                 1, 1, !playback);
-       if (ret < 0) {
-               dev_err(rtd->dev, "failed to set stream format %d\n", ret);
-               return ret;
-       }
-
-       rate = params_rate(params);
-       ret = sst_byt_stream_set_rate(byt, pcm_data->stream, rate);
-       if (ret < 0) {
-               dev_err(rtd->dev, "could not set rate %d\n", rate);
-               return ret;
-       }
-
-       bits = snd_pcm_format_width(params_format(params));
-       ret = sst_byt_stream_set_bits(byt, pcm_data->stream, bits);
-       if (ret < 0) {
-               dev_err(rtd->dev, "could not set formats %d\n",
-                       params_rate(params));
-               return ret;
-       }
-
-       channels = (u8)(params_channels(params) & 0xF);
-       ret = sst_byt_stream_set_channels(byt, pcm_data->stream, channels);
-       if (ret < 0) {
-               dev_err(rtd->dev, "could not set channels %d\n",
-                       params_rate(params));
-               return ret;
-       }
-
-       snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-
-       ret = sst_byt_stream_buffer(byt, pcm_data->stream,
-                                   substream->dma_buffer.addr,
-                                   params_buffer_bytes(params));
-       if (ret < 0) {
-               dev_err(rtd->dev, "PCM: failed to set DMA buffer %d\n", ret);
-               return ret;
-       }
-
-       ret = sst_byt_stream_commit(byt, pcm_data->stream);
-       if (ret < 0) {
-               dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       dev_dbg(rtd->dev, "PCM: hw_free\n");
-       snd_pcm_lib_free_pages(substream);
-
-       return 0;
-}
-
-static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
-       struct sst_byt *byt = pdata->byt;
-       int ret;
-
-       /* commit stream using existing stream params */
-       ret = sst_byt_stream_commit(byt, pcm_data->stream);
-       if (ret < 0) {
-               dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
-               return ret;
-       }
-
-       sst_byt_stream_start(byt, pcm_data->stream, pcm_data->hw_ptr);
-
-       dev_dbg(rtd->dev, "stream context restored at offset %d\n",
-               pcm_data->hw_ptr);
-
-       return 0;
-}
-
-static void sst_byt_pcm_work(struct work_struct *work)
-{
-       struct sst_byt_pcm_data *pcm_data =
-               container_of(work, struct sst_byt_pcm_data, work);
-
-       if (snd_pcm_running(pcm_data->substream))
-               sst_byt_pcm_restore_stream_context(pcm_data->substream);
-}
-
-static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
-       struct sst_byt *byt = pdata->byt;
-
-       dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               pcm_data->hw_ptr = 0;
-               sst_byt_stream_start(byt, pcm_data->stream, 0);
-               break;
-       case SNDRV_PCM_TRIGGER_RESUME:
-               if (pdata->restore_stream == true)
-                       schedule_work(&pcm_data->work);
-               else
-                       sst_byt_stream_resume(byt, pcm_data->stream);
-               break;
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               sst_byt_stream_resume(byt, pcm_data->stream);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               sst_byt_stream_stop(byt, pcm_data->stream);
-               break;
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-               pdata->restore_stream = false;
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               sst_byt_stream_pause(byt, pcm_data->stream);
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
-{
-       struct sst_byt_pcm_data *pcm_data = data;
-       struct snd_pcm_substream *substream = pcm_data->substream;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt *byt = pdata->byt;
-       u32 pos, hw_pos;
-
-       hw_pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
-                                         snd_pcm_lib_buffer_bytes(substream));
-       pcm_data->hw_ptr = hw_pos;
-       pos = frames_to_bytes(runtime,
-                             (runtime->control->appl_ptr %
-                              runtime->buffer_size));
-
-       dev_dbg(rtd->dev, "PCM: App/DMA pointer %u/%u bytes\n", pos, hw_pos);
-
-       snd_pcm_period_elapsed(substream);
-       return pos;
-}
-
-static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
-
-       dev_dbg(rtd->dev, "PCM: DMA pointer %u bytes\n", pcm_data->hw_ptr);
-
-       return bytes_to_frames(runtime, pcm_data->hw_ptr);
-}
-
-static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
-       struct sst_byt *byt = pdata->byt;
-
-       dev_dbg(rtd->dev, "PCM: open\n");
-
-       mutex_lock(&pcm_data->mutex);
-
-       pcm_data->substream = substream;
-
-       snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware);
-
-       pcm_data->stream = sst_byt_stream_new(byt, substream->stream + 1,
-                                             byt_notify_pointer, pcm_data);
-       if (pcm_data->stream == NULL) {
-               dev_err(rtd->dev, "failed to create stream\n");
-               mutex_unlock(&pcm_data->mutex);
-               return -EINVAL;
-       }
-
-       mutex_unlock(&pcm_data->mutex);
-       return 0;
-}
-
-static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
-       struct sst_byt *byt = pdata->byt;
-       int ret;
-
-       dev_dbg(rtd->dev, "PCM: close\n");
-
-       cancel_work_sync(&pcm_data->work);
-       mutex_lock(&pcm_data->mutex);
-       ret = sst_byt_stream_free(byt, pcm_data->stream);
-       if (ret < 0) {
-               dev_dbg(rtd->dev, "Free stream fail\n");
-               goto out;
-       }
-       pcm_data->stream = NULL;
-
-out:
-       mutex_unlock(&pcm_data->mutex);
-       return ret;
-}
-
-static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
-                           struct vm_area_struct *vma)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       dev_dbg(rtd->dev, "PCM: mmap\n");
-       return snd_pcm_lib_default_mmap(substream, vma);
-}
-
-static struct snd_pcm_ops sst_byt_pcm_ops = {
-       .open           = sst_byt_pcm_open,
-       .close          = sst_byt_pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = sst_byt_pcm_hw_params,
-       .hw_free        = sst_byt_pcm_hw_free,
-       .trigger        = sst_byt_pcm_trigger,
-       .pointer        = sst_byt_pcm_pointer,
-       .mmap           = sst_byt_pcm_mmap,
-};
-
-static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_pcm *pcm = rtd->pcm;
-       size_t size;
-       struct snd_soc_platform *platform = rtd->platform;
-       struct sst_pdata *pdata = dev_get_platdata(platform->dev);
-       int ret = 0;
-
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
-           pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               size = sst_byt_pcm_hardware.buffer_bytes_max;
-               ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
-                                                           SNDRV_DMA_TYPE_DEV,
-                                                           pdata->dma_dev,
-                                                           size, size);
-               if (ret) {
-                       dev_err(rtd->dev, "dma buffer allocation failed %d\n",
-                               ret);
-                       return ret;
-               }
-       }
-
-       return ret;
-}
-
-static struct snd_soc_dai_driver byt_dais[] = {
-       {
-               .name  = "Baytrail PCM",
-               .playback = {
-                       .stream_name = "System Playback",
-                       .channels_min = 2,
-                       .channels_max = 2,
-                       .rates = SNDRV_PCM_RATE_48000,
-                       .formats = SNDRV_PCM_FMTBIT_S24_3LE |
-                                  SNDRV_PCM_FMTBIT_S16_LE,
-               },
-               .capture = {
-                       .stream_name = "Analog Capture",
-                       .channels_min = 2,
-                       .channels_max = 2,
-                       .rates = SNDRV_PCM_RATE_48000,
-                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
-               },
-       },
-};
-
-static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
-{
-       struct sst_pdata *plat_data = dev_get_platdata(platform->dev);
-       struct sst_byt_priv_data *priv_data;
-       int i;
-
-       if (!plat_data)
-               return -ENODEV;
-
-       priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data),
-                                GFP_KERNEL);
-       priv_data->byt = plat_data->dsp;
-       snd_soc_platform_set_drvdata(platform, priv_data);
-
-       for (i = 0; i < BYT_PCM_COUNT; i++) {
-               mutex_init(&priv_data->pcm[i].mutex);
-               INIT_WORK(&priv_data->pcm[i].work, sst_byt_pcm_work);
-       }
-
-       return 0;
-}
-
-static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
-{
-       return 0;
-}
-
-static struct snd_soc_platform_driver byt_soc_platform = {
-       .probe          = sst_byt_pcm_probe,
-       .remove         = sst_byt_pcm_remove,
-       .ops            = &sst_byt_pcm_ops,
-       .pcm_new        = sst_byt_pcm_new,
-};
-
-static const struct snd_soc_component_driver byt_dai_component = {
-       .name           = "byt-dai",
-};
-
-#ifdef CONFIG_PM
-static int sst_byt_pcm_dev_suspend_late(struct device *dev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
-       struct sst_byt_priv_data *priv_data = dev_get_drvdata(dev);
-       int ret;
-
-       dev_dbg(dev, "suspending late\n");
-
-       ret = sst_byt_dsp_suspend_late(dev, sst_pdata);
-       if (ret < 0) {
-               dev_err(dev, "failed to suspend %d\n", ret);
-               return ret;
-       }
-
-       priv_data->restore_stream = true;
-
-       return ret;
-}
-
-static int sst_byt_pcm_dev_resume_early(struct device *dev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
-       int ret;
-
-       dev_dbg(dev, "resume early\n");
-
-       /* load fw and boot DSP */
-       ret = sst_byt_dsp_boot(dev, sst_pdata);
-       if (ret)
-               return ret;
-
-       /* wait for FW to finish booting */
-       return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
-}
-
-static const struct dev_pm_ops sst_byt_pm_ops = {
-       .suspend_late = sst_byt_pcm_dev_suspend_late,
-       .resume_early = sst_byt_pcm_dev_resume_early,
-};
-
-#define SST_BYT_PM_OPS (&sst_byt_pm_ops)
-#else
-#define SST_BYT_PM_OPS NULL
-#endif
-
-static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
-       int ret;
-
-       ret = sst_byt_dsp_init(&pdev->dev, sst_pdata);
-       if (ret < 0)
-               return -ENODEV;
-
-       ret = snd_soc_register_platform(&pdev->dev, &byt_soc_platform);
-       if (ret < 0)
-               goto err_plat;
-
-       ret = snd_soc_register_component(&pdev->dev, &byt_dai_component,
-                                        byt_dais, ARRAY_SIZE(byt_dais));
-       if (ret < 0)
-               goto err_comp;
-
-       return 0;
-
-err_comp:
-       snd_soc_unregister_platform(&pdev->dev);
-err_plat:
-       sst_byt_dsp_free(&pdev->dev, sst_pdata);
-       return ret;
-}
-
-static int sst_byt_pcm_dev_remove(struct platform_device *pdev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
-
-       snd_soc_unregister_platform(&pdev->dev);
-       snd_soc_unregister_component(&pdev->dev);
-       sst_byt_dsp_free(&pdev->dev, sst_pdata);
-
-       return 0;
-}
-
-static struct platform_driver sst_byt_pcm_driver = {
-       .driver = {
-               .name = "baytrail-pcm-audio",
-               .pm = SST_BYT_PM_OPS,
-       },
-
-       .probe = sst_byt_pcm_dev_probe,
-       .remove = sst_byt_pcm_dev_remove,
-};
-module_platform_driver(sst_byt_pcm_driver);
-
-MODULE_AUTHOR("Jarkko Nikula");
-MODULE_DESCRIPTION("Baytrail PCM");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:baytrail-pcm-audio");