From b3bd4c2db39135cfec2c276665bfea37807a2671 Mon Sep 17 00:00:00 2001 From: Aditya Rathi Date: Tue, 4 Aug 2026 16:32:30 +0530 Subject: [PATCH 1/2] platform: module: nxp: Add NXP SAI hardware endpoint sink module AudioReach on the NXP i.MX8MP EVK target needs a CAPI endpoint that drives the SAI/SDMA hardware directly through the Zephyr DAI/DMA interfaces used on this platform. Add the nxp_device_sink module under fwk/platform/modules/nxp with its CAPI implementation, endpoint APIs, and build files. Wire it into the module build via a new NXP_DEVICE_SINK Kconfig option and register the nxp subdirectory in the platform modules CMake build so the module is compiled when the option is enabled. Signed-off-by: Aditya Rathi --- fwk/platform/modules/Kconfig | 4 + fwk/platform/modules/build/CMakeLists.txt | 1 + fwk/platform/modules/nxp/build/CMakeLists.txt | 13 + .../nxp/endpoint/api/hw_intf_cmn_api.h | 507 +++++++++++ .../modules/nxp/endpoint/api/nxp_device_api.h | 69 ++ .../modules/nxp/endpoint/build/CMakeLists.txt | 34 + .../nxp/endpoint/capi/inc/capi_nxp_device.h | 39 + .../nxp/endpoint/capi/src/capi_nxp_device.c | 565 ++++++++++++ .../nxp/endpoint/capi/src/capi_nxp_device_i.h | 233 +++++ .../endpoint/capi/src/capi_nxp_device_utils.c | 848 ++++++++++++++++++ 10 files changed, 2313 insertions(+) create mode 100644 fwk/platform/modules/nxp/build/CMakeLists.txt create mode 100644 fwk/platform/modules/nxp/endpoint/api/hw_intf_cmn_api.h create mode 100644 fwk/platform/modules/nxp/endpoint/api/nxp_device_api.h create mode 100644 fwk/platform/modules/nxp/endpoint/build/CMakeLists.txt create mode 100644 fwk/platform/modules/nxp/endpoint/capi/inc/capi_nxp_device.h create mode 100644 fwk/platform/modules/nxp/endpoint/capi/src/capi_nxp_device.c create mode 100644 fwk/platform/modules/nxp/endpoint/capi/src/capi_nxp_device_i.h create mode 100644 fwk/platform/modules/nxp/endpoint/capi/src/capi_nxp_device_utils.c diff --git a/fwk/platform/modules/Kconfig b/fwk/platform/modules/Kconfig index 6c8f3724..d2d17baa 100644 --- a/fwk/platform/modules/Kconfig +++ b/fwk/platform/modules/Kconfig @@ -8,4 +8,8 @@ config ALSA_DEVICE_SOURCE tristate "Enable ALSA_DEVICE_SOURCE Library" default y +config NXP_DEVICE_SINK + tristate "Enable NXP_DEVICE_SINK Library" + default n + endmenu diff --git a/fwk/platform/modules/build/CMakeLists.txt b/fwk/platform/modules/build/CMakeLists.txt index a07c7a9c..76e6ca8e 100644 --- a/fwk/platform/modules/build/CMakeLists.txt +++ b/fwk/platform/modules/build/CMakeLists.txt @@ -17,3 +17,4 @@ include_directories( #Add the sub directories add_subdirectory(../generic/build generic) +add_subdirectory(../nxp/build nxp) diff --git a/fwk/platform/modules/nxp/build/CMakeLists.txt b/fwk/platform/modules/nxp/build/CMakeLists.txt new file mode 100644 index 00000000..daa3f3c1 --- /dev/null +++ b/fwk/platform/modules/nxp/build/CMakeLists.txt @@ -0,0 +1,13 @@ +#[[ + @file CMakeLists.txt + + @brief +]] +cmake_minimum_required(VERSION 3.10) + +#Include directories +include_directories( + ) + +#Add the sub directories +add_subdirectory(../endpoint/build endpoint) diff --git a/fwk/platform/modules/nxp/endpoint/api/hw_intf_cmn_api.h b/fwk/platform/modules/nxp/endpoint/api/hw_intf_cmn_api.h new file mode 100644 index 00000000..c2b5a087 --- /dev/null +++ b/fwk/platform/modules/nxp/endpoint/api/hw_intf_cmn_api.h @@ -0,0 +1,507 @@ +#ifndef HW_INTF_CMN_API +#define HW_INTF_CMN_API +/** + * \file hw_intf_cmn_api.h + * \brief + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "module_cmn_api.h" +#include "imcl_fwk_intent_api.h" + +/** @addtogroup ar_spf_mod_hwep_common_mods + These APIs are used by all hardware endpoint modules such as I2S and PCM + TDM. +*/ + +/*------------------------------------------------------------------------------ + Parameters +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ + +/** @ingroup ar_spf_mod_hwep_common_macros + Frame size in milliseconds (inclusive). */ +#define FRAME_SIZE_FACTOR_1 1 + +/** @ingroup ar_spf_mod_hwep_common_macros + Minimum size of the frame in milliseconds. */ +#define FRAME_SIZE_MIN_MS 1 + +/** @ingroup ar_spf_mod_hwep_common_macros + Maximum size of the frame in milliseconds. */ +#define FRAME_SIZE_MAX_MS 40 + +/** @ingroup ar_spf_mod_hwep_common_mods + Valid types of Low-Power Audio Interfaces (LPAIFs). +*/ +typedef enum /** @cond */ lpaif_type_t /** @endcond */ +{ + LPAIF = 0, /**< */ + LPAIF_RXTX = 1, /**< */ + LPAIF_WSA = 2, /**< */ + LPAIF_VA = 3, /**< */ + LPAIF_AXI = 4, /**< */ + LPAIF_AUD = 5, /**< */ + LPAIF_SDR = 6, /**< */ + LPAIF_WSA2 = 7, /**< */ + MAX_NUM_LPAIF_TYPES, /**< */ + LPAIF_BLK_INVALID = 0x7FFFFFFF /**< */ +} lpaif_type_t ; + +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @ingroup ar_spf_mod_hwep_common_mods + ID of the parameter used to configure the hardware endpoint media format. */ +#define PARAM_ID_HW_EP_MF_CFG 0x08001017 + +/*# @h2xmlp_parameter {"PARAM_ID_HW_EP_MF_CFG", PARAM_ID_HW_EP_MF_CFG} + @h2xmlp_description {ID for the parameter used to configure the hardware + endpoint media format.} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_hwep_common_mods + Payload of the #PARAM_ID_HW_EP_MF_CFG parameter. +*/ +#include "spf_begin_pack.h" +struct param_id_hw_ep_mf_t +{ + uint32_t sample_rate; + /**< Defines the sampling rate of the interface. + + @values 8, 11.025, 12, 16, 22.05, 24,32, 44.1, 48, 88.2, 96, 176.4, + 192, 352.8, 384 kHz */ + + /*#< @h2xmle_description {Defines the sampling rate of the interface.} + @h2xmle_rangeList {"8 kHz"=8000; + "11.025 kHz"=11025; + "12 kHz"=12000; + "16 kHz"=16000; + "22.05 kHz"=22050; + "24 kHz"=24000; + "32 kHz"=32000; + "44.1 kHz"=44100; + "48 kHz"=48000; + "88.2 kHz"=88200; + "96 kHz"=96000; + "176.4 kHz"=176400; + "192 kHz"=192000; + "352.8 kHz"=352800; + "384 kHz"=384000} + @h2xmle_default {48000} */ + + uint16_t bit_width; + /**< Bit width in bits per sample. + + @valuesbul + - #BIT_WIDTH_16 + - #BIT_WIDTH_24 + - #BIT_WIDTH_32 @tablebulletend*/ + + /*#< @h2xmle_description {Bit width in bits per sample.} + @h2xmle_rangeList {"BIT_WIDTH_16"=16; + "BIT_WIDTH_24"=24; + "BIT_WIDTH_32"=32} + @h2xmle_default {16} */ + + uint16_t num_channels; + /**< Number of channels. + + @values 1 through 32 (Default = 1) */ + + /*#< @h2xmle_description {Number of channels.} + @h2xmle_range {1..32} + @h2xmle_default {1} */ + + uint32_t data_format; + /**< Format of the data. + + @valuesbul + - #DATA_FORMAT_FIXED_POINT (Default) + - #DATA_FORMAT_IEC61937_PACKETIZED + - #DATA_FORMAT_IEC60958_PACKETIZED + - #DATA_FORMAT_IEC60958_PACKETIZED_NON_LINEAR + - #DATA_FORMAT_DSD_OVER_PCM + - #DATA_FORMAT_GENERIC_COMPRESSED + - #DATA_FORMAT_RAW_COMPRESSED + - #DATA_FORMAT_COMPR_OVER_PCM_PACKETIZED @tablebulletend */ + + /*#< @h2xmle_description {Format of the data.} + @h2xmle_rangeList {"DATA_FORMAT_FIXED_POINT"=1; + "DATA_FORMAT_IEC61937_PACKETIZED"=2; + "DATA_FORMAT_IEC60958_PACKETIZED"=3; + "DATA_FORMAT_IEC60958_PACKETIZED_NON_LINEAR"= 8; + "DATA_FORMAT_DSD_OVER_PCM"=4; + "DATA_FORMAT_GENERIC_COMPRESSED"=5; + "DATA_FORMAT_RAW_COMPRESSED"=6; + "DATA_FORMAT_COMPR_OVER_PCM_PACKETIZED"= 7} + @h2xmle_default {1} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_hw_ep_mf_t param_id_hw_ep_mf_t; + + +/** @ingroup ar_spf_mod_hwep_common_mods + Identifier for the parameter that configures the operating frame size. + + @msgpayload + param_id_frame_size_factor_t +*/ +#define PARAM_ID_HW_EP_FRAME_SIZE_FACTOR 0x08001018 + +/*# @h2xmlp_parameter {"PARAM_ID_HW_EP_FRAME_SIZE_FACTOR", + PARAM_ID_HW_EP_FRAME_SIZE_FACTOR} + @h2xmlp_description {ID for the parameter that configures the operating + frame size.} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_hwep_common_mods + Payload of the #PARAM_ID_HW_EP_FRAME_SIZE_FACTOR parameter. + */ +#include "spf_begin_pack.h" +struct param_id_frame_size_factor_t +{ + uint32_t frame_size_factor; + /**< Frame size factor used to derive the operating frame size. + + @values 1 through 40 samples per channel (Default = 1) */ + + /*#< @h2xmle_description {Frame size factor used to derive the operating + frame size (in number of samples per channel).} + @h2xmle_range {1..40} + @h2xmle_default {1} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_frame_size_factor_t param_id_frame_size_factor_t; + + +/** @ingroup ar_spf_mod_hwep_common_mods + Identifier for the parameter that configures the power mode (XO shutdown). + + @msgpayload + param_id_hw_ep_power_mode_cfg_t +*/ +#define PARAM_ID_HW_EP_POWER_MODE_CFG 0x08001176 + +/*# @h2xmlp_parameter {"PARAM_ID_HW_EP_POWER_MODE_CFG", + PARAM_ID_HW_EP_POWER_MODE_CFG} + @h2xmlp_description {Configures the power mode (XO shutdown).} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_hwep_common_macros + Default mode where the endpoint is not in the low-power island (LPI). */ +#define POWER_MODE_0 0 + +/** @ingroup ar_spf_mod_hwep_common_macros + XO shutdown (deep sleep) is allowed, all LPM's allowed. */ +#define POWER_MODE_1 1 + +/** @ingroup ar_spf_mod_hwep_common_macros + XO shutdown not allowed, LPM+ modes disabled */ +#define POWER_MODE_2 2 + +/** @ingroup ar_spf_mod_hwep_common_macros + XO shutdown is allowed, LPM+ modes disabled */ +#define POWER_MODE_3 3 + +/** @ingroup ar_spf_mod_hwep_common_macros + Maximum number of power modes. */ +#define HW_EP_POWER_MODE_MAX AR_NON_GUID(POWER_MODE_3) + +/** @ingroup ar_spf_mod_hwep_common_mods + Payload of the #PARAM_ID_HW_EP_POWER_MODE_CFG parameter. + */ +#include "spf_begin_pack.h" +struct param_id_hw_ep_power_mode_cfg_t +{ + uint32_t power_mode; + /**< Indicates the sleep latency XO mode vote in a low-power scenario. + + @valuesbul + - #POWER_MODE_0 (Default) + - #POWER_MODE_1 + - #POWER_MODE_2 + - #POWER_MODE_3 @tablebulletend */ + + /*#< @h2xmle_description {Indicates the sleep latency XO mode vote in a + low-power scenario.} + @h2xmle_default {POWER_MODE_0} + @h2xmle_rangeList {"POWER_MODE_0"=POWER_MODE_0; + "POWER_MODE_1"=POWER_MODE_1; + "POWER_MODE_2"=POWER_MODE_2; + "POWER_MODE_3"=POWER_MODE_3} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_hw_ep_power_mode_cfg_t param_id_hw_ep_power_mode_cfg_t; + +/*********************************** HW EP Timestamp Propagation enable ******************************/ +/** @ingroup ar_spf_mod_hwep_common_mods + Identifier for the parameter that enable/disable the timestamp propagation. + + @msgpayload + param_id_hw_ep_timestamp_propagation_t +*/ +#define PARAM_ID_HW_EP_TIMESTAMP_PROPAGATION 0x08001A7E + +/*# @h2xmlp_parameter {"PARAM_ID_HW_EP_TIMESTAMP_PROPAGATION", + PARAM_ID_HW_EP_TIMESTAMP_PROPAGATION} + @h2xmlp_description {Identifier for the parameter that enable/disable + the timestamp propagation.} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_hwep_common_macros + Mode where the timstamp propagation is disabled. */ +#define TIMESTAMP_PROPAGATION_DISABLE 1 + +/** @ingroup ar_spf_mod_hwep_common_macros + Default mode where the timstamp propagation is enabled. */ +#define TIMESTAMP_PROPAGATION_ENABLE 0 +/** @ingroup ar_spf_mod_hwep_common_mods + Payload of the #PARAM_ID_HW_EP_TIMESTAMP_PROPAGATION parameter. */ + +#include "spf_begin_pack.h" +struct param_id_hw_ep_timestamp_propagation_t +{ + uint32_t is_timestamp_disabled; + /**< Indicates that the timestamp propagation is disabled or not. + + @valuesbul + - #TIMESTAMP_PROPAGATION_DISABLE + - #TIMESTAMP_PROPAGATION_ENABLE (Default) @tablebulletend */ + + /*#< @h2xmle_description {Indicates the timestamp propagation is disabled or not.} + @h2xmle_default {TIMESTAMP_PROPAGATION_ENABLE} + @h2xmle_rangeList {"TIMESTAMP_PROPAGATION_DISABLE"=TIMESTAMP_PROPAGATION_DISABLE; + "TIMESTAMP_PROPAGATION_ENABLE"=TIMESTAMP_PROPAGATION_ENABLE} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_hw_ep_timestamp_propagation_t param_id_hw_ep_timestamp_propagation_t; + + +/*********************************** HW EP Interleaving ******************************/ + +/** @ingroup ar_spf_mod_hwep_common_mods + Identifier for the parameter that configures data interleaving for + the HW EP Source interface. + + @msgpayload + param_id_hw_ep_data_interleaving_t +*/ +#define PARAM_ID_HW_EP_SRC_OUT_DATA_INTERLEAVING 0x08001A7F + +/*# @h2xmlp_parameter {"PARAM_ID_HW_EP_SRC_OUT_DATA_INTERLEAVING", + PARAM_ID_HW_EP_SRC_OUT_DATA_INTERLEAVING} + @h2xmlp_description {ID for the parameter that configures the data + interleaving for the HW EP Module.} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_hwep_common_macros + Mode to configure the data interleaving as interleaved. */ +#define DATA_INTERLEAVED 0 + +/** @ingroup ar_spf_mod_hwep_common_macros + Mode to configure the data interleaving as deinterleaved packed. */ +#define DATA_DEINTERLEAVED_PACKED 1 + +/** @ingroup ar_spf_mod_hwep_common_macros + Default mode to configure the data interleaving as deinterleaved unpacked. */ +#define DATA_DEINTERLEAVED_UNPACKED 2 + +/** @ingroup ar_spf_mod_hwep_common_macros + Mode to configure the data interleaving as invalid. */ +#define DATA_INVALID_INTERLEAVING 3 + +/** @ingroup ar_spf_mod_hwep_common_mods + Payload of the #PARAM_ID_HW_EP_SRC_OUT_DATA_INTERLEAVING parameter. */ + +#include "spf_begin_pack.h" +struct param_id_hw_ep_data_interleaving_t +{ + uint32_t data_interleaving; + /**< Indicates the data interleaving supported by the HW Endpoint Module. + + @valuesbul + - #DATA_INTERLEAVED + - #DATA_DEINTERLEAVED_PACKED + - #DATA_DEINTERLEAVED_UNPACKED (Default) + - #DATA_INVALID_INTERLEAVING @tablebulletend */ + + /*#< @h2xmle_description {Indicates the data interleaving supported by the + HW EP module.} + @h2xmle_default {DATA_DEINTERLEAVED_UNPACKED} + @h2xmle_rangeList {"DATA_INTERLEAVED"=DATA_INTERLEAVED; + "DATA_DEINTERLEAVED_PACKED"=DATA_DEINTERLEAVED_PACKED; + "DATA_DEINTERLEAVED_UNPACKED"=DATA_DEINTERLEAVED_UNPACKED; + "DATA_INVALID_INTERLEAVING"=DATA_INVALID_INTERLEAVING} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_hw_ep_data_interleaving_t param_id_hw_ep_data_interleaving_t; + +/*********************************** HW EP Source Custom Channel Map ******************************/ + +/** @ingroup ar_spf_mod_hwep_common_mods + Identifier for the parameter that configures custom channel maps for the + hardware endpoint source modules. + + @msgpayload + param_id_hw_ep_src_channel_map_t + */ +#define PARAM_ID_HW_EP_SRC_CHANNEL_MAP 0x0800108A + +/*# @h2xmlp_parameter {"PARAM_ID_HW_EP_SRC_CHANNEL_MAP", + PARAM_ID_HW_EP_SRC_CHANNEL_MAP} + @h2xmlp_description {ID for the parameter that configures custom channel + maps for the hardware EP source.} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_hwep_common_mods + Payload of the #PARAM_ID_HW_EP_SRC_CHANNEL_MAP parameter. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_hw_ep_src_channel_map_t +{ + uint16_t num_channels; + /**< Number of channels in the array. + + @values 0 through 16 (Default = 0) */ + + /*#< @h2xmle_description {Number of channels} + @h2xmle_default {0} + @h2xmle_range {0..16} + @h2xmle_policy {Basic} */ + +#if defined(__H2XML__) + uint16_t channel_mapping[0]; + /**< Array of channel mappings of size num_channels. + + @values PCM_CUSTOM_CHANNEL_MAP_1 (Default) through + PCM_CUSTOM_CHANNEL_MAP_16 (see #pcm_channel_map) + + Each element i of the array describes channel i in the buffer, where i + is less than num_channels. An unused channel is set to 0. + + Each channel that is used should be between the values of 48 and 63. + @newpagetable */ + + /*#< @h2xmle_description {Channel mapping array of size num_channels. Each + element i of the array describes channel i + in the buffer, where i is less than + num_channels. An unused channel is set to + 0. Each channel that is used should be + between the values of 48 and 63.} + @h2xmle_rangeList {"PCM_CUSTOM_CHANNEL_MAP_1"=PCM_CUSTOM_CHANNEL_MAP_1, + "PCM_CUSTOM_CHANNEL_MAP_2"=PCM_CUSTOM_CHANNEL_MAP_2, + "PCM_CUSTOM_CHANNEL_MAP_3"=PCM_CUSTOM_CHANNEL_MAP_3, + "PCM_CUSTOM_CHANNEL_MAP_4"=PCM_CUSTOM_CHANNEL_MAP_4, + "PCM_CUSTOM_CHANNEL_MAP_5"=PCM_CUSTOM_CHANNEL_MAP_5, + "PCM_CUSTOM_CHANNEL_MAP_6"=PCM_CUSTOM_CHANNEL_MAP_6, + "PCM_CUSTOM_CHANNEL_MAP_7"=PCM_CUSTOM_CHANNEL_MAP_7, + "PCM_CUSTOM_CHANNEL_MAP_8"=PCM_CUSTOM_CHANNEL_MAP_8, + "PCM_CUSTOM_CHANNEL_MAP_9"=PCM_CUSTOM_CHANNEL_MAP_9, + "PCM_CUSTOM_CHANNEL_MAP_10"=PCM_CUSTOM_CHANNEL_MAP_10, + "PCM_CUSTOM_CHANNEL_MAP_11"=PCM_CUSTOM_CHANNEL_MAP_11, + "PCM_CUSTOM_CHANNEL_MAP_12"=PCM_CUSTOM_CHANNEL_MAP_12, + "PCM_CUSTOM_CHANNEL_MAP_13"=PCM_CUSTOM_CHANNEL_MAP_13, + "PCM_CUSTOM_CHANNEL_MAP_14"=PCM_CUSTOM_CHANNEL_MAP_14, + "PCM_CUSTOM_CHANNEL_MAP_15"=PCM_CUSTOM_CHANNEL_MAP_15, + "PCM_CUSTOM_CHANNEL_MAP_16"=PCM_CUSTOM_CHANNEL_MAP_16} + @h2xmle_default {PCM_CUSTOM_CHANNEL_MAP_1} + @h2xmle_variableArraySize {"num_channels"} + @h2xmle_policy {Basic} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct param_id_hw_ep_src_channel_map_t param_id_hw_ep_src_channel_map_t; + + +/** @ingroup ar_spf_mod_hwep_common_mods + Identifier for the parameter that configures DMA data alignment for the + Codec DMA interface. + + @msgpayload + param_id_hw_ep_dma_data_align_t +*/ +#define PARAM_ID_HW_EP_DMA_DATA_ALIGN 0x08001233 + +/*# @h2xmlp_parameter {"PARAM_ID_HW_EP_DMA_DATA_ALIGN", + PARAM_ID_HW_EP_DMA_DATA_ALIGN} + @h2xmlp_description {ID for the parameter that configures DMA data + alignment for the Codec DMA interface.} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_hwep_common_macros + DMA data is aligned to the most significant bit (MSB). */ +#define DMA_DATA_ALIGN_MSB 0 + +/** @ingroup ar_spf_mod_hwep_common_macros + DMA data is aligned to the least significant bit (LSB). */ +#define DMA_DATA_ALIGN_LSB 1 + +/** @ingroup ar_spf_mod_hwep_common_mods + Payload of the #PARAM_ID_HW_EP_DMA_DATA_ALIGN parameter. + */ +#include "spf_begin_pack.h" +struct param_id_hw_ep_dma_data_align_t +{ + uint32_t dma_data_align; + /**< Indicates the data alignment in the DMA buffer. + + @valuesbul + - #DMA_DATA_ALIGN_MSB (Default) + - #DMA_DATA_ALIGN_LSB @tablebulletend */ + + /*#< @h2xmle_description {Indicates the data alignment in the DMA buffer.} + @h2xmle_rangeList {"DMA_DATA_ALIGN_MSB"=0; + "DMA_DATA_ALIGN_LSB"=1} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_hw_ep_dma_data_align_t param_id_hw_ep_dma_data_align_t; + +/** @ingroup ar_spf_mod_hwep_common_mods + * Identifier for the parameter that configures H.W delay + * for hardware interfaces. + + @msgpayload + param_id_hw_delay_t +*/ +#define PARAM_ID_HW_DELAY 0x080013D5 + +/*# @h2xmlp_parameter {"PARAM_ID_HW_DELAY", + PARAM_ID_HW_DELAY} + @h2xmlp_description {ID for the parameter that configures H.W delay + for hardware interfaces.} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_hwep_common_mods + Payload of the #PARAM_ID_HW_DELAY parameter. + */ +#include "spf_begin_pack.h" +struct param_id_hw_delay_t +{ + uint32_t hw_delay_us; + /**< Indicates the H.W delay in micro seconds. */ + + /*#< @h2xmle_description {Indicates the H.W delay in micro seconds.} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_hw_delay_t param_id_hw_delay_t; + +#endif /* HW_INTF_CMN_API */ diff --git a/fwk/platform/modules/nxp/endpoint/api/nxp_device_api.h b/fwk/platform/modules/nxp/endpoint/api/nxp_device_api.h new file mode 100644 index 00000000..d1f9b08a --- /dev/null +++ b/fwk/platform/modules/nxp/endpoint/api/nxp_device_api.h @@ -0,0 +1,69 @@ +#ifndef NXP_DEVICE_API_H +#define NXP_DEVICE_API_H +/** + * \file nxp_device_api.h + * + * \brief nxp_device_api.h: This file contains the Module Id, Param IDs and + * configuration structures exposed by the NXP Device Sink and Source Modules. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "hw_intf_cmn_api.h" + + /** @h2xml_title1 {NXP Device API} + @h2xml_title_agile_rev {NXP Device API} + @h2xml_title_date {June 10, 2026} */ + +/*============================================================================== + Constants +==============================================================================*/ + +/** @ingroup ar_spf_NXP_device_macros + Input port ID of NXP Device module */ +#define PORT_ID_NXP_DEVICE_INPUT 0x2 + +/** @ingroup ar_spf_NXP_device_macros + Output port ID of NXP Device module */ +#define PORT_ID_NXP_DEVICE_OUTPUT 0x1 + +#define NXP_DEVICE_STACK_SIZE 2048 + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + +#define MODULE_ID_NXP_DEVICE_SINK 0x0700109C + +/** @h2xmlm_module {"MODULE_ID_NXP_DEVICE_SINK", + MODULE_ID_NXP_DEVICE_SINK} + @h2xmlm_displayName {"NXP Device"} + @h2xmlm_modSearchKeys{hardware} + @h2xmlm_description {NXP_DEVICE Sink Module\n + - Supports following params: + - PARAM_ID_HW_EP_MF_CFG \n + - PARAM_ID_HW_EP_FRAME_SIZE_FACTOR \n + - Supported Input Media Format: \n + - Data Format : FIXED_POINT \n + - fmt_id : Don't care \n + - Sample Rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, \n + - 88.2, 96, 176.4, 192, 352.8, 384 kHz \n + - Number of channels : 1 to 8 \n + - Channel type : Don't care \n + - Bit Width : 16 (bits per sample 16 and Q15), \n + - : 24 (bits per sample 24 and Q27) \n + - : 32 (bits per sample 32 and Q31) \n + - Q format : Q15, Q27, Q31 \n + - Interleaving : ? } + @h2xmlm_dataInputPorts {IN = PORT_ID_NXP_DEVICE_INPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {0} + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { NXP_DEVICE_STACK_SIZE } + @{ <-- Start of the Module --> + @} <-- End of the Module -->*/ + +#endif /* NXP_DEVICE_API_H */ \ No newline at end of file diff --git a/fwk/platform/modules/nxp/endpoint/build/CMakeLists.txt b/fwk/platform/modules/nxp/endpoint/build/CMakeLists.txt new file mode 100644 index 00000000..984d6b14 --- /dev/null +++ b/fwk/platform/modules/nxp/endpoint/build/CMakeLists.txt @@ -0,0 +1,34 @@ +#[[ + @file CMakeLists.txt + + @brief +]] + +cmake_minimum_required(VERSION 3.10) + +set(nxp_device_sources + ${LIB_ROOT}/capi/src/capi_nxp_device_utils.c + ${LIB_ROOT}/capi/src/capi_nxp_device.c +) + +set(nxp_device_includes + ${LIB_ROOT}/api + ${LIB_ROOT}/capi/inc + ${LIB_ROOT}/capi/src +) + +spf_module_sources( + KCONFIG CONFIG_NXP_DEVICE_SINK + NAME nxp_device_sink + MAJOR_VER 1 + MINOR_VER 0 + AMDB_ITYPE "capi" + AMDB_MTYPE "end_point" + AMDB_MID "0x0700109C" + AMDB_TAG "capi_nxp_device_sink" + AMDB_MOD_NAME "MODULE_ID_NXP_DEVICE_SINK" + SRCS ${nxp_device_sources} + INCLUDES ${nxp_device_includes} + H2XML_HEADERS "${LIB_ROOT}api/nxp_device_api.h" + CFLAGS "-Wno-address-of-packed-member" +) diff --git a/fwk/platform/modules/nxp/endpoint/capi/inc/capi_nxp_device.h b/fwk/platform/modules/nxp/endpoint/capi/inc/capi_nxp_device.h new file mode 100644 index 00000000..2c23463b --- /dev/null +++ b/fwk/platform/modules/nxp/endpoint/capi/inc/capi_nxp_device.h @@ -0,0 +1,39 @@ +/* ======================================================================== */ +/** + @file capi_nxp_device.h + @brief This file contains CAPI API's published by nxp device module. + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef CAPI_NXP_DEVICE_H +#define CAPI_NXP_DEVICE_H + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "capi.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/*------------------------------------------------------------------------ + * Function declarations + * ----------------------------------------------------------------------*/ + +capi_err_t capi_nxp_device_sink_init( + capi_t *_pif, + capi_proplist_t *init_set_properties); + +capi_err_t capi_nxp_device_sink_get_static_properties( + capi_proplist_t *init_set_properties, + capi_proplist_t *static_properties); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif // CAPI_NXP_DEVICE_H \ No newline at end of file diff --git a/fwk/platform/modules/nxp/endpoint/capi/src/capi_nxp_device.c b/fwk/platform/modules/nxp/endpoint/capi/src/capi_nxp_device.c new file mode 100644 index 00000000..c0e5597b --- /dev/null +++ b/fwk/platform/modules/nxp/endpoint/capi/src/capi_nxp_device.c @@ -0,0 +1,565 @@ +/* ======================================================================== + @file capi_nxp_device.c + @brief This file contains CAPI implementation of nxp device Module + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +/*===================================================================== + Includes + ======================================================================*/ +#include "capi_nxp_device_i.h" + +/*------------------------------------------------------------------------ + Function name: capi_nxp_device_sink_init + DESCRIPTION: Initialize the CAPIv2 nxp_device sink module and library. + This function can allocate memory. + -----------------------------------------------------------------------*/ +capi_err_t capi_nxp_device_sink_init( + capi_t *_pif, + capi_proplist_t *init_set_properties) +{ + //AR_MSG(DBG_ERROR_PRIO, + // "CAPI_NXP_DEVICE: Init enter"); + return capi_nxp_device_common_init(_pif, init_set_properties, 1); +} + +capi_err_t capi_nxp_device_sink_get_static_properties( + capi_proplist_t *init_set_properties, + capi_proplist_t *static_properties) +{ + return capi_nxp_device_process_get_properties((capi_nxp_device_t *)NULL, static_properties); +} + +/*--------------------------------------------------------------------- + Function name: capi_nxp_device_process + DESCRIPTION: Processes an input buffer and generates an output buffer. + -----------------------------------------------------------------------*/ +capi_err_t capi_nxp_device_process(capi_t *_pif, + capi_stream_data_t *input[], + capi_stream_data_t *output[]) +{ + capi_err_t result = CAPI_EOK; + capi_nxp_device_t *me_ptr = (capi_nxp_device_t *)_pif; + + if (me_ptr->direction == 0) + { + result |= capi_nxp_device_process_sink(_pif, input, output); + } + return result; +} + +/*------------------------------------------------------------------------ + Function name: capi_nxp_device_get_mf + DESCRIPTION: Function to get nxp device media fmt + * -----------------------------------------------------------------------*/ +static capi_err_t capi_nxp_device_get_mf(capi_nxp_device_t *me_ptr, capi_media_fmt_v2_t *media_fmt_ptr) +{ + + return CAPI_EOK; +} + +static capi_vtbl_t vtbl = {capi_nxp_device_process, capi_nxp_device_end, + capi_nxp_device_set_param, capi_nxp_device_get_param, + capi_nxp_device_set_properties, capi_nxp_device_get_properties}; + +capi_vtbl_t *capi_nxp_device_get_vtbl() +{ + return &vtbl; +} + +/*------------------------------------------------------------------------ + Function name: capi_nxp_device_get_param + DESCRIPTION: Gets either a parameter value or a parameter structure + containing multiple parameters. In the event of a failure, the appropriate + error code is returned. + * -----------------------------------------------------------------------*/ +capi_err_t capi_nxp_device_get_param(capi_t *_pif, + uint32_t param_id, + const capi_port_info_t *port_info_ptr, + capi_buf_t *params_ptr) +{ + capi_err_t capi_result = CAPI_EOK; + + if ((NULL == _pif) || (NULL == params_ptr) || (NULL == params_ptr->data_ptr)) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Get param received bad pointer, 0x%p, 0x%p", _pif, params_ptr); + return CAPI_EBADPARAM; + } + + capi_nxp_device_t *me_ptr = (capi_nxp_device_t *)_pif; + switch (param_id) + { + case FWK_EXTN_PARAM_ID_LATEST_TRIGGER_TIMESTAMP_PTR: + { + //capi_result = capi_cmn_populate_trigger_ts_payload(params_ptr, + // &me_ptr->drift_info.drift_calc_status.curr_intr_ts, + // capi_hw_intf_cmn_update_ts, + // (void *)(&me_ptr->hw_intf_ts_prop_cfg)); + params_ptr->data_ptr = NULL; + break; + } + case PARAM_ID_HW_EP_MF_CFG: + { + param_id_hw_ep_mf_t *i2s_cfg_ptr = (param_id_hw_ep_mf_t *)params_ptr->data_ptr; + i2s_cfg_ptr->bit_width = 16; + i2s_cfg_ptr->num_channels = 1; + i2s_cfg_ptr->sample_rate = 48000; + i2s_cfg_ptr->data_format = DATA_FORMAT_FIXED_POINT; + + break; + } + /*case PARAM_ID_I2S_INTF_CFG: + { + param_id_i2s_intf_cfg_t *i2s_cfg_ptr = (param_id_i2s_intf_cfg_t *)params_ptr->data_ptr; + i2s_cfg_ptr->intf_idx = 0; + i2s_cfg_ptr->sd_line_idx = I2S_SD0; + i2s_cfg_ptr->ws_src = 0; + + break; + }*/ + default: { + AR_MSG(DBG_ERROR_PRIO, "unsupported get param ID 0x%x", (int)param_id); + CAPI_SET_ERROR(capi_result, CAPI_EUNSUPPORTED); + break; + } + } + + return capi_result; +} + +/*------------------------------------------------------------------------ + Function name: capi_nxp_device_set_param + DESCRIPTION: Sets either a parameter value or a parameter structure containing + multiple parameters. In the event of a failure, the appropriate error code is + returned. + -----------------------------------------------------------------------*/ +capi_err_t capi_nxp_device_set_param(capi_t *_pif, + uint32_t param_id, + const capi_port_info_t *port_info_ptr, + capi_buf_t *params_ptr) +{ + capi_err_t capi_result = CAPI_EOK; + + if ((NULL == _pif) || (NULL == params_ptr) || (NULL == params_ptr->data_ptr)) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_nxp_DEVICE: Get param received bad pointer, 0x%p, 0x%p", _pif, params_ptr); + return CAPI_EBADPARAM; + } + + switch (param_id) { + case PARAM_ID_HW_EP_TIMESTAMP_PROPAGATION: + { + /*if (I2S_SOURCE == me_ptr->i2s_driver.i2s_intf_state.direction) + { + if (param_size < sizeof(param_id_hw_ep_timestamp_propagation_t)) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_I2S: SetParam 0x%lx, invalid param size %lx ", + param_id, + params_ptr->actual_data_len); + capi_result = CAPI_ENEEDMORE; + break; + } + param_id_hw_ep_timestamp_propagation_t *i2s_ts_prop_cfg_ptr = + (param_id_hw_ep_timestamp_propagation_t *)params_ptr->data_ptr; + + ar_result = + capi_hw_intf_cmn_ts_prop_cfg(&me_ptr->hw_intf_ts_prop_cfg, i2s_ts_prop_cfg_ptr->is_timestamp_disabled); + + if (AR_EOK != ar_result) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_I2S: Timestamp propagation failed with 0x%lx", ar_result); + return CAPI_EFAILED; + } + AR_MSG(DBG_LOW_PRIO, + "CAPI_I2S: Timestamp propagation set param received with value [%d] (0:Enable, 1:Disable)", + i2s_ts_prop_cfg_ptr->is_timestamp_disabled); + } + else + { + capi_result |= CAPI_EUNSUPPORTED; + }*/ + break; + } + case PARAM_ID_HW_EP_SRC_OUT_DATA_INTERLEAVING: + { + /*if (I2S_SOURCE == me_ptr->i2s_driver.i2s_intf_state.direction) + { + if (param_size < sizeof(param_id_hw_ep_data_interleaving_t)) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_I2S: SetParam 0x%lx, invalid param size %lx ", + param_id, + params_ptr->actual_data_len); + capi_result = CAPI_ENEEDMORE; + break; + } + + param_id_hw_ep_data_interleaving_t *i2s_src_data_int_ptr = + (param_id_hw_ep_data_interleaving_t *)params_ptr->data_ptr; + + if ((PCM_DEINTERLEAVED_UNPACKED != i2s_src_data_int_ptr->data_interleaving) && + (PCM_INTERLEAVED != i2s_src_data_int_ptr->data_interleaving)) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_I2S: Interleaving value [%lu] not supported. ", + i2s_src_data_int_ptr->data_interleaving); + capi_result = CAPI_EBADPARAM; + break; + } + + pcm_to_capi_interleaved_with_native_param(&me_ptr->i2s_media_fmt.format.data_interleaving, + i2s_src_data_int_ptr->data_interleaving, + CAPI_INVALID_INTERLEAVING); + + if (me_ptr->i2s_driver.i2s_intf_state.ep_mf_received) + { + /*Raise media format events + capi_result |= capi_i2s_raise_media_fmt_event(me_ptr); + } + AR_MSG(DBG_LOW_PRIO, + "CAPI_I2S: Data Interleaving set param received, with int [%d]", + me_ptr->i2s_media_fmt.format.data_interleaving); + } + else + { + capi_result |= CAPI_EUNSUPPORTED; + }*/ + break; + } + case PARAM_ID_HW_EP_MF_CFG: + { + /*if (param_size < sizeof(param_id_hw_ep_mf_t)) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_I2S: SetParam 0x%lx, invalid param size %lx ", + param_id, + params_ptr->actual_data_len); + capi_result = CAPI_ENEEDMORE; + break; + } + + param_id_hw_ep_mf_t *i2s_cfg_ptr = (param_id_hw_ep_mf_t *)params_ptr->data_ptr; + + ar_result = i2s_driver_set_hw_ep_mf_cfg(i2s_cfg_ptr, &(me_ptr->i2s_driver)); + if (AR_EOK != ar_result) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_I2S: Driver set ep mf failed with 0x%lx", ar_result); + if(AR_EALREADY == ar_result) + { + return CAPI_EALREADY; + } + return CAPI_EFAILED; + } + + if (I2S_SOURCE == me_ptr->i2s_driver.i2s_intf_state.direction) + { + capi_cmn_data_fmt_map(&me_ptr->i2s_driver.i2s_intf_state.data_format, &me_ptr->i2s_media_fmt); + AR_MSG(DBG_HIGH_PRIO, "CAPI_I2S: Data format %d", me_ptr->i2s_media_fmt.header.format_header.data_format); + } + + /*Raise media format events + capi_result |= capi_i2s_raise_media_fmt_event(me_ptr); + + // threshold and algo event + capi_result |= capi_i2s_raise_thresh_delay_events(me_ptr); + if (CAPI_EOK != capi_result) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_I2S:Failed to raise output media fmt and algo delay event", ar_result); + } + + // KPPS event + uint32_t kpps = + (3 * (me_ptr->i2s_driver.i2s_intf_state.sample_rate) * (me_ptr->i2s_driver.i2s_intf_state.num_channels)) / + 640; + capi_result = capi_cmn_update_kpps_event(&me_ptr->cb_info, kpps); + + // Bandwidth event + uint32_t code_bandwidth = 0; + uint32_t data_bandwidth = me_ptr->i2s_driver.i2s_intf_state.int_samples_per_period * + me_ptr->i2s_driver.i2s_intf_state.bit_width * + me_ptr->i2s_driver.i2s_intf_state.num_channels * 2; + + capi_result = capi_cmn_update_bandwidth_event(&me_ptr->cb_info, code_bandwidth, data_bandwidth); + if (CAPI_EOK != capi_result) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_I2S: Failed to send bandwidth update event with %lu", capi_result); + }*/ + break; + } + case PARAM_ID_HW_EP_FRAME_SIZE_FACTOR: + { + /*if (param_size < sizeof(param_id_frame_size_factor_t)) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_I2S: SetParam 0x%lx, invalid param size %lu ", + param_id, + params_ptr->actual_data_len); + capi_result = CAPI_ENEEDMORE; + break; + } + param_id_frame_size_factor_t *i2s_cfg_ptr = (param_id_frame_size_factor_t *)params_ptr->data_ptr; + + ar_result = i2s_driver_set_frame_size_cfg(i2s_cfg_ptr, &(me_ptr->i2s_driver)); + if (AR_EOK != ar_result) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_I2S: Driver set param failed with 0x%lx", ar_result); + if(AR_EALREADY == ar_result) + { + return CAPI_EALREADY; + } + return CAPI_EFAILED; + } + + if (me_ptr->i2s_driver.i2s_intf_state.ep_mf_received) + { + capi_result = capi_i2s_raise_thresh_delay_events(me_ptr); + if (CAPI_EOK != capi_result) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_I2S:Failed to raise output media fmt and algo delay event", ar_result); + } + }*/ + break; + } + case PARAM_ID_HW_EP_POWER_MODE_CFG: + { + // cfg should be received before START (STM trigger) + /*if (param_size < sizeof(param_id_hw_ep_power_mode_cfg_t)) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_I2S: SetParam POWER_MODE_CFG, invalid param size %lu ", + params_ptr->actual_data_len); + capi_result = CAPI_ENEEDMORE; + break; + } + param_id_hw_ep_power_mode_cfg_t *power_cfg_ptr = (param_id_hw_ep_power_mode_cfg_t *)params_ptr->data_ptr; + + if (HW_EP_POWER_MODE_MAX < power_cfg_ptr->power_mode) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_I2S: SetParam POWER_MODE_CFG, invalid value %lu ", power_cfg_ptr->power_mode); + capi_result = CAPI_EFAILED; + break; + } + + me_ptr->pm_info.power_mode = power_cfg_ptr->power_mode; + AR_MSG(DBG_HIGH_PRIO, "Received POWER_MODE_CFG: mode %lu", power_cfg_ptr->power_mode);*/ + break; + } + case PARAM_ID_HW_EP_SRC_CHANNEL_MAP: + { + /*if (param_size < sizeof(param_id_hw_ep_src_channel_map_t)) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_I2S: SetParam HW_EP_SRC_CHANNEL_MAP, invalid param size %lu ", + params_ptr->actual_data_len); + capi_result = CAPI_ENEEDMORE; + break; + } + + if (I2S_SOURCE != me_ptr->i2s_driver.i2s_intf_state.direction) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_I2S: SetParam HW_EP_SRC_CHANNEL_MAP only supported for source modules"); + capi_result = CAPI_EBADPARAM; + break; + } + + param_id_hw_ep_src_channel_map_t *channel_cfg_ptr = (param_id_hw_ep_src_channel_map_t *)params_ptr->data_ptr; + + /* Cache channel map to driver + capi_result |= i2s_driver_set_src_channel_map_cfg(channel_cfg_ptr, &me_ptr->i2s_driver); + + /* Send output mf if mf is received, if not it will be sent later + if (me_ptr->i2s_driver.i2s_intf_state.ep_mf_received) + { + /*Raise media format events + capi_result |= capi_i2s_raise_media_fmt_event(me_ptr); + } + + AR_MSG(DBG_HIGH_PRIO, "CAPI_I2S: Received Src Channel Map Cfg");*/ + break; + } + case INTF_EXTN_PARAM_ID_IMCL_PORT_OPERATION: + { + /*if (NULL == params_ptr->data_ptr) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_I2S: Set param id 0x%lX, received null buffer", param_id); + + capi_result |= CAPI_EBADPARAM; + + break; + } + + /** Cache previous drift link state + bool_t was_ctrl_link_connected = me_ptr->ctrl_port_cfg.is_drift_link_connected ? TRUE : FALSE; + + /** Set the control port operation + if (CAPI_EOK != (capi_result = capi_hw_intf_cmn_imcl_port_operation(&me_ptr->ctrl_port_cfg, + &me_ptr->cb_info, + port_info_ptr, + params_ptr, + me_ptr->heap_mem.heap_id))) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_I2S :Failed to set control port operation, result %d", capi_result); + } + else + { + // Check if STM module is enabled + if (TRUE == me_ptr->ctrl_port_cfg.is_stm_enabled) + { + // Check is there any change in drift link connection state + if (was_ctrl_link_connected != me_ptr->ctrl_port_cfg.is_drift_link_connected) + { + /** Reset drift tracking struct + tdu_reset_drift_info(&me_ptr->drift_info); // under mutex lock + + /* Chooses intended update period + tdu_cfg_drift_cal_params(&me_ptr->drift_info, + (me_ptr->ctrl_port_cfg.is_drift_link_connected) + ? TDU_DEFAULT_DRIFT_CALC_PERIOD_US + : TDU_DRIFT_CALC_PERIOD_US_LINK_NOT_CONNECTED, + me_ptr->i2s_driver.i2s_intf_state.frame_size_us); + } + } + }*/ + break; + } + case PARAM_ID_HW_DELAY: + { + /*if (NULL == params_ptr->data_ptr) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_I2S: Set param id 0x%lX, received null buffer", param_id); + + capi_result |= CAPI_EBADPARAM; + + break; + } + + if (param_size < sizeof(param_id_hw_delay_t)) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_I2S: SetParam 0x%lx, invalid param size %lu ", + param_id, + params_ptr->actual_data_len); + capi_result = CAPI_ENEEDMORE; + break; + } + + param_id_hw_delay_t *hw_delay_cfg_ptr = (param_id_hw_delay_t *)params_ptr->data_ptr; + + me_ptr->i2s_driver.i2s_intf_state.hw_delay_us = hw_delay_cfg_ptr->hw_delay_us; + + // In case HW delay is rcvd. after M.F raise algo delay again with HW delay included. + if (me_ptr->i2s_driver.i2s_intf_state.ep_mf_received) + { + capi_result = capi_i2s_raise_thresh_delay_events(me_ptr); + if (CAPI_EOK != capi_result) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_I2S :Failed to raise output media fmt and algo delay event", capi_result); + } + } + + AR_MSG(DBG_HIGH_PRIO, + "CAPI_I2S: Received PARAM_ID_HW_DELAY with delay %d us", + hw_delay_cfg_ptr->hw_delay_us);*/ + break; + } + default: + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Set, unsupported param ID 0x%x", (int)param_id); + CAPI_SET_ERROR(capi_result, CAPI_EUNSUPPORTED); + break; + } + + } /** End of switch (param ID) */ + + return capi_result; +} + +/*------------------------------------------------------------------------ + Function name: capi_nxp_device_end + DESCRIPTION: Returns the library to the uninitialized state and frees the + memory that was allocated by init(). This function also frees the virtual + function table. + -----------------------------------------------------------------------*/ +capi_err_t capi_nxp_device_end(capi_t *_pif) +{ + capi_err_t capi_result = CAPI_EOK; + + if (NULL == _pif) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: capi_nxp_device_end received bad pointer, 0x%p", _pif); + return CAPI_EBADPARAM; + } + + capi_nxp_device_t *me_ptr = (capi_nxp_device_t *)_pif; + + capi_nxp_device_stop(me_ptr); + + capi_nxp_device_reset(me_ptr); + + return capi_result; +} + +/*------------------------------------------------------------------------ + Function name: capi_nxp_device_get_properties + DESCRIPTION: Function to get the properties for the nxp_device module + * -----------------------------------------------------------------------*/ +capi_err_t capi_nxp_device_get_properties(capi_t *_pif, + capi_proplist_t *proplist_ptr) +{ + return capi_nxp_device_process_get_properties((capi_nxp_device_t *)_pif, proplist_ptr); +} + +/*------------------------------------------------------------------------ + Function name: capi_nxp_device_set_properties + DESCRIPTION: Function to set the properties for the nxp_device module + * -----------------------------------------------------------------------*/ +capi_err_t capi_nxp_device_set_properties(capi_t *_pif, + capi_proplist_t *proplist_ptr) +{ + return capi_nxp_device_process_set_properties((capi_nxp_device_t *)_pif, proplist_ptr); +} + + +/*--------------------------------------------------------------------- + Function name: capi_nxp_device_update_dataflow_state + DESCRIPTION: . + -----------------------------------------------------------------------*/ +bool_t capi_nxp_device_update_dataflow_state(capi_stream_data_t *input, nxp_device_data_flow_state *data_flow_state, bool is_data_valid) +{ + bool_t is_not_steady_state = TRUE; + if (input && (TRUE == input->flags.marker_eos)) + { + *data_flow_state = DF_STOPPING; + } + else if (input && input->buf_ptr[0].data_ptr && is_data_valid) + { + *data_flow_state = DF_STARTED; + is_not_steady_state = FALSE; + } + else if (*data_flow_state == DF_STOPPING) + { + *data_flow_state = DF_STOPPED; + } + return is_not_steady_state; +} + +/*--------------------------------------------------------------------- + Function name: capi_nxp_device_check_data_sufficiency + DESCRIPTION: . + -----------------------------------------------------------------------*/ +bool_t capi_nxp_device_check_data_sufficiency(capi_stream_data_t *input, + capi_buf_t * scratch_buf, + uint32_t total_bytes, + bool_t packetized, + bool_t is_capi_in_media_fmt_set, + uint32_t expected_data_len, + uint16_t num_channels, + bool_t * need_to_underrun) +{ + bool_t is_data_valid = TRUE; + + return is_data_valid; +} diff --git a/fwk/platform/modules/nxp/endpoint/capi/src/capi_nxp_device_i.h b/fwk/platform/modules/nxp/endpoint/capi/src/capi_nxp_device_i.h new file mode 100644 index 00000000..6c590270 --- /dev/null +++ b/fwk/platform/modules/nxp/endpoint/capi/src/capi_nxp_device_i.h @@ -0,0 +1,233 @@ +/* ======================================================================== + @file capi_nxp_device_i.h + @brief This file contains CAPI includes of nxp Device Module + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef _CAPI_NXP_DEVICE_I_H +#define _CAPI_NXP_DEVICE_I_H + +/*===================================================================== + Includes + ======================================================================*/ +#include "capi_nxp_device.h" +#include "nxp_device_api.h" +#include "capi_cmn.h" +#include +#include +#include +#include +#include + +/*===================================================================== + Macros + ======================================================================*/ +#ifndef SIZE_OF_ARRAY +#define SIZE_OF_ARRAY(a) (sizeof(a) / sizeof((a)[0])) +#endif + +#ifndef min +#define min(A,B) ((A) < (B) ? (A) : (B)) +#endif + + /* Number of CAPI Framework extension needed */ +#define NXP_DEVICE_NUM_FRAMEWORK_EXTENSIONS 1 + +/* Number of milliseconds in a second*/ +#define NUM_MS_PER_SEC 1000 + +#define ALIGN_UP(val, align) (((val) + (align) - 1) & ~((align) - 1)) + +#define DT_DRV_COMPAT nxp_dai_sai + +typedef enum nxp_device_state +{ + NXP_DEVICE_INTERFACE_STOP = 0, + NXP_DEVICE_INTERFACE_START, + NXP_DEVICE_READY +} nxp_device_interface_state_t; + +typedef enum nxp_device_data_flow_state +{ + DF_STOPPED = 0, + DF_STARTED = 1, + DF_STOPPING = 2, +}nxp_device_data_flow_state; + +typedef struct i2s_port_state +{ + // interrupt statistics + int32_t *i2s_intr_cnt_ptr; + uint32_t fifo_ovf_cnt; + uint32_t ahb_err_cnt; + + // Signal Miss config - For debugging purpose only + bool_t is_periodic_signal_miss; + uint64_t intr_count_pre; // interrupt count to introduce a pre process signal miss (cntr delay) + uint64_t intr_count_post; // interrupt count to introduce a post process signal miss (module proc delay) + + //dma_device_handle dma_dev_hdl; + + // callback signal ptr for the interrupt + void *trigger_signal_ptr; + + /* status of current trigger shared between hwep module and client + * to differentiate between data and signal triggers. + * This flag will be set in interrupt callback context to indicate + * it is a signal trigger + */ + bool_t signal_trigger_status; + + //uint32_t i2s_ctl; /* Content of I2S control status register */ + + // H.W delay in us. + //uint32_t hw_delay_us; + /* This field is used to indicate if the frame duration normalization is allowed or not. + * If the frame duration is outside the range, the frame duration will be normalized to + * the closest supported range. + + bool_t allow_frame_duration_normalization; + uint32_t min_normalized_frame_dur_us; + uint32_t max_normalized_frame_dur_us; + uint32_t normalized_num_dma_buffers;*/ +} i2s_port_state_t; + +typedef struct i2s_drv_state +{ + i2s_port_state_t i2s_intf_state; + /* Pointer to individual interface state object*/ + +} i2s_drv_state_t; + +typedef struct capi_nxp_device { + /* v-table pointer */ + capi_t vtbl; + + /* Heap id, used to allocate memory */ + capi_heap_id_t heap_mem; + + /* Call back info for event raising */ + capi_event_callback_info_t cb_info; + + //struct capi_dai_data dai_data; + + void *user_cb_data; + + i2s_drv_state_t i2s_driver; + + /* Instance ID of this module */ + uint32_t iid; + + uint32_t direction; + + uint32_t log_id; + /* Unique log ID provided by framework */ + + uint32_t log_id_reserved_mask; + /* bits reserved for this module to use from the LSB*/ + + /* pointer to scratch data buffer used in process function */ + int8_t *out_data_buffer; + + /* Size of the scratch data buffer */ + uint32_t out_data_buffer_size; + + void *dma_src_addr; /**< Buffer base address */ + + void *dma_dest_addr; //Address of DMA buffer in system heap + + uint32_t dma_buf_size; /**< Runtime buffer size in bytes (period multiple) */ + + uint32_t dma_chan_index; + + struct dma_config *z_config; + + int dai_dir; //Different from the CAPI direction + +} capi_nxp_device_t; + +struct sai_params { + uint32_t reserved0; + + /* MCLK */ + uint16_t reserved1; + uint16_t mclk_id; + uint32_t mclk_direction; + + uint32_t mclk_rate; /* MCLK frequency in Hz */ + uint32_t fsync_rate; + uint32_t bclk_rate; + + /* TDM */ + uint32_t tdm_slots; + uint32_t rx_slots; + uint32_t tx_slots; + uint16_t tdm_slot_width; + uint16_t reserved2; /* alignment */ +}; + +/*------------------------------------------------------------------------ + * VTBL function declarations + * -----------------------------------------------------------------------*/ + +capi_vtbl_t *capi_nxp_device_get_vtbl(); + +capi_err_t capi_nxp_device_process(capi_t *_pif, + capi_stream_data_t *input[], + capi_stream_data_t *output[]); + +capi_err_t capi_nxp_device_end(capi_t *_pif); + +capi_err_t capi_nxp_device_get_param(capi_t *_pif, + uint32_t param_id, + const capi_port_info_t *port_info_ptr, + capi_buf_t *params_ptr); + +capi_err_t capi_nxp_device_set_param(capi_t *_pif, + uint32_t param_id, + const capi_port_info_t *port_info_ptr, + capi_buf_t *params_ptr); + +capi_err_t capi_nxp_device_get_properties(capi_t *_pif, + capi_proplist_t *proplist_ptr); + +capi_err_t capi_nxp_device_set_properties(capi_t *_pif, + capi_proplist_t *proplist_ptr); + +bool_t capi_nxp_device_update_dataflow_state(capi_stream_data_t *input, + nxp_device_data_flow_state *current_state, + bool is_data_sufficient); + +bool_t capi_nxp_device_check_data_sufficiency(capi_stream_data_t *input, + capi_buf_t *scratch_buf, + uint32_t total_bytes, + bool_t packetized, + bool_t is_capi_in_media_fmt_set, + uint32_t expected_data_len, + uint16_t num_channels, + bool_t *need_to_underrun); + +capi_err_t capi_nxp_device_dai_init(capi_nxp_device_t *me_ptr, uint32_t dir); + +capi_err_t capi_nxp_device_init_param(capi_nxp_device_t *me_ptr); + +capi_err_t capi_nxp_device_init_dma_buffer(capi_nxp_device_t *me_ptr, uint32_t *pb, uint32_t *pc); + +capi_err_t capi_nxp_device_set_dma_config(capi_nxp_device_t *me_ptr, uint32_t period_bytes, uint32_t period_count); + +void capi_nxp_device_reset(capi_nxp_device_t *me_ptr); + +void capi_nxp_device_stop(capi_nxp_device_t *me_ptr); + +void capi_nxp_device_dma_callback(const struct device *dev, void *user_data, + uint32_t channel, int status); + +capi_err_t capi_nxp_device_process_get_properties(capi_nxp_device_t *me_ptr, capi_proplist_t *proplist_ptr); + +capi_err_t capi_nxp_device_process_set_properties(capi_nxp_device_t *me_ptr, capi_proplist_t *proplist_ptr); + +capi_err_t capi_nxp_device_process_sink(capi_t *_pif, capi_stream_data_t *input[], capi_stream_data_t *output[]); + +#endif /* _CAPI_NXP_DEVICE_I_H */ \ No newline at end of file diff --git a/fwk/platform/modules/nxp/endpoint/capi/src/capi_nxp_device_utils.c b/fwk/platform/modules/nxp/endpoint/capi/src/capi_nxp_device_utils.c new file mode 100644 index 00000000..3c89b650 --- /dev/null +++ b/fwk/platform/modules/nxp/endpoint/capi/src/capi_nxp_device_utils.c @@ -0,0 +1,848 @@ +/* ======================================================================== + @file capi_nxp_device_utils.c + @brief This file contains library implementation of nxp device Module + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +/*===================================================================== + Includes + ======================================================================*/ +#include "capi_nxp_device_i.h" +#include +#include + +#define PLATFORM_DCACHE_ALIGN 32 + +/* 16-bit interleaved stereo sine: 48 frames x (L,R) = 96 int16 = 192 bytes. + * Mono source sample duplicated into L and R slots for the 2-slot SAI frame. */ +#define BUF_SIZE 96 +static int16_t sine_buf[BUF_SIZE] = { + 0x0000, 0x0000, 0x10b5, 0x10b5, 0x2120, 0x2120, 0x30fb, 0x30fb, + 0x4000, 0x4000, 0x4deb, 0x4deb, 0x5a82, 0x5a82, 0x658c, 0x658c, + 0x6ed9, 0x6ed9, 0x7641, 0x7641, 0x7ba3, 0x7ba3, 0x7ee7, 0x7ee7, + 0x7fff, 0x7fff, 0x7ee7, 0x7ee7, 0x7ba3, 0x7ba3, 0x7641, 0x7641, + 0x6ed9, 0x6ed9, 0x658c, 0x658c, 0x5a82, 0x5a82, 0x4deb, 0x4deb, + 0x4000, 0x4000, 0x30fb, 0x30fb, 0x2120, 0x2120, 0x10b5, 0x10b5, + 0x0000, 0x0000, 0xef4a, 0xef4a, 0xdedf, 0xdedf, 0xcf04, 0xcf04, + 0xc000, 0xc000, 0xb214, 0xb214, 0xa57d, 0xa57d, 0x9a73, 0x9a73, + 0x9126, 0x9126, 0x89be, 0x89be, 0x845c, 0x845c, 0x8118, 0x8118, + 0x8000, 0x8000, 0x8118, 0x8118, 0x845c, 0x845c, 0x89be, 0x89be, + 0x9126, 0x9126, 0x9a73, 0x9a73, 0xa57d, 0xa57d, 0xb214, 0xb214, + 0xc000, 0xc000, 0xcf04, 0xcf04, 0xdedf, 0xdedf, 0xef4a, 0xef4a, +}; + +extern char _end[], _heap_sentry[]; +#define heapmem ((uint8_t *)ALIGN_UP((uintptr_t)_end, PLATFORM_DCACHE_ALIGN)) + +//Heap for dma_buffer +static struct k_heap kernel_heap; + +//const struct device *dai_devs[] = { DT_FOREACH_STATUS_OKAY(DT_NODELABEL(nxp_dai_sai), DEVICE_DT_GET(DT_NODELABEL(nxp_dai_sai))) }; +const struct device *dma_device = DEVICE_DT_GET(DT_NODELABEL(sdma3)); +const struct device *dai_dev = DEVICE_DT_GET(DT_NODELABEL(sai3)); + +/*------------------------------------------------------------------------ + Function name: capi_nxp_device_common_init + DESCRIPTION: Initialize the CAPIv2 nxp_device module and library. + This function can allocate memory. + -----------------------------------------------------------------------*/ +capi_err_t capi_nxp_device_common_init(capi_t *_pif, capi_proplist_t *init_set_properties, uint32_t dir) +{ + capi_err_t capi_result = CAPI_EOK; + //AR_MSG(DBG_ERROR_PRIO, + // "CAPI_NXP_DEVICE: Init enter"); + + if (NULL == _pif || NULL == init_set_properties) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_NXP_DEVICE: Init received bad pointer, 0x%lx", + (uint32_t)_pif); + return CAPI_EBADPARAM; + } + + capi_nxp_device_t *me_ptr = (capi_nxp_device_t *)_pif; + memset((void *)me_ptr, 0, sizeof(capi_nxp_device_t)); + + // Allocate vtbl + me_ptr->vtbl.vtbl_ptr = capi_nxp_device_get_vtbl(); + + // Cache direction + me_ptr->direction = 0; //sink + //me_ptr->i2s_media_fmt.format.data_interleaving = CAPI_DEINTERLEAVED_UNPACKED; + + capi_result = capi_nxp_device_process_set_properties(me_ptr, init_set_properties); + capi_result ^= (capi_result & CAPI_EUNSUPPORTED); // ignore unsupported + if (CAPI_EOK != capi_result) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: init set properties failed"); + return capi_result; + } + + //me_ptr->drift_info.heap_id = (POSAL_HEAP_ID)me_ptr->heap_mem.heap_id; + + capi_result = capi_nxp_device_dai_init(me_ptr, DAI_DIR_TX); + if (capi_result < 0) { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Failed to initialize dai"); + return CAPI_EFAILED; + } + + capi_result = capi_nxp_device_init_param(me_ptr); + if (capi_result < 0) { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Failed to initialize device parameters"); + return CAPI_EFAILED; + } + + AR_MSG(DBG_ERROR_PRIO, "rc: %d", capi_result); + return capi_result; +} + +/*------------------------------------------------------------------------ + Function name: capi_nxp_device_dai_init + DESCRIPTION: Initialize the CAPIv2 nxp_device dai. + -----------------------------------------------------------------------*/ +capi_err_t capi_nxp_device_dai_init(capi_nxp_device_t *me_ptr, uint32_t dir) +{ + capi_err_t capi_result = CAPI_EOK; + int ret = 0; + struct dai_config cfg; + struct sai_params *sai_cfg_params; + const void* cfg_params; + + if (NULL == me_ptr) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_NXP_DEVICE: Init received null property"); + return CAPI_EBADPARAM; + } + + ret = dai_config_get(dai_dev, &cfg, DAI_DIR_TX); + if (ret != 0) { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Failed to get dai configuration rc: %d", ret); + capi_result = CAPI_EFAILED; + goto end; + } + + if (dai_probe(dai_dev)) { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Failed to probe dai"); + capi_result = CAPI_EFAILED; + goto end; + } + + sai_cfg_params = posal_memory_malloc(sizeof(struct sai_params), (POSAL_HEAP_ID)me_ptr->heap_mem.heap_id); + if (NULL == sai_cfg_params) { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_NXP_DEVICE: Failed to allocate sai configuration pointer"); + capi_result = CAPI_ENOMEMORY; + goto end; + } + + me_ptr->dai_dir = dir; + + //Set the configuration + cfg.dai_index = 3; + //cfg.format = 1; + cfg.format = DAI_PROTO_I2S; + cfg.options = 1; + cfg.rate = 48000; + cfg.type = DAI_IMX_SAI; + cfg.channels = 2; + cfg.word_size = 16; + // Fill cfg_params + sai_cfg_params->mclk_id = 0; + sai_cfg_params->mclk_direction = 0; + sai_cfg_params->mclk_rate = 12288000; + sai_cfg_params->fsync_rate = 48000; + sai_cfg_params->bclk_rate = 1536000; //(48000 x 16 x 2) + sai_cfg_params->tdm_slots = 2; + sai_cfg_params->rx_slots = 0x3; + sai_cfg_params->tx_slots = 0x3; + sai_cfg_params->tdm_slot_width = 16; + cfg_params = sai_cfg_params; + ret = dai_config_set(dai_dev, &cfg, cfg_params); + if (ret) { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: dai_config_set failed %d", ret); + return CAPI_EFAILED; + } + +end: + if (sai_cfg_params) + posal_memory_free(sai_cfg_params); + + return capi_result; +} + +/*------------------------------------------------------------------------ + Function name: capi_nxp_device_init_param + DESCRIPTION: Sets either a parameter value or a parameter structure containing + multiple parameters. In the event of a failure, the appropriate error code is + returned. + -----------------------------------------------------------------------*/ +capi_err_t capi_nxp_device_init_param(capi_nxp_device_t *me_ptr) +{ + capi_err_t capi_result = CAPI_EOK; + uint32_t period_bytes = 0; + uint32_t period_count = 0; + + capi_result = capi_nxp_device_init_dma_buffer(me_ptr, &period_bytes, &period_count); + if (capi_result < 0) { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Failed to initialize dma buffer"); + return CAPI_EFAILED; + } + + capi_result = capi_nxp_device_set_dma_config(me_ptr, period_bytes, period_count); + if (capi_result < 0) { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Failed to set dma config"); + return CAPI_EFAILED; + } + + return capi_result; +} + +capi_err_t capi_nxp_device_init_dma_buffer(capi_nxp_device_t *me_ptr, uint32_t *pb, uint32_t *pc) +{ + capi_err_t capi_result = CAPI_EOK; + //struct capi_dai_data dai_data = me_ptr->dai_data; + struct dai_config cfg; + int ret = 0; + uint32_t channels = 2; /* 2 slots on the wire (WM8960 stereo frame) */ + uint32_t sample_bytes, frame_size, period_bytes, period_count; + uint32_t align = 0, addr_align, buf_size; + size_t heap_size = 0; + + ret = dai_config_get(dai_dev, &cfg, DAI_DIR_TX); + if (ret) { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Failed to get dai configuration"); + return CAPI_EFAILED; + } + + //Get the DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT + ret = dma_get_attribute(dma_device, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, &addr_align); //128 + if (ret < 0) { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Failed to get dma address align"); + return CAPI_EFAILED; + } + + //Get the DMA_ATTR_BUFFER_SIZE_ALIGNMENT + ret = dma_get_attribute(dma_device, DMA_ATTR_BUFFER_SIZE_ALIGNMENT, &align); // 4 + if (ret < 0) { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Failed to get dma align"); + return CAPI_EFAILED; + } + + //Calculate frame size, period size, and period count from the values in cfg + sample_bytes = 2; /* 16-bit sample */ + frame_size = sample_bytes * channels; + period_bytes = 192; /* 48 samples x 2 bytes x 2 slots (1ms @ 48kHz) */ + period_count = 2; + buf_size = ALIGN_UP(period_count * period_bytes, align); + *pb = period_bytes; + *pc = period_count; + me_ptr->dma_buf_size = buf_size; + + AR_MSG(DBG_ERROR_PRIO, "dma_buf_size %u", buf_size); + //If dma buffer exists, change the dma_buffer size to the period size + if (me_ptr->dma_dest_addr) { + //Check if the dma_buffer is the same size as the period size, otherwise resize it + + //Use sys_heap_realloc? + AR_MSG(DBG_ERROR_PRIO, "empty block called"); + } else { + /* heap_size must cover: sys_heap metadata + alignment padding + buf_size + * sys_heap overhead ~ 2 * CHUNK_UNIT (64 bytes on 32-bit) + * alignment padding = addr_align - 1 (up to 127 bytes for 128-byte align) + * Use buf_size * 2 as a safe upper bound. + */ + heap_size = (size_t)(buf_size * 2); + AR_MSG(DBG_ERROR_PRIO, + "sys_heap_init: base=%p size=%u buf_size=%u addr_align=%u", + heapmem, heap_size, buf_size, addr_align); + sys_heap_init(&kernel_heap.heap, heapmem, heap_size); + + me_ptr->dma_src_addr = sys_heap_aligned_alloc(&kernel_heap.heap, addr_align, buf_size); + AR_MSG(DBG_ERROR_PRIO, + "sys_heap_aligned_alloc: ptr=%p align=%u size=%u %s", + me_ptr->dma_src_addr, addr_align, buf_size, + me_ptr->dma_src_addr ? "OK" : "FAILED - NULL returned"); + if (NULL == me_ptr->dma_src_addr) { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_NXP_DEVICE: Failed to allocate DMA destination buffer"); + return CAPI_ENOMEMORY; + } + } + AR_MSG(DBG_ERROR_PRIO, "init_dma_buffer exit"); + return capi_result; +} + +capi_err_t capi_nxp_device_set_dma_config(capi_nxp_device_t *me_ptr, uint32_t period_bytes, uint32_t period_count) +{ + capi_err_t capi_result = CAPI_EOK; + struct dma_config *dma_cfg = NULL; + struct dma_block_config *dma_block_cfg = NULL; + struct dma_block_config *prev = NULL; + int ret, channel; + uint32_t fifo, burst_elems, max_block_count, buf_size; + + const struct dai_properties *props = dai_get_properties(dai_dev, DAI_DIR_TX, 0); + uint32_t hs = props->dma_hs_id; + burst_elems = props->fifo_depth; + fifo = props->fifo_address; + channel = hs & GENMASK(7, 0); + + AR_MSG(DBG_ERROR_PRIO, "channel %d", channel); + + ret = dma_get_attribute(dma_device, DMA_ATTR_MAX_BLOCK_COUNT, &max_block_count); //2 + if (ret < 0 || !max_block_count) { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Failed to get block count"); + capi_result = CAPI_EFAILED; + goto end; + } + + if (max_block_count < period_count) { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: unsupported period count %d, max_block_count %d", period_count, max_block_count); + buf_size = period_count * period_bytes; + do { + if (IS_ALIGNED(buf_size, max_block_count)) { + period_count = max_block_count; + period_bytes = buf_size / period_count; + break; + } else { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: alignment error for buf_size = %d, block count = %d", + buf_size, max_block_count); + } + } while (--max_block_count > 0); + } + + dma_cfg = posal_memory_malloc(sizeof(struct dma_config), (POSAL_HEAP_ID)me_ptr->heap_mem.heap_id); + if (NULL == dma_cfg) { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_NXP_DEVICE: Failed to allocate dma configuration pointer"); + capi_result = CAPI_ENOMEMORY; + goto end; + } + + + dma_cfg->channel_direction = MEMORY_TO_PERIPHERAL; + dma_cfg->source_data_size = 4; + dma_cfg->dest_data_size = dma_cfg->source_data_size; + dma_cfg->source_burst_length = 4; + dma_cfg->dest_burst_length = dma_cfg->source_burst_length; + dma_cfg->cyclic = 1; + dma_cfg->user_data = me_ptr; + dma_cfg->dma_callback = &capi_nxp_device_dma_callback; //Set to dma callback function + dma_cfg->block_count = max_block_count; + dma_cfg->dma_slot = (hs & GENMASK(15, 8)) >> 8; + + dma_block_cfg = posal_memory_malloc(sizeof(struct dma_block_config) * dma_cfg->block_count, (POSAL_HEAP_ID)me_ptr->heap_mem.heap_id); + if (NULL == dma_block_cfg) { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_NXP_DEVICE: Failed to allocate DMA blocks"); + capi_result = CAPI_ENOMEMORY; + goto end; + } + + dma_cfg->head_block = dma_block_cfg; + for (int i = 0; i < dma_cfg->block_count; i++) { + dma_block_cfg->dest_scatter_en = 0; + dma_block_cfg->block_size = period_bytes; + dma_block_cfg->source_address = (uint32_t)me_ptr->dma_src_addr + i * period_bytes; + dma_block_cfg->dest_address = fifo; + dma_block_cfg->source_addr_adj = DMA_ADDR_ADJ_DECREMENT; + dma_block_cfg->dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; + AR_MSG(DBG_ERROR_PRIO, + "DMA BD[%d]: block_cfg=%p src=0x%08x dst=0x%08x size=%u src_adj=%d dst_adj=%d", + i, dma_block_cfg, + dma_block_cfg->source_address, + dma_block_cfg->dest_address, + dma_block_cfg->block_size, + dma_block_cfg->source_addr_adj, + dma_block_cfg->dest_addr_adj); + prev = dma_block_cfg; + prev->next_block = ++dma_block_cfg; + } + if (prev) + prev->next_block = dma_cfg->head_block; + + me_ptr->z_config = dma_cfg; + + channel = dma_request_channel(dma_device, &channel); + if (channel < 0) { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_NXP_DEVICE: DMA request channel failed"); + capi_result = CAPI_EFAILED; + goto end; + } + me_ptr->dma_chan_index = channel; + + ret = dma_config(dma_device, me_ptr->dma_chan_index, dma_cfg); + if (ret < 0) { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_NXP_DEVICE: dma_config failed"); + capi_result = CAPI_EFAILED; + goto end; + } + + end: + if (capi_result != 0) { + if (dma_block_cfg) + posal_memory_free(dma_block_cfg); + if (dma_cfg) + posal_memory_free(dma_cfg); + + if (me_ptr->dma_src_addr) + sys_heap_free(&kernel_heap.heap, me_ptr->dma_src_addr); + } + AR_MSG(DBG_ERROR_PRIO, "set_dma_config exit"); + + return capi_result; +} + +void capi_nxp_device_reset(capi_nxp_device_t *me_ptr) +{ + if (me_ptr->z_config->head_block) + posal_memory_free(me_ptr->z_config->head_block); + + if (me_ptr->z_config) + posal_memory_free(me_ptr->z_config); + + if (me_ptr->dma_src_addr) + sys_heap_free(&kernel_heap.heap, me_ptr->dma_src_addr); +} + +void capi_nxp_device_stop(capi_nxp_device_t *me_ptr) +{ + //Stop the DMA and the DAI + dma_stop(dma_device, me_ptr->dma_chan_index); + dai_trigger(dai_dev, DAI_DIR_TX, DAI_TRIGGER_STOP); +} + +/*--------------------------------------------------------------------- + Function name: capi_nxp_device_dma_callback + DESCRIPTION: Will be called by the DMA driver when it needs more data + -----------------------------------------------------------------------*/ + +void capi_nxp_device_dma_callback(const struct device *dev, void *user_data, + uint32_t channel, int status) { + capi_nxp_device_t *me_ptr; + static uint32_t cb_count = 0; + cb_count++; + + //AR_MSG(DBG_ERROR_PRIO, "NXP CB [#%u]: ch=%u status=%d", cb_count, channel, status); + + if (user_data) + me_ptr = (capi_nxp_device_t *) user_data; + else { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: User data is NULL"); + return; + } + + /* --- SDMA register state --- */ + /*{ + SDMAARM_Type *sdma = (SDMAARM_Type *)0x30E00000; + AR_MSG(DBG_ERROR_PRIO, + "NXP CB [#%u] SDMA: CHNENBL[5]=0x%08x EVTOVR=0x%08x " + "HOSTOVR=0x%08x STOP_STAT=0x%08x INTR=0x%08x CHNPRI[1]=%u", + cb_count, + sdma->CHNENBL[5], + sdma->EVTOVR, + sdma->HOSTOVR, + sdma->STOP_STAT, + sdma->INTR, + sdma->SDMA_CHNPRI[1]); + }*/ + + /* --- SAI FIFO watermark vs burst size --- */ + { + I2S_Type *sai = (I2S_Type *)0x30c30000; + uint32_t tcsr = sai->TCSR; + uint32_t tcr1 = sai->TCR1; /* TX FIFO watermark in TCR1[2:0] */ + AR_MSG(DBG_ERROR_PRIO, + "NXP CB [#%u] SAI: TCSR=0x%08x TCR1=0x%08x " + "FRF=%d FEF=%d TE=%d FRDE=%d", + cb_count, tcsr, tcr1, + !!(tcsr & I2S_TCSR_FRF_MASK), + !!(tcsr & I2S_TCSR_FEF_MASK), + !!(tcsr & I2S_TCSR_TE_MASK), + !!(tcsr & I2S_TCSR_FRDE_MASK)); + } + + /* --- BD source addresses (cache coherency check) --- */ + /*{ + struct dma_block_config *bd0 = me_ptr->z_config->head_block; + struct dma_block_config *bd1 = bd0 ? bd0->next_block : NULL; + AR_MSG(DBG_ERROR_PRIO, + "NXP CB [#%u] BD: bd[0].src=0x%08x bd[0].dst=0x%08x " + "bd[1].src=0x%08x bd[1].dst=0x%08x", + cb_count, + bd0 ? bd0->source_address : 0, + bd0 ? bd0->dest_address : 0, + bd1 ? bd1->source_address : 0, + bd1 ? bd1->dest_address : 0); + }*/ + + /* Trigger the waiting thread to tell the container we need more data */ + if (me_ptr->i2s_driver.i2s_intf_state.trigger_signal_ptr) { + AR_MSG(DBG_ERROR_PRIO, "NXP CB [#%u]: sending signal ptr=%p", + cb_count, me_ptr->i2s_driver.i2s_intf_state.trigger_signal_ptr); + posal_signal_send((posal_signal_t)me_ptr->i2s_driver.i2s_intf_state.trigger_signal_ptr); + } else { + AR_MSG(DBG_ERROR_PRIO, "NXP CB [#%u]: trigger_signal_ptr is NULL", cb_count); + } +} + +/*--------------------------------------------------------------------- + Function name: capi_nxp_device_process_sink + DESCRIPTION: Processes an input buffer and generates an output buffer. + -----------------------------------------------------------------------*/ +capi_err_t capi_nxp_device_process_sink(capi_t *_pif, capi_stream_data_t *input[], capi_stream_data_t *output[]) +{ + capi_err_t capi_result = CAPI_EOK; + capi_nxp_device_t *me_ptr = (capi_nxp_device_t *)_pif; + struct dma_status stat; + int ret = 0; + uint16_t port = 0; + uint16_t i = 0; + uint32_t free_bytes = 0; + uint32_t buf_data_len = 0; + + static uint32_t sink_count = 0; + sink_count++; + + //AR_MSG(DBG_ERROR_PRIO, "process_sink [#%u]", sink_count); + + //Get data sizes and read/write buffer positions from the DMA + ret = dma_get_status(dma_device, me_ptr->dma_chan_index, &stat); + if (ret != 0) + { + AR_MSG(DBG_ERROR_PRIO, "dma_get_status failed rc: %d", ret); + capi_result = CAPI_EFAILED; + return capi_result; + } + + /* Periodic SAI register dump every 10 calls to catch stall */ + if ((sink_count % 10) == 1) { + I2S_Type *sai_base = (I2S_Type *)0x30c30000; + uint32_t tcsr = sai_base->TCSR; + uint32_t tcr3 = sai_base->TCR3; + AR_MSG(DBG_ERROR_PRIO, + "SINK [#%u] SAI: TCSR=0x%08x TCR3=0x%08x " + "TE=%d FEF=%d FWF=%d FRF=%d FRDE=%d", + sink_count, tcsr, tcr3, + !!(tcsr & I2S_TCSR_TE_MASK), + !!(tcsr & I2S_TCSR_FEF_MASK), + !!(tcsr & I2S_TCSR_FWF_MASK), + !!(tcsr & I2S_TCSR_FRF_MASK), + !!(tcsr & I2S_TCSR_FRDE_MASK)); + } + + free_bytes = stat.free; //The amount of free bytes in the output DMA buffer + buf_data_len = input[port]->buf_ptr[i].actual_data_len; + + //AR_MSG(DBG_ERROR_PRIO, "free_bytes: %u, buf_data_len: %u, stat.wr_pos:%u", free_bytes, buf_data_len, stat.write_position); + + /* Reload gating: only copy + flush + reload when at least one full period + * (192 bytes) of space is free in the DMA ring. */ + if (free_bytes >= 192) { + /* Write sine data to the correct ring buffer slot using write_position. + * stat.write_position is the offset within dma_src_addr where the + * CPU should write next — this ensures each BD gets fresh data. + */ + uint8_t *write_addr = (uint8_t *)me_ptr->dma_src_addr + stat.write_position; + memcpy(write_addr, sine_buf, 192); + /* Flush the CPU-written data so SDMA reads fresh bytes from DRAM (dcache is enabled) */ + sys_cache_data_flush_range(write_addr, 192); + /*AR_MSG(DBG_ERROR_PRIO, + "process_sink: wrote 192 bytes to %p (base=%p wr_pos=%u)", + write_addr, me_ptr->dma_src_addr, stat.write_position);*/ + + dma_reload(dma_device, me_ptr->dma_chan_index, 0, 0, 192); + } else { + AR_MSG(DBG_ERROR_PRIO, "process_sink: skip reload, free_bytes %u < 192", free_bytes); + } + + AR_MSG(DBG_ERROR_PRIO, "process_sink exit"); + + return capi_result; +} + + +capi_err_t capi_nxp_device_process_get_properties(capi_nxp_device_t *me_ptr, capi_proplist_t *proplist_ptr) +{ + capi_err_t capi_result = CAPI_EOK; + uint32_t fwk_extn_ids[1] = { 0 }; + fwk_extn_ids[0] = FWK_EXTN_STM; + + capi_basic_prop_t mod_prop; + mod_prop.init_memory_req = sizeof(capi_nxp_device_t); + mod_prop.stack_size = NXP_DEVICE_STACK_SIZE; + mod_prop.num_fwk_extns = NXP_DEVICE_NUM_FRAMEWORK_EXTENSIONS; + mod_prop.fwk_extn_ids_arr = fwk_extn_ids; + mod_prop.is_inplace = 0; // NA + mod_prop.req_data_buffering = 0; // NA + mod_prop.max_metadata_size = 0; // NA + + capi_result = capi_cmn_get_basic_properties(proplist_ptr, &mod_prop); + if (CAPI_EOK != capi_result) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Get common basic properties failed with result %lu", capi_result); + return capi_result; + } + + capi_prop_t *prop_ptr = proplist_ptr->prop_ptr; + for (uint32_t i = 0; i < proplist_ptr->props_num; i++) + { + capi_buf_t *payload_ptr = &prop_ptr[i].payload; + switch (prop_ptr[i].id) + { + case CAPI_INIT_MEMORY_REQUIREMENT: + case CAPI_STACK_SIZE: + case CAPI_NUM_NEEDED_FRAMEWORK_EXTENSIONS: + case CAPI_NEEDED_FRAMEWORK_EXTENSIONS: + case CAPI_OUTPUT_MEDIA_FORMAT_SIZE: + case CAPI_IS_INPLACE: + case CAPI_REQUIRES_DATA_BUFFERING: + case CAPI_OUTPUT_MEDIA_FORMAT_V2: + { + break; + } + case CAPI_PORT_DATA_THRESHOLD: + { + if (NULL == me_ptr) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: null ptr while querying threshold"); + return CAPI_EBADPARAM; + } + + // based on int samples per period calculation (frame size in bytes) + /* mono graph input: 48 samples x 2 bytes/sample x 1 channel = 96 bytes (1ms period) */ + uint32_t threshold_in_bytes = 48 * 2 * 1; + + capi_result = capi_cmn_handle_get_port_threshold(&prop_ptr[i], threshold_in_bytes); + break; + } + case CAPI_INTERFACE_EXTENSIONS: + { + //capi_result = capi_hw_intf_cmn_update_intf_extn_status(payload_ptr); + break; + } + default: + { + AR_MSG(DBG_HIGH_PRIO, "CAPI_NXP_DEVICE: Skipped Get Property for 0x%x. Not supported.", prop_ptr[i].id); + capi_result |= CAPI_EUNSUPPORTED; + break; + } + } + } + return capi_result; +} + +/*------------------------------------------------------------------------ + Function name: capi_nxp_device_process_set_properties + DESCRIPTION: Function to set the properties for the nxp_device module + * -----------------------------------------------------------------------*/ +capi_err_t capi_nxp_device_process_set_properties(capi_nxp_device_t *me_ptr, capi_proplist_t *proplist_ptr) +{ + capi_err_t capi_result = CAPI_EOK; + int ret = 0; + //struct dma_status stat; + //uint32_t free_bytes; + uint32_t i = 0; + //AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Set properties enter"); + + if (NULL == me_ptr) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Set property received null property."); + return CAPI_EBADPARAM; + } + + capi_result = capi_cmn_set_basic_properties(proplist_ptr, &me_ptr->heap_mem, &me_ptr->cb_info, FALSE); + + if (CAPI_EOK != capi_result) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Set basic properties failed with result %lu", capi_result); + return capi_result; + } + + + capi_prop_t *prop_ptr = proplist_ptr->prop_ptr; + + for (i = 0; i < proplist_ptr->props_num; i++) + { + capi_buf_t *payload_ptr = &prop_ptr[i].payload; + switch (prop_ptr[i].id) + { + case CAPI_HEAP_ID: + case CAPI_EVENT_CALLBACK_INFO: + case CAPI_ALGORITHMIC_RESET: + { + break; + } + case CAPI_INPUT_MEDIA_FORMAT_V2: + { + capi_result = CAPI_EOK; + + break; + } + case CAPI_PORT_NUM_INFO: + { + if (payload_ptr->actual_data_len >= sizeof(capi_port_num_info_t)) + { + capi_port_num_info_t *data_ptr = (capi_port_num_info_t *)payload_ptr->data_ptr; + if (!(data_ptr->num_input_ports == 1 && data_ptr->num_output_ports == 0) && + !(data_ptr->num_input_ports == 0 && data_ptr->num_output_ports == 1)) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_NXP_DEVICE: Invalid number of input = %d, number of output ports = %d.", + data_ptr->num_input_ports, + data_ptr->num_output_ports); + CAPI_SET_ERROR(capi_result, CAPI_EBADPARAM); + } + } + else + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Bad param size %lu", payload_ptr->actual_data_len); + CAPI_SET_ERROR(capi_result, CAPI_ENEEDMORE); + } + break; + } + case CAPI_CUSTOM_PROPERTY: + { + capi_custom_property_t *cust_prop_ptr = (capi_custom_property_t *)payload_ptr->data_ptr; + void * cust_payload_ptr = (void *)(cust_prop_ptr + 1); + + switch (cust_prop_ptr->secondary_prop_id) + { + case FWK_EXTN_PROPERTY_ID_STM_TRIGGER: + { + if (payload_ptr->actual_data_len < sizeof(capi_custom_property_t) + sizeof(capi_prop_stm_trigger_t)) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_NXP_DEVICE: Insufficient payload size for stm trigger %d", + payload_ptr->actual_data_len); + return CAPI_EBADPARAM; + } + + //AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Setting STM trigger"); + + // Get end point info + capi_prop_stm_trigger_t *trig_ptr = (capi_prop_stm_trigger_t *)cust_payload_ptr; + me_ptr->i2s_driver.i2s_intf_state.trigger_signal_ptr = trig_ptr->signal_ptr; + me_ptr->i2s_driver.i2s_intf_state.i2s_intr_cnt_ptr = trig_ptr->raised_intr_counter_ptr; + + break; + } + case FWK_EXTN_PROPERTY_ID_STM_CTRL: + { + //AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Setting STM CTRL enter"); + if (payload_ptr->actual_data_len < sizeof(capi_prop_stm_ctrl_t) + sizeof(capi_custom_property_t)) + { + /* Insufficient payload size */ + AR_MSG(DBG_ERROR_PRIO, "invalid payload size"); + capi_result |= CAPI_ENEEDMORE; + break; + } + + capi_prop_stm_ctrl_t *ctr_ptr = (capi_prop_stm_ctrl_t *)cust_payload_ptr; + + if (ctr_ptr->enable){ + + //AR_MSG(DBG_ERROR_PRIO, "Start DMA"); + ret = dma_start(dma_device, me_ptr->dma_chan_index); + if (ret < 0) { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: DMA start failed rc: %d", ret); + return CAPI_EFAILED; + } + + //Start the DAI + dai_trigger(dai_dev, DAI_DIR_TX, DAI_TRIGGER_START); + + /* SAI TCSR status after trigger + * SAI3 base = 0x30c30000 on i.MX8MP + * TCSR offset = 0x00, TCR3 offset = 0x0C + */ + /*{ + I2S_Type *sai_base = (I2S_Type *)0x30c30000; + uint32_t tcsr = sai_base->TCSR; + uint32_t tcr3 = sai_base->TCR3; + AR_MSG(DBG_ERROR_PRIO, + "SAI post-start: TCSR=0x%08x TCR3=0x%08x " + "TE=%d FEF=%d FWF=%d FRF=%d FRDE=%d", + tcsr, tcr3, + !!(tcsr & I2S_TCSR_TE_MASK), + !!(tcsr & I2S_TCSR_FEF_MASK), + !!(tcsr & I2S_TCSR_FWF_MASK), + !!(tcsr & I2S_TCSR_FRF_MASK), + !!(tcsr & I2S_TCSR_FRDE_MASK)); + }*/ + + AR_MSG(DBG_ERROR_PRIO, "DMA & DAI start done"); + } + else{ + AR_MSG(DBG_ERROR_PRIO, "disable: True"); + } + break; + } + default: + { + AR_MSG(DBG_HIGH_PRIO, "CAPI_NXP_DEVICE: Unknown Custom Property[%d]", cust_prop_ptr->secondary_prop_id); + capi_result |= CAPI_EUNSUPPORTED; + break; + } + } // inner switch - CUSTOM Properties + break; + } + case CAPI_MODULE_INSTANCE_ID: + { + if (payload_ptr->actual_data_len >= sizeof(capi_module_instance_id_t)) + { + capi_module_instance_id_t *data_ptr = (capi_module_instance_id_t *)payload_ptr->data_ptr; + me_ptr->iid = data_ptr->module_instance_id; + AR_MSG(DBG_LOW_PRIO, + "CAPI_NXP_DEVICE: This module-id 0x%08lX, instance-id 0x%08lX", + data_ptr->module_id, + me_ptr->iid); + } + else + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_NXP_DEVICE: Set, Param id 0x%lx Bad param size %lu", + (uint32_t)prop_ptr[i].id, + payload_ptr->actual_data_len); + CAPI_SET_ERROR(capi_result, CAPI_ENEEDMORE); + } + break; + } + case CAPI_LOGGING_INFO: + { + if (payload_ptr->actual_data_len >= sizeof(capi_logging_info_t)) + { + capi_logging_info_t *data_ptr = (capi_logging_info_t *)payload_ptr->data_ptr; + me_ptr->log_id = data_ptr->log_id; + me_ptr->log_id_reserved_mask = data_ptr->log_id_mask; + AR_MSG(DBG_LOW_PRIO, + "CAPI_NXP_DEVICE: log-id 0x%08lX, mask 0x%08lX", + me_ptr->log_id, + me_ptr->log_id_reserved_mask); + } + else + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_NXP_DEVICE: Set, Param id 0x%lx Bad param size %lu", + (uint32_t)prop_ptr[i].id, + payload_ptr->actual_data_len); + CAPI_SET_ERROR(capi_result, CAPI_ENEEDMORE); + } + break; + } + default: + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_NXP_DEVICE: Skipping set prop, unsupported param[%d]", prop_ptr[i].id); + capi_result |= CAPI_EUNSUPPORTED; + continue; + } + } /* Outer switch - Generic CAPI Properties */ + } /* Loop all properties */ + + return capi_result; +} \ No newline at end of file From 1ffe21d18faeb89f4e2214590a2722b15ea27d92 Mon Sep 17 00:00:00 2001 From: Aditya Rathi Date: Tue, 4 Aug 2026 16:32:40 +0530 Subject: [PATCH 2/2] build: Enable NXP SAI HW endpoint on imx8mp EVK board With the nxp_device_sink module now available, enable it for the i.MX8MP EVK ADSP target so the SAI/SDMA endpoint is built and wired into the audio path. Turn on NXP_DEVICE_SINK and SHARED_INTERRUPTS in prj.conf. Enable the Zephyr DAI, DMA, SAI, SDMA, and fixed-rate clock drivers in the board conf, and mark the sai3, sdma3, mclk, and micfil device tree nodes okay in the board overlay so the hardware endpoint has the resources it needs. Signed-off-by: Aditya Rathi --- app/boards/imx8mp_evk_mimx8ml8_adsp.conf | 6 ++++++ app/boards/imx8mp_evk_mimx8ml8_adsp.overlay | 22 ++++++++++++++++++++- app/prj.conf | 2 ++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/boards/imx8mp_evk_mimx8ml8_adsp.conf b/app/boards/imx8mp_evk_mimx8ml8_adsp.conf index c57b80ea..73e0db2e 100644 --- a/app/boards/imx8mp_evk_mimx8ml8_adsp.conf +++ b/app/boards/imx8mp_evk_mimx8ml8_adsp.conf @@ -4,3 +4,9 @@ CONFIG_IPM_IMX_MAX_DATA_SIZE_4=y CONFIG_OPENAMP_WITH_DCACHE=y CONFIG_IPM_IMX_FW_READY_REPLY=y CONFIG_POSAL_MMAP_NO_MMU=y +CONFIG_DAI=y +CONFIG_DMA=y +CONFIG_DAI_NXP_SAI=y +CONFIG_DMA_NXP_SDMA=y +CONFIG_SAI_HAS_MCLK_CONFIG_OPTION=y +CONFIG_CLOCK_CONTROL_FIXED_RATE_CLOCK=y \ No newline at end of file diff --git a/app/boards/imx8mp_evk_mimx8ml8_adsp.overlay b/app/boards/imx8mp_evk_mimx8ml8_adsp.overlay index e0b62f79..8b20ec98 100644 --- a/app/boards/imx8mp_evk_mimx8ml8_adsp.overlay +++ b/app/boards/imx8mp_evk_mimx8ml8_adsp.overlay @@ -17,8 +17,28 @@ compatible = "mmio-sram"; reg = <0x942f0000 0x110000>; }; + + mclk1: mclk { + status = "okay"; + }; }; &mailbox0 { status = "okay"; -}; \ No newline at end of file +}; + +&sdma3 { + status = "okay"; +}; + +&sai3 { + rx-fifo-watermark = <65>; + tx-fifo-watermark = <65>; + fifo-depth = <128>; + rx-sync-mode = <1>; + status = "okay"; +}; + +&micfil { + status = "okay"; +}; diff --git a/app/prj.conf b/app/prj.conf index cd387ccd..3422ea59 100644 --- a/app/prj.conf +++ b/app/prj.conf @@ -47,10 +47,12 @@ CONFIG_SHELL_BACKEND_RPMSG=y # AUDIOREACH ENGINE CONFIGURATION CONFIG_PROC_DOMAIN="ADSP" CONFIG_ARCH_ZEPHYR=y +CONFIG_SHARED_INTERRUPTS=y # AudioReach Features - Disabled for minimal build CONFIG_ALSA_DEVICE_SINK=n CONFIG_ALSA_DEVICE_SOURCE=n +CONFIG_NXP_DEVICE_SINK=y CONFIG_SH_MEM_PULL_MODE=n CONFIG_SH_MEM_PUSH_MODE=n CONFIG_LATENCY=n