2 * Copyright (C) 2008-2009 QUALCOMM Incorporated.
5 #include <linux/msm_adsp.h>
6 #include <linux/uaccess.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
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;
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)
50 case VFE_MSG_OUTPUT2: {
51 pinfo->y_phy = ((struct vfe_endframe *)data)->y_address;
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;
75 case VFE_MSG_STATS_AF:
76 case VFE_MSG_STATS_WE:
77 pinfo->sbuf_phy = *(uint32_t *)data;
85 static void vfe_7x_ops(void *driver_data, unsigned id, size_t len,
86 void (*getevent)(void *ptr, size_t len))
89 struct msm_vfe_resp *rp;
92 len = (id == (uint16_t)-1) ? 0 : len;
93 data = resp->vfe_alloc(sizeof(struct msm_vfe_resp) + len, vfe_syncdata);
96 pr_err("rp: cannot allocate buffer\n");
99 rp = (struct msm_vfe_resp *)data;
100 rp->evt_msg.len = len;
102 if (id == ((uint16_t)-1)) {
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);
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) {
118 rp->type = VFE_MSG_SNAPSHOT;
122 rp->type = VFE_MSG_OUTPUT1;
123 vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT1,
124 rp->evt_msg.data, &(rp->extdata),
129 rp->type = VFE_MSG_OUTPUT2;
130 vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT2,
131 rp->evt_msg.data, &(rp->extdata),
136 rp->type = VFE_MSG_STATS_AF;
137 vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_AF,
138 rp->evt_msg.data, NULL, NULL);
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);
150 rp->type = VFE_MSG_GENERAL;
152 wake_up(&stopevent.wait);
157 rp->type = VFE_MSG_GENERAL;
160 resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe_syncdata);
164 static struct msm_adsp_ops vfe_7x_sync = {
168 static int vfe_7x_enable(struct camera_enable_cmd *enable)
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);
180 static int vfe_7x_disable(struct camera_enable_cmd *enable,
181 struct platform_device *dev __attribute__((unused)))
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);
193 static int vfe_7x_stop(void)
196 uint32_t stopcmd = VFE_STOP_CMD;
197 rc = msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
198 &stopcmd, sizeof(uint32_t));
200 CDBG("%s:%d: failed rc = %d \n", __func__, __LINE__, rc);
205 rc = wait_event_timeout(stopevent.wait,
206 stopevent.state != 0,
207 msecs_to_jiffies(stopevent.timeout));
212 static void vfe_7x_release(struct platform_device *pdev)
214 mutex_lock(&vfe_lock);
216 mutex_unlock(&vfe_lock);
219 CDBG("%s:%d:Calling vfe_7x_stop()\n", __func__, __LINE__);
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);
236 static int vfe_7x_init(struct msm_vfe_callback *presp,
237 struct platform_device *dev)
241 init_waitqueue_head(&stopevent.wait);
242 stopevent.timeout = 200;
245 if (presp && presp->vfe_resp)
250 /* Bring up all the required GPIOs and Clocks */
251 rc = msm_camio_enable(dev);
255 msm_camio_camif_pad_reg_reset();
257 extlen = sizeof(struct vfe_frame_extra);
259 extdata = kmalloc(extlen, GFP_ATOMIC);
265 rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL);
271 rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL);
280 msm_adsp_put(qcam_mod);
288 static int vfe_7x_config_axi(int mode,
289 struct axidata *ad, struct axiout *ao)
291 struct msm_pmem_region *regptr;
297 if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) {
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;
308 *bptr = regptr->paddr + regptr->cbcr_off;
315 for (cnt = 0; cnt < (8 - ad->bufnum1); cnt++) {
316 *bptr = regptr->paddr + regptr->y_off;
318 *bptr = regptr->paddr + regptr->cbcr_off;
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;
334 *bptr = regptr->paddr + regptr->cbcr_off;
341 for (cnt = 0; cnt < (8 - ad->bufnum2); cnt++) {
342 *bptr = regptr->paddr + regptr->y_off;
344 *bptr = regptr->paddr + regptr->cbcr_off;
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;
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;
368 struct msm_vfe_command_7k *vfecmd;
371 kmalloc(sizeof(struct msm_vfe_command_7k),
374 pr_err("vfecmd alloc failed!\n");
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))) {
389 switch (cmd->cmd_type) {
390 case CMD_STATS_ENABLE:
391 case CMD_STATS_AXI_CFG: {
399 kmalloc(sizeof(struct vfe_stats_we_cfg),
406 if (copy_from_user(scfg,
407 (void __user *)(vfecmd->value),
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",
425 scfg->wb_expstatoutputbuffer[i] =
426 (void *)regptr->paddr;
439 case CMD_STATS_AF_ENABLE:
440 case CMD_STATS_AF_AXI_CFG: {
448 kmalloc(sizeof(struct vfe_stats_af_cfg),
456 if (copy_from_user(sfcfg,
457 (void __user *)(vfecmd->value),
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",
475 sfcfg->af_outbuf[i] =
476 (void *)regptr->paddr;
490 case CMD_FRAME_BUF_RELEASE: {
493 struct vfe_outputack fack;
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);
516 case CMD_SNAP_BUF_RELEASE:
519 case CMD_STATS_BUF_RELEASE: {
520 CDBG("vfe_7x_config: CMD_STATS_BUF_RELEASE\n");
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);
535 case CMD_STATS_AF_BUF_RELEASE: {
536 CDBG("vfe_7x_config: CMD_STATS_AF_BUF_RELEASE\n");
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);
552 case CMD_STATS_DISABLE: {
553 if (vfecmd->length > 256) {
555 cmd_data = kmalloc(vfecmd->length, GFP_ATOMIC);
563 if (copy_from_user(cmd_data,
564 (void __user *)(vfecmd->value),
571 if (vfecmd->queue == QDSP_CMDQUEUE) {
572 switch (*(uint32_t *)cmd_data) {
574 msm_camio_vfe_blk_reset();
575 msm_camio_camif_pad_reg_reset_2();
580 msm_camio_camif_pad_reg_reset_2();
591 } /* QDSP_CMDQUEUE */
595 case CMD_AXI_CFG_OUT1: {
602 axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
608 if (copy_from_user(axio, (void *)(vfecmd->value),
609 sizeof(struct axiout))) {
614 vfe_7x_config_axi(OUTPUT_1, axid, axio);
620 case CMD_AXI_CFG_OUT2:
621 case CMD_RAW_PICT_AXI_CFG: {
628 axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
634 if (copy_from_user(axio, (void __user *)(vfecmd->value),
635 sizeof(struct axiout))) {
640 vfe_7x_config_axi(OUTPUT_2, axid, axio);
645 case CMD_AXI_CFG_SNAP_O1_AND_O2: {
652 axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
658 if (copy_from_user(axio, (void __user *)(vfecmd->value),
659 sizeof(struct axiout))) {
664 vfe_7x_config_axi(OUTPUT_1_AND_2, axid, axio);
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);
683 if (cmd_data_alloc != NULL)
684 kfree(cmd_data_alloc);
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;