c05564c4d8
Android 13
5114 lines
138 KiB
C
Executable file
5114 lines
138 KiB
C
Executable file
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
* Author: Michael Hsiao <michael.hsiao@mediatek.com>
|
|
*/
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* Filename:
|
|
* ---------
|
|
* mt_sco_afe_control.c
|
|
*
|
|
* Project:
|
|
* --------
|
|
* MT6797 Audio Driver Kernel Function
|
|
*
|
|
* Description:
|
|
* ------------
|
|
* Audio register
|
|
*
|
|
* Author:
|
|
* -------
|
|
* Chipeng Chang
|
|
*
|
|
*------------------------------------------------------------------------------
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
* C O M P I L E R F L A G S
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* E X T E R N A L R E F E R E N C E S
|
|
*****************************************************************************/
|
|
|
|
#include "mtk-soc-afe-control.h"
|
|
#include "mtk-auddrv-afe.h"
|
|
#include "mtk-auddrv-ana.h"
|
|
#include "mtk-auddrv-clk.h"
|
|
#include "mtk-auddrv-common.h"
|
|
#include "mtk-auddrv-def.h"
|
|
#include "mtk-auddrv-gpio.h"
|
|
#include "mtk-auddrv-kernel.h"
|
|
#include "mtk-soc-afe-connection.h"
|
|
#include "mtk-soc-analog-type.h"
|
|
#include "mtk-soc-digital-type.h"
|
|
#include "mtk-soc-pcm-common.h"
|
|
#include "mtk-soc-pcm-platform.h"
|
|
|
|
#include <sound/core.h>
|
|
#include <sound/jack.h>
|
|
#include <sound/soc.h>
|
|
#include <sound/soc-dapm.h>
|
|
#if defined(CONFIG_MTK_AUDIO_SCP_SPKPROTECT_SUPPORT)
|
|
#include "mtk-auddrv-scp-spkprotect-common.h"
|
|
#endif
|
|
/*
|
|
* #include <mt-plat/mt_boot.h>
|
|
* #include <mt-plat/mt_boot_common.h>
|
|
* #include <mt-plat/mt_lpae.h>
|
|
*/
|
|
|
|
#ifdef CONFIG_MTK_AUXADC_INTF
|
|
#include <mach/mtk_pmic.h>
|
|
#include <mt-plat/mtk_auxadc_intf.h>
|
|
#endif
|
|
|
|
#include <linux/ftrace.h>
|
|
|
|
#ifdef AUDIO_VCOREFS_SUPPORT
|
|
#include <mtk_vcorefs_manager.h>
|
|
#endif
|
|
|
|
static DEFINE_SPINLOCK(afe_control_lock);
|
|
static DEFINE_SPINLOCK(afe_sram_control_lock);
|
|
static DEFINE_SPINLOCK(afe_mem_blk_dl1_lock);
|
|
static DEFINE_SPINLOCK(afe_mem_blk_dl1_2_lock);
|
|
static DEFINE_SPINLOCK(afe_mem_blk_dl2_lock);
|
|
static DEFINE_SPINLOCK(afe_mem_blk_dl3_lock);
|
|
static DEFINE_SPINLOCK(afe_dl_abnormal_context_lock);
|
|
static DEFINE_SPINLOCK(afe_mem_blk_ul1_lock);
|
|
static DEFINE_SPINLOCK(afe_mem_blk_ul2_lock);
|
|
static DEFINE_SPINLOCK(afe_mem_blk_ul3_lock);
|
|
static DEFINE_SPINLOCK(afe_mem_blk_dai_lock);
|
|
static DEFINE_SPINLOCK(afe_mem_blk_moddai_lock);
|
|
static DEFINE_SPINLOCK(afe_mem_blk_awb_lock);
|
|
static DEFINE_SPINLOCK(auddrv_dl2_lock);
|
|
static DEFINE_SPINLOCK(auddrv_dl3_lock);
|
|
static unsigned long spinlock_flags[Soc_Aud_Digital_Block_MEM_HDMI + 1];
|
|
|
|
static DEFINE_MUTEX(afe_control_mutex);
|
|
|
|
/* static variable */
|
|
static bool AudioDaiBtStatus;
|
|
static bool AudioAdcI2SStatus;
|
|
static bool Audio2ndAdcI2SStatus;
|
|
static bool AudioMrgStatus;
|
|
static bool mAudioInit;
|
|
static bool mVOWStatus;
|
|
static struct audio_digital_i2s *m2ndI2S; /* input */
|
|
static struct audio_digital_i2s *m2ndI2Sout; /* output */
|
|
static bool mFMEnable;
|
|
static bool mOffloadEnable;
|
|
|
|
static struct audio_hdmi *mHDMIOutput;
|
|
static struct audio_mrg_if *mAudioMrg;
|
|
static struct audio_digital_dai_bt *AudioDaiBt;
|
|
|
|
static struct afe_mem_control_t
|
|
*AFE_Mem_Control_context[Soc_Aud_Digital_Block_NUM_OF_MEM_INTERFACE] = {
|
|
NULL};
|
|
static struct snd_dma_buffer
|
|
*Audio_dma_buf[Soc_Aud_Digital_Block_NUM_OF_MEM_INTERFACE] = {NULL};
|
|
|
|
static struct audio_memif_attribute
|
|
*mAudioMEMIF[Soc_Aud_Digital_Block_NUM_OF_DIGITAL_BLOCK] = {NULL};
|
|
|
|
struct afe_dl_abnormal_control_t AFE_dL_Abnormal_context;
|
|
|
|
/* static struct audio_afe_reg_cache mAudioRegCache; */
|
|
static struct audio_ul_dl_sram_manager mAudioSramManager;
|
|
|
|
const size_t AudioInterruptLimiter = 100;
|
|
static int irqcount;
|
|
static unsigned int irq_mcu_mask;
|
|
static int APLL1TunerCounter;
|
|
static int APLL2TunerCounter;
|
|
|
|
static unsigned int sram_mode_size[2] = {
|
|
AFE_INTERNAL_SRAM_NORMAL_SIZE, AFE_INTERNAL_SRAM_COMPACT_SIZE,
|
|
};
|
|
static struct audio_sram_manager mAud_Sram_Manager;
|
|
|
|
static bool mExternalModemStatus;
|
|
|
|
static struct mtk_dai mtk_dais[Soc_Aud_Digital_Block_NUM_OF_DIGITAL_BLOCK];
|
|
|
|
static struct irq_manager irq_managers[Soc_Aud_IRQ_MCU_MODE_NUM];
|
|
static struct mtk_mem_blk_ops *s_mem_blk_ops;
|
|
static struct mtk_afe_platform_ops *s_afe_platform_ops;
|
|
|
|
#define IrqShortCounter 512
|
|
#define SramBlockSize (4096)
|
|
|
|
static bool ScreenState;
|
|
|
|
static unsigned int LowLatencyDebug;
|
|
|
|
/*
|
|
* Function Forward Declaration
|
|
*/
|
|
|
|
static irqreturn_t AudDrv_IRQ_handler(int irq, void *dev_id);
|
|
static void Clear_Mem_CopySize(enum soc_aud_digital_block MemBlock);
|
|
static kal_uint32 Get_Mem_MaxCopySize(enum soc_aud_digital_block MemBlock);
|
|
|
|
static unsigned int GeneralSampleRateTransform(unsigned int sampleRate);
|
|
static unsigned int DAIMEMIFSampleRateTransform(unsigned int sampleRate);
|
|
static unsigned int ADDADLSampleRateTransform(unsigned int sampleRate);
|
|
static unsigned int ADDAULSampleRateTransform(unsigned int sampleRate);
|
|
static unsigned int MDSampleRateTransform(unsigned int sampleRate);
|
|
|
|
/*
|
|
* function implementation
|
|
*/
|
|
|
|
static bool CheckSize(unsigned int size)
|
|
{
|
|
if (size == 0) {
|
|
pr_debug("%s(), size = 0\n", __func__);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void AfeGlobalVarInit(void)
|
|
{
|
|
AudioDaiBtStatus = false;
|
|
AudioAdcI2SStatus = false;
|
|
Audio2ndAdcI2SStatus = false;
|
|
AudioMrgStatus = false;
|
|
mAudioInit = false;
|
|
mVOWStatus = false;
|
|
m2ndI2S = NULL; /* input */
|
|
m2ndI2Sout = NULL; /* output */
|
|
mFMEnable = false;
|
|
mOffloadEnable = false;
|
|
mHDMIOutput = NULL;
|
|
mAudioMrg = NULL;
|
|
AudioDaiBt = NULL;
|
|
mExternalModemStatus = false;
|
|
irqcount = 0;
|
|
}
|
|
|
|
void AfeControlMutexLock(void)
|
|
{
|
|
mutex_lock(&afe_control_mutex);
|
|
}
|
|
|
|
void AfeControlMutexUnLock(void)
|
|
{
|
|
mutex_unlock(&afe_control_mutex);
|
|
}
|
|
|
|
void AfeControlSramLock(void)
|
|
{
|
|
spin_lock(&afe_sram_control_lock);
|
|
}
|
|
|
|
void AfeControlSramUnLock(void)
|
|
{
|
|
spin_unlock(&afe_sram_control_lock);
|
|
}
|
|
|
|
unsigned int GetSramState(void)
|
|
{
|
|
return mAudioSramManager.mMemoryState;
|
|
}
|
|
|
|
void SetSramState(unsigned int State)
|
|
{
|
|
pr_debug("%s state= %d\n", __func__, State);
|
|
mAudioSramManager.mMemoryState |= State;
|
|
}
|
|
|
|
void ClearSramState(unsigned int State)
|
|
{
|
|
pr_debug("%s state= %d\n", __func__, State);
|
|
mAudioSramManager.mMemoryState &= (~State);
|
|
}
|
|
|
|
unsigned int GetPLaybackSramFullSize(void)
|
|
{
|
|
unsigned int Sramsize = AUDIO_SRAM_PLAYBACK_FULL_SIZE;
|
|
|
|
if (AUDIO_SRAM_PLAYBACK_FULL_SIZE > AFE_INTERNAL_SRAM_SIZE)
|
|
Sramsize = AFE_INTERNAL_SRAM_SIZE;
|
|
|
|
return Sramsize;
|
|
}
|
|
|
|
unsigned int GetPLaybackSramPartial(void)
|
|
{
|
|
unsigned int Sramsize = AUDIO_SRAM_PLAYBACK_PARTIAL_SIZE;
|
|
|
|
return Sramsize;
|
|
}
|
|
|
|
unsigned int GetPLaybackDramSize(void)
|
|
{
|
|
return AUDIO_DRAM_PLAYBACK_SIZE;
|
|
}
|
|
|
|
size_t GetCaptureSramSize(void)
|
|
{
|
|
unsigned int Sramsize = AUDIO_SRAM_CAPTURE_SIZE;
|
|
|
|
return Sramsize;
|
|
}
|
|
|
|
size_t GetCaptureDramSize(void)
|
|
{
|
|
return AUDIO_DRAM_CAPTURE_SIZE;
|
|
}
|
|
|
|
void SetFMEnableFlag(bool bEnable)
|
|
{
|
|
mFMEnable = bEnable;
|
|
}
|
|
|
|
void SetOffloadEnableFlag(bool bEnable)
|
|
{
|
|
mOffloadEnable = bEnable;
|
|
}
|
|
|
|
bool GetOffloadEnableFlag(void)
|
|
{
|
|
return mOffloadEnable;
|
|
}
|
|
|
|
bool ConditionEnterSuspend(void)
|
|
{
|
|
if ((mFMEnable == true) || (mOffloadEnable == true) ||
|
|
(GetMemoryPathEnable(Soc_Aud_Digital_Block_ADDA_ANC) == true))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/* function get internal mode status. */
|
|
bool get_internalmd_status(void)
|
|
{
|
|
bool ret = (get_voice_bt_status() || get_voice_usb_status() ||
|
|
get_voice_status() || get_voice_md2_status() ||
|
|
get_voice_md2_bt_status());
|
|
#ifdef _NON_COMMON_FEATURE_READY
|
|
get_voice_ultra_status();
|
|
#endif
|
|
return (mExternalModemStatus == true) ? false : ret;
|
|
}
|
|
|
|
void SetExternalModemStatus(const bool bEnable)
|
|
{
|
|
pr_debug("%s(), mExternalModemStatus : %d => %d\n", __func__,
|
|
mExternalModemStatus, bEnable);
|
|
mExternalModemStatus = bEnable;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* InitAfeControl ,ResetAfeControl
|
|
*
|
|
* DESCRIPTION
|
|
* afe init function
|
|
*
|
|
*****************************************************************************
|
|
*/
|
|
int InitAfeControl(struct device *pDev)
|
|
{
|
|
int i = 0;
|
|
int ret = 0;
|
|
|
|
pr_debug("%s()\n", __func__);
|
|
|
|
/* first time to init , reg init. */
|
|
AfeGlobalVarInit();
|
|
Auddrv_Reg_map(pDev);
|
|
AudDrv_Clk_Global_Variable_Init();
|
|
AudDrv_Bus_Init();
|
|
Auddrv_Read_Efuse_HPOffset();
|
|
AfeControlMutexLock();
|
|
|
|
/* allocate memory for pointers */
|
|
if (mAudioInit == false) {
|
|
mAudioInit = true;
|
|
mAudioMrg = devm_kzalloc(pDev, sizeof(struct audio_mrg_if),
|
|
GFP_KERNEL);
|
|
if (!mAudioMrg) {
|
|
/* pr_debug("Failed to allocate private data\n"); */
|
|
ret = -ENOMEM;
|
|
} else {
|
|
mAudioMrg->Mrg_I2S_SampleRate =
|
|
SampleRateTransform(44100,
|
|
Soc_Aud_Digital_Block_MRG_I2S_OUT);
|
|
}
|
|
AudioDaiBt =
|
|
devm_kzalloc(pDev, sizeof(struct audio_digital_dai_bt),
|
|
GFP_KERNEL);
|
|
if (!AudioDaiBt) {
|
|
/* pr_debug("Failed to allocate private data\n"); */
|
|
ret = -ENOMEM;
|
|
}
|
|
m2ndI2S = devm_kzalloc(pDev,
|
|
sizeof(struct audio_digital_i2s),
|
|
GFP_KERNEL);
|
|
if (!m2ndI2S) {
|
|
/* pr_debug("Failed to allocate private data\n"); */
|
|
ret = -ENOMEM;
|
|
}
|
|
m2ndI2Sout =
|
|
devm_kzalloc(pDev, sizeof(struct audio_digital_i2s),
|
|
GFP_KERNEL);
|
|
if (!m2ndI2Sout) {
|
|
/* pr_debug("Failed to allocate private data\n"); */
|
|
ret = -ENOMEM;
|
|
}
|
|
mHDMIOutput = devm_kzalloc(pDev, sizeof(struct audio_hdmi),
|
|
GFP_KERNEL);
|
|
if (!mHDMIOutput) {
|
|
/* pr_debug("Failed to allocate private data\n"); */
|
|
ret = -ENOMEM;
|
|
}
|
|
for (i = 0; i < Soc_Aud_Digital_Block_NUM_OF_DIGITAL_BLOCK;
|
|
i++) {
|
|
mAudioMEMIF[i] =
|
|
devm_kzalloc(pDev,
|
|
sizeof(struct audio_memif_attribute),
|
|
GFP_KERNEL);
|
|
if (!mAudioMEMIF[i]) {
|
|
/* pr_debug("Failed to
|
|
* allocate private data\n");
|
|
*/
|
|
ret = -ENOMEM;
|
|
}
|
|
}
|
|
for (i = 0; i < Soc_Aud_Digital_Block_NUM_OF_MEM_INTERFACE;
|
|
i++) {
|
|
AFE_Mem_Control_context[i] = devm_kzalloc(pDev,
|
|
sizeof(struct afe_mem_control_t), GFP_KERNEL);
|
|
if (!AFE_Mem_Control_context[i]) {
|
|
/* pr_debug("Failed to
|
|
* allocate private data\n");
|
|
*/
|
|
ret = -ENOMEM;
|
|
}
|
|
AFE_Mem_Control_context[i]->substreamL = NULL;
|
|
spin_lock_init(
|
|
&AFE_Mem_Control_context[i]->substream_lock);
|
|
}
|
|
|
|
for (i = 0; i < Soc_Aud_Digital_Block_NUM_OF_MEM_INTERFACE;
|
|
i++) {
|
|
Audio_dma_buf[i] =
|
|
devm_kzalloc(pDev,
|
|
sizeof(Audio_dma_buf), GFP_KERNEL);
|
|
if (!Audio_dma_buf[i]) {
|
|
/* pr_debug("Failed to
|
|
* allocate private data\n");
|
|
*/
|
|
ret = -ENOMEM;
|
|
}
|
|
}
|
|
memset((void *)&AFE_dL_Abnormal_context, 0,
|
|
sizeof(struct afe_dl_abnormal_control_t));
|
|
memset((void *)&mtk_dais, 0, sizeof(mtk_dais));
|
|
}
|
|
|
|
AudioDaiBtStatus = false;
|
|
AudioAdcI2SStatus = false;
|
|
Audio2ndAdcI2SStatus = false;
|
|
AudioMrgStatus = false;
|
|
InitSramManager(pDev, SramBlockSize);
|
|
init_irq_manager();
|
|
|
|
PowerDownAllI2SDiv();
|
|
|
|
init_afe_ops();
|
|
if (s_afe_platform_ops->init_platform != NULL)
|
|
s_afe_platform_ops->init_platform();
|
|
/* set APLL clock setting */
|
|
AfeControlMutexUnLock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool ResetAfeControl(void)
|
|
{
|
|
int i = 0;
|
|
|
|
AfeControlMutexLock();
|
|
mAudioInit = false;
|
|
memset((void *)(mAudioMrg), 0, sizeof(struct audio_mrg_if));
|
|
memset((void *)(AudioDaiBt), 0, sizeof(struct audio_digital_dai_bt));
|
|
|
|
for (i = 0; i < Soc_Aud_Digital_Block_NUM_OF_DIGITAL_BLOCK; i++)
|
|
memset((void *)(mAudioMEMIF[i]), 0,
|
|
sizeof(struct audio_memif_attribute));
|
|
|
|
for (i = 0; i < Soc_Aud_Digital_Block_NUM_OF_MEM_INTERFACE; i++)
|
|
memset((void *)(AFE_Mem_Control_context[i]), 0,
|
|
sizeof(struct afe_mem_control_t));
|
|
|
|
AfeControlMutexUnLock();
|
|
|
|
return true;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* Register_aud_irq
|
|
*
|
|
* DESCRIPTION
|
|
* IRQ handler
|
|
*
|
|
*****************************************************************************
|
|
*/
|
|
bool Register_Aud_Irq(void *dev, unsigned int afe_irq_number)
|
|
{
|
|
int ret;
|
|
|
|
#ifdef CONFIG_OF
|
|
ret = request_irq(afe_irq_number, AudDrv_IRQ_handler, IRQF_TRIGGER_LOW,
|
|
"Afe_ISR_Handle", dev);
|
|
#else
|
|
ret = request_irq(MT6735_AFE_MCU_IRQ_LINE, AudDrv_IRQ_handler,
|
|
IRQF_TRIGGER_LOW, "Afe_ISR_Handle", dev);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static unsigned int get_mcu_irq_mask(void)
|
|
{
|
|
int index = 0;
|
|
const struct Aud_RegBitsInfo *irq_status;
|
|
enum Soc_Aud_IRQ_PURPOSE purpose;
|
|
|
|
if (irq_mcu_mask == 0) {
|
|
for (index = 0; index < Soc_Aud_IRQ_MCU_MODE_NUM; index++) {
|
|
irq_status = &GetIRQCtrlReg(index)->status;
|
|
purpose = GetIRQCtrlReg(index)->irqPurpose;
|
|
if (irq_status->reg == AFE_REG_UNDEFINED)
|
|
continue;
|
|
|
|
irq_mcu_mask |= (purpose == Soc_Aud_IRQ_MCU)
|
|
<< irq_status->sbit;
|
|
}
|
|
}
|
|
return irq_mcu_mask;
|
|
}
|
|
|
|
int AudDrv_DSP_IRQ_handler(void *PrivateData)
|
|
{
|
|
if (mAudioMEMIF[Soc_Aud_Digital_Block_MEM_DL1]->mState == true)
|
|
Auddrv_DSP_DL1_Interrupt_Handler(PrivateData);
|
|
return 0;
|
|
}
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_IRQ_handler / AudDrv_magic_tasklet
|
|
*
|
|
* DESCRIPTION
|
|
* IRQ handler
|
|
*
|
|
*****************************************************************************
|
|
*/
|
|
irqreturn_t AudDrv_IRQ_handler(int irq, void *dev_id)
|
|
{
|
|
/* unsigned long flags; */
|
|
kal_uint32 u4RegValue;
|
|
kal_uint32 irq_mcu_en;
|
|
kal_uint32 irq_scp_en = 0;
|
|
kal_uint32 irq_temp_enable;
|
|
unsigned int irqIndex = 0;
|
|
unsigned int mcu_mask = get_mcu_irq_mask();
|
|
const struct Aud_RegBitsInfo *irqOnReg, *irqEnReg, *irqStatusReg,
|
|
*irqMcuEnReg, *irqScpEnReg;
|
|
|
|
u4RegValue = Afe_Get_Reg(AFE_IRQ_MCU_STATUS) & mcu_mask;
|
|
irqMcuEnReg = GetIRQPurposeReg(Soc_Aud_IRQ_MCU);
|
|
irq_mcu_en = Afe_Get_Reg(irqMcuEnReg->reg);
|
|
|
|
/* here is error handle , for interrupt is trigger but not status ,
|
|
* clear all interrupt with bit 6
|
|
*/
|
|
if (u4RegValue == 0) {
|
|
|
|
irqScpEnReg = GetIRQPurposeReg(Soc_Aud_IRQ_CM4);
|
|
if (irqScpEnReg->reg != AFE_REG_UNDEFINED) {
|
|
irq_scp_en = Afe_Get_Reg(irqScpEnReg->reg);
|
|
irq_scp_en &= irqScpEnReg->mask;
|
|
Afe_Set_Reg(AFE_IRQ_MCU_CLR, irq_scp_en, irq_scp_en);
|
|
}
|
|
|
|
/* only clear IRQ which is sent to MCU */
|
|
irq_mcu_en &= irqMcuEnReg->mask;
|
|
Afe_Set_Reg(AFE_IRQ_MCU_CLR, irq_mcu_en, irq_mcu_en);
|
|
|
|
irqcount++;
|
|
|
|
if (irqcount > AudioInterruptLimiter) {
|
|
for (irqIndex = 0; irqIndex < Soc_Aud_IRQ_MCU_MODE_NUM;
|
|
irqIndex++) {
|
|
if (GetIRQCtrlReg(irqIndex)->irqPurpose !=
|
|
Soc_Aud_IRQ_MCU)
|
|
continue;
|
|
|
|
irqEnReg = &GetIRQCtrlReg(irqIndex)->en;
|
|
if (irq_mcu_en & (1 << irqEnReg->sbit)) {
|
|
irqOnReg = &GetIRQCtrlReg(irqIndex)->on;
|
|
Afe_Set_Reg(irqOnReg->reg,
|
|
0 << irqOnReg->sbit,
|
|
irqOnReg->mask
|
|
<< irqOnReg->sbit);
|
|
}
|
|
}
|
|
irqcount = 0;
|
|
}
|
|
|
|
pr_debug("%s(), [AudioWarn] u4RegValue = 0x%x, irqcount = %d, irq_mcu_en = 0x%x irq_scp_en = 0x%x\n",
|
|
__func__,
|
|
u4RegValue, irqcount, irq_mcu_en, irq_scp_en);
|
|
|
|
goto AudDrv_IRQ_handler_exit;
|
|
}
|
|
|
|
/* clear irq */
|
|
/* IRQs need to be enabled before clear */
|
|
irq_temp_enable = u4RegValue & (~irq_mcu_en);
|
|
Afe_Set_Reg(irqMcuEnReg->reg, irq_temp_enable, irq_temp_enable);
|
|
|
|
Afe_Set_Reg(AFE_IRQ_MCU_CLR, u4RegValue, mcu_mask);
|
|
|
|
/* Disable the IRQs are temp enabled */
|
|
Afe_Set_Reg(irqMcuEnReg->reg, 0, irq_temp_enable);
|
|
|
|
/*call each IRQ handler function*/
|
|
for (irqIndex = 0; irqIndex < Soc_Aud_IRQ_MCU_MODE_NUM; irqIndex++) {
|
|
if (GetIRQCtrlReg(irqIndex)->irqPurpose != Soc_Aud_IRQ_MCU)
|
|
continue;
|
|
|
|
irqStatusReg = &GetIRQCtrlReg(irqIndex)->status;
|
|
if (u4RegValue & (0x1 << irqStatusReg->sbit))
|
|
RunIRQHandler(irqIndex);
|
|
}
|
|
|
|
AudDrv_IRQ_handler_exit:
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
void EnableAPLLTunerbySampleRate(unsigned int SampleRate)
|
|
{
|
|
if (GetApllbySampleRate(SampleRate) == Soc_Aud_APLL1) {
|
|
APLL1TunerCounter++;
|
|
if (APLL1TunerCounter == 1) {
|
|
Afe_Set_Reg(AFE_APLL1_TUNER_CFG, 0x00000832,
|
|
0x0000FFF7);
|
|
Afe_Set_Reg(AFE_APLL1_TUNER_CFG, 0x1, 0x1);
|
|
}
|
|
} else if (GetApllbySampleRate(SampleRate) == Soc_Aud_APLL2) {
|
|
APLL2TunerCounter++;
|
|
if (APLL2TunerCounter == 1) {
|
|
Afe_Set_Reg(AFE_APLL2_TUNER_CFG, 0x00000634,
|
|
0x0000FFF7);
|
|
Afe_Set_Reg(AFE_APLL2_TUNER_CFG, 0x1, 0x1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DisableAPLLTunerbySampleRate(unsigned int SampleRate)
|
|
{
|
|
if (GetApllbySampleRate(SampleRate) == Soc_Aud_APLL1) {
|
|
APLL1TunerCounter--;
|
|
|
|
if (APLL1TunerCounter == 0) {
|
|
Afe_Set_Reg(AFE_APLL1_TUNER_CFG, 0x0, 0x1);
|
|
} else if (APLL1TunerCounter < 0) {
|
|
pr_debug("%s(), warning, APLL1TunerCounter<0",
|
|
__func__);
|
|
APLL1TunerCounter = 0;
|
|
}
|
|
|
|
} else if (GetApllbySampleRate(SampleRate) == Soc_Aud_APLL2) {
|
|
APLL2TunerCounter--;
|
|
|
|
if (APLL2TunerCounter == 0) {
|
|
Afe_Set_Reg(AFE_APLL2_TUNER_CFG, 0x0, 0x1);
|
|
} else if (APLL2TunerCounter < 0) {
|
|
pr_debug("%s(), warning, APLL2TunerCounter<0",
|
|
__func__);
|
|
APLL2TunerCounter = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool CheckMemIfEnable(void)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = 0; i < Soc_Aud_Digital_Block_NUM_OF_DIGITAL_BLOCK; i++) {
|
|
if ((mAudioMEMIF[i]->mState) == true) {
|
|
/* pr_debug("CheckMemIfEnable == true\n"); */
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/* pr_debug("CheckMemIfEnable == false\n"); */
|
|
return false;
|
|
}
|
|
|
|
/* record VOW status for AFE GPIO control */
|
|
void SetVOWStatus(bool bEnable)
|
|
{
|
|
unsigned long flags;
|
|
|
|
if (mVOWStatus != bEnable) {
|
|
spin_lock_irqsave(&afe_control_lock, flags);
|
|
mVOWStatus = bEnable;
|
|
pr_debug("%s(), mVOWStatus= %d\n", __func__, mVOWStatus);
|
|
spin_unlock_irqrestore(&afe_control_lock, flags);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* Auddrv_Reg_map
|
|
*
|
|
* DESCRIPTION
|
|
* Auddrv_Reg_map
|
|
*
|
|
*****************************************************************************
|
|
*/
|
|
static bool afe_on;
|
|
void EnableAfe(bool bEnable)
|
|
{
|
|
unsigned long flags;
|
|
bool MemEnable = false;
|
|
|
|
spin_lock_irqsave(&afe_control_lock, flags);
|
|
MemEnable = CheckMemIfEnable();
|
|
|
|
if (false == bEnable && false == MemEnable) {
|
|
if (afe_on && mtk_soc_always_hd) {
|
|
DisableAPLLTunerbySampleRate(44100);
|
|
DisableAPLLTunerbySampleRate(48000);
|
|
}
|
|
|
|
set_chip_afe_enable(false);
|
|
|
|
if (afe_on && mtk_soc_always_hd) {
|
|
DisableALLbySampleRate(44100);
|
|
DisableALLbySampleRate(48000);
|
|
}
|
|
|
|
afe_on = false;
|
|
} else if (true == bEnable && true == MemEnable) {
|
|
if (!afe_on && mtk_soc_always_hd) {
|
|
EnableALLbySampleRate(44100);
|
|
EnableALLbySampleRate(48000);
|
|
}
|
|
|
|
set_chip_afe_enable(true);
|
|
|
|
if (!afe_on && mtk_soc_always_hd) {
|
|
EnableAPLLTunerbySampleRate(44100);
|
|
EnableAPLLTunerbySampleRate(48000);
|
|
}
|
|
|
|
afe_on = true;
|
|
}
|
|
|
|
spin_unlock_irqrestore(&afe_control_lock, flags);
|
|
}
|
|
|
|
unsigned int SampleRateTransform(unsigned int sampleRate,
|
|
enum soc_aud_digital_block audBlock)
|
|
{
|
|
switch (audBlock) {
|
|
case Soc_Aud_Digital_Block_ADDA_DL:
|
|
return ADDADLSampleRateTransform(sampleRate);
|
|
case Soc_Aud_Digital_Block_ADDA_UL:
|
|
return ADDAULSampleRateTransform(sampleRate);
|
|
case Soc_Aud_Digital_Block_MEM_MOD_DAI:
|
|
case Soc_Aud_Digital_Block_MEM_DAI:
|
|
return DAIMEMIFSampleRateTransform(sampleRate);
|
|
case Soc_Aud_Digital_Block_MODEM_PCM_1_O:
|
|
case Soc_Aud_Digital_Block_MODEM_PCM_2_O:
|
|
return MDSampleRateTransform(sampleRate);
|
|
default:
|
|
return GeneralSampleRateTransform(sampleRate);
|
|
}
|
|
}
|
|
|
|
unsigned int GeneralSampleRateTransform(unsigned int sampleRate)
|
|
{
|
|
switch (sampleRate) {
|
|
case 8000:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_8K;
|
|
case 11025:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_11K;
|
|
case 12000:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_12K;
|
|
case 16000:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_16K;
|
|
case 22050:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_22K;
|
|
case 24000:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_24K;
|
|
case 32000:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_32K;
|
|
case 44100:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_44K;
|
|
case 48000:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_48K;
|
|
case 88200:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_88K;
|
|
case 96000:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_96K;
|
|
case 130000:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_130K;
|
|
case 176400:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_174K;
|
|
case 192000:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_192K;
|
|
case 260000:
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_260K;
|
|
default:
|
|
pr_warn("[AudioWarn] %s() sampleRate(%d) is invalid, use 44.1kHz!!!\n",
|
|
__func__, sampleRate);
|
|
return Soc_Aud_I2S_SAMPLERATE_I2S_44K;
|
|
}
|
|
}
|
|
|
|
unsigned int DAIMEMIFSampleRateTransform(unsigned int sampleRate)
|
|
{
|
|
switch (sampleRate) {
|
|
case 8000:
|
|
return Soc_Aud_DAI_MEMIF_SAMPLERATE_8K;
|
|
case 16000:
|
|
return Soc_Aud_DAI_MEMIF_SAMPLERATE_16K;
|
|
case 32000:
|
|
return Soc_Aud_DAI_MEMIF_SAMPLERATE_32K;
|
|
default:
|
|
pr_warn("[AudioWarn] %s() sampleRate(%d) is invalid, use 16kHz!!!\n",
|
|
__func__, sampleRate);
|
|
return Soc_Aud_DAI_MEMIF_SAMPLERATE_16K;
|
|
}
|
|
}
|
|
|
|
unsigned int ADDADLSampleRateTransform(unsigned int sampleRate)
|
|
{
|
|
switch (sampleRate) {
|
|
case 8000:
|
|
return Soc_Aud_ADDA_DL_SAMPLERATE_8K;
|
|
case 11025:
|
|
return Soc_Aud_ADDA_DL_SAMPLERATE_11K;
|
|
case 12000:
|
|
return Soc_Aud_ADDA_DL_SAMPLERATE_12K;
|
|
case 16000:
|
|
return Soc_Aud_ADDA_DL_SAMPLERATE_16K;
|
|
case 22050:
|
|
return Soc_Aud_ADDA_DL_SAMPLERATE_22K;
|
|
case 24000:
|
|
return Soc_Aud_ADDA_DL_SAMPLERATE_24K;
|
|
case 32000:
|
|
return Soc_Aud_ADDA_DL_SAMPLERATE_32K;
|
|
case 44100:
|
|
return Soc_Aud_ADDA_DL_SAMPLERATE_44K;
|
|
case 48000:
|
|
return Soc_Aud_ADDA_DL_SAMPLERATE_48K;
|
|
case 96000:
|
|
return Soc_Aud_ADDA_DL_SAMPLERATE_96K;
|
|
case 192000:
|
|
return Soc_Aud_ADDA_DL_SAMPLERATE_192K;
|
|
default:
|
|
pr_warn("[AudioWarn] %s() sampleRate(%d) is invalid, use 44.1kHz!!!\n",
|
|
__func__, sampleRate);
|
|
return Soc_Aud_ADDA_DL_SAMPLERATE_44K;
|
|
}
|
|
}
|
|
|
|
unsigned int ADDAULSampleRateTransform(unsigned int sampleRate)
|
|
{
|
|
switch (sampleRate) {
|
|
case 8000:
|
|
return Soc_Aud_ADDA_UL_SAMPLERATE_8K;
|
|
case 16000:
|
|
return Soc_Aud_ADDA_UL_SAMPLERATE_16K;
|
|
case 32000:
|
|
return Soc_Aud_ADDA_UL_SAMPLERATE_32K;
|
|
case 48000:
|
|
return Soc_Aud_ADDA_UL_SAMPLERATE_48K;
|
|
case 96000:
|
|
return Soc_Aud_ADDA_UL_SAMPLERATE_96K;
|
|
case 192000:
|
|
return Soc_Aud_ADDA_UL_SAMPLERATE_192K;
|
|
default:
|
|
pr_warn("[AudioWarn] %s() sampleRate(%d) is invalid, use 48kHz(24bit)!!!\n",
|
|
__func__, sampleRate);
|
|
return Soc_Aud_ADDA_UL_SAMPLERATE_48K;
|
|
}
|
|
}
|
|
|
|
unsigned int MDSampleRateTransform(unsigned int sampleRate)
|
|
{
|
|
switch (sampleRate) {
|
|
case 8000:
|
|
return Soc_Aud_PCM_MODE_PCM_MODE_8K;
|
|
case 16000:
|
|
return Soc_Aud_PCM_MODE_PCM_MODE_16K;
|
|
case 32000:
|
|
return Soc_Aud_PCM_MODE_PCM_MODE_32K;
|
|
case 48000:
|
|
return Soc_Aud_PCM_MODE_PCM_MODE_48K;
|
|
default:
|
|
pr_warn("%s(), rate %u not support, use 16k\n", __func__,
|
|
sampleRate);
|
|
return Soc_Aud_PCM_MODE_PCM_MODE_16K;
|
|
}
|
|
}
|
|
|
|
bool Set2ndI2SOutAttribute(uint32_t sampleRate)
|
|
{
|
|
pr_debug("+%s(), sampleRate = %d\n", __func__, sampleRate);
|
|
m2ndI2Sout->mLR_SWAP = Soc_Aud_LR_SWAP_NO_SWAP;
|
|
m2ndI2Sout->mI2S_SLAVE = Soc_Aud_I2S_SRC_MASTER_MODE;
|
|
m2ndI2Sout->mINV_LRCK = Soc_Aud_INV_LRCK_NO_INVERSE;
|
|
m2ndI2Sout->mI2S_FMT = Soc_Aud_I2S_FORMAT_I2S;
|
|
m2ndI2Sout->mI2S_WLEN = Soc_Aud_I2S_WLEN_WLEN_16BITS;
|
|
m2ndI2Sout->mI2S_HDEN = Soc_Aud_NORMAL_CLOCK;
|
|
m2ndI2Sout->mI2S_SAMPLERATE = sampleRate;
|
|
Set2ndI2SOut(m2ndI2Sout);
|
|
return true;
|
|
}
|
|
|
|
bool Set2ndI2SOut(struct audio_digital_i2s *DigtalI2S)
|
|
{
|
|
unsigned int u32AudioI2S = 0;
|
|
|
|
memcpy((void *)m2ndI2Sout, (void *)DigtalI2S,
|
|
sizeof(struct audio_digital_i2s));
|
|
u32AudioI2S = SampleRateTransform(m2ndI2Sout->mI2S_SAMPLERATE,
|
|
Soc_Aud_Digital_Block_I2S_OUT_2)
|
|
<< 8;
|
|
u32AudioI2S |= m2ndI2Sout->mLR_SWAP << 31;
|
|
u32AudioI2S |= m2ndI2Sout->mI2S_HDEN << 12;
|
|
u32AudioI2S |= m2ndI2Sout->mINV_LRCK << 5;
|
|
u32AudioI2S |= m2ndI2Sout->mI2S_FMT << 3;
|
|
u32AudioI2S |= m2ndI2Sout->mI2S_WLEN << 1;
|
|
Afe_Set_Reg(AFE_I2S_CON3, u32AudioI2S, AFE_MASK_ALL);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Set2ndI2SOutEnable(bool benable)
|
|
{
|
|
if (benable)
|
|
Afe_Set_Reg(AFE_I2S_CON3, 0x1, 0x1);
|
|
else
|
|
Afe_Set_Reg(AFE_I2S_CON3, 0x0, 0x1);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SetDaiBt(struct audio_digital_dai_bt *mAudioDaiBt)
|
|
{
|
|
AudioDaiBt->mBT_LEN = mAudioDaiBt->mBT_LEN;
|
|
AudioDaiBt->mUSE_MRGIF_INPUT = mAudioDaiBt->mUSE_MRGIF_INPUT;
|
|
AudioDaiBt->mDAI_BT_MODE = mAudioDaiBt->mDAI_BT_MODE;
|
|
AudioDaiBt->mDAI_DEL = mAudioDaiBt->mDAI_DEL;
|
|
AudioDaiBt->mBT_LEN = mAudioDaiBt->mBT_LEN;
|
|
AudioDaiBt->mDATA_RDY = mAudioDaiBt->mDATA_RDY;
|
|
AudioDaiBt->mBT_SYNC = mAudioDaiBt->mBT_SYNC;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SetDaiBtEnable(bool bEanble)
|
|
{
|
|
pr_debug("%s bEanble = %d\n", __func__, bEanble);
|
|
return set_chip_dai_bt_enable(bEanble, AudioDaiBt, mAudioMrg);
|
|
}
|
|
|
|
bool GetMrgI2SEnable(void)
|
|
{
|
|
return mAudioMEMIF[Soc_Aud_Digital_Block_MRG_I2S_OUT]->mState;
|
|
}
|
|
|
|
bool SetMrgI2SEnable(bool bEnable, unsigned int sampleRate)
|
|
{
|
|
unsigned int sampleRateType;
|
|
|
|
sampleRateType = SampleRateTransform(sampleRate,
|
|
Soc_Aud_Digital_Block_MRG_I2S_OUT);
|
|
|
|
pr_debug("%s bEnable = %d\n", __func__, bEnable);
|
|
|
|
if (bEnable == true) {
|
|
/* To enable MrgI2S */
|
|
if (mAudioMrg->MrgIf_En == true) {
|
|
/* Merge Interface already turn on. */
|
|
/* if sample Rate change, then it need to restart with
|
|
* new setting; else do nothing.
|
|
*/
|
|
if (mAudioMrg->Mrg_I2S_SampleRate != sampleRateType) {
|
|
/* Turn off Merge Interface first to switch I2S
|
|
* sampling rate
|
|
*/
|
|
Afe_Set_Reg(AFE_MRGIF_CON, 0,
|
|
1 << 16); /* Turn off I2S */
|
|
if (AudioDaiBt->mDAIBT_ON == true)
|
|
Afe_Set_Reg(
|
|
AFE_DAIBT_CON0, 0,
|
|
0x1); /* Turn off DAIBT first */
|
|
udelay(100);
|
|
Afe_Set_Reg(AFE_MRGIF_CON, 0,
|
|
0x1); /* Turn off Merge Interface */
|
|
udelay(100);
|
|
Afe_Set_Reg(AFE_MRGIF_CON, 1,
|
|
0x1); /* Turn on Merge Interface */
|
|
if (AudioDaiBt->mDAIBT_ON == true) {
|
|
Afe_Set_Reg(AFE_DAIBT_CON0,
|
|
AudioDaiBt->mDAI_BT_MODE
|
|
<< 9,
|
|
0x1 << 9);
|
|
/* use merge */
|
|
Afe_Set_Reg(AFE_DAIBT_CON0, 0x1 << 12,
|
|
0x1 << 12); /* use merge */
|
|
Afe_Set_Reg(AFE_DAIBT_CON0, 0x1 << 3,
|
|
0x1 << 3); /* data ready */
|
|
Afe_Set_Reg(AFE_DAIBT_CON0, 0x3,
|
|
0x3); /* Turn on DAIBT */
|
|
}
|
|
mAudioMrg->Mrg_I2S_SampleRate = sampleRateType;
|
|
Afe_Set_Reg(AFE_MRGIF_CON,
|
|
mAudioMrg->Mrg_I2S_SampleRate << 20,
|
|
0xF00000);
|
|
/* set Mrg_I2S Samping Rate */
|
|
Afe_Set_Reg(AFE_MRGIF_CON, 1 << 16,
|
|
1 << 16); /* set Mrg_I2S enable */
|
|
}
|
|
} else {
|
|
/* turn on merge Interface from off state */
|
|
mAudioMrg->Mrg_I2S_SampleRate = sampleRateType;
|
|
Afe_Set_Reg(AFE_MRGIF_CON,
|
|
mAudioMrg->Mrg_I2S_SampleRate << 20,
|
|
0xF << 20);
|
|
|
|
/* set Mrg_I2S Samping rates */
|
|
Afe_Set_Reg(AFE_MRGIF_CON, 1 << 16,
|
|
1 << 16); /* set Mrg_I2S enable */
|
|
udelay(100);
|
|
Afe_Set_Reg(AFE_MRGIF_CON, 1,
|
|
0x1); /* Turn on Merge Interface */
|
|
udelay(100);
|
|
|
|
if (AudioDaiBt->mDAIBT_ON == true) {
|
|
Afe_Set_Reg(AFE_DAIBT_CON0,
|
|
AudioDaiBt->mDAI_BT_MODE << 9,
|
|
0x1 << 9);
|
|
|
|
/* use merge */
|
|
Afe_Set_Reg(AFE_DAIBT_CON0, 0x1 << 12,
|
|
0x1 << 12); /* use merge */
|
|
Afe_Set_Reg(AFE_DAIBT_CON0, 0x1 << 3,
|
|
0x1 << 3); /* data ready */
|
|
Afe_Set_Reg(AFE_DAIBT_CON0, 0x3,
|
|
0x3); /* Turn on DAIBT */
|
|
}
|
|
}
|
|
mAudioMrg->MrgIf_En = true;
|
|
mAudioMrg->Mergeif_I2S_Enable = true;
|
|
} else {
|
|
if (mAudioMrg->MrgIf_En == true) {
|
|
Afe_Set_Reg(AFE_MRGIF_CON, 0,
|
|
1 << 16); /* Turn off I2S */
|
|
if (AudioDaiBt->mDAIBT_ON == false) {
|
|
udelay(100);
|
|
/* DAIBT also not using, then it's OK to disable
|
|
* Merge Interface
|
|
*/
|
|
Afe_Set_Reg(AFE_MRGIF_CON, 0,
|
|
0x1); /* Turn off Merge Interface */
|
|
mAudioMrg->MrgIf_En = false;
|
|
}
|
|
}
|
|
mAudioMrg->Mergeif_I2S_Enable = false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Set2ndI2SAdcIn(struct audio_digital_i2s *DigtalI2S)
|
|
{
|
|
/* 6752 todo? */
|
|
return true;
|
|
}
|
|
|
|
bool SetExtI2SAdcIn(struct audio_digital_i2s *DigtalI2S)
|
|
{
|
|
unsigned int Audio_I2S_Adc = 0;
|
|
unsigned int sampleRateType;
|
|
|
|
sampleRateType = SampleRateTransform(DigtalI2S->mI2S_SAMPLERATE,
|
|
Soc_Aud_Digital_Block_I2S_IN_ADC);
|
|
|
|
/* Set I2S_ADC_IN */
|
|
Audio_I2S_Adc |= (DigtalI2S->mLR_SWAP << 31);
|
|
Audio_I2S_Adc |= (DigtalI2S->mBuffer_Update_word << 24);
|
|
Audio_I2S_Adc |= (DigtalI2S->mINV_LRCK << 23);
|
|
Audio_I2S_Adc |= (DigtalI2S->mFpga_bit_test << 22);
|
|
Audio_I2S_Adc |= (DigtalI2S->mFpga_bit << 21);
|
|
Audio_I2S_Adc |= (DigtalI2S->mloopback << 20);
|
|
Audio_I2S_Adc |= (sampleRateType << 8);
|
|
Audio_I2S_Adc |= (DigtalI2S->mI2S_FMT << 3);
|
|
Audio_I2S_Adc |= (DigtalI2S->mI2S_WLEN << 1);
|
|
pr_debug("%s Audio_I2S_Adc = 0x%x", __func__, Audio_I2S_Adc);
|
|
Afe_Set_Reg(AFE_I2S_CON2, Audio_I2S_Adc, MASK_ALL);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SetExtI2SAdcInEnable(bool bEnable)
|
|
{
|
|
Afe_Set_Reg(AFE_I2S_CON2, bEnable, 0x1);
|
|
return true;
|
|
}
|
|
|
|
bool set_adc_in(unsigned int rate)
|
|
{
|
|
mtk_dais[Soc_Aud_Digital_Block_ADDA_UL].sample_rate = rate;
|
|
|
|
return set_chip_adc_in(rate);
|
|
}
|
|
|
|
bool set_adc2_in(unsigned int rate)
|
|
{
|
|
mtk_dais[Soc_Aud_Digital_Block_ADDA_UL2].sample_rate = rate;
|
|
|
|
return set_chip_adc2_in(rate);
|
|
}
|
|
|
|
int get_dai_rate(enum soc_aud_digital_block digitalBlock)
|
|
{
|
|
return mtk_dais[digitalBlock].sample_rate;
|
|
}
|
|
|
|
#ifdef AFE_CONNSYS_I2S_CON
|
|
int setConnsysI2SIn(struct audio_digital_i2s *mDigitalI2S)
|
|
{
|
|
unsigned int i2s_con = 0;
|
|
|
|
/* slave mode, rate is for asrc */
|
|
i2s_con |= (mDigitalI2S->mINV_LRCK << 7);
|
|
i2s_con |= (mDigitalI2S->mI2S_FMT << 3);
|
|
i2s_con |= (mDigitalI2S->mI2S_SLAVE << 2);
|
|
i2s_con |= (mDigitalI2S->mI2S_WLEN << 1);
|
|
i2s_con |= (mDigitalI2S->mI2S_IN_PAD_SEL << 28);
|
|
pr_debug("%s(), i2s_con= 0x%x", __func__, i2s_con);
|
|
Afe_Set_Reg(AFE_CONNSYS_I2S_CON, i2s_con, 0xfffffffe);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int setConnsysI2SInEnable(bool enable)
|
|
{
|
|
pr_debug("%s(), enable = %d", __func__, enable);
|
|
Afe_Set_Reg(AFE_CONNSYS_I2S_CON, enable, 0x1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int setConnsysI2SAsrc(bool bIsUseASRC, unsigned int dToSampleRate)
|
|
{
|
|
unsigned int rate = SampleRateTransform(
|
|
dToSampleRate, Soc_Aud_Digital_Block_I2S_IN_CONNSYS);
|
|
|
|
pr_debug("+%s() bIsUseASRC [%d] dToSampleRate [%d]\n", __func__,
|
|
bIsUseASRC, dToSampleRate);
|
|
|
|
Afe_Set_Reg(AFE_CONNSYS_I2S_CON, (bIsUseASRC ? 0 : 1) << 6, 0x1 << 6);
|
|
|
|
if (bIsUseASRC) {
|
|
AUDIO_ASSERT(
|
|
!(dToSampleRate == 44100 || dToSampleRate == 48000));
|
|
|
|
/* slave mode, set i2s for asrc */
|
|
Afe_Set_Reg(AFE_CONNSYS_I2S_CON, rate << 8, 0xf << 8);
|
|
|
|
if (dToSampleRate == 44100)
|
|
Afe_Set_Reg(AFE_ASRC_CONNSYS_CON14, 0x001B9000,
|
|
AFE_MASK_ALL);
|
|
else
|
|
Afe_Set_Reg(AFE_ASRC_CONNSYS_CON14, 0x001E0000,
|
|
AFE_MASK_ALL);
|
|
|
|
Afe_Set_Reg(AFE_ASRC_CONNSYS_CON15, 0x00140000, AFE_MASK_ALL);
|
|
Afe_Set_Reg(AFE_ASRC_CONNSYS_CON16, 0x00FF5987, AFE_MASK_ALL);
|
|
Afe_Set_Reg(AFE_ASRC_CONNSYS_CON17, 0x00007EF4, AFE_MASK_ALL);
|
|
Afe_Set_Reg(AFE_ASRC_CONNSYS_CON16, 0x00FF5986, AFE_MASK_ALL);
|
|
Afe_Set_Reg(AFE_ASRC_CONNSYS_CON16, 0x00FF5987, AFE_MASK_ALL);
|
|
|
|
/* 0:Stereo 1:Mono */
|
|
Afe_Set_Reg(AFE_ASRC_CONNSYS_CON13, 0, 1 << 16);
|
|
|
|
/* Calibration setting */
|
|
Afe_Set_Reg(AFE_ASRC_CONNSYS_CON20, 0x00036000, AFE_MASK_ALL);
|
|
Afe_Set_Reg(AFE_ASRC_CONNSYS_CON21, 0x0002FC00, AFE_MASK_ALL);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int setConnsysI2SEnable(bool enable)
|
|
{
|
|
if (enable) {
|
|
Afe_Set_Reg(AFE_ASRC_CONNSYS_CON0,
|
|
((1 << 6) | (1 << 4) | (1 << 0)),
|
|
((1 << 6) | (1 << 4) | (1 << 0)));
|
|
} else {
|
|
unsigned int dNeedDisableASM =
|
|
(Afe_Get_Reg(AFE_ASRC_CONNSYS_CON0) & 0x0030) ? 1 : 0;
|
|
|
|
Afe_Set_Reg(AFE_ASRC_CONNSYS_CON0, 0,
|
|
((1 << 6) | (1 << 4) | dNeedDisableASM));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#else
|
|
|
|
int setConnsysI2SIn(struct audio_digital_i2s *DigtalI2S)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
int setConnsysI2SInEnable(bool enable)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
int setConnsysI2SAsrc(bool bIsUseASRC, unsigned int dToSampleRate)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
int setConnsysI2SEnable(bool enable)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
#endif
|
|
|
|
bool setDmicPath(bool _enable)
|
|
{
|
|
unsigned int sample_rate =
|
|
mtk_dais[Soc_Aud_Digital_Block_ADDA_UL].sample_rate;
|
|
|
|
return setChipDmicPath(_enable, sample_rate);
|
|
}
|
|
|
|
bool EnableSineGen(unsigned int connection, bool direction, bool Enable)
|
|
{
|
|
bool ret = 0;
|
|
|
|
pr_debug("+%s(): connection = %d, direction = %d, Enable= %d\n",
|
|
__func__, connection, direction, Enable);
|
|
|
|
/* by platform to implement*/
|
|
if (s_afe_platform_ops != NULL) {
|
|
ret = s_afe_platform_ops->set_sinegen(connection, direction,
|
|
Enable);
|
|
} else {
|
|
pr_err("+%s(): No sine gen implementation, return false!\n",
|
|
__func__);
|
|
ret = false;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool SetSineGenSampleRate(unsigned int SampleRate)
|
|
{
|
|
return set_chip_sine_gen_sample_rate(SampleRate);
|
|
}
|
|
|
|
bool SetSineGenAmplitude(unsigned int ampDivide)
|
|
{
|
|
return set_chip_sine_gen_amplitude(ampDivide);
|
|
}
|
|
|
|
bool Set2ndI2SAdcEnable(bool bEnable)
|
|
{
|
|
/* 6752 todo? */
|
|
return true;
|
|
}
|
|
|
|
bool set_adc_enable(bool enable)
|
|
{
|
|
if (enable) {
|
|
/* Enable UL SRC order:
|
|
* UL clock (AUDIO_TOP_CON0) -> AFE (AFE_DAC_CON0) ->
|
|
* ADDA UL DL (AFE_ADDA_UL_DL_CON0) ->
|
|
* ADDA UL SRC (AFE_ADDA_UL_SRC_CON0)
|
|
*/
|
|
#ifdef CONFIG_FPGA_EARLY_PORTING
|
|
pr_debug("%s(), enable fpga clock divide by 4", __func__);
|
|
Afe_Set_Reg(FPGA_CFG0, 0x1 << 1, 0x1 << 1);
|
|
#endif
|
|
if (mtk_dais[Soc_Aud_Digital_Block_ADDA_UL].sample_rate > 48000)
|
|
AudDrv_ADC_Hires_Clk_On();
|
|
else
|
|
AudDrv_ADC_Clk_On();
|
|
|
|
SetADDAEnable(true);
|
|
set_ul_src_enable(true);
|
|
} else {
|
|
/* Disable UL SRC order: (reverse)
|
|
* ADDA UL SRC (AFE_ADDA_UL_SRC_CON0) ->
|
|
* ADDA UL DL (AFE_ADDA_UL_DL_CON0) ->
|
|
* AFE (AFE_DAC_CON0) -> UL clock (AUDIO_TOP_CON0)
|
|
*/
|
|
set_ul_src_enable(false);
|
|
SetADDAEnable(false);
|
|
|
|
#ifdef CONFIG_FPGA_EARLY_PORTING
|
|
pr_debug("%s(), disable fpga clock divide by 4", __func__);
|
|
Afe_Set_Reg(FPGA_CFG0, 0x0 << 1, 0x1 << 1);
|
|
#endif
|
|
/* should delayed 1/fs(smallest is 8k) = 125us before afe off */
|
|
usleep_range(125, 150);
|
|
if (mtk_dais[Soc_Aud_Digital_Block_ADDA_UL].sample_rate > 48000)
|
|
AudDrv_ADC_Hires_Clk_Off();
|
|
else
|
|
AudDrv_ADC_Clk_Off();
|
|
|
|
}
|
|
AudDrv_GPIO_Request(enable, Soc_Aud_Digital_Block_ADDA_UL);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool set_adc2_enable(bool enable)
|
|
{
|
|
if (enable) {
|
|
/* Enable UL SRC order:
|
|
* UL clock (AUDIO_TOP_CON0) -> AFE (AFE_DAC_CON0) ->
|
|
* ADDA UL DL (AFE_ADDA_UL_DL_CON0) ->
|
|
* ADDA UL SRC (AFE_ADDA_UL_SRC_CON0)
|
|
*/
|
|
#ifdef CONFIG_FPGA_EARLY_PORTING
|
|
pr_debug("%s(), enable fpga clock divide by 4", __func__);
|
|
Afe_Set_Reg(FPGA_CFG0, 0x1 << 1, 0x1 << 1);
|
|
#endif
|
|
if (mtk_dais[Soc_Aud_Digital_Block_ADDA_UL2].sample_rate >
|
|
48000)
|
|
AudDrv_ADC2_Hires_Clk_On();
|
|
else
|
|
AudDrv_ADC2_Clk_On();
|
|
|
|
SetADDAEnable(true);
|
|
set_ul2_src_enable(true);
|
|
} else {
|
|
/* Disable UL SRC order: (reverse)
|
|
* ADDA UL SRC (AFE_ADDA_UL_SRC_CON0) ->
|
|
* ADDA UL DL (AFE_ADDA_UL_DL_CON0) ->
|
|
* AFE (AFE_DAC_CON0) -> UL clock (AUDIO_TOP_CON0)
|
|
*/
|
|
set_ul2_src_enable(false);
|
|
SetADDAEnable(false);
|
|
#ifdef CONFIG_FPGA_EARLY_PORTING
|
|
pr_debug("%s(), disable fpga clock divide by 4", __func__);
|
|
Afe_Set_Reg(FPGA_CFG0, 0x0 << 1, 0x1 << 1);
|
|
#endif
|
|
/* should delayed 1/fs(smallest is 8k) = 125us before afe off */
|
|
usleep_range(125, 150);
|
|
if (mtk_dais[Soc_Aud_Digital_Block_ADDA_UL2].sample_rate >
|
|
48000)
|
|
AudDrv_ADC2_Hires_Clk_Off();
|
|
else
|
|
AudDrv_ADC2_Clk_Off();
|
|
|
|
}
|
|
AudDrv_GPIO_Request(enable, Soc_Aud_Digital_Block_ADDA_UL2);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Set2ndI2SEnable(bool bEnable)
|
|
{
|
|
Afe_Set_Reg(AFE_I2S_CON, bEnable, 0x1);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SetI2SDacOut(unsigned int SampleRate, bool lowjitter, bool I2SWLen)
|
|
{
|
|
unsigned int Audio_I2S_Dac = 0;
|
|
|
|
/* force use 32bit for speaker codec */
|
|
I2SWLen = Soc_Aud_I2S_WLEN_WLEN_32BITS;
|
|
|
|
CleanPreDistortion();
|
|
SetDLSrc2(SampleRate);
|
|
|
|
Audio_I2S_Dac |= (Soc_Aud_LR_SWAP_NO_SWAP << 31);
|
|
Audio_I2S_Dac |= (0 << 16); /* select source from o28o29 */
|
|
Audio_I2S_Dac |= (lowjitter << 12); /* low gitter mode */
|
|
Audio_I2S_Dac |= (SampleRateTransform(SampleRate,
|
|
Soc_Aud_Digital_Block_I2S_OUT_DAC)
|
|
<< 8);
|
|
Audio_I2S_Dac |= (Soc_Aud_INV_LRCK_NO_INVERSE << 5);
|
|
Audio_I2S_Dac |= (Soc_Aud_I2S_FORMAT_I2S << 3);
|
|
Audio_I2S_Dac |= (I2SWLen << 1);
|
|
Afe_Set_Reg(AFE_I2S_CON1, Audio_I2S_Dac, MASK_ALL);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SetHwDigitalGainMode(enum soc_aud_digital_block AudBlock,
|
|
unsigned int SampleRate,
|
|
unsigned int SamplePerStep)
|
|
{
|
|
pr_debug("+%s(), AudBlock = %d, SampleRate = %d, SamplePerStep= %d\n",
|
|
__func__, AudBlock, SampleRate, SamplePerStep);
|
|
|
|
return set_chip_hw_digital_gain_mode(AudBlock, SampleRate,
|
|
SamplePerStep);
|
|
}
|
|
|
|
bool SetHwDigitalGainEnable(enum soc_aud_digital_block AudBlock, bool Enable)
|
|
{
|
|
pr_debug("+%s(), AudBlock = %d, Enable = %d\n",
|
|
__func__, AudBlock, Enable);
|
|
|
|
return set_chip_hw_digital_gain_enable(AudBlock, Enable);
|
|
}
|
|
|
|
bool SetHwDigitalGain(enum soc_aud_digital_block AudBlock, unsigned int Gain)
|
|
{
|
|
pr_debug("+%s(), AudBlock = %d, Gain = 0x%x\n",
|
|
__func__, AudBlock, Gain);
|
|
|
|
return set_chip_hw_digital_gain(AudBlock, Gain);
|
|
}
|
|
|
|
bool SetModemPcmConfig(int modem_index,
|
|
struct audio_digital_pcm p_modem_pcm_attribute)
|
|
{
|
|
SetChipModemPcmConfig(modem_index, p_modem_pcm_attribute);
|
|
return true;
|
|
}
|
|
|
|
bool SetModemPcmEnable(int modem_index, bool modem_pcm_on)
|
|
{
|
|
bool ret;
|
|
|
|
pr_debug("+%s(), modem_index = %d, modem_pcm_on = %d\n", __func__,
|
|
modem_index, modem_pcm_on);
|
|
|
|
ret = SetChipModemPcmEnable(modem_index, modem_pcm_on);
|
|
|
|
if (modem_index == MODEM_1)
|
|
mAudioMEMIF[Soc_Aud_Digital_Block_MODEM_PCM_1_O]->mState =
|
|
modem_pcm_on;
|
|
else if (modem_index == MODEM_2 || modem_index == MODEM_EXTERNAL)
|
|
mAudioMEMIF[Soc_Aud_Digital_Block_MODEM_PCM_2_O]->mState =
|
|
modem_pcm_on;
|
|
else
|
|
pr_info("%s(), no such modem_index: %d!!", __func__,
|
|
modem_index);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool SetMemoryPathEnableReg(unsigned int Aud_block, bool bEnable)
|
|
{
|
|
unsigned int offset = GetEnableAudioBlockRegOffset(Aud_block);
|
|
unsigned int reg = GetEnableAudioBlockRegAddr(Aud_block);
|
|
|
|
if (reg == 0) {
|
|
pr_err("%s(), no such memory path enable bit!!", __func__);
|
|
return false;
|
|
}
|
|
Afe_Set_Reg(reg, bEnable << offset, 1 << offset);
|
|
return true;
|
|
}
|
|
|
|
bool SetMemoryPathEnable(unsigned int Aud_block, bool bEnable)
|
|
{
|
|
/* pr_debug("%s Aud_block = %d bEnable = %d\n", __func__, Aud_block,
|
|
* bEnable);
|
|
*/
|
|
if (Aud_block >= Soc_Aud_Digital_Block_NUM_OF_DIGITAL_BLOCK)
|
|
return false;
|
|
|
|
/* set for counter */
|
|
if (bEnable == true) {
|
|
if (mAudioMEMIF[Aud_block]->mUserCount == 0)
|
|
mAudioMEMIF[Aud_block]->mState = true;
|
|
mAudioMEMIF[Aud_block]->mUserCount++;
|
|
} else {
|
|
mAudioMEMIF[Aud_block]->mUserCount--;
|
|
if (mAudioMEMIF[Aud_block]->mUserCount == 0)
|
|
mAudioMEMIF[Aud_block]->mState = false;
|
|
if (mAudioMEMIF[Aud_block]->mUserCount < 0) {
|
|
mAudioMEMIF[Aud_block]->mUserCount = 0;
|
|
pr_err("[AudioError] , user count < 0\n");
|
|
return false;
|
|
}
|
|
}
|
|
/* pr_debug("%s Aud_block = %d
|
|
* mAudioMEMIF[Aud_block]->mUserCount = %d\n",
|
|
* __func__, Aud_block, mAudioMEMIF[Aud_block]->mUserCount);
|
|
*/
|
|
|
|
if (Aud_block >= Soc_Aud_Digital_Block_NUM_OF_MEM_INTERFACE)
|
|
return true;
|
|
|
|
if ((bEnable == true) && (mAudioMEMIF[Aud_block]->mUserCount == 1))
|
|
SetMemoryPathEnableReg(Aud_block, bEnable);
|
|
else if ((bEnable == false) &&
|
|
(mAudioMEMIF[Aud_block]->mUserCount == 0))
|
|
SetMemoryPathEnableReg(Aud_block, bEnable);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GetMemoryPathEnable(unsigned int Aud_block)
|
|
{
|
|
if (Aud_block < Soc_Aud_Digital_Block_NUM_OF_DIGITAL_BLOCK)
|
|
return mAudioMEMIF[Aud_block]->mState;
|
|
|
|
return false;
|
|
}
|
|
|
|
void set_ul_src_enable(bool enable)
|
|
{
|
|
unsigned long flags;
|
|
|
|
/* pr_debug("%s enable = %d\n", __func__, enable); */
|
|
|
|
spin_lock_irqsave(&afe_control_lock, flags);
|
|
if (enable == true) {
|
|
set_chip_ul_src_enable(true);
|
|
} else {
|
|
if (mAudioMEMIF[Soc_Aud_Digital_Block_ADDA_UL]->mState ==
|
|
false &&
|
|
mAudioMEMIF[Soc_Aud_Digital_Block_ADDA_ANC]->mState ==
|
|
false) {
|
|
set_chip_ul_src_enable(false);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&afe_control_lock, flags);
|
|
}
|
|
|
|
void set_ul2_src_enable(bool enable)
|
|
{
|
|
unsigned long flags;
|
|
|
|
/* pr_debug("%s enable = %d\n", __func__, enable); */
|
|
|
|
spin_lock_irqsave(&afe_control_lock, flags);
|
|
if (enable == true) {
|
|
set_chip_ul2_src_enable(true);
|
|
} else {
|
|
if (mAudioMEMIF[Soc_Aud_Digital_Block_ADDA_UL2]->mState ==
|
|
false &&
|
|
mAudioMEMIF[Soc_Aud_Digital_Block_ADDA_ANC]->mState ==
|
|
false) {
|
|
set_chip_ul2_src_enable(false);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&afe_control_lock, flags);
|
|
}
|
|
|
|
void SetDLSrcEnable(bool bEnable)
|
|
{
|
|
unsigned long flags;
|
|
|
|
/* pr_debug("%s bEnable = %d\n", __func__, bEnable); */
|
|
|
|
spin_lock_irqsave(&afe_control_lock, flags);
|
|
if (bEnable == true) {
|
|
set_chip_dl_src_enable(true);
|
|
} else {
|
|
if (mAudioMEMIF[Soc_Aud_Digital_Block_I2S_OUT_DAC]->mState ==
|
|
false &&
|
|
mAudioMEMIF[Soc_Aud_Digital_Block_ADDA_ANC]->mState ==
|
|
false) {
|
|
set_chip_dl_src_enable(false);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&afe_control_lock, flags);
|
|
}
|
|
|
|
void SetADDAEnable(bool bEnable)
|
|
{
|
|
unsigned long flags;
|
|
|
|
/* pr_debug("%s bEnable = %d\n", __func__, bEnable); */
|
|
|
|
spin_lock_irqsave(&afe_control_lock, flags);
|
|
if (bEnable == true) {
|
|
set_chip_adda_enable(true);
|
|
} else {
|
|
if (mAudioMEMIF[Soc_Aud_Digital_Block_I2S_OUT_DAC]->mState ==
|
|
false &&
|
|
mAudioMEMIF[Soc_Aud_Digital_Block_ADDA_UL]->mState ==
|
|
false &&
|
|
mAudioMEMIF[Soc_Aud_Digital_Block_ADDA_UL2]->mState ==
|
|
false &&
|
|
mAudioMEMIF[Soc_Aud_Digital_Block_ADDA_ANC]->mState ==
|
|
false) {
|
|
set_chip_adda_enable(false);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&afe_control_lock, flags);
|
|
}
|
|
|
|
bool SetI2SDacEnable(bool bEnable)
|
|
{
|
|
/* pr_debug("%s bEnable = %d", __func__, bEnable);*/
|
|
if (bEnable) {
|
|
/* Enable DL SRC order:
|
|
* DL clock (AUDIO_TOP_CON0) -> AFE (AFE_DAC_CON0) ->
|
|
* ADDA UL DL (AFE_ADDA_UL_DL_CON0) ->
|
|
* ADDA DL SRC (AFE_ADDA_DL_SRC2_CON0)
|
|
*/
|
|
EnableAfe(true);
|
|
SetADDAEnable(true);
|
|
SetDLSrcEnable(true);
|
|
Afe_Set_Reg(AFE_I2S_CON1, bEnable, 0x1);
|
|
} else {
|
|
/* Disable DL SRC order: (reverse)
|
|
* ADDA DL SRC (AFE_ADDA_DL_SRC2_CON0) ->
|
|
* ADDA UL DL (AFE_ADDA_UL_DL_CON0) ->
|
|
* AFE (AFE_DAC_CON0) -> DL clock (AUDIO_TOP_CON0)
|
|
*/
|
|
SetDLSrcEnable(false);
|
|
Afe_Set_Reg(AFE_I2S_CON1, bEnable, 0x1);
|
|
SetADDAEnable(false);
|
|
|
|
/* should delayed 1/fs(smallest is 8k) = 125us before afe off */
|
|
usleep_range(125, 150);
|
|
#ifdef CONFIG_FPGA_EARLY_PORTING
|
|
pr_info("%s(), disable fpga clock divide by 4", __func__);
|
|
Afe_Set_Reg(FPGA_CFG0, 0x0 << 1, 0x1 << 1);
|
|
#endif
|
|
}
|
|
|
|
AudDrv_GPIO_Request(bEnable, Soc_Aud_Digital_Block_ADDA_DL);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GetI2SDacEnable(void)
|
|
{
|
|
return mAudioMEMIF[Soc_Aud_Digital_Block_I2S_OUT_DAC]->mState;
|
|
}
|
|
|
|
bool checkDllinkMEMIfStatus(void)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = Soc_Aud_Digital_Block_MEM_DL1;
|
|
i <= Soc_Aud_Digital_Block_MEM_DL2; i++) {
|
|
if (mAudioMEMIF[i]->mState == true)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool checkUplinkMEMIfStatus(void)
|
|
{
|
|
return mAudioMEMIF[Soc_Aud_Digital_Block_MEM_VUL]->mState ||
|
|
mAudioMEMIF[Soc_Aud_Digital_Block_MEM_DAI]->mState ||
|
|
mAudioMEMIF[Soc_Aud_Digital_Block_MEM_AWB]->mState ||
|
|
mAudioMEMIF[Soc_Aud_Digital_Block_MEM_MOD_DAI]->mState ||
|
|
mAudioMEMIF[Soc_Aud_Digital_Block_MEM_VUL_DATA2]->mState;
|
|
}
|
|
|
|
bool SetConnection(unsigned int ConnectionState, unsigned int Input,
|
|
unsigned int Output)
|
|
{
|
|
return SetConnectionState(ConnectionState, Input, Output);
|
|
}
|
|
|
|
bool SetConnectionFormat(unsigned int ConnectionFormat, unsigned int Aud_block)
|
|
{
|
|
return SetIntfConnectionFormat(ConnectionFormat, Aud_block);
|
|
}
|
|
|
|
bool SetIntfConnection(unsigned int ConnectionState, unsigned int Aud_block_In,
|
|
unsigned int Aud_block_Out)
|
|
{
|
|
return SetIntfConnectionState(ConnectionState, Aud_block_In,
|
|
Aud_block_Out);
|
|
}
|
|
|
|
static bool SetIrqEnable(unsigned int irqmode, bool bEnable)
|
|
{
|
|
const struct Aud_RegBitsInfo *irqOnReg, *irqEnReg, *irqClrReg,
|
|
*irqMissClrReg;
|
|
const struct Aud_RegBitsInfo *irqPurposeEnReg;
|
|
unsigned int enShift, purposeIndex;
|
|
bool enSet;
|
|
|
|
pr_debug("%s(), Irqmode %d, bEnable %d\n", __func__, irqmode,
|
|
bEnable);
|
|
|
|
if (irqmode >= Soc_Aud_IRQ_MCU_MODE_NUM) {
|
|
pr_err("%s(), error, not supported IRQ %d", __func__, irqmode);
|
|
return false;
|
|
}
|
|
|
|
irqOnReg = &GetIRQCtrlReg(irqmode)->on;
|
|
Afe_Set_Reg(irqOnReg->reg, (bEnable << irqOnReg->sbit),
|
|
(irqOnReg->mask << irqOnReg->sbit));
|
|
|
|
/* clear irq status */
|
|
if (bEnable == false) {
|
|
irqClrReg = &GetIRQCtrlReg(irqmode)->clr;
|
|
Afe_Set_Reg(irqClrReg->reg, (1 << irqClrReg->sbit),
|
|
(irqClrReg->mask << irqClrReg->sbit));
|
|
Afe_Set_Reg(irqClrReg->reg, (1 << irqClrReg->sbit),
|
|
(irqClrReg->mask << irqClrReg->sbit));
|
|
|
|
irqMissClrReg = &GetIRQCtrlReg(irqmode)->missclr;
|
|
Afe_Set_Reg(irqMissClrReg->reg, (1 << irqMissClrReg->sbit),
|
|
(irqMissClrReg->mask << irqMissClrReg->sbit));
|
|
}
|
|
|
|
/* set irq signal target */
|
|
irqEnReg = &GetIRQCtrlReg(irqmode)->en;
|
|
for (purposeIndex = 0; purposeIndex < Soc_Aud_IRQ_PURPOSE_NUM;
|
|
purposeIndex++) {
|
|
irqPurposeEnReg = GetIRQPurposeReg(purposeIndex);
|
|
enSet = bEnable &&
|
|
(GetIRQCtrlReg(irqmode)->irqPurpose == purposeIndex);
|
|
enShift = irqPurposeEnReg->sbit + irqEnReg->sbit;
|
|
if (irqPurposeEnReg->reg != AFE_REG_UNDEFINED)
|
|
Afe_Set_Reg(irqPurposeEnReg->reg, (enSet << enShift),
|
|
(irqEnReg->mask << enShift));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool SetIrqMcuSampleRate(unsigned int irqmode, unsigned int SampleRate)
|
|
{
|
|
unsigned int SRIdx = SampleRateTransform(SampleRate, 0);
|
|
const struct Aud_RegBitsInfo *irqModeReg;
|
|
|
|
/* pr_debug("%s(), Irqmode %d, SampleRate %d\n", __func__, irqmode,
|
|
* SampleRate);
|
|
*/
|
|
if (irqmode >= Soc_Aud_IRQ_MCU_MODE_NUM)
|
|
return false;
|
|
|
|
irqModeReg = &GetIRQCtrlReg(irqmode)->mode;
|
|
Afe_Set_Reg(irqModeReg->reg, SRIdx << irqModeReg->sbit,
|
|
irqModeReg->mask << irqModeReg->sbit);
|
|
return true;
|
|
}
|
|
|
|
static bool SetIrqMcuCounter(unsigned int irqmode, unsigned int Counter)
|
|
{
|
|
const struct Aud_RegBitsInfo *irqCntReg;
|
|
|
|
/* pr_debug("%s(), Irqmode %d, Counter %d\n",
|
|
* __func__, irqmode, Counter);
|
|
*/
|
|
if (irqmode >= Soc_Aud_IRQ_MCU_MODE_NUM)
|
|
return false;
|
|
|
|
irqCntReg = &GetIRQCtrlReg(irqmode)->cnt;
|
|
Afe_Set_Reg(irqCntReg->reg, Counter, irqCntReg->mask);
|
|
return true;
|
|
}
|
|
|
|
bool Set2ndI2SInConfig(unsigned int sampleRate, bool bIsSlaveMode)
|
|
{
|
|
struct audio_digital_i2s I2S2ndIn_attribute;
|
|
|
|
memset((void *)&I2S2ndIn_attribute, 0, sizeof(I2S2ndIn_attribute));
|
|
I2S2ndIn_attribute.mLR_SWAP = Soc_Aud_LR_SWAP_NO_SWAP;
|
|
I2S2ndIn_attribute.mI2S_SLAVE = bIsSlaveMode;
|
|
I2S2ndIn_attribute.mI2S_SAMPLERATE = sampleRate;
|
|
I2S2ndIn_attribute.mINV_LRCK = Soc_Aud_INV_LRCK_NO_INVERSE;
|
|
I2S2ndIn_attribute.mI2S_FMT = Soc_Aud_I2S_FORMAT_I2S;
|
|
I2S2ndIn_attribute.mI2S_WLEN = Soc_Aud_I2S_WLEN_WLEN_16BITS;
|
|
Set2ndI2SIn(&I2S2ndIn_attribute);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Set2ndI2SIn(struct audio_digital_i2s *mDigitalI2S)
|
|
{
|
|
unsigned int Audio_I2S_Adc = 0;
|
|
|
|
memcpy((void *)m2ndI2S, (void *)mDigitalI2S,
|
|
sizeof(struct audio_digital_i2s));
|
|
|
|
if (!m2ndI2S->mI2S_SLAVE) { /* Master setting SampleRate only */
|
|
SetSampleRate(Soc_Aud_Digital_Block_MEM_I2S,
|
|
m2ndI2S->mI2S_SAMPLERATE);
|
|
}
|
|
|
|
Audio_I2S_Adc |= (m2ndI2S->mINV_LRCK << 5);
|
|
Audio_I2S_Adc |= (m2ndI2S->mI2S_FMT << 3);
|
|
Audio_I2S_Adc |= (m2ndI2S->mI2S_SLAVE << 2);
|
|
Audio_I2S_Adc |= (m2ndI2S->mI2S_WLEN << 1);
|
|
Audio_I2S_Adc |= (m2ndI2S->mI2S_IN_PAD_SEL << 28);
|
|
Afe_Set_Reg(AFE_I2S_CON, Audio_I2S_Adc, 0xfffffffe);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Set2ndI2SInEnable(bool bEnable)
|
|
{
|
|
m2ndI2S->mI2S_EN = bEnable;
|
|
Afe_Set_Reg(AFE_I2S_CON, bEnable, 0x1);
|
|
mAudioMEMIF[Soc_Aud_Digital_Block_I2S_IN_2]->mState = bEnable;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SetMemIfFetchFormatPerSample(unsigned int InterfaceType,
|
|
unsigned int eFetchFormat)
|
|
{
|
|
mAudioMEMIF[InterfaceType]->mFetchFormatPerSample = eFetchFormat;
|
|
return SetMemIfFormatReg(InterfaceType, eFetchFormat);
|
|
}
|
|
|
|
bool SetoutputConnectionFormat(unsigned int ConnectionFormat,
|
|
unsigned int Output)
|
|
{
|
|
if (Output >= Soc_Aud_InterConnectionOutput_O32) {
|
|
#ifdef AFE_CONN_24BIT_1
|
|
unsigned int shift = Output - Soc_Aud_InterConnectionOutput_O32;
|
|
|
|
Afe_Set_Reg(AFE_CONN_24BIT_1, ConnectionFormat << shift,
|
|
1 << shift);
|
|
#else
|
|
pr_err("%s(), not support Output %u\n", __func__, Output);
|
|
return false;
|
|
#endif
|
|
} else {
|
|
Afe_Set_Reg(AFE_CONN_24BIT, ConnectionFormat << Output,
|
|
1 << Output);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int set_memif_pbuf_size(int aud_blk, enum memif_pbuf_size pbuf_size)
|
|
{
|
|
if (pbuf_size < 0 || pbuf_size >= MEMIF_PBUF_SIZE_NUM) {
|
|
pr_err("%s(), invalid pbuf_size %d\n", __func__, pbuf_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (aud_blk) {
|
|
case Soc_Aud_Digital_Block_MEM_DL1:
|
|
Afe_Set_Reg(AFE_MEMIF_PBUF_SIZE, pbuf_size << 0, 0x3 << 0);
|
|
Afe_Set_Reg(AFE_MEMIF_MINLEN, pbuf_size << 0, 0xf << 0);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DL2:
|
|
Afe_Set_Reg(AFE_MEMIF_PBUF_SIZE, pbuf_size << 2, 0x3 << 2);
|
|
Afe_Set_Reg(AFE_MEMIF_MINLEN, pbuf_size << 8, 0xf << 8);
|
|
break;
|
|
default:
|
|
pr_err("%s(): invalid aud_blk %d\n", __func__, aud_blk);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool set_general_asrc_enable(enum audio_general_asrc_id id, bool enable)
|
|
{
|
|
bool ret = false;
|
|
|
|
if (s_afe_platform_ops->set_general_asrc_enable != NULL)
|
|
ret = s_afe_platform_ops->set_general_asrc_enable(id, enable);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool set_general_asrc_parameter(enum audio_general_asrc_id id,
|
|
unsigned int sample_rate_in,
|
|
unsigned int sample_rate_out)
|
|
{
|
|
bool ret = false;
|
|
|
|
if (s_afe_platform_ops->set_general_asrc_parameter != NULL)
|
|
ret = s_afe_platform_ops->set_general_asrc_parameter(
|
|
id, sample_rate_in, sample_rate_out);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_Allocate_DL1_Buffer / AudDrv_Free_DL1_Buffer
|
|
*
|
|
* DESCRIPTION
|
|
* allocate DL1 Buffer
|
|
*
|
|
***************************************************************************
|
|
*/
|
|
int AudDrv_Allocate_DL1_Buffer(struct device *pDev, kal_uint32 Afe_Buf_Length,
|
|
dma_addr_t dma_addr, unsigned char *dma_area)
|
|
{
|
|
struct afe_block_t *pblock;
|
|
|
|
pblock = &(
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_DL1]->rBlock);
|
|
pblock->u4BufferSize = Afe_Buf_Length;
|
|
|
|
if (Afe_Buf_Length > AFE_INTERNAL_SRAM_SIZE) {
|
|
pr_err("%s(), Afe_Buf_Length %d > %d\n", __func__,
|
|
Afe_Buf_Length, AFE_INTERNAL_SRAM_SIZE);
|
|
return -1;
|
|
}
|
|
|
|
pblock->pucPhysBufAddr = (kal_uint32)dma_addr;
|
|
pblock->pucVirtBufAddr = dma_area;
|
|
|
|
pr_debug(
|
|
"%s(), Afe_Buf_Length = %d, pucVirtBufAddr = %p, pblock->pucPhysBufAddr = 0x%x\n",
|
|
__func__, Afe_Buf_Length, pblock->pucVirtBufAddr,
|
|
pblock->pucPhysBufAddr);
|
|
|
|
/* check 32 bytes align */
|
|
if ((pblock->pucPhysBufAddr & 0x1f) != 0) {
|
|
pr_info("[Auddrv] buffer is not aligned (0x%x)\n",
|
|
pblock->pucPhysBufAddr);
|
|
}
|
|
|
|
pblock->u4SampleNumMask = 0x001f; /* 32 byte align */
|
|
pblock->u4WriteIdx = 0;
|
|
pblock->u4DMAReadIdx = 0;
|
|
pblock->u4DataRemained = 0;
|
|
pblock->u4fsyncflag = false;
|
|
pblock->uResetFlag = true;
|
|
|
|
/* set sram address top hardware */
|
|
set_memif_addr(Soc_Aud_Digital_Block_MEM_DL1, pblock->pucPhysBufAddr,
|
|
Afe_Buf_Length);
|
|
|
|
memset_io(pblock->pucVirtBufAddr, 0, pblock->u4BufferSize);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int AudDrv_Allocate_mem_Buffer(struct device *pDev,
|
|
enum soc_aud_digital_block MemBlock,
|
|
unsigned int Buffer_length)
|
|
{
|
|
switch (MemBlock) {
|
|
case Soc_Aud_Digital_Block_MEM_DL1:
|
|
case Soc_Aud_Digital_Block_MEM_DL2:
|
|
case Soc_Aud_Digital_Block_MEM_DL3:
|
|
case Soc_Aud_Digital_Block_MEM_DAI:
|
|
case Soc_Aud_Digital_Block_MEM_AWB:
|
|
case Soc_Aud_Digital_Block_MEM_MOD_DAI:
|
|
/*case Soc_Aud_Digital_Block_MEM_DL1_DATA2:*/
|
|
case Soc_Aud_Digital_Block_MEM_VUL_DATA2:
|
|
case Soc_Aud_Digital_Block_MEM_VUL:
|
|
case Soc_Aud_Digital_Block_MEM_VUL2:
|
|
case Soc_Aud_Digital_Block_MEM_HDMI:
|
|
pr_debug("%s MemBlock =%d Buffer_length = %d\n ", __func__,
|
|
MemBlock, Buffer_length);
|
|
if (Audio_dma_buf[MemBlock] != NULL) {
|
|
if (Audio_dma_buf[MemBlock]->area == NULL) {
|
|
pr_debug("dma_alloc_coherent\n");
|
|
Audio_dma_buf[MemBlock]->area =
|
|
dma_alloc_coherent(
|
|
pDev, Buffer_length,
|
|
&Audio_dma_buf[MemBlock]->addr,
|
|
GFP_KERNEL | GFP_DMA);
|
|
if (Audio_dma_buf[MemBlock]->area)
|
|
Audio_dma_buf[MemBlock]->bytes =
|
|
Buffer_length;
|
|
}
|
|
pr_debug("area = %p\n", Audio_dma_buf[MemBlock]->area);
|
|
}
|
|
break;
|
|
default:
|
|
pr_debug("%s not support\n", __func__);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
struct afe_mem_control_t *Get_Mem_ControlT(enum soc_aud_digital_block MemBlock)
|
|
{
|
|
if (MemBlock >= 0 &&
|
|
MemBlock < Soc_Aud_Digital_Block_NUM_OF_MEM_INTERFACE)
|
|
return AFE_Mem_Control_context[MemBlock];
|
|
|
|
pr_debug("%s error\n", __func__);
|
|
return NULL;
|
|
}
|
|
|
|
bool SetMemifSubStream(enum soc_aud_digital_block MemBlock,
|
|
struct snd_pcm_substream *substream)
|
|
{
|
|
struct substream_list *head;
|
|
struct substream_list *temp = NULL;
|
|
unsigned long flags;
|
|
|
|
temp = kzalloc(sizeof(struct substream_list), GFP_ATOMIC);
|
|
if (temp == NULL)
|
|
return false;
|
|
|
|
/* pr_debug("%s MemBlock = %d substream = %p\n",
|
|
* __func__, MemBlock, substream);
|
|
*/
|
|
spin_lock_irqsave(&AFE_Mem_Control_context[MemBlock]->substream_lock,
|
|
flags);
|
|
head = AFE_Mem_Control_context[MemBlock]->substreamL;
|
|
if (head == NULL) { /* frst item is NULL */
|
|
/* pr_debug("%s head == NULL\n ", __func__); */
|
|
temp->substream = substream;
|
|
temp->next = NULL;
|
|
AFE_Mem_Control_context[MemBlock]->substreamL = temp;
|
|
} else { /* find out Null pointer */
|
|
while (head->next != NULL)
|
|
head = head->next;
|
|
|
|
/* head->next is NULL */
|
|
temp->substream = substream;
|
|
temp->next = NULL;
|
|
head->next = temp;
|
|
}
|
|
|
|
AFE_Mem_Control_context[MemBlock]->MemIfNum++;
|
|
spin_unlock_irqrestore(
|
|
&AFE_Mem_Control_context[MemBlock]->substream_lock, flags);
|
|
/* DumpMemifSubStream(); */
|
|
return true;
|
|
}
|
|
|
|
bool ClearMemBlock(enum soc_aud_digital_block MemBlock)
|
|
{
|
|
if (MemBlock >= 0 &&
|
|
MemBlock < Soc_Aud_Digital_Block_NUM_OF_MEM_INTERFACE) {
|
|
struct afe_block_t *pBlock =
|
|
&AFE_Mem_Control_context[MemBlock]->rBlock;
|
|
|
|
pBlock->u4WriteIdx = 0;
|
|
pBlock->u4DMAReadIdx = 0;
|
|
pBlock->u4DataRemained = 0;
|
|
pBlock->u4fsyncflag = false;
|
|
pBlock->uResetFlag = true;
|
|
} else {
|
|
pr_debug("%s error\n", __func__);
|
|
return NULL;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#define MEM_TIMEOUT_CNT 4
|
|
bool RemoveMemifSubStream(enum soc_aud_digital_block MemBlock,
|
|
struct snd_pcm_substream *substream)
|
|
{
|
|
struct substream_list *head;
|
|
struct substream_list *temp = NULL;
|
|
unsigned long flags;
|
|
int i;
|
|
|
|
spin_lock_irqsave(&AFE_Mem_Control_context[MemBlock]->substream_lock,
|
|
flags);
|
|
|
|
for (i = 0; i < MEM_TIMEOUT_CNT; i++) {
|
|
if (AFE_Mem_Control_context[MemBlock]->mWaitForIRQ == true) {
|
|
pr_debug("%s: enter udelay.\n", __func__);
|
|
mdelay(5);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (AFE_Mem_Control_context[MemBlock]->MemIfNum == 0)
|
|
pr_debug("%s AFE_Mem_Control_context[%d]->MemIfNum == 0\n ",
|
|
__func__, MemBlock);
|
|
else
|
|
AFE_Mem_Control_context[MemBlock]->MemIfNum--;
|
|
|
|
head = AFE_Mem_Control_context[MemBlock]->substreamL;
|
|
/* pr_debug("+ %s MemBlock = %d substream = %p\n ",
|
|
* __func__, MemBlock, substream);
|
|
*/
|
|
|
|
if (head == NULL) { /* no object */
|
|
/* do nothing */
|
|
} else {
|
|
/* condition for first item hit */
|
|
if (head->substream == substream) {
|
|
/* pr_debug("%s head->substream = %p\n ", __func__,
|
|
* head->substream);
|
|
*/
|
|
AFE_Mem_Control_context[MemBlock]->substreamL =
|
|
head->next;
|
|
head->substream = NULL;
|
|
kfree(head);
|
|
head = NULL;
|
|
/* DumpMemifSubStream(); */
|
|
} else {
|
|
temp = head;
|
|
head = head->next;
|
|
while (head) {
|
|
if (head->substream == substream) {
|
|
temp->next = head->next;
|
|
head->substream = NULL;
|
|
kfree(head);
|
|
head = NULL;
|
|
break;
|
|
}
|
|
temp = head;
|
|
head = head->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* DumpMemifSubStream(); */
|
|
if (AFE_Mem_Control_context[MemBlock]->substreamL == NULL)
|
|
ClearMemBlock(MemBlock);
|
|
else
|
|
pr_debug("%s substreram is not NULL MemBlock = %d\n", __func__,
|
|
MemBlock);
|
|
|
|
spin_unlock_irqrestore(
|
|
&AFE_Mem_Control_context[MemBlock]->substream_lock, flags);
|
|
/* pr_debug("- %s MemBlock = %d\n ", __func__, MemBlock); */
|
|
|
|
return true;
|
|
}
|
|
|
|
static unsigned long dl2_flags;
|
|
void Auddrv_Dl2_Spinlock_lock(void)
|
|
{
|
|
spin_lock_irqsave(&auddrv_dl2_lock, dl2_flags);
|
|
}
|
|
|
|
void Auddrv_Dl2_Spinlock_unlock(void)
|
|
{
|
|
spin_unlock_irqrestore(&auddrv_dl2_lock, dl2_flags);
|
|
}
|
|
|
|
static unsigned long dl3_flags;
|
|
void Auddrv_Dl3_Spinlock_lock(void)
|
|
{
|
|
spin_lock_irqsave(&auddrv_dl3_lock, dl3_flags);
|
|
}
|
|
|
|
void Auddrv_Dl3_Spinlock_unlock(void)
|
|
{
|
|
spin_unlock_irqrestore(&auddrv_dl3_lock, dl3_flags);
|
|
}
|
|
|
|
void Auddrv_HDMI_Interrupt_Handler(void)
|
|
{
|
|
#ifdef CONFIG_MTK_HDMI_TDM
|
|
|
|
struct afe_mem_control_t *Mem_Block =
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_HDMI];
|
|
kal_int32 Afe_consumed_bytes = 0;
|
|
kal_int32 HW_memory_index = 0;
|
|
kal_int32 HW_Cur_ReadIdx = 0;
|
|
unsigned long flags;
|
|
struct afe_block_t *Afe_Block =
|
|
&(AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_HDMI]
|
|
->rBlock);
|
|
|
|
if (Mem_Block == NULL) {
|
|
pr_warn("-%s()Mem_Block == NULL\n", __func__);
|
|
return;
|
|
}
|
|
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_HDMI) == false) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
HW_Cur_ReadIdx = Afe_Get_Reg(AFE_HDMI_CUR);
|
|
if (HW_Cur_ReadIdx == 0) {
|
|
/* pr_debug("[Auddrv_HDMI_Interrupt] HW_Cur_ReadIdx ==0\n"); */
|
|
HW_Cur_ReadIdx = Afe_Block->pucPhysBufAddr;
|
|
}
|
|
HW_memory_index = (HW_Cur_ReadIdx - Afe_Block->pucPhysBufAddr);
|
|
|
|
/* get hw consume bytes */
|
|
if (HW_memory_index > Afe_Block->u4DMAReadIdx) {
|
|
Afe_consumed_bytes = HW_memory_index - Afe_Block->u4DMAReadIdx;
|
|
} else {
|
|
Afe_consumed_bytes = Afe_Block->u4BufferSize + HW_memory_index -
|
|
Afe_Block->u4DMAReadIdx;
|
|
}
|
|
|
|
if ((Afe_consumed_bytes & 0x1f) != 0)
|
|
pr_debug("[Auddrv_HDMI_Interrupt] DMA address is not aligned 32 bytes\n");
|
|
|
|
|
|
if (Afe_Block->u4DataRemained < Afe_consumed_bytes ||
|
|
Afe_Block->u4DataRemained <= 0 ||
|
|
Afe_Block->u4DataRemained > Afe_Block->u4BufferSize) {
|
|
/* buffer underflow --> clear whole buffer */
|
|
/* memset(Afe_Block->pucVirtBufAddr, 0,
|
|
* Afe_Block->u4BufferSize);
|
|
*/
|
|
Afe_Block->u4DMAReadIdx = HW_memory_index;
|
|
Afe_Block->u4WriteIdx = Afe_Block->u4DMAReadIdx;
|
|
Afe_Block->u4DataRemained = Afe_Block->u4BufferSize;
|
|
} else {
|
|
Afe_Block->u4DataRemained -= Afe_consumed_bytes;
|
|
Afe_Block->u4DMAReadIdx += Afe_consumed_bytes;
|
|
Afe_Block->u4DMAReadIdx %= Afe_Block->u4BufferSize;
|
|
}
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_HDMI]
|
|
->interruptTrigger = 1;
|
|
|
|
if (Mem_Block->substreamL != NULL) {
|
|
if (Mem_Block->substreamL->substream != NULL) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock,
|
|
flags);
|
|
snd_pcm_period_elapsed(
|
|
Mem_Block->substreamL->substream);
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
#endif
|
|
}
|
|
|
|
void Auddrv_AWB_Interrupt_Handler(void)
|
|
{
|
|
struct afe_mem_control_t *Mem_Block =
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_AWB];
|
|
kal_uint32 HW_Cur_ReadIdx = 0;
|
|
kal_uint32 MaxCopySize = 0;
|
|
kal_int32 Hw_Get_bytes = 0;
|
|
struct substream_list *temp = NULL;
|
|
struct afe_block_t *mBlock = NULL;
|
|
unsigned long flags;
|
|
kal_uint32 temp_cnt = 0;
|
|
|
|
if (Mem_Block == NULL) {
|
|
pr_err("-%s()Mem_Block == NULL\n ", __func__);
|
|
return;
|
|
}
|
|
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
|
|
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_AWB) == false) {
|
|
/* pr_debug("%s(),
|
|
* GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_AWB) == false,
|
|
* return\n ", __func__);
|
|
*/
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
pr_err("-%s(), GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_AWB) = %d\n ",
|
|
__func__,
|
|
GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_AWB));
|
|
return;
|
|
}
|
|
|
|
mBlock = &Mem_Block->rBlock;
|
|
HW_Cur_ReadIdx = word_size_align(Afe_Get_Reg(AFE_AWB_CUR));
|
|
/* pr_debug("+%s HW_Cur_ReadIdx = 0x%x\n ",
|
|
* __func__, HW_Cur_ReadIdx);
|
|
*/
|
|
|
|
if (CheckSize(HW_Cur_ReadIdx)) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
if (mBlock->pucVirtBufAddr == NULL) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
MaxCopySize = Get_Mem_MaxCopySize(Soc_Aud_Digital_Block_MEM_AWB);
|
|
/* pr_debug("1 mBlock = %p MaxCopySize = 0x%x u4BufferSize = 0x%x\n",
|
|
* mBlock, MaxCopySize, mBlock->u4BufferSize);
|
|
*/
|
|
|
|
if (MaxCopySize) {
|
|
if (MaxCopySize > mBlock->u4BufferSize)
|
|
MaxCopySize = mBlock->u4BufferSize;
|
|
mBlock->u4DataRemained -= MaxCopySize;
|
|
mBlock->u4DMAReadIdx += MaxCopySize;
|
|
mBlock->u4DMAReadIdx %= mBlock->u4BufferSize;
|
|
Clear_Mem_CopySize(Soc_Aud_Digital_Block_MEM_AWB);
|
|
/* pr_debug("%s read ReadIdx:0x%x, WriteIdx:0x%x,
|
|
* BufAddr:0x%x CopySize =0x%x\n", __func__,
|
|
* mBlock->u4DMAReadIdx, mBlock->u4WriteIdx,
|
|
* mBlock->pucPhysBufAddr, mBlock->u4MaxCopySize);
|
|
*/
|
|
}
|
|
|
|
/* HW already fill in */
|
|
Hw_Get_bytes =
|
|
(HW_Cur_ReadIdx - mBlock->pucPhysBufAddr) - mBlock->u4WriteIdx;
|
|
if (Hw_Get_bytes < 0)
|
|
Hw_Get_bytes += mBlock->u4BufferSize;
|
|
|
|
/* pr_debug("%s Get_bytes:0x%x,Cur_ReadIdx:0x%x,ReadIdx:0x%x,
|
|
* WriteIdx:0x%x,BufAddr:0x%x Remained = 0x%x\n",
|
|
* __func__, Hw_Get_bytes, HW_Cur_ReadIdx, mBlock->u4DMAReadIdx,
|
|
* mBlock->u4WriteIdx, mBlock->pucPhysBufAddr, mBlock->u4DataRemained);
|
|
*/
|
|
mBlock->u4WriteIdx += Hw_Get_bytes;
|
|
mBlock->u4WriteIdx %= mBlock->u4BufferSize;
|
|
mBlock->u4DataRemained += Hw_Get_bytes;
|
|
|
|
/* buffer overflow */
|
|
if (mBlock->u4DataRemained > mBlock->u4BufferSize) {
|
|
pr_debug("%s buffer overflow u4DMAReadIdx:%x, u4WriteIdx:%x, u4DataRemained:%x, u4BufferSize:%x\n",
|
|
__func__, mBlock->u4DMAReadIdx, mBlock->u4WriteIdx,
|
|
mBlock->u4DataRemained, mBlock->u4BufferSize);
|
|
mBlock->u4DataRemained %= mBlock->u4BufferSize;
|
|
}
|
|
|
|
Mem_Block->interruptTrigger = 1;
|
|
temp = Mem_Block->substreamL;
|
|
|
|
while (temp != NULL) {
|
|
if (temp->substream != NULL) {
|
|
temp_cnt = Mem_Block->MemIfNum;
|
|
Mem_Block->mWaitForIRQ = true;
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock,
|
|
flags);
|
|
snd_pcm_period_elapsed(temp->substream);
|
|
Mem_Block->mWaitForIRQ = false;
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
|
|
if (temp_cnt != Mem_Block->MemIfNum) {
|
|
pr_debug(
|
|
"%s() temp_cnt = %u, Mem_Block->MemIfNum = %u\n",
|
|
__func__, temp_cnt,
|
|
Mem_Block->MemIfNum);
|
|
temp = Mem_Block->substreamL;
|
|
}
|
|
}
|
|
if (temp != NULL)
|
|
temp = temp->next;
|
|
}
|
|
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
/* pr_debug("-%s u4DMAReadIdx:0x%x, u4WriteIdx:0x%x
|
|
* mBlock->u4DataRemained = 0x%x\n", __func__,
|
|
* mBlock->u4DMAReadIdx, mBlock->u4WriteIdx, mBlock->u4DataRemained);
|
|
*/
|
|
}
|
|
|
|
void Auddrv_DAI_Interrupt_Handler(void)
|
|
{
|
|
struct afe_mem_control_t *Mem_Block =
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_DAI];
|
|
kal_uint32 HW_Cur_ReadIdx = 0;
|
|
kal_int32 Hw_Get_bytes = 0;
|
|
struct afe_block_t *mBlock = NULL;
|
|
unsigned long flags;
|
|
|
|
if (Mem_Block == NULL)
|
|
return;
|
|
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
|
|
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_DAI) == false) {
|
|
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
mBlock = &Mem_Block->rBlock;
|
|
HW_Cur_ReadIdx = word_size_align(Afe_Get_Reg(AFE_DAI_CUR));
|
|
|
|
if (CheckSize(HW_Cur_ReadIdx)) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
if (mBlock->pucVirtBufAddr == NULL) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
/* HW already fill in */
|
|
Hw_Get_bytes =
|
|
(HW_Cur_ReadIdx - mBlock->pucPhysBufAddr) - mBlock->u4WriteIdx;
|
|
|
|
if (Hw_Get_bytes < 0)
|
|
Hw_Get_bytes += mBlock->u4BufferSize;
|
|
|
|
/* pr_debug("%s Hw_Get_bytes:0x%x, Cur_ReadIdx:0x%x,ReadIdx:0x%x,
|
|
* WriteIdx:0x%x, PhysAddr:0x%x Block->MemIfNum = %d\n",
|
|
* __func__, Hw_Get_bytes, HW_Cur_ReadIdx, mBlock->u4DMAReadIdx,
|
|
* mBlock->u4WriteIdx, mBlock->pucPhysBufAddr, Mem_Block->MemIfNum);
|
|
*/
|
|
|
|
mBlock->u4WriteIdx += Hw_Get_bytes;
|
|
mBlock->u4WriteIdx %= mBlock->u4BufferSize;
|
|
mBlock->u4DataRemained += Hw_Get_bytes;
|
|
|
|
/* buffer overflow */
|
|
if (mBlock->u4DataRemained > mBlock->u4BufferSize) {
|
|
pr_debug(
|
|
"%s buffer overflow u4DMAReadIdx:%x,WriteIdx:%x, Remained:%x, u4BufferSize:%x\n",
|
|
__func__, mBlock->u4DMAReadIdx, mBlock->u4WriteIdx,
|
|
mBlock->u4DataRemained, mBlock->u4BufferSize);
|
|
}
|
|
|
|
Mem_Block->interruptTrigger = 1;
|
|
|
|
if (Mem_Block->substreamL != NULL) {
|
|
if (Mem_Block->substreamL->substream != NULL) {
|
|
Mem_Block->mWaitForIRQ = true;
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock,
|
|
flags);
|
|
snd_pcm_period_elapsed(
|
|
Mem_Block->substreamL->substream);
|
|
Mem_Block->mWaitForIRQ = false;
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
}
|
|
}
|
|
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
}
|
|
|
|
void Auddrv_VUL2_Interrupt_Handler(void)
|
|
{
|
|
struct afe_mem_control_t *Mem_Block =
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_VUL2];
|
|
kal_uint32 HW_Cur_ReadIdx = 0;
|
|
kal_uint32 MaxCopySize = 0;
|
|
kal_int32 Hw_Get_bytes = 0;
|
|
struct substream_list *temp = NULL;
|
|
struct afe_block_t *mBlock = NULL;
|
|
unsigned long flags;
|
|
kal_uint32 temp_cnt = 0;
|
|
|
|
if (Mem_Block == NULL) {
|
|
pr_err("-%s()Mem_Block == NULL\n ", __func__);
|
|
return;
|
|
}
|
|
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
|
|
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_VUL2) == false) {
|
|
/* pr_debug("%s(),
|
|
* GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_AWB) == false,
|
|
* return\n ", __func__);
|
|
*/
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
pr_err("-%s(), GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_AWB) = %d\n ",
|
|
__func__,
|
|
GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_VUL2));
|
|
return;
|
|
}
|
|
|
|
mBlock = &Mem_Block->rBlock;
|
|
HW_Cur_ReadIdx = word_size_align(Afe_Get_Reg(AFE_VUL2_CUR));
|
|
/* pr_debug("+%s HW_Cur_ReadIdx = 0x%x\n ",
|
|
* __func__, HW_Cur_ReadIdx);
|
|
*/
|
|
|
|
if (CheckSize(HW_Cur_ReadIdx)) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
if (mBlock->pucVirtBufAddr == NULL) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
MaxCopySize = Get_Mem_MaxCopySize(Soc_Aud_Digital_Block_MEM_VUL2);
|
|
/* pr_debug("1 mBlock = %p MaxCopySize = 0x%x u4BufferSize = 0x%x\n",
|
|
* mBlock, MaxCopySize, mBlock->u4BufferSize);
|
|
*/
|
|
|
|
if (MaxCopySize) {
|
|
if (MaxCopySize > mBlock->u4BufferSize)
|
|
MaxCopySize = mBlock->u4BufferSize;
|
|
mBlock->u4DataRemained -= MaxCopySize;
|
|
mBlock->u4DMAReadIdx += MaxCopySize;
|
|
mBlock->u4DMAReadIdx %= mBlock->u4BufferSize;
|
|
Clear_Mem_CopySize(Soc_Aud_Digital_Block_MEM_VUL2);
|
|
/* pr_debug(
|
|
* "%s read ReadIdx:0x%x, WriteIdx:0x%x,BufAddr:0x%x
|
|
* CopySize =0x%x\n",
|
|
* __func__, mBlock->u4DMAReadIdx, mBlock->u4WriteIdx,
|
|
* mBlock->pucPhysBufAddr, mBlock->u4MaxCopySize);
|
|
*/
|
|
}
|
|
|
|
/* HW already fill in */
|
|
Hw_Get_bytes =
|
|
(HW_Cur_ReadIdx - mBlock->pucPhysBufAddr) - mBlock->u4WriteIdx;
|
|
if (Hw_Get_bytes < 0)
|
|
Hw_Get_bytes += mBlock->u4BufferSize;
|
|
|
|
/* pr_debug("%s Get_bytes:0x%x,Cur_ReadIdx:0x%x,ReadIdx:0x%x,
|
|
* WriteIdx:0x%x,BufAddr:0x%x Remained = 0x%x\n",
|
|
* __func__, Hw_Get_bytes, HW_Cur_ReadIdx, mBlock->u4DMAReadIdx,
|
|
* mBlock->u4WriteIdx, mBlock->pucPhysBufAddr, mBlock->u4DataRemained);
|
|
*/
|
|
mBlock->u4WriteIdx += Hw_Get_bytes;
|
|
mBlock->u4WriteIdx %= mBlock->u4BufferSize;
|
|
mBlock->u4DataRemained += Hw_Get_bytes;
|
|
|
|
/* buffer overflow */
|
|
if (mBlock->u4DataRemained > mBlock->u4BufferSize) {
|
|
pr_debug(
|
|
"%s buffer overflow u4DMAReadIdx:%x, u4WriteIdx:%x, u4DataRemained:%x, u4BufferSize:%x\n",
|
|
__func__, mBlock->u4DMAReadIdx, mBlock->u4WriteIdx,
|
|
mBlock->u4DataRemained, mBlock->u4BufferSize);
|
|
mBlock->u4DataRemained %= mBlock->u4BufferSize;
|
|
}
|
|
|
|
Mem_Block->interruptTrigger = 1;
|
|
temp = Mem_Block->substreamL;
|
|
|
|
while (temp != NULL) {
|
|
if (temp->substream != NULL) {
|
|
temp_cnt = Mem_Block->MemIfNum;
|
|
Mem_Block->mWaitForIRQ = true;
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock,
|
|
flags);
|
|
snd_pcm_period_elapsed(temp->substream);
|
|
Mem_Block->mWaitForIRQ = false;
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
|
|
if (temp_cnt != Mem_Block->MemIfNum) {
|
|
pr_debug(
|
|
"%s() temp_cnt = %u, Mem_Block->MemIfNum = %u\n",
|
|
__func__, temp_cnt,
|
|
Mem_Block->MemIfNum);
|
|
temp = Mem_Block->substreamL;
|
|
}
|
|
}
|
|
if (temp != NULL)
|
|
temp = temp->next;
|
|
}
|
|
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
/* pr_debug( "-%s u4DMAReadIdx:0x%x, u4WriteIdx:0x%x
|
|
* mBlock->u4DataRemained = 0x%x\n", __func__,
|
|
* mBlock->u4DMAReadIdx, mBlock->u4WriteIdx, mBlock->u4DataRemained);
|
|
*/
|
|
}
|
|
|
|
void Auddrv_DSP_DL1_Interrupt_Handler(void *PrivateData)
|
|
{
|
|
/* irq1 ISR handler */
|
|
struct afe_mem_control_t *Mem_Block =
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_DL1];
|
|
kal_int32 Afe_consumed_bytes = 0;
|
|
kal_int32 HW_memory_index = 0;
|
|
kal_int32 HW_Cur_ReadIdx = 0;
|
|
struct afe_block_t *Afe_Block = &(
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_DL1]->rBlock);
|
|
unsigned long flags;
|
|
|
|
if (Mem_Block == NULL)
|
|
return;
|
|
|
|
if (get_voice_usb_status() &&
|
|
GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_DL1)) {
|
|
if (Mem_Block->substreamL != NULL) {
|
|
if (Mem_Block->substreamL->substream != NULL)
|
|
snd_pcm_period_elapsed(
|
|
Mem_Block->substreamL->substream);
|
|
}
|
|
return;
|
|
}
|
|
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
|
|
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_DL1) == false) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
HW_Cur_ReadIdx = word_size_align(Afe_Get_Reg(AFE_DL1_CUR));
|
|
|
|
if (HW_Cur_ReadIdx == 0) {
|
|
/* pr_debug("[Auddrv] HW_Cur_ReadIdx ==0\n"); */
|
|
HW_Cur_ReadIdx = Afe_Block->pucPhysBufAddr;
|
|
}
|
|
|
|
HW_memory_index = HW_Cur_ReadIdx - Afe_Get_Reg(AFE_DL1_BASE);
|
|
|
|
/* pr_debug("[Auddrv] HW_Cur_ReadIdx=0x%x HW_memory_index = 0x%x
|
|
* Afe_Block->pucPhysBufAddr = 0x%x\n", HW_Cur_ReadIdx,
|
|
* HW_memory_index, Afe_Block->pucPhysBufAddr);
|
|
*/
|
|
|
|
/* get hw consume bytes */
|
|
if (HW_memory_index >= Afe_Block->u4DMAReadIdx) {
|
|
Afe_consumed_bytes = HW_memory_index - Afe_Block->u4DMAReadIdx;
|
|
} else {
|
|
Afe_consumed_bytes = Afe_Block->u4BufferSize + HW_memory_index -
|
|
Afe_Block->u4DMAReadIdx;
|
|
}
|
|
|
|
Afe_consumed_bytes = word_size_align(Afe_consumed_bytes);
|
|
|
|
/* pr_debug("+%s ReadIdx:%x WriteIdx:%x,Remained:%x,
|
|
* consumed_bytes:%x HW_memory_index = %x\n", __func__,
|
|
* Afe_Block->u4DMAReadIdx, Afe_Block->u4WriteIdx,
|
|
* Afe_Block->u4DataRemained, Afe_consumed_bytes, HW_memory_index);
|
|
*/
|
|
|
|
if (Afe_Block->u4DataRemained < Afe_consumed_bytes ||
|
|
Afe_Block->u4DataRemained <= 0 ||
|
|
Afe_Block->u4DataRemained > Afe_Block->u4BufferSize) {
|
|
if (AFE_dL_Abnormal_context.u4UnderflowCnt <
|
|
DL_ABNORMAL_CONTROL_MAX) {
|
|
AFE_dL_Abnormal_context.pucPhysBufAddr
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Afe_Block->pucPhysBufAddr;
|
|
AFE_dL_Abnormal_context.u4BufferSize
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Afe_Block->u4BufferSize;
|
|
AFE_dL_Abnormal_context.u4ConsumedBytes
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Afe_consumed_bytes;
|
|
AFE_dL_Abnormal_context.u4DataRemained
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Afe_Block->u4DataRemained;
|
|
AFE_dL_Abnormal_context.u4DMAReadIdx
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Afe_Block->u4DMAReadIdx;
|
|
AFE_dL_Abnormal_context.u4HwMemoryIndex
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
HW_memory_index;
|
|
AFE_dL_Abnormal_context.u4WriteIdx
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Afe_Block->u4WriteIdx;
|
|
AFE_dL_Abnormal_context.MemIfNum
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Soc_Aud_Digital_Block_MEM_DL1;
|
|
}
|
|
AFE_dL_Abnormal_context.u4UnderflowCnt++;
|
|
} else {
|
|
/* pr_debug("+DL_Handling normal ReadIdx:%x ,DataRemained:%x,
|
|
* WriteIdx:%x\n", Afe_Block->u4DMAReadIdx,
|
|
* Afe_Block->u4DataRemained, Afe_Block->u4WriteIdx);
|
|
*/
|
|
Afe_Block->u4DataRemained -= Afe_consumed_bytes;
|
|
Afe_Block->u4DMAReadIdx += Afe_consumed_bytes;
|
|
Afe_Block->u4DMAReadIdx %= Afe_Block->u4BufferSize;
|
|
}
|
|
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_DL1]
|
|
->interruptTrigger = 1;
|
|
/* pr_debug("-DL_Handling normal ReadIdx:%x ,
|
|
* DataRemained:%x, WriteIdx:%x\n", Afe_Block->u4DMAReadIdx,
|
|
* Afe_Block->u4DataRemained,Afe_Block->u4WriteIdx);
|
|
*/
|
|
|
|
if (Mem_Block->substreamL != NULL) {
|
|
if (Mem_Block->substreamL->substream != NULL) {
|
|
Mem_Block->mWaitForIRQ = true;
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock,
|
|
flags);
|
|
snd_pcm_period_elapsed(
|
|
Mem_Block->substreamL->substream);
|
|
Mem_Block->mWaitForIRQ = false;
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
}
|
|
|
|
void Auddrv_DL1_Interrupt_Handler(void)
|
|
{
|
|
/* irq1 ISR handler */
|
|
struct afe_mem_control_t *Mem_Block =
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_DL1];
|
|
kal_int32 Afe_consumed_bytes = 0;
|
|
kal_int32 HW_memory_index = 0;
|
|
kal_int32 HW_Cur_ReadIdx = 0;
|
|
struct afe_block_t *Afe_Block = &(
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_DL1]->rBlock);
|
|
unsigned long flags;
|
|
|
|
if (Mem_Block == NULL)
|
|
return;
|
|
|
|
if (get_voice_usb_status() &&
|
|
GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_DL1)) {
|
|
if (Mem_Block->substreamL != NULL) {
|
|
if (Mem_Block->substreamL->substream != NULL)
|
|
snd_pcm_period_elapsed(
|
|
Mem_Block->substreamL->substream);
|
|
}
|
|
return;
|
|
}
|
|
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
|
|
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_DL1) == false) {
|
|
/* pr_debug("%s(),
|
|
* GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_DL1) == false,
|
|
* return\n ", __func__);
|
|
*/
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
HW_Cur_ReadIdx = Afe_Get_Reg(AFE_DL1_CUR);
|
|
|
|
if (HW_Cur_ReadIdx == 0) {
|
|
/* pr_debug("[Auddrv] HW_Cur_ReadIdx ==0\n"); */
|
|
HW_Cur_ReadIdx = Afe_Block->pucPhysBufAddr;
|
|
}
|
|
|
|
HW_memory_index = (HW_Cur_ReadIdx - Afe_Block->pucPhysBufAddr);
|
|
/* pr_debug("[Auddrv] HW_Cur_ReadIdx=0x%x HW_memory_index = 0x%x
|
|
* Afe_Block->pucPhysBufAddr = 0x%x\n",
|
|
* HW_Cur_ReadIdx, HW_memory_index, Afe_Block->pucPhysBufAddr);
|
|
*/
|
|
|
|
/* get hw consume bytes */
|
|
if (HW_memory_index >= Afe_Block->u4DMAReadIdx) {
|
|
Afe_consumed_bytes = HW_memory_index - Afe_Block->u4DMAReadIdx;
|
|
} else {
|
|
Afe_consumed_bytes = Afe_Block->u4BufferSize + HW_memory_index -
|
|
Afe_Block->u4DMAReadIdx;
|
|
}
|
|
|
|
Afe_consumed_bytes = word_size_align(Afe_consumed_bytes);
|
|
/* pr_debug("%s ReadIdx:%x WriteIdx:%x,Remained:%x,
|
|
* consumed_bytes:%x HW_memory_index = %x\n",
|
|
* __func__, Afe_Block->u4DMAReadIdx, Afe_Block->u4WriteIdx,
|
|
* Afe_Block->u4DataRemained, Afe_consumed_bytes, HW_memory_index);
|
|
*/
|
|
|
|
if (Afe_Block->u4DataRemained < Afe_consumed_bytes ||
|
|
Afe_Block->u4DataRemained <= 0 ||
|
|
Afe_Block->u4DataRemained > Afe_Block->u4BufferSize) {
|
|
if (AFE_dL_Abnormal_context.u4UnderflowCnt <
|
|
DL_ABNORMAL_CONTROL_MAX) {
|
|
AFE_dL_Abnormal_context.pucPhysBufAddr
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Afe_Block->pucPhysBufAddr;
|
|
AFE_dL_Abnormal_context.u4BufferSize
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Afe_Block->u4BufferSize;
|
|
AFE_dL_Abnormal_context.u4ConsumedBytes
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Afe_consumed_bytes;
|
|
AFE_dL_Abnormal_context.u4DataRemained
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Afe_Block->u4DataRemained;
|
|
AFE_dL_Abnormal_context.u4DMAReadIdx
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Afe_Block->u4DMAReadIdx;
|
|
AFE_dL_Abnormal_context.u4HwMemoryIndex
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
HW_memory_index;
|
|
AFE_dL_Abnormal_context.u4WriteIdx
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Afe_Block->u4WriteIdx;
|
|
AFE_dL_Abnormal_context.MemIfNum
|
|
[AFE_dL_Abnormal_context.u4UnderflowCnt] =
|
|
Soc_Aud_Digital_Block_MEM_DL1;
|
|
}
|
|
AFE_dL_Abnormal_context.u4UnderflowCnt++;
|
|
} else {
|
|
/* pr_debug("+DL_Handling normal ReadIdx:%x ,DataRemained:%x,
|
|
* WriteIdx:%x\n", Afe_Block->u4DMAReadIdx,
|
|
* Afe_Block->u4DataRemained, Afe_Block->u4WriteIdx);
|
|
*/
|
|
Afe_Block->u4DataRemained -= Afe_consumed_bytes;
|
|
Afe_Block->u4DMAReadIdx += Afe_consumed_bytes;
|
|
Afe_Block->u4DMAReadIdx %= Afe_Block->u4BufferSize;
|
|
}
|
|
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_DL1]
|
|
->interruptTrigger = 1;
|
|
/* pr_debug("-DL_Handling normal ReadIdx:%x ,DataRemained:%x,
|
|
* WriteIdx:%x\n", Afe_Block->u4DMAReadIdx, Afe_Block->u4DataRemained,
|
|
* Afe_Block->u4WriteIdx);
|
|
*/
|
|
|
|
if (Mem_Block->substreamL != NULL) {
|
|
if (Mem_Block->substreamL->substream != NULL) {
|
|
Mem_Block->mWaitForIRQ = true;
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock,
|
|
flags);
|
|
snd_pcm_period_elapsed(
|
|
Mem_Block->substreamL->substream);
|
|
Mem_Block->mWaitForIRQ = false;
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
}
|
|
|
|
void Auddrv_DL1_Data2_Interrupt_Handler(enum soc_aud_digital_block mem_block)
|
|
{
|
|
/* irq6 ISR handler */
|
|
struct afe_mem_control_t *Mem_Block =
|
|
AFE_Mem_Control_context[mem_block];
|
|
unsigned long flags;
|
|
|
|
if (GetMemoryPathEnable(mem_block)) {
|
|
if (Mem_Block->substreamL != NULL) {
|
|
if (Mem_Block->substreamL->substream != NULL) {
|
|
spin_lock_irqsave(&Mem_Block->substream_lock,
|
|
flags);
|
|
Mem_Block->mWaitForIRQ = true;
|
|
spin_unlock_irqrestore(
|
|
&Mem_Block->substream_lock, flags);
|
|
|
|
snd_pcm_period_elapsed(
|
|
Mem_Block->substreamL->substream);
|
|
|
|
spin_lock_irqsave(&Mem_Block->substream_lock,
|
|
flags);
|
|
Mem_Block->mWaitForIRQ = false;
|
|
spin_unlock_irqrestore(
|
|
&Mem_Block->substream_lock, flags);
|
|
}
|
|
}
|
|
} else {
|
|
pr_debug("%s, memif use wrong irq handler", __func__);
|
|
}
|
|
}
|
|
|
|
void Auddrv_DL2_Interrupt_Handler(void)
|
|
{
|
|
/* irq2 ISR handler */
|
|
struct afe_mem_control_t *Mem_Block =
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_DL2];
|
|
unsigned long flags;
|
|
|
|
if (Mem_Block == NULL)
|
|
return;
|
|
|
|
Auddrv_Dl2_Spinlock_lock();
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
|
|
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_DL2) == false) {
|
|
/* pr_debug("%s(),
|
|
* GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_DL2) == false,
|
|
* return\n ", __func__);
|
|
*/
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
Auddrv_Dl2_Spinlock_unlock();
|
|
return;
|
|
}
|
|
|
|
if (Mem_Block->substreamL != NULL) {
|
|
if (Mem_Block->substreamL->substream != NULL) {
|
|
Mem_Block->mWaitForIRQ = true;
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock,
|
|
flags);
|
|
snd_pcm_period_elapsed(
|
|
Mem_Block->substreamL->substream);
|
|
Mem_Block->mWaitForIRQ = false;
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
|
|
#ifdef AUDIO_DL2_ISR_COPY_SUPPORT
|
|
mtk_dl2_copy_l();
|
|
#endif
|
|
|
|
Auddrv_Dl2_Spinlock_unlock();
|
|
}
|
|
|
|
struct snd_dma_buffer *Get_Mem_Buffer(enum soc_aud_digital_block MemBlock)
|
|
{
|
|
pr_debug("%s MemBlock = %d\n", __func__, MemBlock);
|
|
switch (MemBlock) {
|
|
case Soc_Aud_Digital_Block_MEM_DL1:
|
|
return Audio_dma_buf[MemBlock];
|
|
case Soc_Aud_Digital_Block_MEM_DL2:
|
|
return Audio_dma_buf[MemBlock];
|
|
case Soc_Aud_Digital_Block_MEM_DL3:
|
|
return Audio_dma_buf[MemBlock];
|
|
case Soc_Aud_Digital_Block_MEM_VUL2:
|
|
case Soc_Aud_Digital_Block_MEM_VUL:
|
|
return Audio_dma_buf[MemBlock];
|
|
case Soc_Aud_Digital_Block_MEM_DAI:
|
|
return Audio_dma_buf[MemBlock];
|
|
case Soc_Aud_Digital_Block_MEM_AWB:
|
|
return Audio_dma_buf[MemBlock];
|
|
case Soc_Aud_Digital_Block_MEM_MOD_DAI:
|
|
return Audio_dma_buf[MemBlock];
|
|
/*
|
|
* case Soc_Aud_Digital_Block_MEM_DL1_DATA2:
|
|
* return Audio_dma_buf[MemBlock];
|
|
*/
|
|
case Soc_Aud_Digital_Block_MEM_VUL_DATA2:
|
|
return Audio_dma_buf[MemBlock];
|
|
case Soc_Aud_Digital_Block_MEM_HDMI:
|
|
return Audio_dma_buf[MemBlock];
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void Auddrv_UL1_Interrupt_Handler(void)
|
|
{
|
|
struct afe_mem_control_t *Mem_Block =
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_VUL];
|
|
kal_uint32 HW_Cur_ReadIdx = 0;
|
|
kal_int32 Hw_Get_bytes = 0;
|
|
struct afe_block_t *mBlock = NULL;
|
|
unsigned long flags;
|
|
struct snd_pcm_substream *temp_substream = NULL;
|
|
|
|
if (Mem_Block == NULL) {
|
|
pr_err("Mem_Block == NULL\n ");
|
|
return;
|
|
}
|
|
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
|
|
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_VUL) == false) {
|
|
/* pr_debug("%s(),
|
|
* GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_VUL) == false,
|
|
* return\n ", __func__);
|
|
*/
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
mBlock = &Mem_Block->rBlock;
|
|
HW_Cur_ReadIdx = word_size_align(Afe_Get_Reg(AFE_VUL_CUR));
|
|
|
|
if (CheckSize(HW_Cur_ReadIdx)) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
if (mBlock->pucVirtBufAddr == NULL) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
/* HW already fill in */
|
|
Hw_Get_bytes =
|
|
(HW_Cur_ReadIdx - mBlock->pucPhysBufAddr) - mBlock->u4WriteIdx;
|
|
|
|
if (Hw_Get_bytes < 0)
|
|
Hw_Get_bytes += mBlock->u4BufferSize;
|
|
|
|
/* pr_debug("%s Get_bytes:%x, Cur_ReadIdx:%x,ReadIdx:%x, WriteIdx:0x%x,
|
|
* BufAddr:%x MemIfNum = %d\n", __func__, Hw_Get_bytes, HW_Cur_ReadIdx,
|
|
* mBlock->u4DMAReadIdx, mBlock->u4WriteIdx,
|
|
* mBlock->pucPhysBufAddr, Mem_Block->MemIfNum);
|
|
*/
|
|
mBlock->u4WriteIdx += Hw_Get_bytes;
|
|
mBlock->u4WriteIdx %= mBlock->u4BufferSize;
|
|
mBlock->u4DataRemained += Hw_Get_bytes;
|
|
|
|
/* buffer overflow */
|
|
if (mBlock->u4DataRemained > mBlock->u4BufferSize) {
|
|
pr_debug(
|
|
"buffer overflow u4DMAReadIdx:%x,u4WriteIdx:%x, u4DataRemained:%x, u4BufferSize:%x\n",
|
|
mBlock->u4DMAReadIdx, mBlock->u4WriteIdx,
|
|
mBlock->u4DataRemained, mBlock->u4BufferSize);
|
|
}
|
|
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_VUL]
|
|
->interruptTrigger = 1;
|
|
|
|
if (Mem_Block->substreamL != NULL) {
|
|
if (Mem_Block->substreamL->substream != NULL) {
|
|
temp_substream = Mem_Block->substreamL->substream;
|
|
Mem_Block->mWaitForIRQ = true;
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock,
|
|
flags);
|
|
snd_pcm_period_elapsed(temp_substream);
|
|
Mem_Block->mWaitForIRQ = false;
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
}
|
|
|
|
static void Clear_Mem_CopySize(enum soc_aud_digital_block MemBlock)
|
|
{
|
|
struct substream_list *head;
|
|
/* unsigned long flags; */
|
|
/* spin_lock_irqsave(&AFE_Mem_Control_context[MemBlock]->substream_lock,
|
|
* flags);
|
|
*/
|
|
head = AFE_Mem_Control_context[MemBlock]->substreamL;
|
|
|
|
while (head != NULL) { /* frst item is NULL */
|
|
head->u4MaxCopySize = 0;
|
|
head = head->next;
|
|
}
|
|
}
|
|
|
|
kal_uint32 Get_Mem_CopySizeByStream(enum soc_aud_digital_block MemBlock,
|
|
struct snd_pcm_substream *substream)
|
|
{
|
|
struct substream_list *head;
|
|
unsigned long flags;
|
|
kal_uint32 MaxCopySize;
|
|
|
|
spin_lock_irqsave(&AFE_Mem_Control_context[MemBlock]->substream_lock,
|
|
flags);
|
|
head = AFE_Mem_Control_context[MemBlock]->substreamL;
|
|
|
|
/* pr_debug("+%s MemBlock = %d\n ", __func__, MemBlock); */
|
|
while (head != NULL) { /* frst item is NULL */
|
|
if (head->substream == substream) {
|
|
MaxCopySize = head->u4MaxCopySize;
|
|
spin_unlock_irqrestore(
|
|
&AFE_Mem_Control_context[MemBlock]
|
|
->substream_lock,
|
|
flags);
|
|
return MaxCopySize;
|
|
}
|
|
head = head->next;
|
|
}
|
|
spin_unlock_irqrestore(
|
|
&AFE_Mem_Control_context[MemBlock]->substream_lock, flags);
|
|
/* pr_debug("-%s MemBlock = %d\n ", __func__, MemBlock); */
|
|
|
|
return 0;
|
|
}
|
|
|
|
static kal_uint32 Get_Mem_MaxCopySize(enum soc_aud_digital_block MemBlock)
|
|
{
|
|
struct substream_list *head;
|
|
|
|
/* unsigned long flags; */
|
|
kal_uint32 MaxCopySize;
|
|
|
|
/* spin_lock_irqsave(&AFE_Mem_Control_context[MemBlock]->substream_lock,
|
|
* flags);
|
|
*/
|
|
head = AFE_Mem_Control_context[MemBlock]->substreamL;
|
|
MaxCopySize = 0;
|
|
/* pr_debug("+%s MemBlock = %d\n ", __func__, MemBlock); */
|
|
while (head != NULL) { /* frst item is NULL */
|
|
if (MaxCopySize < head->u4MaxCopySize)
|
|
MaxCopySize = head->u4MaxCopySize;
|
|
head = head->next;
|
|
}
|
|
|
|
/* spin_unlock_irqrestore(
|
|
* &AFE_Mem_Control_context[MemBlock]->substream_lock,
|
|
* flags);
|
|
*/
|
|
/* pr_debug("-%s MemBlock = %d\n ", __func__, MemBlock); */
|
|
return MaxCopySize;
|
|
}
|
|
|
|
void Set_Mem_CopySizeByStream(enum soc_aud_digital_block MemBlock,
|
|
struct snd_pcm_substream *substream,
|
|
unsigned int size)
|
|
{
|
|
struct substream_list *head;
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&AFE_Mem_Control_context[MemBlock]->substream_lock,
|
|
flags);
|
|
head = AFE_Mem_Control_context[MemBlock]->substreamL;
|
|
|
|
/* pr_debug("+%s MemBlock = %d\n ", __func__, MemBlock); */
|
|
while (head != NULL) { /* frst item is NULL */
|
|
if (head->substream == substream) {
|
|
head->u4MaxCopySize += size;
|
|
break;
|
|
}
|
|
head = head->next;
|
|
}
|
|
spin_unlock_irqrestore(
|
|
&AFE_Mem_Control_context[MemBlock]->substream_lock, flags);
|
|
/* pr_debug("-%s MemBlock = %d\n ", __func__, MemBlock); */
|
|
}
|
|
|
|
void Auddrv_UL2_Interrupt_Handler(void)
|
|
{
|
|
struct afe_mem_control_t *Mem_Block =
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_VUL_DATA2];
|
|
kal_uint32 HW_Cur_ReadIdx = 0;
|
|
kal_int32 Hw_Get_bytes = 0;
|
|
struct afe_block_t *mBlock = NULL;
|
|
unsigned long flags;
|
|
|
|
if (Mem_Block == NULL) {
|
|
pr_err("Mem_Block == NULL\n ");
|
|
return;
|
|
}
|
|
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
|
|
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_VUL_DATA2) == false) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
mBlock = &Mem_Block->rBlock;
|
|
HW_Cur_ReadIdx = word_size_align(Afe_Get_Reg(AFE_VUL_D2_CUR));
|
|
|
|
if (CheckSize(HW_Cur_ReadIdx)) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
if (mBlock->pucVirtBufAddr == NULL) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
/* HW already fill in */
|
|
Hw_Get_bytes =
|
|
(HW_Cur_ReadIdx - mBlock->pucPhysBufAddr) - mBlock->u4WriteIdx;
|
|
|
|
if (Hw_Get_bytes < 0)
|
|
Hw_Get_bytes += mBlock->u4BufferSize;
|
|
|
|
/* pr_debug("%s Get_bytes:%x, Cur_ReadIdx:%x,RadIdx:%x, WriteIdx:0x%x,
|
|
* BufAddr:%x MemIfNum = %d\n", __func__, Hw_Get_bytes, HW_Cur_ReadIdx,
|
|
* mBlock->u4DMAReadIdx, mBlock->u4WriteIdx, mBlock->pucPhysBufAddr,
|
|
* Mem_Block->MemIfNum);
|
|
*/
|
|
|
|
mBlock->u4WriteIdx += Hw_Get_bytes;
|
|
mBlock->u4WriteIdx %= mBlock->u4BufferSize;
|
|
mBlock->u4DataRemained += Hw_Get_bytes;
|
|
|
|
/* buffer overflow */
|
|
if (mBlock->u4DataRemained > mBlock->u4BufferSize) {
|
|
pr_debug(
|
|
"buffer overflow u4DMAReadIdx:%x,u4WriteIdx:%x, u4DataRemained:%x, u4BufferSize:%x\n",
|
|
mBlock->u4DMAReadIdx, mBlock->u4WriteIdx,
|
|
mBlock->u4DataRemained, mBlock->u4BufferSize);
|
|
}
|
|
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_VUL_DATA2]
|
|
->interruptTrigger = 1;
|
|
|
|
if (Mem_Block->substreamL != NULL) {
|
|
if (Mem_Block->substreamL->substream != NULL) {
|
|
Mem_Block->mWaitForIRQ = true;
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock,
|
|
flags);
|
|
snd_pcm_period_elapsed(
|
|
Mem_Block->substreamL->substream);
|
|
Mem_Block->mWaitForIRQ = false;
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
}
|
|
|
|
void Auddrv_MOD_DAI_Interrupt_Handler(void)
|
|
{
|
|
struct afe_mem_control_t *Mem_Block =
|
|
AFE_Mem_Control_context[Soc_Aud_Digital_Block_MEM_MOD_DAI];
|
|
kal_uint32 HW_Cur_ReadIdx = 0;
|
|
kal_int32 Hw_Get_bytes = 0;
|
|
struct afe_block_t *mBlock = NULL;
|
|
unsigned long flags;
|
|
|
|
if (Mem_Block == NULL)
|
|
return;
|
|
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_MOD_DAI) == false) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
mBlock = &Mem_Block->rBlock;
|
|
HW_Cur_ReadIdx = word_size_align(Afe_Get_Reg(AFE_MOD_DAI_CUR));
|
|
|
|
if (CheckSize(HW_Cur_ReadIdx)) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
if (mBlock->pucVirtBufAddr == NULL) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
return;
|
|
}
|
|
|
|
Hw_Get_bytes =
|
|
(HW_Cur_ReadIdx - mBlock->pucPhysBufAddr) - mBlock->u4WriteIdx;
|
|
if (Hw_Get_bytes < 0)
|
|
Hw_Get_bytes += mBlock->u4BufferSize;
|
|
|
|
mBlock->u4WriteIdx += Hw_Get_bytes;
|
|
mBlock->u4WriteIdx %= mBlock->u4BufferSize;
|
|
mBlock->u4DataRemained += Hw_Get_bytes;
|
|
|
|
if (mBlock->u4DataRemained > mBlock->u4BufferSize) {
|
|
pr_warn("%s buffer overflow u4DMAReadIdx:%x, u4WriteIdx:%x, u4DataRemained:%x, u4BufferSize:%x\n",
|
|
__func__, mBlock->u4DMAReadIdx, mBlock->u4WriteIdx,
|
|
mBlock->u4DataRemained, mBlock->u4BufferSize);
|
|
}
|
|
Mem_Block->interruptTrigger = 1;
|
|
|
|
if (Mem_Block->substreamL != NULL) {
|
|
if (Mem_Block->substreamL->substream != NULL) {
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock,
|
|
flags);
|
|
snd_pcm_period_elapsed(
|
|
Mem_Block->substreamL->substream);
|
|
spin_lock_irqsave(&Mem_Block->substream_lock, flags);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&Mem_Block->substream_lock, flags);
|
|
}
|
|
|
|
bool Restore_Audio_Register(void)
|
|
{
|
|
/* 6752 TODO? */
|
|
return true;
|
|
}
|
|
|
|
unsigned int word_size_align(unsigned int in_size)
|
|
{
|
|
unsigned int align_size;
|
|
|
|
#if defined(CONFIG_MTK_AUDIO_SCP_SPKPROTECT_SUPPORT)
|
|
if (scp_smartpa_used_flag) {
|
|
/* SCP use cache. Cache use 32 bytes data alignment */
|
|
align_size = in_size & 0xFFFFFFE0;
|
|
} else
|
|
#endif
|
|
{
|
|
/* sram is device memory, need word size align,
|
|
* 8 byte for 64 bit platform.
|
|
* [3:0] = 4'h0 for the convenience of the hardware
|
|
* implementation.
|
|
*/
|
|
align_size = in_size & 0xFFFFFFF0;
|
|
}
|
|
|
|
return align_size;
|
|
}
|
|
|
|
void AudDrv_checkDLISRStatus(void)
|
|
{
|
|
unsigned long flags1;
|
|
struct afe_dl_abnormal_control_t localctl;
|
|
bool dumplog = false;
|
|
|
|
spin_lock_irqsave(&afe_dl_abnormal_context_lock, flags1);
|
|
if (AFE_dL_Abnormal_context.IrqDelayCnt ||
|
|
AFE_dL_Abnormal_context.u4UnderflowCnt) {
|
|
memcpy((void *)&localctl, (void *)&AFE_dL_Abnormal_context,
|
|
sizeof(struct afe_dl_abnormal_control_t));
|
|
dumplog = true;
|
|
if (AFE_dL_Abnormal_context.IrqDelayCnt > 0)
|
|
AFE_dL_Abnormal_context.IrqDelayCnt = 0;
|
|
|
|
if (AFE_dL_Abnormal_context.u4UnderflowCnt > 0)
|
|
AFE_dL_Abnormal_context.u4UnderflowCnt = 0;
|
|
}
|
|
spin_unlock_irqrestore(&afe_dl_abnormal_context_lock, flags1);
|
|
|
|
if (dumplog) {
|
|
int index = 0;
|
|
|
|
if (localctl.IrqDelayCnt) {
|
|
for (index = 0; index < localctl.IrqDelayCnt &&
|
|
index < DL_ABNORMAL_CONTROL_MAX;
|
|
index++) {
|
|
pr_warn("AudWarn isr blocked [%d/%d] %llu - %llu = %llu > %d ms\n",
|
|
index, localctl.IrqDelayCnt,
|
|
localctl.IrqCurrentTimeNs[index],
|
|
localctl.IrqLastTimeNs[index],
|
|
localctl.IrqIntervalNs[index],
|
|
localctl.IrqIntervalLimitMs[index]);
|
|
}
|
|
}
|
|
if (localctl.u4UnderflowCnt) {
|
|
for (index = 0; index < localctl.u4UnderflowCnt &&
|
|
index < DL_ABNORMAL_CONTROL_MAX;
|
|
index++) {
|
|
static DEFINE_RATELIMIT_STATE(_rs, HZ, 5);
|
|
|
|
if (__ratelimit(&_rs)) {
|
|
pr_warn(
|
|
"AudWarn data underflow [%d/%d] MemType %d, Remain:0x%x, R:0x%x W:0x%x, BufSize:0x%x, consumebyte:0x%x, hw index:0x%x, addr:0x%x\n",
|
|
index,
|
|
localctl.u4UnderflowCnt,
|
|
localctl.MemIfNum[index],
|
|
localctl.u4DataRemained[index],
|
|
localctl.u4DMAReadIdx[index],
|
|
localctl.u4WriteIdx[index],
|
|
localctl.u4BufferSize[index],
|
|
localctl.u4ConsumedBytes[index],
|
|
localctl.u4HwMemoryIndex[index],
|
|
localctl.pucPhysBufAddr[index]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void update_sram_block_valid(enum audio_sram_mode mode)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < mAud_Sram_Manager.mBlocknum; i++) {
|
|
if ((i + 1) * mAud_Sram_Manager.mBlockSize >
|
|
sram_mode_size[mode]) {
|
|
mAud_Sram_Manager.mAud_Sram_Block[i].mValid = false;
|
|
} else {
|
|
mAud_Sram_Manager.mAud_Sram_Block[i].mValid = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool InitSramManager(struct device *pDev, unsigned int sramblocksize)
|
|
{
|
|
int i = 0;
|
|
|
|
memset((void *)&mAud_Sram_Manager, 0,
|
|
sizeof(struct audio_sram_manager));
|
|
mAud_Sram_Manager.msram_phys_addr = Get_Afe_Sram_Phys_Addr();
|
|
mAud_Sram_Manager.msram_virt_addr = Get_Afe_SramBase_Pointer();
|
|
mAud_Sram_Manager.mSramLength = Get_Afe_Sram_Length();
|
|
mAud_Sram_Manager.mBlockSize = sramblocksize;
|
|
mAud_Sram_Manager.mBlocknum =
|
|
(mAud_Sram_Manager.mSramLength / mAud_Sram_Manager.mBlockSize);
|
|
|
|
pr_debug("%s mBlocknum = %d mAud_Sram_Manager.mSramLength = %d mAud_Sram_Manager.mBlockSize = %d\n",
|
|
__func__, mAud_Sram_Manager.mBlocknum,
|
|
mAud_Sram_Manager.mSramLength, mAud_Sram_Manager.mBlockSize);
|
|
|
|
/* Dynamic allocate mAud_Sram_Block according to mBlocknum */
|
|
mAud_Sram_Manager.mAud_Sram_Block =
|
|
devm_kzalloc(pDev, mAud_Sram_Manager.mBlocknum *
|
|
sizeof(struct audio_sram_block),
|
|
GFP_KERNEL);
|
|
if (!mAud_Sram_Manager.mAud_Sram_Block)
|
|
return -ENOMEM;
|
|
for (i = 0; i < mAud_Sram_Manager.mBlocknum; i++) {
|
|
mAud_Sram_Manager.mAud_Sram_Block[i].mValid = true;
|
|
mAud_Sram_Manager.mAud_Sram_Block[i].mLength =
|
|
mAud_Sram_Manager.mBlockSize;
|
|
mAud_Sram_Manager.mAud_Sram_Block[i].mUser = 0;
|
|
mAud_Sram_Manager.mAud_Sram_Block[i].msram_phys_addr =
|
|
mAud_Sram_Manager.msram_phys_addr + (sramblocksize * i);
|
|
mAud_Sram_Manager.mAud_Sram_Block[i].msram_virt_addr =
|
|
(void *)((char *)mAud_Sram_Manager.msram_virt_addr +
|
|
(sramblocksize * (dma_addr_t)i));
|
|
}
|
|
|
|
/* init for normal mode or compact mode */
|
|
mAud_Sram_Manager.sram_mode = get_prefer_sram_mode();
|
|
update_sram_block_valid(mAud_Sram_Manager.sram_mode);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CheckSramAvail(unsigned int mSramLength, unsigned int *mSramBlockidx,
|
|
unsigned int *mSramBlocknum)
|
|
{
|
|
unsigned int MaxSramSize = 0;
|
|
bool StartRecord = false;
|
|
struct audio_sram_block *SramBlock = NULL;
|
|
int i = 0;
|
|
|
|
*mSramBlockidx = 0;
|
|
|
|
for (i = 0; i < mAud_Sram_Manager.mBlocknum; i++) {
|
|
SramBlock = &mAud_Sram_Manager.mAud_Sram_Block[i];
|
|
if ((SramBlock->mUser == NULL) && SramBlock->mValid) {
|
|
MaxSramSize += mAud_Sram_Manager.mBlockSize;
|
|
if (StartRecord == false) {
|
|
StartRecord = true;
|
|
*mSramBlockidx = i;
|
|
}
|
|
(*mSramBlocknum)++;
|
|
|
|
/* can callocate sram */
|
|
if (MaxSramSize >= mSramLength)
|
|
break;
|
|
}
|
|
|
|
/* when reach allocate buffer , reset condition*/
|
|
if ((SramBlock->mUser != NULL) && SramBlock->mValid) {
|
|
MaxSramSize = 0;
|
|
*mSramBlocknum = 0;
|
|
*mSramBlockidx = 0;
|
|
StartRecord = false;
|
|
}
|
|
|
|
if (SramBlock->mValid == 0) {
|
|
pr_warn("%s SramBlock->mValid == 0 i = %d\n", __func__,
|
|
i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
pr_info("%s MaxSramSize = %d mSramLength = %d mSramBlockidx = %d mSramBlocknum= %d\n",
|
|
__func__, MaxSramSize, mSramLength, *mSramBlockidx,
|
|
*mSramBlocknum);
|
|
|
|
if (MaxSramSize >= mSramLength)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
int AllocateAudioSram(dma_addr_t *sram_phys_addr,
|
|
unsigned char **msram_virt_addr, unsigned int mSramLength,
|
|
void *user, snd_pcm_format_t format, bool force_normal)
|
|
{
|
|
unsigned int SramBlockNum = 0;
|
|
unsigned int SramBlockidx = 0;
|
|
struct audio_sram_block *sram_block = NULL;
|
|
enum audio_sram_mode request_sram_mode;
|
|
bool has_user = false;
|
|
int ret = 0;
|
|
int i;
|
|
|
|
AfeControlSramLock();
|
|
|
|
/* check if sram has user */
|
|
for (i = 0; i < mAud_Sram_Manager.mBlocknum; i++) {
|
|
sram_block = &mAud_Sram_Manager.mAud_Sram_Block[i];
|
|
if (sram_block->mValid == true && sram_block->mUser != NULL) {
|
|
has_user = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* get sram mode for this request */
|
|
if (force_normal) {
|
|
request_sram_mode = audio_sram_normal_mode;
|
|
} else {
|
|
if (format == SNDRV_PCM_FORMAT_S32_LE ||
|
|
format == SNDRV_PCM_FORMAT_U32_LE) {
|
|
request_sram_mode =
|
|
has_user ? mAud_Sram_Manager.sram_mode
|
|
: get_prefer_sram_mode();
|
|
} else {
|
|
request_sram_mode = audio_sram_normal_mode;
|
|
}
|
|
}
|
|
|
|
/* change sram mode if needed */
|
|
if (mAud_Sram_Manager.sram_mode != request_sram_mode) {
|
|
if (has_user) {
|
|
pr_debug("%s(), cannot change mode to %d\n", __func__,
|
|
request_sram_mode);
|
|
AfeControlSramUnLock();
|
|
return -ENOMEM;
|
|
}
|
|
|
|
mAud_Sram_Manager.sram_mode = request_sram_mode;
|
|
update_sram_block_valid(mAud_Sram_Manager.sram_mode);
|
|
}
|
|
|
|
set_sram_mode(mAud_Sram_Manager.sram_mode);
|
|
|
|
if (CheckSramAvail(mSramLength, &SramBlockidx, &SramBlockNum) == true) {
|
|
*sram_phys_addr =
|
|
mAud_Sram_Manager.mAud_Sram_Block[SramBlockidx]
|
|
.msram_phys_addr;
|
|
*msram_virt_addr =
|
|
(char *)mAud_Sram_Manager.mAud_Sram_Block[SramBlockidx]
|
|
.msram_virt_addr;
|
|
|
|
/* set aud sram with user*/
|
|
while (SramBlockNum) {
|
|
mAud_Sram_Manager.mAud_Sram_Block[SramBlockidx].mUser =
|
|
user;
|
|
SramBlockNum--;
|
|
SramBlockidx++;
|
|
}
|
|
AfeControlSramUnLock();
|
|
} else {
|
|
AfeControlSramUnLock();
|
|
ret = -ENOMEM;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int freeAudioSram(void *user)
|
|
{
|
|
unsigned int i = 0;
|
|
struct audio_sram_block *SramBlock = NULL;
|
|
|
|
AfeControlSramLock();
|
|
for (i = 0; i < mAud_Sram_Manager.mBlocknum; i++) {
|
|
SramBlock = &mAud_Sram_Manager.mAud_Sram_Block[i];
|
|
if (SramBlock->mUser == user) {
|
|
SramBlock->mUser = NULL;
|
|
/* pr_debug("%s SramBlockidx = %d\n", __func__, i); */
|
|
}
|
|
}
|
|
AfeControlSramUnLock();
|
|
return 0;
|
|
}
|
|
|
|
/* IRQ Manager */
|
|
static int enable_aud_irq(const struct irq_user *_irq_user,
|
|
enum Soc_Aud_IRQ_MCU_MODE _irq, unsigned int _rate,
|
|
unsigned int _count)
|
|
{
|
|
SetIrqMcuSampleRate(_irq, _rate);
|
|
SetIrqMcuCounter(_irq, _count);
|
|
SetIrqEnable(_irq, true);
|
|
|
|
irq_managers[_irq].is_on = true;
|
|
irq_managers[_irq].rate = _rate;
|
|
irq_managers[_irq].count = _count;
|
|
irq_managers[_irq].selected_user = _irq_user;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int disable_aud_irq(enum Soc_Aud_IRQ_MCU_MODE _irq)
|
|
{
|
|
SetIrqEnable(_irq, false);
|
|
SetIrqMcuCounter(_irq, 0);
|
|
|
|
irq_managers[_irq].is_on = false;
|
|
irq_managers[_irq].count = 0;
|
|
irq_managers[_irq].selected_user = NULL;
|
|
return 0;
|
|
}
|
|
|
|
static int update_aud_irq(const struct irq_user *_irq_user,
|
|
enum Soc_Aud_IRQ_MCU_MODE _irq, unsigned int _count)
|
|
{
|
|
SetIrqMcuCounter(_irq, _count);
|
|
irq_managers[_irq].count = _count;
|
|
irq_managers[_irq].selected_user = _irq_user;
|
|
return 0;
|
|
}
|
|
|
|
static void dump_irq_manager(void)
|
|
{
|
|
struct irq_user *ptr;
|
|
int i;
|
|
|
|
for (i = 0; i < Soc_Aud_IRQ_MCU_MODE_NUM; i++) {
|
|
pr_info("irq_managers[%d], is_on %d, rate %d, count %d, selected_user %p\n",
|
|
i, irq_managers[i].is_on, irq_managers[i].rate,
|
|
irq_managers[i].count,
|
|
(void *)irq_managers[i].selected_user);
|
|
|
|
list_for_each_entry(ptr, &irq_managers[i].users, list) {
|
|
pr_info("\tirq_user: user %p, rate %d, count %d\n",
|
|
ptr->user, ptr->request_rate,
|
|
ptr->request_count);
|
|
}
|
|
}
|
|
}
|
|
|
|
static unsigned int get_tgt_count(unsigned int _rate, unsigned int _count,
|
|
unsigned int _tgt_rate)
|
|
{
|
|
return ((_tgt_rate / 100) * _count) / (_rate / 100);
|
|
}
|
|
|
|
static bool is_tgt_rate_ok(unsigned int _rate, unsigned int _count,
|
|
unsigned int _tgt_rate)
|
|
{
|
|
unsigned int tgt_rate = _tgt_rate / 100;
|
|
unsigned int request_rate = _rate / 100;
|
|
unsigned int target_cnt = get_tgt_count(_rate, _count, _tgt_rate);
|
|
unsigned int val_1 = _count * tgt_rate;
|
|
unsigned int val_2 = target_cnt * request_rate;
|
|
unsigned int val_3 = (IRQ_TOLERANCE_US * tgt_rate * request_rate) / 100;
|
|
|
|
if (target_cnt <= 1)
|
|
return false;
|
|
|
|
if (val_1 > val_2) {
|
|
if (val_1 - val_2 >= val_3)
|
|
return false;
|
|
} else {
|
|
if (val_2 - val_1 >= val_3)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool is_period_smaller(enum Soc_Aud_IRQ_MCU_MODE _irq,
|
|
struct irq_user *_user)
|
|
{
|
|
const struct irq_user *selected_user = irq_managers[_irq].selected_user;
|
|
|
|
if (selected_user != NULL) {
|
|
if (get_tgt_count(_user->request_rate, _user->request_count,
|
|
IRQ_MAX_RATE) >=
|
|
get_tgt_count(selected_user->request_rate,
|
|
selected_user->request_count, IRQ_MAX_RATE))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static const struct irq_user *
|
|
get_min_period_user(enum Soc_Aud_IRQ_MCU_MODE _irq)
|
|
{
|
|
struct irq_user *ptr;
|
|
struct irq_user *min_user = NULL;
|
|
unsigned int min_count = IRQ_MAX_RATE;
|
|
unsigned int cur_count;
|
|
|
|
if (list_empty(&irq_managers[_irq].users)) {
|
|
pr_info("error, irq_managers[%d].users is empty\n", _irq);
|
|
dump_irq_manager();
|
|
AUDIO_AEE("error, irq_managers[].users is empty\n");
|
|
}
|
|
|
|
list_for_each_entry(ptr, &irq_managers[_irq].users, list) {
|
|
cur_count = get_tgt_count(ptr->request_rate, ptr->request_count,
|
|
IRQ_MAX_RATE);
|
|
if (cur_count < min_count) {
|
|
min_count = cur_count;
|
|
min_user = ptr;
|
|
}
|
|
}
|
|
|
|
return min_user;
|
|
}
|
|
|
|
static int check_and_update_irq(const struct irq_user *_irq_user,
|
|
enum Soc_Aud_IRQ_MCU_MODE _irq)
|
|
{
|
|
if (_irq_user == NULL) {
|
|
pr_info("error, irq_user is empty\n");
|
|
return -EINVAL;
|
|
}
|
|
if (!is_tgt_rate_ok(_irq_user->request_rate, _irq_user->request_count,
|
|
irq_managers[_irq].rate)) {
|
|
/* if you got here, you should reconsider your irq usage */
|
|
pr_info("error, irq not updated, irq %d, irq rate %d, rate %d, count %d\n",
|
|
_irq, irq_managers[_irq].rate, _irq_user->request_rate,
|
|
_irq_user->request_count);
|
|
dump_irq_manager();
|
|
|
|
/* mt6797 disable for MP, enable before enter SQC !!!! */
|
|
/* AUDIO_AEE("error, irq not updated\n"); */
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
update_aud_irq(_irq_user, _irq, get_tgt_count(_irq_user->request_rate,
|
|
_irq_user->request_count,
|
|
irq_managers[_irq].rate));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int init_irq_manager(void)
|
|
{
|
|
int i;
|
|
|
|
memset((void *)&irq_managers, 0, sizeof(irq_managers));
|
|
for (i = 0; i < Soc_Aud_IRQ_MCU_MODE_NUM; i++)
|
|
INIT_LIST_HEAD(&irq_managers[i].users);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int irq_add_substream_user(struct snd_pcm_substream *substream,
|
|
enum Soc_Aud_IRQ_MCU_MODE _irq, unsigned int _rate,
|
|
unsigned int _count)
|
|
{
|
|
if (substream->runtime->no_period_wakeup == true)
|
|
return 0;
|
|
else
|
|
return irq_add_user(substream, _irq, _rate, _count);
|
|
}
|
|
|
|
int irq_add_user(const void *_user, enum Soc_Aud_IRQ_MCU_MODE _irq,
|
|
unsigned int _rate, unsigned int _count)
|
|
{
|
|
unsigned long flags;
|
|
struct irq_user *new_user;
|
|
struct irq_user *ptr;
|
|
|
|
spin_lock_irqsave(&afe_control_lock, flags);
|
|
list_for_each_entry(ptr, &irq_managers[_irq].users, list) {
|
|
if (ptr->user == _user) {
|
|
pr_info("error, _user %p already exist\n", _user);
|
|
dump_irq_manager();
|
|
AUDIO_AEE("error, _user already exist\n");
|
|
}
|
|
}
|
|
|
|
/* create instance */
|
|
new_user = kzalloc(sizeof(*new_user), GFP_ATOMIC);
|
|
if (!new_user) {
|
|
spin_unlock_irqrestore(&afe_control_lock, flags);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
new_user->user = _user;
|
|
new_user->request_rate = _rate;
|
|
new_user->request_count = _count;
|
|
INIT_LIST_HEAD(&new_user->list);
|
|
|
|
/* add user to list */
|
|
list_add(&new_user->list, &irq_managers[_irq].users);
|
|
|
|
/* */
|
|
if (irq_managers[_irq].is_on) {
|
|
if (is_period_smaller(_irq, new_user))
|
|
check_and_update_irq(new_user, _irq);
|
|
} else {
|
|
enable_aud_irq(new_user, _irq, _rate, _count);
|
|
}
|
|
|
|
spin_unlock_irqrestore(&afe_control_lock, flags);
|
|
return 0;
|
|
}
|
|
|
|
int irq_remove_user(const void *_user, enum Soc_Aud_IRQ_MCU_MODE _irq)
|
|
{
|
|
unsigned long flags;
|
|
struct irq_user *ptr;
|
|
struct irq_user *corr_user = NULL;
|
|
|
|
spin_lock_irqsave(&afe_control_lock, flags);
|
|
list_for_each_entry(ptr, &irq_managers[_irq].users, list) {
|
|
if (ptr->user == _user) {
|
|
corr_user = ptr;
|
|
break;
|
|
}
|
|
}
|
|
if (corr_user == NULL) {
|
|
pr_info("%s(), error, _user not found\n", __func__);
|
|
dump_irq_manager();
|
|
AUDIO_AEE("error, _user not found\n");
|
|
spin_unlock_irqrestore(&afe_control_lock, flags);
|
|
return -EINVAL;
|
|
}
|
|
/* remove from irq_handler[_irq].users */
|
|
list_del(&corr_user->list);
|
|
|
|
/* check if is selected user */
|
|
if (corr_user == irq_managers[_irq].selected_user) {
|
|
if (list_empty(&irq_managers[_irq].users))
|
|
disable_aud_irq(_irq);
|
|
else
|
|
check_and_update_irq(get_min_period_user(_irq), _irq);
|
|
}
|
|
/* free */
|
|
kfree(corr_user);
|
|
|
|
spin_unlock_irqrestore(&afe_control_lock, flags);
|
|
return 0;
|
|
}
|
|
|
|
int irq_remove_substream_user(struct snd_pcm_substream *substream,
|
|
enum Soc_Aud_IRQ_MCU_MODE _irq)
|
|
{
|
|
/* for no period wake up , do not set irq*/
|
|
if (substream->runtime->no_period_wakeup == true)
|
|
return 0;
|
|
else
|
|
return irq_remove_user(substream, _irq);
|
|
}
|
|
|
|
int irq_update_user(const void *_user, enum Soc_Aud_IRQ_MCU_MODE _irq,
|
|
unsigned int _rate, unsigned int _count)
|
|
{
|
|
unsigned long flags;
|
|
struct irq_user *ptr;
|
|
struct irq_user *corr_user = NULL;
|
|
|
|
spin_lock_irqsave(&afe_control_lock, flags);
|
|
list_for_each_entry(ptr, &irq_managers[_irq].users, list) {
|
|
if (ptr->user == _user) {
|
|
corr_user = ptr;
|
|
break;
|
|
}
|
|
}
|
|
if (corr_user == NULL) {
|
|
pr_err("%s(), error, _user not found\n", __func__);
|
|
dump_irq_manager();
|
|
AUDIO_AEE("error, _user not found\n");
|
|
spin_unlock_irqrestore(&afe_control_lock, flags);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* if _rate == 0, just update count */
|
|
if (_rate)
|
|
corr_user->request_rate = _rate;
|
|
|
|
corr_user->request_count = _count;
|
|
|
|
/* update irq user */
|
|
if (corr_user == irq_managers[_irq].selected_user) {
|
|
/* selected user */
|
|
check_and_update_irq(get_min_period_user(_irq), _irq);
|
|
} else {
|
|
/* not selected user */
|
|
if (is_period_smaller(_irq, corr_user))
|
|
check_and_update_irq(corr_user, _irq);
|
|
}
|
|
|
|
spin_unlock_irqrestore(&afe_control_lock, flags);
|
|
return 0;
|
|
}
|
|
|
|
int irq_get_total_user(enum Soc_Aud_IRQ_MCU_MODE _irq)
|
|
{
|
|
unsigned long flags;
|
|
struct irq_user *ptr;
|
|
unsigned int users = 0;
|
|
|
|
spin_lock_irqsave(&afe_control_lock, flags);
|
|
list_for_each_entry(ptr, &irq_managers[_irq].users, list) {
|
|
users++;
|
|
}
|
|
|
|
spin_unlock_irqrestore(&afe_control_lock, flags);
|
|
return users;
|
|
}
|
|
/* IRQ Manager END*/
|
|
|
|
/* memif lpbk api */
|
|
/*
|
|
* implementation of hw data delay mechanism using memif
|
|
* dl and ul memif share one same memory,
|
|
* buffer size is 2 * delay_us
|
|
* dl memif will start first, after a delay_us the ul will start
|
|
*/
|
|
static struct memif_lpbk *cur_memif_lpbk;
|
|
int memif_lpbk_enable(struct memif_lpbk *memif_lpbk)
|
|
{
|
|
size_t mem_size;
|
|
unsigned int format_bytes;
|
|
unsigned int rate = memif_lpbk->rate;
|
|
unsigned int delay_us = memif_lpbk->delay_us;
|
|
unsigned int format = memif_lpbk->format;
|
|
|
|
if (cur_memif_lpbk != NULL) {
|
|
pr_err("%s(), cur_memif_lpbk %p != NULL\n", __func__,
|
|
cur_memif_lpbk);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (memif_lpbk->enable) {
|
|
pr_err("%s(), memif_lpbk %p already enabled\n", __func__,
|
|
memif_lpbk);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (GetMemoryPathEnable(memif_lpbk->dl_memif)) {
|
|
pr_err("%s(), dl_memif %d in use\n", __func__,
|
|
memif_lpbk->dl_memif);
|
|
return -EBUSY;
|
|
}
|
|
|
|
if (GetMemoryPathEnable(memif_lpbk->ul_memif)) {
|
|
pr_err("%s(), ul_memif %d in use\n", __func__,
|
|
memif_lpbk->ul_memif);
|
|
return -EBUSY;
|
|
}
|
|
|
|
#ifdef MEMIF_LPBK_IRQ
|
|
if (irq_get_total_user(memif_lpbk->irq) != 0) {
|
|
pr_err("%s(), irq %d in use\n", __func__, memif_lpbk->irq);
|
|
return -EBUSY;
|
|
}
|
|
#endif
|
|
/* calculate memory size for delay_us */
|
|
if (format == SNDRV_PCM_FORMAT_S32_LE ||
|
|
format == SNDRV_PCM_FORMAT_U32_LE ||
|
|
format == SNDRV_PCM_FORMAT_S24_LE ||
|
|
format == SNDRV_PCM_FORMAT_U24_LE)
|
|
format_bytes = 4;
|
|
else
|
|
format_bytes = 2;
|
|
|
|
mem_size = ((delay_us * rate) / 1000000);
|
|
mem_size *= memif_lpbk->channel * format_bytes;
|
|
mem_size = word_size_align(mem_size);
|
|
|
|
pr_debug(
|
|
"%s(), ul_memif %d, dl_memif %d, rate %u, ch %u, fmt %d, delay_us %u, mem_size %zu\n",
|
|
__func__, memif_lpbk->ul_memif, memif_lpbk->dl_memif, rate,
|
|
memif_lpbk->channel, format, delay_us, mem_size);
|
|
|
|
AudDrv_Clk_On();
|
|
|
|
/* allocate memory */
|
|
memif_lpbk->dma_bytes = mem_size;
|
|
if (AllocateAudioSram(&memif_lpbk->dma_addr, &memif_lpbk->dma_area,
|
|
memif_lpbk->dma_bytes, memif_lpbk, format,
|
|
false) == 0) {
|
|
memif_lpbk->use_dram = false;
|
|
} else {
|
|
memif_lpbk->dma_area = dma_alloc_coherent(memif_lpbk->dev,
|
|
memif_lpbk->dma_bytes,
|
|
&memif_lpbk->dma_addr,
|
|
GFP_KERNEL | GFP_DMA);
|
|
if (!memif_lpbk->dma_area) {
|
|
pr_err("%s(), dma_alloc_coherent fail\n", __func__);
|
|
AudDrv_Clk_Off();
|
|
return -ENOMEM;
|
|
}
|
|
memif_lpbk->use_dram = true;
|
|
AudDrv_Emi_Clk_On();
|
|
}
|
|
|
|
memset_io(memif_lpbk->dma_area, 0, memif_lpbk->dma_bytes);
|
|
|
|
/* setup memif */
|
|
SetHighAddr(memif_lpbk->dl_memif, memif_lpbk->use_dram,
|
|
memif_lpbk->dma_addr);
|
|
SetHighAddr(memif_lpbk->ul_memif, memif_lpbk->use_dram,
|
|
memif_lpbk->dma_addr);
|
|
|
|
set_memif_addr(memif_lpbk->dl_memif, memif_lpbk->dma_addr,
|
|
memif_lpbk->dma_bytes);
|
|
SetSampleRate(memif_lpbk->dl_memif, memif_lpbk->rate);
|
|
SetChannels(memif_lpbk->dl_memif, memif_lpbk->channel);
|
|
|
|
set_memif_addr(memif_lpbk->ul_memif, memif_lpbk->dma_addr,
|
|
memif_lpbk->dma_bytes);
|
|
SetSampleRate(memif_lpbk->ul_memif, memif_lpbk->rate);
|
|
SetChannels(memif_lpbk->ul_memif, memif_lpbk->channel);
|
|
|
|
/* set memif format */
|
|
if (format == SNDRV_PCM_FORMAT_S32_LE ||
|
|
format == SNDRV_PCM_FORMAT_U32_LE ||
|
|
format == SNDRV_PCM_FORMAT_S24_LE ||
|
|
format == SNDRV_PCM_FORMAT_U24_LE) {
|
|
SetMemIfFetchFormatPerSample(
|
|
memif_lpbk->dl_memif,
|
|
AFE_WLEN_32_BIT_ALIGN_8BIT_0_24BIT_DATA);
|
|
SetMemIfFetchFormatPerSample(
|
|
memif_lpbk->ul_memif,
|
|
AFE_WLEN_32_BIT_ALIGN_8BIT_0_24BIT_DATA);
|
|
} else {
|
|
SetMemIfFetchFormatPerSample(memif_lpbk->dl_memif,
|
|
AFE_WLEN_16_BIT);
|
|
SetMemIfFetchFormatPerSample(memif_lpbk->ul_memif,
|
|
AFE_WLEN_16_BIT);
|
|
}
|
|
|
|
/* set pbuf size */
|
|
set_memif_pbuf_size(memif_lpbk->dl_memif, MEMIF_PBUF_SIZE_32_BYTES);
|
|
|
|
/* enable memif with a bit delay */
|
|
EnableAfe(true);
|
|
|
|
/* note: dl memif have prefetch buffer, it will have a leap at the
|
|
* beginning
|
|
*/
|
|
SetMemoryPathEnable(memif_lpbk->dl_memif, true);
|
|
udelay(30);
|
|
SetMemoryPathEnable(memif_lpbk->ul_memif, true);
|
|
|
|
pr_debug("%s(), memif_lpbk path hw enabled\n", __func__);
|
|
|
|
memif_lpbk->enable = true;
|
|
cur_memif_lpbk = memif_lpbk;
|
|
return 0;
|
|
}
|
|
|
|
int memif_lpbk_disable(struct memif_lpbk *memif_lpbk)
|
|
{
|
|
pr_debug("%s()\n", __func__);
|
|
|
|
if (!cur_memif_lpbk) {
|
|
pr_err("%s(), cur_memif_lpbk %p == NULL\n", __func__,
|
|
cur_memif_lpbk);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!memif_lpbk->enable) {
|
|
pr_err("%s(), memif_lpbk %p not enabled\n", __func__,
|
|
memif_lpbk);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SetMemoryPathEnable(memif_lpbk->dl_memif, false);
|
|
SetMemoryPathEnable(memif_lpbk->ul_memif, false);
|
|
/* resume pbuf size */
|
|
set_memif_pbuf_size(memif_lpbk->dl_memif, MEMIF_PBUF_SIZE_256_BYTES);
|
|
|
|
EnableAfe(false);
|
|
|
|
/* free memory */
|
|
if (memif_lpbk->use_dram) {
|
|
dma_free_coherent(memif_lpbk->dev, memif_lpbk->dma_bytes,
|
|
memif_lpbk->dma_area, memif_lpbk->dma_addr);
|
|
AudDrv_Emi_Clk_Off();
|
|
} else {
|
|
freeAudioSram(memif_lpbk);
|
|
}
|
|
|
|
AudDrv_Clk_Off();
|
|
memif_lpbk->enable = false;
|
|
cur_memif_lpbk = NULL;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef MEMIF_LPBK_IRQ
|
|
int memif_lpbk_irq_handler(void)
|
|
{
|
|
pr_debug("%s()\n", __func__);
|
|
if (!cur_memif_lpbk) {
|
|
pr_err("%s(), cur_memif_lpbk %p == NULL\n", __func__,
|
|
cur_memif_lpbk);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SetMemoryPathEnable(cur_memif_lpbk->ul_memif, true);
|
|
irq_remove_user(cur_memif_lpbk, cur_memif_lpbk->irq);
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool memif_lpbk_is_enable(void)
|
|
{
|
|
if (cur_memif_lpbk) {
|
|
if (cur_memif_lpbk->enable)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int memif_lpbk_get_irq(void)
|
|
{
|
|
if (cur_memif_lpbk)
|
|
return cur_memif_lpbk->irq;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/* api for other module */
|
|
static int irq_from_ext_module;
|
|
|
|
bool is_irq_from_ext_module(void)
|
|
{
|
|
return irq_from_ext_module > 0 ? true : false;
|
|
}
|
|
|
|
/* VCORE DVFS START*/
|
|
static void vcore_dvfs_enable(bool enable, bool reset)
|
|
{
|
|
#ifdef AUDIO_VCOREFS_SUPPORT
|
|
static DEFINE_MUTEX(vcore_control_mutex);
|
|
static int counter;
|
|
|
|
pr_debug("%s(), counter %d, enable %d, reset %d\n", __func__, counter,
|
|
enable, reset);
|
|
|
|
mutex_lock(&vcore_control_mutex);
|
|
if (enable) {
|
|
counter++;
|
|
if (counter == 1) {
|
|
vcorefs_request_dvfs_opp(KIR_AUDIO, OPPI_ULTRA_LOW_PWR);
|
|
pr_debug("%s(), OPPI_ULTRA_LOW_PWR\n", __func__);
|
|
}
|
|
} else {
|
|
counter--;
|
|
if (counter == 0) {
|
|
vcorefs_request_dvfs_opp(KIR_AUDIO, OPPI_UNREQ);
|
|
pr_debug("%s(), OPPI_UNREQ\n", __func__);
|
|
}
|
|
}
|
|
|
|
if (reset) {
|
|
counter = 0;
|
|
vcorefs_request_dvfs_opp(KIR_AUDIO, OPPI_UNREQ);
|
|
}
|
|
mutex_unlock(&vcore_control_mutex);
|
|
#endif
|
|
}
|
|
|
|
int vcore_dvfs(bool *enable, bool reset)
|
|
{
|
|
if (ScreenState == false && reset == false && *enable == false) {
|
|
*enable = true;
|
|
vcore_dvfs_enable(true, false);
|
|
} else if ((ScreenState == true || reset == true) && *enable == true) {
|
|
*enable = false;
|
|
vcore_dvfs_enable(false, false);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(vcore_dvfs);
|
|
|
|
void set_screen_state(bool state)
|
|
{
|
|
ScreenState = state;
|
|
}
|
|
EXPORT_SYMBOL(set_screen_state);
|
|
/* VCORE DVFS END*/
|
|
|
|
struct timeval ext_time;
|
|
struct timeval ext_time_prev;
|
|
struct timeval ext_time_diff;
|
|
|
|
static struct timeval ext_diff(struct timeval start, struct timeval end)
|
|
{
|
|
struct timeval temp;
|
|
|
|
if ((end.tv_usec - start.tv_usec) < 0) {
|
|
temp.tv_sec = end.tv_sec - start.tv_sec - 1;
|
|
temp.tv_usec = 1000000 + end.tv_usec - start.tv_usec;
|
|
} else {
|
|
temp.tv_sec = end.tv_sec - start.tv_sec;
|
|
temp.tv_usec = end.tv_usec - start.tv_usec;
|
|
}
|
|
return temp;
|
|
}
|
|
|
|
int start_ext_sync_signal(void)
|
|
{
|
|
unsigned int dl1_state;
|
|
|
|
ext_sync_signal_lock();
|
|
|
|
dl1_state = GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_DL1);
|
|
|
|
do_gettimeofday(&ext_time);
|
|
ext_time_prev = ext_time;
|
|
#if 0
|
|
pr_debug("%s(), irq_from_ext_module = %d, dl1_state = %d, time = %ld, %ld\n",
|
|
__func__,
|
|
irq_from_ext_module,
|
|
dl1_state,
|
|
ext_time.tv_sec,
|
|
ext_time.tv_usec);
|
|
#endif
|
|
irq_from_ext_module++;
|
|
|
|
if (dl1_state == true)
|
|
Auddrv_DL1_Interrupt_Handler();
|
|
|
|
ext_sync_signal_unlock();
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(start_ext_sync_signal);
|
|
|
|
int stop_ext_sync_signal(void)
|
|
{
|
|
unsigned int dl1_state;
|
|
|
|
ext_sync_signal_lock();
|
|
|
|
dl1_state = GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_DL1);
|
|
|
|
do_gettimeofday(&ext_time);
|
|
|
|
ext_time_diff = ext_diff(ext_time_prev, ext_time);
|
|
ext_time_prev = ext_time;
|
|
pr_debug("%s(), irq_from_ext_module = %d, dl1_state = %d, time diff= %ld, %ld\n",
|
|
__func__, irq_from_ext_module, dl1_state, ext_time_diff.tv_sec,
|
|
ext_time_diff.tv_usec);
|
|
|
|
if (irq_from_ext_module > 0) {
|
|
irq_from_ext_module--;
|
|
} else {
|
|
irq_from_ext_module = 0;
|
|
pr_warn("%s(), irq_from_ext_module %d <= 0\n", __func__,
|
|
irq_from_ext_module);
|
|
}
|
|
|
|
if (dl1_state == true)
|
|
Auddrv_DL1_Interrupt_Handler();
|
|
|
|
ext_sync_signal_unlock();
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(stop_ext_sync_signal);
|
|
|
|
int ext_sync_signal(void)
|
|
{
|
|
unsigned int dl1_state;
|
|
|
|
ext_sync_signal_lock();
|
|
|
|
dl1_state = GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_DL1);
|
|
|
|
do_gettimeofday(&ext_time);
|
|
|
|
ext_time_diff = ext_diff(ext_time_prev, ext_time);
|
|
ext_time_prev = ext_time;
|
|
pr_debug("%s(), irq_from_ext_module = %d, dl1_state = %d, time diff= %ld, %ld\n",
|
|
__func__, irq_from_ext_module, dl1_state, ext_time_diff.tv_sec,
|
|
ext_time_diff.tv_usec);
|
|
|
|
if (irq_from_ext_module && dl1_state == true)
|
|
Auddrv_DL1_Interrupt_Handler();
|
|
|
|
ext_sync_signal_unlock();
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(ext_sync_signal);
|
|
|
|
static DEFINE_SPINLOCK(ext_sync_lock);
|
|
static unsigned long ext_sync_lock_flags;
|
|
void ext_sync_signal_lock(void)
|
|
{
|
|
spin_lock_irqsave(&ext_sync_lock, ext_sync_lock_flags);
|
|
}
|
|
|
|
void ext_sync_signal_unlock(void)
|
|
{
|
|
spin_unlock_irqrestore(&ext_sync_lock, ext_sync_lock_flags);
|
|
}
|
|
|
|
/* api for other modules */
|
|
static int request_sram_count;
|
|
int mtk_audio_request_sram(dma_addr_t *phys_addr, unsigned char **virt_addr,
|
|
unsigned int length, void *user)
|
|
{
|
|
int ret;
|
|
|
|
pr_debug("%s(), user = %p, length = %d, count = %d\n", __func__, user,
|
|
length, request_sram_count);
|
|
|
|
AudDrv_Clk_On();
|
|
|
|
ret = AllocateAudioSram(phys_addr, virt_addr, length, user,
|
|
SNDRV_PCM_FORMAT_S32_LE, true);
|
|
if (ret) {
|
|
pr_warn("%s(), allocate sram fail, ret %d\n", __func__, ret);
|
|
AudDrv_Clk_Off();
|
|
return ret;
|
|
}
|
|
|
|
request_sram_count++;
|
|
|
|
pr_debug("%s(), return 0, count = %d\n", __func__, request_sram_count);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(mtk_audio_request_sram);
|
|
|
|
void mtk_audio_free_sram(void *user)
|
|
{
|
|
pr_debug("%s(), user = %p, count = %d\n", __func__, user,
|
|
request_sram_count);
|
|
|
|
freeAudioSram(user);
|
|
AudDrv_Clk_Off();
|
|
request_sram_count--;
|
|
|
|
pr_debug("%s(), return, count = %d\n", __func__, request_sram_count);
|
|
}
|
|
EXPORT_SYMBOL(mtk_audio_free_sram);
|
|
|
|
static snd_pcm_uframes_t
|
|
get_dlmem_frame_index(struct snd_pcm_substream *substream,
|
|
struct afe_mem_control_t *afe_mem_control,
|
|
enum soc_aud_digital_block mem_block)
|
|
{
|
|
kal_int32 HW_memory_index = 0;
|
|
kal_int32 HW_Cur_ReadIdx = 0;
|
|
unsigned long Frameidx = 0;
|
|
kal_int32 Afe_consumed_bytes = 0;
|
|
struct afe_block_t *Afe_Block = &afe_mem_control->rBlock;
|
|
unsigned long flags;
|
|
|
|
if (afe_mem_control == NULL) {
|
|
pr_err("%s err afe_mem_control = NULL", __func__);
|
|
return 0;
|
|
}
|
|
spin_lock_irqsave(&afe_mem_control->substream_lock, flags);
|
|
#ifdef AFE_CONTROL_DEBUG_LOG
|
|
pr_debug(" %s u4DMAReadIdx = 0x%x\n", __func__,
|
|
Afe_Block->u4DMAReadIdx);
|
|
#endif
|
|
if (GetMemoryPathEnable(mem_block) == true) {
|
|
switch (mem_block) {
|
|
case Soc_Aud_Digital_Block_MEM_DL1:
|
|
HW_Cur_ReadIdx = Afe_Get_Reg(AFE_DL1_CUR);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DL2:
|
|
HW_Cur_ReadIdx = Afe_Get_Reg(AFE_DL2_CUR);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DL3:
|
|
break;
|
|
default:
|
|
pr_info("%s err mem_block = %d", __func__, mem_block);
|
|
}
|
|
if (HW_Cur_ReadIdx == 0) {
|
|
pr_warn("[Auddrv] HW_Cur_ReadIdx ==0\n");
|
|
HW_Cur_ReadIdx = Afe_Block->pucPhysBufAddr;
|
|
}
|
|
HW_memory_index = (HW_Cur_ReadIdx - Afe_Block->pucPhysBufAddr);
|
|
if (HW_memory_index >= Afe_Block->u4DMAReadIdx)
|
|
Afe_consumed_bytes =
|
|
HW_memory_index - Afe_Block->u4DMAReadIdx;
|
|
else {
|
|
Afe_consumed_bytes = Afe_Block->u4BufferSize +
|
|
HW_memory_index -
|
|
Afe_Block->u4DMAReadIdx;
|
|
}
|
|
|
|
Afe_consumed_bytes = word_size_align(Afe_consumed_bytes);
|
|
|
|
/* if using mmap , do not calculate data remain*/
|
|
switch (substream->runtime->access) {
|
|
case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
|
|
case SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED:
|
|
break;
|
|
case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
|
|
case SNDRV_PCM_ACCESS_RW_NONINTERLEAVED:
|
|
default:
|
|
Afe_Block->u4DataRemained -= Afe_consumed_bytes;
|
|
break;
|
|
}
|
|
|
|
Afe_Block->u4DMAReadIdx += Afe_consumed_bytes;
|
|
Afe_Block->u4DMAReadIdx %= Afe_Block->u4BufferSize;
|
|
if (Afe_Block->u4DataRemained < 0) {
|
|
static DEFINE_RATELIMIT_STATE(_rs, HZ, 5);
|
|
|
|
if (__ratelimit(&_rs)) {
|
|
pr_warn(
|
|
"[AudioWarn] u4DataRemained=0x%x, mem_block %d\n",
|
|
Afe_Block->u4DataRemained, mem_block);
|
|
}
|
|
};
|
|
Frameidx = bytes_to_frames(substream->runtime,
|
|
Afe_Block->u4DMAReadIdx);
|
|
} else {
|
|
Frameidx = bytes_to_frames(substream->runtime,
|
|
Afe_Block->u4DMAReadIdx);
|
|
}
|
|
spin_unlock_irqrestore(&afe_mem_control->substream_lock, flags);
|
|
return Frameidx;
|
|
}
|
|
|
|
static snd_pcm_uframes_t
|
|
get_ulmem_frame_index(struct snd_pcm_substream *substream,
|
|
struct afe_mem_control_t *afe_mem_control,
|
|
enum soc_aud_digital_block mem_block)
|
|
{
|
|
kal_int32 HW_memory_index = 0;
|
|
kal_int32 HW_Cur_ReadIdx = 0;
|
|
kal_int32 Hw_Get_bytes = 0;
|
|
bool bIsOverflow = false;
|
|
unsigned long flags;
|
|
struct afe_block_t *UL1_Block = &(afe_mem_control->rBlock);
|
|
|
|
/* pr_debug("%s Awb_Block->u4WriteIdx;= 0x%x\n", __func__,
|
|
* UL1_Block->u4WriteIdx);
|
|
*/
|
|
mem_blk_spinlock(mem_block);
|
|
spin_lock_irqsave(&afe_mem_control->substream_lock, flags);
|
|
/* pr_debug("mtk_capture_pcm_pointer UL1_Block->u4WriteIdx= 0x%x,
|
|
* u4DataRemained=0x%x\n", UL1_Block->u4WriteIdx,
|
|
* UL1_Block->u4DataRemained);
|
|
*/
|
|
|
|
if (GetMemoryPathEnable(mem_block) == true) {
|
|
switch (mem_block) {
|
|
case Soc_Aud_Digital_Block_MEM_VUL:
|
|
HW_Cur_ReadIdx =
|
|
word_size_align(Afe_Get_Reg(AFE_VUL_CUR));
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DAI:
|
|
HW_Cur_ReadIdx =
|
|
word_size_align(Afe_Get_Reg(AFE_DAI_CUR));
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_AWB:
|
|
HW_Cur_ReadIdx =
|
|
word_size_align(Afe_Get_Reg(AFE_AWB_CUR));
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_MOD_DAI:
|
|
HW_Cur_ReadIdx =
|
|
word_size_align(Afe_Get_Reg(AFE_MOD_DAI_CUR));
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_VUL_DATA2:
|
|
HW_Cur_ReadIdx =
|
|
word_size_align(Afe_Get_Reg(AFE_VUL_D2_CUR));
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_VUL2:
|
|
HW_Cur_ReadIdx =
|
|
word_size_align(Afe_Get_Reg(AFE_VUL2_CUR));
|
|
break;
|
|
default:
|
|
pr_err("%s error mem_block = %d", __func__, mem_block);
|
|
}
|
|
if (HW_Cur_ReadIdx == 0) {
|
|
/* pr_debug("[Auddrv] %s HW_Cur_ReadIdx ==0\n",
|
|
* __func__);
|
|
*/
|
|
HW_Cur_ReadIdx = UL1_Block->pucPhysBufAddr;
|
|
}
|
|
HW_memory_index = (HW_Cur_ReadIdx - UL1_Block->pucPhysBufAddr);
|
|
|
|
/* update for data get to hardware */
|
|
Hw_Get_bytes = (HW_Cur_ReadIdx - UL1_Block->pucPhysBufAddr) -
|
|
UL1_Block->u4WriteIdx;
|
|
|
|
if (Hw_Get_bytes < 0)
|
|
Hw_Get_bytes += UL1_Block->u4BufferSize;
|
|
|
|
UL1_Block->u4WriteIdx += Hw_Get_bytes;
|
|
UL1_Block->u4WriteIdx %= UL1_Block->u4BufferSize;
|
|
|
|
/* if using mmap , do not calculate dataremind*/
|
|
switch (substream->runtime->access) {
|
|
case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
|
|
case SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED:
|
|
break;
|
|
case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
|
|
case SNDRV_PCM_ACCESS_RW_NONINTERLEAVED:
|
|
default:
|
|
UL1_Block->u4DataRemained += Hw_Get_bytes;
|
|
/* buffer overflow */
|
|
if (UL1_Block->u4DataRemained >
|
|
UL1_Block->u4BufferSize) {
|
|
bIsOverflow = true;
|
|
pr_info("%s buffer overflow u4DMAReadIdx:%x, u4WriteIdx:%x, DataRemained:%x, BufferSize:%x\n",
|
|
__func__, UL1_Block->u4DMAReadIdx,
|
|
UL1_Block->u4WriteIdx,
|
|
UL1_Block->u4DataRemained,
|
|
UL1_Block->u4BufferSize);
|
|
#if defined(CONFIG_MT_USERDEBUG_BUILD)
|
|
AUDIO_AEE("ulmem_frame_index - UL overflow");
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
/* pr_debug("[Auddrv] mtk_capture_pcm_pointer =0x%x
|
|
* HW_memory_index = 0x%x\n",
|
|
* HW_Cur_ReadIdx, HW_memory_index);
|
|
*/
|
|
|
|
spin_unlock_irqrestore(&afe_mem_control->substream_lock, flags);
|
|
mem_blk_spinunlock(mem_block);
|
|
|
|
if (bIsOverflow == true)
|
|
return -1;
|
|
|
|
return audio_bytes_to_frame(substream, HW_memory_index);
|
|
}
|
|
|
|
spin_unlock_irqrestore(&afe_mem_control->substream_lock, flags);
|
|
mem_blk_spinunlock(mem_block);
|
|
|
|
return 0;
|
|
}
|
|
|
|
snd_pcm_uframes_t get_mem_frame_index(struct snd_pcm_substream *substream,
|
|
struct afe_mem_control_t *afe_mem_control,
|
|
enum soc_aud_digital_block mem_block)
|
|
{
|
|
switch (mem_block) {
|
|
case Soc_Aud_Digital_Block_MEM_DL1:
|
|
case Soc_Aud_Digital_Block_MEM_DL2:
|
|
case Soc_Aud_Digital_Block_MEM_DL3:
|
|
return get_dlmem_frame_index(substream, afe_mem_control,
|
|
mem_block);
|
|
case Soc_Aud_Digital_Block_MEM_VUL:
|
|
case Soc_Aud_Digital_Block_MEM_VUL2:
|
|
case Soc_Aud_Digital_Block_MEM_DAI:
|
|
case Soc_Aud_Digital_Block_MEM_AWB:
|
|
case Soc_Aud_Digital_Block_MEM_MOD_DAI:
|
|
case Soc_Aud_Digital_Block_MEM_VUL_DATA2:
|
|
return get_ulmem_frame_index(substream, afe_mem_control,
|
|
mem_block);
|
|
default:
|
|
pr_warn("%s not support", __func__);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void mem_blk_spinlock(enum soc_aud_digital_block mem_blk)
|
|
{
|
|
switch (mem_blk) {
|
|
case Soc_Aud_Digital_Block_MEM_DL1:
|
|
spin_lock_irqsave(
|
|
&afe_mem_blk_dl1_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_DL1]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DL2:
|
|
spin_lock_irqsave(
|
|
&afe_mem_blk_dl2_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_DL2]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DL3:
|
|
spin_lock_irqsave(
|
|
&afe_mem_blk_dl3_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_DL3]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DL1_DATA2:
|
|
spin_lock_irqsave(
|
|
&afe_mem_blk_dl1_2_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_DL1_DATA2]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_VUL:
|
|
spin_lock_irqsave(
|
|
&afe_mem_blk_ul1_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_VUL]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DAI:
|
|
spin_lock_irqsave(
|
|
&afe_mem_blk_dai_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_DAI]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_AWB:
|
|
spin_lock_irqsave(
|
|
&afe_mem_blk_awb_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_AWB]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_MOD_DAI:
|
|
spin_lock_irqsave(
|
|
&afe_mem_blk_moddai_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_MOD_DAI]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_VUL_DATA2:
|
|
spin_lock_irqsave(
|
|
&afe_mem_blk_ul2_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_VUL_DATA2]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_VUL2:
|
|
spin_lock_irqsave(
|
|
&afe_mem_blk_ul3_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_VUL2]);
|
|
break;
|
|
default:
|
|
pr_warn("%s is not support", __func__);
|
|
}
|
|
}
|
|
|
|
void mem_blk_spinunlock(enum soc_aud_digital_block mem_blk)
|
|
{
|
|
switch (mem_blk) {
|
|
case Soc_Aud_Digital_Block_MEM_DL1:
|
|
spin_unlock_irqrestore(
|
|
&afe_mem_blk_dl1_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_DL1]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DL2:
|
|
spin_unlock_irqrestore(
|
|
&afe_mem_blk_dl2_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_DL2]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DL3:
|
|
spin_unlock_irqrestore(
|
|
&afe_mem_blk_dl3_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_DL3]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DL1_DATA2:
|
|
spin_unlock_irqrestore(
|
|
&afe_mem_blk_dl1_2_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_DL1_DATA2]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_VUL:
|
|
spin_unlock_irqrestore(
|
|
&afe_mem_blk_ul1_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_VUL]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DAI:
|
|
spin_unlock_irqrestore(
|
|
&afe_mem_blk_dai_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_DAI]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_AWB:
|
|
spin_unlock_irqrestore(
|
|
&afe_mem_blk_awb_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_AWB]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_MOD_DAI:
|
|
spin_unlock_irqrestore(
|
|
&afe_mem_blk_moddai_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_MOD_DAI]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_VUL_DATA2:
|
|
spin_unlock_irqrestore(
|
|
&afe_mem_blk_ul2_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_VUL_DATA2]);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_VUL2:
|
|
spin_unlock_irqrestore(
|
|
&afe_mem_blk_ul3_lock,
|
|
spinlock_flags[Soc_Aud_Digital_Block_MEM_VUL2]);
|
|
break;
|
|
default:
|
|
pr_warn("%s is not support", __func__);
|
|
}
|
|
}
|
|
|
|
static int mtk_mem_dlblk_copy(struct snd_pcm_substream *substream, int channel,
|
|
unsigned long pos, void __user *dst,
|
|
unsigned long count,
|
|
struct afe_mem_control_t *pMemControl,
|
|
enum soc_aud_digital_block mem_blk)
|
|
{
|
|
struct afe_block_t *Afe_Block = NULL;
|
|
int copy_size = 0, Afe_WriteIdx_tmp;
|
|
char *data_w_ptr = (char *)dst;
|
|
|
|
/* check which memif nned to be write */
|
|
Afe_Block = &pMemControl->rBlock;
|
|
|
|
/* handle for buffer management */
|
|
|
|
/* pr_debug(" WriteIdx=0x%x, ReadIdx=0x%x, DataRemained=0x%x\n",
|
|
* Afe_Block->u4WriteIdx, Afe_Block->u4DMAReadIdx,
|
|
* Afe_Block->u4DataRemained);
|
|
*/
|
|
if (Afe_Block->u4BufferSize == 0) {
|
|
pr_err(" u4BufferSize=0 Error");
|
|
return 0;
|
|
}
|
|
|
|
if (mem_blk == Soc_Aud_Digital_Block_MEM_DL1)
|
|
AudDrv_checkDLISRStatus();
|
|
|
|
mem_blk_spinlock(mem_blk);
|
|
/* free space of the buffer */
|
|
copy_size = Afe_Block->u4BufferSize - Afe_Block->u4DataRemained;
|
|
mem_blk_spinunlock(mem_blk);
|
|
if (count <= copy_size) {
|
|
if (copy_size < 0)
|
|
copy_size = 0;
|
|
else
|
|
copy_size = count;
|
|
}
|
|
|
|
copy_size = word_size_align(copy_size);
|
|
|
|
if (copy_size != 0) {
|
|
mem_blk_spinlock(mem_blk);
|
|
Afe_WriteIdx_tmp = Afe_Block->u4WriteIdx;
|
|
mem_blk_spinunlock(mem_blk);
|
|
|
|
if (Afe_WriteIdx_tmp + copy_size <
|
|
Afe_Block->u4BufferSize) { /* copy once */
|
|
if (!access_ok(VERIFY_READ, data_w_ptr, copy_size)) {
|
|
pr_warn("0 w_ptr=%p, size=%d Size=%d,left=%d",
|
|
data_w_ptr, copy_size,
|
|
Afe_Block->u4BufferSize,
|
|
Afe_Block->u4DataRemained);
|
|
} else {
|
|
#ifdef AFE_CONTROL_DEBUG_LOG
|
|
pr_debug(
|
|
"memcpy Idx= %p data_w_ptr = %p copy_size = 0x%x\n",
|
|
Afe_Block->pucVirtBufAddr +
|
|
Afe_WriteIdx_tmp,
|
|
data_w_ptr, copy_size);
|
|
#endif
|
|
if (copy_from_user((Afe_Block->pucVirtBufAddr +
|
|
Afe_WriteIdx_tmp),
|
|
data_w_ptr, copy_size)) {
|
|
pr_warn("[AudioWarn] Fail copy from user\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
mem_blk_spinlock(mem_blk);
|
|
Afe_Block->u4DataRemained += copy_size;
|
|
Afe_Block->u4WriteIdx = Afe_WriteIdx_tmp + copy_size;
|
|
Afe_Block->u4WriteIdx %= Afe_Block->u4BufferSize;
|
|
mem_blk_spinunlock(mem_blk);
|
|
data_w_ptr += copy_size;
|
|
count -= copy_size;
|
|
#ifdef AFE_CONTROL_DEBUG_LOG
|
|
pr_debug("finish1, copy_size:%x, WriteIdx:%x, ReadIdx=%x, Remained:%x, count=%x \r\n",
|
|
copy_size, Afe_Block->u4WriteIdx,
|
|
Afe_Block->u4DMAReadIdx,
|
|
Afe_Block->u4DataRemained,
|
|
(unsigned int)count);
|
|
#endif
|
|
} else { /* copy twice */
|
|
kal_uint32 size_1 = 0, size_2 = 0;
|
|
|
|
size_1 = word_size_align(
|
|
(Afe_Block->u4BufferSize - Afe_WriteIdx_tmp));
|
|
size_2 = word_size_align((copy_size - size_1));
|
|
#ifdef AFE_CONTROL_DEBUG_LOG
|
|
pr_debug("size_1=0x%x, size_2=0x%x\n", size_1,
|
|
size_2);
|
|
#endif
|
|
if (!access_ok(VERIFY_READ, data_w_ptr, size_1)) {
|
|
pr_warn("1 w_ptr=%p, size_1=%d bSize=%d,left=%d",
|
|
data_w_ptr, size_1,
|
|
Afe_Block->u4BufferSize,
|
|
Afe_Block->u4DataRemained);
|
|
} else {
|
|
#ifdef AFE_CONTROL_DEBUG_LOG
|
|
pr_debug(
|
|
"mcmcpy Idx= %p data_w_ptr = %p size_1 = %x\n",
|
|
Afe_Block->pucVirtBufAddr +
|
|
Afe_WriteIdx_tmp,
|
|
data_w_ptr, size_1);
|
|
#endif
|
|
if ((copy_from_user((Afe_Block->pucVirtBufAddr +
|
|
Afe_WriteIdx_tmp),
|
|
data_w_ptr, size_1))) {
|
|
pr_warn(" Fail 1 copy from user");
|
|
return -1;
|
|
}
|
|
}
|
|
mem_blk_spinlock(mem_blk);
|
|
Afe_Block->u4DataRemained += size_1;
|
|
Afe_Block->u4WriteIdx = Afe_WriteIdx_tmp + size_1;
|
|
Afe_Block->u4WriteIdx %= Afe_Block->u4BufferSize;
|
|
Afe_WriteIdx_tmp = Afe_Block->u4WriteIdx;
|
|
mem_blk_spinunlock(mem_blk);
|
|
|
|
if (!access_ok(VERIFY_READ, data_w_ptr + size_1,
|
|
size_2)) {
|
|
pr_warn("2ptr invalid data_w_ptr=%p, size_1=%d, size_2=%d u4BufferSize=%d, u4DataRemained=%d",
|
|
data_w_ptr, size_1, size_2,
|
|
Afe_Block->u4BufferSize,
|
|
Afe_Block->u4DataRemained
|
|
);
|
|
} else {
|
|
#ifdef AFE_CONTROL_DEBUG_LOG
|
|
pr_debug(
|
|
"mcmcpy Idx= %p data_w_ptr+size_1 = %p size_2 = %x\n",
|
|
Afe_Block->pucVirtBufAddr +
|
|
Afe_WriteIdx_tmp,
|
|
data_w_ptr + size_1, size_2);
|
|
#endif
|
|
if ((copy_from_user((Afe_Block->pucVirtBufAddr +
|
|
Afe_WriteIdx_tmp),
|
|
(data_w_ptr + size_1),
|
|
size_2))) {
|
|
pr_warn("AudDrv_write Fail 2 copy from user");
|
|
return -1;
|
|
}
|
|
}
|
|
mem_blk_spinlock(mem_blk);
|
|
Afe_Block->u4DataRemained += size_2;
|
|
Afe_Block->u4WriteIdx = Afe_WriteIdx_tmp + size_2;
|
|
Afe_Block->u4WriteIdx %= Afe_Block->u4BufferSize;
|
|
mem_blk_spinunlock(mem_blk);
|
|
|
|
count -= copy_size;
|
|
data_w_ptr += copy_size;
|
|
#ifdef AFE_CONTROL_DEBUG_LOG
|
|
pr_debug("finish2, copy size:%x, WriteIdx:%x,ReadIdx=%x DataRemained:%x \r\n",
|
|
copy_size, Afe_Block->u4WriteIdx,
|
|
Afe_Block->u4DMAReadIdx,
|
|
Afe_Block->u4DataRemained);
|
|
#endif
|
|
}
|
|
}
|
|
#ifdef AFE_CONTROL_DEBUG_LOG
|
|
pr_debug("pcm_copy return\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static bool CheckNullPointer(void *pointer)
|
|
{
|
|
if (pointer == NULL) {
|
|
pr_info("%s(), pointer = NULL", __func__);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static int mtk_mem_ulblk_copy(struct snd_pcm_substream *substream, int channel,
|
|
unsigned long pos, void __user *dst,
|
|
unsigned long count,
|
|
struct afe_mem_control_t *pMemControl,
|
|
enum soc_aud_digital_block mem_blk)
|
|
{
|
|
struct afe_mem_control_t *pVUL_MEM_ConTrol = NULL;
|
|
struct afe_block_t *Vul_Block = NULL;
|
|
char *Read_Data_Ptr = (char *)dst;
|
|
ssize_t DMA_Read_Ptr = 0, read_size = 0, read_count = 0;
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
#ifdef AFE_CONTROL_DEBUG_LOG
|
|
pr_debug("%s(), pos = %lucount = %lu\n ", __func__, pos,
|
|
count);
|
|
#endif
|
|
/* check which memif nned to be write */
|
|
pVUL_MEM_ConTrol = pMemControl;
|
|
Vul_Block = &(pVUL_MEM_ConTrol->rBlock);
|
|
|
|
if (pVUL_MEM_ConTrol == NULL) {
|
|
pr_warn("cannot find MEM control !!!!!!!\n");
|
|
msleep(50);
|
|
return 0;
|
|
}
|
|
|
|
if (Vul_Block->u4BufferSize <= 0) {
|
|
msleep(50);
|
|
pr_err("Vul_Block->u4BufferSize <= 0 =%d\n",
|
|
Vul_Block->u4BufferSize);
|
|
return 0;
|
|
}
|
|
|
|
if (CheckNullPointer((void *)Vul_Block->pucVirtBufAddr)) {
|
|
pr_err("CheckNullPointer pucVirtBufAddr = %p\n",
|
|
Vul_Block->pucVirtBufAddr);
|
|
return 0;
|
|
}
|
|
|
|
mem_blk_spinlock(mem_blk);
|
|
if (Vul_Block->u4DataRemained > Vul_Block->u4BufferSize) {
|
|
/* pr_debug("%s u4DataRemained=%x > u4BufferSize=%x",
|
|
* __func__, Vul_Block->u4DataRemained,
|
|
* Vul_Block->u4BufferSize);
|
|
*/
|
|
Vul_Block->u4DataRemained = 0;
|
|
Vul_Block->u4DMAReadIdx = Vul_Block->u4WriteIdx;
|
|
}
|
|
|
|
if (count > Vul_Block->u4DataRemained)
|
|
read_size = Vul_Block->u4DataRemained;
|
|
else
|
|
read_size = count;
|
|
|
|
DMA_Read_Ptr = Vul_Block->u4DMAReadIdx;
|
|
mem_blk_spinunlock(mem_blk);
|
|
#ifdef AFE_CONTROL_DEBUG_LOG
|
|
pr_debug(
|
|
"%s finish0, read_count:%x, read_size:%x, Remained:%x, ReadIdx:0x%x, WriteIdx:%x \r\n",
|
|
__func__, (unsigned int)read_count, (unsigned int)read_size,
|
|
Vul_Block->u4DataRemained, Vul_Block->u4DMAReadIdx,
|
|
Vul_Block->u4WriteIdx);
|
|
#endif
|
|
if (DMA_Read_Ptr + read_size < Vul_Block->u4BufferSize) {
|
|
if (DMA_Read_Ptr != Vul_Block->u4DMAReadIdx) {
|
|
pr_warn("%s 1, read_size:%zu, Remained:%x, Ptr:%zu, DMAReadIdx:%x \r\n",
|
|
__func__, read_size, Vul_Block->u4DataRemained,
|
|
DMA_Read_Ptr, Vul_Block->u4DMAReadIdx);
|
|
}
|
|
|
|
if (copy_to_user((void __user *)Read_Data_Ptr,
|
|
(Vul_Block->pucVirtBufAddr + DMA_Read_Ptr),
|
|
read_size)) {
|
|
|
|
pr_err("%s Fail 1 copy to user Ptr:%p, Addr:%p, ReadIdx:0x%x, Read_Ptr:%zu,size:%zu",
|
|
__func__, Read_Data_Ptr,
|
|
Vul_Block->pucVirtBufAddr,
|
|
Vul_Block->u4DMAReadIdx, DMA_Read_Ptr,
|
|
read_size);
|
|
return 0;
|
|
}
|
|
|
|
read_count += read_size;
|
|
mem_blk_spinlock(mem_blk);
|
|
Vul_Block->u4DataRemained -= read_size;
|
|
Vul_Block->u4DMAReadIdx += read_size;
|
|
Vul_Block->u4DMAReadIdx %= Vul_Block->u4BufferSize;
|
|
DMA_Read_Ptr = Vul_Block->u4DMAReadIdx;
|
|
mem_blk_spinunlock(mem_blk);
|
|
|
|
Read_Data_Ptr += read_size;
|
|
count -= read_size;
|
|
#ifdef AFE_CONTROL_DEBUG_LOG
|
|
pr_debug(
|
|
"%s finish1, copy size:%x, ReadIdx:0x%x, WriteIdx:%x, Remained:%x \r\n",
|
|
__func__, (unsigned int)read_size,
|
|
Vul_Block->u4DMAReadIdx, Vul_Block->u4WriteIdx,
|
|
Vul_Block->u4DataRemained);
|
|
#endif
|
|
}
|
|
|
|
else {
|
|
unsigned int size_1 = Vul_Block->u4BufferSize - DMA_Read_Ptr;
|
|
unsigned int size_2 = read_size - size_1;
|
|
|
|
if (DMA_Read_Ptr != Vul_Block->u4DMAReadIdx) {
|
|
|
|
pr_warn("%s 2, read_size1:%x, Remained:%x, Read_Ptr:%zu, ReadIdx:%x \r\n",
|
|
__func__, size_1, Vul_Block->u4DataRemained,
|
|
DMA_Read_Ptr, Vul_Block->u4DMAReadIdx);
|
|
}
|
|
if (copy_to_user((void __user *)Read_Data_Ptr,
|
|
(Vul_Block->pucVirtBufAddr + DMA_Read_Ptr),
|
|
(unsigned int)size_1)) {
|
|
|
|
pr_err("%s Fail 2 copy to user Ptr:%p, Addr:%p, ReadIdx:0x%x, Read_Ptr:%zu,read_size:%zu",
|
|
__func__, Read_Data_Ptr,
|
|
Vul_Block->pucVirtBufAddr,
|
|
Vul_Block->u4DMAReadIdx, DMA_Read_Ptr,
|
|
read_size);
|
|
return 0;
|
|
}
|
|
|
|
read_count += size_1;
|
|
mem_blk_spinlock(mem_blk);
|
|
Vul_Block->u4DataRemained -= size_1;
|
|
Vul_Block->u4DMAReadIdx += size_1;
|
|
Vul_Block->u4DMAReadIdx %= Vul_Block->u4BufferSize;
|
|
DMA_Read_Ptr = Vul_Block->u4DMAReadIdx;
|
|
mem_blk_spinunlock(mem_blk);
|
|
#ifdef AFE_CONTROL_DEBUG_LOG
|
|
pr_debug(
|
|
"%s finish2, copy size_1:%x, ReadIdx:0x%x, WriteIdx:0x%x, Remained:%x \r\n",
|
|
__func__, size_1, Vul_Block->u4DMAReadIdx,
|
|
Vul_Block->u4WriteIdx, Vul_Block->u4DataRemained);
|
|
#endif
|
|
if (DMA_Read_Ptr != Vul_Block->u4DMAReadIdx) {
|
|
|
|
pr_warn("%s 3, read_size2:%x, Remained:%x, DMA_Read_Ptr:%zu, DMAReadIdx:%x \r\n",
|
|
__func__, size_2, Vul_Block->u4DataRemained,
|
|
DMA_Read_Ptr, Vul_Block->u4DMAReadIdx);
|
|
}
|
|
if (copy_to_user((void __user *)(Read_Data_Ptr + size_1),
|
|
(Vul_Block->pucVirtBufAddr + DMA_Read_Ptr),
|
|
size_2)) {
|
|
|
|
pr_err("%s Fail 3 copy to user Ptr:%p, Addr:%p, ReadIdx:0x%x , Read_Ptr:%zu, read_size:%zu",
|
|
__func__, Read_Data_Ptr,
|
|
Vul_Block->pucVirtBufAddr,
|
|
Vul_Block->u4DMAReadIdx, DMA_Read_Ptr,
|
|
read_size);
|
|
return bytes_to_frames(runtime, read_count);
|
|
}
|
|
|
|
read_count += size_2;
|
|
mem_blk_spinlock(mem_blk);
|
|
Vul_Block->u4DataRemained -= size_2;
|
|
Vul_Block->u4DMAReadIdx += size_2;
|
|
DMA_Read_Ptr = Vul_Block->u4DMAReadIdx;
|
|
mem_blk_spinunlock(mem_blk);
|
|
count -= read_size;
|
|
Read_Data_Ptr += read_size;
|
|
#ifdef AFE_CONTROL_DEBUG_LOG
|
|
pr_debug(
|
|
"%s finish3, copy size_2:%x, u4DMAReadIdx:0x%x, u4WriteIdx:0x%x u4DataRemained:%x \r\n",
|
|
__func__, size_2, Vul_Block->u4DMAReadIdx,
|
|
Vul_Block->u4WriteIdx, Vul_Block->u4DataRemained);
|
|
#endif
|
|
}
|
|
|
|
return bytes_to_frames(runtime, read_count);
|
|
}
|
|
|
|
int mtk_memblk_copy(struct snd_pcm_substream *substream, int channel,
|
|
unsigned long pos, void __user *dst,
|
|
unsigned long count,
|
|
struct afe_mem_control_t *pMemControl,
|
|
enum soc_aud_digital_block mem_blk)
|
|
{
|
|
if (pMemControl == NULL)
|
|
return 0;
|
|
|
|
switch (mem_blk) {
|
|
case Soc_Aud_Digital_Block_MEM_DL1:
|
|
case Soc_Aud_Digital_Block_MEM_DL2:
|
|
case Soc_Aud_Digital_Block_MEM_DL3:
|
|
mtk_mem_dlblk_copy(substream, channel, pos, dst, count,
|
|
pMemControl, mem_blk);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_VUL:
|
|
case Soc_Aud_Digital_Block_MEM_DAI:
|
|
case Soc_Aud_Digital_Block_MEM_AWB:
|
|
case Soc_Aud_Digital_Block_MEM_MOD_DAI:
|
|
case Soc_Aud_Digital_Block_MEM_VUL_DATA2:
|
|
case Soc_Aud_Digital_Block_MEM_VUL2:
|
|
mtk_mem_ulblk_copy(substream, channel, pos, dst, count,
|
|
pMemControl, mem_blk);
|
|
break;
|
|
default:
|
|
pr_info("%s not support", __func__);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int set_memif_addr(int mem_blk, dma_addr_t addr, size_t size)
|
|
{
|
|
int ret;
|
|
|
|
/* by platform to implement*/
|
|
if (s_mem_blk_ops != NULL &&
|
|
s_mem_blk_ops->set_chip_memif_addr != NULL) {
|
|
ret = s_mem_blk_ops->set_chip_memif_addr(mem_blk, addr, size);
|
|
return ret;
|
|
}
|
|
|
|
/* set address hardware , default implemant*/
|
|
switch (mem_blk) {
|
|
case Soc_Aud_Digital_Block_MEM_DL1:
|
|
Afe_Set_Reg(AFE_DL1_BASE, addr, 0xffffffff);
|
|
Afe_Set_Reg(AFE_DL1_END, addr + (size - 1), 0xffffffff);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DL2:
|
|
Afe_Set_Reg(AFE_DL2_BASE, addr, 0xffffffff);
|
|
Afe_Set_Reg(AFE_DL2_END, addr + (size - 1), 0xffffffff);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_VUL:
|
|
Afe_Set_Reg(AFE_VUL_BASE, addr, 0xffffffff);
|
|
Afe_Set_Reg(AFE_VUL_END, addr + (size - 1), 0xffffffff);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DAI:
|
|
Afe_Set_Reg(AFE_DAI_BASE, addr, 0xffffffff);
|
|
Afe_Set_Reg(AFE_DAI_END, addr + (size - 1), 0xffffffff);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_MOD_DAI:
|
|
Afe_Set_Reg(AFE_MOD_DAI_BASE, addr, 0xffffffff);
|
|
Afe_Set_Reg(AFE_MOD_DAI_END, addr + (size - 1), 0xffffffff);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_VUL_DATA2:
|
|
Afe_Set_Reg(AFE_VUL_D2_BASE, addr, 0xffffffff);
|
|
Afe_Set_Reg(AFE_VUL_D2_END, addr + (size - 1), 0xffffffff);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_AWB:
|
|
Afe_Set_Reg(AFE_AWB_BASE, addr, 0xffffffff);
|
|
Afe_Set_Reg(AFE_AWB_END, addr + (size - 1), 0xffffffff);
|
|
break;
|
|
case Soc_Aud_Digital_Block_MEM_DL1_DATA2:
|
|
case Soc_Aud_Digital_Block_MEM_DL3:
|
|
case Soc_Aud_Digital_Block_MEM_HDMI:
|
|
default:
|
|
pr_warn("%s not suuport mem_blk = %d", __func__, mem_blk);
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int set_mem_block(struct snd_pcm_substream *substream,
|
|
struct snd_pcm_hw_params *hw_params,
|
|
struct afe_mem_control_t *pMemControl,
|
|
enum soc_aud_digital_block mem_blk)
|
|
{
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
struct afe_block_t *pblock = &pMemControl->rBlock;
|
|
|
|
pblock->pucPhysBufAddr = runtime->dma_addr;
|
|
pblock->pucVirtBufAddr = runtime->dma_area;
|
|
pblock->u4BufferSize = runtime->dma_bytes;
|
|
pblock->u4SampleNumMask = 0x001f; /* 32 byte align */
|
|
pblock->u4WriteIdx = 0;
|
|
pblock->u4DMAReadIdx = 0;
|
|
pblock->u4DataRemained = 0;
|
|
pblock->u4fsyncflag = false;
|
|
pblock->uResetFlag = true;
|
|
/*
|
|
*pr_debug("%s u4BufferSize = %d pucVirtBufAddr = %p pucPhysBufAddr =
|
|
*0x%x\n",
|
|
* __func__, pblock->u4BufferSize, pblock->pucVirtBufAddr,
|
|
*pblock->pucPhysBufAddr);
|
|
*/
|
|
|
|
set_memif_addr(mem_blk, pblock->pucPhysBufAddr, pblock->u4BufferSize);
|
|
|
|
memset_io((void *)pblock->pucVirtBufAddr, 0, pblock->u4BufferSize);
|
|
return 0;
|
|
}
|
|
|
|
bool handle_suspend(bool suspend)
|
|
{
|
|
bool ret = false;
|
|
|
|
if (s_afe_platform_ops->handle_suspend != NULL) {
|
|
s_afe_platform_ops->handle_suspend(suspend);
|
|
ret = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void set_mem_blk_ops(struct mtk_mem_blk_ops *ops)
|
|
{
|
|
s_mem_blk_ops = ops;
|
|
}
|
|
|
|
void set_afe_platform_ops(struct mtk_afe_platform_ops *ops)
|
|
{
|
|
s_afe_platform_ops = ops;
|
|
}
|
|
|
|
struct mtk_afe_platform_ops *get_afe_platform_ops(void)
|
|
{
|
|
return s_afe_platform_ops;
|
|
}
|
|
|
|
/* low latency debug */
|
|
int get_LowLatencyDebug(void)
|
|
{
|
|
return LowLatencyDebug;
|
|
}
|
|
|
|
void set_LowLatencyDebug(unsigned int bFlag)
|
|
{
|
|
LowLatencyDebug = bFlag;
|
|
pr_debug("%s LowLatencyDebug = %d\n", __func__, LowLatencyDebug);
|
|
}
|
|
|
|
int mtk_pcm_mmap(struct snd_pcm_substream *substream,
|
|
struct vm_area_struct *vma)
|
|
{
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
|
|
pr_debug("+%s dma_mmap_coherent\n", __func__);
|
|
/* set mmap meory with no cache*/
|
|
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
|
return dma_mmap_coherent(substream->pcm->card->dev, vma,
|
|
runtime->dma_area, runtime->dma_addr,
|
|
runtime->dma_bytes);
|
|
}
|
|
|
|
/* calculate the target DMA-buffer position to be written/read */
|
|
static void *get_dma_ptr(struct snd_pcm_runtime *runtime,
|
|
int channel, unsigned long hwoff)
|
|
{
|
|
return runtime->dma_area + hwoff +
|
|
channel * (runtime->dma_bytes / runtime->channels);
|
|
}
|
|
|
|
/* default copy_user ops for write; used for both interleaved and non- modes */
|
|
static int default_write_copy(struct snd_pcm_substream *substream,
|
|
int channel, unsigned long hwoff,
|
|
void *buf, unsigned long bytes)
|
|
{
|
|
if (copy_from_user(get_dma_ptr(substream->runtime, channel, hwoff),
|
|
(void __user *)buf, bytes))
|
|
return -EFAULT;
|
|
return 0;
|
|
}
|
|
|
|
/* default copy_user ops for read; used for both interleaved and non- modes */
|
|
static int default_read_copy(struct snd_pcm_substream *substream,
|
|
int channel, unsigned long hwoff,
|
|
void *buf, unsigned long bytes)
|
|
{
|
|
if (copy_to_user((void __user *)buf,
|
|
get_dma_ptr(substream->runtime, channel, hwoff),
|
|
bytes))
|
|
return -EFAULT;
|
|
return 0;
|
|
}
|
|
|
|
int mtk_afe_pcm_copy(struct snd_pcm_substream *substream,
|
|
int channel, unsigned long hwoff,
|
|
void *buf, unsigned long bytes)
|
|
{
|
|
int (*sp_copy)(struct snd_pcm_substream *substream,
|
|
int channel, unsigned long hwoff,
|
|
void *buf, unsigned long bytes) = NULL;
|
|
int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
|
|
|
sp_copy = is_playback ? default_write_copy : default_read_copy;
|
|
sp_copy(substream, channel, hwoff,
|
|
(void __user *)buf, bytes);
|
|
|
|
return 0;
|
|
}
|
|
|