blob: f27c63ba0401092ef68e8f6ee56e2e44cd9ef456 [file] [log] [blame]
Banajit Goswamiaec1b462016-11-21 21:54:23 -08001/*
2 * Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/fs.h>
18#include <linux/cdev.h>
19#include <linux/uaccess.h>
20#include <linux/device.h>
21#include <linux/io.h>
22#include <linux/platform_device.h>
23#include <linux/avtimer.h>
24#include <linux/slab.h>
25#include <linux/of.h>
26#include <linux/wait.h>
27#include <linux/sched.h>
28#include <linux/qdsp6v2/apr.h>
29#include <sound/q6core.h>
30
31#define DEVICE_NAME "avtimer"
32#define TIMEOUT_MS 1000
33#define CORE_CLIENT 1
34#define TEMP_PORT ((CORE_CLIENT << 8) | 0x0001)
35#define SSR_WAKETIME 1000
36#define Q6_READY_RETRY 250
37#define Q6_READY_MAX_RETRIES 40
38
39#define AVCS_CMD_REMOTE_AVTIMER_VOTE_REQUEST 0x00012914
40#define AVCS_CMD_RSP_REMOTE_AVTIMER_VOTE_REQUEST 0x00012915
41#define AVCS_CMD_REMOTE_AVTIMER_RELEASE_REQUEST 0x00012916
42#define AVTIMER_REG_CNT 2
43
44struct adsp_avt_timer {
45 struct apr_hdr hdr;
46 union {
47 char client_name[8];
48 u32 avtimer_handle;
49 };
50} __packed;
51
52static int major;
53
54struct avtimer_t {
55 struct apr_svc *core_handle_q;
56 struct cdev myc;
57 struct class *avtimer_class;
58 struct mutex avtimer_lock;
59 int avtimer_open_cnt;
60 struct delayed_work ssr_dwork;
61 wait_queue_head_t adsp_resp_wait;
62 int enable_timer_resp_received;
63 int timer_handle;
64 void __iomem *p_avtimer_msw;
65 void __iomem *p_avtimer_lsw;
66 uint32_t clk_div;
67 atomic_t adsp_ready;
68 int num_retries;
69};
70
71static struct avtimer_t avtimer;
72
73static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
74{
75 uint32_t *payload1;
76
77 if (!data) {
78 pr_err("%s: Invalid params\n", __func__);
79 return -EINVAL;
80 }
81 pr_debug("%s: core msg: payload len = %u, apr resp opcode = 0x%X\n",
82 __func__, data->payload_size, data->opcode);
83
84 switch (data->opcode) {
85
86 case APR_BASIC_RSP_RESULT:{
87
88 if (!data->payload_size) {
89 pr_err("%s: APR_BASIC_RSP_RESULT No Payload ",
90 __func__);
91 return 0;
92 }
93
94 payload1 = data->payload;
95 switch (payload1[0]) {
96 case AVCS_CMD_REMOTE_AVTIMER_RELEASE_REQUEST:
97 pr_debug("%s: Cmd = TIMER RELEASE status[0x%x]\n",
98 __func__, payload1[1]);
99 break;
100 default:
101 pr_err("Invalid cmd rsp[0x%x][0x%x]\n",
102 payload1[0], payload1[1]);
103 break;
104 }
105 break;
106 }
107
108 case RESET_EVENTS:{
109 pr_debug("%s: Reset event received in AV timer\n", __func__);
110 apr_reset(avtimer.core_handle_q);
111 avtimer.core_handle_q = NULL;
112 avtimer.avtimer_open_cnt = 0;
113 atomic_set(&avtimer.adsp_ready, 0);
114 schedule_delayed_work(&avtimer.ssr_dwork,
115 msecs_to_jiffies(SSR_WAKETIME));
116 break;
117 }
118
119 case AVCS_CMD_RSP_REMOTE_AVTIMER_VOTE_REQUEST:
120 payload1 = data->payload;
121 pr_debug("%s: RSP_REMOTE_AVTIMER_VOTE_REQUEST handle %x\n",
122 __func__, payload1[0]);
123 avtimer.timer_handle = payload1[0];
124 avtimer.enable_timer_resp_received = 1;
125 wake_up(&avtimer.adsp_resp_wait);
126 break;
127 default:
128 pr_err("%s: Message adspcore svc: %d\n",
129 __func__, data->opcode);
130 break;
131 }
132
133 return 0;
134}
135
136int avcs_core_open(void)
137{
138 if (!avtimer.core_handle_q)
139 avtimer.core_handle_q = apr_register("ADSP", "CORE",
140 aprv2_core_fn_q, TEMP_PORT, NULL);
141 pr_debug("%s: Open_q %p\n", __func__, avtimer.core_handle_q);
142 if (!avtimer.core_handle_q) {
143 pr_err("%s: Unable to register CORE\n", __func__);
144 return -EINVAL;
145 }
146 return 0;
147}
148EXPORT_SYMBOL(avcs_core_open);
149
150static int avcs_core_disable_avtimer(int timerhandle)
151{
152 int rc = -EINVAL;
153 struct adsp_avt_timer payload;
154
155 if (!timerhandle) {
156 pr_err("%s: Invalid timer handle\n", __func__);
157 return -EINVAL;
158 }
159 memset(&payload, 0, sizeof(payload));
160 rc = avcs_core_open();
161 if (!rc && avtimer.core_handle_q) {
162 payload.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
163 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
164 payload.hdr.pkt_size =
165 sizeof(struct adsp_avt_timer);
166 payload.hdr.src_svc = avtimer.core_handle_q->id;
167 payload.hdr.src_domain = APR_DOMAIN_APPS;
168 payload.hdr.dest_domain = APR_DOMAIN_ADSP;
169 payload.hdr.dest_svc = APR_SVC_ADSP_CORE;
170 payload.hdr.src_port = TEMP_PORT;
171 payload.hdr.dest_port = TEMP_PORT;
172 payload.hdr.token = CORE_CLIENT;
173 payload.hdr.opcode = AVCS_CMD_REMOTE_AVTIMER_RELEASE_REQUEST;
174 payload.avtimer_handle = timerhandle;
175 pr_debug("%s: disable avtimer opcode %x handle %x\n",
176 __func__, payload.hdr.opcode, payload.avtimer_handle);
177 rc = apr_send_pkt(avtimer.core_handle_q,
178 (uint32_t *)&payload);
179 if (rc < 0)
180 pr_err("%s: Enable AVtimer failed op[0x%x]rc[%d]\n",
181 __func__, payload.hdr.opcode, rc);
182 else
183 rc = 0;
184 }
185 return rc;
186}
187
188static int avcs_core_enable_avtimer(char *client_name)
189{
190 int rc = -EINVAL, ret = -EINVAL;
191 struct adsp_avt_timer payload;
192
193 if (!client_name) {
194 pr_err("%s: Invalid params\n", __func__);
195 return -EINVAL;
196 }
197 memset(&payload, 0, sizeof(payload));
198 rc = avcs_core_open();
199 if (!rc && avtimer.core_handle_q) {
200 avtimer.enable_timer_resp_received = 0;
201 payload.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
202 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
203 payload.hdr.pkt_size =
204 sizeof(struct adsp_avt_timer);
205 payload.hdr.src_svc = avtimer.core_handle_q->id;
206 payload.hdr.src_domain = APR_DOMAIN_APPS;
207 payload.hdr.dest_domain = APR_DOMAIN_ADSP;
208 payload.hdr.dest_svc = APR_SVC_ADSP_CORE;
209 payload.hdr.src_port = TEMP_PORT;
210 payload.hdr.dest_port = TEMP_PORT;
211 payload.hdr.token = CORE_CLIENT;
212 payload.hdr.opcode = AVCS_CMD_REMOTE_AVTIMER_VOTE_REQUEST;
213 strlcpy(payload.client_name, client_name,
214 sizeof(payload.client_name));
215 pr_debug("%s: enable avtimer opcode %x client name %s\n",
216 __func__, payload.hdr.opcode, payload.client_name);
217 rc = apr_send_pkt(avtimer.core_handle_q,
218 (uint32_t *)&payload);
219 if (rc < 0) {
220 pr_err("%s: Enable AVtimer failed op[0x%x]rc[%d]\n",
221 __func__, payload.hdr.opcode, rc);
222 goto bail;
223 } else
224 rc = 0;
225 ret = wait_event_timeout(avtimer.adsp_resp_wait,
226 (avtimer.enable_timer_resp_received == 1),
227 msecs_to_jiffies(TIMEOUT_MS));
228 if (!ret) {
229 pr_err("%s: wait_event timeout for Enable timer\n",
230 __func__);
231 rc = -ETIMEDOUT;
232 }
233 if (rc)
234 avtimer.timer_handle = 0;
235 }
236bail:
237 return rc;
238}
239
240int avcs_core_disable_power_collapse(int enable)
241{
242 int rc = 0;
243
244 mutex_lock(&avtimer.avtimer_lock);
245 if (enable) {
246 if (avtimer.avtimer_open_cnt) {
247 avtimer.avtimer_open_cnt++;
248 pr_debug("%s: opened avtimer open count=%d\n",
249 __func__, avtimer.avtimer_open_cnt);
250 rc = 0;
251 goto done;
252 }
253 rc = avcs_core_enable_avtimer("timer");
254 if (!rc) {
255 avtimer.avtimer_open_cnt++;
256 atomic_set(&avtimer.adsp_ready, 1);
257 }
258 } else {
259 if (avtimer.avtimer_open_cnt > 0) {
260 avtimer.avtimer_open_cnt--;
261 if (!avtimer.avtimer_open_cnt) {
262 rc = avcs_core_disable_avtimer(
263 avtimer.timer_handle);
264 avtimer.timer_handle = 0;
265 }
266 }
267 }
268done:
269 mutex_unlock(&avtimer.avtimer_lock);
270 return rc;
271}
272EXPORT_SYMBOL(avcs_core_disable_power_collapse);
273
274static void reset_work(struct work_struct *work)
275{
276 if (q6core_is_adsp_ready()) {
277 avcs_core_disable_power_collapse(1);
278 avtimer.num_retries = Q6_READY_MAX_RETRIES;
279 return;
280 }
281 pr_debug("%s:Q6 not ready-retry after sometime\n", __func__);
282 if (--avtimer.num_retries > 0) {
283 schedule_delayed_work(&avtimer.ssr_dwork,
284 msecs_to_jiffies(Q6_READY_RETRY));
285 } else {
286 pr_err("%s: Q6 failed responding after multiple retries\n",
287 __func__);
288 avtimer.num_retries = Q6_READY_MAX_RETRIES;
289 }
290}
291
292int avcs_core_query_timer(uint64_t *avtimer_tick)
293{
294 uint32_t avtimer_msw = 0, avtimer_lsw = 0;
295 uint32_t res = 0;
296 uint64_t avtimer_tick_temp;
297
298 if (!atomic_read(&avtimer.adsp_ready)) {
299 pr_debug("%s:In SSR, return\n", __func__);
300 return -ENETRESET;
301 }
302 avtimer_lsw = ioread32(avtimer.p_avtimer_lsw);
303 avtimer_msw = ioread32(avtimer.p_avtimer_msw);
304
305 avtimer_tick_temp =
306 (uint64_t)((uint64_t)avtimer_msw << 32)
307 | avtimer_lsw;
308 res = do_div(avtimer_tick_temp, avtimer.clk_div);
309 *avtimer_tick = avtimer_tick_temp;
Laxminath Kasam282e28d2015-11-26 10:11:07 +0530310 pr_debug_ratelimited("%s:Avtimer: msw: %u, lsw: %u, tick: %llu\n",
311 __func__,
Banajit Goswamiaec1b462016-11-21 21:54:23 -0800312 return 0;
313}
314EXPORT_SYMBOL(avcs_core_query_timer);
315
316static int avtimer_open(struct inode *inode, struct file *file)
317{
318 return avcs_core_disable_power_collapse(1);
319}
320
321static int avtimer_release(struct inode *inode, struct file *file)
322{
323 return avcs_core_disable_power_collapse(0);
324}
325
326/*
327 * ioctl call provides GET_AVTIMER
328 */
329static long avtimer_ioctl(struct file *file, unsigned int ioctl_num,
330 unsigned long ioctl_param)
331{
332 switch (ioctl_num) {
333 case IOCTL_GET_AVTIMER_TICK:
334 {
Banajit Goswamiaec1b462016-11-21 21:54:23 -0800335 uint64_t avtimer_tick;
336
Laxminath Kasam282e28d2015-11-26 10:11:07 +0530337 avcs_core_query_timer(&avtimer_tick);
338 pr_debug_ratelimited("%s: AV Timer tick: time %llx\n",
339 __func__, avtimer_tick);
Banajit Goswamiaec1b462016-11-21 21:54:23 -0800340 if (copy_to_user((void *) ioctl_param, &avtimer_tick,
341 sizeof(avtimer_tick))) {
342 pr_err("%s: copy_to_user failed\n", __func__);
343 return -EFAULT;
344 }
345 }
346 break;
347
348 default:
349 pr_err("%s: invalid cmd\n", __func__);
350 return -EINVAL;
351 }
352 return 0;
353}
354
355static const struct file_operations avtimer_fops = {
356 .unlocked_ioctl = avtimer_ioctl,
357 .compat_ioctl = avtimer_ioctl,
358 .open = avtimer_open,
359 .release = avtimer_release
360};
361
362static int dev_avtimer_probe(struct platform_device *pdev)
363{
364 int result = 0;
365 dev_t dev = MKDEV(major, 0);
366 struct device *device_handle;
367 struct resource *reg_lsb = NULL, *reg_msb = NULL;
368 uint32_t clk_div_val;
369
370 if (!pdev) {
371 pr_err("%s: Invalid params\n", __func__);
372 return -EINVAL;
373 }
374 reg_lsb = platform_get_resource_byname(pdev,
375 IORESOURCE_MEM, "avtimer_lsb_addr");
376 if (!reg_lsb) {
377 dev_err(&pdev->dev, "%s: Looking up %s property",
378 "avtimer_lsb_addr", __func__);
379 return -EINVAL;
380 }
381 reg_msb = platform_get_resource_byname(pdev,
382 IORESOURCE_MEM, "avtimer_msb_addr");
383 if (!reg_msb) {
384 dev_err(&pdev->dev, "%s: Looking up %s property",
385 "avtimer_msb_addr", __func__);
386 return -EINVAL;
387 }
388 INIT_DELAYED_WORK(&avtimer.ssr_dwork, reset_work);
389
390 avtimer.p_avtimer_lsw = devm_ioremap_nocache(&pdev->dev,
391 reg_lsb->start, resource_size(reg_lsb));
392 if (!avtimer.p_avtimer_lsw) {
393 dev_err(&pdev->dev, "%s: ioremap failed for lsb avtimer register",
394 __func__);
395 return -ENOMEM;
396 }
397
398 avtimer.p_avtimer_msw = devm_ioremap_nocache(&pdev->dev,
399 reg_msb->start, resource_size(reg_msb));
400 if (!avtimer.p_avtimer_msw) {
401 dev_err(&pdev->dev, "%s: ioremap failed for msb avtimer register",
402 __func__);
403 goto unmap;
404 }
405 avtimer.num_retries = Q6_READY_MAX_RETRIES;
406 /* get the device number */
407 if (major)
408 result = register_chrdev_region(dev, 1, DEVICE_NAME);
409 else {
410 result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
411 major = MAJOR(dev);
412 }
413
414 if (result < 0) {
415 dev_err(&pdev->dev, "%s: Registering avtimer device failed\n",
416 __func__);
417 goto unmap;
418 }
419
420 avtimer.avtimer_class = class_create(THIS_MODULE, "avtimer");
421 if (IS_ERR(avtimer.avtimer_class)) {
422 result = PTR_ERR(avtimer.avtimer_class);
423 dev_err(&pdev->dev, "%s: Error creating avtimer class: %d\n",
424 __func__, result);
425 goto unregister_chrdev_region;
426 }
427
428 cdev_init(&avtimer.myc, &avtimer_fops);
429 result = cdev_add(&avtimer.myc, dev, 1);
430
431 if (result < 0) {
432 dev_err(&pdev->dev, "%s: Registering file operations failed\n",
433 __func__);
434 goto class_destroy;
435 }
436
437 device_handle = device_create(avtimer.avtimer_class,
438 NULL, avtimer.myc.dev, NULL, "avtimer");
439 if (IS_ERR(device_handle)) {
440 result = PTR_ERR(device_handle);
441 pr_err("%s: device_create failed: %d\n", __func__, result);
442 goto class_destroy;
443 }
444 init_waitqueue_head(&avtimer.adsp_resp_wait);
445 mutex_init(&avtimer.avtimer_lock);
446 avtimer.avtimer_open_cnt = 0;
447
448 pr_debug("%s: Device create done for avtimer major=%d\n",
449 __func__, major);
450
451 if (of_property_read_u32(pdev->dev.of_node,
452 "qcom,clk-div", &clk_div_val))
453 avtimer.clk_div = 1;
454 else
455 avtimer.clk_div = clk_div_val;
456
457 pr_debug("avtimer.clk_div = %d\n", avtimer.clk_div);
458 return 0;
459
460class_destroy:
461 class_destroy(avtimer.avtimer_class);
462unregister_chrdev_region:
463 unregister_chrdev_region(MKDEV(major, 0), 1);
464unmap:
465 if (avtimer.p_avtimer_lsw)
466 devm_iounmap(&pdev->dev, avtimer.p_avtimer_lsw);
467 if (avtimer.p_avtimer_msw)
468 devm_iounmap(&pdev->dev, avtimer.p_avtimer_msw);
469 avtimer.p_avtimer_lsw = NULL;
470 avtimer.p_avtimer_msw = NULL;
471 return result;
472
473}
474
475static int dev_avtimer_remove(struct platform_device *pdev)
476{
477 pr_debug("%s: dev_avtimer_remove\n", __func__);
478
479 if (avtimer.p_avtimer_lsw)
480 devm_iounmap(&pdev->dev, avtimer.p_avtimer_lsw);
481 if (avtimer.p_avtimer_msw)
482 devm_iounmap(&pdev->dev, avtimer.p_avtimer_msw);
483 device_destroy(avtimer.avtimer_class, avtimer.myc.dev);
484 cdev_del(&avtimer.myc);
485 class_destroy(avtimer.avtimer_class);
486 unregister_chrdev_region(MKDEV(major, 0), 1);
487
488 return 0;
489}
490
491static const struct of_device_id avtimer_machine_of_match[] = {
492 { .compatible = "qcom,avtimer", },
493 {},
494};
495static struct platform_driver dev_avtimer_driver = {
496 .probe = dev_avtimer_probe,
497 .remove = dev_avtimer_remove,
498 .driver = {
499 .name = "dev_avtimer",
500 .of_match_table = avtimer_machine_of_match,
501 },
502};
503
504static int __init avtimer_init(void)
505{
506 s32 rc;
507
508 rc = platform_driver_register(&dev_avtimer_driver);
Xiaoyu Ye1a2d8bd92017-01-31 18:54:15 -0800509 if (rc < 0) {
Banajit Goswamiaec1b462016-11-21 21:54:23 -0800510 pr_err("%s: platform_driver_register failed\n", __func__);
511 goto error_platform_driver;
512 }
513 pr_debug("%s: dev_avtimer_init : done\n", __func__);
514
515 return 0;
516error_platform_driver:
517
518 pr_err("%s: encounterd error\n", __func__);
519 return rc;
520}
521
522static void __exit avtimer_exit(void)
523{
524 pr_debug("%s: avtimer_exit\n", __func__);
525 platform_driver_unregister(&dev_avtimer_driver);
526}
527
528module_init(avtimer_init);
529module_exit(avtimer_exit);
530
531MODULE_DESCRIPTION("avtimer driver");
532MODULE_LICENSE("GPL v2");