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