Ensure FMODE_NONOTIFY is not set by userspace
[pandora-kernel.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 <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 }