[Sound-open-firmware] [PATCH] ipc: cnl: Add support for IPC on cannonlake

Liam Girdwood liam.r.girdwood at linux.intel.com
Tue Jan 23 17:40:16 CET 2018


From: Rander Wang <rander.wang at linux.intel.com>

Support IPC on Intel Cannonlake platform.

Signed-off-by: Rander Wang <rander.wang at linux.intel.com>
---
 src/ipc/Makefile.am |   8 ++
 src/ipc/cnl-ipc.c   | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 220 insertions(+)
 create mode 100644 src/ipc/cnl-ipc.c

diff --git a/src/ipc/Makefile.am b/src/ipc/Makefile.am
index 8438b70..bd83f60 100644
--- a/src/ipc/Makefile.am
+++ b/src/ipc/Makefile.am
@@ -42,6 +42,14 @@ libipc_a_SOURCES = \
 	dma-copy.c
 endif
 
+if BUILD_CANNONLAKE
+libipc_a_SOURCES = \
+	ipc.c \
+	intel-ipc.c \
+	cnl-ipc.c \
+	dma-copy.c
+endif
+
 libipc_a_CFLAGS = \
 	$(ARCH_CFLAGS) \
 	$(ARCH_INCDIR) \
diff --git a/src/ipc/cnl-ipc.c b/src/ipc/cnl-ipc.c
new file mode 100644
index 0000000..cd5e825
--- /dev/null
+++ b/src/ipc/cnl-ipc.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2017, 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>
+ *	Keyon Jie <yang.jie at linux.intel.com>
+	Rander Wang <rander.wang at 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;
+
+/* test code to check working IRQ */
+static void irq_handler(void *arg)
+{
+	uint32_t dipctdr;
+	uint32_t dipcida;
+	uint32_t msg = 0;
+
+	trace_ipc("IRQ");
+
+	dipctdr = ipc_read(IPC_DIPCTDR);
+	dipcida = ipc_read(IPC_DIPCIDA);
+
+	/* new message from host */
+	if (dipctdr & IPC_DIPCTDR_BUSY) {
+		trace_ipc("Nms");
+
+		/* mask Busy interrupt */
+		ipc_write(IPC_DIPCCTL, ipc_read(IPC_DIPCCTL) & ~IPC_DIPCCTL_IPCTBIE);
+
+		msg = dipctdr & IPC_DIPCTDR_MSG_MASK;
+
+		/* TODO: place message in Q and process later */
+		/* It's not Q ATM, may overwrite */
+		if (_ipc->host_pending)
+			trace_ipc_error("Pen");
+		_ipc->host_msg = msg;
+		_ipc->host_pending = 1;
+	}
+
+	/* reply message(done) from host */
+	if (dipcida & IPC_DIPCIDA_DONE) {
+		trace_ipc("Rpy");
+		/* mask Done interrupt */
+		ipc_write(IPC_DIPCCTL, ipc_read(IPC_DIPCCTL) & ~IPC_DIPCCTL_IPCIDIE);
+
+		/* clear DONE bit - tell host we have completed the operation */
+		ipc_write(IPC_DIPCIDA, ipc_read(IPC_DIPCIDA) |IPC_DIPCIDA_DONE);
+
+		/* unmask Done interrupt */
+		ipc_write(IPC_DIPCCTL, ipc_read(IPC_DIPCCTL) | IPC_DIPCCTL_IPCIDIE);
+	}
+
+}
+
+void ipc_platform_do_cmd(struct ipc *ipc)
+{
+	struct intel_ipc_data *iipc = ipc_get_drvdata(ipc);
+	struct sof_ipc_reply reply;
+	int32_t err;
+
+	trace_ipc("Cmd");
+
+	/* perform command and return any error */
+	err = ipc_cmd();
+	if (err > 0) {
+		goto done; /* reply created and copied by cmd() */
+	} else if (err < 0) {
+		/* send std error reply */
+		reply.error = err;
+	} else if (err == 0) {
+		/* send std reply */
+		reply.error = 0;
+	}
+
+	/* 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:
+	ipc->host_pending = 0;
+
+	/* write 1 to clear busy, and trigger interrupt to host*/
+	ipc_write(IPC_DIPCTDR, ipc_read(IPC_DIPCTDR) |IPC_DIPCTDR_BUSY);
+	ipc_write(IPC_DIPCTDA, ipc_read(IPC_DIPCTDA) |IPC_DIPCTDA_BUSY );
+
+	/* unmask Busy interrupt */
+	ipc_write(IPC_DIPCCTL, ipc_read(IPC_DIPCCTL) | IPC_DIPCCTL_IPCTBIE);
+
+	// 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);
+	}
+
+	tracev_ipc("CmD");
+}
+
+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;
+	}
+
+	/* 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 */
+	ipc_write(IPC_DIPCIDD, 0);
+	ipc_write(IPC_DIPCIDR, 0x80000000 | msg->header);
+
+out:
+	spin_unlock_irq(&ipc->lock, flags);
+}
+
+int platform_ipc_init(struct ipc *ipc)
+{
+	struct intel_ipc_data *iipc;
+	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 = rballoc(RZONE_SYS, RFLAGS_NONE,
+			HOST_PAGE_SIZE);
+	if (iipc->page_table)
+		bzero(iipc->page_table, HOST_PAGE_SIZE);
+
+	/* dma */
+	iipc->dmac0 = dma_get(DMA_GP_LP_DMAC0);
+
+	/* PM */
+	iipc->pm_prepare_D3 = 0;
+
+	/* configure interrupt */
+	interrupt_register(PLATFORM_IPC_INTERUPT, irq_handler, NULL);
+	interrupt_enable(PLATFORM_IPC_INTERUPT);
+
+	/* enable IPC interrupts from host */
+	ipc_write(IPC_DIPCCTL, IPC_DIPCCTL_IPCIDIE | IPC_DIPCCTL_IPCTBIE);
+
+	return 0;
+}
-- 
2.14.1



More information about the Sound-open-firmware mailing list