/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2019. All rights reserved. * Description: aflt device and driver * Author: audio * Create: 2019-05-30 */ #include "hal_aflt.h" #include "osal_ext.h" #include "drv_sys_ext.h" #include "audsp_aflt_ext.h" #include "drv_aflt_debug.h" #include "drv_ioctl_aflt.h" #include "soc_errno.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ static volatile ext_aflt_chan_reg *g_aflt_chn_reg[AFLT_MAX_CHAN_NUM] = { TD_NULL }; static td_bool g_sw_aflt_flag = TD_TRUE; /* TD_TRUE: sw; TD_FALSE: hw */ static td_void aflt_io_address_map(td_u8 *reg) { td_u32 id; if (reg == TD_NULL) { soc_log_fatal("reg is NULL\n"); return; } reg += DSP0_SHARESRAM_AFLT_OFFSET + AFLT_CHN_REG_OFFSET; for (id = 0; id < AFLT_MAX_CHAN_NUM; id++) { g_aflt_chn_reg[id] = (ext_aflt_chan_reg *)(reg + AFLT_CHN_REG_BANDSIZE * id); } } static td_void aflt_io_address_unmap(td_void) { td_u32 id; for (id = 0; id < AFLT_MAX_CHAN_NUM; id++) { g_aflt_chn_reg[id] = TD_NULL; } } static ext_aflt_chan_reg *aflt_hal_get_chan_reg(td_u32 aflt_id) { if (aflt_id >= AFLT_MAX_CHAN_NUM) { return TD_NULL; } return (ext_aflt_chan_reg *)g_aflt_chn_reg[aflt_id]; } static aflt_cmd_ret i_hal_aflt_ack_cmd(const ext_aflt_chan_reg *aflt_reg) { volatile td_u32 loop_outer; volatile td_u32 loop_inner; for (loop_outer = 0; loop_outer < 100; loop_outer++) { /* 100 is a number */ for (loop_inner = 0; loop_inner < 8; loop_inner++) { /* 8 is a number */ if (aflt_reg->ctrl.bits.cmd_done) { return (aflt_cmd_ret)aflt_reg->ctrl.bits.cmd_return_value; } osal_udelay(10); /* 10us */ } osal_msleep(1); } return AFLT_CMD_ERR_TIMEOUT; } static td_s32 i_hal_aflt_set_cmd(td_u32 aflt_id, aflt_cmd cmd) { aflt_cmd_ret ack; ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if (aflt_reg == TD_NULL) { return SOC_ERR_AFLT_INVALID_PARA; } switch (cmd) { case AFLT_CMD_CREATE: case AFLT_CMD_DESTROY: case AFLT_CMD_START: case AFLT_CMD_STOP: case AFLT_CMD_SETPARAM: case AFLT_CMD_GETPARAM: case AFLT_CMD_SETCONFIG: case AFLT_CMD_GETCONFIG: case AFLT_CMD_RESTORESETTING: case AFLT_CMD_STORESETTING: case AFLT_CMD_INITINBUF: case AFLT_CMD_DEINITINBUF: case AFLT_CMD_INITOUTBUF: case AFLT_CMD_DEINITOUTBUF: aflt_reg->ctrl.bits.cmd = (td_u32)cmd; break; default: soc_log_err("aflt CMD ERR!\n"); soc_err_print_u32(cmd); return TD_FAILURE; } aflt_reg->ctrl.bits.cmd_done = 0; ack = i_hal_aflt_ack_cmd(aflt_reg); if (ack != AFLT_CMD_DONE) { soc_log_err("aflt ack cmd failed"); soc_err_print_u32(aflt_id); soc_err_print_u32(cmd); soc_err_print_h32(ack); return TD_FAILURE; } return TD_SUCCESS; } td_void aflt_hal_init(td_u8 *reg_base, td_bool sw_aflt) { aflt_io_address_map(reg_base); g_sw_aflt_flag = sw_aflt; } td_void aflt_hal_deinit(td_void) { aflt_io_address_unmap(); } td_s32 aflt_hal_create(td_u32 aflt_id, const aflt_create_attr *attr) { td_s32 ret; ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if (aflt_reg == TD_NULL) { return SOC_ERR_AFLT_INVALID_PARA; } if (attr == TD_NULL) { return SOC_ERR_AFLT_NULL_PTR; } aflt_reg->attr.bits.master_flag = (attr->master == TD_TRUE) ? 1 : 0; aflt_reg->attr.bits.filter_id = (td_u32)attr->aflt_comp_id; aflt_reg->auth_key[0] = attr->auth_key[0]; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_CREATE); if (ret != TD_SUCCESS) { soc_log_err("set alft create cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } return TD_SUCCESS; } td_s32 aflt_hal_destroy(td_u32 aflt_id) { td_s32 ret; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_DESTROY); if (ret != TD_SUCCESS) { soc_log_err("set alft destroy cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } return TD_SUCCESS; } td_s32 aflt_hal_start(td_u32 aflt_id) { td_s32 ret; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_START); if (ret != TD_SUCCESS) { soc_log_err("set alft start cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } return TD_SUCCESS; } td_s32 aflt_hal_stop(td_u32 aflt_id) { td_s32 ret; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_STOP); if (ret != TD_SUCCESS) { soc_log_err("set alft stop cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } return TD_SUCCESS; } td_s32 aflt_hal_set_param(td_u32 aflt_id, const aflt_param *param) { td_s32 ret; u_aflt_ctrl ctrl; ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if (aflt_reg == TD_NULL) { return SOC_ERR_AFLT_INVALID_PARA; } if (param == TD_NULL) { return SOC_ERR_AFLT_NULL_PTR; } ctrl.u32 = aflt_reg->ctrl.u32; ctrl.bits.param_index = param->param_index; ctrl.bits.param_wordsize = param->param_struct_size; aflt_reg->ctrl.u32 = ctrl.u32; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_SETPARAM); if (ret != TD_SUCCESS) { soc_log_err("set alft param cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } return TD_SUCCESS; } td_s32 aflt_hal_get_param(td_u32 aflt_id, aflt_param *param) { td_s32 ret; u_aflt_ctrl ctrl; ext_aflt_chan_reg *reg = aflt_hal_get_chan_reg(aflt_id); if (reg == TD_NULL) { return SOC_ERR_AFLT_INVALID_PARA; } if (param == TD_NULL) { return SOC_ERR_AFLT_NULL_PTR; } ctrl.u32 = reg->ctrl.u32; ctrl.bits.param_index = param->param_index; reg->ctrl.u32 = ctrl.u32; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_GETPARAM); if (ret != TD_SUCCESS) { soc_log_err("get alft param cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } param->param_struct_size = reg->ctrl.bits.param_wordsize; return TD_SUCCESS; } td_s32 aflt_hal_set_config(td_u32 aflt_id, const aflt_config *cfg) { td_s32 ret; u_aflt_ctrl ctrl; ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if (aflt_reg == TD_NULL) { return SOC_ERR_AFLT_INVALID_PARA; } if (cfg == TD_NULL) { return SOC_ERR_AFLT_NULL_PTR; } ctrl.u32 = aflt_reg->ctrl.u32; ctrl.bits.param_index = cfg->config_index; ctrl.bits.param_wordsize = cfg->config_struct_size; aflt_reg->ctrl.u32 = ctrl.u32; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_SETCONFIG); if (ret != TD_SUCCESS) { soc_log_err("set alft config cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } return TD_SUCCESS; } td_s32 aflt_hal_get_config(td_u32 aflt_id, aflt_config *cfg) { td_s32 ret; u_aflt_ctrl ctrl; ext_aflt_chan_reg *reg = aflt_hal_get_chan_reg(aflt_id); if (reg == TD_NULL) { return SOC_ERR_AFLT_INVALID_PARA; } if (cfg == TD_NULL) { return SOC_ERR_AFLT_NULL_PTR; } ctrl.u32 = reg->ctrl.u32; ctrl.bits.param_index = cfg->config_index; reg->ctrl.u32 = ctrl.u32; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_GETCONFIG); if (ret != TD_SUCCESS) { soc_log_err("get alft cfg cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } cfg->config_struct_size = reg->ctrl.bits.param_wordsize; return TD_SUCCESS; } td_s32 aflt_hal_restore_setting(td_u32 aflt_id) { td_s32 ret; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_RESTORESETTING); if (ret != TD_SUCCESS) { soc_log_err("restore alft setting cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } return TD_SUCCESS; } td_s32 aflt_hal_store_setting(td_u32 aflt_id) { td_s32 ret; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_STORESETTING); if (ret != TD_SUCCESS) { soc_log_err("store alft setting cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } return TD_SUCCESS; } td_void aflt_hal_set_msg_pool_attr(td_u32 aflt_id, hal_aflt_msgpool_attr *msg_pool_attr) { u_aflt_attr attr; ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if ((aflt_reg == TD_NULL) || (msg_pool_attr == TD_NULL)) { return; } attr.u32 = aflt_reg->attr.u32; if (g_sw_aflt_flag == TD_TRUE) { adsp_write_addr(msg_pool_attr->virt_addr, aflt_reg->msg_pool_addr); } else { adsp_write_addr(msg_pool_attr->phys_addr, aflt_reg->msg_pool_addr); } attr.bits.msgpool_size = msg_pool_attr->size; aflt_reg->attr.u32 = attr.u32; } td_s32 aflt_hal_init_inbuf(td_u32 aflt_id, hal_aflt_inbuf_attr *in_buf_attr) { td_s32 ret; u_ip_buf_size ip_buf_size; ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if (aflt_reg == TD_NULL) { return SOC_ERR_AFLT_INVALID_PARA; } if (in_buf_attr == TD_NULL) { return SOC_ERR_AFLT_NULL_PTR; } ip_buf_size.u32 = aflt_reg->ip_buf_size.u32; if (g_sw_aflt_flag == TD_TRUE) { adsp_write_addr(in_buf_attr->virt_addr, aflt_reg->ip_buf_addr); } else { adsp_write_addr(in_buf_attr->phys_addr, aflt_reg->ip_buf_addr); } ip_buf_size.bits.inbuff_size = in_buf_attr->size; ip_buf_size.bits.inbuff_flag = in_buf_attr->buf_flag; ip_buf_size.bits.inbuff_eos_flag = (in_buf_attr->eos == TD_TRUE) ? 1 : 0; aflt_reg->ip_buf_size.u32 = ip_buf_size.u32; aflt_reg->ip_buf_wptr = in_buf_attr->write; aflt_reg->ip_buf_rptr = in_buf_attr->read; aflt_reg->read_pos = in_buf_attr->stream_read_pos; aflt_reg->ip_buf_boundary = in_buf_attr->pts_boundary; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_INITINBUF); if (ret != TD_SUCCESS) { soc_log_err("init alft inbuf cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } return TD_SUCCESS; } td_s32 aflt_hal_deinit_inbuf(td_u32 aflt_id) { td_s32 ret; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_DEINITINBUF); if (ret != TD_SUCCESS) { soc_log_err("deinit alft inbuf cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } return TD_SUCCESS; } td_s32 aflt_hal_init_outbuf(td_u32 aflt_id, hal_aflt_outbuf_attr *out_buf_attr) { td_s32 ret; u_op_buf_size op_buf_size; u_op_buf_widx op_buf_widx; u_op_buf_ridx op_buf_ridx; ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if (aflt_reg == TD_NULL) { return SOC_ERR_AFLT_INVALID_PARA; } if (out_buf_attr == TD_NULL) { return SOC_ERR_AFLT_NULL_PTR; } op_buf_size.u32 = aflt_reg->op_buf_size.u32; if (g_sw_aflt_flag == TD_TRUE) { adsp_write_addr(out_buf_attr->virt_addr, aflt_reg->op_buf_addr); } else { adsp_write_addr(out_buf_attr->phys_addr, aflt_reg->op_buf_addr); } op_buf_widx.u32 = aflt_reg->op_buf_widx.u32; op_buf_ridx.u32 = aflt_reg->op_buf_ridx.u32; op_buf_size.bits.periond_size = out_buf_attr->period_buf_size; op_buf_size.bits.periond_num = out_buf_attr->period_number; op_buf_widx.bits.periond_write_idx = out_buf_attr->write; op_buf_widx.bits.periond_write_wrap = out_buf_attr->write_wrap; op_buf_ridx.bits.periond_read_idx = out_buf_attr->read; op_buf_ridx.bits.periond_read_wrap = out_buf_attr->read_wrap; aflt_reg->op_buf_size.u32 = op_buf_size.u32; aflt_reg->op_buf_widx.u32 = op_buf_widx.u32; aflt_reg->op_buf_ridx.u32 = op_buf_ridx.u32; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_INITOUTBUF); if (ret != TD_SUCCESS) { soc_log_err("init alft outbuf cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } return TD_SUCCESS; } td_s32 aflt_hal_deinit_outbuf(td_u32 aflt_id) { td_s32 ret; ret = i_hal_aflt_set_cmd(aflt_id, AFLT_CMD_DEINITOUTBUF); if (ret != TD_SUCCESS) { soc_log_err("deinit alft outbuf cmd failed\n"); soc_err_print_u32(aflt_id); soc_err_print_h32(ret); return ret; } return TD_SUCCESS; } td_void aflt_hal_get_inbuf_write_pos(td_u32 aflt_id, td_u32 *write_pos) { ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if ((aflt_reg == TD_NULL) || (write_pos == TD_NULL)) { return; } *write_pos = aflt_reg->ip_buf_wptr; } td_void aflt_hal_get_inbuf_read_pos(td_u32 aflt_id, td_u32 *read_pos) { ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if ((aflt_reg == TD_NULL) || (read_pos == TD_NULL)) { return; } *read_pos = aflt_reg->ip_buf_rptr; } td_void aflt_hal_get_inbuf_stream_read_pos(td_u32 aflt_id, td_u32 *stream_read_pos) { ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if ((aflt_reg == TD_NULL) || (stream_read_pos == TD_NULL)) { return; } *stream_read_pos = aflt_reg->read_pos; } td_void aflt_hal_set_inbuf_write_pos(td_u32 aflt_id, td_u32 write_pos) { ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if (aflt_reg == TD_NULL) { return; } aflt_reg->ip_buf_wptr = write_pos; } td_void aflt_hal_get_outbuf_write_idx_and_wrap(td_u32 aflt_id, td_u32 *write_idx, td_u32 *write_wrap) { ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if (aflt_reg == TD_NULL) { return; } if (write_idx != TD_NULL) { *write_idx = aflt_reg->op_buf_widx.bits.periond_write_idx; } if (write_wrap != TD_NULL) { *write_wrap = aflt_reg->op_buf_widx.bits.periond_write_wrap; } } td_void aflt_hal_get_outbuf_read_idx_and_wrap(td_u32 aflt_id, td_u32 *read_idx, td_u32 *read_wrap) { ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if (aflt_reg == TD_NULL) { return; } if (read_idx != TD_NULL) { *read_idx = aflt_reg->op_buf_ridx.bits.periond_read_idx; } if (read_wrap != TD_NULL) { *read_wrap = aflt_reg->op_buf_ridx.bits.periond_read_wrap; } } td_void aflt_hal_get_exe_frame_statistics_info(td_u32 aflt_id, td_u32 *try_exe_cnt, td_u32 *frame_cnt, td_u32 *err_frame_cnt) { ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if (aflt_reg == TD_NULL) { return; } if (try_exe_cnt != TD_NULL) { *try_exe_cnt = aflt_reg->try_exe_cnt; } if (frame_cnt != TD_NULL) { *frame_cnt = aflt_reg->status_0.bits.frame_cnt; } if (err_frame_cnt != TD_NULL) { *err_frame_cnt = aflt_reg->status_0.bits.frame_err_cnt; } } td_void aflt_hal_get_time_out_statistics_info(td_u32 aflt_id, td_u32 *sche_time_out_cnt, td_u32 *exe_time_out_cnt) { ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if (aflt_reg == TD_NULL) { return; } if (sche_time_out_cnt != TD_NULL) { *sche_time_out_cnt = aflt_reg->time_out.bits.sche_timeout_cnt; } if (exe_time_out_cnt != TD_NULL) { *exe_time_out_cnt = aflt_reg->time_out.bits.exe_timeout_cnt; } } td_void aflt_hal_set_out_buf_rptr_and_wrap(td_u32 aflt_id, td_u32 read_idx) { td_u32 read_wrap; td_u32 period_num; u_op_buf_ridx op_buf_ridx; ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if (aflt_reg == TD_NULL) { return; } period_num = aflt_reg->op_buf_size.bits.periond_num; op_buf_ridx.u32 = aflt_reg->op_buf_ridx.u32; if (read_idx == period_num) { op_buf_ridx.bits.periond_read_idx = 0; read_wrap = op_buf_ridx.bits.periond_read_wrap; read_wrap ^= 1; /* readidx wrap */ op_buf_ridx.bits.periond_read_wrap = read_wrap; } else { op_buf_ridx.bits.periond_read_idx = read_idx; } aflt_reg->op_buf_ridx.u32 = op_buf_ridx.u32; } td_void aflt_hal_set_eos_flag(td_u32 aflt_id, td_bool eos) { u_aflt_attr attr; ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if (aflt_reg == TD_NULL) { return; } attr.u32 = aflt_reg->attr.u32; attr.bits.eos_flag = !!eos; attr.bits.end_of_frame = 0; aflt_reg->attr.u32 = attr.u32; } td_void aflt_hal_get_end_of_frame(td_u32 aflt_id, td_bool *end_of_frame) { ext_aflt_chan_reg *aflt_reg = aflt_hal_get_chan_reg(aflt_id); if ((aflt_reg == TD_NULL) || (end_of_frame == TD_NULL)) { return; } *end_of_frame = !!aflt_reg->attr.bits.end_of_frame; } #ifdef __cplusplus } #endif /* __cplusplus */