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 <mach/msm_adsp.h>
11 #include <linux/delay.h>
12 #include <linux/wait.h>
13 #include "msm_vfe7x.h"
15 #define QDSP_CMDQUEUE QDSP_vfeCommandQueue
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
24 #define MSG_STOP_ACK 1
25 #define MSG_SNAPSHOT 2
28 #define MSG_STATS_AF 8
29 #define MSG_STATS_WE 9
31 static struct msm_adsp_module *qcam_mod;
32 static struct msm_adsp_module *vfe_mod;
33 static struct msm_vfe_callback *resp;
35 static uint32_t extlen;
37 struct mutex vfe_lock;
38 static void *vfe_syncdata;
39 static uint8_t vfestopped;
41 static struct stop_event stopevent;
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)
49 case VFE_MSG_OUTPUT2: {
50 pinfo->y_phy = ((struct vfe_endframe *)data)->y_address;
52 ((struct vfe_endframe *)data)->cbcr_address;
54 CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
55 pinfo->y_phy, pinfo->cbcr_phy);
57 ((struct vfe_frame_extra *)extdata)->bl_evencol =
58 ((struct vfe_endframe *)data)->blacklevelevencolumn;
60 ((struct vfe_frame_extra *)extdata)->bl_oddcol =
61 ((struct vfe_endframe *)data)->blackleveloddcolumn;
63 ((struct vfe_frame_extra *)extdata)->g_def_p_cnt =
64 ((struct vfe_endframe *)data)->greendefectpixelcount;
66 ((struct vfe_frame_extra *)extdata)->r_b_def_p_cnt =
67 ((struct vfe_endframe *)data)->redbluedefectpixelcount;
74 case VFE_MSG_STATS_AF:
75 case VFE_MSG_STATS_WE:
76 pinfo->sbuf_phy = *(uint32_t *)data;
84 static void vfe_7x_ops(void *driver_data, unsigned id, size_t len,
85 void (*getevent)(void *ptr, size_t len))
88 struct msm_vfe_resp *rp;
91 len = (id == (uint16_t)-1) ? 0 : len;
92 data = resp->vfe_alloc(sizeof(struct msm_vfe_resp) + len, vfe_syncdata);
95 pr_err("rp: cannot allocate buffer\n");
98 rp = (struct msm_vfe_resp *)data;
99 rp->evt_msg.len = len;
101 if (id == ((uint16_t)-1)) {
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);
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);
115 switch (rp->evt_msg.msg_id) {
117 rp->type = VFE_MSG_SNAPSHOT;
121 rp->type = VFE_MSG_OUTPUT1;
122 vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT1,
123 rp->evt_msg.data, &(rp->extdata),
128 rp->type = VFE_MSG_OUTPUT2;
129 vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT2,
130 rp->evt_msg.data, &(rp->extdata),
135 rp->type = VFE_MSG_STATS_AF;
136 vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_AF,
137 rp->evt_msg.data, NULL, NULL);
141 rp->type = VFE_MSG_STATS_WE;
142 vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_WE,
143 rp->evt_msg.data, NULL, NULL);
145 CDBG("MSG_STATS_WE: phy = 0x%x\n", rp->phy.sbuf_phy);
149 rp->type = VFE_MSG_GENERAL;
151 wake_up(&stopevent.wait);
156 rp->type = VFE_MSG_GENERAL;
159 resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe_syncdata);
163 static struct msm_adsp_ops vfe_7x_sync = {
167 static int vfe_7x_enable(struct camera_enable_cmd *enable)
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);
179 static int vfe_7x_disable(struct camera_enable_cmd *enable,
180 struct platform_device *dev __attribute__((unused)))
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);
192 static int vfe_7x_stop(void)
195 uint32_t stopcmd = VFE_STOP_CMD;
196 rc = msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
197 &stopcmd, sizeof(uint32_t));
199 CDBG("%s:%d: failed rc = %d \n", __func__, __LINE__, rc);
204 rc = wait_event_timeout(stopevent.wait,
205 stopevent.state != 0,
206 msecs_to_jiffies(stopevent.timeout));
211 static void vfe_7x_release(struct platform_device *pdev)
213 mutex_lock(&vfe_lock);
215 mutex_unlock(&vfe_lock);
218 CDBG("%s:%d:Calling vfe_7x_stop()\n", __func__, __LINE__);
223 msm_adsp_disable(qcam_mod);
224 msm_adsp_disable(vfe_mod);
226 msm_adsp_put(qcam_mod);
227 msm_adsp_put(vfe_mod);
229 msm_camio_disable(pdev);
235 static int vfe_7x_init(struct msm_vfe_callback *presp,
236 struct platform_device *dev)
240 init_waitqueue_head(&stopevent.wait);
241 stopevent.timeout = 200;
244 if (presp && presp->vfe_resp)
249 /* Bring up all the required GPIOs and Clocks */
250 rc = msm_camio_enable(dev);
254 msm_camio_camif_pad_reg_reset();
256 extlen = sizeof(struct vfe_frame_extra);
258 extdata = kmalloc(extlen, GFP_ATOMIC);
264 rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL);
270 rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL);
279 msm_adsp_put(qcam_mod);
287 static int vfe_7x_config_axi(int mode,
288 struct axidata *ad, struct axiout *ao)
290 struct msm_pmem_region *regptr;
296 if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) {
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);
303 bptr = &ao->output1buffer1_y_phy;
304 for (cnt = 0; cnt < ad->bufnum1; cnt++) {
305 *bptr = regptr->paddr + regptr->y_off;
307 *bptr = regptr->paddr + regptr->cbcr_off;
314 for (cnt = 0; cnt < (8 - ad->bufnum1); cnt++) {
315 *bptr = regptr->paddr + regptr->y_off;
317 *bptr = regptr->paddr + regptr->cbcr_off;
320 } /* if OUTPUT1 or Both */
322 if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) {
323 regptr = &(ad->region[ad->bufnum1]);
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);
329 bptr = &ao->output2buffer1_y_phy;
330 for (cnt = 0; cnt < ad->bufnum2; cnt++) {
331 *bptr = regptr->paddr + regptr->y_off;
333 *bptr = regptr->paddr + regptr->cbcr_off;
340 for (cnt = 0; cnt < (8 - ad->bufnum2); cnt++) {
341 *bptr = regptr->paddr + regptr->y_off;
343 *bptr = regptr->paddr + regptr->cbcr_off;
351 static int vfe_7x_config(struct msm_vfe_cfg_cmd *cmd, void *data)
353 struct msm_pmem_region *regptr;
354 unsigned char buf[256];
356 struct vfe_stats_ack sack;
357 struct axidata *axid;
360 struct vfe_stats_we_cfg *scfg = NULL;
361 struct vfe_stats_af_cfg *sfcfg = NULL;
363 struct axiout *axio = NULL;
364 void *cmd_data = NULL;
365 void *cmd_data_alloc = NULL;
367 struct msm_vfe_command_7k *vfecmd;
370 kmalloc(sizeof(struct msm_vfe_command_7k),
373 pr_err("vfecmd alloc failed!\n");
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))) {
388 switch (cmd->cmd_type) {
389 case CMD_STATS_ENABLE:
390 case CMD_STATS_AXI_CFG: {
398 kmalloc(sizeof(struct vfe_stats_we_cfg),
405 if (copy_from_user(scfg,
406 (void __user *)(vfecmd->value),
413 CDBG("STATS_ENABLE: bufnum = %d, enabling = %d\n",
414 axid->bufnum1, scfg->wb_expstatsenable);
416 if (axid->bufnum1 > 0) {
417 regptr = axid->region;
419 for (i = 0; i < axid->bufnum1; i++) {
421 CDBG("STATS_ENABLE, phy = 0x%lx\n",
424 scfg->wb_expstatoutputbuffer[i] =
425 (void *)regptr->paddr;
438 case CMD_STATS_AF_ENABLE:
439 case CMD_STATS_AF_AXI_CFG: {
447 kmalloc(sizeof(struct vfe_stats_af_cfg),
455 if (copy_from_user(sfcfg,
456 (void __user *)(vfecmd->value),
463 CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
464 axid->bufnum1, sfcfg->af_enable);
466 if (axid->bufnum1 > 0) {
467 regptr = axid->region;
469 for (i = 0; i < axid->bufnum1; i++) {
471 CDBG("STATS_ENABLE, phy = 0x%lx\n",
474 sfcfg->af_outbuf[i] =
475 (void *)regptr->paddr;
489 case CMD_FRAME_BUF_RELEASE: {
492 struct vfe_outputack fack;
498 b = (struct msm_frame *)(cmd->value);
499 p = *(unsigned long *)data;
501 fack.header = VFE_FRAME_ACK;
503 fack.output2newybufferaddress =
504 (void *)(p + b->y_off);
506 fack.output2newcbcrbufferaddress =
507 (void *)(p + b->cbcr_off);
509 vfecmd->queue = QDSP_CMDQUEUE;
510 vfecmd->length = sizeof(struct vfe_outputack);
515 case CMD_SNAP_BUF_RELEASE:
518 case CMD_STATS_BUF_RELEASE: {
519 CDBG("vfe_7x_config: CMD_STATS_BUF_RELEASE\n");
525 sack.header = STATS_WE_ACK;
526 sack.bufaddr = (void *)*(uint32_t *)data;
528 vfecmd->queue = QDSP_CMDQUEUE;
529 vfecmd->length = sizeof(struct vfe_stats_ack);
534 case CMD_STATS_AF_BUF_RELEASE: {
535 CDBG("vfe_7x_config: CMD_STATS_AF_BUF_RELEASE\n");
541 sack.header = STATS_AF_ACK;
542 sack.bufaddr = (void *)*(uint32_t *)data;
544 vfecmd->queue = QDSP_CMDQUEUE;
545 vfecmd->length = sizeof(struct vfe_stats_ack);
551 case CMD_STATS_DISABLE: {
552 if (vfecmd->length > 256) {
554 cmd_data = kmalloc(vfecmd->length, GFP_ATOMIC);
562 if (copy_from_user(cmd_data,
563 (void __user *)(vfecmd->value),
570 if (vfecmd->queue == QDSP_CMDQUEUE) {
571 switch (*(uint32_t *)cmd_data) {
573 msm_camio_vfe_blk_reset();
574 msm_camio_camif_pad_reg_reset_2();
579 msm_camio_camif_pad_reg_reset_2();
590 } /* QDSP_CMDQUEUE */
594 case CMD_AXI_CFG_OUT1: {
601 axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
607 if (copy_from_user(axio, (void *)(vfecmd->value),
608 sizeof(struct axiout))) {
613 vfe_7x_config_axi(OUTPUT_1, axid, axio);
619 case CMD_AXI_CFG_OUT2:
620 case CMD_RAW_PICT_AXI_CFG: {
627 axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
633 if (copy_from_user(axio, (void __user *)(vfecmd->value),
634 sizeof(struct axiout))) {
639 vfe_7x_config_axi(OUTPUT_2, axid, axio);
644 case CMD_AXI_CFG_SNAP_O1_AND_O2: {
651 axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
657 if (copy_from_user(axio, (void __user *)(vfecmd->value),
658 sizeof(struct axiout))) {
663 vfe_7x_config_axi(OUTPUT_1_AND_2, axid, axio);
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);
682 if (cmd_data_alloc != NULL)
683 kfree(cmd_data_alloc);
692 void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
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;