/* * Copyright (c) 1997-2015, Wind River Systems, Inc. * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include "dsp_inner.h" #include extern const struct dsp_imageinfo *dsp_create_image(const char *name); extern void dsp_free_image(const struct dsp_imageinfo *image); static struct dsp_session *global_session = NULL; static unsigned int global_uuid = 0; int dsp_session_get_state(struct dsp_session *session) { int state = 0; dsp_request_userinfo(session->dev, DSP_REQUEST_TASK_STATE, &state); return state; } int dsp_session_get_error(struct dsp_session *session) { int error = 0; dsp_request_userinfo(session->dev, DSP_REQUEST_ERROR_CODE, &error); return error; } uint32_t dsp_session_get_debug_info(struct dsp_session *session, uint32_t index) { dsp_request_userinfo(session->dev, DSP_REQUEST_USER_DEFINED, &index); return index; } void dsp_session_dump(struct dsp_session *session) { struct dsp_request_session request; if (!session) { /* implicitly point to global session */ session = global_session; if (!session) return; } dsp_request_userinfo(session->dev, DSP_REQUEST_SESSION_INFO, &request); SYS_LOG_ERR("\n---------------------------dsp dump---------------------------\n"); SYS_LOG_ERR("session (id=%u, uuid=%u):\n", session->id, session->uuid); SYS_LOG_ERR("\tstate=%d\n", dsp_session_get_state(session)); SYS_LOG_ERR("\terror=0x%x\n", dsp_session_get_error(session)); SYS_LOG_ERR("\tfunc_allowed=0x%x\n", session->func_allowed); SYS_LOG_ERR("\tfunc_enabled=0x%x\n", request.func_enabled); SYS_LOG_ERR("\tfunc_runnable=0x%x\n", request.func_runnable); SYS_LOG_ERR("\tfunc_counter=0x%x\n", request.func_counter); if (request.info) dsp_session_dump_info(session, request.info); if (request.func_enabled) { for (int i = 0; i < DSP_NUM_FUNCTIONS; i++) { if (request.func_enabled & DSP_FUNC_BIT(i)) dsp_session_dump_function(session, i); } } SYS_LOG_ERR("--------------------------------------------------------------\n\n"); } static int dsp_session_set_id(struct dsp_session *session) { struct dsp_session_id_set set = { .id = session->id, .uuid = session->uuid, .func_allowed = session->func_allowed, }; struct dsp_command *command = dsp_command_alloc(DSP_CMD_SET_SESSION, NULL, sizeof(set), &set); if (command == NULL) return -ENOMEM; dsp_session_submit_command(session, command); dsp_command_free(command); return 0; } static inline int dsp_session_get(struct dsp_session *session) { return atomic_inc(&session->open_refcnt); } static inline int dsp_session_put(struct dsp_session *session) { return atomic_dec(&session->open_refcnt); } static void dsp_session_destroy(struct dsp_session *session); static struct acts_ringbuf cmd_buff __in_section_unique(DSP_SHARE_RAM); static u8_t dsp_cmd_buff[DSP_SESSION_COMMAND_BUFFER_SIZE] __in_section_unique(DSP_SHARE_RAM); static struct dsp_session static_globle_session __in_section_unique(DSP_SHARE_RAM); static struct dsp_session *dsp_session_create(struct dsp_session_info *info) { struct dsp_session *session = NULL; if (info == NULL || info->main_dsp == NULL) return NULL; session = &static_globle_session; memset(session, 0, sizeof(struct dsp_session)); if (session == NULL) { SYS_LOG_ERR("malloc failed %d", sizeof(*session)); return NULL; } memset(session, 0, sizeof(*session)); /* find dsp device */ session->dev = (struct device *)device_get_binding(CONFIG_DSP_NAME); if (session->dev == NULL) { SYS_LOG_ERR("cannot find device \"%s\"", CONFIG_DSP_ACTS_DEV_NAME); goto fail_exit; } /* find images */ session->images[DSP_IMAGE_MAIN] = dsp_create_image(info->main_dsp); if (!session->images[DSP_IMAGE_MAIN]) { goto fail_exit; } if (info->sub_dsp) { session->images[DSP_IMAGE_SUB] = dsp_create_image(info->sub_dsp); if (!session->images[DSP_IMAGE_SUB]) { //goto fail_exit; } } /* allocate command buffer */ acts_ringbuf_init(&cmd_buff, dsp_cmd_buff, DSP_SESSION_COMMAND_BUFFER_SIZE); cmd_buff.dsp_ptr = mcu_to_dsp_address(cmd_buff.cpu_ptr, 0); session->cmdbuf.cur_seq = 0; session->cmdbuf.alloc_seq = 1; session->cmdbuf.cpu_bufptr = (uint32_t)&cmd_buff; session->cmdbuf.dsp_bufptr = mcu_to_dsp_address(session->cmdbuf.cpu_bufptr, 0); k_sem_init(&session->sem, 0, 1); k_mutex_init(&session->mutex); atomic_set(&session->open_refcnt, 0); #ifdef ENABLE_SESSION_BEGIN_END_REFCNT atomic_set(&session->run_refcnt, 0); #endif session->id = info->type; session->uuid = ++global_uuid; SYS_LOG_INF("session %u created (uuid=%u)", session->id, session->uuid); return session; fail_exit: dsp_session_destroy(session); return NULL; } static void dsp_session_destroy(struct dsp_session *session) { if (atomic_get(&session->open_refcnt) != 0) SYS_LOG_ERR("session not closed yet (ref=%d)", atomic_get(&session->open_refcnt)); for (int i = 0; i < ARRAY_SIZE(session->images); i++) { if (session->images[i]) dsp_free_image(session->images[i]); } //static malloc, should no be free //if (session->cmdbuf.cpu_bufptr) // acts_ringbuf_free((struct acts_ringbuf *)(session->cmdbuf.cpu_bufptr)); SYS_LOG_INF("session %u destroyed (uuid=%u)", session->id, session->uuid); //mem_free(session); } static int dsp_session_message_handler(struct dsp_message *message) { if (!global_session || message->id != DSP_MSG_KICK) return -ENOTTY; switch (message->param1) { case DSP_EVENT_FENCE_SYNC: if (message->param2){ if(k_sem_count_get((struct k_sem *)message->param2) > 1){ SYS_LOG_ERR("invalid ksem %p", (struct k_sem *)message->param2); }else{ k_sem_give((struct k_sem *)message->param2); } } break; case DSP_EVENT_NEW_CMD: case DSP_EVENT_NEW_DATA: k_sem_give(&global_session->sem); break; default: return -ENOTTY; } return 0; } #ifdef CONFIG_DSP_LOAD_ROM #define DSP_PROM_ADDR 0x30010000 #define DSP_SDKPROM_ADDR (0x30010000 + 0x12E00) #define DSP_DROM_ADDR 0x30000000 #define DSP_PROM_NAME "DPROM.bin" #define DSP_DROM_NAME "DDROM.bin" #define DSP_SDKDROM_NAME "sdk_rom.bin" static int rom_image_loaded = 0; static int dsp_load_rom_image(const char *name, unsigned int addr) { void *ptr; int size; SYS_LOG_ERR("dsp image \"%s\"\n", name); if (sd_fmap(name, (void **)&ptr, (int *)&size)) { SYS_LOG_ERR("cannot find dsp image \"%s\"\n", name); return -1; } memcpy((void *)addr, ptr, size); return 0; } #endif static int dsp_session_open(struct dsp_session *session, struct dsp_session_info *info) { int res = 0; if (dsp_session_get(session) != 0) { //SYS_LOG_ERR("session is opened already! uuid: 0x%x\n", session->uuid); return -EALREADY; } if (info == NULL) { res = -EINVAL; goto fail_out; } /* load dsp rom image */ #ifdef CONFIG_DSP_LOAD_ROM if( !rom_image_loaded ) { if(dsp_load_rom_image(DSP_PROM_NAME, DSP_PROM_ADDR) < 0) { res = -1; goto fail_out; } if(dsp_load_rom_image(DSP_DROM_NAME, DSP_DROM_ADDR) < 0) { res = -1; goto fail_out; } #if 0 if(dsp_load_rom_image(DSP_SDKDROM_NAME, DSP_SDKPROM_ADDR) < 0) { res = -1; goto fail_out; } #endif rom_image_loaded = 1; } #endif /* load main dsp image */ res = dsp_request_image(session->dev, session->images[DSP_IMAGE_MAIN], DSP_IMAGE_MAIN); if (res) { SYS_LOG_ERR("failed to load main image \"%s\"", session->images[DSP_IMAGE_MAIN]->name); goto fail_out; } /* load sub dsp image */ if (session->images[DSP_IMAGE_SUB]) { res = dsp_request_image(session->dev, session->images[DSP_IMAGE_SUB], DSP_IMAGE_SUB); if (res) { SYS_LOG_ERR("failed to load sub image \"%s\"", session->images[DSP_IMAGE_SUB]->name); goto fail_release_main; } } /* reset and register command buffer */ session->cmdbuf.cur_seq = 0; session->cmdbuf.alloc_seq = 1; acts_ringbuf_reset((struct acts_ringbuf *)(session->cmdbuf.cpu_bufptr)); /* power on */ res = dsp_poweron(session->dev, &session->cmdbuf); if (res) { SYS_LOG_ERR("dsp_poweron failed"); goto fail_release_sub; } /* configure session id to dsp */ session->func_allowed = info->func_allowed; res = dsp_session_set_id(session); if (res) { SYS_LOG_ERR("dsp_session_set_id failed"); dsp_poweroff(session->dev); goto fail_release_sub; } /* register message handler only after everything OK */ k_sem_reset(&session->sem); dsp_register_message_handler(session->dev, dsp_session_message_handler); SYS_LOG_INF("session %u opened (uuid=%u, allowed=0x%x)", session->id, session->uuid, info->func_allowed); return 0; fail_release_sub: if (session->images[DSP_IMAGE_SUB]) dsp_release_image(session->dev, DSP_IMAGE_SUB); fail_release_main: dsp_release_image(session->dev, DSP_IMAGE_MAIN); fail_out: dsp_session_put(session); return res; } static int dsp_session_close(struct dsp_session *session) { if (dsp_session_put(session) != 1) return -EBUSY; if (session->cmdbuf.cur_seq + 1 != session->cmdbuf.alloc_seq) SYS_LOG_WRN("session %u command not finished %d %d ", session->id,session->cmdbuf.cur_seq,session->cmdbuf.alloc_seq); dsp_unregister_message_handler(session->dev); dsp_poweroff(session->dev); for (int i = 0; i < ARRAY_SIZE(session->images); i++) { if (session->images[i]) dsp_release_image(session->dev, i); } dsp_release_mem(session->dev, 0); SYS_LOG_INF("session %u closed (uuid=%u)", session->id, session->uuid); return 0; } struct dsp_session *dsp_open_global_session(struct dsp_session_info *info) { int res; if (global_session == NULL) { if(info){ global_session = dsp_session_create(info); if (global_session == NULL) { SYS_LOG_ERR("failed to create global session"); return NULL; } }else{ return NULL; } } if(info){ res = dsp_session_open(global_session, info); if (res < 0 && res != -EALREADY) { SYS_LOG_ERR("failed to open global session"); dsp_session_destroy(global_session); global_session = NULL; } }else{ res = dsp_session_open(global_session, info); if (res < 0 && res != -EALREADY) { SYS_LOG_ERR("failed to open global session"); return NULL; } } return global_session; } void dsp_close_global_session(struct dsp_session *session) { //assert(session == global_session); if (global_session) { if (!dsp_session_close(global_session)) { dsp_session_destroy(global_session); global_session = NULL; } } } int dsp_session_wait(struct dsp_session *session, int timeout) { return k_sem_take(&session->sem, SYS_TIMEOUT_MS(timeout)); } int dsp_session_kick(struct dsp_session *session) { return dsp_kick(session->dev, session->uuid, DSP_EVENT_NEW_DATA, 0); } int dsp_session_submit_command(struct dsp_session *session, struct dsp_command *command) { struct acts_ringbuf *buf = (struct acts_ringbuf *)(session->cmdbuf.cpu_bufptr); unsigned int size = sizeof_dsp_command(command); unsigned int space; unsigned int wait_time = 500; int res = -ENOMEM; if (!global_session){ return -ENODEV; } k_mutex_lock(&session->mutex, K_FOREVER); #ifdef ENABLE_SESSION_BEGIN_END_REFCNT if ((command->id == DSP_CMD_SESSION_BEGIN && atomic_inc(&session->run_refcnt) != 0) || (command->id == DSP_CMD_SESSION_END && atomic_dec(&session->run_refcnt) != 1)) { if (command->sem) { SYS_LOG_DBG("ignore command %d", command->id); k_sem_give((struct k_sem *)command->sem); } res = 0; goto out_unlock; } #endif while(wait_time){ space = acts_ringbuf_space(buf); if (space < ACTS_RINGBUF_NELEM(size)) { os_sleep(10); wait_time -= 10; SYS_LOG_WRN("wait cmd space %d %d %d", size, acts_ringbuf_head_offset(buf), acts_ringbuf_tail_offset(buf)); }else{ break; } } if (wait_time == 0){ SYS_LOG_ERR("No enough space (%u) for command (id=0x%04x, size=%u)", space, command->id, size); #ifdef ENABLE_SESSION_BEGIN_END_REFCNT switch (command->id) { case DSP_CMD_SESSION_BEGIN: atomic_dec(&session->run_refcnt); break; case DSP_CMD_SESSION_END: atomic_inc(&session->run_refcnt); break; default: break; } #endif goto out_unlock; } /* alloc sequence number */ command->seq = session->cmdbuf.alloc_seq++; /* insert command */ res = acts_ringbuf_put(buf, command, ACTS_RINGBUF_NELEM(size)); if(res == 0){ SYS_LOG_ERR("send cmd failed\n"); } SYS_LOG_INF("submit cmd %d %d %d %d seq %d totalsize %d buffer %d \n", command->id, command->data[0], command->data[1],command->size,command->seq,ACTS_RINGBUF_NELEM(size),acts_ringbuf_length(buf)); /* kick dsp to process command */ res = dsp_kick(session->dev, session->uuid, DSP_EVENT_NEW_CMD, 0); res = 0; out_unlock: k_mutex_unlock(&session->mutex); return res; } int dsp_console_set_cmd(uint16_t id, uint32_t param1, uint32_t param2) { struct dsp_command *command; int ret = 0; command = mem_malloc(sizeof(*command) + 8); if (command) { command->id = id; command->sem = 0; command->size = 8; command->data[0] = param1; command->data[1] = param2; } else { return -ENOMEM; } if (!global_session) { printk("[WRN] dsp global session is null\n"); ret = -ENODEV; } else { dsp_session_submit_command(global_session, command); } mem_free((void *)command); return ret; }