From 70c29ec0dcb528e2e1b80bd783e46ae8b36d15f7 Mon Sep 17 00:00:00 2001 From: Mangesh Kunchamwar Date: Tue, 13 Nov 2018 15:58:13 +0530 Subject: [PATCH] dsp: update q6core driver to vote for LPASS island NPA resource Add interface functions to vote for LPASS island NPA resource from clients. Change-Id: I532dd697f986aca48c3125b1bab3435b890d4039 Signed-off-by: Mangesh Kunchamwar --- dsp/q6core.c | 219 ++++++++++++++++++++++++++++++++++++++++++- include/dsp/q6core.h | 103 +++++++++++++++++++- 2 files changed, 320 insertions(+), 2 deletions(-) diff --git a/dsp/q6core.c b/dsp/q6core.c index f66fc842b52c..d4ea98466308 100644 --- a/dsp/q6core.c +++ b/dsp/q6core.c @@ -32,7 +32,7 @@ #define TIMEOUT_MS 1000 /* - * AVS bring up in the modem is optimitized for the new + * AVS bring up in the modem is optimized for the new * Sub System Restart design and 100 milliseconds timeout * is sufficient to make sure the Q6 will be ready. */ @@ -67,6 +67,8 @@ struct q6core_str { wait_queue_head_t mdf_map_resp_wait; wait_queue_head_t cmd_req_wait; wait_queue_head_t avcs_fwk_ver_req_wait; + wait_queue_head_t lpass_npa_rsc_wait; + u32 lpass_npa_rsc_rsp_rcvd; u32 bus_bw_resp_received; u32 mdf_map_resp_received; enum cmd_flags { @@ -84,6 +86,7 @@ struct q6core_str { struct cal_type_data *cal_data[CORE_MAX_CAL]; uint32_t mem_map_cal_handle; uint32_t mdf_mem_map_cal_handle; + uint32_t npa_client_handle; int32_t adsp_status; int32_t avs_state; struct q6core_avcs_ver_info q6core_avcs_ver_info; @@ -321,6 +324,15 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv) "AVCS_CMD_UNLOAD_TOPO_MODULES", adsp_err_get_err_str(payload1[1])); break; + case AVCS_CMD_DESTROY_LPASS_NPA_CLIENT: + case AVCS_CMD_REQUEST_LPASS_NPA_RESOURCES: + pr_debug("%s: Cmd = AVCS_CMD_CREATE_LPASS_NPA_CLIENT/AVCS_CMD_DESTROY_LPASS_NPA_CLIENT status[%s]\n", + __func__, adsp_err_get_err_str(payload1[1])); + /* ADSP status to match Linux error standard */ + q6core_lcl.adsp_status = -payload1[1]; + q6core_lcl.lpass_npa_rsc_rsp_rcvd = 1; + wake_up(&q6core_lcl.lpass_npa_rsc_wait); + break; default: pr_err("%s: Invalid cmd rsp[0x%x][0x%x] opcode %d\n", __func__, @@ -355,6 +367,15 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv) wake_up(&q6core_lcl.bus_bw_req_wait); } break; + case AVCS_CMDRSP_CREATE_LPASS_NPA_CLIENT: + payload1 = data->payload; + pr_debug("%s: AVCS_CMDRSP_CREATE_LPASS_NPA_CLIENT handle %d\n", + __func__, payload1[1]); + q6core_lcl.adsp_status = payload1[0]; + q6core_lcl.npa_client_handle = payload1[1]; + q6core_lcl.lpass_npa_rsc_rsp_rcvd = 1; + wake_up(&q6core_lcl.lpass_npa_rsc_wait); + break; case AVCS_CMDRSP_ADSP_EVENT_GET_STATE: payload1 = data->payload; q6core_lcl.param = payload1[0]; @@ -933,6 +954,201 @@ bail: } EXPORT_SYMBOL(q6core_is_adsp_ready); +int q6core_create_lpass_npa_client(uint32_t node_id, char *client_name, + uint32_t *client_handle) +{ + struct avcs_cmd_create_lpass_npa_client_t create_lpass_npa_client; + struct avcs_cmd_create_lpass_npa_client_t *cmd_ptr = + &create_lpass_npa_client; + int ret = 0; + + if (!client_name) { + pr_err("%s: Invalid params\n", __func__); + return -EINVAL; + } + + mutex_lock(&(q6core_lcl.cmd_lock)); + + memset(cmd_ptr, 0, sizeof(create_lpass_npa_client)); + + cmd_ptr->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + cmd_ptr->hdr.pkt_size = sizeof(create_lpass_npa_client); + cmd_ptr->hdr.src_port = 0; + cmd_ptr->hdr.dest_port = 0; + cmd_ptr->hdr.token = 0; + cmd_ptr->hdr.opcode = AVCS_CMD_CREATE_LPASS_NPA_CLIENT; + cmd_ptr->node_id = AVCS_SLEEP_ISLAND_CORE_DRIVER_NODE_ID; + strlcpy(cmd_ptr->client_name, client_name, + sizeof(cmd_ptr->client_name)); + + pr_debug("%s: create lpass npa client opcode[0x%x] node id[0x%x]\n", + __func__, cmd_ptr->hdr.opcode, cmd_ptr->node_id); + + *client_handle = 0; + q6core_lcl.adsp_status = 0; + q6core_lcl.lpass_npa_rsc_rsp_rcvd = 0; + ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) cmd_ptr); + if (ret < 0) { + pr_err("%s: create lpass npa client failed %d\n", + __func__, ret); + ret = -EINVAL; + goto done; + } + + ret = wait_event_timeout(q6core_lcl.lpass_npa_rsc_wait, + (q6core_lcl.lpass_npa_rsc_rsp_rcvd == 1), + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + pr_err("%s: timeout. waited for create lpass npa rsc client\n", + __func__); + ret = -ETIMEDOUT; + goto done; + } else { + /* set ret to 0 as no timeout happened */ + ret = 0; + } + + if (q6core_lcl.adsp_status < 0) { + pr_err("%s: DSP returned error %d\n", + __func__, q6core_lcl.adsp_status); + ret = q6core_lcl.adsp_status; + goto done; + } + + *client_handle = q6core_lcl.npa_client_handle; + pr_debug("%s: q6core_lcl.npa_client_handle %d\n", __func__, + q6core_lcl.npa_client_handle); +done: + mutex_unlock(&q6core_lcl.cmd_lock); + return ret; +} +EXPORT_SYMBOL(q6core_create_lpass_npa_client); + +int q6core_destroy_lpass_npa_client(uint32_t client_handle) +{ + struct avcs_cmd_destroy_lpass_npa_client_t destroy_lpass_npa_client; + struct avcs_cmd_destroy_lpass_npa_client_t *cmd_ptr = + &destroy_lpass_npa_client; + int ret = 0; + + mutex_lock(&(q6core_lcl.cmd_lock)); + + memset(cmd_ptr, 0, sizeof(destroy_lpass_npa_client)); + + cmd_ptr->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + cmd_ptr->hdr.pkt_size = sizeof(destroy_lpass_npa_client); + cmd_ptr->hdr.src_port = 0; + cmd_ptr->hdr.dest_port = 0; + cmd_ptr->hdr.token = 0; + cmd_ptr->hdr.opcode = AVCS_CMD_DESTROY_LPASS_NPA_CLIENT; + cmd_ptr->client_handle = client_handle; + + pr_debug("%s: dstry lpass npa client opcode[0x%x] client hdl[0x%x]\n", + __func__, cmd_ptr->hdr.opcode, cmd_ptr->client_handle); + + q6core_lcl.adsp_status = 0; + q6core_lcl.lpass_npa_rsc_rsp_rcvd = 0; + ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) cmd_ptr); + if (ret < 0) { + pr_err("%s: destroy lpass npa client failed %d\n", + __func__, ret); + ret = -EINVAL; + goto done; + } + + ret = wait_event_timeout(q6core_lcl.lpass_npa_rsc_wait, + (q6core_lcl.lpass_npa_rsc_rsp_rcvd == 1), + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + pr_err("%s: timeout. waited for destroy lpass npa rsc client\n", + __func__); + ret = -ETIMEDOUT; + goto done; + } else { + /* set ret to 0 as no timeout happened */ + ret = 0; + } + + if (q6core_lcl.adsp_status < 0) { + pr_err("%s: DSP returned error %d\n", + __func__, q6core_lcl.adsp_status); + ret = q6core_lcl.adsp_status; + } +done: + mutex_unlock(&q6core_lcl.cmd_lock); + return ret; +} +EXPORT_SYMBOL(q6core_destroy_lpass_npa_client); + +int q6core_request_island_transition(uint32_t client_handle, + uint32_t island_allow_mode) +{ + struct avcs_sleep_node_island_transition_config_t island_tsn_cfg; + struct avcs_sleep_node_island_transition_config_t *cmd_ptr = + &island_tsn_cfg; + int ret = 0; + + mutex_lock(&(q6core_lcl.cmd_lock)); + + memset(cmd_ptr, 0, sizeof(island_tsn_cfg)); + + cmd_ptr->req_lpass_npa_rsc.hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + cmd_ptr->req_lpass_npa_rsc.hdr.pkt_size = sizeof(island_tsn_cfg); + cmd_ptr->req_lpass_npa_rsc.hdr.src_port = 0; + cmd_ptr->req_lpass_npa_rsc.hdr.dest_port = 0; + cmd_ptr->req_lpass_npa_rsc.hdr.token = 0; + cmd_ptr->req_lpass_npa_rsc.hdr.opcode = + AVCS_CMD_REQUEST_LPASS_NPA_RESOURCES; + cmd_ptr->req_lpass_npa_rsc.client_handle = client_handle; + cmd_ptr->req_lpass_npa_rsc.resource_id = + AVCS_SLEEP_NODE_ISLAND_TRANSITION_RESOURCE_ID; + cmd_ptr->island_allow_mode = island_allow_mode; + + pr_debug("%s: req islnd tnsn opcode[0x%x] island_allow_mode[0x%x]\n", + __func__, cmd_ptr->req_lpass_npa_rsc.hdr.opcode, + cmd_ptr->island_allow_mode); + + q6core_lcl.adsp_status = 0; + q6core_lcl.lpass_npa_rsc_rsp_rcvd = 0; + ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) cmd_ptr); + if (ret < 0) { + pr_err("%s: island tnsn cmd send failed %d\n", + __func__, ret); + ret = -EINVAL; + goto done; + } + + ret = wait_event_timeout(q6core_lcl.lpass_npa_rsc_wait, + (q6core_lcl.lpass_npa_rsc_rsp_rcvd == 1), + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + pr_err("%s: timeout. waited for island lpass npa rsc req\n", + __func__); + ret = -ETIMEDOUT; + goto done; + } else { + /* set ret to 0 as no timeout happened */ + ret = 0; + } + + if (q6core_lcl.adsp_status < 0) { + pr_err("%s: DSP returned error %d\n", + __func__, q6core_lcl.adsp_status); + ret = q6core_lcl.adsp_status; + } +done: + mutex_unlock(&q6core_lcl.cmd_lock); + return ret; +} +EXPORT_SYMBOL(q6core_request_island_transition); + int q6core_map_memory_regions(phys_addr_t *buf_add, uint32_t mempool_id, uint32_t *bufsz, uint32_t bufcnt, uint32_t *map_handle) { @@ -1671,6 +1887,7 @@ int __init core_init(void) init_waitqueue_head(&q6core_lcl.cmd_req_wait); init_waitqueue_head(&q6core_lcl.avcs_fwk_ver_req_wait); init_waitqueue_head(&q6core_lcl.mdf_map_resp_wait); + init_waitqueue_head(&q6core_lcl.lpass_npa_rsc_wait); q6core_lcl.cmd_resp_received_flag = FLAG_NONE; mutex_init(&q6core_lcl.cmd_lock); mutex_init(&q6core_lcl.ver_lock); diff --git a/include/dsp/q6core.h b/include/dsp/q6core.h index 1fa0d1e98a9f..e1f8b97dbb90 100644 --- a/include/dsp/q6core.h +++ b/include/dsp/q6core.h @@ -19,6 +19,8 @@ #define AVCS_CMD_ADSP_EVENT_GET_STATE 0x0001290C #define AVCS_CMDRSP_ADSP_EVENT_GET_STATE 0x0001290D +#define AVCS_API_VERSION_V4 4 +#define APRV2_IDS_SERVICE_ID_ADSP_CORE_V (0x3) bool q6core_is_adsp_ready(void); @@ -150,7 +152,7 @@ struct avcs_cmd_register_topologies { } __packed; -#define AVCS_CMD_DEREGISTER_TOPOLOGIES 0x0001292a +#define AVCS_CMD_DEREGISTER_TOPOLOGIES 0x0001292a /* The payload for the AVCS_CMD_DEREGISTER_TOPOLOGIES command */ struct avcs_cmd_deregister_topologies { @@ -195,6 +197,99 @@ struct avcs_cmd_load_unload_topo_modules { uint32_t topology_id; } __packed; +/* This command allows a remote client(HLOS) creates a client to LPASS NPA + * resource node. Currently, this command supports only the NPA Sleep resource + * "/island/core/drivers" node ID. + */ +#define AVCS_CMD_CREATE_LPASS_NPA_CLIENT 0x00012985 + +#define AVCS_SLEEP_ISLAND_CORE_DRIVER_NODE_ID 0x00000001 + +struct avcs_cmd_create_lpass_npa_client_t { + struct apr_hdr hdr; + uint32_t node_id; + /* Unique ID of the NPA node. + * @values + * - #AVCS_SLEEP_ISLAND_CORE_DRIVER_NODE_ID + */ + + char client_name[16]; + /* Client name, up to a maximum of sixteen characters.*/ +}; + +/* In response to the #AVCS_CMD_CREATE_LPASS_NPA_CLIENT command, the AVCS + * returns the handle to remote HLOS client. + */ +#define AVCS_CMDRSP_CREATE_LPASS_NPA_CLIENT 0x00012986 + +struct avcs_cmdrsp_create_lpass_npa_client_t { + uint32_t status; + /* Status message (error code). + * @values + * - ADSP_EOK -- Create was successful + * - ADSP_EFAILED -- Create failed + */ + + uint32_t client_handle; + /* Handle of the client.*/ +}; + +/* The remote HLOS client use this command to issue the request to the npa + * resource. Remote client(HLOS) must send the valid npa client handle and + * resource id info. + */ +#define AVCS_CMD_REQUEST_LPASS_NPA_RESOURCES 0x00012987 + +#define AVCS_SLEEP_NODE_ISLAND_TRANSITION_RESOURCE_ID 0x00000001 + +#define SLEEP_RESTRICT_ISLAND 0x0 +#define SLEEP_ALLOW_ISLAND 0x1 + +/* Immediately following this structure is the resource request configuration + * data payload. Payload varies depend on the resource_id requested. + * Currently supported only island transition payload. + */ +struct avcs_cmd_request_lpass_npa_resources_t { + struct apr_hdr hdr; + uint32_t client_handle; + /* Handle of the client. + * @values + * - Valid uint32 number + */ + + uint32_t resource_id; + /* Unique ID of the NPA resource ID. + * @values + * - #AVCS_SLEEP_NODE_ISLAND_TRANSITION_RESOURCE_ID + */ +}; + +/* This structure contains the sleep node resource payload data. + */ +struct avcs_sleep_node_island_transition_config_t { + struct avcs_cmd_request_lpass_npa_resources_t req_lpass_npa_rsc; + uint32_t island_allow_mode; + /* Specifies the island state. + * @values + * - #SLEEP_RESTRICT_ISLAND + * - #SLEEP_ALLOW_ISLAND + */ +}; + +/* This command allows remote client(HLOS) to destroy the npa node client + * handle, which is created using the #AVCS_CMD_CREATE_LPASS_NPA_CLIENT command. + * Remote client(HLOS) must send the valid npa client handle. + */ +#define AVCS_CMD_DESTROY_LPASS_NPA_CLIENT 0x00012988 + +struct avcs_cmd_destroy_lpass_npa_client_t { + struct apr_hdr hdr; + uint32_t client_handle; + /* Handle of the client. + * @values + * - Valid uint32 number + */ +}; int q6core_map_memory_regions(phys_addr_t *buf_add, uint32_t mempool_id, uint32_t *bufsz, uint32_t bufcnt, uint32_t *map_handle); @@ -212,6 +307,12 @@ int32_t core_get_license_status(uint32_t module_id); int32_t q6core_load_unload_topo_modules(uint32_t topology_id, bool preload_type); +int q6core_create_lpass_npa_client(uint32_t node_id, char *client_name, + uint32_t *client_handle); +int q6core_destroy_lpass_npa_client(uint32_t client_handle); +int q6core_request_island_transition(uint32_t client_handle, + uint32_t island_allow_mode); + #if IS_ENABLED(CONFIG_USE_Q6_32CH_SUPPORT) static inline bool q6core_use_Q6_32ch_support(void) {