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.
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];
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) {
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;
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;
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]);
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;