diff options
-rw-r--r-- | common/audio_codec.c | 138 | ||||
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | include/audio_codec.h | 61 | ||||
-rw-r--r-- | include/config.h | 6 | ||||
-rw-r--r-- | include/console_channel.inc | 3 | ||||
-rw-r--r-- | include/ec_commands.h | 64 |
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, |