0001
0002
0003
0004
0005 #include <linux/slab.h>
0006 #include <linux/wait.h>
0007 #include <linux/kernel.h>
0008 #include <linux/module.h>
0009 #include <linux/sched.h>
0010 #include <linux/of.h>
0011 #include <linux/of_platform.h>
0012 #include <linux/jiffies.h>
0013 #include <linux/soc/qcom/apr.h>
0014 #include "q6core.h"
0015 #include "q6dsp-errno.h"
0016
0017 #define ADSP_STATE_READY_TIMEOUT_MS 3000
0018 #define Q6_READY_TIMEOUT_MS 100
0019 #define AVCS_CMD_ADSP_EVENT_GET_STATE 0x0001290C
0020 #define AVCS_CMDRSP_ADSP_EVENT_GET_STATE 0x0001290D
0021 #define AVCS_GET_VERSIONS 0x00012905
0022 #define AVCS_GET_VERSIONS_RSP 0x00012906
0023 #define AVCS_CMD_GET_FWK_VERSION 0x001292c
0024 #define AVCS_CMDRSP_GET_FWK_VERSION 0x001292d
0025
0026 struct avcs_svc_info {
0027 uint32_t service_id;
0028 uint32_t version;
0029 } __packed;
0030
0031 struct avcs_cmdrsp_get_version {
0032 uint32_t build_id;
0033 uint32_t num_services;
0034 struct avcs_svc_info svc_api_info[];
0035 } __packed;
0036
0037
0038 struct avcs_svc_api_info {
0039 uint32_t service_id;
0040 uint32_t api_version;
0041 uint32_t api_branch_version;
0042 } __packed;
0043
0044 struct avcs_cmdrsp_get_fwk_version {
0045 uint32_t build_major_version;
0046 uint32_t build_minor_version;
0047 uint32_t build_branch_version;
0048 uint32_t build_subbranch_version;
0049 uint32_t num_services;
0050 struct avcs_svc_api_info svc_api_info[];
0051 } __packed;
0052
0053 struct q6core {
0054 struct apr_device *adev;
0055 wait_queue_head_t wait;
0056 uint32_t avcs_state;
0057 struct mutex lock;
0058 bool resp_received;
0059 uint32_t num_services;
0060 struct avcs_cmdrsp_get_fwk_version *fwk_version;
0061 struct avcs_cmdrsp_get_version *svc_version;
0062 bool fwk_version_supported;
0063 bool get_state_supported;
0064 bool get_version_supported;
0065 bool is_version_requested;
0066 };
0067
0068 static struct q6core *g_core;
0069
0070 static int q6core_callback(struct apr_device *adev, struct apr_resp_pkt *data)
0071 {
0072 struct q6core *core = dev_get_drvdata(&adev->dev);
0073 struct aprv2_ibasic_rsp_result_t *result;
0074 struct apr_hdr *hdr = &data->hdr;
0075
0076 result = data->payload;
0077 switch (hdr->opcode) {
0078 case APR_BASIC_RSP_RESULT:{
0079 result = data->payload;
0080 switch (result->opcode) {
0081 case AVCS_GET_VERSIONS:
0082 if (result->status == ADSP_EUNSUPPORTED)
0083 core->get_version_supported = false;
0084 core->resp_received = true;
0085 break;
0086 case AVCS_CMD_GET_FWK_VERSION:
0087 if (result->status == ADSP_EUNSUPPORTED)
0088 core->fwk_version_supported = false;
0089 core->resp_received = true;
0090 break;
0091 case AVCS_CMD_ADSP_EVENT_GET_STATE:
0092 if (result->status == ADSP_EUNSUPPORTED)
0093 core->get_state_supported = false;
0094 core->resp_received = true;
0095 break;
0096 }
0097 break;
0098 }
0099 case AVCS_CMDRSP_GET_FWK_VERSION: {
0100 struct avcs_cmdrsp_get_fwk_version *fwk;
0101
0102 fwk = data->payload;
0103
0104 core->fwk_version = kmemdup(data->payload,
0105 struct_size(fwk, svc_api_info,
0106 fwk->num_services),
0107 GFP_ATOMIC);
0108 if (!core->fwk_version)
0109 return -ENOMEM;
0110
0111 core->fwk_version_supported = true;
0112 core->resp_received = true;
0113
0114 break;
0115 }
0116 case AVCS_GET_VERSIONS_RSP: {
0117 struct avcs_cmdrsp_get_version *v;
0118
0119 v = data->payload;
0120
0121 core->svc_version = kmemdup(data->payload,
0122 struct_size(v, svc_api_info,
0123 v->num_services),
0124 GFP_ATOMIC);
0125 if (!core->svc_version)
0126 return -ENOMEM;
0127
0128 core->get_version_supported = true;
0129 core->resp_received = true;
0130
0131 break;
0132 }
0133 case AVCS_CMDRSP_ADSP_EVENT_GET_STATE:
0134 core->get_state_supported = true;
0135 core->avcs_state = result->opcode;
0136
0137 core->resp_received = true;
0138 break;
0139 default:
0140 dev_err(&adev->dev, "Message id from adsp core svc: 0x%x\n",
0141 hdr->opcode);
0142 break;
0143 }
0144
0145 if (core->resp_received)
0146 wake_up(&core->wait);
0147
0148 return 0;
0149 }
0150
0151 static int q6core_get_fwk_versions(struct q6core *core)
0152 {
0153 struct apr_device *adev = core->adev;
0154 struct apr_pkt pkt;
0155 int rc;
0156
0157 pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
0158 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
0159 pkt.hdr.pkt_size = APR_HDR_SIZE;
0160 pkt.hdr.opcode = AVCS_CMD_GET_FWK_VERSION;
0161
0162 rc = apr_send_pkt(adev, &pkt);
0163 if (rc < 0)
0164 return rc;
0165
0166 rc = wait_event_timeout(core->wait, (core->resp_received),
0167 msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
0168 if (rc > 0 && core->resp_received) {
0169 core->resp_received = false;
0170
0171 if (!core->fwk_version_supported)
0172 return -ENOTSUPP;
0173 else
0174 return 0;
0175 }
0176
0177
0178 return rc;
0179 }
0180
0181 static int q6core_get_svc_versions(struct q6core *core)
0182 {
0183 struct apr_device *adev = core->adev;
0184 struct apr_pkt pkt;
0185 int rc;
0186
0187 pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
0188 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
0189 pkt.hdr.pkt_size = APR_HDR_SIZE;
0190 pkt.hdr.opcode = AVCS_GET_VERSIONS;
0191
0192 rc = apr_send_pkt(adev, &pkt);
0193 if (rc < 0)
0194 return rc;
0195
0196 rc = wait_event_timeout(core->wait, (core->resp_received),
0197 msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
0198 if (rc > 0 && core->resp_received) {
0199 core->resp_received = false;
0200 return 0;
0201 }
0202
0203 return rc;
0204 }
0205
0206 static bool __q6core_is_adsp_ready(struct q6core *core)
0207 {
0208 struct apr_device *adev = core->adev;
0209 struct apr_pkt pkt;
0210 int rc;
0211
0212 core->get_state_supported = false;
0213
0214 pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
0215 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
0216 pkt.hdr.pkt_size = APR_HDR_SIZE;
0217 pkt.hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE;
0218
0219 rc = apr_send_pkt(adev, &pkt);
0220 if (rc < 0)
0221 return false;
0222
0223 rc = wait_event_timeout(core->wait, (core->resp_received),
0224 msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
0225 if (rc > 0 && core->resp_received) {
0226 core->resp_received = false;
0227
0228 if (core->avcs_state)
0229 return true;
0230 }
0231
0232
0233 if (!core->get_state_supported)
0234 return true;
0235
0236 return false;
0237 }
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247 int q6core_get_svc_api_info(int svc_id, struct q6core_svc_api_info *ainfo)
0248 {
0249 int i;
0250 int ret = -ENOTSUPP;
0251
0252 if (!g_core || !ainfo)
0253 return 0;
0254
0255 mutex_lock(&g_core->lock);
0256 if (!g_core->is_version_requested) {
0257 if (q6core_get_fwk_versions(g_core) == -ENOTSUPP)
0258 q6core_get_svc_versions(g_core);
0259 g_core->is_version_requested = true;
0260 }
0261
0262 if (g_core->fwk_version_supported) {
0263 for (i = 0; i < g_core->fwk_version->num_services; i++) {
0264 struct avcs_svc_api_info *info;
0265
0266 info = &g_core->fwk_version->svc_api_info[i];
0267 if (svc_id != info->service_id)
0268 continue;
0269
0270 ainfo->api_version = info->api_version;
0271 ainfo->api_branch_version = info->api_branch_version;
0272 ret = 0;
0273 break;
0274 }
0275 } else if (g_core->get_version_supported) {
0276 for (i = 0; i < g_core->svc_version->num_services; i++) {
0277 struct avcs_svc_info *info;
0278
0279 info = &g_core->svc_version->svc_api_info[i];
0280 if (svc_id != info->service_id)
0281 continue;
0282
0283 ainfo->api_version = info->version;
0284 ainfo->api_branch_version = 0;
0285 ret = 0;
0286 break;
0287 }
0288 }
0289
0290 mutex_unlock(&g_core->lock);
0291
0292 return ret;
0293 }
0294 EXPORT_SYMBOL_GPL(q6core_get_svc_api_info);
0295
0296
0297
0298
0299
0300
0301 bool q6core_is_adsp_ready(void)
0302 {
0303 unsigned long timeout;
0304 bool ret = false;
0305
0306 if (!g_core)
0307 return false;
0308
0309 mutex_lock(&g_core->lock);
0310 timeout = jiffies + msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
0311 for (;;) {
0312 if (__q6core_is_adsp_ready(g_core)) {
0313 ret = true;
0314 break;
0315 }
0316
0317 if (!time_after(timeout, jiffies)) {
0318 ret = false;
0319 break;
0320 }
0321 }
0322
0323 mutex_unlock(&g_core->lock);
0324 return ret;
0325 }
0326 EXPORT_SYMBOL_GPL(q6core_is_adsp_ready);
0327
0328 static int q6core_probe(struct apr_device *adev)
0329 {
0330 g_core = kzalloc(sizeof(*g_core), GFP_KERNEL);
0331 if (!g_core)
0332 return -ENOMEM;
0333
0334 dev_set_drvdata(&adev->dev, g_core);
0335
0336 mutex_init(&g_core->lock);
0337 g_core->adev = adev;
0338 init_waitqueue_head(&g_core->wait);
0339 return 0;
0340 }
0341
0342 static int q6core_exit(struct apr_device *adev)
0343 {
0344 struct q6core *core = dev_get_drvdata(&adev->dev);
0345
0346 if (core->fwk_version_supported)
0347 kfree(core->fwk_version);
0348 if (core->get_version_supported)
0349 kfree(core->svc_version);
0350
0351 g_core = NULL;
0352 kfree(core);
0353
0354 return 0;
0355 }
0356
0357 #ifdef CONFIG_OF
0358 static const struct of_device_id q6core_device_id[] = {
0359 { .compatible = "qcom,q6core" },
0360 {},
0361 };
0362 MODULE_DEVICE_TABLE(of, q6core_device_id);
0363 #endif
0364
0365 static struct apr_driver qcom_q6core_driver = {
0366 .probe = q6core_probe,
0367 .remove = q6core_exit,
0368 .callback = q6core_callback,
0369 .driver = {
0370 .name = "qcom-q6core",
0371 .of_match_table = of_match_ptr(q6core_device_id),
0372 },
0373 };
0374
0375 module_apr_driver(qcom_q6core_driver);
0376 MODULE_DESCRIPTION("q6 core");
0377 MODULE_LICENSE("GPL v2");