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>
11 #include <linux/of_platform.h>
12 #include <linux/jiffies.h>
13 #include <linux/wait.h>
14 #include <linux/soc/qcom/apr.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
{
32 struct avcs_cmdrsp_get_version
{
34 uint32_t num_services
;
35 struct avcs_svc_info svc_api_info
[];
38 /* for ADSP2.8 and above */
39 struct avcs_svc_api_info
{
42 uint32_t api_branch_version
;
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
[];
55 struct apr_device
*adev
;
56 wait_queue_head_t wait
;
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;
87 case AVCS_CMD_GET_FWK_VERSION
:
88 if (result
->status
== ADSP_EUNSUPPORTED
)
89 core
->fwk_version_supported
= false;
90 core
->resp_received
= true;
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;
100 case AVCS_CMDRSP_GET_FWK_VERSION
: {
101 struct avcs_cmdrsp_get_fwk_version
*fwk
;
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
)
112 memcpy(core
->fwk_version
, data
->payload
, bytes
);
114 core
->fwk_version_supported
= true;
115 core
->resp_received
= true;
119 case AVCS_GET_VERSIONS_RSP
: {
120 struct avcs_cmdrsp_get_version
*v
;
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
)
131 memcpy(core
->svc_version
, data
->payload
, len
);
133 core
->get_version_supported
= true;
134 core
->resp_received
= true;
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;
145 dev_err(&adev
->dev
, "Message id from adsp core svc: 0x%x\n",
150 if (core
->resp_received
)
151 wake_up(&core
->wait
);
156 static int q6core_get_fwk_versions(struct q6core
*core
)
158 struct apr_device
*adev
= core
->adev
;
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
);
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
)
186 static int q6core_get_svc_versions(struct q6core
*core
)
188 struct apr_device
*adev
= core
->adev
;
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
);
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;
211 static bool __q6core_is_adsp_ready(struct q6core
*core
)
213 struct apr_device
*adev
= core
->adev
;
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
);
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
)
237 /* assume that the adsp is up if we not support this command */
238 if (!core
->get_state_supported
)
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
)
257 if (!g_core
|| !ainfo
)
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
)
275 ainfo
->api_version
= info
->api_version
;
276 ainfo
->api_branch_version
= info
->api_branch_version
;
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
)
288 ainfo
->api_version
= info
->version
;
289 ainfo
->api_branch_version
= 0;
295 mutex_unlock(&g_core
->lock
);
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
;
314 mutex_lock(&g_core
->lock
);
315 timeout
= jiffies
+ msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS
);
317 if (__q6core_is_adsp_ready(g_core
)) {
322 if (!time_after(timeout
, jiffies
)) {
328 mutex_unlock(&g_core
->lock
);
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
);
339 dev_set_drvdata(&adev
->dev
, g_core
);
341 mutex_init(&g_core
->lock
);
343 init_waitqueue_head(&g_core
->wait
);
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
);
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
,
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");