/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2019. All rights reserved. * Description: drv adsp * Author: Audio * Create: 2012-05-30 */ #include "adsp_debug_ext.h" #include "osal_ext.h" #include "drv_adsp_private.h" #include "drv_adsp_ext.h" #include "dsp_resampler_ext.h" #include "drv_adsp_hal.h" #include "drv_adsp_cmd.h" #include "drv_adsp_trace.h" #include "audio_mem.h" #if defined(ENABLE_FAULT_CHECK) #include "drv_sys_ext.h" #include "drv_sys_struct.h" #include "drv_adsp_trace_proc.h" #include "drv_adsp_fault_check.h" #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ static osal_semaphore g_adsp_mutex = {TD_NULL}; #if defined(ENABLE_FAULT_CHECK) typedef enum { ADSP_FC_ENABLE_STATE_UNKNOWN = -1, ADSP_FC_ENABLE_STATE_DISABLE = 0, ADSP_FC_ENABLE_STATE_ENABLE = 1, } adsp_fault_check_enable_state; static volatile aoe_regs_type *g_aoe_reg = TD_NULL; static volatile adsp_fault_check_enable_state g_fault_check_state = ADSP_FC_ENABLE_STATE_UNKNOWN; static ext_chip_revision get_chip_revision(td_void) { td_s32 ret; ext_chip_revision chip_revision = CHIP_REVISION_MAX; ret = ext_drv_sys_get_chip_revision(&chip_revision); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_drv_sys_get_chip_revision, ret); return CHIP_REVISION_MAX; } return chip_revision; } /* must be called after adsp_hal_load_fw */ static td_bool is_enable_fault_check(td_void) { if (g_fault_check_state == ADSP_FC_ENABLE_STATE_UNKNOWN) { int ret; aoe_fw_info fw_info; ext_chip_revision revision = get_chip_revision(); if (revision != CHIP_REVISION_B && revision != CHIP_REVISION_C) { g_fault_check_state = ADSP_FC_ENABLE_STATE_DISABLE; return TD_FALSE; } memset_s(&fw_info, sizeof(fw_info), 0, sizeof(aoe_fw_info)); ret = adsp_hal_get_aoe_fw_info(&fw_info); if (ret != TD_SUCCESS || fw_info.aoe_sw_flag == TD_TRUE) { g_fault_check_state = ADSP_FC_ENABLE_STATE_DISABLE; soc_log_info("disable faultcheck becasue of get_aoe_fw_info ret %d, aoe_sw_flag=%d\n", ret, fw_info.aoe_sw_flag); return TD_FALSE; } g_fault_check_state = ADSP_FC_ENABLE_STATE_ENABLE; return TD_TRUE; } return (g_fault_check_state == ADSP_FC_ENABLE_STATE_ENABLE ? TD_TRUE : TD_FALSE); } #endif static td_void drv_adsp_unload_aoe(td_void) { #if defined(ENABLE_FAULT_CHECK) if (is_enable_fault_check() == TD_TRUE) { adfc_deinit(); g_aoe_reg = TD_NULL; } #endif adsp_hal_unload_aoe(); #if defined(ENABLE_FAULT_CHECK) if (is_enable_fault_check() == TD_TRUE) { trace_proc_deinit(); trace_adsp_deinit(); } #endif adsp_hal_unload_fw(); } #if defined(ENABLE_FAULT_CHECK) static td_s32 get_dsp_status(adfc_dsp_status *status) { volatile adsp_chn_regs_type *adsp_sys = TD_NULL; if (status == TD_NULL) { return TD_FAILURE; } if (g_aoe_reg == TD_NULL) { aoe_fw_info fw_info; td_s32 ret; ret = adsp_hal_get_aoe_fw_info(&fw_info); if (ret != TD_SUCCESS) { return ret; } g_aoe_reg = (aoe_regs_type *)fw_info.aoe_reg.virt_addr; if (g_aoe_reg == TD_NULL) { soc_log_err("aoe_reg is NULL\n"); return TD_FAILURE; } } adsp_sys = (volatile adsp_chn_regs_type *)((td_u8 *)g_aoe_reg + DSP0_SHARESRAM_SYS_OFFSET); status->counter_value = adsp_sys->adsp_run_cnt; status->run_position = g_aoe_reg->aoe_status0; return TD_SUCCESS; } #endif static td_s32 drv_adsp_load_aoe(td_void) { td_s32 ret; ret = adsp_hal_load_fw(); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(adsp_hal_load_fw, ret); return ret; } #if defined(ENABLE_FAULT_CHECK) if (is_enable_fault_check() == TD_TRUE) { trace_adsp_init(); trace_proc_init(); } #endif ret = adsp_hal_load_aoe(); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(adsp_hal_load_aoe, ret); #if defined(ENABLE_FAULT_CHECK) if (is_enable_fault_check() == TD_TRUE) { trace_proc_deinit(); trace_adsp_deinit(); } #endif adsp_hal_unload_fw(); return ret; } #if defined(ENABLE_FAULT_CHECK) if (is_enable_fault_check() == TD_TRUE) { adfc_param local_dfc_param; memset_s(&local_dfc_param, sizeof(local_dfc_param), 0, sizeof(local_dfc_param)); local_dfc_param.get_dsp_status = get_dsp_status; ret = adfc_init(&local_dfc_param); if (ret != TD_SUCCESS) { soc_log_err("adfc_init return error %d\n", ret); } } #endif return TD_SUCCESS; } static td_void drv_adsp_unload_aflt(td_void) { adsp_hal_unload_aflt(); adsp_hal_unload_fw(); } static td_s32 drv_adsp_load_aflt(td_void) { td_s32 ret; ret = adsp_hal_load_fw(); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(adsp_hal_load_fw, ret); return ret; } ret = adsp_hal_load_aflt(); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(adsp_hal_load_aflt, ret); adsp_hal_unload_fw(); return ret; } return TD_SUCCESS; } static td_s32 drv_adsp_load_firmware(adsp_code_id dsp_code_id) { td_s32 ret; ret = osal_sem_down_interruptible(&g_adsp_mutex); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(osal_sem_down_interruptible, ret); return ret; } switch (dsp_code_id) { case ADSP_CODE_AOE: ret = drv_adsp_load_aoe(); break; case ADSP_CODE_AFLT: ret = drv_adsp_load_aflt(); break; default: soc_log_warn("unsupport dsp code id\n"); soc_warn_print_h32(dsp_code_id); ret = SOC_ERR_ADSP_INVALID_PARA; break; } osal_sem_up(&g_adsp_mutex); return ret; } static td_s32 drv_adsp_unload_firmware(adsp_code_id dsp_code_id) { td_s32 ret; ret = osal_sem_down_interruptible(&g_adsp_mutex); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(osal_sem_down_interruptible, ret); return ret; } switch (dsp_code_id) { case ADSP_CODE_AOE: drv_adsp_unload_aoe(); break; case ADSP_CODE_AFLT: drv_adsp_unload_aflt(); break; default: soc_log_warn("unsupport dsp code id\n"); soc_warn_print_h32(dsp_code_id); osal_sem_up(&g_adsp_mutex); return SOC_ERR_ADSP_INVALID_PARA; } osal_sem_up(&g_adsp_mutex); return TD_SUCCESS; } static td_s32 drv_adsp_get_aoe_fw_info(adsp_code_id dsp_code_id, aoe_fw_info *info) { td_s32 ret; if (dsp_code_id != ADSP_CODE_AOE) { return SOC_ERR_ADSP_INVALID_PARA; } ret = osal_sem_down_interruptible(&g_adsp_mutex); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(osal_sem_down_interruptible, ret); return ret; } ret = adsp_hal_get_aoe_fw_info(info); osal_sem_up(&g_adsp_mutex); return ret; } static const adsp_export_func g_adsp_func = { .adsp_load_firmware = drv_adsp_load_firmware, .adsp_unload_firmware = drv_adsp_unload_firmware, .adsp_get_aoe_fw_info = drv_adsp_get_aoe_fw_info, .adsp_write_cmd = drv_adsp_write_cmd, .mmz_alloc = ext_drv_audio_mmz_alloc, .mmz_release = ext_drv_audio_mmz_release, .sec_mmz_alloc = ext_drv_audio_sec_mmz_alloc, .sec_mmz_release = ext_drv_audio_sec_mmz_release, .smmu_alloc = ext_drv_audio_smmu_alloc, .smmu_release = ext_drv_audio_smmu_release, .sec_smmu_alloc = ext_drv_audio_sec_smmu_alloc, .sec_smmu_release = ext_drv_audio_sec_smmu_release, .adsp_src_create = drv_resampler_create, .adsp_src_process = drv_resampler_process_frame, .adsp_src_destroy = drv_resampler_destroy, }; static inline td_void adsp_osal_deinit(td_void) { osal_sem_destroy(&g_adsp_mutex); } static inline td_s32 adsp_osal_init(td_void) { return osal_sem_init(&g_adsp_mutex, 1); } td_s32 adsp_drv_init(td_void) { td_s32 ret; ret = osal_exportfunc_register(SOC_ID_ADSP, "SOC_ADSP", (td_void *)&g_adsp_func); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(osal_exportfunc_register, ret); return ret; } ret = adsp_osal_init(); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(adsp_osal_init, ret); goto out0; } ret = adsp_hal_init(); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(adsp_hal_init, ret); goto out1; } return TD_SUCCESS; out1: adsp_osal_deinit(); out0: if (osal_exportfunc_unregister(SOC_ID_ADSP) != TD_SUCCESS) { soc_log_err("call osal_exportfunc_unregister failed"); } return ret; } td_void adsp_drv_exit(td_void) { adsp_hal_deinit(); adsp_osal_deinit(); if (osal_exportfunc_unregister(SOC_ID_ADSP) != TD_SUCCESS) { soc_log_err("call osal_exportfunc_unregister failed"); } } td_s32 ext_drv_adsp_init(td_void) { return adsp_drv_init(); } td_void ext_drv_adsp_deinit(td_void) { adsp_drv_exit(); } #ifdef __cplusplus } #endif /* __cplusplus */