summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/audio_codec.c138
-rw-r--r--common/build.mk1
-rw-r--r--include/audio_codec.h61
-rw-r--r--include/config.h6
-rw-r--r--include/console_channel.inc3
-rw-r--r--include/ec_commands.h64
6 files changed, 268 insertions, 5 deletions
diff --git a/common/audio_codec.c b/common/audio_codec.c
new file mode 100644
index 0000000000..1dcc7e9b16
--- /dev/null
+++ b/common/audio_codec.c
@@ -0,0 +1,138 @@
+/*
+ * 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 "console.h"
+#include "host_command.h"
+
+#define CPRINTS(format, args...) cprints(CC_AUDIO_CODEC, format, ## args)
+
+static const uint32_t capabilities;
+
+static struct {
+ uint8_t cap;
+ uint8_t type;
+ uintptr_t *addr;
+ uint32_t len;
+} shms[EC_CODEC_SHM_ID_LAST];
+
+static int get_capabilities(struct host_cmd_handler_args *args)
+{
+ struct ec_response_ec_codec_get_capabilities *r = args->response;
+
+ r->capabilities = capabilities;
+
+ args->response_size = sizeof(*r);
+ return EC_RES_SUCCESS;
+}
+
+static int get_shm_addr(struct host_cmd_handler_args *args)
+{
+ const struct ec_param_ec_codec *p = args->params;
+ struct ec_response_ec_codec_get_shm_addr *r = args->response;
+ const uint8_t shm_id = p->get_shm_addr_param.shm_id;
+
+ if (shm_id >= EC_CODEC_SHM_ID_LAST)
+ return EC_RES_INVALID_PARAM;
+ if (!shms[shm_id].addr || !audio_codec_capable(shms[shm_id].cap))
+ return EC_RES_INVALID_PARAM;
+ if (!*shms[shm_id].addr &&
+ shms[shm_id].type == EC_CODEC_SHM_TYPE_EC_RAM)
+ return EC_RES_ERROR;
+
+ r->len = shms[shm_id].len;
+ r->type = shms[shm_id].type;
+ r->phys_addr = *shms[shm_id].addr;
+
+ args->response_size = sizeof(*r);
+ return EC_RES_SUCCESS;
+}
+
+static int set_shm_addr(struct host_cmd_handler_args *args)
+{
+ const struct ec_param_ec_codec *p = args->params;
+ const uint8_t shm_id = p->set_shm_addr_param.shm_id;
+ uintptr_t ap_addr, ec_addr;
+
+ if (shm_id >= EC_CODEC_SHM_ID_LAST)
+ return EC_RES_INVALID_PARAM;
+ if (!shms[shm_id].addr || !audio_codec_capable(shms[shm_id].cap))
+ return EC_RES_INVALID_PARAM;
+ if (p->set_shm_addr_param.len < shms[shm_id].len)
+ return EC_RES_INVALID_PARAM;
+ if (*shms[shm_id].addr)
+ return EC_RES_BUSY;
+
+ ap_addr = (uintptr_t)p->set_shm_addr_param.phys_addr;
+ if (audio_codec_memmap_ap_to_ec(ap_addr, &ec_addr) != EC_SUCCESS)
+ return EC_RES_ERROR;
+ *shms[shm_id].addr = ec_addr;
+
+ args->response_size = 0;
+ return EC_RES_SUCCESS;
+}
+
+static int (*sub_cmds[])(struct host_cmd_handler_args *) = {
+ [EC_CODEC_GET_CAPABILITIES] = get_capabilities,
+ [EC_CODEC_GET_SHM_ADDR] = get_shm_addr,
+ [EC_CODEC_SET_SHM_ADDR] = set_shm_addr,
+};
+
+#ifdef DEBUG_AUDIO_CODEC
+static char *strcmd[] = {
+ [EC_CODEC_GET_CAPABILITIES] = "EC_CODEC_GET_CAPABILITIES",
+ [EC_CODEC_GET_SHM_ADDR] = "EC_CODEC_GET_SHM_ADDR",
+ [EC_CODEC_SET_SHM_ADDR] = "EC_CODEC_SET_SHM_ADDR",
+};
+BUILD_ASSERT(ARRAY_SIZE(sub_cmds) == ARRAY_SIZE(strcmd));
+#endif
+
+static int host_command(struct host_cmd_handler_args *args)
+{
+ const struct ec_param_ec_codec *p = args->params;
+
+#ifdef DEBUG_AUDIO_CODEC
+ CPRINTS("subcommand: %s", strcmd[p->cmd]);
+#endif
+
+ if (p->cmd < EC_CODEC_SUBCMD_COUNT)
+ return sub_cmds[p->cmd](args);
+
+ return EC_RES_INVALID_PARAM;
+}
+DECLARE_HOST_COMMAND(EC_CMD_EC_CODEC, host_command, EC_VER_MASK(0));
+
+/*
+ * Exported interfaces.
+ */
+int audio_codec_capable(uint8_t cap)
+{
+ return capabilities & BIT(cap);
+}
+
+int audio_codec_register_shm(uint8_t shm_id, uint8_t cap,
+ uintptr_t *addr, uint32_t len, uint8_t type)
+{
+ if (shm_id >= EC_CODEC_SHM_ID_LAST)
+ return EC_ERROR_INVAL;
+ if (cap >= EC_CODEC_CAP_LAST)
+ return EC_ERROR_INVAL;
+ if (shms[shm_id].addr || shms[shm_id].len)
+ return EC_ERROR_BUSY;
+
+ shms[shm_id].cap = cap;
+ shms[shm_id].addr = addr;
+ shms[shm_id].len = len;
+ shms[shm_id].type = type;
+
+ return EC_SUCCESS;
+}
+
+__attribute__((weak))
+int audio_codec_memmap_ap_to_ec(uintptr_t ap_addr, uintptr_t *ec_addr)
+{
+ return EC_ERROR_UNIMPLEMENTED;
+}
diff --git a/common/build.mk b/common/build.mk
index 02c08ac8ff..213db0a0fc 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -29,6 +29,7 @@ common-$(CONFIG_AES_GCM)+=aes-gcm.o
common-$(CONFIG_CMD_ADC)+=adc.o
common-$(HAS_TASK_ALS)+=als.o
common-$(CONFIG_AP_HANG_DETECT)+=ap_hang_detect.o
+common-$(CONFIG_AUDIO_CODEC)+=audio_codec.o
common-$(CONFIG_BACKLIGHT_LID)+=backlight_lid.o
common-$(CONFIG_BASE32)+=base32.o
common-$(CONFIG_DETACHABLE_BASE)+=base_state.o
diff --git a/include/audio_codec.h b/include/audio_codec.h
new file mode 100644
index 0000000000..ab1c65ae61
--- /dev/null
+++ b/include/audio_codec.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifndef __CROS_EC_AUDIO_CODEC_H
+#define __CROS_EC_AUDIO_CODEC_H
+
+#include "stdint.h"
+
+/*
+ * Common abstract layer
+ */
+
+/*
+ * Checks capability of audio codec.
+ *
+ * @cap is an integer from enum ec_codec_cap. Note that it represents a
+ * bit field in a 32-bit integer. The valid range is [0, 31].
+ *
+ * Returns:
+ * 1 if audio codec capabilities include cap passed as parameter.
+ * 0 if not capable.
+ */
+int audio_codec_capable(uint8_t cap);
+
+/*
+ * Registers shared memory (SHM).
+ *
+ * @shm_id is a SHM identifier from enum ec_codec_shm_id.
+ * @cap is an integer from enum ec_codec_cap.
+ * @addr is the address pointer to the SHM.
+ * @len is the maximum length of the SHM.
+ * @type is an integer from enum ec_codec_shm_type.
+ *
+ * Returns:
+ * EC_SUCCESS if success.
+ * EC_ERROR_UNKNOWN if internal errors.
+ * EC_ERROR_INVAL if invalid shm_id.
+ * EC_ERROR_INVAL if invalid cap.
+ * EC_ERROR_BUSY if the shm_id has been registered.
+ */
+int audio_codec_register_shm(uint8_t shm_id, uint8_t cap,
+ uintptr_t *addr, uint32_t len, uint8_t type);
+
+/*
+ * Translates the physical address from AP to EC's memory space. Required if
+ * wants to use AP SHM.
+ *
+ * @ap_addr is physical address from AP.
+ * @ec_addr is the translation destination.
+ *
+ * Returns:
+ * EC_SUCCESS if success.
+ * EC_ERROR_UNKNOWN if internal errors.
+ * EC_ERROR_UNIMPLEMENTED if no concrete implementation.
+ */
+int audio_codec_memmap_ap_to_ec(uintptr_t ap_addr, uintptr_t *ec_addr);
+
+#endif
diff --git a/include/config.h b/include/config.h
index da88d31015..b09f26555b 100644
--- a/include/config.h
+++ b/include/config.h
@@ -337,9 +337,6 @@
/* Support AP Warm reset Interrupt. */
#undef CONFIG_AP_WARM_RESET_INTERRUPT
-/* Support audio codec for WoV and I2S normal recording. */
-#undef CONFIG_AUDIO_CODEC
-
/*
* Enable support for CPU caches behaving according to the ARMv7-M ISA.
* (so far, only the Cortex-M7 has such caches)
@@ -353,6 +350,9 @@
*/
#undef CONFIG_ASSEMBLY_MULA32
+/* Support audio codec. */
+#undef CONFIG_AUDIO_CODEC
+
/* Allow proprietary communication protocols' extensions. */
#undef CONFIG_EXTENSION_COMMAND
diff --git a/include/console_channel.inc b/include/console_channel.inc
index 0f931e88f7..21059fc64e 100644
--- a/include/console_channel.inc
+++ b/include/console_channel.inc
@@ -7,6 +7,9 @@
CONSOLE_CHANNEL(CC_COMMAND, "command")
CONSOLE_CHANNEL(CC_ACCEL, "accel")
+#ifdef CONFIG_AUDIO_CODEC
+CONSOLE_CHANNEL(CC_AUDIO_CODEC, "audio_codec")
+#endif
#ifdef CONFIG_BLUETOOTH_LE
CONSOLE_CHANNEL(CC_BLUETOOTH_LE, "bluetooth_le")
#ifdef CONFIG_BLUETOOTH_LL_DEBUG
diff --git a/include/ec_commands.h b/include/ec_commands.h
index 954d956e65..057c3411f4 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -4659,8 +4659,68 @@ enum mkbp_cec_event {
/*****************************************************************************/
+/* Commands for audio codec. */
+#define EC_CMD_EC_CODEC 0x00BC
+
+enum ec_codec_subcmd {
+ EC_CODEC_GET_CAPABILITIES = 0x0,
+ EC_CODEC_GET_SHM_ADDR = 0x1,
+ EC_CODEC_SET_SHM_ADDR = 0x2,
+ EC_CODEC_SUBCMD_COUNT,
+};
+
+enum ec_codec_cap {
+ EC_CODEC_CAP_LAST = 32,
+};
+
+enum ec_codec_shm_id {
+ EC_CODEC_SHM_ID_LAST,
+};
+
+enum ec_codec_shm_type {
+ EC_CODEC_SHM_TYPE_EC_RAM = 0x0,
+ EC_CODEC_SHM_TYPE_SYSTEM_RAM = 0x1,
+};
+
+struct __ec_align1 ec_param_ec_codec_get_shm_addr {
+ uint8_t shm_id;
+ uint8_t reserved[3];
+};
+
+struct __ec_align4 ec_param_ec_codec_set_shm_addr {
+ uint64_t phys_addr;
+ uint32_t len;
+ uint8_t shm_id;
+ uint8_t reserved[3];
+};
+
+struct __ec_align4 ec_param_ec_codec {
+ uint8_t cmd; /* enum ec_codec_subcmd */
+ uint8_t reserved[3];
+
+ union {
+ struct ec_param_ec_codec_get_shm_addr
+ get_shm_addr_param;
+ struct ec_param_ec_codec_set_shm_addr
+ set_shm_addr_param;
+ };
+};
+
+struct __ec_align4 ec_response_ec_codec_get_capabilities {
+ uint32_t capabilities;
+};
+
+struct __ec_align4 ec_response_ec_codec_get_shm_addr {
+ uint64_t phys_addr;
+ uint32_t len;
+ uint8_t type;
+ uint8_t reserved[3];
+};
+
+/*****************************************************************************/
+
/* Commands for DMIC on audio codec. */
-#define EC_CMD_EC_CODEC_DMIC 0x00BC
+#define EC_CMD_EC_CODEC_DMIC 0x00BD
enum ec_codec_dmic_subcmd {
EC_CODEC_DMIC_SET_GAIN = 0x0,
@@ -4693,7 +4753,7 @@ struct __ec_align1 ec_response_ec_codec_dmic_get_gain {
/* Commands for I2S RX on audio codec. */
-#define EC_CMD_EC_CODEC_I2S_RX 0x00BD
+#define EC_CMD_EC_CODEC_I2S_RX 0x00BE
enum ec_codec_i2s_rx_subcmd {
EC_CODEC_I2S_RX_ENABLE = 0x0,