Merge "ASoC: msm: qdsp6v2: enable DMA channel control"

This commit is contained in:
Linux Build Service Account 2018-05-06 02:07:09 -07:00 committed by Gerrit - the friendly Code Review server
commit 5c49e73d6d
3 changed files with 552 additions and 1 deletions

View file

@ -3512,6 +3512,263 @@ struct afe_param_id_set_topology_cfg {
u32 topology_id;
} __packed;
/*
* This command is used by client to request the LPASS resources.
* Currently this command supports only LPAIF DMA resources.
* Allocated resources will be in control of remote client until
* they get released.
*
* If all the requested resources are available then response status in
* AFE_CMDRSP_REQUEST_LPASS_RESOURCES payload will
* be updated with ADSP_EOK, otherwise it will be ADSP_EFAILED.
*
* This command is variable payload size command, and size depends
* on the type of resource requested.
*
* For example, if client requests AFE_LPAIF_DMA_RESOURCE_ID
* resources, afe_cmd_request_lpass_resources structure will
* be followed with the afe_cmd_request_lpass_dma_resources
* structure.
*
* AFE_CMDRSP_REQUEST_LPASS_RESOURCES is the response for
* this command, which returns the allocated resources.
*
* @apr_hdr_fields
* Opcode -- AFE_CMD_REQUEST_LPASS_RESOURCES
*
* @return
* #AFE_CMDRSP_REQUEST_LPASS_RESOURCES
*/
#define AFE_CMD_REQUEST_LPASS_RESOURCES 0x00010109
/* Macro for requesting LPAIF DMA resources */
#define AFE_LPAIF_DMA_RESOURCE_ID 0x00000001
struct afe_cmd_request_lpass_resources {
/*
* LPASS Resource ID
* @values:
* - AFE_LPAIF_DMA_RESOURCE_ID
*/
u32 resource_id;
} __packed;
/*
* AFE_CMD_REQUEST_LPASS_RESOURCES uses this structure when
* client is requesting LPAIF DMA resources.
*
* Number of read DMA channels and write DMA channels varies from chipset to
* chipset. HLOS needs to make sure that when it requests LPASS DMA
* resources, it should not impact the concurrencies which
* are mandatory for a given chipset.
*/
/* Macro for AFE LPAIF default DMA data type */
#define AFE_LPAIF_DEFAULT_DMA_TYPE 0x0
struct afe_cmd_request_lpass_dma_resources {
/*
* LPASS DMA Type
* @values:
* - AFE_LPAIF_DEFAULT_DMA_TYPE
*/
u8 dma_type;
/*
* Number of read DMA channels required
* @values: >=0
* - 0 indicates channels are not requested
*/
u8 num_read_dma_channels;
/*
* Number of write DMA channels required
* @values: >=0
* - 0 indicates channels are not requested
*/
u8 num_write_dma_channels;
/*
* Reserved field for 4 byte alignment
* @values: 0
*/
u8 reserved;
} __packed;
struct afe_request_lpass_dma_resources_command {
struct apr_hdr hdr;
struct afe_cmd_request_lpass_resources resources;
struct afe_cmd_request_lpass_dma_resources dma_resources;
} __packed;
/*
* This is the response for the command AFE_CMD_REQUEST_LPASS_RESOURCES.
* Payload of this command is variable.
*
* Resources allocated successfully or not, are determined by the "status"
* in the payload. If status is ADSP_EOK, then resources are
* allocated successfully and allocated resource information
* follows.
*
* For example, if the response resource id is AFE_LPAIF_DMA_RESOURCE_ID,
* afe_cmdrsp_request_lpass_dma_resources structure will
* follow after afe_cmdrsp_request_lpass_resources.
*
* If status is ADSP_EFAILED, this indicates requested resources
* are not allocated successfully. In this case the payload following
* this structure is invalid.
* @apr_hdr_fields
* Opcode -- AFE_CMDRSP_REQUEST_LPASS_RESOURCES
*/
#define AFE_CMDRSP_REQUEST_LPASS_RESOURCES 0x0001010A
struct afe_cmdrsp_request_lpass_resources {
/*
* ADSP_EOK if all requested resources are allocated.
* ADSP_EFAILED if resource allocation is failed.
*/
u32 status;
/*
* Returned LPASS DMA resource ID
* @values:
* - AFE_LPAIF_DMA_RESOURCE_ID
*/
u32 resource_id;
} __packed;
/*
* This command will be sent as a payload for
* AFE_CMDRSP_REQUEST_LPASS_RESOURCES, when the LPAIF DMA resources
* were requested. Payload of this command is variable, which
* follows after the afe_cmdrsp_request_lpass_dma_resources structure.
* The size in bytes following this structure is sum of
* num_read_dma_channels and num_write_dma_channels.
*
* If the resource allocation is successful, then the payload contains
* the valid DMA channel indices.
*
* For example, if number of requested DMA read channels is 2, and they
* are successfully allocated, the variable payload contains
* valid DMA channel index values in first two bytes array.
*
* In the failure case this payload can be ignored, and all the values will be
* initialized with zeros.
*
* An example payload of the command response is below:
* <struct afe_cmdrsp_request_lpass_resources>
* <struct afe_cmdrsp_request_lpass_dma_resources>
* read DMA index value for each byte.
* write DMA index value for each byte.
* padded zeros, if sum of num_read_dma_channels and num_write_dma_channels
* are not multiples of 4.
*/
struct afe_cmdrsp_request_lpass_dma_resources {
/*
* LPASS DMA Type
* @values:
* - AFE_LPAIF_DEFAULT_DMA_TYPE
*/
u8 dma_type;
/*
* Returned number of read DMA channels allocated
* @values: >=0
*/
u8 num_read_dma_channels;
/*
* Returned number of write DMA channels allocated
* @values: >=0
*/
u8 num_write_dma_channels;
/*
* Reserved field for 4 byte alignment
* @values: 0
*/
u8 reserved;
} __packed;
/*
* This command is for releasing resources which are allocated as
* part of AFE_CMD_REQUEST_LPASS_RESOURCES.
*
* Payload of this command is variable, which follows
* after the afe_cmd_release_lpass_resources structure.
*
* If release resource is AFE_LPAIF_DMA_RESOURCE_ID
* afe_cmd_release_lpass_dma_resources structure will be
* followed after afe_cmd_release_lpass_resources.
*
*
* @apr_hdr_fields
* Opcode -- AFE_CMD_RELEASE_LPASS_RESOURCES
* @return
* #APRv2 IBASIC RSP Result
*/
#define AFE_CMD_RELEASE_LPASS_RESOURCES 0x0001010B
struct afe_cmd_release_lpass_resources {
/*
* LPASS DMA resource ID
* @values:
* - AFE_LPAIF_DMA_RESOURCE_ID
*/
u32 resource_id;
} __packed;
/*
* This payload to be appended as part of AFE_CMD_RELEASE_LPASS_RESOURCES
* when resource id AFE_LPAIF_DMA_RESOURCE_ID is used.
*
* Payload of this command is variable, which will be followed after the
* afe_cmd_release_lpass_dma_resources structure.
* The variable payload's size in bytes is sum of
* num_read_dma_channels and num_write_dma_channels.
* Variable payload data contains the valid DMA channel indices which are
* allocated as part of AFE_CMD_REQUEST_LPASS_RESOURCES.
*
* For example, if number of DMA read channels released are 2,
* the variable payload contains valid DMA channel
* index values in first two bytes of variable payload.
* Client needs to fill the same DMA channel indices were returned
* as part of AFE_CMD_RELEASE_LPASS_RESOURCES, otherwise
* ADSP will return the error.
*
* An example payload of the release command is below:
* <struct afe_cmd_release_lpass_resources>
* <struct afe_cmd_release_lpass_dma_resources>
* read DMA index value for each byte.
* write DMA index value for each byte.
*/
struct afe_cmd_release_lpass_dma_resources {
/*
* LPASS DMA Type
* @values:
* - AFE_LPAIF_DEFAULT_DMA_TYPE
*/
u8 dma_type;
/*
* Number of read DMA channels to be released
* @values: >=0
* - 0 indicates channels are not released
*/
u8 num_read_dma_channels;
/*
* Number of write DMA channels to be released
* @values: >=0
* - 0 indicates channels are not released
*/
u8 num_write_dma_channels;
/*
* Reserved field for 4 byte alignment
* @values: 0
*/
u8 reserved;
} __packed;
struct afe_release_lpass_dma_resources_command {
struct apr_hdr hdr;
struct afe_cmd_release_lpass_resources resources;
struct afe_cmd_release_lpass_dma_resources dma_resources;
} __packed;
/*
* Generic encoder module ID.

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -42,6 +42,9 @@
#define AFE_CLK_VERSION_V1 1
#define AFE_CLK_VERSION_V2 2
#define AFE_MAX_RDDMA 10
#define AFE_MAX_WRDMA 10
typedef int (*routing_cb)(int port);
enum {
@ -450,4 +453,9 @@ void afe_set_routing_callback(routing_cb);
int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats,
u16 port);
int afe_get_svc_version(uint32_t service_id);
int afe_request_dma_resources(uint8_t dma_type, uint8_t num_read_dma_channels,
uint8_t num_write_dma_channels);
int afe_get_dma_idx(bool **ret_rddma_idx,
bool **ret_wrdma_idx);
int afe_release_all_dma_resources(void);
#endif /* __Q6AFE_V2_H__ */

View file

@ -124,6 +124,10 @@ struct afe_ctl {
int set_custom_topology;
int dev_acdb_id[AFE_MAX_PORTS];
routing_cb rt_cb;
int num_alloced_rddma;
bool alloced_rddma[AFE_MAX_RDDMA];
int num_alloced_wrdma;
bool alloced_wrdma[AFE_MAX_WRDMA];
};
static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
@ -385,6 +389,99 @@ static int32_t sp_make_afe_callback(uint32_t opcode, uint32_t *payload,
return 0;
}
static int32_t afe_lpass_resources_callback(struct apr_client_data *data)
{
uint8_t *payload = data->payload;
struct afe_cmdrsp_request_lpass_resources *resources =
(struct afe_cmdrsp_request_lpass_resources *) payload;
struct afe_cmdrsp_request_lpass_dma_resources *dma_resources = NULL;
uint8_t *dma_channels_id_payload = NULL;
if (!payload || (data->token >= AFE_MAX_PORTS)) {
pr_err("%s: Error: size %d payload %pK token %d\n",
__func__, data->payload_size,
payload, data->token);
atomic_set(&this_afe.status, ADSP_EBADPARAM);
return -EINVAL;
}
if (resources->status != 0) {
pr_debug("%s: Error: Requesting LPASS resources ret %d\n",
__func__, resources->status);
atomic_set(&this_afe.status, ADSP_EBADPARAM);
return -EINVAL;
}
if (resources->resource_id == AFE_LPAIF_DMA_RESOURCE_ID) {
int i;
payload += sizeof(
struct afe_cmdrsp_request_lpass_resources);
dma_resources = (struct
afe_cmdrsp_request_lpass_dma_resources *)
payload;
pr_debug("%s: DMA Type allocated = %d\n",
__func__,
dma_resources->dma_type);
if (dma_resources->num_read_dma_channels > AFE_MAX_RDDMA) {
pr_err("%s: Allocated Read DMA %d exceeds max %d\n",
__func__,
dma_resources->num_read_dma_channels,
AFE_MAX_RDDMA);
dma_resources->num_read_dma_channels = AFE_MAX_RDDMA;
}
if (dma_resources->num_write_dma_channels > AFE_MAX_WRDMA) {
pr_err("%s: Allocated Write DMA %d exceeds max %d\n",
__func__,
dma_resources->num_write_dma_channels,
AFE_MAX_WRDMA);
dma_resources->num_write_dma_channels = AFE_MAX_WRDMA;
}
this_afe.num_alloced_rddma =
dma_resources->num_read_dma_channels;
this_afe.num_alloced_wrdma =
dma_resources->num_write_dma_channels;
pr_debug("%s: Number of allocated Read DMA channels= %d\n",
__func__,
dma_resources->num_read_dma_channels);
pr_debug("%s: Number of allocated Write DMA channels= %d\n",
__func__,
dma_resources->num_write_dma_channels);
payload += sizeof(
struct afe_cmdrsp_request_lpass_dma_resources);
dma_channels_id_payload = payload;
for (i = 0; i < this_afe.num_alloced_rddma; i++) {
pr_debug("%s: Read DMA Index %d allocated\n",
__func__, *dma_channels_id_payload);
this_afe.alloced_rddma
[*dma_channels_id_payload] = 1;
dma_channels_id_payload++;
}
for (i = 0; i < this_afe.num_alloced_wrdma; i++) {
pr_debug("%s: Write DMA Index %d allocated\n",
__func__, *dma_channels_id_payload);
this_afe.alloced_wrdma
[*dma_channels_id_payload] = 1;
dma_channels_id_payload++;
}
} else {
pr_err("%s: Error: Unknown resource ID %d",
__func__, resources->resource_id);
atomic_set(&this_afe.status, ADSP_EBADPARAM);
return -EINVAL;
}
return 0;
}
static int32_t afe_callback(struct apr_client_data *data, void *priv)
{
if (!data) {
@ -472,6 +569,15 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
return -EINVAL;
}
wake_up(&this_afe.wait[data->token]);
} else if (data->opcode == AFE_CMDRSP_REQUEST_LPASS_RESOURCES) {
uint32_t ret = 0;
ret = afe_lpass_resources_callback(data);
atomic_set(&this_afe.state, 0);
wake_up(&this_afe.wait[data->token]);
if (!ret) {
return ret;
}
} else if (data->payload_size) {
uint32_t *payload;
uint16_t port_id = 0;
@ -502,6 +608,7 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
case AFE_PORTS_CMD_DTMF_CTL:
case AFE_SVC_CMD_SET_PARAM:
case AFE_SVC_CMD_SET_PARAM_V2:
case AFE_CMD_REQUEST_LPASS_RESOURCES:
atomic_set(&this_afe.state, 0);
wake_up(&this_afe.wait[data->token]);
break;
@ -541,6 +648,18 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
atomic_set(&this_afe.state, payload[1]);
wake_up(&this_afe.wait[data->token]);
break;
case AFE_CMD_RELEASE_LPASS_RESOURCES:
memset(&this_afe.alloced_rddma[0],
0,
AFE_MAX_RDDMA);
memset(&this_afe.alloced_wrdma[0],
0,
AFE_MAX_WRDMA);
this_afe.num_alloced_rddma = 0;
this_afe.num_alloced_wrdma = 0;
atomic_set(&this_afe.state, 0);
wake_up(&this_afe.wait[data->token]);
break;
default:
pr_err("%s: Unknown cmd 0x%x\n", __func__,
payload[0]);
@ -6598,6 +6717,173 @@ done:
return result;
}
int afe_request_dma_resources(uint8_t dma_type, uint8_t num_read_dma_channels,
uint8_t num_write_dma_channels)
{
int result = 0;
struct afe_request_lpass_dma_resources_command config;
pr_debug("%s:\n", __func__);
if (dma_type != AFE_LPAIF_DEFAULT_DMA_TYPE) {
pr_err("%s: DMA type %d is invalid\n",
__func__,
dma_type);
goto done;
}
if ((num_read_dma_channels == 0) &&
(num_write_dma_channels == 0)) {
pr_err("%s: DMA channels to allocate are 0\n",
__func__);
goto done;
}
if (num_read_dma_channels > AFE_MAX_RDDMA) {
pr_err("%s: Read DMA channels %d to allocate are > %d\n",
__func__,
num_read_dma_channels,
AFE_MAX_RDDMA);
goto done;
}
if (num_write_dma_channels > AFE_MAX_WRDMA) {
pr_err("%s: Write DMA channels %d to allocate are > %d\n",
__func__,
num_write_dma_channels,
AFE_MAX_WRDMA);
goto done;
}
result = afe_q6_interface_prepare();
if (result != 0) {
pr_err("%s: Q6 interface prepare failed %d\n",
__func__, result);
goto done;
}
memset(&config, 0, sizeof(config));
config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
APR_PKT_VER);
config.hdr.pkt_size = sizeof(config);
config.hdr.src_port = 0;
config.hdr.dest_port = 0;
config.hdr.token = IDX_GLOBAL_CFG;
config.hdr.opcode = AFE_CMD_REQUEST_LPASS_RESOURCES;
config.resources.resource_id = AFE_LPAIF_DMA_RESOURCE_ID;
/* Only AFE_LPAIF_DEFAULT_DMA_TYPE dma type is supported */
config.dma_resources.dma_type = dma_type;
config.dma_resources.num_read_dma_channels = num_read_dma_channels;
config.dma_resources.num_write_dma_channels = num_write_dma_channels;
result = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
if (result)
pr_err("%s: AFE_CMD_REQUEST_LPASS_RESOURCES failed %d\n",
__func__, result);
done:
return result;
}
EXPORT_SYMBOL(afe_request_dma_resources);
int afe_get_dma_idx(bool **ret_rddma_idx,
bool **ret_wrdma_idx)
{
int ret = 0;
if (!ret_rddma_idx || !ret_wrdma_idx) {
pr_err("%s: invalid return pointers.", __func__);
ret = -EINVAL;
goto done;
}
*ret_rddma_idx = &this_afe.alloced_rddma[0];
*ret_wrdma_idx = &this_afe.alloced_wrdma[0];
done:
return ret;
}
EXPORT_SYMBOL(afe_get_dma_idx);
int afe_release_all_dma_resources(void)
{
int result = 0;
int i, total_size;
struct afe_release_lpass_dma_resources_command *config;
uint8_t *payload;
pr_debug("%s:\n", __func__);
if ((this_afe.num_alloced_rddma == 0) &&
(this_afe.num_alloced_wrdma == 0)) {
pr_err("%s: DMA channels to release is 0",
__func__);
goto done;
}
result = afe_q6_interface_prepare();
if (result != 0) {
pr_err("%s: Q6 interface prepare failed %d\n",
__func__, result);
goto done;
}
total_size = sizeof(struct afe_release_lpass_dma_resources_command) +
sizeof(uint8_t) *
(this_afe.num_alloced_rddma + this_afe.num_alloced_wrdma);
config = kzalloc(total_size, GFP_KERNEL);
if (!config) {
result = -ENOMEM;
goto done;
}
memset(config, 0, total_size);
payload = (uint8_t *) config +
sizeof(struct afe_release_lpass_dma_resources_command);
config->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
APR_PKT_VER);
config->hdr.pkt_size = total_size;
config->hdr.src_port = 0;
config->hdr.dest_port = 0;
config->hdr.token = IDX_GLOBAL_CFG;
config->hdr.opcode = AFE_CMD_RELEASE_LPASS_RESOURCES;
config->resources.resource_id = AFE_LPAIF_DMA_RESOURCE_ID;
/* Only AFE_LPAIF_DEFAULT_DMA_TYPE dma type is supported */
config->dma_resources.dma_type = AFE_LPAIF_DEFAULT_DMA_TYPE;
config->dma_resources.num_read_dma_channels =
this_afe.num_alloced_rddma;
config->dma_resources.num_write_dma_channels =
this_afe.num_alloced_wrdma;
for (i = 0; i < AFE_MAX_RDDMA; i++) {
if (this_afe.alloced_rddma[i]) {
*payload = i;
payload++;
}
}
for (i = 0; i < AFE_MAX_WRDMA; i++) {
if (this_afe.alloced_wrdma[i]) {
*payload = i;
payload++;
}
}
result = afe_apr_send_pkt(config, &this_afe.wait[IDX_GLOBAL_CFG]);
if (result)
pr_err("%s: AFE_CMD_RELEASE_LPASS_RESOURCES failed %d\n",
__func__, result);
kfree(config);
done:
return result;
}
EXPORT_SYMBOL(afe_release_all_dma_resources);
static int __init afe_init(void)
{
int i = 0, ret;