blob: 04e351da24bbaa1f586534835ec1ed0bbd7b1c5f [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 {
Xiaoyu Yed6fb56d2016-12-07 16:35:07 -0800335 uint64_t avtimer_tick = 0;
336 int rc;
Banajit Goswamiaec1b462016-11-21 21:54:23 -0800337
Xiaoyu Yed6fb56d2016-12-07 16:35:07 -0800338 rc = avcs_core_query_timer(&avtimer_tick);
339
340 if (rc) {
341 pr_err("%s: Error: Invalid AV Timer tick, rc = %d\n",
342 __func__, rc);
343 return rc;
344 }
345
Laxminath Kasam282e28d2015-11-26 10:11:07 +0530346 pr_debug_ratelimited("%s: AV Timer tick: time %llx\n",
347 __func__, avtimer_tick);
Banajit Goswamiaec1b462016-11-21 21:54:23 -0800348 if (copy_to_user((void *) ioctl_param, &avtimer_tick,
349 sizeof(avtimer_tick))) {
350 pr_err("%s: copy_to_user failed\n", __func__);
351 return -EFAULT;
352 }
353 }
354 break;
355
356 default:
357 pr_err("%s: invalid cmd\n", __func__);
358 return -EINVAL;
359 }
360 return 0;
361}
362
363static const struct file_operations avtimer_fops = {
364 .unlocked_ioctl = avtimer_ioctl,
365 .compat_ioctl = avtimer_ioctl,
366 .open = avtimer_open,
367 .release = avtimer_release
368};
369
370static int dev_avtimer_probe(struct platform_device *pdev)
371{
372 int result = 0;
373 dev_t dev = MKDEV(major, 0);
374 struct device *device_handle;
375 struct resource *reg_lsb = NULL, *reg_msb = NULL;
376 uint32_t clk_div_val;
377
378 if (!pdev) {
379 pr_err("%s: Invalid params\n", __func__);
380 return -EINVAL;
381 }
382 reg_lsb = platform_get_resource_byname(pdev,
383 IORESOURCE_MEM, "avtimer_lsb_addr");
384 if (!reg_lsb) {
385 dev_err(&pdev->dev, "%s: Looking up %s property",
386 "avtimer_lsb_addr", __func__);
387 return -EINVAL;
388 }
389 reg_msb = platform_get_resource_byname(pdev,
390 IORESOURCE_MEM, "avtimer_msb_addr");
391 if (!reg_msb) {
392 dev_err(&pdev->dev, "%s: Looking up %s property",
393 "avtimer_msb_addr", __func__);
394 return -EINVAL;
395 }
396 INIT_DELAYED_WORK(&avtimer.ssr_dwork, reset_work);
397
398 avtimer.p_avtimer_lsw = devm_ioremap_nocache(&pdev->dev,
399 reg_lsb->start, resource_size(reg_lsb));
400 if (!avtimer.p_avtimer_lsw) {
401 dev_err(&pdev->dev, "%s: ioremap failed for lsb avtimer register",
402 __func__);
403 return -ENOMEM;
404 }
405
406 avtimer.p_avtimer_msw = devm_ioremap_nocache(&pdev->dev,
407 reg_msb->start, resource_size(reg_msb));
408 if (!avtimer.p_avtimer_msw) {
409 dev_err(&pdev->dev, "%s: ioremap failed for msb avtimer register",
410 __func__);
411 goto unmap;
412 }
413 avtimer.num_retries = Q6_READY_MAX_RETRIES;
414 /* get the device number */
415 if (major)
416 result = register_chrdev_region(dev, 1, DEVICE_NAME);
417 else {
418 result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
419 major = MAJOR(dev);
420 }
421
422 if (result < 0) {
423 dev_err(&pdev->dev, "%s: Registering avtimer device failed\n",
424 __func__);
425 goto unmap;
426 }
427
428 avtimer.avtimer_class = class_create(THIS_MODULE, "avtimer");
429 if (IS_ERR(avtimer.avtimer_class)) {
430 result = PTR_ERR(avtimer.avtimer_class);
431 dev_err(&pdev->dev, "%s: Error creating avtimer class: %d\n",
432 __func__, result);
433 goto unregister_chrdev_region;
434 }
435
436 cdev_init(&avtimer.myc, &avtimer_fops);
437 result = cdev_add(&avtimer.myc, dev, 1);
438
439 if (result < 0) {
440 dev_err(&pdev->dev, "%s: Registering file operations failed\n",
441 __func__);
442 goto class_destroy;
443 }
444
445 device_handle = device_create(avtimer.avtimer_class,
446 NULL, avtimer.myc.dev, NULL, "avtimer");
447 if (IS_ERR(device_handle)) {
448 result = PTR_ERR(device_handle);
449 pr_err("%s: device_create failed: %d\n", __func__, result);
450 goto class_destroy;
451 }
452 init_waitqueue_head(&avtimer.adsp_resp_wait);
453 mutex_init(&avtimer.avtimer_lock);
454 avtimer.avtimer_open_cnt = 0;
455
456 pr_debug("%s: Device create done for avtimer major=%d\n",
457 __func__, major);
458
459 if (of_property_read_u32(pdev->dev.of_node,
460 "qcom,clk-div", &clk_div_val))
461 avtimer.clk_div = 1;
462 else
463 avtimer.clk_div = clk_div_val;
464
465 pr_debug("avtimer.clk_div = %d\n", avtimer.clk_div);
466 return 0;
467
468class_destroy:
469 class_destroy(avtimer.avtimer_class);
470unregister_chrdev_region:
471 unregister_chrdev_region(MKDEV(major, 0), 1);
472unmap:
473 if (avtimer.p_avtimer_lsw)
474 devm_iounmap(&pdev->dev, avtimer.p_avtimer_lsw);
475 if (avtimer.p_avtimer_msw)
476 devm_iounmap(&pdev->dev, avtimer.p_avtimer_msw);
477 avtimer.p_avtimer_lsw = NULL;
478 avtimer.p_avtimer_msw = NULL;
479 return result;
480
481}
482
483static int dev_avtimer_remove(struct platform_device *pdev)
484{
485 pr_debug("%s: dev_avtimer_remove\n", __func__);
486
487 if (avtimer.p_avtimer_lsw)
488 devm_iounmap(&pdev->dev, avtimer.p_avtimer_lsw);
489 if (avtimer.p_avtimer_msw)
490 devm_iounmap(&pdev->dev, avtimer.p_avtimer_msw);
491 device_destroy(avtimer.avtimer_class, avtimer.myc.dev);
492 cdev_del(&avtimer.myc);
493 class_destroy(avtimer.avtimer_class);
494 unregister_chrdev_region(MKDEV(major, 0), 1);
495
496 return 0;
497}
498
499static const struct of_device_id avtimer_machine_of_match[] = {
500 { .compatible = "qcom,avtimer", },
501 {},
502};
503static struct platform_driver dev_avtimer_driver = {
504 .probe = dev_avtimer_probe,
505 .remove = dev_avtimer_remove,
506 .driver = {
507 .name = "dev_avtimer",
508 .of_match_table = avtimer_machine_of_match,
509 },
510};
511
512static int __init avtimer_init(void)
513{
514 s32 rc;
515
516 rc = platform_driver_register(&dev_avtimer_driver);
Xiaoyu Ye1a2d8bd92017-01-31 18:54:15 -0800517 if (rc < 0) {
Banajit Goswamiaec1b462016-11-21 21:54:23 -0800518 pr_err("%s: platform_driver_register failed\n", __func__);
519 goto error_platform_driver;
520 }
521 pr_debug("%s: dev_avtimer_init : done\n", __func__);
522
523 return 0;
524error_platform_driver:
525
526 pr_err("%s: encounterd error\n", __func__);
527 return rc;
528}
529
530static void __exit avtimer_exit(void)
531{
532 pr_debug("%s: avtimer_exit\n", __func__);
533 platform_driver_unregister(&dev_avtimer_driver);
534}
535
536module_init(avtimer_init);
537module_exit(avtimer_exit);
538
539MODULE_DESCRIPTION("avtimer driver");
540MODULE_LICENSE("GPL v2");