brintos

brintos / linux-shallow public Read only

0
0
Text · 8.4 KiB · 49cfb32 Raw
376 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.3// Copyright (c) 2018, Linaro Limited4 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/soc/qcom/apr.h>14#include "q6core.h"15#include "q6dsp-errno.h"16 17#define ADSP_STATE_READY_TIMEOUT_MS    300018#define Q6_READY_TIMEOUT_MS 10019#define AVCS_CMD_ADSP_EVENT_GET_STATE		0x0001290C20#define AVCS_CMDRSP_ADSP_EVENT_GET_STATE	0x0001290D21#define AVCS_GET_VERSIONS       0x0001290522#define AVCS_GET_VERSIONS_RSP   0x0001290623#define AVCS_CMD_GET_FWK_VERSION	0x001292c24#define AVCS_CMDRSP_GET_FWK_VERSION	0x001292d25 26struct avcs_svc_info {27	uint32_t service_id;28	uint32_t version;29} __packed;30 31struct avcs_cmdrsp_get_version {32	uint32_t build_id;33	uint32_t num_services;34	struct avcs_svc_info svc_api_info[];35} __packed;36 37/* for ADSP2.8 and above */38struct avcs_svc_api_info {39	uint32_t service_id;40	uint32_t api_version;41	uint32_t api_branch_version;42} __packed;43 44struct avcs_cmdrsp_get_fwk_version {45	uint32_t build_major_version;46	uint32_t build_minor_version;47	uint32_t build_branch_version;48	uint32_t build_subbranch_version;49	uint32_t num_services;50	struct avcs_svc_api_info svc_api_info[];51} __packed;52 53struct q6core {54	struct apr_device *adev;55	wait_queue_head_t wait;56	uint32_t avcs_state;57	struct mutex lock;58	bool resp_received;59	uint32_t num_services;60	struct avcs_cmdrsp_get_fwk_version *fwk_version;61	struct avcs_cmdrsp_get_version *svc_version;62	bool fwk_version_supported;63	bool get_state_supported;64	bool get_version_supported;65	bool is_version_requested;66};67 68static struct q6core *g_core;69 70static int q6core_callback(struct apr_device *adev, struct apr_resp_pkt *data)71{72	struct q6core *core = dev_get_drvdata(&adev->dev);73	struct aprv2_ibasic_rsp_result_t *result;74	struct apr_hdr *hdr = &data->hdr;75 76	result = data->payload;77	switch (hdr->opcode) {78	case APR_BASIC_RSP_RESULT:{79		result = data->payload;80		switch (result->opcode) {81		case AVCS_GET_VERSIONS:82			if (result->status == ADSP_EUNSUPPORTED)83				core->get_version_supported = false;84			core->resp_received = true;85			break;86		case AVCS_CMD_GET_FWK_VERSION:87			if (result->status == ADSP_EUNSUPPORTED)88				core->fwk_version_supported = false;89			core->resp_received = true;90			break;91		case AVCS_CMD_ADSP_EVENT_GET_STATE:92			if (result->status == ADSP_EUNSUPPORTED)93				core->get_state_supported = false;94			core->resp_received = true;95			break;96		}97		break;98	}99	case AVCS_CMDRSP_GET_FWK_VERSION: {100		struct avcs_cmdrsp_get_fwk_version *fwk;101 102		fwk = data->payload;103 104		core->fwk_version = kmemdup(data->payload,105					    struct_size(fwk, svc_api_info,106							fwk->num_services),107					    GFP_ATOMIC);108		if (!core->fwk_version)109			return -ENOMEM;110 111		core->fwk_version_supported = true;112		core->resp_received = true;113 114		break;115	}116	case AVCS_GET_VERSIONS_RSP: {117		struct avcs_cmdrsp_get_version *v;118 119		v = data->payload;120 121		core->svc_version = kmemdup(data->payload,122					    struct_size(v, svc_api_info,123							v->num_services),124					    GFP_ATOMIC);125		if (!core->svc_version)126			return -ENOMEM;127 128		core->get_version_supported = true;129		core->resp_received = true;130 131		break;132	}133	case AVCS_CMDRSP_ADSP_EVENT_GET_STATE:134		core->get_state_supported = true;135		core->avcs_state = result->opcode;136 137		core->resp_received = true;138		break;139	default:140		dev_err(&adev->dev, "Message id from adsp core svc: 0x%x\n",141			hdr->opcode);142		break;143	}144 145	if (core->resp_received)146		wake_up(&core->wait);147 148	return 0;149}150 151static int q6core_get_fwk_versions(struct q6core *core)152{153	struct apr_device *adev = core->adev;154	struct apr_pkt pkt;155	int rc;156 157	pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,158				      APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);159	pkt.hdr.pkt_size = APR_HDR_SIZE;160	pkt.hdr.opcode = AVCS_CMD_GET_FWK_VERSION;161 162	rc = apr_send_pkt(adev, &pkt);163	if (rc < 0)164		return rc;165 166	rc = wait_event_timeout(core->wait, (core->resp_received),167				msecs_to_jiffies(Q6_READY_TIMEOUT_MS));168	if (rc > 0 && core->resp_received) {169		core->resp_received = false;170 171		if (!core->fwk_version_supported)172			return -ENOTSUPP;173		else174			return 0;175	}176 177 178	return rc;179}180 181static int q6core_get_svc_versions(struct q6core *core)182{183	struct apr_device *adev = core->adev;184	struct apr_pkt pkt;185	int rc;186 187	pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,188				      APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);189	pkt.hdr.pkt_size = APR_HDR_SIZE;190	pkt.hdr.opcode = AVCS_GET_VERSIONS;191 192	rc = apr_send_pkt(adev, &pkt);193	if (rc < 0)194		return rc;195 196	rc = wait_event_timeout(core->wait, (core->resp_received),197				msecs_to_jiffies(Q6_READY_TIMEOUT_MS));198	if (rc > 0 && core->resp_received) {199		core->resp_received = false;200		return 0;201	}202 203	return rc;204}205 206static bool __q6core_is_adsp_ready(struct q6core *core)207{208	struct apr_device *adev = core->adev;209	struct apr_pkt pkt;210	int rc;211 212	core->get_state_supported = false;213 214	pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,215				      APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);216	pkt.hdr.pkt_size = APR_HDR_SIZE;217	pkt.hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE;218 219	rc = apr_send_pkt(adev, &pkt);220	if (rc < 0)221		return false;222 223	rc = wait_event_timeout(core->wait, (core->resp_received),224				msecs_to_jiffies(Q6_READY_TIMEOUT_MS));225	if (rc > 0 && core->resp_received) {226		core->resp_received = false;227 228		if (core->avcs_state)229			return true;230	}231 232	/* assume that the adsp is up if we not support this command */233	if (!core->get_state_supported)234		return true;235 236	return false;237}238 239/**240 * q6core_get_svc_api_info() - Get version number of a service.241 *242 * @svc_id: service id of the service.243 * @ainfo: Valid struct pointer to fill svc api information.244 *245 * Return: zero on success and error code on failure or unsupported246 */247int q6core_get_svc_api_info(int svc_id, struct q6core_svc_api_info *ainfo)248{249	int i;250	int ret = -ENOTSUPP;251 252	if (!g_core || !ainfo)253		return 0;254 255	mutex_lock(&g_core->lock);256	if (!g_core->is_version_requested) {257		if (q6core_get_fwk_versions(g_core) == -ENOTSUPP)258			q6core_get_svc_versions(g_core);259		g_core->is_version_requested = true;260	}261 262	if (g_core->fwk_version_supported) {263		for (i = 0; i < g_core->fwk_version->num_services; i++) {264			struct avcs_svc_api_info *info;265 266			info = &g_core->fwk_version->svc_api_info[i];267			if (svc_id != info->service_id)268				continue;269 270			ainfo->api_version = info->api_version;271			ainfo->api_branch_version = info->api_branch_version;272			ret = 0;273			break;274		}275	} else if (g_core->get_version_supported) {276		for (i = 0; i < g_core->svc_version->num_services; i++) {277			struct avcs_svc_info *info;278 279			info = &g_core->svc_version->svc_api_info[i];280			if (svc_id != info->service_id)281				continue;282 283			ainfo->api_version = info->version;284			ainfo->api_branch_version = 0;285			ret = 0;286			break;287		}288	}289 290	mutex_unlock(&g_core->lock);291 292	return ret;293}294EXPORT_SYMBOL_GPL(q6core_get_svc_api_info);295 296/**297 * q6core_is_adsp_ready() - Get status of adsp298 *299 * Return: Will be an true if adsp is ready and false if not.300 */301bool q6core_is_adsp_ready(void)302{303	unsigned long  timeout;304	bool ret = false;305 306	if (!g_core)307		return false;308 309	mutex_lock(&g_core->lock);310	timeout = jiffies + msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);311	for (;;) {312		if (__q6core_is_adsp_ready(g_core)) {313			ret = true;314			break;315		}316 317		if (!time_after(timeout, jiffies)) {318			ret = false;319			break;320		}321	}322 323	mutex_unlock(&g_core->lock);324	return ret;325}326EXPORT_SYMBOL_GPL(q6core_is_adsp_ready);327 328static int q6core_probe(struct apr_device *adev)329{330	g_core = kzalloc(sizeof(*g_core), GFP_KERNEL);331	if (!g_core)332		return -ENOMEM;333 334	dev_set_drvdata(&adev->dev, g_core);335 336	mutex_init(&g_core->lock);337	g_core->adev = adev;338	init_waitqueue_head(&g_core->wait);339	return 0;340}341 342static void q6core_exit(struct apr_device *adev)343{344	struct q6core *core = dev_get_drvdata(&adev->dev);345 346	if (core->fwk_version_supported)347		kfree(core->fwk_version);348	if (core->get_version_supported)349		kfree(core->svc_version);350 351	g_core = NULL;352	kfree(core);353}354 355#ifdef CONFIG_OF356static const struct of_device_id q6core_device_id[]  = {357	{ .compatible = "qcom,q6core" },358	{},359};360MODULE_DEVICE_TABLE(of, q6core_device_id);361#endif362 363static struct apr_driver qcom_q6core_driver = {364	.probe = q6core_probe,365	.remove = q6core_exit,366	.callback = q6core_callback,367	.driver = {368		.name = "qcom-q6core",369		.of_match_table = of_match_ptr(q6core_device_id),370	},371};372 373module_apr_driver(qcom_q6core_driver);374MODULE_DESCRIPTION("q6 core");375MODULE_LICENSE("GPL v2");376