198656a
[GitHub/LineageOS/android_kernel_samsung_universal7580.git] /
1 /*
2 * Copyright (C) 2008-2009 QUALCOMM Incorporated.
3 */
4
5 #include <linux/msm_adsp.h>
6 #include <linux/uaccess.h>
7 #include <linux/fs.h>
8 #include <linux/sched.h>
9 #include <linux/android_pmem.h>
10 #include <linux/slab.h>
11 #include <mach/msm_adsp.h>
12 #include <linux/delay.h>
13 #include <linux/wait.h>
14 #include "msm_vfe7x.h"
15
16 #define QDSP_CMDQUEUE QDSP_vfeCommandQueue
17
18 #define VFE_RESET_CMD 0
19 #define VFE_START_CMD 1
20 #define VFE_STOP_CMD 2
21 #define VFE_FRAME_ACK 20
22 #define STATS_AF_ACK 21
23 #define STATS_WE_ACK 22
24
25 #define MSG_STOP_ACK 1
26 #define MSG_SNAPSHOT 2
27 #define MSG_OUTPUT1 6
28 #define MSG_OUTPUT2 7
29 #define MSG_STATS_AF 8
30 #define MSG_STATS_WE 9
31
32 static struct msm_adsp_module *qcam_mod;
33 static struct msm_adsp_module *vfe_mod;
34 static struct msm_vfe_callback *resp;
35 static void *extdata;
36 static uint32_t extlen;
37
38 struct mutex vfe_lock;
39 static void *vfe_syncdata;
40 static uint8_t vfestopped;
41
42 static struct stop_event stopevent;
43
44 static void vfe_7x_convert(struct msm_vfe_phy_info *pinfo,
45 enum vfe_resp_msg type,
46 void *data, void **ext, int32_t *elen)
47 {
48 switch (type) {
49 case VFE_MSG_OUTPUT1:
50 case VFE_MSG_OUTPUT2: {
51 pinfo->y_phy = ((struct vfe_endframe *)data)->y_address;
52 pinfo->cbcr_phy =
53 ((struct vfe_endframe *)data)->cbcr_address;
54
55 CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
56 pinfo->y_phy, pinfo->cbcr_phy);
57
58 ((struct vfe_frame_extra *)extdata)->bl_evencol =
59 ((struct vfe_endframe *)data)->blacklevelevencolumn;
60
61 ((struct vfe_frame_extra *)extdata)->bl_oddcol =
62 ((struct vfe_endframe *)data)->blackleveloddcolumn;
63
64 ((struct vfe_frame_extra *)extdata)->g_def_p_cnt =
65 ((struct vfe_endframe *)data)->greendefectpixelcount;
66
67 ((struct vfe_frame_extra *)extdata)->r_b_def_p_cnt =
68 ((struct vfe_endframe *)data)->redbluedefectpixelcount;
69
70 *ext = extdata;
71 *elen = extlen;
72 }
73 break;
74
75 case VFE_MSG_STATS_AF:
76 case VFE_MSG_STATS_WE:
77 pinfo->sbuf_phy = *(uint32_t *)data;
78 break;
79
80 default:
81 break;
82 } /* switch */
83 }
84
85 static void vfe_7x_ops(void *driver_data, unsigned id, size_t len,
86 void (*getevent)(void *ptr, size_t len))
87 {
88 uint32_t evt_buf[3];
89 struct msm_vfe_resp *rp;
90 void *data;
91
92 len = (id == (uint16_t)-1) ? 0 : len;
93 data = resp->vfe_alloc(sizeof(struct msm_vfe_resp) + len, vfe_syncdata);
94
95 if (!data) {
96 pr_err("rp: cannot allocate buffer\n");
97 return;
98 }
99 rp = (struct msm_vfe_resp *)data;
100 rp->evt_msg.len = len;
101
102 if (id == ((uint16_t)-1)) {
103 /* event */
104 rp->type = VFE_EVENT;
105 rp->evt_msg.type = MSM_CAMERA_EVT;
106 getevent(evt_buf, sizeof(evt_buf));
107 rp->evt_msg.msg_id = evt_buf[0];
108 resp->vfe_resp(rp, MSM_CAM_Q_VFE_EVT, vfe_syncdata);
109 } else {
110 /* messages */
111 rp->evt_msg.type = MSM_CAMERA_MSG;
112 rp->evt_msg.msg_id = id;
113 rp->evt_msg.data = rp + 1;
114 getevent(rp->evt_msg.data, len);
115
116 switch (rp->evt_msg.msg_id) {
117 case MSG_SNAPSHOT:
118 rp->type = VFE_MSG_SNAPSHOT;
119 break;
120
121 case MSG_OUTPUT1:
122 rp->type = VFE_MSG_OUTPUT1;
123 vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT1,
124 rp->evt_msg.data, &(rp->extdata),
125 &(rp->extlen));
126 break;
127
128 case MSG_OUTPUT2:
129 rp->type = VFE_MSG_OUTPUT2;
130 vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT2,
131 rp->evt_msg.data, &(rp->extdata),
132 &(rp->extlen));
133 break;
134
135 case MSG_STATS_AF:
136 rp->type = VFE_MSG_STATS_AF;
137 vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_AF,
138 rp->evt_msg.data, NULL, NULL);
139 break;
140
141 case MSG_STATS_WE:
142 rp->type = VFE_MSG_STATS_WE;
143 vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_WE,
144 rp->evt_msg.data, NULL, NULL);
145
146 CDBG("MSG_STATS_WE: phy = 0x%x\n", rp->phy.sbuf_phy);
147 break;
148
149 case MSG_STOP_ACK:
150 rp->type = VFE_MSG_GENERAL;
151 stopevent.state = 1;
152 wake_up(&stopevent.wait);
153 break;
154
155
156 default:
157 rp->type = VFE_MSG_GENERAL;
158 break;
159 }
160 resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe_syncdata);
161 }
162 }
163
164 static struct msm_adsp_ops vfe_7x_sync = {
165 .event = vfe_7x_ops,
166 };
167
168 static int vfe_7x_enable(struct camera_enable_cmd *enable)
169 {
170 int rc = -EFAULT;
171
172 if (!strcmp(enable->name, "QCAMTASK"))
173 rc = msm_adsp_enable(qcam_mod);
174 else if (!strcmp(enable->name, "VFETASK"))
175 rc = msm_adsp_enable(vfe_mod);
176
177 return rc;
178 }
179
180 static int vfe_7x_disable(struct camera_enable_cmd *enable,
181 struct platform_device *dev __attribute__((unused)))
182 {
183 int rc = -EFAULT;
184
185 if (!strcmp(enable->name, "QCAMTASK"))
186 rc = msm_adsp_disable(qcam_mod);
187 else if (!strcmp(enable->name, "VFETASK"))
188 rc = msm_adsp_disable(vfe_mod);
189
190 return rc;
191 }
192
193 static int vfe_7x_stop(void)
194 {
195 int rc = 0;
196 uint32_t stopcmd = VFE_STOP_CMD;
197 rc = msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
198 &stopcmd, sizeof(uint32_t));
199 if (rc < 0) {
200 CDBG("%s:%d: failed rc = %d \n", __func__, __LINE__, rc);
201 return rc;
202 }
203
204 stopevent.state = 0;
205 rc = wait_event_timeout(stopevent.wait,
206 stopevent.state != 0,
207 msecs_to_jiffies(stopevent.timeout));
208
209 return rc;
210 }
211
212 static void vfe_7x_release(struct platform_device *pdev)
213 {
214 mutex_lock(&vfe_lock);
215 vfe_syncdata = NULL;
216 mutex_unlock(&vfe_lock);
217
218 if (!vfestopped) {
219 CDBG("%s:%d:Calling vfe_7x_stop()\n", __func__, __LINE__);
220 vfe_7x_stop();
221 } else
222 vfestopped = 0;
223
224 msm_adsp_disable(qcam_mod);
225 msm_adsp_disable(vfe_mod);
226
227 msm_adsp_put(qcam_mod);
228 msm_adsp_put(vfe_mod);
229
230 msm_camio_disable(pdev);
231
232 kfree(extdata);
233 extlen = 0;
234 }
235
236 static int vfe_7x_init(struct msm_vfe_callback *presp,
237 struct platform_device *dev)
238 {
239 int rc = 0;
240
241 init_waitqueue_head(&stopevent.wait);
242 stopevent.timeout = 200;
243 stopevent.state = 0;
244
245 if (presp && presp->vfe_resp)
246 resp = presp;
247 else
248 return -EFAULT;
249
250 /* Bring up all the required GPIOs and Clocks */
251 rc = msm_camio_enable(dev);
252 if (rc < 0)
253 return rc;
254
255 msm_camio_camif_pad_reg_reset();
256
257 extlen = sizeof(struct vfe_frame_extra);
258
259 extdata = kmalloc(extlen, GFP_ATOMIC);
260 if (!extdata) {
261 rc = -ENOMEM;
262 goto init_fail;
263 }
264
265 rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL);
266 if (rc) {
267 rc = -EBUSY;
268 goto get_qcam_fail;
269 }
270
271 rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL);
272 if (rc) {
273 rc = -EBUSY;
274 goto get_vfe_fail;
275 }
276
277 return 0;
278
279 get_vfe_fail:
280 msm_adsp_put(qcam_mod);
281 get_qcam_fail:
282 kfree(extdata);
283 init_fail:
284 extlen = 0;
285 return rc;
286 }
287
288 static int vfe_7x_config_axi(int mode,
289 struct axidata *ad, struct axiout *ao)
290 {
291 struct msm_pmem_region *regptr;
292 unsigned long *bptr;
293 int cnt;
294
295 int rc = 0;
296
297 if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) {
298 regptr = ad->region;
299
300 CDBG("bufnum1 = %d\n", ad->bufnum1);
301 CDBG("config_axi1: O1, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
302 regptr->paddr, regptr->y_off, regptr->cbcr_off);
303
304 bptr = &ao->output1buffer1_y_phy;
305 for (cnt = 0; cnt < ad->bufnum1; cnt++) {
306 *bptr = regptr->paddr + regptr->y_off;
307 bptr++;
308 *bptr = regptr->paddr + regptr->cbcr_off;
309
310 bptr++;
311 regptr++;
312 }
313
314 regptr--;
315 for (cnt = 0; cnt < (8 - ad->bufnum1); cnt++) {
316 *bptr = regptr->paddr + regptr->y_off;
317 bptr++;
318 *bptr = regptr->paddr + regptr->cbcr_off;
319 bptr++;
320 }
321 } /* if OUTPUT1 or Both */
322
323 if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) {
324 regptr = &(ad->region[ad->bufnum1]);
325
326 CDBG("bufnum2 = %d\n", ad->bufnum2);
327 CDBG("config_axi2: O2, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
328 regptr->paddr, regptr->y_off, regptr->cbcr_off);
329
330 bptr = &ao->output2buffer1_y_phy;
331 for (cnt = 0; cnt < ad->bufnum2; cnt++) {
332 *bptr = regptr->paddr + regptr->y_off;
333 bptr++;
334 *bptr = regptr->paddr + regptr->cbcr_off;
335
336 bptr++;
337 regptr++;
338 }
339
340 regptr--;
341 for (cnt = 0; cnt < (8 - ad->bufnum2); cnt++) {
342 *bptr = regptr->paddr + regptr->y_off;
343 bptr++;
344 *bptr = regptr->paddr + regptr->cbcr_off;
345 bptr++;
346 }
347 }
348
349 return rc;
350 }
351
352 static int vfe_7x_config(struct msm_vfe_cfg_cmd *cmd, void *data)
353 {
354 struct msm_pmem_region *regptr;
355 unsigned char buf[256];
356
357 struct vfe_stats_ack sack;
358 struct axidata *axid;
359 uint32_t i;
360
361 struct vfe_stats_we_cfg *scfg = NULL;
362 struct vfe_stats_af_cfg *sfcfg = NULL;
363
364 struct axiout *axio = NULL;
365 void *cmd_data = NULL;
366 void *cmd_data_alloc = NULL;
367 long rc = 0;
368 struct msm_vfe_command_7k *vfecmd;
369
370 vfecmd =
371 kmalloc(sizeof(struct msm_vfe_command_7k),
372 GFP_ATOMIC);
373 if (!vfecmd) {
374 pr_err("vfecmd alloc failed!\n");
375 return -ENOMEM;
376 }
377
378 if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
379 cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
380 cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
381 if (copy_from_user(vfecmd,
382 (void __user *)(cmd->value),
383 sizeof(struct msm_vfe_command_7k))) {
384 rc = -EFAULT;
385 goto config_failure;
386 }
387 }
388
389 switch (cmd->cmd_type) {
390 case CMD_STATS_ENABLE:
391 case CMD_STATS_AXI_CFG: {
392 axid = data;
393 if (!axid) {
394 rc = -EFAULT;
395 goto config_failure;
396 }
397
398 scfg =
399 kmalloc(sizeof(struct vfe_stats_we_cfg),
400 GFP_ATOMIC);
401 if (!scfg) {
402 rc = -ENOMEM;
403 goto config_failure;
404 }
405
406 if (copy_from_user(scfg,
407 (void __user *)(vfecmd->value),
408 vfecmd->length)) {
409
410 rc = -EFAULT;
411 goto config_done;
412 }
413
414 CDBG("STATS_ENABLE: bufnum = %d, enabling = %d\n",
415 axid->bufnum1, scfg->wb_expstatsenable);
416
417 if (axid->bufnum1 > 0) {
418 regptr = axid->region;
419
420 for (i = 0; i < axid->bufnum1; i++) {
421
422 CDBG("STATS_ENABLE, phy = 0x%lx\n",
423 regptr->paddr);
424
425 scfg->wb_expstatoutputbuffer[i] =
426 (void *)regptr->paddr;
427 regptr++;
428 }
429
430 cmd_data = scfg;
431
432 } else {
433 rc = -EINVAL;
434 goto config_done;
435 }
436 }
437 break;
438
439 case CMD_STATS_AF_ENABLE:
440 case CMD_STATS_AF_AXI_CFG: {
441 axid = data;
442 if (!axid) {
443 rc = -EFAULT;
444 goto config_failure;
445 }
446
447 sfcfg =
448 kmalloc(sizeof(struct vfe_stats_af_cfg),
449 GFP_ATOMIC);
450
451 if (!sfcfg) {
452 rc = -ENOMEM;
453 goto config_failure;
454 }
455
456 if (copy_from_user(sfcfg,
457 (void __user *)(vfecmd->value),
458 vfecmd->length)) {
459
460 rc = -EFAULT;
461 goto config_done;
462 }
463
464 CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
465 axid->bufnum1, sfcfg->af_enable);
466
467 if (axid->bufnum1 > 0) {
468 regptr = axid->region;
469
470 for (i = 0; i < axid->bufnum1; i++) {
471
472 CDBG("STATS_ENABLE, phy = 0x%lx\n",
473 regptr->paddr);
474
475 sfcfg->af_outbuf[i] =
476 (void *)regptr->paddr;
477
478 regptr++;
479 }
480
481 cmd_data = sfcfg;
482
483 } else {
484 rc = -EINVAL;
485 goto config_done;
486 }
487 }
488 break;
489
490 case CMD_FRAME_BUF_RELEASE: {
491 struct msm_frame *b;
492 unsigned long p;
493 struct vfe_outputack fack;
494 if (!data) {
495 rc = -EFAULT;
496 goto config_failure;
497 }
498
499 b = (struct msm_frame *)(cmd->value);
500 p = *(unsigned long *)data;
501
502 fack.header = VFE_FRAME_ACK;
503
504 fack.output2newybufferaddress =
505 (void *)(p + b->y_off);
506
507 fack.output2newcbcrbufferaddress =
508 (void *)(p + b->cbcr_off);
509
510 vfecmd->queue = QDSP_CMDQUEUE;
511 vfecmd->length = sizeof(struct vfe_outputack);
512 cmd_data = &fack;
513 }
514 break;
515
516 case CMD_SNAP_BUF_RELEASE:
517 break;
518
519 case CMD_STATS_BUF_RELEASE: {
520 CDBG("vfe_7x_config: CMD_STATS_BUF_RELEASE\n");
521 if (!data) {
522 rc = -EFAULT;
523 goto config_failure;
524 }
525
526 sack.header = STATS_WE_ACK;
527 sack.bufaddr = (void *)*(uint32_t *)data;
528
529 vfecmd->queue = QDSP_CMDQUEUE;
530 vfecmd->length = sizeof(struct vfe_stats_ack);
531 cmd_data = &sack;
532 }
533 break;
534
535 case CMD_STATS_AF_BUF_RELEASE: {
536 CDBG("vfe_7x_config: CMD_STATS_AF_BUF_RELEASE\n");
537 if (!data) {
538 rc = -EFAULT;
539 goto config_failure;
540 }
541
542 sack.header = STATS_AF_ACK;
543 sack.bufaddr = (void *)*(uint32_t *)data;
544
545 vfecmd->queue = QDSP_CMDQUEUE;
546 vfecmd->length = sizeof(struct vfe_stats_ack);
547 cmd_data = &sack;
548 }
549 break;
550
551 case CMD_GENERAL:
552 case CMD_STATS_DISABLE: {
553 if (vfecmd->length > 256) {
554 cmd_data_alloc =
555 cmd_data = kmalloc(vfecmd->length, GFP_ATOMIC);
556 if (!cmd_data) {
557 rc = -ENOMEM;
558 goto config_failure;
559 }
560 } else
561 cmd_data = buf;
562
563 if (copy_from_user(cmd_data,
564 (void __user *)(vfecmd->value),
565 vfecmd->length)) {
566
567 rc = -EFAULT;
568 goto config_done;
569 }
570
571 if (vfecmd->queue == QDSP_CMDQUEUE) {
572 switch (*(uint32_t *)cmd_data) {
573 case VFE_RESET_CMD:
574 msm_camio_vfe_blk_reset();
575 msm_camio_camif_pad_reg_reset_2();
576 vfestopped = 0;
577 break;
578
579 case VFE_START_CMD:
580 msm_camio_camif_pad_reg_reset_2();
581 vfestopped = 0;
582 break;
583
584 case VFE_STOP_CMD:
585 vfestopped = 1;
586 goto config_send;
587
588 default:
589 break;
590 }
591 } /* QDSP_CMDQUEUE */
592 }
593 break;
594
595 case CMD_AXI_CFG_OUT1: {
596 axid = data;
597 if (!axid) {
598 rc = -EFAULT;
599 goto config_failure;
600 }
601
602 axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
603 if (!axio) {
604 rc = -ENOMEM;
605 goto config_failure;
606 }
607
608 if (copy_from_user(axio, (void *)(vfecmd->value),
609 sizeof(struct axiout))) {
610 rc = -EFAULT;
611 goto config_done;
612 }
613
614 vfe_7x_config_axi(OUTPUT_1, axid, axio);
615
616 cmd_data = axio;
617 }
618 break;
619
620 case CMD_AXI_CFG_OUT2:
621 case CMD_RAW_PICT_AXI_CFG: {
622 axid = data;
623 if (!axid) {
624 rc = -EFAULT;
625 goto config_failure;
626 }
627
628 axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
629 if (!axio) {
630 rc = -ENOMEM;
631 goto config_failure;
632 }
633
634 if (copy_from_user(axio, (void __user *)(vfecmd->value),
635 sizeof(struct axiout))) {
636 rc = -EFAULT;
637 goto config_done;
638 }
639
640 vfe_7x_config_axi(OUTPUT_2, axid, axio);
641 cmd_data = axio;
642 }
643 break;
644
645 case CMD_AXI_CFG_SNAP_O1_AND_O2: {
646 axid = data;
647 if (!axid) {
648 rc = -EFAULT;
649 goto config_failure;
650 }
651
652 axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
653 if (!axio) {
654 rc = -ENOMEM;
655 goto config_failure;
656 }
657
658 if (copy_from_user(axio, (void __user *)(vfecmd->value),
659 sizeof(struct axiout))) {
660 rc = -EFAULT;
661 goto config_done;
662 }
663
664 vfe_7x_config_axi(OUTPUT_1_AND_2, axid, axio);
665
666 cmd_data = axio;
667 }
668 break;
669
670 default:
671 break;
672 } /* switch */
673
674 if (vfestopped)
675 goto config_done;
676
677 config_send:
678 CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data);
679 rc = msm_adsp_write(vfe_mod, vfecmd->queue,
680 cmd_data, vfecmd->length);
681
682 config_done:
683 if (cmd_data_alloc != NULL)
684 kfree(cmd_data_alloc);
685
686 config_failure:
687 kfree(scfg);
688 kfree(axio);
689 kfree(vfecmd);
690 return rc;
691 }
692
693 void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
694 {
695 mutex_init(&vfe_lock);
696 fptr->vfe_init = vfe_7x_init;
697 fptr->vfe_enable = vfe_7x_enable;
698 fptr->vfe_config = vfe_7x_config;
699 fptr->vfe_disable = vfe_7x_disable;
700 fptr->vfe_release = vfe_7x_release;
701 vfe_syncdata = data;
702 }