Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / dream / camera / msm_vfe7x.c
blob198656ac3de530ba68f39afd08b9bfa3be2fb22f
1 /*
2 * Copyright (C) 2008-2009 QUALCOMM Incorporated.
3 */
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"
16 #define QDSP_CMDQUEUE QDSP_vfeCommandQueue
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
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
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;
38 struct mutex vfe_lock;
39 static void *vfe_syncdata;
40 static uint8_t vfestopped;
42 static struct stop_event stopevent;
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)
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;
55 CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
56 pinfo->y_phy, pinfo->cbcr_phy);
58 ((struct vfe_frame_extra *)extdata)->bl_evencol =
59 ((struct vfe_endframe *)data)->blacklevelevencolumn;
61 ((struct vfe_frame_extra *)extdata)->bl_oddcol =
62 ((struct vfe_endframe *)data)->blackleveloddcolumn;
64 ((struct vfe_frame_extra *)extdata)->g_def_p_cnt =
65 ((struct vfe_endframe *)data)->greendefectpixelcount;
67 ((struct vfe_frame_extra *)extdata)->r_b_def_p_cnt =
68 ((struct vfe_endframe *)data)->redbluedefectpixelcount;
70 *ext = extdata;
71 *elen = extlen;
73 break;
75 case VFE_MSG_STATS_AF:
76 case VFE_MSG_STATS_WE:
77 pinfo->sbuf_phy = *(uint32_t *)data;
78 break;
80 default:
81 break;
82 } /* switch */
85 static void vfe_7x_ops(void *driver_data, unsigned id, size_t len,
86 void (*getevent)(void *ptr, size_t len))
88 uint32_t evt_buf[3];
89 struct msm_vfe_resp *rp;
90 void *data;
92 len = (id == (uint16_t)-1) ? 0 : len;
93 data = resp->vfe_alloc(sizeof(struct msm_vfe_resp) + len, vfe_syncdata);
95 if (!data) {
96 pr_err("rp: cannot allocate buffer\n");
97 return;
99 rp = (struct msm_vfe_resp *)data;
100 rp->evt_msg.len = len;
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);
116 switch (rp->evt_msg.msg_id) {
117 case MSG_SNAPSHOT:
118 rp->type = VFE_MSG_SNAPSHOT;
119 break;
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;
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;
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;
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);
146 CDBG("MSG_STATS_WE: phy = 0x%x\n", rp->phy.sbuf_phy);
147 break;
149 case MSG_STOP_ACK:
150 rp->type = VFE_MSG_GENERAL;
151 stopevent.state = 1;
152 wake_up(&stopevent.wait);
153 break;
156 default:
157 rp->type = VFE_MSG_GENERAL;
158 break;
160 resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe_syncdata);
164 static struct msm_adsp_ops vfe_7x_sync = {
165 .event = vfe_7x_ops,
168 static int vfe_7x_enable(struct camera_enable_cmd *enable)
170 int rc = -EFAULT;
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);
177 return rc;
180 static int vfe_7x_disable(struct camera_enable_cmd *enable,
181 struct platform_device *dev __attribute__((unused)))
183 int rc = -EFAULT;
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);
190 return rc;
193 static int vfe_7x_stop(void)
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;
204 stopevent.state = 0;
205 rc = wait_event_timeout(stopevent.wait,
206 stopevent.state != 0,
207 msecs_to_jiffies(stopevent.timeout));
209 return rc;
212 static void vfe_7x_release(struct platform_device *pdev)
214 mutex_lock(&vfe_lock);
215 vfe_syncdata = NULL;
216 mutex_unlock(&vfe_lock);
218 if (!vfestopped) {
219 CDBG("%s:%d:Calling vfe_7x_stop()\n", __func__, __LINE__);
220 vfe_7x_stop();
221 } else
222 vfestopped = 0;
224 msm_adsp_disable(qcam_mod);
225 msm_adsp_disable(vfe_mod);
227 msm_adsp_put(qcam_mod);
228 msm_adsp_put(vfe_mod);
230 msm_camio_disable(pdev);
232 kfree(extdata);
233 extlen = 0;
236 static int vfe_7x_init(struct msm_vfe_callback *presp,
237 struct platform_device *dev)
239 int rc = 0;
241 init_waitqueue_head(&stopevent.wait);
242 stopevent.timeout = 200;
243 stopevent.state = 0;
245 if (presp && presp->vfe_resp)
246 resp = presp;
247 else
248 return -EFAULT;
250 /* Bring up all the required GPIOs and Clocks */
251 rc = msm_camio_enable(dev);
252 if (rc < 0)
253 return rc;
255 msm_camio_camif_pad_reg_reset();
257 extlen = sizeof(struct vfe_frame_extra);
259 extdata = kmalloc(extlen, GFP_ATOMIC);
260 if (!extdata) {
261 rc = -ENOMEM;
262 goto init_fail;
265 rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL);
266 if (rc) {
267 rc = -EBUSY;
268 goto get_qcam_fail;
271 rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL);
272 if (rc) {
273 rc = -EBUSY;
274 goto get_vfe_fail;
277 return 0;
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;
288 static int vfe_7x_config_axi(int mode,
289 struct axidata *ad, struct axiout *ao)
291 struct msm_pmem_region *regptr;
292 unsigned long *bptr;
293 int cnt;
295 int rc = 0;
297 if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) {
298 regptr = ad->region;
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);
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;
310 bptr++;
311 regptr++;
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++;
321 } /* if OUTPUT1 or Both */
323 if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) {
324 regptr = &(ad->region[ad->bufnum1]);
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);
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;
336 bptr++;
337 regptr++;
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++;
349 return rc;
352 static int vfe_7x_config(struct msm_vfe_cfg_cmd *cmd, void *data)
354 struct msm_pmem_region *regptr;
355 unsigned char buf[256];
357 struct vfe_stats_ack sack;
358 struct axidata *axid;
359 uint32_t i;
361 struct vfe_stats_we_cfg *scfg = NULL;
362 struct vfe_stats_af_cfg *sfcfg = NULL;
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;
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;
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;
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;
398 scfg =
399 kmalloc(sizeof(struct vfe_stats_we_cfg),
400 GFP_ATOMIC);
401 if (!scfg) {
402 rc = -ENOMEM;
403 goto config_failure;
406 if (copy_from_user(scfg,
407 (void __user *)(vfecmd->value),
408 vfecmd->length)) {
410 rc = -EFAULT;
411 goto config_done;
414 CDBG("STATS_ENABLE: bufnum = %d, enabling = %d\n",
415 axid->bufnum1, scfg->wb_expstatsenable);
417 if (axid->bufnum1 > 0) {
418 regptr = axid->region;
420 for (i = 0; i < axid->bufnum1; i++) {
422 CDBG("STATS_ENABLE, phy = 0x%lx\n",
423 regptr->paddr);
425 scfg->wb_expstatoutputbuffer[i] =
426 (void *)regptr->paddr;
427 regptr++;
430 cmd_data = scfg;
432 } else {
433 rc = -EINVAL;
434 goto config_done;
437 break;
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;
447 sfcfg =
448 kmalloc(sizeof(struct vfe_stats_af_cfg),
449 GFP_ATOMIC);
451 if (!sfcfg) {
452 rc = -ENOMEM;
453 goto config_failure;
456 if (copy_from_user(sfcfg,
457 (void __user *)(vfecmd->value),
458 vfecmd->length)) {
460 rc = -EFAULT;
461 goto config_done;
464 CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
465 axid->bufnum1, sfcfg->af_enable);
467 if (axid->bufnum1 > 0) {
468 regptr = axid->region;
470 for (i = 0; i < axid->bufnum1; i++) {
472 CDBG("STATS_ENABLE, phy = 0x%lx\n",
473 regptr->paddr);
475 sfcfg->af_outbuf[i] =
476 (void *)regptr->paddr;
478 regptr++;
481 cmd_data = sfcfg;
483 } else {
484 rc = -EINVAL;
485 goto config_done;
488 break;
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;
499 b = (struct msm_frame *)(cmd->value);
500 p = *(unsigned long *)data;
502 fack.header = VFE_FRAME_ACK;
504 fack.output2newybufferaddress =
505 (void *)(p + b->y_off);
507 fack.output2newcbcrbufferaddress =
508 (void *)(p + b->cbcr_off);
510 vfecmd->queue = QDSP_CMDQUEUE;
511 vfecmd->length = sizeof(struct vfe_outputack);
512 cmd_data = &fack;
514 break;
516 case CMD_SNAP_BUF_RELEASE:
517 break;
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;
526 sack.header = STATS_WE_ACK;
527 sack.bufaddr = (void *)*(uint32_t *)data;
529 vfecmd->queue = QDSP_CMDQUEUE;
530 vfecmd->length = sizeof(struct vfe_stats_ack);
531 cmd_data = &sack;
533 break;
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;
542 sack.header = STATS_AF_ACK;
543 sack.bufaddr = (void *)*(uint32_t *)data;
545 vfecmd->queue = QDSP_CMDQUEUE;
546 vfecmd->length = sizeof(struct vfe_stats_ack);
547 cmd_data = &sack;
549 break;
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;
560 } else
561 cmd_data = buf;
563 if (copy_from_user(cmd_data,
564 (void __user *)(vfecmd->value),
565 vfecmd->length)) {
567 rc = -EFAULT;
568 goto config_done;
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;
579 case VFE_START_CMD:
580 msm_camio_camif_pad_reg_reset_2();
581 vfestopped = 0;
582 break;
584 case VFE_STOP_CMD:
585 vfestopped = 1;
586 goto config_send;
588 default:
589 break;
591 } /* QDSP_CMDQUEUE */
593 break;
595 case CMD_AXI_CFG_OUT1: {
596 axid = data;
597 if (!axid) {
598 rc = -EFAULT;
599 goto config_failure;
602 axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
603 if (!axio) {
604 rc = -ENOMEM;
605 goto config_failure;
608 if (copy_from_user(axio, (void *)(vfecmd->value),
609 sizeof(struct axiout))) {
610 rc = -EFAULT;
611 goto config_done;
614 vfe_7x_config_axi(OUTPUT_1, axid, axio);
616 cmd_data = axio;
618 break;
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;
628 axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
629 if (!axio) {
630 rc = -ENOMEM;
631 goto config_failure;
634 if (copy_from_user(axio, (void __user *)(vfecmd->value),
635 sizeof(struct axiout))) {
636 rc = -EFAULT;
637 goto config_done;
640 vfe_7x_config_axi(OUTPUT_2, axid, axio);
641 cmd_data = axio;
643 break;
645 case CMD_AXI_CFG_SNAP_O1_AND_O2: {
646 axid = data;
647 if (!axid) {
648 rc = -EFAULT;
649 goto config_failure;
652 axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
653 if (!axio) {
654 rc = -ENOMEM;
655 goto config_failure;
658 if (copy_from_user(axio, (void __user *)(vfecmd->value),
659 sizeof(struct axiout))) {
660 rc = -EFAULT;
661 goto config_done;
664 vfe_7x_config_axi(OUTPUT_1_AND_2, axid, axio);
666 cmd_data = axio;
668 break;
670 default:
671 break;
672 } /* switch */
674 if (vfestopped)
675 goto config_done;
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);
682 config_done:
683 if (cmd_data_alloc != NULL)
684 kfree(cmd_data_alloc);
686 config_failure:
687 kfree(scfg);
688 kfree(axio);
689 kfree(vfecmd);
690 return rc;
693 void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
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;