62fd24d632d5cef6ef36d5ddc757862bf7be07aa
[linux-flexiantxendom0.git] / drivers / staging / dream / camera / msm_vfe7x.c
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 <mach/msm_adsp.h>
11 #include <linux/delay.h>
12 #include <linux/wait.h>
13 #include "msm_vfe7x.h"
14
15 #define QDSP_CMDQUEUE QDSP_vfeCommandQueue
16
17 #define VFE_RESET_CMD 0
18 #define VFE_START_CMD 1
19 #define VFE_STOP_CMD  2
20 #define VFE_FRAME_ACK 20
21 #define STATS_AF_ACK  21
22 #define STATS_WE_ACK  22
23
24 #define MSG_STOP_ACK  1
25 #define MSG_SNAPSHOT  2
26 #define MSG_OUTPUT1   6
27 #define MSG_OUTPUT2   7
28 #define MSG_STATS_AF  8
29 #define MSG_STATS_WE  9
30
31 static struct msm_adsp_module *qcam_mod;
32 static struct msm_adsp_module *vfe_mod;
33 static struct msm_vfe_callback *resp;
34 static void *extdata;
35 static uint32_t extlen;
36
37 struct mutex vfe_lock;
38 static void     *vfe_syncdata;
39 static uint8_t vfestopped;
40
41 static struct stop_event stopevent;
42
43 static void vfe_7x_convert(struct msm_vfe_phy_info *pinfo,
44                 enum vfe_resp_msg type,
45                 void *data, void **ext, int32_t *elen)
46 {
47         switch (type) {
48         case VFE_MSG_OUTPUT1:
49         case VFE_MSG_OUTPUT2: {
50                 pinfo->y_phy = ((struct vfe_endframe *)data)->y_address;
51                 pinfo->cbcr_phy =
52                         ((struct vfe_endframe *)data)->cbcr_address;
53
54                 CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
55                                  pinfo->y_phy, pinfo->cbcr_phy);
56
57                 ((struct vfe_frame_extra *)extdata)->bl_evencol =
58                 ((struct vfe_endframe *)data)->blacklevelevencolumn;
59
60                 ((struct vfe_frame_extra *)extdata)->bl_oddcol =
61                 ((struct vfe_endframe *)data)->blackleveloddcolumn;
62
63                 ((struct vfe_frame_extra *)extdata)->g_def_p_cnt =
64                 ((struct vfe_endframe *)data)->greendefectpixelcount;
65
66                 ((struct vfe_frame_extra *)extdata)->r_b_def_p_cnt =
67                 ((struct vfe_endframe *)data)->redbluedefectpixelcount;
68
69                 *ext  = extdata;
70                 *elen = extlen;
71         }
72                 break;
73
74         case VFE_MSG_STATS_AF:
75         case VFE_MSG_STATS_WE:
76                 pinfo->sbuf_phy = *(uint32_t *)data;
77                 break;
78
79         default:
80                 break;
81         } /* switch */
82 }
83
84 static void vfe_7x_ops(void *driver_data, unsigned id, size_t len,
85                 void (*getevent)(void *ptr, size_t len))
86 {
87         uint32_t evt_buf[3];
88         struct msm_vfe_resp *rp;
89         void *data;
90
91         len = (id == (uint16_t)-1) ? 0 : len;
92         data = resp->vfe_alloc(sizeof(struct msm_vfe_resp) + len, vfe_syncdata);
93
94         if (!data) {
95                 pr_err("rp: cannot allocate buffer\n");
96                 return;
97         }
98         rp = (struct msm_vfe_resp *)data;
99         rp->evt_msg.len = len;
100
101         if (id == ((uint16_t)-1)) {
102                 /* event */
103                 rp->type           = VFE_EVENT;
104                 rp->evt_msg.type   = MSM_CAMERA_EVT;
105                 getevent(evt_buf, sizeof(evt_buf));
106                 rp->evt_msg.msg_id = evt_buf[0];
107                 resp->vfe_resp(rp, MSM_CAM_Q_VFE_EVT, vfe_syncdata);
108         } else {
109                 /* messages */
110                 rp->evt_msg.type   = MSM_CAMERA_MSG;
111                 rp->evt_msg.msg_id = id;
112                 rp->evt_msg.data = rp + 1;
113                 getevent(rp->evt_msg.data, len);
114
115                 switch (rp->evt_msg.msg_id) {
116                 case MSG_SNAPSHOT:
117                         rp->type = VFE_MSG_SNAPSHOT;
118                         break;
119
120                 case MSG_OUTPUT1:
121                         rp->type = VFE_MSG_OUTPUT1;
122                         vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT1,
123                                 rp->evt_msg.data, &(rp->extdata),
124                                 &(rp->extlen));
125                         break;
126
127                 case MSG_OUTPUT2:
128                         rp->type = VFE_MSG_OUTPUT2;
129                         vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT2,
130                                         rp->evt_msg.data, &(rp->extdata),
131                                         &(rp->extlen));
132                         break;
133
134                 case MSG_STATS_AF:
135                         rp->type = VFE_MSG_STATS_AF;
136                         vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_AF,
137                                         rp->evt_msg.data, NULL, NULL);
138                         break;
139
140                 case MSG_STATS_WE:
141                         rp->type = VFE_MSG_STATS_WE;
142                         vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_WE,
143                                         rp->evt_msg.data, NULL, NULL);
144
145                         CDBG("MSG_STATS_WE: phy = 0x%x\n", rp->phy.sbuf_phy);
146                         break;
147
148                 case MSG_STOP_ACK:
149                         rp->type = VFE_MSG_GENERAL;
150                         stopevent.state = 1;
151                         wake_up(&stopevent.wait);
152                         break;
153
154
155                 default:
156                         rp->type = VFE_MSG_GENERAL;
157                         break;
158                 }
159                 resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe_syncdata);
160         }
161 }
162
163 static struct msm_adsp_ops vfe_7x_sync = {
164         .event = vfe_7x_ops,
165 };
166
167 static int vfe_7x_enable(struct camera_enable_cmd *enable)
168 {
169         int rc = -EFAULT;
170
171         if (!strcmp(enable->name, "QCAMTASK"))
172                 rc = msm_adsp_enable(qcam_mod);
173         else if (!strcmp(enable->name, "VFETASK"))
174                 rc = msm_adsp_enable(vfe_mod);
175
176         return rc;
177 }
178
179 static int vfe_7x_disable(struct camera_enable_cmd *enable,
180                 struct platform_device *dev __attribute__((unused)))
181 {
182         int rc = -EFAULT;
183
184         if (!strcmp(enable->name, "QCAMTASK"))
185                 rc = msm_adsp_disable(qcam_mod);
186         else if (!strcmp(enable->name, "VFETASK"))
187                 rc = msm_adsp_disable(vfe_mod);
188
189         return rc;
190 }
191
192 static int vfe_7x_stop(void)
193 {
194         int rc = 0;
195         uint32_t stopcmd = VFE_STOP_CMD;
196         rc = msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
197                                 &stopcmd, sizeof(uint32_t));
198         if (rc < 0) {
199                 CDBG("%s:%d: failed rc = %d \n", __func__, __LINE__, rc);
200                 return rc;
201         }
202
203         stopevent.state = 0;
204         rc = wait_event_timeout(stopevent.wait,
205                 stopevent.state != 0,
206                 msecs_to_jiffies(stopevent.timeout));
207
208         return rc;
209 }
210
211 static void vfe_7x_release(struct platform_device *pdev)
212 {
213         mutex_lock(&vfe_lock);
214         vfe_syncdata = NULL;
215         mutex_unlock(&vfe_lock);
216
217         if (!vfestopped) {
218                 CDBG("%s:%d:Calling vfe_7x_stop()\n", __func__, __LINE__);
219                 vfe_7x_stop();
220         } else
221                 vfestopped = 0;
222
223         msm_adsp_disable(qcam_mod);
224         msm_adsp_disable(vfe_mod);
225
226         msm_adsp_put(qcam_mod);
227         msm_adsp_put(vfe_mod);
228
229         msm_camio_disable(pdev);
230
231         kfree(extdata);
232         extlen = 0;
233 }
234
235 static int vfe_7x_init(struct msm_vfe_callback *presp,
236         struct platform_device *dev)
237 {
238         int rc = 0;
239
240         init_waitqueue_head(&stopevent.wait);
241         stopevent.timeout = 200;
242         stopevent.state = 0;
243
244         if (presp && presp->vfe_resp)
245                 resp = presp;
246         else
247                 return -EFAULT;
248
249         /* Bring up all the required GPIOs and Clocks */
250         rc = msm_camio_enable(dev);
251         if (rc < 0)
252                 return rc;
253
254         msm_camio_camif_pad_reg_reset();
255
256         extlen = sizeof(struct vfe_frame_extra);
257
258         extdata = kmalloc(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
278 get_vfe_fail:
279         msm_adsp_put(qcam_mod);
280 get_qcam_fail:
281         kfree(extdata);
282 init_fail:
283         extlen = 0;
284         return rc;
285 }
286
287 static 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         } /* if OUTPUT1 or Both */
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
351 static 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                 } /* QDSP_CMDQUEUE */
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         } /* switch */
672
673         if (vfestopped)
674                 goto config_done;
675
676 config_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
681 config_done:
682         if (cmd_data_alloc != NULL)
683                 kfree(cmd_data_alloc);
684
685 config_failure:
686         kfree(scfg);
687         kfree(axio);
688         kfree(vfecmd);
689         return rc;
690 }
691
692 void 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 }