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
;