blob: 6d3d19a39ab7ead997463680a3225a7e8f367b1d [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 INTEL_HDA_UTILS_INTEL_AUDIO_DSP_IPC_H_
#define INTEL_HDA_UTILS_INTEL_AUDIO_DSP_IPC_H_
#include <stdint.h>
#include <zircon/compiler.h>
/**
* Host <-> DSP IPC interface definitions taken from
*
* cAVS Audio DSP
* Audio DSP Firmware Interface Specification
* Revision 0.5
* September 2017
*
* And
*
* cAVS Audio DSP Modules Specification
* Audio DSP Firmware Modules Interface Specification
* Revision 0.5
* September 2017
*/
namespace audio::intel_hda {
// Common structures
enum class MsgTarget : uint8_t {
FW_GEN_MSG = 0u,
MODULE_MSG = 1u,
};
enum class MsgDir : uint8_t {
MSG_REQUEST = 0u,
MSG_NOTIFICATION = 0u,
MSG_REPLY = 1u,
};
// Global Message
enum class GlobalType : uint8_t {
CREATE_PIPELINE = 17u,
SET_PIPELINE_STATE = 19u,
NOTIFICATION = 27u,
};
// Module Message
enum class ModuleMsgType : uint8_t {
INIT_INSTANCE = 0u,
MODULE_CONFIG_GET = 1u,
MODULE_CONFIG_SET = 2u,
LARGE_CONFIG_GET = 3u,
LARGE_CONFIG_SET = 4u,
BIND = 5u,
UNBIND = 6u,
SET_DX = 7u,
ENTER_MODULE_RESTORE = 9u,
EXIT_MODULE_RESTORE = 10u,
DELETE_INSTANCE = 11u,
};
// Message Reply
enum class MsgStatus : uint32_t {
IPC_SUCCESS = 0u,
// General errors.
ERROR_INVALID_PARAM = 1u,
UNKNOWN_MESSAGE_TYPE = 2u,
OUT_OF_MEMORY = 3u,
BUSY = 4u,
FAILURE = 6u,
INVALID_REQUEST = 7u,
INVALID_RESOURCE_ID = 9u,
RESOURCE_ID_EXISTS = 10u,
INVALID_RESOURCE_STATE = 12u,
POWER_TRANSITION_FAILED = 13u,
// Library loading errors.
INVALID_MANIFEST = 14u,
UNAVAILABLE = 15u,
LOAD_ADDRESS_OUT_OF_RANGE = 42u,
CSE_VALIDATION_FAILED = 44u,
// Module management errors.
MOD_MGMT_ERROR = 100u,
MOD_LOAD_CL_FAILED = 101u,
MOD_LOAD_INVALID_HASH = 102u,
MOD_INSTANCE_EXISTS = 103u,
MOD_NOT_INITIALIZED = 104u,
MOD_INVALID_ID = 110u,
MOD_INST_INVALID_ID = 111u,
QUEUE_INVALID_ID = 112u,
QUEUE_DST_INVALID_ID = 113u,
// Configuration errors.
INVALID_CORE_ID = 116u,
INVALID_CONFIG_PARAM_ID = 120u,
INVALID_CONFIG_DATA_LEN = 121u,
INVALID_CONFIG_DATA_STRUCT = 122u,
// Gateway errors.
GATEWAY_NOT_INITIALIZED = 140u,
GATEWAY_NOT_EXIST = 141u,
GATEWAY_STATE_NOT_SET = 142u,
// Other errors.
SCLK_ALREADY_RUNNING = 150u,
MCLK_ALREADY_RUNNING = 151u,
NO_RUNNING_SCLK = 152u,
NO_RUNNING_MCLK = 153u,
CORE_INACTIVE = 166u,
};
// Notifications
enum class NotificationType : uint8_t {
PHRASE_DETECTED = 4u,
RESOURCE_EVENT = 5u,
LOG_BUFFER_STATUS = 6u,
TIMESTAMP_CAPTURED = 7u,
FW_READY = 8u,
EXCEPTION_CAUGHT = 10u,
};
enum class ResourceType : uint32_t {
MODULE_INSTANCE = 0u,
PIPELINE = 1u,
GATEWAY = 2u,
EDF_TASK = 3u,
};
enum class ResourceEventType : uint32_t {
BUDGET_VIOLATION = 0u,
MIXER_UNDERRUN_DETECTED = 1u,
STREAM_DATA_SEGMENT = 2u,
PROCESS_DATA_ERROR = 3u,
STACK_OVERFLOW = 4u,
BUFFERING_MODE_CHANGED = 5u,
GATEWAY_UNDERRUN_DETECTED = 6u,
EDF_DOMAIN_UNSTABLE = 7u,
WATCHDOG_EXPIRED = 8u,
GATEWAY_HIGH_THRES = 10u,
GATEWAY_LOW_THRES = 11u,
};
struct ResourceEventData {
uint32_t resource_type;
uint32_t resource_id;
uint32_t event_type;
uint32_t event_data[6];
};
// Init Instance
enum class ProcDomain : uint8_t {
LOW_LATENCY = 0u,
DATA_PROCESSING = 1u,
};
enum class SamplingFrequency : uint32_t {
FS_8000HZ = 8000u,
FS_11025HZ = 11025u,
FS_12000HZ = 12000u,
FS_16000HZ = 16000u,
FS_22050HZ = 22050u,
FS_24000HZ = 24000u,
FS_32000HZ = 32000u,
FS_44100HZ = 44100u,
FS_48000HZ = 48000u,
FS_64000HZ = 64000u,
FS_88200HZ = 88200u,
FS_96000HZ = 96000u,
FS_128000HZ = 128000u,
FS_176000HZ = 176000u,
FS_192000HZ = 192000u,
};
enum class BitDepth : uint32_t {
DEPTH_8BIT = 8u,
DEPTH_16BIT = 16u,
DEPTH_24BIT = 24u,
DEPTH_32BIT = 32u,
};
enum ChannelIndex : uint8_t {
LEFT = 0u,
CENTER = 1u,
RIGHT = 2u,
LEFT_SURROUND = 3u,
CENTER_SURROUND = 3u,
RIGHT_SURROUND = 4u,
LEFT_SIDE = 5u,
RIGHT_SIDE = 6u,
LFE = 7u,
INVALID = 0xF,
};
enum ChannelConfig : uint32_t {
CONFIG_MONO = 0u,
CONFIG_STEREO = 1u,
CONFIG_2_POINT_1 = 2u,
CONFIG_3_POINT_0 = 3u,
CONFIG_3_POINT_1 = 4u,
CONFIG_QUATRO = 5u,
CONFIG_4_POINT_0 = 6u,
CONFIG_5_POINT_0 = 7u,
CONFIG_5_POINT_1 = 8u,
CONFIG_DUAL_MONO = 9u,
CONFIG_I2S_DUAL_STEREO_0 = 10u,
CONFIG_I2S_DUAL_STEREO_1 = 11u,
};
enum InterleavingStyle : uint32_t {
PER_CHANNEL = 0,
PER_SAMPLE = 1,
};
enum SampleType : uint8_t {
INT_MSB = 0u,
INT_LSB = 1u,
INT_SIGNED = 2u,
INT_UNSIGNED = 3u,
FLOAT = 4u,
};
struct AudioDataFormat {
SamplingFrequency sampling_frequency;
BitDepth bit_depth;
uint32_t channel_map;
ChannelConfig channel_config;
InterleavingStyle interleaving_style;
uint8_t number_of_channels;
uint8_t valid_bit_depth;
SampleType sample_type;
uint8_t reserved;
} __PACKED;
static_assert(sizeof(AudioDataFormat) == 24, "invalid AudioDataFormat size\n");
struct BaseModuleCfg {
uint32_t cpc; // DSP cycles required to process one input frame.
uint32_t ibs; // Size of module's input frame, in bytes.
uint32_t obs; // Size of module's output frame, in bytes.
uint32_t is_pages; // Number of memory pages to be allocated for this module.
AudioDataFormat audio_fmt; // Format of the module's input data.
} __PACKED;
struct IoPinFormat {
uint32_t pin_index; // Input/output pin number.
uint32_t ibs_obs; // Input/output frame size (in bytes).
AudioDataFormat audio_fmt;
} __PACKED;
struct BaseModuleCfgExt {
uint16_t nb_input_pins; // Number of input pins in |input_output_pins|.
uint16_t nb_output_pins; // Number of output pins in |input_output_pins|.
uint8_t reserved[8];
uint32_t priv_param_length; // Length of module-specific parameters for this module.
// Array of input pins, followed by array of output pins.
//
// Input and output pins will not necessarily be contiguous: the
// |pin_index| is used, not the index of the entry in this array.
IoPinFormat input_output_pins[];
} __PACKED;
// Pipeline Management
enum class PipelineState : uint16_t {
INVALID = 0u,
UNINITIALIZED = 1u,
RESET = 2u,
PAUSED = 3u,
RUNNING = 4u,
ERROR_STOP = 5u,
SAVED = 6u,
RESTORED = 7u,
};
// Common message defines
constexpr uint32_t IPC_PRI_MSG_TGT_MASK = 0x1;
constexpr uint32_t IPC_PRI_MSG_TGT_SHIFT = 30;
constexpr uint32_t IPC_PRI_RSP_MASK = 0x1;
constexpr uint32_t IPC_PRI_RSP_SHIFT = 29;
constexpr uint32_t IPC_PRI_TYPE_MASK = 0x1F;
constexpr uint32_t IPC_PRI_TYPE_SHIFT = 24;
constexpr uint32_t IPC_PRI_INSTANCE_ID_MASK = 0xFF;
constexpr uint32_t IPC_PRI_INSTANCE_ID_SHIFT = 16;
constexpr uint32_t IPC_PRI_MODULE_ID_MASK = 0xFFFF;
constexpr uint32_t IPC_PRI_MODULE_ID_SHIFT = 0;
// Message Reply
constexpr uint32_t IPC_PRI_STATUS_MASK = 0x00FFFFFF;
// Notification
constexpr uint32_t IPC_PRI_NOTIF_TYPE_MASK = 0xFF;
constexpr uint32_t IPC_PRI_NOTIF_TYPE_SHIFT = 16;
// Init Instance Request Parameters
constexpr uint32_t IPC_EXT_PROC_DOMAIN_SHIFT = 28;
constexpr uint32_t IPC_EXT_CORE_ID_MASK = 0xF;
constexpr uint32_t IPC_EXT_CORE_ID_SHIFT = 24;
constexpr uint32_t IPC_EXT_PPL_INSTANCE_ID_SHIFT = 16;
// Large Config Get Request Parameters
constexpr uint32_t IPC_EXT_INIT_BLOCK_SHIFT = 29;
constexpr uint32_t IPC_EXT_FINAL_BLOCK_SHIFT = 28;
constexpr uint32_t IPC_EXT_LARGE_PARAM_ID_MASK = 0xFF;
constexpr uint32_t IPC_EXT_LARGE_PARAM_ID_SHIFT = 20;
constexpr uint32_t IPC_EXT_DATA_OFF_SIZE_MASK = 0x000FFFFF;
constexpr uint32_t IPC_EXT_DATA_OFF_MAX_SIZE = IPC_EXT_DATA_OFF_SIZE_MASK;
// Bind/Unbind Request Parameters
constexpr uint32_t IPC_EXT_DST_INSTANCE_ID_SHIFT = 16;
constexpr uint32_t IPC_EXT_DST_QUEUE_MASK = 0x7;
constexpr uint32_t IPC_EXT_DST_QUEUE_SHIFT = 24;
constexpr uint32_t IPC_EXT_SRC_QUEUE_MASK = 0x7;
constexpr uint32_t IPC_EXT_SRC_QUEUE_SHIFT = 27;
// Create Pipeline Request Parameters
constexpr uint32_t IPC_PRI_PPL_PRIORITY_MASK = 0x1F;
constexpr uint32_t IPC_PRI_PPL_PRIORITY_SHIFT = 11;
constexpr uint32_t IPC_PRI_PPL_MEM_SIZE_MASK = 0x3FF;
// Set Pipeline State Parameters
constexpr uint32_t IPC_EXT_SYNC_STOP_START_SHIFT = 1;
struct IpcMessage {
public:
IpcMessage(uint32_t pri, uint32_t ext) : primary(pri), extension(ext) {}
IpcMessage() {}
// Common
MsgTarget msg_tgt() const {
return static_cast<MsgTarget>((primary >> IPC_PRI_MSG_TGT_SHIFT) & IPC_PRI_MSG_TGT_MASK);
}
MsgDir msg_dir() const {
return static_cast<MsgDir>((primary >> IPC_PRI_RSP_SHIFT) & IPC_PRI_RSP_MASK);
}
uint8_t type() const { return (primary >> IPC_PRI_TYPE_SHIFT) & IPC_PRI_TYPE_MASK; }
uint8_t instance_id() const {
return (primary >> IPC_PRI_INSTANCE_ID_SHIFT) & IPC_PRI_INSTANCE_ID_MASK;
}
uint16_t module_id() const { return primary & IPC_PRI_MODULE_ID_MASK; }
// Message Reply
MsgStatus status() const { return static_cast<MsgStatus>(primary & IPC_PRI_STATUS_MASK); }
bool is_reply() const { return msg_dir() == MsgDir::MSG_REPLY; }
// Notification
bool is_notif() const {
return (msg_tgt() == MsgTarget::FW_GEN_MSG) && (msg_dir() == MsgDir::MSG_NOTIFICATION) &&
(static_cast<GlobalType>(type()) == GlobalType::NOTIFICATION);
}
NotificationType notif_type() const {
return static_cast<NotificationType>((primary >> IPC_PRI_NOTIF_TYPE_SHIFT) &
IPC_PRI_NOTIF_TYPE_MASK);
}
// Large Config Get/Set
bool init_block() { return static_cast<bool>((extension >> IPC_EXT_INIT_BLOCK_SHIFT) & 0x1); }
bool final_block() { return static_cast<bool>((extension >> IPC_EXT_FINAL_BLOCK_SHIFT) & 0x1); }
uint8_t large_param_id() {
return (extension >> IPC_EXT_LARGE_PARAM_ID_SHIFT) & IPC_EXT_LARGE_PARAM_ID_MASK;
}
uint32_t data_off_size() { return extension & IPC_EXT_DATA_OFF_SIZE_MASK; }
uint32_t primary = 0;
uint32_t extension = 0;
};
// Common
static inline constexpr uint32_t IPC_PRI(MsgTarget msg_tgt, MsgDir rsp, ModuleMsgType type,
uint8_t instance_id, uint16_t module_id) {
return (static_cast<uint8_t>(msg_tgt) << IPC_PRI_MSG_TGT_SHIFT) |
(static_cast<uint8_t>(rsp) << IPC_PRI_RSP_SHIFT) |
(static_cast<uint8_t>(type) << IPC_PRI_TYPE_SHIFT) |
(instance_id << IPC_PRI_INSTANCE_ID_SHIFT) | module_id;
}
// Init Instance
static inline constexpr uint32_t IPC_INIT_INSTANCE_EXT(ProcDomain proc_domain, uint8_t core_id,
uint8_t ppl_instance_id,
uint16_t param_block_size) {
return (static_cast<uint8_t>(proc_domain) << IPC_EXT_PROC_DOMAIN_SHIFT) |
((core_id & IPC_EXT_CORE_ID_MASK) << IPC_EXT_CORE_ID_SHIFT) |
(ppl_instance_id << IPC_EXT_PPL_INSTANCE_ID_SHIFT) | param_block_size;
}
// Large Config Get/Set
static inline constexpr uint32_t IPC_LARGE_CONFIG_EXT(bool init_block, bool final_block,
uint8_t large_param_id,
uint32_t data_off_size) {
return (init_block ? (1 << IPC_EXT_INIT_BLOCK_SHIFT) : 0) |
(final_block ? (1 << IPC_EXT_FINAL_BLOCK_SHIFT) : 0) |
(large_param_id << IPC_EXT_LARGE_PARAM_ID_SHIFT) |
(data_off_size & IPC_EXT_DATA_OFF_SIZE_MASK);
}
// Bind/Unbind
static inline constexpr uint32_t IPC_BIND_UNBIND_EXT(uint16_t dst_module_id,
uint8_t dst_instance_id, uint8_t dst_queue,
uint8_t src_queue) {
return ((src_queue & IPC_EXT_SRC_QUEUE_MASK) << IPC_EXT_SRC_QUEUE_SHIFT) |
((dst_queue & IPC_EXT_DST_QUEUE_MASK) << IPC_EXT_DST_QUEUE_SHIFT) |
(dst_instance_id << IPC_EXT_DST_INSTANCE_ID_SHIFT) | dst_module_id;
}
// Create Pipeline
static inline constexpr uint32_t IPC_CREATE_PIPELINE_PRI(uint8_t instance_id, uint8_t ppl_priority,
uint16_t ppl_mem_size) {
return (static_cast<uint8_t>(MsgTarget::FW_GEN_MSG) << IPC_PRI_MSG_TGT_SHIFT) |
(static_cast<uint8_t>(MsgDir::MSG_REQUEST) << IPC_PRI_RSP_SHIFT) |
(static_cast<uint8_t>(GlobalType::CREATE_PIPELINE) << IPC_PRI_TYPE_SHIFT) |
(instance_id << IPC_PRI_INSTANCE_ID_SHIFT) |
((ppl_priority & IPC_PRI_PPL_PRIORITY_MASK) << IPC_PRI_PPL_PRIORITY_SHIFT) |
(ppl_mem_size & IPC_PRI_PPL_MEM_SIZE_MASK);
}
static inline constexpr uint32_t IPC_CREATE_PIPELINE_EXT(bool lp) { return (lp ? 1 : 0); }
// Set Pipeline State
static inline constexpr uint32_t IPC_SET_PIPELINE_STATE_PRI(uint8_t ppl_id, PipelineState state) {
return (static_cast<uint8_t>(MsgTarget::FW_GEN_MSG) << IPC_PRI_MSG_TGT_SHIFT) |
(static_cast<uint8_t>(MsgDir::MSG_REQUEST) << IPC_PRI_RSP_SHIFT) |
(static_cast<uint8_t>(GlobalType::SET_PIPELINE_STATE) << IPC_PRI_TYPE_SHIFT) |
(ppl_id << IPC_PRI_INSTANCE_ID_SHIFT) | static_cast<uint16_t>(state);
}
static inline constexpr uint32_t IPC_SET_PIPELINE_STATE_EXT(bool multi_ppl, bool sync_stop_start) {
return (sync_stop_start ? (1 << IPC_EXT_SYNC_STOP_START_SHIFT) : 0) | (multi_ppl ? 1 : 0);
}
// Base FW Run-time Parameters
enum class BaseFWParamType : uint8_t {
ADSP_PROPERTIES = 0u,
ADSP_RESOURCE_STATE = 1u,
NOTIFICATION_MASK = 3u,
ASTATE_TABLE = 4u,
DMA_CONTROL = 5u,
ENABLE_LOGS = 6u,
FIRMWARE_CONFIG = 7u,
HARDWARE_CONFIG = 8u,
MODULES_INFO = 9u,
PIPELINE_LIST_INFO = 10u,
PIPELINE_PROPS = 11u,
SCHEDULERS_INFO = 12u,
GATEWAYS_INFO = 13u,
MEMORY_STATE_INFO = 14u,
POWER_STATE_INFO = 15u,
LIBRARIES_INFO = 16u,
PERF_MEASUREMENTS_STATE = 17u,
GLOBAL_PERF_DATA = 18u,
L2_CACHE_INFO = 19u,
SYSTEM_TIME = 20u,
};
enum class FirmwareConfigType : uint32_t {
FW_VERSION = 0u,
MEMORY_RECLAIMED = 1u,
SLOW_CLOCK_FREQ_HZ = 2u,
FAST_CLOCK_FREQ_HZ = 3u,
DMA_BUFFER_CONFIG = 4u,
ALH_SUPPORT_LEVEL = 5u,
IPC_DL_MAILBOX_BYTES = 6u,
IPC_UL_MAILBOX_BYTES = 7u,
TRACE_LOG_BYTES = 8u,
MAX_PPL_COUNT = 9u,
MAX_ASTATE_COUNT = 10u,
MAX_MODULE_PIN_COUNT = 11u,
MODULES_COUNT = 12u,
MAX_MOD_INST_COUNT = 13u,
MAX_LL_TASKS_PER_PRI_COUNT = 14u,
LL_PRI_COUNT = 15u,
MAX_DP_TASKS_COUNT = 16u,
MAX_LIBS_COUNT = 17u,
SCHEDULER_CONFIG = 18u,
XTAL_FREQ_HZ = 19u,
};
enum class HardwareConfigType : uint32_t {
CAVS_VERSION = 0u,
DSP_CORES = 1u,
MEM_PAGE_BYTES = 2u,
TOTAL_PHYS_MEM_PAGES = 3u,
I2S_CAPS = 4u,
GPDMA_CAPS = 5u,
GATEWAY_COUNT = 6u,
HP_EBB_COUNT = 7u,
LP_EBB_COUNT = 8u,
EBB_SIZE_BYTES = 9u,
};
// Base FW Common
struct TLVHeader {
uint32_t type;
uint32_t length;
uint8_t data[];
} __PACKED;
// Base FW Modules Info
struct SegmentDesc {
uint32_t flags;
uint32_t v_base_addr;
uint32_t file_offset;
} __PACKED;
struct ModuleEntry {
uint16_t module_id;
uint16_t state_flags;
uint8_t name[8];
uint32_t uuid[4];
uint32_t type;
uint8_t hash[32];
uint32_t entry_point;
uint16_t cfg_offset;
uint16_t cfg_count;
uint16_t affinity_mask;
uint16_t instance_max_count;
uint16_t instance_bss_size;
SegmentDesc segments[3];
uint8_t reserved[2]; // not in spec but seems necessary
} __PACKED;
struct ModulesInfo {
uint32_t module_count;
// Followed by "module_count" packed instances of "ModuleEntry".
} __PACKED;
// Base FW Pipeline List Info
struct PipelineListInfo {
uint32_t ppl_count;
uint32_t ppl_id[];
} __PACKED;
// Base FW Pipeline Props
struct ModInstListInfo {
uint32_t module_instance_count;
uint32_t module_instance_id[];
};
struct PipelineProps {
uint32_t id;
uint32_t priority;
uint32_t state;
uint32_t total_memory_bytes;
uint32_t used_memory_bytes;
uint32_t context_pages;
ModInstListInfo module_instances;
// tasks follow
} __PACKED;
// Copier Module
constexpr uint32_t NODE_ID_DMA_TYPE_MASK = 0x1F;
constexpr uint32_t NODE_ID_DMA_TYPE_SHIFT = 8;
constexpr uint32_t NODE_ID_I2S_INSTANCE_MASK = 0xF;
constexpr uint32_t NODE_ID_I2S_INSTANCE_SHIFT = 4;
constexpr uint32_t NODE_ID_TIME_SLOT_MASK = 0xF;
constexpr uint32_t NODE_ID_DMA_ID_MASK = 0xFF;
constexpr uint8_t DMA_TYPE_HDA_HOST_OUTPUT = 0;
constexpr uint8_t DMA_TYPE_HDA_HOST_INPUT = 1;
constexpr uint8_t DMA_TYPE_I2S_LINK_OUTPUT = 12;
constexpr uint8_t DMA_TYPE_I2S_LINK_INPUT = 13;
struct CopierGatewayCfg {
uint32_t node_id;
uint32_t dma_buffer_size;
uint32_t config_length;
uint8_t config_data[];
} __PACKED;
static inline constexpr uint32_t HDA_GATEWAY_CFG_NODE_ID(uint8_t dma_type, uint8_t dma_id) {
return ((dma_type & NODE_ID_DMA_TYPE_MASK) << NODE_ID_DMA_TYPE_SHIFT) |
(dma_id & NODE_ID_DMA_ID_MASK);
}
static inline constexpr uint32_t I2S_GATEWAY_CFG_NODE_ID(uint8_t dma_type, uint8_t i2s_instance,
uint8_t time_slot) {
return ((dma_type & NODE_ID_DMA_TYPE_MASK) << NODE_ID_DMA_TYPE_SHIFT) |
((i2s_instance & NODE_ID_I2S_INSTANCE_MASK) << NODE_ID_I2S_INSTANCE_SHIFT) |
(time_slot & NODE_ID_TIME_SLOT_MASK);
}
struct CopierCfg {
BaseModuleCfg base_cfg;
AudioDataFormat out_fmt;
uint32_t copier_feature_mask;
CopierGatewayCfg gtw_cfg;
} __PACKED;
} // namespace audio::intel_hda
#endif // INTEL_HDA_UTILS_INTEL_AUDIO_DSP_IPC_H_