blob: a2b4b6e700491e7906269210a609db97585c130a [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/slab.h>
15#include <linux/cdev.h>
16#include <linux/file.h>
17#include <linux/device.h>
18#include <linux/fs.h>
19#include <linux/list.h>
20#include <linux/module.h>
21#include <linux/sched.h>
22#include <linux/spinlock.h>
23#include <linux/uaccess.h>
24#include <linux/wakelock.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/msm_q6venc.h>
Stephen Boyd2fcabf92012-05-30 10:41:11 -070026#include <linux/pm_qos.h>
27
28#include <mach/cpuidle.h>
29
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070030#include "dal.h"
31
32#define DALDEVICEID_VENC_DEVICE 0x0200002D
33#define DALDEVICEID_VENC_PORTNAME "DAL_AQ_VID"
34
35#define VENC_NAME "q6venc"
36#define VENC_MSG_MAX 128
37
38#define VENC_INTERFACE_VERSION 0x00020000
39#define MAJOR_MASK 0xFFFF0000
40#define MINOR_MASK 0x0000FFFF
41#define VENC_GET_MAJOR_VERSION(version) ((version & MAJOR_MASK)>>16)
42#define VENC_GET_MINOR_VERSION(version) (version & MINOR_MASK)
43
44enum {
45 VENC_BUFFER_TYPE_INPUT,
46 VENC_BUFFER_TYPE_OUTPUT,
47 VENC_BUFFER_TYPE_QDSP6,
48 VENC_BUFFER_TYPE_HDR
49};
50enum {
51 VENC_DALRPC_GET_SYNTAX_HEADER = DAL_OP_FIRST_DEVICE_API,
52 VENC_DALRPC_UPDATE_INTRA_REFRESH,
53 VENC_DALRPC_UPDATE_FRAME_RATE,
54 VENC_DALRPC_UPDATE_BITRATE,
55 VENC_DALRPC_UPDATE_QP_RANGE,
56 VENC_DALRPC_UPDATE_INTRA_PERIOD,
57 VENC_DALRPC_REQUEST_IFRAME,
58 VENC_DALRPC_START,
59 VENC_DALRPC_STOP,
60 VENC_DALRPC_SUSPEND,
61 VENC_DALRPC_RESUME,
62 VENC_DALRPC_FLUSH,
63 VENC_DALRPC_QUEUE_INPUT,
64 VENC_DALRPC_QUEUE_OUTPUT
65};
66struct venc_input_payload {
67 u32 data;
68};
69struct venc_output_payload {
70 u32 size;
71 long long time_stamp;
72 u32 flags;
73 u32 data;
74 u32 client_data_from_input;
75};
76union venc_payload {
77 struct venc_input_payload input_payload;
78 struct venc_output_payload output_payload;
79};
80struct venc_msg_type {
81 u32 event;
82 u32 status;
83 union venc_payload payload;
84};
85struct venc_input_buf {
86 struct venc_buf_type yuv_buf;
87 u32 data_size;
88 long long time_stamp;
89 u32 flags;
90 u32 dvs_offsetx;
91 u32 dvs_offsety;
92 u32 client_data;
93 u32 op_client_data;
94};
95struct venc_output_buf {
96 struct venc_buf_type bit_stream_buf;
97 u32 client_data;
98};
99
100struct venc_msg_list {
101 struct list_head list;
102 struct venc_msg msg_data;
103};
104struct venc_buf {
105 int fd;
106 u32 src;
107 u32 offset;
108 u32 size;
109 u32 btype;
110 unsigned long paddr;
111 struct file *file;
112};
113struct venc_pmem_list {
114 struct list_head list;
115 struct venc_buf buf;
116};
117struct venc_dev {
118 bool is_active;
119 bool pmem_freed;
120 enum venc_state_type state;
121 struct list_head venc_msg_list_head;
122 struct list_head venc_msg_list_free;
123 spinlock_t venc_msg_list_lock;
124 struct list_head venc_pmem_list_head;
125 spinlock_t venc_pmem_list_lock;
126 struct dal_client *q6_handle;
127 wait_queue_head_t venc_msg_evt;
128 struct device *class_devp;
129};
130
131#define DEBUG_VENC 0
132#if DEBUG_VENC
133#define TRACE(fmt, x...) \
134 do { pr_debug("%s:%d " fmt, __func__, __LINE__, ##x); } while (0)
135#else
136#define TRACE(fmt, x...) do { } while (0)
137#endif
138
139static struct cdev cdev;
140static dev_t venc_dev_num;
141static struct class *venc_class;
142static struct venc_dev *venc_device_p;
143static int venc_ref;
144
145static DEFINE_MUTEX(idlecount_lock);
146static int idlecount;
147static struct wake_lock wakelock;
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700148static struct pm_qos_request pm_qos_req;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149
150static void prevent_sleep(void)
151{
152 mutex_lock(&idlecount_lock);
153 if (++idlecount == 1) {
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700154 pm_qos_update_request(&pm_qos_req,
155 msm_cpuidle_get_deep_idle_latency());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156 wake_lock(&wakelock);
157 }
158 mutex_unlock(&idlecount_lock);
159}
160
161static void allow_sleep(void)
162{
163 mutex_lock(&idlecount_lock);
164 if (--idlecount == 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165 wake_unlock(&wakelock);
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700166 pm_qos_update_request(&pm_qos_req, PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700167 }
168 mutex_unlock(&idlecount_lock);
169}
170
171static inline int venc_check_version(u32 client, u32 server)
172{
173 int ret = -EINVAL;
174
175 if ((VENC_GET_MAJOR_VERSION(client) == VENC_GET_MAJOR_VERSION(server))
176 && (VENC_GET_MINOR_VERSION(client) <=
177 VENC_GET_MINOR_VERSION(server)))
178 ret = 0;
179
180 return ret;
181}
182
183static int venc_get_msg(struct venc_dev *dvenc, void *msg)
184{
185 struct venc_msg_list *l;
186 unsigned long flags;
187 int ret = 0;
188 struct venc_msg qdsp_msg;
189
190 if (!dvenc->is_active)
191 return -EPERM;
192 spin_lock_irqsave(&dvenc->venc_msg_list_lock, flags);
193 list_for_each_entry_reverse(l, &dvenc->venc_msg_list_head, list) {
194 memcpy(&qdsp_msg, &l->msg_data, sizeof(struct venc_msg));
195 list_del(&l->list);
196 list_add(&l->list, &dvenc->venc_msg_list_free);
197 ret = 1;
198 break;
199 }
200 spin_unlock_irqrestore(&dvenc->venc_msg_list_lock, flags);
201 if (copy_to_user(msg, &qdsp_msg, sizeof(struct venc_msg)))
202 pr_err("%s failed to copy_to_user\n", __func__);
203 return ret;
204}
205
206static void venc_put_msg(struct venc_dev *dvenc, struct venc_msg *msg)
207{
208 struct venc_msg_list *l;
209 unsigned long flags;
210 int found = 0;
211
212 spin_lock_irqsave(&dvenc->venc_msg_list_lock, flags);
213 list_for_each_entry(l, &dvenc->venc_msg_list_free, list) {
214 memcpy(&l->msg_data, msg, sizeof(struct venc_msg));
215 list_del(&l->list);
216 list_add(&l->list, &dvenc->venc_msg_list_head);
217 found = 1;
218 break;
219 }
220 spin_unlock_irqrestore(&dvenc->venc_msg_list_lock, flags);
221 if (found)
222 wake_up(&dvenc->venc_msg_evt);
223 else
224 pr_err("%s: failed to find a free node\n", __func__);
225
226}
227
228static struct venc_pmem_list *venc_add_pmem_to_list(struct venc_dev *dvenc,
229 struct venc_pmem *mptr,
230 u32 btype)
231{
232 int ret = 0;
233 unsigned long flags;
234 unsigned long len;
235 unsigned long vaddr;
236 struct venc_pmem_list *plist = NULL;
237
238 plist = kzalloc(sizeof(struct venc_pmem_list), GFP_KERNEL);
239 if (!plist) {
240 pr_err("%s: kzalloc failed\n", __func__);
241 return NULL;
242 }
243
244 ret = get_pmem_file(mptr->fd, &(plist->buf.paddr),
245 &vaddr, &len, &(plist->buf.file));
246 if (ret) {
247 pr_err("%s: get_pmem_file failed for fd=%d offset=%d\n",
248 __func__, mptr->fd, mptr->offset);
249 goto err_venc_add_pmem;
250 } else if (mptr->offset >= len) {
251 pr_err("%s: invalid offset (%d > %ld) for fd=%d\n",
252 __func__, mptr->offset, len, mptr->fd);
253 ret = -EINVAL;
254 goto err_venc_get_pmem;
255 }
256
257 plist->buf.fd = mptr->fd;
258 plist->buf.paddr += mptr->offset;
259 plist->buf.size = mptr->size;
260 plist->buf.btype = btype;
261 plist->buf.offset = mptr->offset;
262 plist->buf.src = mptr->src;
263
264 spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
265 list_add(&plist->list, &dvenc->venc_pmem_list_head);
266 spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
267 return plist;
268
269err_venc_get_pmem:
270 put_pmem_file(plist->buf.file);
271err_venc_add_pmem:
272 kfree(plist);
273 return NULL;
274}
275
276static struct venc_pmem_list *venc_get_pmem_from_list(
277 struct venc_dev *dvenc, u32 pmem_fd,
278 u32 offset, u32 btype)
279{
280 struct venc_pmem_list *plist;
281 unsigned long flags;
282 struct file *file;
283 int found = 0;
284
285 file = fget(pmem_fd);
286 if (!file) {
287 pr_err("%s: invalid encoder buffer fd(%d)\n", __func__,
288 pmem_fd);
289 return NULL;
290 }
291 spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
292 list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list) {
293 if (plist->buf.btype == btype && plist->buf.file == file &&
294 plist->buf.offset == offset) {
295 found = 1;
296 break;
297 }
298 }
299 spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
300 fput(file);
301 if (found)
302 return plist;
303
304 else
305 return NULL;
306}
307
308static int venc_set_buffer(struct venc_dev *dvenc, void *argp,
309 u32 btype)
310{
311 struct venc_pmem pmem;
312 struct venc_pmem_list *plist;
313 int ret = 0;
314
315 ret = copy_from_user(&pmem, argp, sizeof(pmem));
316 if (ret) {
317 pr_err("%s: copy_from_user failed\n", __func__);
318 return ret;
319 }
320 plist = venc_add_pmem_to_list(dvenc, &pmem, btype);
321 if (plist == NULL) {
322 pr_err("%s: buffer add_to_pmem_list failed\n",
323 __func__);
324 return -EPERM;
325 }
326 return ret;
327}
328
329static int venc_assign_q6_buffers(struct venc_dev *dvenc,
330 struct venc_buffers *pbufs,
331 struct venc_nonio_buf_config *pcfg)
332{
333 int ret = 0;
334 struct venc_pmem_list *plist;
335
336 plist = venc_add_pmem_to_list(dvenc, &(pbufs->recon_buf[0]),
337 VENC_BUFFER_TYPE_QDSP6);
338 if (plist == NULL) {
339 pr_err("%s: recon_buf0 failed to add_to_pmem_list\n",
340 __func__);
341 return -EPERM;
342 }
343 pcfg->recon_buf1.region = pbufs->recon_buf[0].src;
344 pcfg->recon_buf1.phys = plist->buf.paddr;
345 pcfg->recon_buf1.size = plist->buf.size;
346 pcfg->recon_buf1.offset = 0;
347
348 plist = venc_add_pmem_to_list(dvenc, &(pbufs->recon_buf[1]),
349 VENC_BUFFER_TYPE_QDSP6);
350 if (plist == NULL) {
351 pr_err("%s: recons_buf1 failed to add_to_pmem_list\n",
352 __func__);
353 return -EPERM;
354 }
355 pcfg->recon_buf2.region = pbufs->recon_buf[1].src;
356 pcfg->recon_buf2.phys = plist->buf.paddr;
357 pcfg->recon_buf2.size = plist->buf.size;
358 pcfg->recon_buf2.offset = 0;
359
360 plist = venc_add_pmem_to_list(dvenc, &(pbufs->wb_buf),
361 VENC_BUFFER_TYPE_QDSP6);
362 if (plist == NULL) {
363 pr_err("%s: wb_buf failed to add_to_pmem_list\n",
364 __func__);
365 return -EPERM;
366 }
367 pcfg->wb_buf.region = pbufs->wb_buf.src;
368 pcfg->wb_buf.phys = plist->buf.paddr;
369 pcfg->wb_buf.size = plist->buf.size;
370 pcfg->wb_buf.offset = 0;
371
372 plist = venc_add_pmem_to_list(dvenc, &(pbufs->cmd_buf),
373 VENC_BUFFER_TYPE_QDSP6);
374 if (plist == NULL) {
375 pr_err("%s: cmd_buf failed to add_to_pmem_list\n",
376 __func__);
377 return -EPERM;
378 }
379 pcfg->cmd_buf.region = pbufs->cmd_buf.src;
380 pcfg->cmd_buf.phys = plist->buf.paddr;
381 pcfg->cmd_buf.size = plist->buf.size;
382 pcfg->cmd_buf.offset = 0;
383
384 plist = venc_add_pmem_to_list(dvenc, &(pbufs->vlc_buf),
385 VENC_BUFFER_TYPE_QDSP6);
386 if (plist == NULL) {
387 pr_err("%s: vlc_buf failed to add_to_pmem_list"
388 " failed\n", __func__);
389 return -EPERM;
390 }
391 pcfg->vlc_buf.region = pbufs->vlc_buf.src;
392 pcfg->vlc_buf.phys = plist->buf.paddr;
393 pcfg->vlc_buf.size = plist->buf.size;
394 pcfg->vlc_buf.offset = 0;
395
396 return ret;
397}
398
399static int venc_start(struct venc_dev *dvenc, void *argp)
400{
401 int ret = 0;
402 struct venc_q6_config q6_config;
403 struct venc_init_config vconfig;
404
405 dvenc->state = VENC_STATE_START;
406 ret = copy_from_user(&vconfig, argp, sizeof(struct venc_init_config));
407 if (ret) {
408 pr_err("%s: copy_from_user failed\n", __func__);
409 return ret;
410 }
411 memcpy(&q6_config, &(vconfig.q6_config), sizeof(q6_config));
412 ret = venc_assign_q6_buffers(dvenc, &(vconfig.q6_bufs),
413 &(q6_config.buf_params));
414 if (ret != 0) {
415 pr_err("%s: assign_q6_buffers failed\n", __func__);
416 return -EPERM;
417 }
418
419 q6_config.callback_event = dvenc->q6_handle;
420 TRACE("%s: parameters: handle:%p, config:%p, callback:%p \n", __func__,
421 dvenc->q6_handle, &q6_config, q6_config.callback_event);
422 TRACE("%s: parameters:recon1:0x%x, recon2:0x%x,"
423 " wb_buf:0x%x, cmd:0x%x, vlc:0x%x\n", __func__,
424 q6_config.buf_params.recon_buf1.phys,
425 q6_config.buf_params.recon_buf2.phys,
426 q6_config.buf_params.wb_buf.phys,
427 q6_config.buf_params.cmd_buf.phys,
428 q6_config.buf_params.vlc_buf.phys);
429 TRACE("%s: size of param:%d \n", __func__, sizeof(q6_config));
430 ret = dal_call_f5(dvenc->q6_handle, VENC_DALRPC_START, &q6_config,
431 sizeof(q6_config));
432 if (ret != 0) {
433 pr_err("%s: remote function failed (%d)\n", __func__, ret);
434 return ret;
435 }
436 return ret;
437}
438
439static int venc_encode_frame(struct venc_dev *dvenc, void *argp)
440{
441 int ret = 0;
442 struct venc_pmem buf;
443 struct venc_input_buf q6_input;
444 struct venc_pmem_list *plist;
445 struct venc_buffer input;
446
447 ret = copy_from_user(&input, argp, sizeof(struct venc_buffer));
448 if (ret) {
449 pr_err("%s: copy_from_user failed\n", __func__);
450 return ret;
451 }
452 ret = copy_from_user(&buf,
453 ((struct venc_buffer *)argp)->ptr_buffer,
454 sizeof(struct venc_pmem));
455 if (ret) {
456 pr_err("%s: copy_from_user failed\n", __func__);
457 return ret;
458 }
459
460 plist = venc_get_pmem_from_list(dvenc, buf.fd, buf.offset,
461 VENC_BUFFER_TYPE_INPUT);
462 if (NULL == plist) {
463 plist = venc_add_pmem_to_list(dvenc, &buf,
464 VENC_BUFFER_TYPE_INPUT);
465 if (plist == NULL) {
466 pr_err("%s: buffer add_to_pmem_list failed\n",
467 __func__);
468 return -EPERM;
469 }
470 }
471
472 q6_input.flags = 0;
473 if (input.flags & VENC_FLAG_EOS)
474 q6_input.flags |= 0x00000001;
475 q6_input.yuv_buf.region = plist->buf.src;
476 q6_input.yuv_buf.phys = plist->buf.paddr;
477 q6_input.yuv_buf.size = plist->buf.size;
478 q6_input.yuv_buf.offset = 0;
479 q6_input.data_size = plist->buf.size;
480 q6_input.client_data = (u32)input.client_data;
481 q6_input.time_stamp = input.time_stamp;
482 q6_input.dvs_offsetx = 0;
483 q6_input.dvs_offsety = 0;
484
485 TRACE("Pushing down input phys=0x%x fd= %d, client_data: 0x%x,"
486 " time_stamp:%lld \n", q6_input.yuv_buf.phys, plist->buf.fd,
487 input.client_data, input.time_stamp);
488 ret = dal_call_f5(dvenc->q6_handle, VENC_DALRPC_QUEUE_INPUT,
489 &q6_input, sizeof(q6_input));
490
491 if (ret != 0)
492 pr_err("%s: Q6 queue_input failed (%d)\n", __func__,
493 (int)ret);
494 return ret;
495}
496
497static int venc_fill_output(struct venc_dev *dvenc, void *argp)
498{
499 int ret = 0;
500 struct venc_pmem buf;
501 struct venc_output_buf q6_output;
502 struct venc_pmem_list *plist;
503 struct venc_buffer output;
504
505 ret = copy_from_user(&output, argp, sizeof(struct venc_buffer));
506 if (ret) {
507 pr_err("%s: copy_from_user failed\n", __func__);
508 return ret;
509 }
510 ret = copy_from_user(&buf,
511 ((struct venc_buffer *)argp)->ptr_buffer,
512 sizeof(struct venc_pmem));
513 if (ret) {
514 pr_err("%s: copy_from_user failed\n", __func__);
515 return ret;
516 }
517 plist = venc_get_pmem_from_list(dvenc, buf.fd, buf.offset,
518 VENC_BUFFER_TYPE_OUTPUT);
519 if (NULL == plist) {
520 plist = venc_add_pmem_to_list(dvenc, &buf,
521 VENC_BUFFER_TYPE_OUTPUT);
522 if (NULL == plist) {
523 pr_err("%s: output buffer failed to add_to_pmem_list"
524 "\n", __func__);
525 return -EPERM;
526 }
527 }
528 q6_output.bit_stream_buf.region = plist->buf.src;
529 q6_output.bit_stream_buf.phys = (u32)plist->buf.paddr;
530 q6_output.bit_stream_buf.size = plist->buf.size;
531 q6_output.bit_stream_buf.offset = 0;
532 q6_output.client_data = (u32)output.client_data;
533 ret =
534 dal_call_f5(dvenc->q6_handle, VENC_DALRPC_QUEUE_OUTPUT, &q6_output,
535 sizeof(q6_output));
536 if (ret != 0)
537 pr_err("%s: remote function failed (%d)\n", __func__, ret);
538 return ret;
539}
540
541static int venc_stop(struct venc_dev *dvenc)
542{
543 int ret = 0;
544 struct venc_msg msg;
545
546 ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_STOP, 1);
547 if (ret) {
548 pr_err("%s: remote runction failed (%d)\n", __func__, ret);
549 msg.msg_code = VENC_MSG_STOP;
550 msg.msg_data_size = 0;
551 msg.status_code = VENC_S_EFAIL;
552 venc_put_msg(dvenc, &msg);
553 }
554 return ret;
555}
556
557static int venc_pause(struct venc_dev *dvenc)
558{
559 int ret = 0;
560 struct venc_msg msg;
561
562 ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_SUSPEND, 1);
563 if (ret) {
564 pr_err("%s: remote function failed (%d)\n", __func__, ret);
565 msg.msg_code = VENC_MSG_PAUSE;
566 msg.status_code = VENC_S_EFAIL;
567 msg.msg_data_size = 0;
568 venc_put_msg(dvenc, &msg);
569 }
570 return ret;
571}
572
573static int venc_resume(struct venc_dev *dvenc)
574{
575 int ret = 0;
576 struct venc_msg msg;
577
578 ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_RESUME, 1);
579 if (ret) {
580 pr_err("%s: remote function failed (%d)\n", __func__, ret);
581 msg.msg_code = VENC_MSG_RESUME;
582 msg.msg_data_size = 0;
583 msg.status_code = VENC_S_EFAIL;
584 venc_put_msg(dvenc, &msg);
585 }
586 return ret;
587}
588
589static int venc_flush(struct venc_dev *dvenc, void *argp)
590{
591 int ret = 0;
592 struct venc_msg msg;
593 union venc_msg_data smsg;
594 int status = VENC_S_SUCCESS;
595 struct venc_buffer_flush flush;
596
597 if (copy_from_user(&flush, argp, sizeof(struct venc_buffer_flush)))
598 return -EFAULT;
599 if (flush.flush_mode == VENC_FLUSH_ALL) {
600 ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_FLUSH, 1);
601 if (ret)
602 status = VENC_S_EFAIL;
603 } else
604 status = VENC_S_ENOTSUPP;
605
606 if (status != VENC_S_SUCCESS) {
607 if ((flush.flush_mode == VENC_FLUSH_INPUT) ||
608 (flush.flush_mode == VENC_FLUSH_ALL)) {
609 smsg.flush_ret.flush_mode = VENC_FLUSH_INPUT;
610 msg.msg_data = smsg;
611 msg.status_code = status;
612 msg.msg_code = VENC_MSG_FLUSH;
613 msg.msg_data_size = sizeof(union venc_msg_data);
614 venc_put_msg(dvenc, &msg);
615 }
616 if (flush.flush_mode == VENC_FLUSH_OUTPUT ||
617 (flush.flush_mode == VENC_FLUSH_ALL)) {
618 smsg.flush_ret.flush_mode = VENC_FLUSH_OUTPUT;
619 msg.msg_data = smsg;
620 msg.status_code = status;
621 msg.msg_code = VENC_MSG_FLUSH;
622 msg.msg_data_size = sizeof(union venc_msg_data);
623 venc_put_msg(dvenc, &msg);
624 }
625 return -EIO;
626 }
627 return ret;
628}
629
630static int venc_get_sequence_hdr(struct venc_dev *dvenc, void *argp)
631{
632 pr_err("%s not supported\n", __func__);
633 return -EIO;
634}
635
636static int venc_set_qp_range(struct venc_dev *dvenc, void *argp)
637{
638 int ret = 0;
639 struct venc_qp_range qp;
640
641 ret = copy_from_user(&qp, argp, sizeof(struct venc_qp_range));
642 if (ret) {
643 pr_err("%s: copy_from_user failed\n", __func__);
644 return ret;
645 }
646
647 if (dvenc->state == VENC_STATE_START ||
648 dvenc->state == VENC_STATE_PAUSE) {
649 ret =
650 dal_call_f5(dvenc->q6_handle, VENC_DALRPC_UPDATE_QP_RANGE,
651 &qp, sizeof(struct venc_qp_range));
652 if (ret) {
653 pr_err("%s: remote function failed (%d) \n", __func__,
654 ret);
655 return ret;
656 }
657 }
658 return ret;
659}
660
661static int venc_set_intra_period(struct venc_dev *dvenc, void *argp)
662{
663 int ret = 0;
664 u32 pnum = 0;
665
666 ret = copy_from_user(&pnum, argp, sizeof(int));
667 if (ret) {
668 pr_err("%s: copy_from_user failed\n", __func__);
669 return ret;
670 }
671 if (dvenc->state == VENC_STATE_START ||
672 dvenc->state == VENC_STATE_PAUSE) {
673 ret = dal_call_f0(dvenc->q6_handle,
674 VENC_DALRPC_UPDATE_INTRA_PERIOD, pnum);
675 if (ret)
676 pr_err("%s: remote function failed (%d)\n", __func__,
677 ret);
678 }
679 return ret;
680}
681
682static int venc_set_intra_refresh(struct venc_dev *dvenc, void *argp)
683{
684 int ret = 0;
685 u32 mb_num = 0;
686
687 ret = copy_from_user(&mb_num, argp, sizeof(int));
688 if (ret) {
689 pr_err("%s: copy_from_user failed\n", __func__);
690 return ret;
691 }
692 if (dvenc->state == VENC_STATE_START ||
693 dvenc->state == VENC_STATE_PAUSE) {
694 ret = dal_call_f0(dvenc->q6_handle,
695 VENC_DALRPC_UPDATE_INTRA_REFRESH, mb_num);
696 if (ret)
697 pr_err("%s: remote function failed (%d)\n", __func__,
698 ret);
699 }
700 return ret;
701}
702
703static int venc_set_frame_rate(struct venc_dev *dvenc, void *argp)
704{
705 int ret = 0;
706 struct venc_frame_rate pdata;
707 ret = copy_from_user(&pdata, argp, sizeof(struct venc_frame_rate));
708 if (ret) {
709 pr_err("%s: copy_from_user failed\n", __func__);
710 return ret;
711 }
712 if (dvenc->state == VENC_STATE_START ||
713 dvenc->state == VENC_STATE_PAUSE) {
714 ret = dal_call_f5(dvenc->q6_handle,
715 VENC_DALRPC_UPDATE_FRAME_RATE,
716 (void *)&(pdata),
717 sizeof(struct venc_frame_rate));
718 if (ret)
719 pr_err("%s: remote function failed (%d)\n", __func__,
720 ret);
721 }
722 return ret;
723}
724
725static int venc_set_target_bitrate(struct venc_dev *dvenc, void *argp)
726{
727 int ret = 0;
728 u32 pdata = 0;
729
730 ret = copy_from_user(&pdata, argp, sizeof(int));
731 if (ret) {
732 pr_err("%s: copy_from_user failed\n", __func__);
733 return ret;
734 }
735 if (dvenc->state == VENC_STATE_START ||
736 dvenc->state == VENC_STATE_PAUSE) {
737 ret = dal_call_f0(dvenc->q6_handle,
738 VENC_DALRPC_UPDATE_BITRATE, pdata);
739 if (ret)
740 pr_err("%s: remote function failed (%d)\n", __func__,
741 ret);
742 }
743 return ret;
744}
745
746static int venc_request_iframe(struct venc_dev *dvenc)
747{
748 int ret = 0;
749
750 if (dvenc->state != VENC_STATE_START)
751 return -EINVAL;
752
753 ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_REQUEST_IFRAME, 1);
754 if (ret)
755 pr_err("%s: remote function failed (%d)\n", __func__, ret);
756 return ret;
757}
758
759static int venc_stop_read_msg(struct venc_dev *dvenc)
760{
761 struct venc_msg msg;
762 int ret = 0;
763
764 msg.status_code = 0;
765 msg.msg_code = VENC_MSG_STOP_READING_MSG;
766 msg.msg_data_size = 0;
767 venc_put_msg(dvenc, &msg);
768 return ret;
769}
770
771static int venc_q6_stop(struct venc_dev *dvenc)
772{
773 int ret = 0;
774 struct venc_pmem_list *plist;
775 unsigned long flags;
776
777 wake_up(&dvenc->venc_msg_evt);
778 spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
779 if (!dvenc->pmem_freed) {
780 list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list)
781 put_pmem_file(plist->buf.file);
782 dvenc->pmem_freed = 1;
783 }
784 spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
785
786 dvenc->state = VENC_STATE_STOP;
787 return ret;
788}
789
790static int venc_translate_error(enum venc_status_code q6_status)
791{
792 int ret = 0;
793
794 switch (q6_status) {
795 case VENC_STATUS_SUCCESS:
796 ret = VENC_S_SUCCESS;
797 break;
798 case VENC_STATUS_ERROR:
799 ret = VENC_S_EFAIL;
800 break;
801 case VENC_STATUS_INVALID_STATE:
802 ret = VENC_S_EINVALSTATE;
803 break;
804 case VENC_STATUS_FLUSHING:
805 ret = VENC_S_EFLUSHED;
806 break;
807 case VENC_STATUS_INVALID_PARAM:
808 ret = VENC_S_EBADPARAM;
809 break;
810 case VENC_STATUS_CMD_QUEUE_FULL:
811 ret = VENC_S_ECMDQFULL;
812 break;
813 case VENC_STATUS_CRITICAL:
814 ret = VENC_S_EFATAL;
815 break;
816 case VENC_STATUS_INSUFFICIENT_RESOURCES:
817 ret = VENC_S_ENOHWRES;
818 break;
819 case VENC_STATUS_TIMEOUT:
820 ret = VENC_S_ETIMEOUT;
821 break;
822 }
823 if (q6_status != VENC_STATUS_SUCCESS)
824 pr_err("%s: Q6 failed (%d)", __func__, (int)q6_status);
825 return ret;
826}
827
828static void venc_q6_callback(void *data, int len, void *cookie)
829{
830 int status = 0;
831 struct venc_dev *dvenc = (struct venc_dev *)cookie;
832 struct venc_msg_type *q6_msg = NULL;
833 struct venc_msg msg, msg1;
834 union venc_msg_data smsg1, smsg2;
835 unsigned long msg_code = 0;
836 struct venc_input_payload *pload1;
837 struct venc_output_payload *pload2;
838 uint32_t * tmp = (uint32_t *) data;
839
840 if (dvenc == NULL) {
841 pr_err("%s: empty driver parameter\n", __func__);
842 return;
843 }
844 if (tmp[2] == sizeof(struct venc_msg_type)) {
845 q6_msg = (struct venc_msg_type *)&tmp[3];
846 } else {
847 pr_err("%s: callback with empty message (%d, %d)\n",
848 __func__, tmp[2], sizeof(struct venc_msg_type));
849 return;
850 }
851 msg.msg_data_size = 0;
852 status = venc_translate_error(q6_msg->status);
853 switch ((enum venc_event_type_enum)q6_msg->event) {
854 case VENC_EVENT_START_STATUS:
855 dvenc->state = VENC_STATE_START;
856 msg_code = VENC_MSG_START;
857 break;
858 case VENC_EVENT_STOP_STATUS:
859 venc_q6_stop(dvenc);
860 msg_code = VENC_MSG_STOP;
861 break;
862 case VENC_EVENT_SUSPEND_STATUS:
863 dvenc->state = VENC_STATE_PAUSE;
864 msg_code = VENC_MSG_PAUSE;
865 break;
866 case VENC_EVENT_RESUME_STATUS:
867 dvenc->state = VENC_STATE_START;
868 msg_code = VENC_MSG_RESUME;
869 break;
870 case VENC_EVENT_FLUSH_STATUS:
871 smsg1.flush_ret.flush_mode = VENC_FLUSH_INPUT;
872 msg1.status_code = status;
873 msg1.msg_code = VENC_MSG_FLUSH;
874 msg1.msg_data = smsg1;
875 msg1.msg_data_size = sizeof(union venc_msg_data);
876 venc_put_msg(dvenc, &msg1);
877 smsg2.flush_ret.flush_mode = VENC_FLUSH_OUTPUT;
878 msg_code = VENC_MSG_FLUSH;
879 msg.msg_data = smsg2;
880 msg.msg_data_size = sizeof(union venc_msg_data);
881 break;
882 case VENC_EVENT_RELEASE_INPUT:
883 pload1 = &((q6_msg->payload).input_payload);
884 TRACE("Release_input: data: 0x%x \n", pload1->data);
885 if (pload1 != NULL) {
886 msg.msg_data.buf.client_data = pload1->data;
887 msg_code = VENC_MSG_INPUT_BUFFER_DONE;
888 msg.msg_data_size = sizeof(union venc_msg_data);
889 }
890 break;
891 case VENC_EVENT_DELIVER_OUTPUT:
892 pload2 = &((q6_msg->payload).output_payload);
893 smsg1.buf.flags = 0;
894 if (pload2->flags & VENC_FLAG_SYNC_FRAME)
895 smsg1.buf.flags |= VENC_FLAG_SYNC_FRAME;
896 if (pload2->flags & VENC_FLAG_CODEC_CONFIG)
897 smsg1.buf.flags |= VENC_FLAG_CODEC_CONFIG;
898 if (pload2->flags & VENC_FLAG_END_OF_FRAME)
899 smsg1.buf.flags |= VENC_FLAG_END_OF_FRAME;
900 if (pload2->flags & VENC_FLAG_EOS)
901 smsg1.buf.flags |= VENC_FLAG_EOS;
902 smsg1.buf.len = pload2->size;
903 smsg1.buf.offset = 0;
904 smsg1.buf.time_stamp = pload2->time_stamp;
905 smsg1.buf.client_data = pload2->data;
906 msg_code = VENC_MSG_OUTPUT_BUFFER_DONE;
907 msg.msg_data = smsg1;
908 msg.msg_data_size = sizeof(union venc_msg_data);
909 break;
910 default:
911 pr_err("%s: invalid response from Q6 (%d)\n", __func__,
912 (int)q6_msg->event);
913 return;
914 }
915 msg.status_code = status;
916 msg.msg_code = msg_code;
917 venc_put_msg(dvenc, &msg);
918 return;
919}
920
921static int venc_get_version(struct venc_dev *dvenc, void *argp)
922{
923 struct venc_version ver_info;
924 int ret = 0;
925
926 ver_info.major = VENC_GET_MAJOR_VERSION(VENC_INTERFACE_VERSION);
927 ver_info.minor = VENC_GET_MINOR_VERSION(VENC_INTERFACE_VERSION);
928
929 ret = copy_to_user(((struct venc_version *)argp),
930 &ver_info, sizeof(ver_info));
931 if (ret)
932 pr_err("%s failed to copy_to_user\n", __func__);
933
934 return ret;
935
936}
937
938static long q6venc_ioctl(struct file *file, u32 cmd,
939 unsigned long arg)
940{
941 long ret = 0;
942 void __user *argp = (void __user *)arg;
943 struct venc_dev *dvenc = file->private_data;
944
945 if (!dvenc || !dvenc->is_active)
946 return -EPERM;
947
948 switch (cmd) {
949 case VENC_IOCTL_SET_INPUT_BUFFER:
950 ret = venc_set_buffer(dvenc, argp, VENC_BUFFER_TYPE_INPUT);
951 break;
952 case VENC_IOCTL_SET_OUTPUT_BUFFER:
953 ret = venc_set_buffer(dvenc, argp, VENC_BUFFER_TYPE_OUTPUT);
954 break;
955 case VENC_IOCTL_GET_SEQUENCE_HDR:
956 ret = venc_get_sequence_hdr(dvenc, argp);
957 break;
958 case VENC_IOCTL_SET_QP_RANGE:
959 ret = venc_set_qp_range(dvenc, argp);
960 break;
961 case VENC_IOCTL_SET_INTRA_PERIOD:
962 ret = venc_set_intra_period(dvenc, argp);
963 break;
964 case VENC_IOCTL_SET_INTRA_REFRESH:
965 ret = venc_set_intra_refresh(dvenc, argp);
966 break;
967 case VENC_IOCTL_SET_FRAME_RATE:
968 ret = venc_set_frame_rate(dvenc, argp);
969 break;
970 case VENC_IOCTL_SET_TARGET_BITRATE:
971 ret = venc_set_target_bitrate(dvenc, argp);
972 break;
973 case VENC_IOCTL_CMD_REQUEST_IFRAME:
974 if (dvenc->state == VENC_STATE_START)
975 ret = venc_request_iframe(dvenc);
976 break;
977 case VENC_IOCTL_CMD_START:
978 ret = venc_start(dvenc, argp);
979 break;
980 case VENC_IOCTL_CMD_STOP:
981 ret = venc_stop(dvenc);
982 break;
983 case VENC_IOCTL_CMD_PAUSE:
984 ret = venc_pause(dvenc);
985 break;
986 case VENC_IOCTL_CMD_RESUME:
987 ret = venc_resume(dvenc);
988 break;
989 case VENC_IOCTL_CMD_ENCODE_FRAME:
990 ret = venc_encode_frame(dvenc, argp);
991 break;
992 case VENC_IOCTL_CMD_FILL_OUTPUT_BUFFER:
993 ret = venc_fill_output(dvenc, argp);
994 break;
995 case VENC_IOCTL_CMD_FLUSH:
996 ret = venc_flush(dvenc, argp);
997 break;
998 case VENC_IOCTL_CMD_READ_NEXT_MSG:
999 wait_event_interruptible(dvenc->venc_msg_evt,
1000 venc_get_msg(dvenc, argp));
1001 break;
1002 case VENC_IOCTL_CMD_STOP_READ_MSG:
1003 ret = venc_stop_read_msg(dvenc);
1004 break;
1005 case VENC_IOCTL_GET_VERSION:
1006 ret = venc_get_version(dvenc, argp);
1007 break;
1008 default:
1009 pr_err("%s: invalid ioctl code (%d)\n", __func__, cmd);
1010 ret = -ENOTTY;
1011 break;
1012 }
1013 return ret;
1014}
1015
1016static int q6venc_open(struct inode *inode, struct file *file)
1017{
1018 int i;
1019 int ret = 0;
1020 struct venc_dev *dvenc;
1021 struct venc_msg_list *plist, *tmp;
1022 struct dal_info version_info;
1023
1024 dvenc = kzalloc(sizeof(struct venc_dev), GFP_KERNEL);
1025 if (!dvenc) {
1026 pr_err("%s: unable to allocate memory for struct venc_dev\n",
1027 __func__);
1028 return -ENOMEM;
1029 }
1030 file->private_data = dvenc;
1031 INIT_LIST_HEAD(&dvenc->venc_msg_list_head);
1032 INIT_LIST_HEAD(&dvenc->venc_msg_list_free);
1033 INIT_LIST_HEAD(&dvenc->venc_pmem_list_head);
1034 init_waitqueue_head(&dvenc->venc_msg_evt);
1035 spin_lock_init(&dvenc->venc_msg_list_lock);
1036 spin_lock_init(&dvenc->venc_pmem_list_lock);
1037 venc_ref++;
1038 for (i = 0; i < VENC_MSG_MAX; i++) {
1039 plist = kzalloc(sizeof(struct venc_msg_list), GFP_KERNEL);
1040 if (!plist) {
1041 pr_err("%s: kzalloc failed\n", __func__);
1042 ret = -ENOMEM;
1043 goto err_venc_create_msg_list;
1044 }
1045 list_add(&plist->list, &dvenc->venc_msg_list_free);
1046 }
1047 dvenc->q6_handle =
1048 dal_attach(DALDEVICEID_VENC_DEVICE, DALDEVICEID_VENC_PORTNAME, 1,
1049 venc_q6_callback, (void *)dvenc);
1050 if (!(dvenc->q6_handle)) {
1051 pr_err("%s: daldevice_attach failed (%d)\n", __func__, ret);
1052 goto err_venc_dal_attach;
1053 }
1054 ret = dal_call_f9(dvenc->q6_handle, DAL_OP_INFO, &version_info,
1055 sizeof(struct dal_info));
1056 if (ret) {
1057 pr_err("%s: failed to get version\n", __func__);
1058 goto err_venc_dal_open;
1059 }
1060 if (venc_check_version(VENC_INTERFACE_VERSION, version_info.version)) {
1061 pr_err("%s: driver version mismatch\n", __func__);
1062 goto err_venc_dal_open;
1063 }
1064 ret = dal_call_f0(dvenc->q6_handle, DAL_OP_OPEN, 1);
1065 if (ret) {
1066 pr_err("%s: dal_call_open failed (%d)\n", __func__, ret);
1067 goto err_venc_dal_open;
1068 }
1069 dvenc->state = VENC_STATE_STOP;
1070 dvenc->is_active = 1;
1071 prevent_sleep();
1072 return ret;
1073err_venc_dal_open:
1074 dal_detach(dvenc->q6_handle);
1075err_venc_dal_attach:
1076 list_for_each_entry_safe(plist, tmp, &dvenc->venc_msg_list_free, list) {
1077 list_del(&plist->list);
1078 kfree(plist);
1079 }
1080err_venc_create_msg_list:
1081 kfree(dvenc);
1082 venc_ref--;
1083 return ret;
1084}
1085
1086static int q6venc_release(struct inode *inode, struct file *file)
1087{
1088 int ret = 0;
1089 struct venc_msg_list *l, *n;
1090 struct venc_pmem_list *plist, *m;
1091 struct venc_dev *dvenc;
1092 unsigned long flags;
1093
1094 venc_ref--;
1095 dvenc = file->private_data;
1096 dvenc->is_active = 0;
1097 wake_up_all(&dvenc->venc_msg_evt);
1098 dal_call_f0(dvenc->q6_handle, VENC_DALRPC_STOP, 1);
1099 dal_call_f0(dvenc->q6_handle, DAL_OP_CLOSE, 1);
1100 dal_detach(dvenc->q6_handle);
1101 list_for_each_entry_safe(l, n, &dvenc->venc_msg_list_free, list) {
1102 list_del(&l->list);
1103 kfree(l);
1104 }
1105 list_for_each_entry_safe(l, n, &dvenc->venc_msg_list_head, list) {
1106 list_del(&l->list);
1107 kfree(l);
1108 }
1109 spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
1110 if (!dvenc->pmem_freed) {
1111 list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list)
1112 put_pmem_file(plist->buf.file);
1113 dvenc->pmem_freed = 1;
1114 }
1115 spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
1116
1117 list_for_each_entry_safe(plist, m, &dvenc->venc_pmem_list_head, list) {
1118 list_del(&plist->list);
1119 kfree(plist);
1120 }
1121 kfree(dvenc);
1122 allow_sleep();
1123 return ret;
1124}
1125
1126const struct file_operations q6venc_fops = {
1127 .owner = THIS_MODULE,
1128 .open = q6venc_open,
1129 .release = q6venc_release,
1130 .unlocked_ioctl = q6venc_ioctl,
1131};
1132
1133static int __init q6venc_init(void)
1134{
1135 int ret = 0;
1136
Stephen Boyd2fcabf92012-05-30 10:41:11 -07001137 pm_qos_add_request(&pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
1138 PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139 wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "venc_suspend");
1140
1141 venc_device_p = kzalloc(sizeof(struct venc_dev), GFP_KERNEL);
1142 if (!venc_device_p) {
1143 pr_err("%s: unable to allocate memory for venc_device_p\n",
1144 __func__);
1145 return -ENOMEM;
1146 }
1147 ret = alloc_chrdev_region(&venc_dev_num, 0, 1, VENC_NAME);
1148 if (ret < 0) {
1149 pr_err("%s: alloc_chrdev_region failed (%d)\n", __func__,
1150 ret);
1151 return ret;
1152 }
1153 venc_class = class_create(THIS_MODULE, VENC_NAME);
1154 if (IS_ERR(venc_class)) {
1155 ret = PTR_ERR(venc_class);
1156 pr_err("%s: failed to create venc_class (%d)\n",
1157 __func__, ret);
1158 goto err_venc_class_create;
1159 }
1160 venc_device_p->class_devp =
1161 device_create(venc_class, NULL, venc_dev_num, NULL,
1162 VENC_NAME);
1163 if (IS_ERR(venc_device_p->class_devp)) {
1164 ret = PTR_ERR(venc_device_p->class_devp);
1165 pr_err("%s: failed to create class_device (%d)\n", __func__,
1166 ret);
1167 goto err_venc_class_device_create;
1168 }
1169 cdev_init(&cdev, &q6venc_fops);
1170 cdev.owner = THIS_MODULE;
1171 ret = cdev_add(&cdev, venc_dev_num, 1);
1172 if (ret < 0) {
1173 pr_err("%s: cdev_add failed (%d)\n", __func__, ret);
1174 goto err_venc_cdev_add;
1175 }
1176 init_waitqueue_head(&venc_device_p->venc_msg_evt);
1177 return ret;
1178
1179err_venc_cdev_add:
1180 device_destroy(venc_class, venc_dev_num);
1181err_venc_class_device_create:
1182 class_destroy(venc_class);
1183err_venc_class_create:
1184 unregister_chrdev_region(venc_dev_num, 1);
1185 return ret;
1186}
1187
1188static void __exit q6venc_exit(void)
1189{
1190 cdev_del(&(cdev));
1191 device_destroy(venc_class, venc_dev_num);
1192 class_destroy(venc_class);
1193 unregister_chrdev_region(venc_dev_num, 1);
1194}
1195
1196MODULE_LICENSE("GPL v2");
1197MODULE_DESCRIPTION("Video encoder driver for QDSP6");
1198MODULE_VERSION("2.0");
1199module_init(q6venc_init);
1200module_exit(q6venc_exit);