[Sound-open-firmware] [PATCH] ipc: hsw: Add IPC support for haswell and broadwell
Liam Girdwood
liam.r.girdwood at linux.intel.com
Mon Jan 22 12:33:26 CET 2018
Add IPC support for Haswell and Broadwell platforms.
Signed-off-by: Liam Girdwood <liam.r.girdwood at linux.intel.com>
---
src/ipc/Makefile.am | 16 ++++
src/ipc/hsw-ipc.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 248 insertions(+)
create mode 100644 src/ipc/hsw-ipc.c
diff --git a/src/ipc/Makefile.am b/src/ipc/Makefile.am
index 7e63ca6..5018da0 100644
--- a/src/ipc/Makefile.am
+++ b/src/ipc/Makefile.am
@@ -18,6 +18,22 @@ libipc_a_SOURCES = \
dma-copy.c
endif
+if BUILD_BROADWELL
+libipc_a_SOURCES = \
+ ipc.c \
+ intel-ipc.c \
+ hsw-ipc.c \
+ dma-copy.c
+endif
+
+if BUILD_HASWELL
+libipc_a_SOURCES = \
+ ipc.c \
+ intel-ipc.c \
+ hsw-ipc.c \
+ dma-copy.c
+endif
+
libipc_a_CFLAGS = \
$(ARCH_CFLAGS) \
$(ARCH_INCDIR) \
diff --git a/src/ipc/hsw-ipc.c b/src/ipc/hsw-ipc.c
new file mode 100644
index 0000000..4a16f41
--- /dev/null
+++ b/src/ipc/hsw-ipc.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Liam Girdwood <liam.r.girdwood at linux.intel.com>
+ */
+
+#include <reef/debug.h>
+#include <reef/timer.h>
+#include <reef/interrupt.h>
+#include <reef/ipc.h>
+#include <reef/mailbox.h>
+#include <reef/reef.h>
+#include <reef/stream.h>
+#include <reef/dai.h>
+#include <reef/dma.h>
+#include <reef/alloc.h>
+#include <reef/wait.h>
+#include <reef/trace.h>
+#include <reef/ssp.h>
+#include <platform/interrupt.h>
+#include <platform/mailbox.h>
+#include <platform/shim.h>
+#include <platform/dma.h>
+#include <platform/platform.h>
+#include <reef/audio/component.h>
+#include <reef/audio/pipeline.h>
+#include <uapi/ipc.h>
+#include <reef/intel-ipc.h>
+
+extern struct ipc *_ipc;
+
+static void do_notify(void)
+{
+ uint32_t flags;
+ struct ipc_msg *msg;
+
+ tracev_ipc("Not");
+
+ spin_lock_irq(&_ipc->lock, flags);
+ msg = _ipc->dsp_msg;
+ if (msg == NULL)
+ goto out;
+
+ /* copy the data returned from DSP */
+ if (msg->rx_size && msg->rx_size < SOF_IPC_MSG_MAX_SIZE)
+ mailbox_dspbox_read(msg->rx_data, 0, msg->rx_size);
+
+ /* any callback ? */
+ if (msg->cb)
+ msg->cb(msg->cb_data, msg->rx_data);
+
+ list_item_append(&msg->list, &_ipc->empty_list);
+
+out:
+ spin_unlock_irq(&_ipc->lock, flags);
+
+ /* clear DONE bit - tell Host we have completed */
+ shim_write(SHIM_IPCD, shim_read(SHIM_IPCD) & ~SHIM_IPCD_DONE);
+
+ /* unmask Done interrupt */
+ shim_write(SHIM_IMRD, shim_read(SHIM_IMRD) & ~SHIM_IMRD_DONE);
+}
+
+/* test code to check working IRQ */
+static void irq_handler(void *arg)
+{
+ uint32_t isr;
+
+ tracev_ipc("IRQ");
+
+ /* Interrupt arrived, check src */
+ isr = shim_read(SHIM_ISRD);
+
+ if (isr & SHIM_ISRD_DONE) {
+
+ /* Mask Done interrupt before return */
+ shim_write(SHIM_IMRD, shim_read(SHIM_IMRD) | SHIM_IMRD_DONE);
+ interrupt_clear(PLATFORM_IPC_INTERUPT);
+ do_notify();
+ }
+
+ if (isr & SHIM_ISRD_BUSY) {
+
+ /* Mask Busy interrupt before return */
+ shim_write(SHIM_IMRD, shim_read(SHIM_IMRD) | SHIM_IMRD_BUSY);
+ interrupt_clear(PLATFORM_IPC_INTERUPT);
+
+ /* place message in Q and process later */
+ _ipc->host_msg = shim_read(SHIM_IPCX);
+ _ipc->host_pending = 1;
+ }
+}
+
+void ipc_platform_do_cmd(struct ipc *ipc)
+{
+ struct intel_ipc_data *iipc = ipc_get_drvdata(ipc);
+ struct sof_ipc_reply reply;
+ uint32_t ipcx;
+ int32_t err;
+
+ tracev_ipc("Cmd");
+
+ /* perform command and return any error */
+ err = ipc_cmd();
+ if (err > 0) {
+ goto done; /* reply created and copied by cmd() */
+ } else {
+ /* send std error reply */
+ reply.error = err;
+ }
+
+ /* send std error/ok reply */
+ reply.hdr.cmd = SOF_IPC_GLB_REPLY;
+ reply.hdr.size = sizeof(reply);
+ mailbox_hostbox_write(0, &reply, sizeof(reply));
+
+done:
+
+ /* clear BUSY bit and set DONE bit - accept new messages */
+ ipcx = shim_read(SHIM_IPCX);
+ ipcx &= ~SHIM_IPCX_BUSY;
+ ipcx |= SHIM_IPCX_DONE;
+ shim_write(SHIM_IPCX, ipcx);
+
+ // TODO: signal audio work to enter D3 in normal context
+ /* are we about to enter D3 ? */
+ if (iipc->pm_prepare_D3) {
+ while (1)
+ wait_for_interrupt(0);
+ }
+
+ /* unmask busy interrupt */
+ shim_write(SHIM_IMRD, shim_read(SHIM_IMRD) & ~SHIM_IMRD_BUSY);
+}
+
+void ipc_platform_send_msg(struct ipc *ipc)
+{
+ struct ipc_msg *msg;
+ uint32_t flags;
+
+ spin_lock_irq(&ipc->lock, flags);
+
+ /* any messages to send ? */
+ if (list_is_empty(&ipc->msg_list)) {
+ ipc->dsp_pending = 0;
+ goto out;
+ }
+
+ /* can't send nofication when one is in progress */
+ if (shim_read(SHIM_IPCD) & (SHIM_IPCD_BUSY | SHIM_IPCD_DONE))
+ goto out;
+
+ /* now send the message */
+ msg = list_first_item(&ipc->msg_list, struct ipc_msg, list);
+ mailbox_dspbox_write(0, msg->tx_data, msg->tx_size);
+ list_item_del(&msg->list);
+ ipc->dsp_msg = msg;
+ tracev_ipc("Msg");
+
+ /* now interrupt host to tell it we have message sent */
+ shim_write(SHIM_IPCD, msg->header | SHIM_IPCD_BUSY);
+
+out:
+ spin_unlock_irq(&ipc->lock, flags);
+}
+
+int platform_ipc_init(struct ipc *ipc)
+{
+ struct intel_ipc_data *iipc;
+ uint32_t imrd;
+ int i;
+
+ _ipc = ipc;
+
+ /* init ipc data */
+ iipc = rzalloc(RZONE_SYS, RFLAGS_NONE, sizeof(struct intel_ipc_data));
+ ipc_set_drvdata(_ipc, iipc);
+ _ipc->dsp_msg = NULL;
+ list_init(&ipc->empty_list);
+ list_init(&ipc->msg_list);
+ spinlock_init(&ipc->lock);
+ for (i = 0; i < MSG_QUEUE_SIZE; i++)
+ list_item_prepend(&ipc->message[i].list, &ipc->empty_list);
+
+ /* allocate page table buffer */
+ iipc->page_table = rzalloc(RZONE_SYS, RFLAGS_NONE,
+ PLATFORM_PAGE_TABLE_SIZE);
+ if (iipc->page_table)
+ bzero(iipc->page_table, PLATFORM_PAGE_TABLE_SIZE);
+
+ /* dma */
+ iipc->dmac0 = dma_get(DMA_ID_DMAC0);
+
+ /* PM */
+ iipc->pm_prepare_D3 = 0;
+
+ /* configure interrupt */
+ interrupt_register(PLATFORM_IPC_INTERUPT, irq_handler, NULL);
+ interrupt_enable(PLATFORM_IPC_INTERUPT);
+
+ /* Unmask Busy and Done interrupts */
+ imrd = shim_read(SHIM_IMRD);
+ imrd &= ~(SHIM_IMRD_BUSY | SHIM_IMRD_DONE);
+ shim_write(SHIM_IMRD, imrd);
+
+ return 0;
+}
+
--
2.14.1
More information about the Sound-open-firmware
mailing list