]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/staging/dream/camera/msm_vfe7x.c
Staging: dream: remove wakelock support
[net-next-2.6.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 =
259                 kmalloc(sizeof(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 }