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