]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/dream/camera/msm_vfe7x.c
iwlwifi: don't include iwl-dev.h from iwl-devtrace.h
[net-next-2.6.git] / drivers / staging / dream / camera / msm_vfe7x.c
CommitLineData
eb7b797b
BS
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>
ace9e791 8#include <linux/sched.h>
eb7b797b
BS
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
31static struct msm_adsp_module *qcam_mod;
32static struct msm_adsp_module *vfe_mod;
33static struct msm_vfe_callback *resp;
34static void *extdata;
35static uint32_t extlen;
36
37struct mutex vfe_lock;
38static void *vfe_syncdata;
39static uint8_t vfestopped;
40
41static struct stop_event stopevent;
42
43static 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
84static 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
163static struct msm_adsp_ops vfe_7x_sync = {
164 .event = vfe_7x_ops,
165};
166
167static 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
179static 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
192static 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
211static 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
235static 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
32dbb671 258 extdata = kmalloc(extlen, GFP_ATOMIC);
eb7b797b
BS
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 } /* 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
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 } /* 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
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}