drm/i915: fix port checks for MST support on gen >= 11
[linux/fpc-iii.git] / sound / soc / qcom / qdsp6 / q6core.c
blob06f03a5fe9bd70e07b74343c63e93e5f1f50d309
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
3 // Copyright (c) 2018, Linaro Limited
5 #include <linux/slab.h>
6 #include <linux/wait.h>
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/sched.h>
10 #include <linux/of.h>
11 #include <linux/of_platform.h>
12 #include <linux/jiffies.h>
13 #include <linux/wait.h>
14 #include <linux/soc/qcom/apr.h>
15 #include "q6core.h"
16 #include "q6dsp-errno.h"
18 #define ADSP_STATE_READY_TIMEOUT_MS 3000
19 #define Q6_READY_TIMEOUT_MS 100
20 #define AVCS_CMD_ADSP_EVENT_GET_STATE 0x0001290C
21 #define AVCS_CMDRSP_ADSP_EVENT_GET_STATE 0x0001290D
22 #define AVCS_GET_VERSIONS 0x00012905
23 #define AVCS_GET_VERSIONS_RSP 0x00012906
24 #define AVCS_CMD_GET_FWK_VERSION 0x001292c
25 #define AVCS_CMDRSP_GET_FWK_VERSION 0x001292d
27 struct avcs_svc_info {
28 uint32_t service_id;
29 uint32_t version;
30 } __packed;
32 struct avcs_cmdrsp_get_version {
33 uint32_t build_id;
34 uint32_t num_services;
35 struct avcs_svc_info svc_api_info[];
36 } __packed;
38 /* for ADSP2.8 and above */
39 struct avcs_svc_api_info {
40 uint32_t service_id;
41 uint32_t api_version;
42 uint32_t api_branch_version;
43 } __packed;
45 struct avcs_cmdrsp_get_fwk_version {
46 uint32_t build_major_version;
47 uint32_t build_minor_version;
48 uint32_t build_branch_version;
49 uint32_t build_subbranch_version;
50 uint32_t num_services;
51 struct avcs_svc_api_info svc_api_info[];
52 } __packed;
54 struct q6core {
55 struct apr_device *adev;
56 wait_queue_head_t wait;
57 uint32_t avcs_state;
58 struct mutex lock;
59 bool resp_received;
60 uint32_t num_services;
61 struct avcs_cmdrsp_get_fwk_version *fwk_version;
62 struct avcs_cmdrsp_get_version *svc_version;
63 bool fwk_version_supported;
64 bool get_state_supported;
65 bool get_version_supported;
66 bool is_version_requested;
69 static struct q6core *g_core;
71 static int q6core_callback(struct apr_device *adev, struct apr_resp_pkt *data)
73 struct q6core *core = dev_get_drvdata(&adev->dev);
74 struct aprv2_ibasic_rsp_result_t *result;
75 struct apr_hdr *hdr = &data->hdr;
77 result = data->payload;
78 switch (hdr->opcode) {
79 case APR_BASIC_RSP_RESULT:{
80 result = data->payload;
81 switch (result->opcode) {
82 case AVCS_GET_VERSIONS:
83 if (result->status == ADSP_EUNSUPPORTED)
84 core->get_version_supported = false;
85 core->resp_received = true;
86 break;
87 case AVCS_CMD_GET_FWK_VERSION:
88 if (result->status == ADSP_EUNSUPPORTED)
89 core->fwk_version_supported = false;
90 core->resp_received = true;
91 break;
92 case AVCS_CMD_ADSP_EVENT_GET_STATE:
93 if (result->status == ADSP_EUNSUPPORTED)
94 core->get_state_supported = false;
95 core->resp_received = true;
96 break;
98 break;
100 case AVCS_CMDRSP_GET_FWK_VERSION: {
101 struct avcs_cmdrsp_get_fwk_version *fwk;
102 int bytes;
104 fwk = data->payload;
105 bytes = sizeof(*fwk) + fwk->num_services *
106 sizeof(fwk->svc_api_info[0]);
108 core->fwk_version = kzalloc(bytes, GFP_ATOMIC);
109 if (!core->fwk_version)
110 return -ENOMEM;
112 memcpy(core->fwk_version, data->payload, bytes);
114 core->fwk_version_supported = true;
115 core->resp_received = true;
117 break;
119 case AVCS_GET_VERSIONS_RSP: {
120 struct avcs_cmdrsp_get_version *v;
121 int len;
123 v = data->payload;
125 len = sizeof(*v) + v->num_services * sizeof(v->svc_api_info[0]);
127 core->svc_version = kzalloc(len, GFP_ATOMIC);
128 if (!core->svc_version)
129 return -ENOMEM;
131 memcpy(core->svc_version, data->payload, len);
133 core->get_version_supported = true;
134 core->resp_received = true;
136 break;
138 case AVCS_CMDRSP_ADSP_EVENT_GET_STATE:
139 core->get_state_supported = true;
140 core->avcs_state = result->opcode;
142 core->resp_received = true;
143 break;
144 default:
145 dev_err(&adev->dev, "Message id from adsp core svc: 0x%x\n",
146 hdr->opcode);
147 break;
150 if (core->resp_received)
151 wake_up(&core->wait);
153 return 0;
156 static int q6core_get_fwk_versions(struct q6core *core)
158 struct apr_device *adev = core->adev;
159 struct apr_pkt pkt;
160 int rc;
162 pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
163 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
164 pkt.hdr.pkt_size = APR_HDR_SIZE;
165 pkt.hdr.opcode = AVCS_CMD_GET_FWK_VERSION;
167 rc = apr_send_pkt(adev, &pkt);
168 if (rc < 0)
169 return rc;
171 rc = wait_event_timeout(core->wait, (core->resp_received),
172 msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
173 if (rc > 0 && core->resp_received) {
174 core->resp_received = false;
176 if (!core->fwk_version_supported)
177 return -ENOTSUPP;
178 else
179 return 0;
183 return rc;
186 static int q6core_get_svc_versions(struct q6core *core)
188 struct apr_device *adev = core->adev;
189 struct apr_pkt pkt;
190 int rc;
192 pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
193 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
194 pkt.hdr.pkt_size = APR_HDR_SIZE;
195 pkt.hdr.opcode = AVCS_GET_VERSIONS;
197 rc = apr_send_pkt(adev, &pkt);
198 if (rc < 0)
199 return rc;
201 rc = wait_event_timeout(core->wait, (core->resp_received),
202 msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
203 if (rc > 0 && core->resp_received) {
204 core->resp_received = false;
205 return 0;
208 return rc;
211 static bool __q6core_is_adsp_ready(struct q6core *core)
213 struct apr_device *adev = core->adev;
214 struct apr_pkt pkt;
215 int rc;
217 core->get_state_supported = false;
219 pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
220 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
221 pkt.hdr.pkt_size = APR_HDR_SIZE;
222 pkt.hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE;
224 rc = apr_send_pkt(adev, &pkt);
225 if (rc < 0)
226 return false;
228 rc = wait_event_timeout(core->wait, (core->resp_received),
229 msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
230 if (rc > 0 && core->resp_received) {
231 core->resp_received = false;
233 if (core->avcs_state)
234 return true;
237 /* assume that the adsp is up if we not support this command */
238 if (!core->get_state_supported)
239 return true;
241 return false;
245 * q6core_get_svc_api_info() - Get version number of a service.
247 * @svc_id: service id of the service.
248 * @ainfo: Valid struct pointer to fill svc api information.
250 * Return: zero on success and error code on failure or unsupported
252 int q6core_get_svc_api_info(int svc_id, struct q6core_svc_api_info *ainfo)
254 int i;
255 int ret = -ENOTSUPP;
257 if (!g_core || !ainfo)
258 return 0;
260 mutex_lock(&g_core->lock);
261 if (!g_core->is_version_requested) {
262 if (q6core_get_fwk_versions(g_core) == -ENOTSUPP)
263 q6core_get_svc_versions(g_core);
264 g_core->is_version_requested = true;
267 if (g_core->fwk_version_supported) {
268 for (i = 0; i < g_core->fwk_version->num_services; i++) {
269 struct avcs_svc_api_info *info;
271 info = &g_core->fwk_version->svc_api_info[i];
272 if (svc_id != info->service_id)
273 continue;
275 ainfo->api_version = info->api_version;
276 ainfo->api_branch_version = info->api_branch_version;
277 ret = 0;
278 break;
280 } else if (g_core->get_version_supported) {
281 for (i = 0; i < g_core->svc_version->num_services; i++) {
282 struct avcs_svc_info *info;
284 info = &g_core->svc_version->svc_api_info[i];
285 if (svc_id != info->service_id)
286 continue;
288 ainfo->api_version = info->version;
289 ainfo->api_branch_version = 0;
290 ret = 0;
291 break;
295 mutex_unlock(&g_core->lock);
297 return ret;
299 EXPORT_SYMBOL_GPL(q6core_get_svc_api_info);
302 * q6core_is_adsp_ready() - Get status of adsp
304 * Return: Will be an true if adsp is ready and false if not.
306 bool q6core_is_adsp_ready(void)
308 unsigned long timeout;
309 bool ret = false;
311 if (!g_core)
312 return false;
314 mutex_lock(&g_core->lock);
315 timeout = jiffies + msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
316 for (;;) {
317 if (__q6core_is_adsp_ready(g_core)) {
318 ret = true;
319 break;
322 if (!time_after(timeout, jiffies)) {
323 ret = false;
324 break;
328 mutex_unlock(&g_core->lock);
329 return ret;
331 EXPORT_SYMBOL_GPL(q6core_is_adsp_ready);
333 static int q6core_probe(struct apr_device *adev)
335 g_core = kzalloc(sizeof(*g_core), GFP_KERNEL);
336 if (!g_core)
337 return -ENOMEM;
339 dev_set_drvdata(&adev->dev, g_core);
341 mutex_init(&g_core->lock);
342 g_core->adev = adev;
343 init_waitqueue_head(&g_core->wait);
344 return 0;
347 static int q6core_exit(struct apr_device *adev)
349 struct q6core *core = dev_get_drvdata(&adev->dev);
351 if (core->fwk_version_supported)
352 kfree(core->fwk_version);
353 if (core->get_version_supported)
354 kfree(core->svc_version);
356 g_core = NULL;
357 kfree(core);
359 return 0;
362 static const struct of_device_id q6core_device_id[] = {
363 { .compatible = "qcom,q6core" },
366 MODULE_DEVICE_TABLE(of, q6core_device_id);
368 static struct apr_driver qcom_q6core_driver = {
369 .probe = q6core_probe,
370 .remove = q6core_exit,
371 .callback = q6core_callback,
372 .driver = {
373 .name = "qcom-q6core",
374 .of_match_table = of_match_ptr(q6core_device_id),
378 module_apr_driver(qcom_q6core_driver);
379 MODULE_DESCRIPTION("q6 core");
380 MODULE_LICENSE("GPL v2");