summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/mt_scp/audio_codec_wov.c97
-rw-r--r--chip/mt_scp/build.mk1
-rw-r--r--chip/mt_scp/registers.h43
3 files changed, 141 insertions, 0 deletions
diff --git a/chip/mt_scp/audio_codec_wov.c b/chip/mt_scp/audio_codec_wov.c
new file mode 100644
index 0000000000..bff8f776b7
--- /dev/null
+++ b/chip/mt_scp/audio_codec_wov.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "audio_codec.h"
+#include "hooks.h"
+#include "memmap.h"
+#include "registers.h"
+#include "task.h"
+#include "util.h"
+
+/* VIF FIFO irq is triggered above this level */
+#define WOV_TRIGGER_LEVEL 160
+
+int audio_codec_wov_enable_notifier(void)
+{
+ SCP_VIF_FIFO_DATA_THRE = WOV_TRIGGER_LEVEL + 1;
+ SCP_VIF_FIFO_EN |= VIF_FIFO_IRQ_EN;
+
+ task_enable_irq(SCP_IRQ_MAD_FIFO);
+
+ return EC_SUCCESS;
+}
+
+int audio_codec_wov_disable_notifier(void)
+{
+ SCP_VIF_FIFO_EN &= ~VIF_FIFO_IRQ_EN;
+
+ task_disable_irq(SCP_IRQ_MAD_FIFO);
+
+ return EC_SUCCESS;
+}
+
+int audio_codec_wov_enable(void)
+{
+ SCP_VIF_FIFO_EN = 0;
+
+ SCP_RXIF_CFG0 = (RXIF_CFG0_RESET_VAL & ~RXIF_RGDL2_MASK) |
+ RXIF_RGDL2_DMIC_16K;
+ SCP_RXIF_CFG1 = RXIF_CFG1_RESET_VAL;
+
+ SCP_VIF_FIFO_EN |= VIF_FIFO_RSTN;
+
+ return EC_SUCCESS;
+}
+
+int audio_codec_wov_disable(void)
+{
+ SCP_VIF_FIFO_EN = 0;
+
+ return EC_SUCCESS;
+}
+
+static size_t wov_fifo_level(void)
+{
+ uint32_t fifo_status = SCP_VIF_FIFO_STATUS;
+
+ if (!(fifo_status & VIF_FIFO_VALID))
+ return 0;
+
+ if (fifo_status & VIF_FIFO_FULL)
+ return VIF_FIFO_MAX;
+
+ return VIF_FIFO_LEVEL(fifo_status);
+}
+
+int32_t audio_codec_wov_read(void *buf, uint32_t count)
+{
+ int16_t *out = buf;
+
+ count >>= 1;
+
+ while (count-- && wov_fifo_level())
+ *out++ = SCP_VIF_FIFO_DATA;
+
+ return (void *)out - buf;
+}
+
+static void wov_fifo_interrupt_handler(void)
+{
+#ifdef HAS_TASK_WOV
+ task_wake(TASK_ID_WOV);
+#endif
+
+ audio_codec_wov_disable_notifier();
+
+ /* Read to clear */
+ SCP_VIF_FIFO_IRQ_STATUS;
+}
+DECLARE_IRQ(SCP_IRQ_MAD_FIFO, wov_fifo_interrupt_handler, 2);
+
+int audio_codec_memmap_ap_to_ec(uintptr_t ap_addr, uintptr_t *ec_addr)
+{
+ return memmap_ap_to_scp(ap_addr, ec_addr);
+}
diff --git a/chip/mt_scp/build.mk b/chip/mt_scp/build.mk
index 151876a1c8..fa6164056e 100644
--- a/chip/mt_scp/build.mk
+++ b/chip/mt_scp/build.mk
@@ -26,6 +26,7 @@ endif
endif
# Optional chip modules
+chip-$(CONFIG_AUDIO_CODEC_WOV)+=audio_codec_wov.o
chip-$(CONFIG_COMMON_TIMER)+=hrtimer.o
chip-$(CONFIG_I2C)+=i2c.o
chip-$(CONFIG_IPI)+=ipi.o ipi_table.o
diff --git a/chip/mt_scp/registers.h b/chip/mt_scp/registers.h
index dd70d6b273..6196a936e2 100644
--- a/chip/mt_scp/registers.h
+++ b/chip/mt_scp/registers.h
@@ -187,6 +187,49 @@
#define SCP_L1_EXT_ADDR_OTHER_LSB_MASK (BIT(SCP_REMAP_ADDR_SHIFT) - 1)
#define SCP_L1_EXT_ADDR_OTHER_MSB_MASK ((~0) << SCP_REMAP_ADDR_SHIFT)
+/* Audio/voice FIFO */
+#define SCP_AUDIO_BASE (SCP_CFG_BASE + 0x1000)
+#define SCP_VIF_FIFO_EN REG32(SCP_AUDIO_BASE)
+#define VIF_FIFO_RSTN (1 << 0)
+#define VIF_FIFO_IRQ_EN (1 << 1)
+#define VIF_FIFO_SRAM_PWR (1 << 2)
+#define VIF_FIFO_RSTN_STATUS (1 << 4)
+#define SCP_VIF_FIFO_STATUS REG32(SCP_AUDIO_BASE + 0x04)
+#define VIF_FIFO_VALID (1 << 0)
+#define VIF_FIFO_FULL (1 << 4)
+#define VIF_FIFO_LEVEL(status) (((status) >> 16) & 0xff)
+#define VIF_FIFO_MAX 256
+#define SCP_VIF_FIFO_DATA REG32(SCP_AUDIO_BASE + 0x08)
+#define SCP_VIF_FIFO_DATA_THRE REG32(SCP_AUDIO_BASE + 0x0C)
+/* VIF IRQ status clears on read! */
+#define SCP_VIF_FIFO_IRQ_STATUS REG32(SCP_AUDIO_BASE + 0x10)
+/* Audio/voice serial interface */
+#define SCP_RXIF_CFG0 REG32(SCP_AUDIO_BASE + 0x14)
+#define RXIF_CFG0_RESET_VAL 0x2A130001
+#define RXIF_AFE_ON (1 << 0)
+#define RXIF_SCKINV (1 << 1)
+#define RXIF_RG_DL_2_IN_MODE(mode) (((mode) & 0xf) << 8)
+#define RXIF_RGDL2_AMIC_16K (0x1 << 8)
+#define RXIF_RGDL2_DMIC_16K (0x2 << 8)
+#define RXIF_RGDL2_DMIC_LP_16K (0x3 << 8)
+#define RXIF_RGDL2_AMIC_32K (0x5 << 8)
+#define RXIF_RGDL2_MASK (0xf << 8)
+#define RXIF_UP8X_RSP(p) (((p) & 0x7) << 16)
+#define RXIF_RG_RX_READEN (1 << 19)
+#define RXIF_MONO (1 << 20)
+#define RXIF_RG_CLK_A16P7K_EN(cnt) (((cnt) & 0xff) << 24)
+#define SCP_RXIF_CFG1 REG32(SCP_AUDIO_BASE + 0x18)
+#define RXIF_CFG1_RESET_VAL 0x33180014
+#define RXIF_RG_SYNC_CNT_TBL(t) ((t) & 0x1ff)
+#define RXIF_RG_SYNC_SEARCH_TBL(t) (((t) & 0x1f) << 16)
+#define RXIF_RG_SYNC_CHECK_ROUND(r) (((r) & 0xf) << 24)
+#define RXIF_RG_INSYNC_CHECK_ROUND(r) (((r) & 0xf) << 28)
+#define SCP_RXIF_CFG2 REG32(SCP_AUDIO_BASE + 0x1C)
+#define RXIF_SYNC_WORD(w) ((w) & 0xffff)
+#define SCP_RXIF_OUT REG32(SCP_AUDIO_BASE + 0x20)
+#define SCP_RXIF_STATUS REG32(SCP_AUDIO_BASE + 0x24)
+#define SCP_RXIF_IRQ_EN REG32(SCP_AUDIO_BASE + 0x28)
+
/* INTC control */
#define SCP_INTC_BASE (SCP_CFG_BASE + 0x2000)
#define SCP_INTC_IRQ_STATUS REG32(SCP_INTC_BASE)