MLK-11508-4: V4L2 Capture: Porting MXC V4L2 Capture from 3.14.y
Initial port of the mxc V4L2 capture driver. Baseline copied from imx_3.14.y branch: Signed-off-by: Sandor Yu <R01008@freescale.com>wifi-calibration
parent
55505f11eb
commit
9bd019f585
|
@ -154,10 +154,10 @@ CONFIG_KEYBOARD_IMX=y
|
|||
CONFIG_MOUSE_PS2=m
|
||||
CONFIG_MOUSE_PS2_ELANTECH=y
|
||||
CONFIG_INPUT_TOUCHSCREEN=y
|
||||
CONFIG_TOUCHSCREEN_IMX6UL_TSC=y
|
||||
CONFIG_TOUCHSCREEN_EGALAX=y
|
||||
CONFIG_TOUCHSCREEN_ELAN=y
|
||||
CONFIG_TOUCHSCREEN_MAX11801=y
|
||||
CONFIG_TOUCHSCREEN_IMX6UL_TSC=y
|
||||
CONFIG_TOUCHSCREEN_MC13783=y
|
||||
CONFIG_TOUCHSCREEN_TSC2007=y
|
||||
CONFIG_TOUCHSCREEN_STMPE=y
|
||||
|
@ -217,10 +217,20 @@ CONFIG_MEDIA_USB_SUPPORT=y
|
|||
CONFIG_USB_VIDEO_CLASS=m
|
||||
CONFIG_V4L_PLATFORM_DRIVERS=y
|
||||
CONFIG_VIDEO_MXC_OUTPUT=y
|
||||
CONFIG_SOC_CAMERA=y
|
||||
CONFIG_VIDEO_MX3=y
|
||||
CONFIG_VIDEO_MXC_CAPTURE=m
|
||||
CONFIG_MXC_CAMERA_OV5640=m
|
||||
CONFIG_MXC_CAMERA_OV5642=m
|
||||
CONFIG_MXC_CAMERA_OV5640_MIPI=m
|
||||
CONFIG_MXC_TVIN_ADV7180=m
|
||||
CONFIG_MXC_IPU_DEVICE_QUEUE_SDC=m
|
||||
CONFIG_VIDEO_MXC_IPU_OUTPUT=y
|
||||
CONFIG_VIDEO_MXC_PXP_V4L2=y
|
||||
CONFIG_VIDEO_MXC_CSI_CAMERA=m
|
||||
CONFIG_MXC_VADC=m
|
||||
CONFIG_MXC_MIPI_CSI=m
|
||||
CONFIG_MXC_CAMERA_OV5647_MIPI=m
|
||||
CONFIG_SOC_CAMERA=y
|
||||
CONFIG_VIDEO_MX3=y
|
||||
CONFIG_V4L_MEM2MEM_DRIVERS=y
|
||||
CONFIG_VIDEO_CODA=y
|
||||
CONFIG_RADIO_SI476X=y
|
||||
|
@ -303,6 +313,8 @@ CONFIG_MXC_MLB150=m
|
|||
CONFIG_MXC_IPU_V3_PRE=y
|
||||
CONFIG_MXC_GPU_VIV=y
|
||||
CONFIG_MXC_SIM=y
|
||||
CONFIG_MXC_MIPI_CSI2=y
|
||||
CONFIG_MXC_HDMI_CEC=y
|
||||
CONFIG_NEW_LEDS=y
|
||||
CONFIG_LEDS_CLASS=y
|
||||
CONFIG_LEDS_GPIO=y
|
||||
|
|
|
@ -121,13 +121,21 @@ config VIDEO_MXC_OUTPUT
|
|||
---help---
|
||||
This is the video4linux2 output driver based on MXC module.
|
||||
|
||||
config VIDEO_MXC_CAPTURE
|
||||
tristate "MXC Video For Linux Video Capture"
|
||||
depends on VIDEO_V4L2
|
||||
---help---
|
||||
This is the video4linux2 capture driver based on i.MX video-in module.
|
||||
|
||||
source "drivers/media/platform/mxc/capture/Kconfig"
|
||||
source "drivers/media/platform/mxc/output/Kconfig"
|
||||
source "drivers/media/platform/mxc/subdev/Kconfig"
|
||||
source "drivers/media/platform/soc_camera/Kconfig"
|
||||
source "drivers/media/platform/exynos4-is/Kconfig"
|
||||
source "drivers/media/platform/s5p-tv/Kconfig"
|
||||
source "drivers/media/platform/am437x/Kconfig"
|
||||
source "drivers/media/platform/xilinx/Kconfig"
|
||||
|
||||
source "drivers/media/platform/mxc/output/Kconfig"
|
||||
|
||||
endif # V4L_PLATFORM_DRIVERS
|
||||
|
||||
|
|
|
@ -50,6 +50,8 @@ obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/
|
|||
|
||||
obj-$(CONFIG_VIDEO_XILINX) += xilinx/
|
||||
|
||||
obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc/capture/
|
||||
obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc/subdev/
|
||||
obj-$(CONFIG_VIDEO_MXC_OUTPUT) += mxc/output/
|
||||
|
||||
ccflags-y += -I$(srctree)/drivers/media/i2c
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
if VIDEO_MXC_CAPTURE
|
||||
config VIDEO_V4L2_MXC_INT_DEVICE
|
||||
tristate
|
||||
|
||||
menu "MXC Camera/V4L2 PRP Features support"
|
||||
config VIDEO_MXC_IPU_CAMERA
|
||||
bool
|
||||
select VIDEO_V4L2_MXC_INT_DEVICE
|
||||
depends on VIDEO_MXC_CAPTURE && MXC_IPU
|
||||
default y
|
||||
|
||||
config MXC_CAMERA_OV5640
|
||||
tristate "OmniVision ov5640 camera support"
|
||||
depends on !VIDEO_MXC_EMMA_CAMERA && I2C
|
||||
---help---
|
||||
If you plan to use the ov5640 Camera with your MXC system, say Y here.
|
||||
|
||||
config MXC_CAMERA_OV5642
|
||||
tristate "OmniVision ov5642 camera support"
|
||||
depends on !VIDEO_MXC_EMMA_CAMERA && I2C
|
||||
---help---
|
||||
If you plan to use the ov5642 Camera with your MXC system, say Y here.
|
||||
|
||||
config MXC_CAMERA_OV5640_MIPI
|
||||
tristate "OmniVision ov5640 camera support using mipi"
|
||||
depends on !VIDEO_MXC_EMMA_CAMERA && I2C
|
||||
---help---
|
||||
If you plan to use the ov5640 Camera with mipi interface in your MXC system, say Y here.
|
||||
|
||||
config MXC_TVIN_ADV7180
|
||||
tristate "Analog Device adv7180 TV Decoder Input support"
|
||||
depends on !VIDEO_MXC_EMMA_CAMERA && I2C
|
||||
---help---
|
||||
If you plan to use the adv7180 video decoder with your MXC system, say Y here.
|
||||
|
||||
choice
|
||||
prompt "Select Overlay Rounting"
|
||||
default MXC_IPU_DEVICE_QUEUE_SDC
|
||||
depends on VIDEO_MXC_IPU_CAMERA && FB_MXC_SYNC_PANEL
|
||||
|
||||
config MXC_IPU_DEVICE_QUEUE_SDC
|
||||
tristate "Queue ipu device for overlay library"
|
||||
depends on VIDEO_MXC_IPU_CAMERA
|
||||
---help---
|
||||
Use case CSI->MEM->IPU DEVICE->SDC:
|
||||
Images from sensor will be frist recieved in memory,then
|
||||
queue to ipu device for processing if needed, and displaying
|
||||
it on synchronous display with SDC use case.
|
||||
|
||||
config MXC_IPU_PRP_VF_SDC
|
||||
bool "Pre-Processor VF SDC library"
|
||||
depends on VIDEO_MXC_IPU_CAMERA
|
||||
---help---
|
||||
Use case PRP_VF_SDC:
|
||||
Preprocessing image from smart sensor for viewfinder and
|
||||
displaying it on synchronous display with SDC use case.
|
||||
If SDC BG is selected, Rotation will not be supported.
|
||||
CSI -> IC (PRP VF) -> MEM
|
||||
MEM -> IC (ROT) -> MEM
|
||||
MEM -> SDC (FG/BG)
|
||||
|
||||
endchoice
|
||||
|
||||
config MXC_IPU_PRP_ENC
|
||||
tristate "Pre-processor Encoder library"
|
||||
depends on VIDEO_MXC_IPU_CAMERA
|
||||
default y
|
||||
---help---
|
||||
Use case PRP_ENC:
|
||||
Preprocessing image from smart sensor for encoder.
|
||||
CSI -> IC (PRP ENC) -> MEM
|
||||
|
||||
config MXC_IPU_CSI_ENC
|
||||
tristate "IPU CSI Encoder library"
|
||||
depends on VIDEO_MXC_IPU_CAMERA
|
||||
default y
|
||||
---help---
|
||||
Use case IPU_CSI_ENC:
|
||||
Get raw image with CSI from smart sensor for encoder.
|
||||
CSI -> MEM
|
||||
endmenu
|
||||
|
||||
endif
|
|
@ -0,0 +1,21 @@
|
|||
ifeq ($(CONFIG_VIDEO_MXC_IPU_CAMERA),y)
|
||||
obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc_v4l2_capture.o
|
||||
obj-$(CONFIG_MXC_IPU_PRP_VF_SDC) += ipu_prp_vf_sdc.o ipu_prp_vf_sdc_bg.o
|
||||
obj-$(CONFIG_MXC_IPU_DEVICE_QUEUE_SDC) += ipu_fg_overlay_sdc.o ipu_bg_overlay_sdc.o
|
||||
obj-$(CONFIG_MXC_IPU_PRP_ENC) += ipu_prp_enc.o ipu_still.o
|
||||
obj-$(CONFIG_MXC_IPU_CSI_ENC) += ipu_csi_enc.o ipu_still.o
|
||||
endif
|
||||
|
||||
ov5640_camera_int-objs := ov5640.o
|
||||
obj-$(CONFIG_MXC_CAMERA_OV5640) += ov5640_camera_int.o
|
||||
|
||||
ov5642_camera-objs := ov5642.o
|
||||
obj-$(CONFIG_MXC_CAMERA_OV5642) += ov5642_camera.o
|
||||
|
||||
ov5640_camera_mipi_int-objs := ov5640_mipi.o
|
||||
obj-$(CONFIG_MXC_CAMERA_OV5640_MIPI) += ov5640_camera_mipi_int.o
|
||||
|
||||
adv7180_tvin-objs := adv7180.o
|
||||
obj-$(CONFIG_MXC_TVIN_ADV7180) += adv7180_tvin.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_V4L2_MXC_INT_DEVICE) += v4l2-int-device.o
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,552 @@
|
|||
|
||||
/*
|
||||
* Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file ipu_bg_overlay_sdc_bg.c
|
||||
*
|
||||
* @brief IPU Use case for PRP-VF back-ground
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/ipu.h>
|
||||
#include <linux/mipi_csi2.h>
|
||||
#include "mxc_v4l2_capture.h"
|
||||
#include "ipu_prp_sw.h"
|
||||
|
||||
static int csi_buffer_num;
|
||||
static u32 bpp, csi_mem_bufsize = 3;
|
||||
static u32 out_format;
|
||||
static struct ipu_soc *disp_ipu;
|
||||
static u32 offset;
|
||||
|
||||
static void csi_buf_work_func(struct work_struct *work)
|
||||
{
|
||||
int err = 0;
|
||||
cam_data *cam =
|
||||
container_of(work, struct _cam_data, csi_work_struct);
|
||||
|
||||
struct ipu_task task;
|
||||
memset(&task, 0, sizeof(task));
|
||||
|
||||
if (csi_buffer_num)
|
||||
task.input.paddr = cam->vf_bufs[0];
|
||||
else
|
||||
task.input.paddr = cam->vf_bufs[1];
|
||||
task.input.width = cam->crop_current.width;
|
||||
task.input.height = cam->crop_current.height;
|
||||
task.input.format = IPU_PIX_FMT_UYVY;
|
||||
|
||||
task.output.paddr = offset;
|
||||
task.output.width = cam->overlay_fb->var.xres;
|
||||
task.output.height = cam->overlay_fb->var.yres;
|
||||
task.output.format = out_format;
|
||||
task.output.rotate = cam->rotation;
|
||||
task.output.crop.pos.x = cam->win.w.left;
|
||||
task.output.crop.pos.y = cam->win.w.top;
|
||||
if (cam->win.w.width > 1024 || cam->win.w.height > 1024) {
|
||||
task.output.crop.w = cam->overlay_fb->var.xres;
|
||||
task.output.crop.h = cam->overlay_fb->var.yres;
|
||||
} else {
|
||||
task.output.crop.w = cam->win.w.width;
|
||||
task.output.crop.h = cam->win.w.height;
|
||||
}
|
||||
again:
|
||||
err = ipu_check_task(&task);
|
||||
if (err != IPU_CHECK_OK) {
|
||||
if (err > IPU_CHECK_ERR_MIN) {
|
||||
if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) {
|
||||
task.input.crop.w -= 8;
|
||||
goto again;
|
||||
}
|
||||
if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) {
|
||||
task.input.crop.h -= 8;
|
||||
goto again;
|
||||
}
|
||||
if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) {
|
||||
task.output.width -= 8;
|
||||
task.output.crop.w = task.output.width;
|
||||
goto again;
|
||||
}
|
||||
if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) {
|
||||
task.output.height -= 8;
|
||||
task.output.crop.h = task.output.height;
|
||||
goto again;
|
||||
}
|
||||
printk(KERN_ERR "check ipu taks fail\n");
|
||||
return;
|
||||
}
|
||||
printk(KERN_ERR "check ipu taks fail\n");
|
||||
return;
|
||||
}
|
||||
err = ipu_queue_task(&task);
|
||||
if (err < 0)
|
||||
printk(KERN_ERR "queue ipu task error\n");
|
||||
}
|
||||
|
||||
static void get_disp_ipu(cam_data *cam)
|
||||
{
|
||||
if (cam->output > 2)
|
||||
disp_ipu = ipu_get_soc(1); /* using DISP4 */
|
||||
else
|
||||
disp_ipu = ipu_get_soc(0);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* csi ENC callback function.
|
||||
*
|
||||
* @param irq int irq line
|
||||
* @param dev_id void * device id
|
||||
*
|
||||
* @return status IRQ_HANDLED for handled
|
||||
*/
|
||||
static irqreturn_t csi_enc_callback(int irq, void *dev_id)
|
||||
{
|
||||
cam_data *cam = (cam_data *) dev_id;
|
||||
ipu_channel_t chan = (irq == IPU_IRQ_CSI0_OUT_EOF) ?
|
||||
CSI_MEM0 : CSI_MEM1;
|
||||
|
||||
ipu_select_buffer(cam->ipu, chan,
|
||||
IPU_OUTPUT_BUFFER, csi_buffer_num);
|
||||
schedule_work(&cam->csi_work_struct);
|
||||
csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int csi_enc_setup(cam_data *cam)
|
||||
{
|
||||
ipu_channel_params_t params;
|
||||
u32 pixel_fmt;
|
||||
int err = 0, sensor_protocol = 0;
|
||||
ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
void *mipi_csi2_info;
|
||||
int ipu_id;
|
||||
int csi_id;
|
||||
#endif
|
||||
|
||||
if (!cam) {
|
||||
printk(KERN_ERR "cam private is NULL\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
memset(¶ms, 0, sizeof(ipu_channel_params_t));
|
||||
params.csi_mem.csi = cam->csi;
|
||||
|
||||
sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
|
||||
switch (sensor_protocol) {
|
||||
case IPU_CSI_CLK_MODE_GATED_CLK:
|
||||
case IPU_CSI_CLK_MODE_NONGATED_CLK:
|
||||
case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
|
||||
case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
|
||||
case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
|
||||
params.csi_mem.interlaced = false;
|
||||
break;
|
||||
case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
|
||||
case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
|
||||
case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
|
||||
params.csi_mem.interlaced = true;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "sensor protocol unsupported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
mipi_csi2_info = mipi_csi2_get_info();
|
||||
|
||||
if (mipi_csi2_info) {
|
||||
if (mipi_csi2_get_status(mipi_csi2_info)) {
|
||||
ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
|
||||
csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
|
||||
|
||||
if (cam->ipu == ipu_get_soc(ipu_id)
|
||||
&& cam->csi == csi_id) {
|
||||
params.csi_mem.mipi_en = true;
|
||||
params.csi_mem.mipi_vc =
|
||||
mipi_csi2_get_virtual_channel(mipi_csi2_info);
|
||||
params.csi_mem.mipi_id =
|
||||
mipi_csi2_get_datatype(mipi_csi2_info);
|
||||
|
||||
mipi_csi2_pixelclk_enable(mipi_csi2_info);
|
||||
} else {
|
||||
params.csi_mem.mipi_en = false;
|
||||
params.csi_mem.mipi_vc = 0;
|
||||
params.csi_mem.mipi_id = 0;
|
||||
}
|
||||
} else {
|
||||
params.csi_mem.mipi_en = false;
|
||||
params.csi_mem.mipi_vc = 0;
|
||||
params.csi_mem.mipi_id = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cam->vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[0],
|
||||
cam->vf_bufs_vaddr[0],
|
||||
(dma_addr_t) cam->vf_bufs[0]);
|
||||
}
|
||||
if (cam->vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[1],
|
||||
cam->vf_bufs_vaddr[1],
|
||||
(dma_addr_t) cam->vf_bufs[1]);
|
||||
}
|
||||
csi_mem_bufsize =
|
||||
cam->crop_current.width * cam->crop_current.height * 2;
|
||||
cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize);
|
||||
cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
|
||||
cam->vf_bufs_size[0],
|
||||
(dma_addr_t *) &
|
||||
cam->vf_bufs[0],
|
||||
GFP_DMA |
|
||||
GFP_KERNEL);
|
||||
if (cam->vf_bufs_vaddr[0] == NULL) {
|
||||
printk(KERN_ERR "Error to allocate vf buffer\n");
|
||||
err = -ENOMEM;
|
||||
goto out_2;
|
||||
}
|
||||
cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize);
|
||||
cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
|
||||
cam->vf_bufs_size[1],
|
||||
(dma_addr_t *) &
|
||||
cam->vf_bufs[1],
|
||||
GFP_DMA |
|
||||
GFP_KERNEL);
|
||||
if (cam->vf_bufs_vaddr[1] == NULL) {
|
||||
printk(KERN_ERR "Error to allocate vf buffer\n");
|
||||
err = -ENOMEM;
|
||||
goto out_1;
|
||||
}
|
||||
pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
|
||||
|
||||
err = ipu_init_channel(cam->ipu, chan, ¶ms);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "ipu_init_channel %d\n", err);
|
||||
goto out_1;
|
||||
}
|
||||
|
||||
pixel_fmt = IPU_PIX_FMT_UYVY;
|
||||
err = ipu_init_channel_buffer(
|
||||
cam->ipu, chan, IPU_OUTPUT_BUFFER, pixel_fmt,
|
||||
cam->crop_current.width, cam->crop_current.height,
|
||||
cam->crop_current.width, IPU_ROTATE_NONE,
|
||||
cam->vf_bufs[0], cam->vf_bufs[1], 0,
|
||||
cam->offset.u_offset, cam->offset.u_offset);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "CSI_MEM output buffer\n");
|
||||
goto out_1;
|
||||
}
|
||||
err = ipu_enable_channel(cam->ipu, chan);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
|
||||
goto out_1;
|
||||
}
|
||||
|
||||
csi_buffer_num = 0;
|
||||
|
||||
ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 0);
|
||||
ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 1);
|
||||
return err;
|
||||
out_1:
|
||||
if (cam->vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[0],
|
||||
cam->vf_bufs_vaddr[0],
|
||||
(dma_addr_t) cam->vf_bufs[0]);
|
||||
cam->vf_bufs_vaddr[0] = NULL;
|
||||
cam->vf_bufs[0] = 0;
|
||||
}
|
||||
if (cam->vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[1],
|
||||
cam->vf_bufs_vaddr[1],
|
||||
(dma_addr_t) cam->vf_bufs[1]);
|
||||
cam->vf_bufs_vaddr[1] = NULL;
|
||||
cam->vf_bufs[1] = 0;
|
||||
}
|
||||
out_2:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Enable encoder task
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int csi_enc_enabling_tasks(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0;
|
||||
|
||||
ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi);
|
||||
err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi,
|
||||
csi_enc_callback, 0, "Mxc Camera", cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error registering CSI_OUT_EOF irq\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
INIT_WORK(&cam->csi_work_struct, csi_buf_work_func);
|
||||
|
||||
err = csi_enc_setup(cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "csi_enc_setup %d\n", err);
|
||||
goto out1;
|
||||
}
|
||||
|
||||
return err;
|
||||
out1:
|
||||
ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* bg_overlay_start - start the overlay task
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
*/
|
||||
static int bg_overlay_start(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0;
|
||||
|
||||
if (!cam) {
|
||||
printk(KERN_ERR "private is NULL\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (cam->overlay_active == true) {
|
||||
pr_debug("already start.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
get_disp_ipu(cam);
|
||||
|
||||
out_format = cam->v4l2_fb.fmt.pixelformat;
|
||||
if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) {
|
||||
bpp = 3, csi_mem_bufsize = 3;
|
||||
pr_info("BGR24\n");
|
||||
} else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) {
|
||||
bpp = 2, csi_mem_bufsize = 2;
|
||||
pr_info("RGB565\n");
|
||||
} else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) {
|
||||
bpp = 4, csi_mem_bufsize = 4;
|
||||
pr_info("BGR32\n");
|
||||
} else {
|
||||
printk(KERN_ERR
|
||||
"unsupported fix format from the framebuffer.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top +
|
||||
csi_mem_bufsize * cam->win.w.left;
|
||||
|
||||
if (cam->v4l2_fb.base == 0)
|
||||
printk(KERN_ERR "invalid frame buffer address.\n");
|
||||
else
|
||||
offset += (u32) cam->v4l2_fb.base;
|
||||
|
||||
csi_mem_bufsize = cam->win.w.width * cam->win.w.height
|
||||
* csi_mem_bufsize;
|
||||
|
||||
err = csi_enc_enabling_tasks(cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error csi enc enable fail\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
cam->overlay_active = true;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* bg_overlay_stop - stop the overlay task
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
*/
|
||||
static int bg_overlay_stop(void *private)
|
||||
{
|
||||
int err = 0;
|
||||
cam_data *cam = (cam_data *) private;
|
||||
ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
void *mipi_csi2_info;
|
||||
int ipu_id;
|
||||
int csi_id;
|
||||
#endif
|
||||
|
||||
if (cam->overlay_active == false)
|
||||
return 0;
|
||||
|
||||
err = ipu_disable_channel(cam->ipu, chan, true);
|
||||
|
||||
ipu_uninit_channel(cam->ipu, chan);
|
||||
|
||||
csi_buffer_num = 0;
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
mipi_csi2_info = mipi_csi2_get_info();
|
||||
|
||||
if (mipi_csi2_info) {
|
||||
if (mipi_csi2_get_status(mipi_csi2_info)) {
|
||||
ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
|
||||
csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
|
||||
|
||||
if (cam->ipu == ipu_get_soc(ipu_id)
|
||||
&& cam->csi == csi_id)
|
||||
mipi_csi2_pixelclk_disable(mipi_csi2_info);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
flush_work(&cam->csi_work_struct);
|
||||
cancel_work_sync(&cam->csi_work_struct);
|
||||
|
||||
if (cam->vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[0],
|
||||
cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
|
||||
cam->vf_bufs_vaddr[0] = NULL;
|
||||
cam->vf_bufs[0] = 0;
|
||||
}
|
||||
if (cam->vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[1],
|
||||
cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
|
||||
cam->vf_bufs_vaddr[1] = NULL;
|
||||
cam->vf_bufs[1] = 0;
|
||||
}
|
||||
if (cam->rot_vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->rot_vf_buf_size[0],
|
||||
cam->rot_vf_bufs_vaddr[0],
|
||||
cam->rot_vf_bufs[0]);
|
||||
cam->rot_vf_bufs_vaddr[0] = NULL;
|
||||
cam->rot_vf_bufs[0] = 0;
|
||||
}
|
||||
if (cam->rot_vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->rot_vf_buf_size[1],
|
||||
cam->rot_vf_bufs_vaddr[1],
|
||||
cam->rot_vf_bufs[1]);
|
||||
cam->rot_vf_bufs_vaddr[1] = NULL;
|
||||
cam->rot_vf_bufs[1] = 0;
|
||||
}
|
||||
|
||||
cam->overlay_active = false;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Enable csi
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int bg_overlay_enable_csi(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
return ipu_enable_csi(cam->ipu, cam->csi);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Disable csi
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int bg_overlay_disable_csi(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
/* free csi eof irq firstly.
|
||||
* when disable csi, wait for idmac eof.
|
||||
* it requests eof irq again */
|
||||
ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam);
|
||||
|
||||
return ipu_disable_csi(cam->ipu, cam->csi);
|
||||
}
|
||||
|
||||
/*!
|
||||
* function to select bg as the working path
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
int bg_overlay_sdc_select(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
if (cam) {
|
||||
cam->vf_start_sdc = bg_overlay_start;
|
||||
cam->vf_stop_sdc = bg_overlay_stop;
|
||||
cam->vf_enable_csi = bg_overlay_enable_csi;
|
||||
cam->vf_disable_csi = bg_overlay_disable_csi;
|
||||
cam->overlay_active = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(bg_overlay_sdc_select);
|
||||
|
||||
/*!
|
||||
* function to de-select bg as the working path
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
int bg_overlay_sdc_deselect(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
if (cam) {
|
||||
cam->vf_start_sdc = NULL;
|
||||
cam->vf_stop_sdc = NULL;
|
||||
cam->vf_enable_csi = NULL;
|
||||
cam->vf_disable_csi = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(bg_overlay_sdc_deselect);
|
||||
|
||||
/*!
|
||||
* Init background overlay task.
|
||||
*
|
||||
* @return Error code indicating success or failure
|
||||
*/
|
||||
__init int bg_overlay_sdc_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Deinit background overlay task.
|
||||
*
|
||||
* @return Error code indicating success or failure
|
||||
*/
|
||||
void __exit bg_overlay_sdc_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(bg_overlay_sdc_init);
|
||||
module_exit(bg_overlay_sdc_exit);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
* Copyright 2009-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file ipu_csi_enc.c
|
||||
*
|
||||
* @brief CSI Use case for video capture
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/ipu.h>
|
||||
#include <linux/mipi_csi2.h>
|
||||
#include "mxc_v4l2_capture.h"
|
||||
#include "ipu_prp_sw.h"
|
||||
|
||||
#ifdef CAMERA_DBG
|
||||
#define CAMERA_TRACE(x) (printk)x
|
||||
#else
|
||||
#define CAMERA_TRACE(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Function definitions
|
||||
*/
|
||||
|
||||
/*!
|
||||
* csi ENC callback function.
|
||||
*
|
||||
* @param irq int irq line
|
||||
* @param dev_id void * device id
|
||||
*
|
||||
* @return status IRQ_HANDLED for handled
|
||||
*/
|
||||
static irqreturn_t csi_enc_callback(int irq, void *dev_id)
|
||||
{
|
||||
cam_data *cam = (cam_data *) dev_id;
|
||||
|
||||
if (cam->enc_callback == NULL)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
cam->enc_callback(irq, dev_id);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*!
|
||||
* CSI ENC enable channel setup function
|
||||
*
|
||||
* @param cam struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int csi_enc_setup(cam_data *cam)
|
||||
{
|
||||
ipu_channel_params_t params;
|
||||
u32 pixel_fmt;
|
||||
int err = 0, sensor_protocol = 0;
|
||||
dma_addr_t dummy = cam->dummy_frame.buffer.m.offset;
|
||||
ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
void *mipi_csi2_info;
|
||||
int ipu_id;
|
||||
int csi_id;
|
||||
#endif
|
||||
|
||||
CAMERA_TRACE("In csi_enc_setup\n");
|
||||
if (!cam) {
|
||||
printk(KERN_ERR "cam private is NULL\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
memset(¶ms, 0, sizeof(ipu_channel_params_t));
|
||||
params.csi_mem.csi = cam->csi;
|
||||
|
||||
sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
|
||||
switch (sensor_protocol) {
|
||||
case IPU_CSI_CLK_MODE_GATED_CLK:
|
||||
case IPU_CSI_CLK_MODE_NONGATED_CLK:
|
||||
case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
|
||||
case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
|
||||
case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
|
||||
params.csi_mem.interlaced = false;
|
||||
break;
|
||||
case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
|
||||
case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
|
||||
case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
|
||||
params.csi_mem.interlaced = true;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "sensor protocol unsupported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
|
||||
pixel_fmt = IPU_PIX_FMT_YUV420P;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420)
|
||||
pixel_fmt = IPU_PIX_FMT_YVU420P;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P)
|
||||
pixel_fmt = IPU_PIX_FMT_YUV422P;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
|
||||
pixel_fmt = IPU_PIX_FMT_UYVY;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
|
||||
pixel_fmt = IPU_PIX_FMT_YUYV;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)
|
||||
pixel_fmt = IPU_PIX_FMT_NV12;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
|
||||
pixel_fmt = IPU_PIX_FMT_BGR24;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
|
||||
pixel_fmt = IPU_PIX_FMT_RGB24;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565)
|
||||
pixel_fmt = IPU_PIX_FMT_RGB565;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32)
|
||||
pixel_fmt = IPU_PIX_FMT_BGR32;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32)
|
||||
pixel_fmt = IPU_PIX_FMT_RGB32;
|
||||
else {
|
||||
printk(KERN_ERR "format not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
mipi_csi2_info = mipi_csi2_get_info();
|
||||
|
||||
if (mipi_csi2_info) {
|
||||
if (mipi_csi2_get_status(mipi_csi2_info)) {
|
||||
ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
|
||||
csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
|
||||
|
||||
if (cam->ipu == ipu_get_soc(ipu_id)
|
||||
&& cam->csi == csi_id) {
|
||||
params.csi_mem.mipi_en = true;
|
||||
params.csi_mem.mipi_vc =
|
||||
mipi_csi2_get_virtual_channel(mipi_csi2_info);
|
||||
params.csi_mem.mipi_id =
|
||||
mipi_csi2_get_datatype(mipi_csi2_info);
|
||||
|
||||
mipi_csi2_pixelclk_enable(mipi_csi2_info);
|
||||
} else {
|
||||
params.csi_mem.mipi_en = false;
|
||||
params.csi_mem.mipi_vc = 0;
|
||||
params.csi_mem.mipi_id = 0;
|
||||
}
|
||||
} else {
|
||||
params.csi_mem.mipi_en = false;
|
||||
params.csi_mem.mipi_vc = 0;
|
||||
params.csi_mem.mipi_id = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
err = ipu_init_channel(cam->ipu, chan, ¶ms);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "ipu_init_channel %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ipu_init_channel_buffer(cam->ipu,
|
||||
chan,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
pixel_fmt, cam->v2f.fmt.pix.width,
|
||||
cam->v2f.fmt.pix.height,
|
||||
cam->v2f.fmt.pix.bytesperline,
|
||||
IPU_ROTATE_NONE,
|
||||
dummy, dummy, 0,
|
||||
cam->offset.u_offset,
|
||||
cam->offset.v_offset);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "CSI_MEM output buffer\n");
|
||||
return err;
|
||||
}
|
||||
err = ipu_enable_channel(cam->ipu, chan);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* function to update physical buffer address for encorder IDMA channel
|
||||
*
|
||||
* @param *private pointer to the cam_data structure
|
||||
* @param eba physical buffer address for encorder IDMA channel
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int csi_enc_eba_update(void *private, dma_addr_t eba)
|
||||
{
|
||||
int err = 0;
|
||||
cam_data *cam = (cam_data *) private;
|
||||
struct ipu_soc *ipu = cam->ipu;
|
||||
int *buffer_num = &cam->ping_pong_csi;
|
||||
ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
|
||||
|
||||
pr_debug("eba %x\n", eba);
|
||||
err = ipu_update_channel_buffer(ipu, chan, IPU_OUTPUT_BUFFER,
|
||||
*buffer_num, eba);
|
||||
if (err != 0) {
|
||||
ipu_clear_buffer_ready(ipu, chan, IPU_OUTPUT_BUFFER,
|
||||
*buffer_num);
|
||||
|
||||
err = ipu_update_channel_buffer(ipu, chan,
|
||||
IPU_OUTPUT_BUFFER, *buffer_num, eba);
|
||||
if (err != 0) {
|
||||
pr_err("ERROR: v4l2 capture: fail to update "
|
||||
"buf%d\n", *buffer_num);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
ipu_select_buffer(ipu, chan, IPU_OUTPUT_BUFFER, *buffer_num);
|
||||
|
||||
*buffer_num = (*buffer_num == 0) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Enable encoder task
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int csi_enc_enabling_tasks(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0;
|
||||
uint32_t irq = (cam->csi == 0) ?
|
||||
IPU_IRQ_CSI0_OUT_EOF : IPU_IRQ_CSI1_OUT_EOF;
|
||||
|
||||
CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n");
|
||||
|
||||
cam->dummy_frame.vaddress = dma_alloc_coherent(0,
|
||||
PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
|
||||
&cam->dummy_frame.paddress,
|
||||
GFP_DMA | GFP_KERNEL);
|
||||
if (cam->dummy_frame.vaddress == 0) {
|
||||
pr_err("ERROR: v4l2 capture: Allocate dummy frame "
|
||||
"failed.\n");
|
||||
return -ENOBUFS;
|
||||
}
|
||||
cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE;
|
||||
cam->dummy_frame.buffer.length =
|
||||
PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
|
||||
cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress;
|
||||
|
||||
ipu_clear_irq(cam->ipu, irq);
|
||||
err = ipu_request_irq(
|
||||
cam->ipu, irq, csi_enc_callback, 0, "Mxc Camera", cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error registering rot irq\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = csi_enc_setup(cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "csi_enc_setup %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Disable encoder task
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
static int csi_enc_disabling_tasks(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0;
|
||||
ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
void *mipi_csi2_info;
|
||||
int ipu_id;
|
||||
int csi_id;
|
||||
#endif
|
||||
|
||||
err = ipu_disable_channel(cam->ipu, chan, true);
|
||||
|
||||
ipu_uninit_channel(cam->ipu, chan);
|
||||
|
||||
if (cam->dummy_frame.vaddress != 0) {
|
||||
dma_free_coherent(0, cam->dummy_frame.buffer.length,
|
||||
cam->dummy_frame.vaddress,
|
||||
cam->dummy_frame.paddress);
|
||||
cam->dummy_frame.vaddress = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
mipi_csi2_info = mipi_csi2_get_info();
|
||||
|
||||
if (mipi_csi2_info) {
|
||||
if (mipi_csi2_get_status(mipi_csi2_info)) {
|
||||
ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
|
||||
csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
|
||||
|
||||
if (cam->ipu == ipu_get_soc(ipu_id)
|
||||
&& cam->csi == csi_id)
|
||||
mipi_csi2_pixelclk_disable(mipi_csi2_info);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Enable csi
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int csi_enc_enable_csi(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
return ipu_enable_csi(cam->ipu, cam->csi);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Disable csi
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int csi_enc_disable_csi(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
uint32_t irq = (cam->csi == 0) ?
|
||||
IPU_IRQ_CSI0_OUT_EOF : IPU_IRQ_CSI1_OUT_EOF;
|
||||
|
||||
/* free csi eof irq firstly.
|
||||
* when disable csi, wait for idmac eof.
|
||||
* it requests eof irq again */
|
||||
ipu_free_irq(cam->ipu, irq, cam);
|
||||
|
||||
return ipu_disable_csi(cam->ipu, cam->csi);
|
||||
}
|
||||
|
||||
/*!
|
||||
* function to select CSI ENC as the working path
|
||||
*
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int csi_enc_select(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0;
|
||||
|
||||
if (cam) {
|
||||
cam->enc_update_eba = csi_enc_eba_update;
|
||||
cam->enc_enable = csi_enc_enabling_tasks;
|
||||
cam->enc_disable = csi_enc_disabling_tasks;
|
||||
cam->enc_enable_csi = csi_enc_enable_csi;
|
||||
cam->enc_disable_csi = csi_enc_disable_csi;
|
||||
} else {
|
||||
err = -EIO;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(csi_enc_select);
|
||||
|
||||
/*!
|
||||
* function to de-select CSI ENC as the working path
|
||||
*
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int csi_enc_deselect(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0;
|
||||
|
||||
if (cam) {
|
||||
cam->enc_update_eba = NULL;
|
||||
cam->enc_enable = NULL;
|
||||
cam->enc_disable = NULL;
|
||||
cam->enc_enable_csi = NULL;
|
||||
cam->enc_disable_csi = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(csi_enc_deselect);
|
||||
|
||||
/*!
|
||||
* Init the Encorder channels
|
||||
*
|
||||
* @return Error code indicating success or failure
|
||||
*/
|
||||
__init int csi_enc_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Deinit the Encorder channels
|
||||
*
|
||||
*/
|
||||
void __exit csi_enc_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(csi_enc_init);
|
||||
module_exit(csi_enc_exit);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("CSI ENC Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,638 @@
|
|||
/*
|
||||
* Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
/* * The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file ipu_foreground_sdc.c
|
||||
*
|
||||
* @brief IPU Use case for PRP-VF
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/ipu.h>
|
||||
#include <linux/mxcfb.h>
|
||||
#include <linux/mipi_csi2.h>
|
||||
|
||||
#include "mxc_v4l2_capture.h"
|
||||
#include "ipu_prp_sw.h"
|
||||
|
||||
#ifdef CAMERA_DBG
|
||||
#define CAMERA_TRACE(x) (printk)x
|
||||
#else
|
||||
#define CAMERA_TRACE(x)
|
||||
#endif
|
||||
|
||||
static int csi_buffer_num, buffer_num;
|
||||
static u32 csi_mem_bufsize;
|
||||
static struct ipu_soc *disp_ipu;
|
||||
static struct fb_info *fbi;
|
||||
static struct fb_var_screeninfo fbvar;
|
||||
static u32 vf_out_format;
|
||||
static void csi_buf_work_func(struct work_struct *work)
|
||||
{
|
||||
int err = 0;
|
||||
cam_data *cam =
|
||||
container_of(work, struct _cam_data, csi_work_struct);
|
||||
|
||||
struct ipu_task task;
|
||||
memset(&task, 0, sizeof(task));
|
||||
|
||||
if (csi_buffer_num)
|
||||
task.input.paddr = cam->vf_bufs[0];
|
||||
else
|
||||
task.input.paddr = cam->vf_bufs[1];
|
||||
task.input.width = cam->crop_current.width;
|
||||
task.input.height = cam->crop_current.height;
|
||||
task.input.format = IPU_PIX_FMT_NV12;
|
||||
|
||||
if (buffer_num == 0)
|
||||
task.output.paddr = fbi->fix.smem_start +
|
||||
(fbi->fix.line_length * fbvar.yres);
|
||||
else
|
||||
task.output.paddr = fbi->fix.smem_start;
|
||||
task.output.width = cam->win.w.width;
|
||||
task.output.height = cam->win.w.height;
|
||||
task.output.format = vf_out_format;
|
||||
task.output.rotate = cam->rotation;
|
||||
again:
|
||||
err = ipu_check_task(&task);
|
||||
if (err != IPU_CHECK_OK) {
|
||||
if (err > IPU_CHECK_ERR_MIN) {
|
||||
if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) {
|
||||
task.input.crop.w -= 8;
|
||||
goto again;
|
||||
}
|
||||
if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) {
|
||||
task.input.crop.h -= 8;
|
||||
goto again;
|
||||
}
|
||||
if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) {
|
||||
task.output.width -= 8;
|
||||
task.output.crop.w = task.output.width;
|
||||
goto again;
|
||||
}
|
||||
if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) {
|
||||
task.output.height -= 8;
|
||||
task.output.crop.h = task.output.height;
|
||||
goto again;
|
||||
}
|
||||
printk(KERN_ERR "check ipu taks fail\n");
|
||||
return;
|
||||
}
|
||||
printk(KERN_ERR "check ipu taks fail\n");
|
||||
return;
|
||||
}
|
||||
err = ipu_queue_task(&task);
|
||||
if (err < 0)
|
||||
printk(KERN_ERR "queue ipu task error\n");
|
||||
ipu_select_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, buffer_num);
|
||||
buffer_num = (buffer_num == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void get_disp_ipu(cam_data *cam)
|
||||
{
|
||||
if (cam->output > 2)
|
||||
disp_ipu = ipu_get_soc(1); /* using DISP4 */
|
||||
else
|
||||
disp_ipu = ipu_get_soc(0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* csi ENC callback function.
|
||||
*
|
||||
* @param irq int irq line
|
||||
* @param dev_id void * device id
|
||||
*
|
||||
* @return status IRQ_HANDLED for handled
|
||||
*/
|
||||
static irqreturn_t csi_enc_callback(int irq, void *dev_id)
|
||||
{
|
||||
cam_data *cam = (cam_data *) dev_id;
|
||||
ipu_channel_t chan = (irq == IPU_IRQ_CSI0_OUT_EOF) ?
|
||||
CSI_MEM0 : CSI_MEM1;
|
||||
|
||||
ipu_select_buffer(cam->ipu, chan,
|
||||
IPU_OUTPUT_BUFFER, csi_buffer_num);
|
||||
|
||||
if ((cam->crop_current.width != cam->win.w.width) ||
|
||||
(cam->crop_current.height != cam->win.w.height) ||
|
||||
(vf_out_format != IPU_PIX_FMT_NV12) ||
|
||||
(cam->rotation >= IPU_ROTATE_VERT_FLIP))
|
||||
schedule_work(&cam->csi_work_struct);
|
||||
csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int csi_enc_setup(cam_data *cam)
|
||||
{
|
||||
ipu_channel_params_t params;
|
||||
int err = 0, sensor_protocol = 0;
|
||||
ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
void *mipi_csi2_info;
|
||||
int ipu_id;
|
||||
int csi_id;
|
||||
#endif
|
||||
|
||||
CAMERA_TRACE("In csi_enc_setup\n");
|
||||
if (!cam) {
|
||||
printk(KERN_ERR "cam private is NULL\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
memset(¶ms, 0, sizeof(ipu_channel_params_t));
|
||||
params.csi_mem.csi = cam->csi;
|
||||
|
||||
sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
|
||||
switch (sensor_protocol) {
|
||||
case IPU_CSI_CLK_MODE_GATED_CLK:
|
||||
case IPU_CSI_CLK_MODE_NONGATED_CLK:
|
||||
case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
|
||||
case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
|
||||
case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
|
||||
params.csi_mem.interlaced = false;
|
||||
break;
|
||||
case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
|
||||
case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
|
||||
case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
|
||||
params.csi_mem.interlaced = true;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "sensor protocol unsupported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
mipi_csi2_info = mipi_csi2_get_info();
|
||||
|
||||
if (mipi_csi2_info) {
|
||||
if (mipi_csi2_get_status(mipi_csi2_info)) {
|
||||
ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
|
||||
csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
|
||||
|
||||
if (cam->ipu == ipu_get_soc(ipu_id)
|
||||
&& cam->csi == csi_id) {
|
||||
params.csi_mem.mipi_en = true;
|
||||
params.csi_mem.mipi_vc =
|
||||
mipi_csi2_get_virtual_channel(mipi_csi2_info);
|
||||
params.csi_mem.mipi_id =
|
||||
mipi_csi2_get_datatype(mipi_csi2_info);
|
||||
|
||||
mipi_csi2_pixelclk_enable(mipi_csi2_info);
|
||||
} else {
|
||||
params.csi_mem.mipi_en = false;
|
||||
params.csi_mem.mipi_vc = 0;
|
||||
params.csi_mem.mipi_id = 0;
|
||||
}
|
||||
} else {
|
||||
params.csi_mem.mipi_en = false;
|
||||
params.csi_mem.mipi_vc = 0;
|
||||
params.csi_mem.mipi_id = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cam->vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[0],
|
||||
cam->vf_bufs_vaddr[0],
|
||||
(dma_addr_t) cam->vf_bufs[0]);
|
||||
}
|
||||
if (cam->vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[1],
|
||||
cam->vf_bufs_vaddr[1],
|
||||
(dma_addr_t) cam->vf_bufs[1]);
|
||||
}
|
||||
csi_mem_bufsize = cam->crop_current.width *
|
||||
cam->crop_current.height * 3/2;
|
||||
cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize);
|
||||
cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
|
||||
cam->vf_bufs_size[0],
|
||||
(dma_addr_t *) &
|
||||
cam->vf_bufs[0],
|
||||
GFP_DMA |
|
||||
GFP_KERNEL);
|
||||
if (cam->vf_bufs_vaddr[0] == NULL) {
|
||||
printk(KERN_ERR "Error to allocate vf buffer\n");
|
||||
err = -ENOMEM;
|
||||
goto out_2;
|
||||
}
|
||||
cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize);
|
||||
cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
|
||||
cam->vf_bufs_size[1],
|
||||
(dma_addr_t *) &
|
||||
cam->vf_bufs[1],
|
||||
GFP_DMA |
|
||||
GFP_KERNEL);
|
||||
if (cam->vf_bufs_vaddr[1] == NULL) {
|
||||
printk(KERN_ERR "Error to allocate vf buffer\n");
|
||||
err = -ENOMEM;
|
||||
goto out_1;
|
||||
}
|
||||
pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
|
||||
|
||||
err = ipu_init_channel(cam->ipu, chan, ¶ms);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "ipu_init_channel %d\n", err);
|
||||
goto out_1;
|
||||
}
|
||||
|
||||
if ((cam->crop_current.width == cam->win.w.width) &&
|
||||
(cam->crop_current.height == cam->win.w.height) &&
|
||||
(vf_out_format == IPU_PIX_FMT_NV12) &&
|
||||
(cam->rotation < IPU_ROTATE_VERT_FLIP)) {
|
||||
err = ipu_init_channel_buffer(cam->ipu, chan,
|
||||
IPU_OUTPUT_BUFFER, IPU_PIX_FMT_NV12,
|
||||
cam->crop_current.width,
|
||||
cam->crop_current.height,
|
||||
cam->crop_current.width, IPU_ROTATE_NONE,
|
||||
fbi->fix.smem_start +
|
||||
(fbi->fix.line_length * fbvar.yres),
|
||||
fbi->fix.smem_start, 0,
|
||||
cam->offset.u_offset, cam->offset.u_offset);
|
||||
} else {
|
||||
err = ipu_init_channel_buffer(cam->ipu, chan,
|
||||
IPU_OUTPUT_BUFFER, IPU_PIX_FMT_NV12,
|
||||
cam->crop_current.width,
|
||||
cam->crop_current.height,
|
||||
cam->crop_current.width, IPU_ROTATE_NONE,
|
||||
cam->vf_bufs[0], cam->vf_bufs[1], 0,
|
||||
cam->offset.u_offset, cam->offset.u_offset);
|
||||
}
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "CSI_MEM output buffer\n");
|
||||
goto out_1;
|
||||
}
|
||||
err = ipu_enable_channel(cam->ipu, chan);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
|
||||
goto out_1;
|
||||
}
|
||||
|
||||
csi_buffer_num = 0;
|
||||
|
||||
ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 0);
|
||||
ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 1);
|
||||
return err;
|
||||
out_1:
|
||||
if (cam->vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[0],
|
||||
cam->vf_bufs_vaddr[0],
|
||||
(dma_addr_t) cam->vf_bufs[0]);
|
||||
cam->vf_bufs_vaddr[0] = NULL;
|
||||
cam->vf_bufs[0] = 0;
|
||||
}
|
||||
if (cam->vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[1],
|
||||
cam->vf_bufs_vaddr[1],
|
||||
(dma_addr_t) cam->vf_bufs[1]);
|
||||
cam->vf_bufs_vaddr[1] = NULL;
|
||||
cam->vf_bufs[1] = 0;
|
||||
}
|
||||
out_2:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Enable encoder task
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int csi_enc_enabling_tasks(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0;
|
||||
CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n");
|
||||
|
||||
ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi);
|
||||
err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi,
|
||||
csi_enc_callback, 0, "Mxc Camera", cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error registering CSI_OUT_EOF irq\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
INIT_WORK(&cam->csi_work_struct, csi_buf_work_func);
|
||||
|
||||
err = csi_enc_setup(cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "csi_enc_setup %d\n", err);
|
||||
goto out1;
|
||||
}
|
||||
|
||||
return err;
|
||||
out1:
|
||||
ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function definitions
|
||||
*/
|
||||
|
||||
/*!
|
||||
* foreground_start - start the vf task
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
*/
|
||||
static int foreground_start(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0, i = 0, screen_size;
|
||||
char *base;
|
||||
|
||||
if (!cam) {
|
||||
printk(KERN_ERR "private is NULL\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (cam->overlay_active == true) {
|
||||
pr_debug("already started.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
get_disp_ipu(cam);
|
||||
|
||||
for (i = 0; i < num_registered_fb; i++) {
|
||||
char *idstr = registered_fb[i]->fix.id;
|
||||
if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
|
||||
((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
|
||||
fbi = registered_fb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fbi == NULL) {
|
||||
printk(KERN_ERR "DISP FG fb not found\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
fbvar = fbi->var;
|
||||
|
||||
/* Store the overlay frame buffer's original std */
|
||||
cam->fb_origin_std = fbvar.nonstd;
|
||||
|
||||
if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) {
|
||||
/* Use DP to do CSC so that we can get better performance */
|
||||
vf_out_format = IPU_PIX_FMT_NV12;
|
||||
fbvar.nonstd = vf_out_format;
|
||||
} else {
|
||||
vf_out_format = IPU_PIX_FMT_RGB565;
|
||||
fbvar.nonstd = 0;
|
||||
}
|
||||
|
||||
fbvar.bits_per_pixel = 16;
|
||||
fbvar.xres = fbvar.xres_virtual = cam->win.w.width;
|
||||
fbvar.yres = cam->win.w.height;
|
||||
fbvar.yres_virtual = cam->win.w.height * 2;
|
||||
fbvar.yoffset = 0;
|
||||
fbvar.vmode &= ~FB_VMODE_YWRAP;
|
||||
fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG;
|
||||
fbvar.activate |= FB_ACTIVATE_FORCE;
|
||||
fb_set_var(fbi, &fbvar);
|
||||
|
||||
ipu_disp_set_window_pos(disp_ipu, MEM_FG_SYNC, cam->win.w.left,
|
||||
cam->win.w.top);
|
||||
|
||||
/* Fill black color for framebuffer */
|
||||
base = (char *) fbi->screen_base;
|
||||
screen_size = fbi->var.xres * fbi->var.yres;
|
||||
if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) {
|
||||
memset(base, 0, screen_size);
|
||||
base += screen_size;
|
||||
for (i = 0; i < screen_size / 2; i++, base++)
|
||||
*base = 0x80;
|
||||
} else {
|
||||
for (i = 0; i < screen_size * 2; i++, base++)
|
||||
*base = 0x00;
|
||||
}
|
||||
|
||||
console_lock();
|
||||
fb_blank(fbi, FB_BLANK_UNBLANK);
|
||||
console_unlock();
|
||||
|
||||
/* correct display ch buffer address */
|
||||
ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
|
||||
0, fbi->fix.smem_start +
|
||||
(fbi->fix.line_length * fbvar.yres));
|
||||
ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
|
||||
1, fbi->fix.smem_start);
|
||||
|
||||
err = csi_enc_enabling_tasks(cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error csi enc enable fail\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
cam->overlay_active = true;
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* foreground_stop - stop the vf task
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
*/
|
||||
static int foreground_stop(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0, i = 0;
|
||||
struct fb_info *fbi = NULL;
|
||||
struct fb_var_screeninfo fbvar;
|
||||
ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
void *mipi_csi2_info;
|
||||
int ipu_id;
|
||||
int csi_id;
|
||||
#endif
|
||||
|
||||
if (cam->overlay_active == false)
|
||||
return 0;
|
||||
|
||||
err = ipu_disable_channel(cam->ipu, chan, true);
|
||||
|
||||
ipu_uninit_channel(cam->ipu, chan);
|
||||
|
||||
csi_buffer_num = 0;
|
||||
buffer_num = 0;
|
||||
|
||||
for (i = 0; i < num_registered_fb; i++) {
|
||||
char *idstr = registered_fb[i]->fix.id;
|
||||
if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
|
||||
((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
|
||||
fbi = registered_fb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fbi == NULL) {
|
||||
printk(KERN_ERR "DISP FG fb not found\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
console_lock();
|
||||
fb_blank(fbi, FB_BLANK_POWERDOWN);
|
||||
console_unlock();
|
||||
|
||||
/* Set the overlay frame buffer std to what it is used to be */
|
||||
fbvar = fbi->var;
|
||||
fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG;
|
||||
fbvar.nonstd = cam->fb_origin_std;
|
||||
fbvar.activate |= FB_ACTIVATE_FORCE;
|
||||
fb_set_var(fbi, &fbvar);
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
mipi_csi2_info = mipi_csi2_get_info();
|
||||
|
||||
if (mipi_csi2_info) {
|
||||
if (mipi_csi2_get_status(mipi_csi2_info)) {
|
||||
ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
|
||||
csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
|
||||
|
||||
if (cam->ipu == ipu_get_soc(ipu_id)
|
||||
&& cam->csi == csi_id)
|
||||
mipi_csi2_pixelclk_disable(mipi_csi2_info);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
flush_work(&cam->csi_work_struct);
|
||||
cancel_work_sync(&cam->csi_work_struct);
|
||||
|
||||
if (cam->vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[0],
|
||||
cam->vf_bufs_vaddr[0],
|
||||
(dma_addr_t) cam->vf_bufs[0]);
|
||||
cam->vf_bufs_vaddr[0] = NULL;
|
||||
cam->vf_bufs[0] = 0;
|
||||
}
|
||||
if (cam->vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[1],
|
||||
cam->vf_bufs_vaddr[1],
|
||||
(dma_addr_t) cam->vf_bufs[1]);
|
||||
cam->vf_bufs_vaddr[1] = NULL;
|
||||
cam->vf_bufs[1] = 0;
|
||||
}
|
||||
|
||||
cam->overlay_active = false;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Enable csi
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int foreground_enable_csi(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
return ipu_enable_csi(cam->ipu, cam->csi);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Disable csi
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int foreground_disable_csi(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
/* free csi eof irq firstly.
|
||||
* when disable csi, wait for idmac eof.
|
||||
* it requests eof irq again */
|
||||
ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam);
|
||||
|
||||
return ipu_disable_csi(cam->ipu, cam->csi);
|
||||
}
|
||||
|
||||
/*!
|
||||
* function to select foreground as the working path
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
int foreground_sdc_select(void *private)
|
||||
{
|
||||
cam_data *cam;
|
||||
int err = 0;
|
||||
if (private) {
|
||||
cam = (cam_data *) private;
|
||||
cam->vf_start_sdc = foreground_start;
|
||||
cam->vf_stop_sdc = foreground_stop;
|
||||
cam->vf_enable_csi = foreground_enable_csi;
|
||||
cam->vf_disable_csi = foreground_disable_csi;
|
||||
cam->overlay_active = false;
|
||||
} else
|
||||
err = -EIO;
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(foreground_sdc_select);
|
||||
|
||||
/*!
|
||||
* function to de-select foreground as the working path
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int foreground_sdc_deselect(void *private)
|
||||
{
|
||||
cam_data *cam;
|
||||
|
||||
if (private) {
|
||||
cam = (cam_data *) private;
|
||||
cam->vf_start_sdc = NULL;
|
||||
cam->vf_stop_sdc = NULL;
|
||||
cam->vf_enable_csi = NULL;
|
||||
cam->vf_disable_csi = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(foreground_sdc_deselect);
|
||||
|
||||
/*!
|
||||
* Init viewfinder task.
|
||||
*
|
||||
* @return Error code indicating success or failure
|
||||
*/
|
||||
__init int foreground_sdc_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Deinit viewfinder task.
|
||||
*
|
||||
* @return Error code indicating success or failure
|
||||
*/
|
||||
void __exit foreground_sdc_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(foreground_sdc_init);
|
||||
module_exit(foreground_sdc_exit);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("IPU PRP VF SDC Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,597 @@
|
|||
/*
|
||||
* Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file ipu_prp_enc.c
|
||||
*
|
||||
* @brief IPU Use case for PRP-ENC
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/ipu.h>
|
||||
#include <linux/mipi_csi2.h>
|
||||
#include "mxc_v4l2_capture.h"
|
||||
#include "ipu_prp_sw.h"
|
||||
|
||||
#ifdef CAMERA_DBG
|
||||
#define CAMERA_TRACE(x) (printk)x
|
||||
#else
|
||||
#define CAMERA_TRACE(x)
|
||||
#endif
|
||||
|
||||
static ipu_rotate_mode_t grotation = IPU_ROTATE_NONE;
|
||||
|
||||
/*
|
||||
* Function definitions
|
||||
*/
|
||||
|
||||
/*!
|
||||
* IPU ENC callback function.
|
||||
*
|
||||
* @param irq int irq line
|
||||
* @param dev_id void * device id
|
||||
*
|
||||
* @return status IRQ_HANDLED for handled
|
||||
*/
|
||||
static irqreturn_t prp_enc_callback(int irq, void *dev_id)
|
||||
{
|
||||
cam_data *cam = (cam_data *) dev_id;
|
||||
|
||||
if (cam->enc_callback == NULL)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
cam->enc_callback(irq, dev_id);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*!
|
||||
* PrpENC enable channel setup function
|
||||
*
|
||||
* @param cam struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int prp_enc_setup(cam_data *cam)
|
||||
{
|
||||
ipu_channel_params_t enc;
|
||||
int err = 0;
|
||||
dma_addr_t dummy = cam->dummy_frame.buffer.m.offset;
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
void *mipi_csi2_info;
|
||||
int ipu_id;
|
||||
int csi_id;
|
||||
#endif
|
||||
|
||||
CAMERA_TRACE("In prp_enc_setup\n");
|
||||
if (!cam) {
|
||||
printk(KERN_ERR "cam private is NULL\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
memset(&enc, 0, sizeof(ipu_channel_params_t));
|
||||
|
||||
ipu_csi_get_window_size(cam->ipu, &enc.csi_prp_enc_mem.in_width,
|
||||
&enc.csi_prp_enc_mem.in_height, cam->csi);
|
||||
|
||||
enc.csi_prp_enc_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
|
||||
enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.width;
|
||||
enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.height;
|
||||
enc.csi_prp_enc_mem.csi = cam->csi;
|
||||
if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
|
||||
enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.height;
|
||||
enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.width;
|
||||
}
|
||||
|
||||
if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV420P;
|
||||
pr_info("YUV420\n");
|
||||
} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) {
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YVU420P;
|
||||
pr_info("YVU420\n");
|
||||
} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) {
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV422P;
|
||||
pr_info("YUV422P\n");
|
||||
} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUYV;
|
||||
pr_info("YUYV\n");
|
||||
} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) {
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_UYVY;
|
||||
pr_info("UYVY\n");
|
||||
} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) {
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_NV12;
|
||||
pr_info("NV12\n");
|
||||
} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) {
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR24;
|
||||
pr_info("BGR24\n");
|
||||
} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB24;
|
||||
pr_info("RGB24\n");
|
||||
} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB565;
|
||||
pr_info("RGB565\n");
|
||||
} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) {
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR32;
|
||||
pr_info("BGR32\n");
|
||||
} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) {
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB32;
|
||||
pr_info("RGB32\n");
|
||||
} else {
|
||||
printk(KERN_ERR "format not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
mipi_csi2_info = mipi_csi2_get_info();
|
||||
|
||||
if (mipi_csi2_info) {
|
||||
if (mipi_csi2_get_status(mipi_csi2_info)) {
|
||||
ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
|
||||
csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
|
||||
|
||||
if (cam->ipu == ipu_get_soc(ipu_id)
|
||||
&& cam->csi == csi_id) {
|
||||
enc.csi_prp_enc_mem.mipi_en = true;
|
||||
enc.csi_prp_enc_mem.mipi_vc =
|
||||
mipi_csi2_get_virtual_channel(mipi_csi2_info);
|
||||
enc.csi_prp_enc_mem.mipi_id =
|
||||
mipi_csi2_get_datatype(mipi_csi2_info);
|
||||
|
||||
mipi_csi2_pixelclk_enable(mipi_csi2_info);
|
||||
} else {
|
||||
enc.csi_prp_enc_mem.mipi_en = false;
|
||||
enc.csi_prp_enc_mem.mipi_vc = 0;
|
||||
enc.csi_prp_enc_mem.mipi_id = 0;
|
||||
}
|
||||
} else {
|
||||
enc.csi_prp_enc_mem.mipi_en = false;
|
||||
enc.csi_prp_enc_mem.mipi_vc = 0;
|
||||
enc.csi_prp_enc_mem.mipi_id = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
err = ipu_init_channel(cam->ipu, CSI_PRP_ENC_MEM, &enc);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "ipu_init_channel %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
grotation = cam->rotation;
|
||||
if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
|
||||
if (cam->rot_enc_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->rot_enc_buf_size[0],
|
||||
cam->rot_enc_bufs_vaddr[0],
|
||||
cam->rot_enc_bufs[0]);
|
||||
}
|
||||
if (cam->rot_enc_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->rot_enc_buf_size[1],
|
||||
cam->rot_enc_bufs_vaddr[1],
|
||||
cam->rot_enc_bufs[1]);
|
||||
}
|
||||
cam->rot_enc_buf_size[0] =
|
||||
PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
|
||||
cam->rot_enc_bufs_vaddr[0] =
|
||||
(void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[0],
|
||||
&cam->rot_enc_bufs[0],
|
||||
GFP_DMA | GFP_KERNEL);
|
||||
if (!cam->rot_enc_bufs_vaddr[0]) {
|
||||
printk(KERN_ERR "alloc enc_bufs0\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
cam->rot_enc_buf_size[1] =
|
||||
PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
|
||||
cam->rot_enc_bufs_vaddr[1] =
|
||||
(void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[1],
|
||||
&cam->rot_enc_bufs[1],
|
||||
GFP_DMA | GFP_KERNEL);
|
||||
if (!cam->rot_enc_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->rot_enc_buf_size[0],
|
||||
cam->rot_enc_bufs_vaddr[0],
|
||||
cam->rot_enc_bufs[0]);
|
||||
cam->rot_enc_bufs_vaddr[0] = NULL;
|
||||
cam->rot_enc_bufs[0] = 0;
|
||||
printk(KERN_ERR "alloc enc_bufs1\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt,
|
||||
enc.csi_prp_enc_mem.out_width,
|
||||
enc.csi_prp_enc_mem.out_height,
|
||||
enc.csi_prp_enc_mem.out_width,
|
||||
IPU_ROTATE_NONE,
|
||||
cam->rot_enc_bufs[0],
|
||||
cam->rot_enc_bufs[1], 0, 0, 0);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "CSI_PRP_ENC_MEM err\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ipu_init_channel(cam->ipu, MEM_ROT_ENC_MEM, NULL);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "MEM_ROT_ENC_MEM channel err\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM,
|
||||
IPU_INPUT_BUFFER,
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt,
|
||||
enc.csi_prp_enc_mem.out_width,
|
||||
enc.csi_prp_enc_mem.out_height,
|
||||
enc.csi_prp_enc_mem.out_width,
|
||||
cam->rotation,
|
||||
cam->rot_enc_bufs[0],
|
||||
cam->rot_enc_bufs[1], 0, 0, 0);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "MEM_ROT_ENC_MEM input buffer\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err =
|
||||
ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt,
|
||||
enc.csi_prp_enc_mem.out_height,
|
||||
enc.csi_prp_enc_mem.out_width,
|
||||
cam->v2f.fmt.pix.bytesperline /
|
||||
bytes_per_pixel(enc.csi_prp_enc_mem.
|
||||
out_pixel_fmt),
|
||||
IPU_ROTATE_NONE,
|
||||
dummy, dummy, 0,
|
||||
cam->offset.u_offset,
|
||||
cam->offset.v_offset);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "MEM_ROT_ENC_MEM output buffer\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ipu_link_channels(cam->ipu,
|
||||
CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR
|
||||
"link CSI_PRP_ENC_MEM-MEM_ROT_ENC_MEM\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n");
|
||||
return err;
|
||||
}
|
||||
err = ipu_enable_channel(cam->ipu, MEM_ROT_ENC_MEM);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "ipu_enable_channel MEM_ROT_ENC_MEM\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM,
|
||||
IPU_OUTPUT_BUFFER, 0);
|
||||
ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM,
|
||||
IPU_OUTPUT_BUFFER, 1);
|
||||
} else {
|
||||
err =
|
||||
ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
enc.csi_prp_enc_mem.out_pixel_fmt,
|
||||
enc.csi_prp_enc_mem.out_width,
|
||||
enc.csi_prp_enc_mem.out_height,
|
||||
cam->v2f.fmt.pix.bytesperline /
|
||||
bytes_per_pixel(enc.csi_prp_enc_mem.
|
||||
out_pixel_fmt),
|
||||
cam->rotation,
|
||||
dummy, dummy, 0,
|
||||
cam->offset.u_offset,
|
||||
cam->offset.v_offset);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "CSI_PRP_ENC_MEM output buffer\n");
|
||||
return err;
|
||||
}
|
||||
err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* function to update physical buffer address for encorder IDMA channel
|
||||
*
|
||||
* @param private pointer to cam_data structure
|
||||
* @param eba physical buffer address for encorder IDMA channel
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int prp_enc_eba_update(void *private, dma_addr_t eba)
|
||||
{
|
||||
int err = 0;
|
||||
cam_data *cam = (cam_data *) private;
|
||||
struct ipu_soc *ipu = cam->ipu;
|
||||
int *buffer_num = &cam->ping_pong_csi;
|
||||
|
||||
pr_debug("eba %x\n", eba);
|
||||
if (grotation >= IPU_ROTATE_90_RIGHT) {
|
||||
err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM,
|
||||
IPU_OUTPUT_BUFFER, *buffer_num,
|
||||
eba);
|
||||
} else {
|
||||
err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM,
|
||||
IPU_OUTPUT_BUFFER, *buffer_num,
|
||||
eba);
|
||||
}
|
||||
if (err != 0) {
|
||||
if (grotation >= IPU_ROTATE_90_RIGHT) {
|
||||
ipu_clear_buffer_ready(ipu, MEM_ROT_ENC_MEM,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
*buffer_num);
|
||||
err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
*buffer_num,
|
||||
eba);
|
||||
} else {
|
||||
ipu_clear_buffer_ready(ipu, CSI_PRP_ENC_MEM,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
*buffer_num);
|
||||
err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
*buffer_num,
|
||||
eba);
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
pr_err("ERROR: v4l2 capture: fail to update "
|
||||
"buf%d\n", *buffer_num);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (grotation >= IPU_ROTATE_90_RIGHT) {
|
||||
ipu_select_buffer(ipu, MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER,
|
||||
*buffer_num);
|
||||
} else {
|
||||
ipu_select_buffer(ipu, CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER,
|
||||
*buffer_num);
|
||||
}
|
||||
|
||||
*buffer_num = (*buffer_num == 0) ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Enable encoder task
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int prp_enc_enabling_tasks(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0;
|
||||
CAMERA_TRACE("IPU:In prp_enc_enabling_tasks\n");
|
||||
|
||||
cam->dummy_frame.vaddress = dma_alloc_coherent(0,
|
||||
PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
|
||||
&cam->dummy_frame.paddress,
|
||||
GFP_DMA | GFP_KERNEL);
|
||||
if (cam->dummy_frame.vaddress == 0) {
|
||||
pr_err("ERROR: v4l2 capture: Allocate dummy frame "
|
||||
"failed.\n");
|
||||
return -ENOBUFS;
|
||||
}
|
||||
cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE;
|
||||
cam->dummy_frame.buffer.length =
|
||||
PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
|
||||
cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress;
|
||||
|
||||
if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
|
||||
err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF,
|
||||
prp_enc_callback, 0, "Mxc Camera", cam);
|
||||
} else {
|
||||
err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF,
|
||||
prp_enc_callback, 0, "Mxc Camera", cam);
|
||||
}
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error registering rot irq\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = prp_enc_setup(cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "prp_enc_setup %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Disable encoder task
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
static int prp_enc_disabling_tasks(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0;
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
void *mipi_csi2_info;
|
||||
int ipu_id;
|
||||
int csi_id;
|
||||
#endif
|
||||
|
||||
if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
|
||||
ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF, cam);
|
||||
ipu_unlink_channels(cam->ipu, CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM);
|
||||
}
|
||||
|
||||
err = ipu_disable_channel(cam->ipu, CSI_PRP_ENC_MEM, true);
|
||||
if (cam->rotation >= IPU_ROTATE_90_RIGHT)
|
||||
err |= ipu_disable_channel(cam->ipu, MEM_ROT_ENC_MEM, true);
|
||||
|
||||
ipu_uninit_channel(cam->ipu, CSI_PRP_ENC_MEM);
|
||||
if (cam->rotation >= IPU_ROTATE_90_RIGHT)
|
||||
ipu_uninit_channel(cam->ipu, MEM_ROT_ENC_MEM);
|
||||
|
||||
if (cam->dummy_frame.vaddress != 0) {
|
||||
dma_free_coherent(0, cam->dummy_frame.buffer.length,
|
||||
cam->dummy_frame.vaddress,
|
||||
cam->dummy_frame.paddress);
|
||||
cam->dummy_frame.vaddress = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
mipi_csi2_info = mipi_csi2_get_info();
|
||||
|
||||
if (mipi_csi2_info) {
|
||||
if (mipi_csi2_get_status(mipi_csi2_info)) {
|
||||
ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
|
||||
csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
|
||||
|
||||
if (cam->ipu == ipu_get_soc(ipu_id)
|
||||
&& cam->csi == csi_id)
|
||||
mipi_csi2_pixelclk_disable(mipi_csi2_info);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Enable csi
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int prp_enc_enable_csi(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
return ipu_enable_csi(cam->ipu, cam->csi);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Disable csi
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int prp_enc_disable_csi(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
/* free csi eof irq firstly.
|
||||
* when disable csi, wait for idmac eof.
|
||||
* it requests eof irq again */
|
||||
if (cam->rotation < IPU_ROTATE_90_RIGHT)
|
||||
ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF, cam);
|
||||
|
||||
return ipu_disable_csi(cam->ipu, cam->csi);
|
||||
}
|
||||
|
||||
/*!
|
||||
* function to select PRP-ENC as the working path
|
||||
*
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int prp_enc_select(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0;
|
||||
|
||||
if (cam) {
|
||||
cam->enc_update_eba = prp_enc_eba_update;
|
||||
cam->enc_enable = prp_enc_enabling_tasks;
|
||||
cam->enc_disable = prp_enc_disabling_tasks;
|
||||
cam->enc_enable_csi = prp_enc_enable_csi;
|
||||
cam->enc_disable_csi = prp_enc_disable_csi;
|
||||
} else {
|
||||
err = -EIO;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(prp_enc_select);
|
||||
|
||||
/*!
|
||||
* function to de-select PRP-ENC as the working path
|
||||
*
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int prp_enc_deselect(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0;
|
||||
|
||||
if (cam) {
|
||||
cam->enc_update_eba = NULL;
|
||||
cam->enc_enable = NULL;
|
||||
cam->enc_disable = NULL;
|
||||
cam->enc_enable_csi = NULL;
|
||||
cam->enc_disable_csi = NULL;
|
||||
if (cam->rot_enc_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->rot_enc_buf_size[0],
|
||||
cam->rot_enc_bufs_vaddr[0],
|
||||
cam->rot_enc_bufs[0]);
|
||||
cam->rot_enc_bufs_vaddr[0] = NULL;
|
||||
cam->rot_enc_bufs[0] = 0;
|
||||
}
|
||||
if (cam->rot_enc_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->rot_enc_buf_size[1],
|
||||
cam->rot_enc_bufs_vaddr[1],
|
||||
cam->rot_enc_bufs[1]);
|
||||
cam->rot_enc_bufs_vaddr[1] = NULL;
|
||||
cam->rot_enc_bufs[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(prp_enc_deselect);
|
||||
|
||||
/*!
|
||||
* Init the Encorder channels
|
||||
*
|
||||
* @return Error code indicating success or failure
|
||||
*/
|
||||
__init int prp_enc_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Deinit the Encorder channels
|
||||
*
|
||||
*/
|
||||
void __exit prp_enc_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(prp_enc_init);
|
||||
module_exit(prp_enc_exit);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("IPU PRP ENC Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file ipu_prp_sw.h
|
||||
*
|
||||
* @brief This file contains the IPU PRP use case driver header.
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_IPU__PRP_SW_H_
|
||||
#define _INCLUDE_IPU__PRP_SW_H_
|
||||
|
||||
int csi_enc_select(void *private);
|
||||
int csi_enc_deselect(void *private);
|
||||
int prp_enc_select(void *private);
|
||||
int prp_enc_deselect(void *private);
|
||||
#ifdef CONFIG_MXC_IPU_PRP_VF_SDC
|
||||
int prp_vf_sdc_select(void *private);
|
||||
int prp_vf_sdc_deselect(void *private);
|
||||
int prp_vf_sdc_select_bg(void *private);
|
||||
int prp_vf_sdc_deselect_bg(void *private);
|
||||
#else
|
||||
int foreground_sdc_select(void *private);
|
||||
int foreground_sdc_deselect(void *private);
|
||||
int bg_overlay_sdc_select(void *private);
|
||||
int bg_overlay_sdc_deselect(void *private);
|
||||
#endif
|
||||
int prp_still_select(void *private);
|
||||
int prp_still_deselect(void *private);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,582 @@
|
|||
/*
|
||||
* Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
/* * The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file ipu_prp_vf_sdc.c
|
||||
*
|
||||
* @brief IPU Use case for PRP-VF
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/ipu.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mxcfb.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/mipi_csi2.h>
|
||||
#include "mxc_v4l2_capture.h"
|
||||
#include "ipu_prp_sw.h"
|
||||
|
||||
static int buffer_num;
|
||||
static struct ipu_soc *disp_ipu;
|
||||
|
||||
static void get_disp_ipu(cam_data *cam)
|
||||
{
|
||||
if (cam->output > 2)
|
||||
disp_ipu = ipu_get_soc(1); /* using DISP4 */
|
||||
else
|
||||
disp_ipu = ipu_get_soc(0);
|
||||
}
|
||||
|
||||
static irqreturn_t prpvf_rot_eof_callback(int irq, void *dev_id)
|
||||
{
|
||||
cam_data *cam = dev_id;
|
||||
pr_debug("buffer_num %d\n", buffer_num);
|
||||
|
||||
if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
|
||||
ipu_select_buffer(disp_ipu, MEM_FG_SYNC,
|
||||
IPU_INPUT_BUFFER, buffer_num);
|
||||
buffer_num = (buffer_num == 0) ? 1 : 0;
|
||||
ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER, buffer_num);
|
||||
} else {
|
||||
ipu_select_buffer(disp_ipu, MEM_FG_SYNC,
|
||||
IPU_INPUT_BUFFER, buffer_num);
|
||||
buffer_num = (buffer_num == 0) ? 1 : 0;
|
||||
ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER, buffer_num);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
/*
|
||||
* Function definitions
|
||||
*/
|
||||
|
||||
/*!
|
||||
* prpvf_start - start the vf task
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
*/
|
||||
static int prpvf_start(void *private)
|
||||
{
|
||||
struct fb_var_screeninfo fbvar;
|
||||
struct fb_info *fbi = NULL;
|
||||
cam_data *cam = (cam_data *) private;
|
||||
ipu_channel_params_t vf;
|
||||
u32 vf_out_format = 0;
|
||||
u32 size = 2, temp = 0;
|
||||
int err = 0, i = 0;
|
||||
short *tmp, color;
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
void *mipi_csi2_info;
|
||||
int ipu_id;
|
||||
int csi_id;
|
||||
#endif
|
||||
|
||||
if (!cam) {
|
||||
printk(KERN_ERR "private is NULL\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (cam->overlay_active == true) {
|
||||
pr_debug("already started.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
get_disp_ipu(cam);
|
||||
|
||||
for (i = 0; i < num_registered_fb; i++) {
|
||||
char *idstr = registered_fb[i]->fix.id;
|
||||
if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
|
||||
((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
|
||||
fbi = registered_fb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fbi == NULL) {
|
||||
printk(KERN_ERR "DISP FG fb not found\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
fbvar = fbi->var;
|
||||
|
||||
/* Store the overlay frame buffer's original std */
|
||||
cam->fb_origin_std = fbvar.nonstd;
|
||||
|
||||
if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) {
|
||||
/* Use DP to do CSC so that we can get better performance */
|
||||
vf_out_format = IPU_PIX_FMT_UYVY;
|
||||
fbvar.nonstd = vf_out_format;
|
||||
color = 0x80;
|
||||
} else {
|
||||
vf_out_format = IPU_PIX_FMT_RGB565;
|
||||
fbvar.nonstd = 0;
|
||||
color = 0x0;
|
||||
}
|
||||
|
||||
fbvar.bits_per_pixel = 16;
|
||||
fbvar.xres = fbvar.xres_virtual = cam->win.w.width;
|
||||
fbvar.yres = cam->win.w.height;
|
||||
fbvar.yres_virtual = cam->win.w.height * 2;
|
||||
fbvar.yoffset = 0;
|
||||
fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG;
|
||||
fbvar.activate |= FB_ACTIVATE_FORCE;
|
||||
fb_set_var(fbi, &fbvar);
|
||||
|
||||
ipu_disp_set_window_pos(disp_ipu, MEM_FG_SYNC, cam->win.w.left,
|
||||
cam->win.w.top);
|
||||
|
||||
/* Fill black color for framebuffer */
|
||||
tmp = (short *) fbi->screen_base;
|
||||
for (i = 0; i < (fbi->fix.line_length * fbi->var.yres)/2;
|
||||
i++, tmp++)
|
||||
*tmp = color;
|
||||
|
||||
console_lock();
|
||||
fb_blank(fbi, FB_BLANK_UNBLANK);
|
||||
console_unlock();
|
||||
|
||||
/* correct display ch buffer address */
|
||||
ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
|
||||
0, fbi->fix.smem_start +
|
||||
(fbi->fix.line_length * fbvar.yres));
|
||||
ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
|
||||
1, fbi->fix.smem_start);
|
||||
|
||||
memset(&vf, 0, sizeof(ipu_channel_params_t));
|
||||
ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width,
|
||||
&vf.csi_prp_vf_mem.in_height, cam->csi);
|
||||
vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
|
||||
vf.csi_prp_vf_mem.out_width = cam->win.w.width;
|
||||
vf.csi_prp_vf_mem.out_height = cam->win.w.height;
|
||||
vf.csi_prp_vf_mem.csi = cam->csi;
|
||||
if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
|
||||
vf.csi_prp_vf_mem.out_width = cam->win.w.height;
|
||||
vf.csi_prp_vf_mem.out_height = cam->win.w.width;
|
||||
}
|
||||
vf.csi_prp_vf_mem.out_pixel_fmt = vf_out_format;
|
||||
size = cam->win.w.width * cam->win.w.height * size;
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
mipi_csi2_info = mipi_csi2_get_info();
|
||||
|
||||
if (mipi_csi2_info) {
|
||||
if (mipi_csi2_get_status(mipi_csi2_info)) {
|
||||
ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
|
||||
csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
|
||||
|
||||
if (cam->ipu == ipu_get_soc(ipu_id)
|
||||
&& cam->csi == csi_id) {
|
||||
vf.csi_prp_vf_mem.mipi_en = true;
|
||||
vf.csi_prp_vf_mem.mipi_vc =
|
||||
mipi_csi2_get_virtual_channel(mipi_csi2_info);
|
||||
vf.csi_prp_vf_mem.mipi_id =
|
||||
mipi_csi2_get_datatype(mipi_csi2_info);
|
||||
|
||||
mipi_csi2_pixelclk_enable(mipi_csi2_info);
|
||||
} else {
|
||||
vf.csi_prp_vf_mem.mipi_en = false;
|
||||
vf.csi_prp_vf_mem.mipi_vc = 0;
|
||||
vf.csi_prp_vf_mem.mipi_id = 0;
|
||||
}
|
||||
} else {
|
||||
vf.csi_prp_vf_mem.mipi_en = false;
|
||||
vf.csi_prp_vf_mem.mipi_vc = 0;
|
||||
vf.csi_prp_vf_mem.mipi_id = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf);
|
||||
if (err != 0)
|
||||
goto out_5;
|
||||
|
||||
if (cam->vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[0],
|
||||
cam->vf_bufs_vaddr[0],
|
||||
(dma_addr_t) cam->vf_bufs[0]);
|
||||
}
|
||||
if (cam->vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[1],
|
||||
cam->vf_bufs_vaddr[1],
|
||||
(dma_addr_t) cam->vf_bufs[1]);
|
||||
}
|
||||
cam->vf_bufs_size[0] = PAGE_ALIGN(size);
|
||||
cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
|
||||
cam->vf_bufs_size[0],
|
||||
(dma_addr_t *) &
|
||||
cam->vf_bufs[0],
|
||||
GFP_DMA |
|
||||
GFP_KERNEL);
|
||||
if (cam->vf_bufs_vaddr[0] == NULL) {
|
||||
printk(KERN_ERR "Error to allocate vf buffer\n");
|
||||
err = -ENOMEM;
|
||||
goto out_4;
|
||||
}
|
||||
cam->vf_bufs_size[1] = PAGE_ALIGN(size);
|
||||
cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
|
||||
cam->vf_bufs_size[1],
|
||||
(dma_addr_t *) &
|
||||
cam->vf_bufs[1],
|
||||
GFP_DMA |
|
||||
GFP_KERNEL);
|
||||
if (cam->vf_bufs_vaddr[1] == NULL) {
|
||||
printk(KERN_ERR "Error to allocate vf buffer\n");
|
||||
err = -ENOMEM;
|
||||
goto out_3;
|
||||
}
|
||||
pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
|
||||
|
||||
if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
|
||||
err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
vf_out_format,
|
||||
vf.csi_prp_vf_mem.out_width,
|
||||
vf.csi_prp_vf_mem.out_height,
|
||||
vf.csi_prp_vf_mem.out_width,
|
||||
IPU_ROTATE_NONE,
|
||||
cam->vf_bufs[0], cam->vf_bufs[1],
|
||||
0, 0, 0);
|
||||
if (err != 0)
|
||||
goto out_3;
|
||||
|
||||
err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
|
||||
goto out_3;
|
||||
}
|
||||
|
||||
err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
|
||||
IPU_INPUT_BUFFER,
|
||||
vf_out_format,
|
||||
vf.csi_prp_vf_mem.out_width,
|
||||
vf.csi_prp_vf_mem.out_height,
|
||||
vf.csi_prp_vf_mem.out_width,
|
||||
cam->vf_rotation,
|
||||
cam->vf_bufs[0],
|
||||
cam->vf_bufs[1],
|
||||
0, 0, 0);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n");
|
||||
goto out_2;
|
||||
}
|
||||
|
||||
if (cam->vf_rotation < IPU_ROTATE_90_RIGHT) {
|
||||
temp = vf.csi_prp_vf_mem.out_width;
|
||||
vf.csi_prp_vf_mem.out_width =
|
||||
vf.csi_prp_vf_mem.out_height;
|
||||
vf.csi_prp_vf_mem.out_height = temp;
|
||||
}
|
||||
|
||||
err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
vf_out_format,
|
||||
vf.csi_prp_vf_mem.out_height,
|
||||
vf.csi_prp_vf_mem.out_width,
|
||||
vf.csi_prp_vf_mem.out_height,
|
||||
IPU_ROTATE_NONE,
|
||||
fbi->fix.smem_start +
|
||||
(fbi->fix.line_length *
|
||||
fbi->var.yres),
|
||||
fbi->fix.smem_start, 0, 0, 0);
|
||||
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
|
||||
goto out_2;
|
||||
}
|
||||
|
||||
ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF);
|
||||
err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF,
|
||||
prpvf_rot_eof_callback,
|
||||
0, "Mxc Camera", cam);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_ROT_OUT_EOF\n");
|
||||
goto out_2;
|
||||
}
|
||||
|
||||
err = ipu_link_channels(cam->ipu,
|
||||
CSI_PRP_VF_MEM, MEM_ROT_VF_MEM);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR
|
||||
"Error link CSI_PRP_VF_MEM-MEM_ROT_VF_MEM\n");
|
||||
goto out_1;
|
||||
}
|
||||
|
||||
ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
|
||||
ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM);
|
||||
|
||||
ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER, 0);
|
||||
ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER, 1);
|
||||
ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER, 0);
|
||||
} else {
|
||||
err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
vf_out_format, cam->win.w.width,
|
||||
cam->win.w.height,
|
||||
cam->win.w.width,
|
||||
cam->vf_rotation,
|
||||
fbi->fix.smem_start +
|
||||
(fbi->fix.line_length *
|
||||
fbi->var.yres),
|
||||
fbi->fix.smem_start, 0, 0, 0);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
|
||||
goto out_4;
|
||||
}
|
||||
ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF);
|
||||
err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF,
|
||||
prpvf_rot_eof_callback,
|
||||
0, "Mxc Camera", cam);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_OUT_EOF\n");
|
||||
goto out_4;
|
||||
}
|
||||
|
||||
ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
|
||||
|
||||
ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER, 0);
|
||||
}
|
||||
|
||||
cam->overlay_active = true;
|
||||
return err;
|
||||
|
||||
out_1:
|
||||
ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL);
|
||||
out_2:
|
||||
if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP)
|
||||
ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
|
||||
out_3:
|
||||
if (cam->vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[0],
|
||||
cam->vf_bufs_vaddr[0],
|
||||
(dma_addr_t) cam->vf_bufs[0]);
|
||||
cam->vf_bufs_vaddr[0] = NULL;
|
||||
cam->vf_bufs[0] = 0;
|
||||
}
|
||||
if (cam->vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[1],
|
||||
cam->vf_bufs_vaddr[1],
|
||||
(dma_addr_t) cam->vf_bufs[1]);
|
||||
cam->vf_bufs_vaddr[1] = NULL;
|
||||
cam->vf_bufs[1] = 0;
|
||||
}
|
||||
out_4:
|
||||
ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
|
||||
out_5:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* prpvf_stop - stop the vf task
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
*/
|
||||
static int prpvf_stop(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0, i = 0;
|
||||
struct fb_info *fbi = NULL;
|
||||
struct fb_var_screeninfo fbvar;
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
void *mipi_csi2_info;
|
||||
int ipu_id;
|
||||
int csi_id;
|
||||
#endif
|
||||
|
||||
if (cam->overlay_active == false)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < num_registered_fb; i++) {
|
||||
char *idstr = registered_fb[i]->fix.id;
|
||||
if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
|
||||
((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
|
||||
fbi = registered_fb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fbi == NULL) {
|
||||
printk(KERN_ERR "DISP FG fb not found\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
|
||||
ipu_unlink_channels(cam->ipu, CSI_PRP_VF_MEM, MEM_ROT_VF_MEM);
|
||||
ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF, cam);
|
||||
}
|
||||
buffer_num = 0;
|
||||
|
||||
ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true);
|
||||
|
||||
if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
|
||||
ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true);
|
||||
ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
|
||||
}
|
||||
ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
|
||||
|
||||
console_lock();
|
||||
fb_blank(fbi, FB_BLANK_POWERDOWN);
|
||||
console_unlock();
|
||||
|
||||
/* Set the overlay frame buffer std to what it is used to be */
|
||||
fbvar = fbi->var;
|
||||
fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG;
|
||||
fbvar.nonstd = cam->fb_origin_std;
|
||||
fbvar.activate |= FB_ACTIVATE_FORCE;
|
||||
fb_set_var(fbi, &fbvar);
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
mipi_csi2_info = mipi_csi2_get_info();
|
||||
|
||||
if (mipi_csi2_info) {
|
||||
if (mipi_csi2_get_status(mipi_csi2_info)) {
|
||||
ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
|
||||
csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
|
||||
|
||||
if (cam->ipu == ipu_get_soc(ipu_id)
|
||||
&& cam->csi == csi_id)
|
||||
mipi_csi2_pixelclk_disable(mipi_csi2_info);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cam->vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[0],
|
||||
cam->vf_bufs_vaddr[0],
|
||||
(dma_addr_t) cam->vf_bufs[0]);
|
||||
cam->vf_bufs_vaddr[0] = NULL;
|
||||
cam->vf_bufs[0] = 0;
|
||||
}
|
||||
if (cam->vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[1],
|
||||
cam->vf_bufs_vaddr[1],
|
||||
(dma_addr_t) cam->vf_bufs[1]);
|
||||
cam->vf_bufs_vaddr[1] = NULL;
|
||||
cam->vf_bufs[1] = 0;
|
||||
}
|
||||
|
||||
cam->overlay_active = false;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Enable csi
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int prp_vf_enable_csi(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
return ipu_enable_csi(cam->ipu, cam->csi);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Disable csi
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int prp_vf_disable_csi(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
/* free csi eof irq firstly.
|
||||
* when disable csi, wait for idmac eof.
|
||||
* it requests eof irq again */
|
||||
if (cam->vf_rotation < IPU_ROTATE_VERT_FLIP)
|
||||
ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam);
|
||||
|
||||
return ipu_disable_csi(cam->ipu, cam->csi);
|
||||
}
|
||||
|
||||
/*!
|
||||
* function to select PRP-VF as the working path
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
int prp_vf_sdc_select(void *private)
|
||||
{
|
||||
cam_data *cam;
|
||||
int err = 0;
|
||||
if (private) {
|
||||
cam = (cam_data *) private;
|
||||
cam->vf_start_sdc = prpvf_start;
|
||||
cam->vf_stop_sdc = prpvf_stop;
|
||||
cam->vf_enable_csi = prp_vf_enable_csi;
|
||||
cam->vf_disable_csi = prp_vf_disable_csi;
|
||||
cam->overlay_active = false;
|
||||
} else
|
||||
err = -EIO;
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(prp_vf_sdc_select);
|
||||
|
||||
/*!
|
||||
* function to de-select PRP-VF as the working path
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int prp_vf_sdc_deselect(void *private)
|
||||
{
|
||||
cam_data *cam;
|
||||
|
||||
if (private) {
|
||||
cam = (cam_data *) private;
|
||||
cam->vf_start_sdc = NULL;
|
||||
cam->vf_stop_sdc = NULL;
|
||||
cam->vf_enable_csi = NULL;
|
||||
cam->vf_disable_csi = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(prp_vf_sdc_deselect);
|
||||
|
||||
/*!
|
||||
* Init viewfinder task.
|
||||
*
|
||||
* @return Error code indicating success or failure
|
||||
*/
|
||||
__init int prp_vf_sdc_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Deinit viewfinder task.
|
||||
*
|
||||
* @return Error code indicating success or failure
|
||||
*/
|
||||
void __exit prp_vf_sdc_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(prp_vf_sdc_init);
|
||||
module_exit(prp_vf_sdc_exit);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("IPU PRP VF SDC Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,521 @@
|
|||
/*
|
||||
* Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file ipu_prp_vf_sdc_bg.c
|
||||
*
|
||||
* @brief IPU Use case for PRP-VF back-ground
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/ipu.h>
|
||||
#include <linux/module.h>
|
||||
#include <mach/mipi_csi2.h>
|
||||
#include "mxc_v4l2_capture.h"
|
||||
#include "ipu_prp_sw.h"
|
||||
|
||||
static int buffer_num;
|
||||
static int buffer_ready;
|
||||
static struct ipu_soc *disp_ipu;
|
||||
|
||||
static void get_disp_ipu(cam_data *cam)
|
||||
{
|
||||
if (cam->output > 2)
|
||||
disp_ipu = ipu_get_soc(1); /* using DISP4 */
|
||||
else
|
||||
disp_ipu = ipu_get_soc(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function definitions
|
||||
*/
|
||||
|
||||
/*!
|
||||
* SDC V-Sync callback function.
|
||||
*
|
||||
* @param irq int irq line
|
||||
* @param dev_id void * device id
|
||||
*
|
||||
* @return status IRQ_HANDLED for handled
|
||||
*/
|
||||
static irqreturn_t prpvf_sdc_vsync_callback(int irq, void *dev_id)
|
||||
{
|
||||
cam_data *cam = dev_id;
|
||||
if (buffer_ready > 0) {
|
||||
ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER, 0);
|
||||
buffer_ready--;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*!
|
||||
* VF EOF callback function.
|
||||
*
|
||||
* @param irq int irq line
|
||||
* @param dev_id void * device id
|
||||
*
|
||||
* @return status IRQ_HANDLED for handled
|
||||
*/
|
||||
static irqreturn_t prpvf_vf_eof_callback(int irq, void *dev_id)
|
||||
{
|
||||
cam_data *cam = dev_id;
|
||||
pr_debug("buffer_ready %d buffer_num %d\n", buffer_ready, buffer_num);
|
||||
|
||||
ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
|
||||
IPU_INPUT_BUFFER, buffer_num);
|
||||
buffer_num = (buffer_num == 0) ? 1 : 0;
|
||||
ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER, buffer_num);
|
||||
buffer_ready++;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*!
|
||||
* prpvf_start - start the vf task
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
*/
|
||||
static int prpvf_start(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
ipu_channel_params_t vf;
|
||||
u32 format;
|
||||
u32 offset;
|
||||
u32 bpp, size = 3;
|
||||
int err = 0;
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
void *mipi_csi2_info;
|
||||
int ipu_id;
|
||||
int csi_id;
|
||||
#endif
|
||||
|
||||
if (!cam) {
|
||||
printk(KERN_ERR "private is NULL\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (cam->overlay_active == true) {
|
||||
pr_debug("already start.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
get_disp_ipu(cam);
|
||||
|
||||
format = cam->v4l2_fb.fmt.pixelformat;
|
||||
if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) {
|
||||
bpp = 3, size = 3;
|
||||
pr_info("BGR24\n");
|
||||
} else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) {
|
||||
bpp = 2, size = 2;
|
||||
pr_info("RGB565\n");
|
||||
} else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) {
|
||||
bpp = 4, size = 4;
|
||||
pr_info("BGR32\n");
|
||||
} else {
|
||||
printk(KERN_ERR
|
||||
"unsupported fix format from the framebuffer.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top +
|
||||
size * cam->win.w.left;
|
||||
|
||||
if (cam->v4l2_fb.base == 0)
|
||||
printk(KERN_ERR "invalid frame buffer address.\n");
|
||||
else
|
||||
offset += (u32) cam->v4l2_fb.base;
|
||||
|
||||
memset(&vf, 0, sizeof(ipu_channel_params_t));
|
||||
ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width,
|
||||
&vf.csi_prp_vf_mem.in_height, cam->csi);
|
||||
vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
|
||||
vf.csi_prp_vf_mem.out_width = cam->win.w.width;
|
||||
vf.csi_prp_vf_mem.out_height = cam->win.w.height;
|
||||
vf.csi_prp_vf_mem.csi = cam->csi;
|
||||
if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
|
||||
vf.csi_prp_vf_mem.out_width = cam->win.w.height;
|
||||
vf.csi_prp_vf_mem.out_height = cam->win.w.width;
|
||||
}
|
||||
vf.csi_prp_vf_mem.out_pixel_fmt = format;
|
||||
size = cam->win.w.width * cam->win.w.height * size;
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
mipi_csi2_info = mipi_csi2_get_info();
|
||||
|
||||
if (mipi_csi2_info) {
|
||||
if (mipi_csi2_get_status(mipi_csi2_info)) {
|
||||
ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
|
||||
csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
|
||||
|
||||
if (cam->ipu == ipu_get_soc(ipu_id)
|
||||
&& cam->csi == csi_id) {
|
||||
vf.csi_prp_vf_mem.mipi_en = true;
|
||||
vf.csi_prp_vf_mem.mipi_vc =
|
||||
mipi_csi2_get_virtual_channel(mipi_csi2_info);
|
||||
vf.csi_prp_vf_mem.mipi_id =
|
||||
mipi_csi2_get_datatype(mipi_csi2_info);
|
||||
|
||||
mipi_csi2_pixelclk_enable(mipi_csi2_info);
|
||||
} else {
|
||||
vf.csi_prp_vf_mem.mipi_en = false;
|
||||
vf.csi_prp_vf_mem.mipi_vc = 0;
|
||||
vf.csi_prp_vf_mem.mipi_id = 0;
|
||||
}
|
||||
} else {
|
||||
vf.csi_prp_vf_mem.mipi_en = false;
|
||||
vf.csi_prp_vf_mem.mipi_vc = 0;
|
||||
vf.csi_prp_vf_mem.mipi_id = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf);
|
||||
if (err != 0)
|
||||
goto out_4;
|
||||
|
||||
if (cam->vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[0],
|
||||
cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
|
||||
}
|
||||
if (cam->vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[1],
|
||||
cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
|
||||
}
|
||||
cam->vf_bufs_size[0] = PAGE_ALIGN(size);
|
||||
cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
|
||||
cam->vf_bufs_size[0],
|
||||
&cam->vf_bufs[0],
|
||||
GFP_DMA |
|
||||
GFP_KERNEL);
|
||||
if (cam->vf_bufs_vaddr[0] == NULL) {
|
||||
printk(KERN_ERR "Error to allocate vf buffer\n");
|
||||
err = -ENOMEM;
|
||||
goto out_3;
|
||||
}
|
||||
cam->vf_bufs_size[1] = PAGE_ALIGN(size);
|
||||
cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
|
||||
cam->vf_bufs_size[1],
|
||||
&cam->vf_bufs[1],
|
||||
GFP_DMA |
|
||||
GFP_KERNEL);
|
||||
if (cam->vf_bufs_vaddr[1] == NULL) {
|
||||
printk(KERN_ERR "Error to allocate vf buffer\n");
|
||||
err = -ENOMEM;
|
||||
goto out_3;
|
||||
}
|
||||
|
||||
err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
format, vf.csi_prp_vf_mem.out_width,
|
||||
vf.csi_prp_vf_mem.out_height,
|
||||
vf.csi_prp_vf_mem.out_width,
|
||||
IPU_ROTATE_NONE,
|
||||
cam->vf_bufs[0],
|
||||
cam->vf_bufs[1],
|
||||
0, 0, 0);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
|
||||
goto out_3;
|
||||
}
|
||||
err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
|
||||
goto out_3;
|
||||
}
|
||||
|
||||
err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
|
||||
IPU_INPUT_BUFFER,
|
||||
format, vf.csi_prp_vf_mem.out_width,
|
||||
vf.csi_prp_vf_mem.out_height,
|
||||
vf.csi_prp_vf_mem.out_width,
|
||||
cam->vf_rotation,
|
||||
cam->vf_bufs[0],
|
||||
cam->vf_bufs[1],
|
||||
0, 0, 0);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n");
|
||||
goto out_2;
|
||||
}
|
||||
|
||||
if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
|
||||
err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
format,
|
||||
vf.csi_prp_vf_mem.out_height,
|
||||
vf.csi_prp_vf_mem.out_width,
|
||||
cam->overlay_fb->var.xres * bpp,
|
||||
IPU_ROTATE_NONE,
|
||||
offset, 0, 0, 0, 0);
|
||||
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
|
||||
goto out_2;
|
||||
}
|
||||
} else {
|
||||
err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
|
||||
IPU_OUTPUT_BUFFER,
|
||||
format,
|
||||
vf.csi_prp_vf_mem.out_width,
|
||||
vf.csi_prp_vf_mem.out_height,
|
||||
cam->overlay_fb->var.xres * bpp,
|
||||
IPU_ROTATE_NONE,
|
||||
offset, 0, 0, 0, 0);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
|
||||
goto out_2;
|
||||
}
|
||||
}
|
||||
|
||||
ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF);
|
||||
err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF,
|
||||
prpvf_vf_eof_callback,
|
||||
0, "Mxc Camera", cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR
|
||||
"Error registering IPU_IRQ_PRP_VF_OUT_EOF irq.\n");
|
||||
goto out_2;
|
||||
}
|
||||
|
||||
ipu_clear_irq(disp_ipu, IPU_IRQ_BG_SF_END);
|
||||
err = ipu_request_irq(disp_ipu, IPU_IRQ_BG_SF_END,
|
||||
prpvf_sdc_vsync_callback,
|
||||
0, "Mxc Camera", cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error registering IPU_IRQ_BG_SF_END irq.\n");
|
||||
goto out_1;
|
||||
}
|
||||
|
||||
ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
|
||||
ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM);
|
||||
|
||||
buffer_num = 0;
|
||||
buffer_ready = 0;
|
||||
ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 0);
|
||||
|
||||
cam->overlay_active = true;
|
||||
return err;
|
||||
|
||||
out_1:
|
||||
ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL);
|
||||
out_2:
|
||||
ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
|
||||
out_3:
|
||||
ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
|
||||
out_4:
|
||||
if (cam->vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[0],
|
||||
cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
|
||||
cam->vf_bufs_vaddr[0] = NULL;
|
||||
cam->vf_bufs[0] = 0;
|
||||
}
|
||||
if (cam->vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[1],
|
||||
cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
|
||||
cam->vf_bufs_vaddr[1] = NULL;
|
||||
cam->vf_bufs[1] = 0;
|
||||
}
|
||||
if (cam->rot_vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->rot_vf_buf_size[0],
|
||||
cam->rot_vf_bufs_vaddr[0],
|
||||
cam->rot_vf_bufs[0]);
|
||||
cam->rot_vf_bufs_vaddr[0] = NULL;
|
||||
cam->rot_vf_bufs[0] = 0;
|
||||
}
|
||||
if (cam->rot_vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->rot_vf_buf_size[1],
|
||||
cam->rot_vf_bufs_vaddr[1],
|
||||
cam->rot_vf_bufs[1]);
|
||||
cam->rot_vf_bufs_vaddr[1] = NULL;
|
||||
cam->rot_vf_bufs[1] = 0;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* prpvf_stop - stop the vf task
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
*/
|
||||
static int prpvf_stop(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
void *mipi_csi2_info;
|
||||
int ipu_id;
|
||||
int csi_id;
|
||||
#endif
|
||||
|
||||
if (cam->overlay_active == false)
|
||||
return 0;
|
||||
|
||||
ipu_free_irq(disp_ipu, IPU_IRQ_BG_SF_END, cam);
|
||||
|
||||
ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true);
|
||||
ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true);
|
||||
ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
|
||||
ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
|
||||
|
||||
#ifdef CONFIG_MXC_MIPI_CSI2
|
||||
mipi_csi2_info = mipi_csi2_get_info();
|
||||
|
||||
if (mipi_csi2_info) {
|
||||
if (mipi_csi2_get_status(mipi_csi2_info)) {
|
||||
ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
|
||||
csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
|
||||
|
||||
if (cam->ipu == ipu_get_soc(ipu_id)
|
||||
&& cam->csi == csi_id)
|
||||
mipi_csi2_pixelclk_disable(mipi_csi2_info);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cam->vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[0],
|
||||
cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
|
||||
cam->vf_bufs_vaddr[0] = NULL;
|
||||
cam->vf_bufs[0] = 0;
|
||||
}
|
||||
if (cam->vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->vf_bufs_size[1],
|
||||
cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
|
||||
cam->vf_bufs_vaddr[1] = NULL;
|
||||
cam->vf_bufs[1] = 0;
|
||||
}
|
||||
if (cam->rot_vf_bufs_vaddr[0]) {
|
||||
dma_free_coherent(0, cam->rot_vf_buf_size[0],
|
||||
cam->rot_vf_bufs_vaddr[0],
|
||||
cam->rot_vf_bufs[0]);
|
||||
cam->rot_vf_bufs_vaddr[0] = NULL;
|
||||
cam->rot_vf_bufs[0] = 0;
|
||||
}
|
||||
if (cam->rot_vf_bufs_vaddr[1]) {
|
||||
dma_free_coherent(0, cam->rot_vf_buf_size[1],
|
||||
cam->rot_vf_bufs_vaddr[1],
|
||||
cam->rot_vf_bufs[1]);
|
||||
cam->rot_vf_bufs_vaddr[1] = NULL;
|
||||
cam->rot_vf_bufs[1] = 0;
|
||||
}
|
||||
|
||||
buffer_num = 0;
|
||||
buffer_ready = 0;
|
||||
cam->overlay_active = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Enable csi
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int prp_vf_enable_csi(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
return ipu_enable_csi(cam->ipu, cam->csi);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Disable csi
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int prp_vf_disable_csi(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
/* free csi eof irq firstly.
|
||||
* when disable csi, wait for idmac eof.
|
||||
* it requests eof irq again */
|
||||
ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam);
|
||||
|
||||
return ipu_disable_csi(cam->ipu, cam->csi);
|
||||
}
|
||||
|
||||
/*!
|
||||
* function to select PRP-VF as the working path
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
int prp_vf_sdc_select_bg(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
if (cam) {
|
||||
cam->vf_start_sdc = prpvf_start;
|
||||
cam->vf_stop_sdc = prpvf_stop;
|
||||
cam->vf_enable_csi = prp_vf_enable_csi;
|
||||
cam->vf_disable_csi = prp_vf_disable_csi;
|
||||
cam->overlay_active = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(prp_vf_sdc_select_bg);
|
||||
|
||||
/*!
|
||||
* function to de-select PRP-VF as the working path
|
||||
*
|
||||
* @param private cam_data * mxc v4l2 main structure
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
int prp_vf_sdc_deselect_bg(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
if (cam) {
|
||||
cam->vf_start_sdc = NULL;
|
||||
cam->vf_stop_sdc = NULL;
|
||||
cam->vf_enable_csi = NULL;
|
||||
cam->vf_disable_csi = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(prp_vf_sdc_deselect_bg);
|
||||
|
||||
/*!
|
||||
* Init viewfinder task.
|
||||
*
|
||||
* @return Error code indicating success or failure
|
||||
*/
|
||||
__init int prp_vf_sdc_init_bg(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Deinit viewfinder task.
|
||||
*
|
||||
* @return Error code indicating success or failure
|
||||
*/
|
||||
void __exit prp_vf_sdc_exit_bg(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(prp_vf_sdc_init_bg);
|
||||
module_exit(prp_vf_sdc_exit_bg);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file ipu_still.c
|
||||
*
|
||||
* @brief IPU Use case for still image capture
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ipu.h>
|
||||
#include "mxc_v4l2_capture.h"
|
||||
#include "ipu_prp_sw.h"
|
||||
|
||||
static int callback_eof_flag;
|
||||
#ifndef CONFIG_MXC_IPU_V1
|
||||
static int buffer_num;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MXC_IPU_V1
|
||||
static int callback_flag;
|
||||
/*
|
||||
* Function definitions
|
||||
*/
|
||||
/*!
|
||||
* CSI EOF callback function.
|
||||
*
|
||||
* @param irq int irq line
|
||||
* @param dev_id void * device id
|
||||
*
|
||||
* @return status IRQ_HANDLED for handled
|
||||
*/
|
||||
static irqreturn_t prp_csi_eof_callback(int irq, void *dev_id)
|
||||
{
|
||||
cam_data *cam = devid;
|
||||
ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
|
||||
callback_flag%2 ? 1 : 0);
|
||||
if (callback_flag == 0)
|
||||
ipu_enable_channel(cam->ipu, CSI_MEM);
|
||||
|
||||
callback_flag++;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* CSI callback function.
|
||||
*
|
||||
* @param irq int irq line
|
||||
* @param dev_id void * device id
|
||||
*
|
||||
* @return status IRQ_HANDLED for handled
|
||||
*/
|
||||
static irqreturn_t prp_still_callback(int irq, void *dev_id)
|
||||
{
|
||||
cam_data *cam = (cam_data *) dev_id;
|
||||
|
||||
callback_eof_flag++;
|
||||
if (callback_eof_flag < 5) {
|
||||
#ifndef CONFIG_MXC_IPU_V1
|
||||
buffer_num = (buffer_num == 0) ? 1 : 0;
|
||||
ipu_select_buffer(cam->ipu, CSI_MEM,
|
||||
IPU_OUTPUT_BUFFER, buffer_num);
|
||||
#endif
|
||||
} else {
|
||||
cam->still_counter++;
|
||||
wake_up_interruptible(&cam->still_queue);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*!
|
||||
* start csi->mem task
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int prp_still_start(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
u32 pixel_fmt;
|
||||
int err;
|
||||
ipu_channel_params_t params;
|
||||
|
||||
if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
|
||||
pixel_fmt = IPU_PIX_FMT_YUV420P;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)
|
||||
pixel_fmt = IPU_PIX_FMT_NV12;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P)
|
||||
pixel_fmt = IPU_PIX_FMT_YUV422P;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
|
||||
pixel_fmt = IPU_PIX_FMT_UYVY;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
|
||||
pixel_fmt = IPU_PIX_FMT_YUYV;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
|
||||
pixel_fmt = IPU_PIX_FMT_BGR24;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
|
||||
pixel_fmt = IPU_PIX_FMT_RGB24;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565)
|
||||
pixel_fmt = IPU_PIX_FMT_RGB565;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32)
|
||||
pixel_fmt = IPU_PIX_FMT_BGR32;
|
||||
else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32)
|
||||
pixel_fmt = IPU_PIX_FMT_RGB32;
|
||||
else {
|
||||
printk(KERN_ERR "format not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
err = ipu_init_channel(cam->ipu, CSI_MEM, ¶ms);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
|
||||
pixel_fmt, cam->v2f.fmt.pix.width,
|
||||
cam->v2f.fmt.pix.height,
|
||||
cam->v2f.fmt.pix.width, IPU_ROTATE_NONE,
|
||||
cam->still_buf[0], cam->still_buf[1], 0,
|
||||
0, 0);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
#ifdef CONFIG_MXC_IPU_V1
|
||||
ipu_clear_irq(IPU_IRQ_SENSOR_OUT_EOF);
|
||||
err = ipu_request_irq(IPU_IRQ_SENSOR_OUT_EOF, prp_still_callback,
|
||||
0, "Mxc Camera", cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error registering irq.\n");
|
||||
return err;
|
||||
}
|
||||
callback_flag = 0;
|
||||
callback_eof_flag = 0;
|
||||
ipu_clear_irq(IPU_IRQ_SENSOR_EOF);
|
||||
err = ipu_request_irq(IPU_IRQ_SENSOR_EOF, prp_csi_eof_callback,
|
||||
0, "Mxc Camera", cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error IPU_IRQ_SENSOR_EOF\n");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
callback_eof_flag = 0;
|
||||
buffer_num = 0;
|
||||
|
||||
ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF);
|
||||
err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF,
|
||||
prp_still_callback,
|
||||
0, "Mxc Camera", cam);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "Error registering irq.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 0);
|
||||
ipu_enable_channel(cam->ipu, CSI_MEM);
|
||||
ipu_enable_csi(cam->ipu, cam->csi);
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* stop csi->mem encoder task
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
static int prp_still_stop(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0;
|
||||
|
||||
#ifdef CONFIG_MXC_IPU_V1
|
||||
ipu_free_irq(IPU_IRQ_SENSOR_EOF, NULL);
|
||||
ipu_free_irq(IPU_IRQ_SENSOR_OUT_EOF, cam);
|
||||
#else
|
||||
ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
|
||||
#endif
|
||||
|
||||
ipu_disable_csi(cam->ipu, cam->csi);
|
||||
ipu_disable_channel(cam->ipu, CSI_MEM, true);
|
||||
ipu_uninit_channel(cam->ipu, CSI_MEM);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*!
|
||||
* function to select CSI_MEM as the working path
|
||||
*
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
int prp_still_select(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
|
||||
if (cam) {
|
||||
cam->csi_start = prp_still_start;
|
||||
cam->csi_stop = prp_still_stop;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(prp_still_select);
|
||||
|
||||
/*!
|
||||
* function to de-select CSI_MEM as the working path
|
||||
*
|
||||
* @param private struct cam_data * mxc capture instance
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
int prp_still_deselect(void *private)
|
||||
{
|
||||
cam_data *cam = (cam_data *) private;
|
||||
int err = 0;
|
||||
|
||||
err = prp_still_stop(cam);
|
||||
|
||||
if (cam) {
|
||||
cam->csi_start = NULL;
|
||||
cam->csi_stop = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(prp_still_deselect);
|
||||
|
||||
/*!
|
||||
* Init the Encorder channels
|
||||
*
|
||||
* @return Error code indicating success or failure
|
||||
*/
|
||||
__init int prp_still_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Deinit the Encorder channels
|
||||
*
|
||||
*/
|
||||
void __exit prp_still_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(prp_still_init);
|
||||
module_exit(prp_still_exit);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("IPU PRP STILL IMAGE Driver");
|
||||
MODULE_LICENSE("GPL");
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @defgroup MXC_V4L2_CAPTURE MXC V4L2 Video Capture Driver
|
||||
*/
|
||||
/*!
|
||||
* @file mxc_v4l2_capture.h
|
||||
*
|
||||
* @brief mxc V4L2 capture device API Header file
|
||||
*
|
||||
* It include all the defines for frame operations, also three structure defines
|
||||
* use case ops structure, common v4l2 driver structure and frame structure.
|
||||
*
|
||||
* @ingroup MXC_V4L2_CAPTURE
|
||||
*/
|
||||
#ifndef __MXC_V4L2_CAPTURE_H__
|
||||
#define __MXC_V4L2_CAPTURE_H__
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mxc_v4l2.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/pxp_dma.h>
|
||||
#include <linux/ipu-v3.h>
|
||||
#include <linux/platform_data/dma-imx.h>
|
||||
|
||||
#include <media/v4l2-dev.h>
|
||||
#include "v4l2-int-device.h"
|
||||
|
||||
|
||||
#define FRAME_NUM 10
|
||||
#define MXC_SENSOR_NUM 2
|
||||
|
||||
enum imx_v4l2_devtype {
|
||||
IMX5_V4L2,
|
||||
IMX6_V4L2,
|
||||
};
|
||||
|
||||
/*!
|
||||
* v4l2 frame structure.
|
||||
*/
|
||||
struct mxc_v4l_frame {
|
||||
u32 paddress;
|
||||
void *vaddress;
|
||||
int count;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
struct v4l2_buffer buffer;
|
||||
struct list_head queue;
|
||||
int index;
|
||||
union {
|
||||
int ipu_buf_num;
|
||||
int csi_buf_num;
|
||||
};
|
||||
};
|
||||
|
||||
/* Only for old version. Will go away soon. */
|
||||
typedef struct {
|
||||
u8 clk_mode;
|
||||
u8 ext_vsync;
|
||||
u8 Vsync_pol;
|
||||
u8 Hsync_pol;
|
||||
u8 pixclk_pol;
|
||||
u8 data_pol;
|
||||
u8 data_width;
|
||||
u8 pack_tight;
|
||||
u8 force_eof;
|
||||
u8 data_en_pol;
|
||||
u16 width;
|
||||
u16 height;
|
||||
u32 pixel_fmt;
|
||||
u32 mclk;
|
||||
u16 active_width;
|
||||
u16 active_height;
|
||||
} sensor_interface;
|
||||
|
||||
/* Sensor control function */
|
||||
/* Only for old version. Will go away soon. */
|
||||
struct camera_sensor {
|
||||
void (*set_color) (int bright, int saturation, int red, int green,
|
||||
int blue);
|
||||
void (*get_color) (int *bright, int *saturation, int *red, int *green,
|
||||
int *blue);
|
||||
void (*set_ae_mode) (int ae_mode);
|
||||
void (*get_ae_mode) (int *ae_mode);
|
||||
sensor_interface *(*config) (int *frame_rate, int high_quality);
|
||||
sensor_interface *(*reset) (void);
|
||||
void (*get_std) (v4l2_std_id *std);
|
||||
void (*set_std) (v4l2_std_id std);
|
||||
unsigned int csi;
|
||||
};
|
||||
|
||||
/*!
|
||||
* common v4l2 driver structure.
|
||||
*/
|
||||
typedef struct _cam_data {
|
||||
struct video_device *video_dev;
|
||||
int device_type;
|
||||
|
||||
/* semaphore guard against SMP multithreading */
|
||||
struct semaphore busy_lock;
|
||||
|
||||
int open_count;
|
||||
|
||||
/* params lock for this camera */
|
||||
struct semaphore param_lock;
|
||||
|
||||
/* Encoder */
|
||||
struct list_head ready_q;
|
||||
struct list_head done_q;
|
||||
struct list_head working_q;
|
||||
int ping_pong_csi;
|
||||
spinlock_t queue_int_lock;
|
||||
spinlock_t dqueue_int_lock;
|
||||
struct mxc_v4l_frame frame[FRAME_NUM];
|
||||
struct mxc_v4l_frame dummy_frame;
|
||||
wait_queue_head_t enc_queue;
|
||||
int enc_counter;
|
||||
dma_addr_t rot_enc_bufs[2];
|
||||
void *rot_enc_bufs_vaddr[2];
|
||||
int rot_enc_buf_size[2];
|
||||
enum v4l2_buf_type type;
|
||||
|
||||
/* still image capture */
|
||||
wait_queue_head_t still_queue;
|
||||
int still_counter;
|
||||
dma_addr_t still_buf[2];
|
||||
void *still_buf_vaddr;
|
||||
|
||||
/* overlay */
|
||||
struct v4l2_window win;
|
||||
struct v4l2_framebuffer v4l2_fb;
|
||||
dma_addr_t vf_bufs[2];
|
||||
void *vf_bufs_vaddr[2];
|
||||
int vf_bufs_size[2];
|
||||
dma_addr_t rot_vf_bufs[2];
|
||||
void *rot_vf_bufs_vaddr[2];
|
||||
int rot_vf_buf_size[2];
|
||||
bool overlay_active;
|
||||
int output;
|
||||
struct fb_info *overlay_fb;
|
||||
int fb_origin_std;
|
||||
struct work_struct csi_work_struct;
|
||||
|
||||
/* v4l2 format */
|
||||
struct v4l2_format v2f;
|
||||
struct v4l2_format input_fmt; /* camera in */
|
||||
bool bswapenable;
|
||||
int rotation; /* for IPUv1 and IPUv3, this means encoder rotation */
|
||||
int vf_rotation; /* viewfinder rotation only for IPUv1 and IPUv3 */
|
||||
struct v4l2_mxc_offset offset;
|
||||
|
||||
/* V4l2 control bit */
|
||||
int bright;
|
||||
int hue;
|
||||
int contrast;
|
||||
int saturation;
|
||||
int red;
|
||||
int green;
|
||||
int blue;
|
||||
int ae_mode;
|
||||
|
||||
/* standard */
|
||||
struct v4l2_streamparm streamparm;
|
||||
struct v4l2_standard standard;
|
||||
bool standard_autodetect;
|
||||
|
||||
/* crop */
|
||||
struct v4l2_rect crop_bounds;
|
||||
struct v4l2_rect crop_defrect;
|
||||
struct v4l2_rect crop_current;
|
||||
|
||||
int (*enc_update_eba) (void *private, dma_addr_t eba);
|
||||
int (*enc_enable) (void *private);
|
||||
int (*enc_disable) (void *private);
|
||||
int (*enc_enable_csi) (void *private);
|
||||
int (*enc_disable_csi) (void *private);
|
||||
void (*enc_callback) (u32 mask, void *dev);
|
||||
int (*vf_start_adc) (void *private);
|
||||
int (*vf_stop_adc) (void *private);
|
||||
int (*vf_start_sdc) (void *private);
|
||||
int (*vf_stop_sdc) (void *private);
|
||||
int (*vf_enable_csi) (void *private);
|
||||
int (*vf_disable_csi) (void *private);
|
||||
int (*csi_start) (void *private);
|
||||
int (*csi_stop) (void *private);
|
||||
|
||||
/* misc status flag */
|
||||
bool overlay_on;
|
||||
bool capture_on;
|
||||
int overlay_pid;
|
||||
int capture_pid;
|
||||
bool low_power;
|
||||
wait_queue_head_t power_queue;
|
||||
unsigned int ipu_id;
|
||||
unsigned int csi;
|
||||
u8 mclk_source;
|
||||
bool mclk_on[2]; /* two mclk sources at most now */
|
||||
int current_input;
|
||||
|
||||
int local_buf_num;
|
||||
|
||||
/* camera sensor interface */
|
||||
struct camera_sensor *cam_sensor; /* old version */
|
||||
struct v4l2_int_device *all_sensors[MXC_SENSOR_NUM];
|
||||
struct v4l2_int_device *sensor;
|
||||
struct v4l2_int_device *self;
|
||||
int sensor_index;
|
||||
void *ipu;
|
||||
void *csi_soc;
|
||||
enum imx_v4l2_devtype devtype;
|
||||
|
||||
/* v4l2 buf elements related to PxP DMA */
|
||||
struct completion pxp_tx_cmpl;
|
||||
struct pxp_channel *pxp_chan;
|
||||
struct pxp_config_data pxp_conf;
|
||||
struct dma_async_tx_descriptor *txd;
|
||||
dma_cookie_t cookie;
|
||||
struct scatterlist sg[2];
|
||||
} cam_data;
|
||||
|
||||
struct sensor_data {
|
||||
const struct ov5642_platform_data *platform_data;
|
||||
struct v4l2_int_device *v4l2_int_device;
|
||||
struct i2c_client *i2c_client;
|
||||
struct v4l2_pix_format pix;
|
||||
struct v4l2_captureparm streamcap;
|
||||
bool on;
|
||||
|
||||
/* control settings */
|
||||
int brightness;
|
||||
int hue;
|
||||
int contrast;
|
||||
int saturation;
|
||||
int red;
|
||||
int green;
|
||||
int blue;
|
||||
int ae_mode;
|
||||
|
||||
u32 mclk;
|
||||
u8 mclk_source;
|
||||
struct clk *sensor_clk;
|
||||
int csi;
|
||||
|
||||
void (*io_init)(void);
|
||||
};
|
||||
|
||||
void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi);
|
||||
#endif /* __MXC_V4L2_CAPTURE_H__ */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* drivers/media/video/v4l2-int-device.c
|
||||
*
|
||||
* V4L2 internal ioctl interface.
|
||||
*
|
||||
* Copyright 2005-2014 Freescale Semiconductor, Inc.
|
||||
* Copyright (C) 2007 Nokia Corporation.
|
||||
*
|
||||
* Contact: Sakari Ailus <sakari.ailus@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "v4l2-int-device.h"
|
||||
|
||||
static DEFINE_MUTEX(mutex);
|
||||
static LIST_HEAD(int_list);
|
||||
|
||||
void v4l2_int_device_try_attach_all(void)
|
||||
{
|
||||
struct v4l2_int_device *m, *s;
|
||||
|
||||
list_for_each_entry(m, &int_list, head) {
|
||||
if (m->type != v4l2_int_type_master)
|
||||
continue;
|
||||
|
||||
list_for_each_entry(s, &int_list, head) {
|
||||
if (s->type != v4l2_int_type_slave)
|
||||
continue;
|
||||
|
||||
/* Slave is connected? */
|
||||
if (s->u.slave->master)
|
||||
continue;
|
||||
|
||||
/* Slave wants to attach to master? */
|
||||
if (s->u.slave->attach_to[0] != 0
|
||||
&& strncmp(m->name, s->u.slave->attach_to,
|
||||
V4L2NAMESIZE))
|
||||
continue;
|
||||
|
||||
if (!try_module_get(m->module))
|
||||
continue;
|
||||
|
||||
s->u.slave->master = m;
|
||||
if (m->u.master->attach(s)) {
|
||||
s->u.slave->master = NULL;
|
||||
module_put(m->module);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_int_device_try_attach_all);
|
||||
|
||||
static int ioctl_sort_cmp(const void *a, const void *b)
|
||||
{
|
||||
const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b;
|
||||
|
||||
if (d1->num > d2->num)
|
||||
return 1;
|
||||
|
||||
if (d1->num < d2->num)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int v4l2_int_device_register(struct v4l2_int_device *d)
|
||||
{
|
||||
if (d->type == v4l2_int_type_slave)
|
||||
sort(d->u.slave->ioctls, d->u.slave->num_ioctls,
|
||||
sizeof(struct v4l2_int_ioctl_desc),
|
||||
&ioctl_sort_cmp, NULL);
|
||||
mutex_lock(&mutex);
|
||||
list_add(&d->head, &int_list);
|
||||
v4l2_int_device_try_attach_all();
|
||||
mutex_unlock(&mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_int_device_register);
|
||||
|
||||
void v4l2_int_device_unregister(struct v4l2_int_device *d)
|
||||
{
|
||||
mutex_lock(&mutex);
|
||||
list_del(&d->head);
|
||||
if (d->type == v4l2_int_type_slave
|
||||
&& d->u.slave->master != NULL) {
|
||||
d->u.slave->master->u.master->detach(d);
|
||||
module_put(d->u.slave->master->module);
|
||||
d->u.slave->master = NULL;
|
||||
}
|
||||
mutex_unlock(&mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_int_device_unregister);
|
||||
|
||||
/* Adapted from search_extable in extable.c. */
|
||||
static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd,
|
||||
v4l2_int_ioctl_func *no_such_ioctl)
|
||||
{
|
||||
const struct v4l2_int_ioctl_desc *first = slave->ioctls;
|
||||
const struct v4l2_int_ioctl_desc *last =
|
||||
first + slave->num_ioctls - 1;
|
||||
|
||||
while (first <= last) {
|
||||
const struct v4l2_int_ioctl_desc *mid;
|
||||
|
||||
mid = (last - first) / 2 + first;
|
||||
|
||||
if (mid->num < cmd)
|
||||
first = mid + 1;
|
||||
else if (mid->num > cmd)
|
||||
last = mid - 1;
|
||||
else
|
||||
return mid->func;
|
||||
}
|
||||
|
||||
return no_such_ioctl;
|
||||
}
|
||||
|
||||
static int no_such_ioctl_0(struct v4l2_int_device *d)
|
||||
{
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd)
|
||||
{
|
||||
return ((v4l2_int_ioctl_func_0 *)
|
||||
find_ioctl(d->u.slave, cmd,
|
||||
(v4l2_int_ioctl_func *)no_such_ioctl_0))(d);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_int_ioctl_0);
|
||||
|
||||
static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg)
|
||||
{
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg)
|
||||
{
|
||||
return ((v4l2_int_ioctl_func_1 *)
|
||||
find_ioctl(d->u.slave, cmd,
|
||||
(v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_int_ioctl_1);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* include/media/v4l2-int-device.h
|
||||
*
|
||||
* V4L2 internal ioctl interface.
|
||||
*
|
||||
* Copyright 2005-2014 Freescale Semiconductor, Inc.
|
||||
* Copyright (C) 2007 Nokia Corporation.
|
||||
*
|
||||
* Contact: Sakari Ailus <sakari.ailus@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef V4L2_INT_DEVICE_H
|
||||
#define V4L2_INT_DEVICE_H
|
||||
|
||||
#include <media/v4l2-common.h>
|
||||
|
||||
#define V4L2NAMESIZE 32
|
||||
|
||||
/*
|
||||
*
|
||||
* The internal V4L2 device interface core.
|
||||
*
|
||||
*/
|
||||
|
||||
enum v4l2_int_type {
|
||||
v4l2_int_type_master = 1,
|
||||
v4l2_int_type_slave
|
||||
};
|
||||
|
||||
struct module;
|
||||
|
||||
struct v4l2_int_device;
|
||||
|
||||
struct v4l2_int_master {
|
||||
int (*attach)(struct v4l2_int_device *slave);
|
||||
void (*detach)(struct v4l2_int_device *slave);
|
||||
};
|
||||
|
||||
typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *);
|
||||
typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *);
|
||||
typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *);
|
||||
|
||||
struct v4l2_int_ioctl_desc {
|
||||
int num;
|
||||
v4l2_int_ioctl_func *func;
|
||||
};
|
||||
|
||||
struct v4l2_int_slave {
|
||||
/* Don't touch master. */
|
||||
struct v4l2_int_device *master;
|
||||
|
||||
char attach_to[V4L2NAMESIZE];
|
||||
|
||||
int num_ioctls;
|
||||
struct v4l2_int_ioctl_desc *ioctls;
|
||||
};
|
||||
|
||||
struct v4l2_int_device {
|
||||
/* Don't touch head. */
|
||||
struct list_head head;
|
||||
|
||||
struct module *module;
|
||||
|
||||
char name[V4L2NAMESIZE];
|
||||
|
||||
enum v4l2_int_type type;
|
||||
union {
|
||||
struct v4l2_int_master *master;
|
||||
struct v4l2_int_slave *slave;
|
||||
} u;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
void v4l2_int_device_try_attach_all(void);
|
||||
|
||||
int v4l2_int_device_register(struct v4l2_int_device *d);
|
||||
void v4l2_int_device_unregister(struct v4l2_int_device *d);
|
||||
|
||||
int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd);
|
||||
int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg);
|
||||
|
||||
/*
|
||||
*
|
||||
* Types and definitions for IOCTL commands.
|
||||
*
|
||||
*/
|
||||
|
||||
enum v4l2_power {
|
||||
V4L2_POWER_OFF = 0,
|
||||
V4L2_POWER_ON,
|
||||
V4L2_POWER_STANDBY,
|
||||
};
|
||||
|
||||
/* Slave interface type. */
|
||||
enum v4l2_if_type {
|
||||
/*
|
||||
* Parallel 8-, 10- or 12-bit interface, used by for example
|
||||
* on certain image sensors.
|
||||
*/
|
||||
V4L2_IF_TYPE_BT656,
|
||||
};
|
||||
|
||||
enum v4l2_if_type_bt656_mode {
|
||||
/*
|
||||
* Modes without Bt synchronisation codes. Separate
|
||||
* synchronisation signal lines are used.
|
||||
*/
|
||||
V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT,
|
||||
V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT,
|
||||
V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT,
|
||||
/*
|
||||
* Use Bt synchronisation codes. The vertical and horizontal
|
||||
* synchronisation is done based on synchronisation codes.
|
||||
*/
|
||||
V4L2_IF_TYPE_BT656_MODE_BT_8BIT,
|
||||
V4L2_IF_TYPE_BT656_MODE_BT_10BIT,
|
||||
};
|
||||
|
||||
struct v4l2_if_type_bt656 {
|
||||
/*
|
||||
* 0: Frame begins when vsync is high.
|
||||
* 1: Frame begins when vsync changes from low to high.
|
||||
*/
|
||||
unsigned frame_start_on_rising_vs:1;
|
||||
/* Use Bt synchronisation codes for sync correction. */
|
||||
unsigned bt_sync_correct:1;
|
||||
/* Swap every two adjacent image data elements. */
|
||||
unsigned swap:1;
|
||||
/* Inverted latch clock polarity from slave. */
|
||||
unsigned latch_clk_inv:1;
|
||||
/* Hs polarity. 0 is active high, 1 active low. */
|
||||
unsigned nobt_hs_inv:1;
|
||||
/* Vs polarity. 0 is active high, 1 active low. */
|
||||
unsigned nobt_vs_inv:1;
|
||||
enum v4l2_if_type_bt656_mode mode;
|
||||
/* Minimum accepted bus clock for slave (in Hz). */
|
||||
u32 clock_min;
|
||||
/* Maximum accepted bus clock for slave. */
|
||||
u32 clock_max;
|
||||
/*
|
||||
* Current wish of the slave. May only change in response to
|
||||
* ioctls that affect image capture.
|
||||
*/
|
||||
u32 clock_curr;
|
||||
};
|
||||
|
||||
struct v4l2_ifparm {
|
||||
enum v4l2_if_type if_type;
|
||||
union {
|
||||
struct v4l2_if_type_bt656 bt656;
|
||||
} u;
|
||||
};
|
||||
|
||||
/* IOCTL command numbers. */
|
||||
enum v4l2_int_ioctl_num {
|
||||
/*
|
||||
*
|
||||
* "Proper" V4L ioctls, as in struct video_device.
|
||||
*
|
||||
*/
|
||||
vidioc_int_enum_fmt_cap_num = 1,
|
||||
vidioc_int_g_fmt_cap_num,
|
||||
vidioc_int_s_fmt_cap_num,
|
||||
vidioc_int_try_fmt_cap_num,
|
||||
vidioc_int_queryctrl_num,
|
||||
vidioc_int_g_ctrl_num,
|
||||
vidioc_int_s_ctrl_num,
|
||||
vidioc_int_cropcap_num,
|
||||
vidioc_int_g_crop_num,
|
||||
vidioc_int_s_crop_num,
|
||||
vidioc_int_g_parm_num,
|
||||
vidioc_int_s_parm_num,
|
||||
vidioc_int_querystd_num,
|
||||
vidioc_int_s_std_num,
|
||||
vidioc_int_s_video_routing_num,
|
||||
|
||||
/*
|
||||
*
|
||||
* Strictly internal ioctls.
|
||||
*
|
||||
*/
|
||||
/* Initialise the device when slave attaches to the master. */
|
||||
vidioc_int_dev_init_num = 1000,
|
||||
/* Delinitialise the device at slave detach. */
|
||||
vidioc_int_dev_exit_num,
|
||||
/* Set device power state. */
|
||||
vidioc_int_s_power_num,
|
||||
/*
|
||||
* Get slave private data, e.g. platform-specific slave
|
||||
* configuration used by the master.
|
||||
*/
|
||||
vidioc_int_g_priv_num,
|
||||
/* Get slave interface parameters. */
|
||||
vidioc_int_g_ifparm_num,
|
||||
/* Does the slave need to be reset after VIDIOC_DQBUF? */
|
||||
vidioc_int_g_needs_reset_num,
|
||||
vidioc_int_enum_framesizes_num,
|
||||
vidioc_int_enum_frameintervals_num,
|
||||
|
||||
/*
|
||||
*
|
||||
* VIDIOC_INT_* ioctls.
|
||||
*
|
||||
*/
|
||||
/* VIDIOC_INT_RESET */
|
||||
vidioc_int_reset_num,
|
||||
/* VIDIOC_INT_INIT */
|
||||
vidioc_int_init_num,
|
||||
/* VIDIOC_DBG_G_CHIP_IDENT */
|
||||
vidioc_int_g_chip_ident_num,
|
||||
|
||||
/*
|
||||
*
|
||||
* Start of private ioctls.
|
||||
*
|
||||
*/
|
||||
vidioc_int_priv_start_num = 2000,
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* IOCTL wrapper functions for better type checking.
|
||||
*
|
||||
*/
|
||||
|
||||
#define V4L2_INT_WRAPPER_0(name) \
|
||||
static inline int vidioc_int_##name(struct v4l2_int_device *d) \
|
||||
{ \
|
||||
return v4l2_int_ioctl_0(d, vidioc_int_##name##_num); \
|
||||
} \
|
||||
\
|
||||
static inline struct v4l2_int_ioctl_desc \
|
||||
vidioc_int_##name##_cb(int (*func) \
|
||||
(struct v4l2_int_device *)) \
|
||||
{ \
|
||||
struct v4l2_int_ioctl_desc desc; \
|
||||
\
|
||||
desc.num = vidioc_int_##name##_num; \
|
||||
desc.func = (v4l2_int_ioctl_func *)func; \
|
||||
\
|
||||
return desc; \
|
||||
}
|
||||
|
||||
#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk) \
|
||||
static inline int vidioc_int_##name(struct v4l2_int_device *d, \
|
||||
arg_type asterisk arg) \
|
||||
{ \
|
||||
return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \
|
||||
(void *)(unsigned long)arg); \
|
||||
} \
|
||||
\
|
||||
static inline struct v4l2_int_ioctl_desc \
|
||||
vidioc_int_##name##_cb(int (*func) \
|
||||
(struct v4l2_int_device *, \
|
||||
arg_type asterisk)) \
|
||||
{ \
|
||||
struct v4l2_int_ioctl_desc desc; \
|
||||
\
|
||||
desc.num = vidioc_int_##name##_num; \
|
||||
desc.func = (v4l2_int_ioctl_func *)func; \
|
||||
\
|
||||
return desc; \
|
||||
}
|
||||
|
||||
V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *);
|
||||
V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *);
|
||||
V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *);
|
||||
V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *);
|
||||
V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *);
|
||||
V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *);
|
||||
V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *);
|
||||
V4L2_INT_WRAPPER_1(cropcap, struct v4l2_cropcap, *);
|
||||
V4L2_INT_WRAPPER_1(g_crop, struct v4l2_crop, *);
|
||||
V4L2_INT_WRAPPER_1(s_crop, struct v4l2_crop, *);
|
||||
V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *);
|
||||
V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *);
|
||||
V4L2_INT_WRAPPER_1(querystd, v4l2_std_id, *);
|
||||
V4L2_INT_WRAPPER_1(s_std, v4l2_std_id, *);
|
||||
V4L2_INT_WRAPPER_1(s_video_routing, struct v4l2_routing, *);
|
||||
|
||||
V4L2_INT_WRAPPER_0(dev_init);
|
||||
V4L2_INT_WRAPPER_0(dev_exit);
|
||||
V4L2_INT_WRAPPER_1(s_power, enum v4l2_power, /*dummy arg*/);
|
||||
V4L2_INT_WRAPPER_1(g_priv, void, *);
|
||||
V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *);
|
||||
V4L2_INT_WRAPPER_1(g_needs_reset, void, *);
|
||||
V4L2_INT_WRAPPER_1(enum_framesizes, struct v4l2_frmsizeenum, *);
|
||||
V4L2_INT_WRAPPER_1(enum_frameintervals, struct v4l2_frmivalenum, *);
|
||||
|
||||
V4L2_INT_WRAPPER_0(reset);
|
||||
V4L2_INT_WRAPPER_0(init);
|
||||
V4L2_INT_WRAPPER_1(g_chip_ident, int, *);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,38 @@
|
|||
if VIDEO_MXC_CAPTURE
|
||||
|
||||
config VIDEO_MXC_CSI_CAMERA
|
||||
tristate "CSI camera support"
|
||||
depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2
|
||||
---help---
|
||||
This is the video4linux2 capture driver based on CSI module.
|
||||
|
||||
config MXC_CAMERA_OV5640
|
||||
tristate "OmniVision ov5640 camera support"
|
||||
depends on VIDEO_MXC_CAPTURE && I2C
|
||||
---help---
|
||||
If you plan to use the ov5640 Camera with your MXC system, say Y here.
|
||||
|
||||
config MXC_VADC
|
||||
tristate "mxc VADC support"
|
||||
depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2
|
||||
---help---
|
||||
If you plan to use the VADC with your MXC system, say Y here.
|
||||
|
||||
config MXC_MIPI_CSI
|
||||
tristate "mxc mipi csi driver"
|
||||
depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2
|
||||
---help---
|
||||
This is a V4L2 driver for i.MX7D SoC MIPI-CSI2 receiver devices.
|
||||
|
||||
config MXC_CAMERA_OV5640_MIPI
|
||||
tristate "OmniVision ov5640 camera support using mipi"
|
||||
depends on MXC_MIPI_CSI && I2C
|
||||
---help---
|
||||
If you plan to use the ov5640 Camera with mipi interface in your MXC system, say Y here.
|
||||
|
||||
config MXC_CAMERA_OV5647_MIPI
|
||||
tristate "OmniVision ov5647 camera support using mipi"
|
||||
depends on MXC_MIPI_CSI && I2C
|
||||
---help---
|
||||
If you plan to use the ov5647 Camera with mipi interface in your MXC system, say Y here.
|
||||
endif
|
|
@ -0,0 +1,14 @@
|
|||
#Makefile for mxc csi driver
|
||||
|
||||
obj-$(CONFIG_VIDEO_MXC_CSI_CAMERA) += mx6s_capture.o
|
||||
obj-$(CONFIG_MXC_VADC) += mxc_vadc.o
|
||||
obj-$(CONFIG_MXC_MIPI_CSI) += mxc_mipi_csi.o
|
||||
|
||||
ov5640_camera-objs := ov5640.o
|
||||
obj-$(CONFIG_MXC_CAMERA_OV5640) += ov5640_camera.o
|
||||
|
||||
ov5640_camera_mipi-objs := ov5640_mipi.o
|
||||
obj-$(CONFIG_MXC_CAMERA_OV5640_MIPI) += ov5640_camera_mipi.o
|
||||
|
||||
ov5647_camera_mipi-objs := ov5647_mipi.o
|
||||
obj-$(CONFIG_MXC_CAMERA_OV5647_MIPI) += ov5647_camera_mipi.o
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,817 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/media-bus-format.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include "mxc_vadc.h"
|
||||
|
||||
/* Resource names for the VADC driver. */
|
||||
#define VAFE_REGS_ADDR_RES_NAME "vadc-vafe"
|
||||
#define VDEC_REGS_ADDR_RES_NAME "vadc-vdec"
|
||||
|
||||
#define reg32_write(addr, val) __raw_writel(val, addr)
|
||||
#define reg32_read(addr) __raw_readl(addr)
|
||||
#define reg32setbit(addr, bitpos) \
|
||||
reg32_write((addr), (reg32_read((addr)) | (1<<(bitpos))))
|
||||
|
||||
#define reg32clrbit(addr, bitpos) \
|
||||
reg32_write((addr), (reg32_read((addr)) & (0xFFFFFFFF ^ (1<<(bitpos)))))
|
||||
|
||||
#define GPC_CNTR 0x00
|
||||
#define IMX6SX_GPC_CNTR_VADC_ANALOG_OFF_MASK BIT(17)
|
||||
#define IMX6SX_GPC_CNTR_VADC_POWER_DOWN_MASK BIT(18)
|
||||
|
||||
void __iomem *vafe_regbase;
|
||||
void __iomem *vdec_regbase;
|
||||
|
||||
|
||||
/* List of input video formats supported. The video formats is corresponding
|
||||
* with v4l2 id in video_fmt
|
||||
*/
|
||||
enum video_fmt_idx {
|
||||
VADC_NTSC = 0, /* Locked on (M) NTSC video signal. */
|
||||
VADC_PAL, /* (B, G, H, I, N)PAL video signal. */
|
||||
};
|
||||
|
||||
/* Number of video standards supported (including 'not locked' signal). */
|
||||
#define VADC_STD_MAX (VADC_PAL + 1)
|
||||
|
||||
/* Video format structure. */
|
||||
struct video_fmt{
|
||||
v4l2_std_id v4l2_std; /* Video for linux ID. */
|
||||
char name[16]; /* Name (e.g., "NTSC", "PAL", etc.) */
|
||||
u16 raw_width; /* Raw width. */
|
||||
u16 raw_height; /* Raw height. */
|
||||
u16 active_width; /* Active width. */
|
||||
u16 active_height; /* Active height. */
|
||||
u16 framerates;
|
||||
};
|
||||
|
||||
/*
|
||||
* Maintains the information on the current state of the sensor.
|
||||
*/
|
||||
struct vadc_state {
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct v4l2_subdev sd;
|
||||
struct video_fmt *fmt;
|
||||
|
||||
struct clk *vadc_clk;
|
||||
struct clk *csi_clk;
|
||||
struct regmap *gpr;
|
||||
void __iomem *gpc_reg;
|
||||
|
||||
u32 vadc_in;
|
||||
u32 csi_id;
|
||||
};
|
||||
|
||||
static int vadc_querystd(struct v4l2_subdev *sd, v4l2_std_id *std);
|
||||
|
||||
/* Description of video formats supported.
|
||||
*
|
||||
* PAL: raw=720x625, active=720x576.
|
||||
* NTSC: raw=720x525, active=720x480.
|
||||
*/
|
||||
static struct video_fmt video_fmts[] = {
|
||||
/* NTSC */
|
||||
{
|
||||
.v4l2_std = V4L2_STD_NTSC,
|
||||
.name = "NTSC",
|
||||
.raw_width = 720,
|
||||
.raw_height = 525,
|
||||
.active_width = 720,
|
||||
.active_height = 480,
|
||||
.framerates = 30,
|
||||
},
|
||||
/* (B, G, H, I, N) PAL */
|
||||
{
|
||||
.v4l2_std = V4L2_STD_PAL,
|
||||
.name = "PAL",
|
||||
.raw_width = 720,
|
||||
.raw_height = 625,
|
||||
.active_width = 720,
|
||||
.active_height = 576,
|
||||
.framerates = 25,
|
||||
},
|
||||
};
|
||||
|
||||
static void afe_voltage_clampingmode(void)
|
||||
{
|
||||
reg32_write(AFE_CLAMP, 0x07);
|
||||
reg32_write(AFE_CLMPAMP, 0x60);
|
||||
reg32_write(AFE_CLMPDAT, 0xF0);
|
||||
}
|
||||
|
||||
static void afe_alwayson_clampingmode(void)
|
||||
{
|
||||
reg32_write(AFE_CLAMP, 0x15);
|
||||
reg32_write(AFE_CLMPDAT, 0x08);
|
||||
reg32_write(AFE_CLMPAMP, 0x00);
|
||||
}
|
||||
|
||||
static void afe_init(void)
|
||||
{
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
reg32_write(AFE_PDBUF, 0x1f);
|
||||
reg32_write(AFE_PDADC, 0x0f);
|
||||
reg32_write(AFE_PDSARH, 0x01);
|
||||
reg32_write(AFE_PDSARL, 0xff);
|
||||
reg32_write(AFE_PDADCRFH, 0x01);
|
||||
reg32_write(AFE_PDADCRFL, 0xff);
|
||||
reg32_write(AFE_ICTRL, 0x3a);
|
||||
reg32_write(AFE_ICTLSTG, 0x1e);
|
||||
|
||||
reg32_write(AFE_RCTRLSTG, 0x1e);
|
||||
reg32_write(AFE_INPBUF, 0x035);
|
||||
reg32_write(AFE_INPFLT, 0x02);
|
||||
reg32_write(AFE_ADCDGN, 0x40);
|
||||
reg32_write(AFE_TSTSEL, 0x10);
|
||||
|
||||
reg32_write(AFE_ACCTST, 0x07);
|
||||
|
||||
reg32_write(AFE_BGREG, 0x08);
|
||||
|
||||
reg32_write(AFE_ADCGN, 0x09);
|
||||
|
||||
/* set current controlled clamping
|
||||
* always on, low current */
|
||||
reg32_write(AFE_CLAMP, 0x11);
|
||||
reg32_write(AFE_CLMPAMP, 0x08);
|
||||
}
|
||||
|
||||
static void vdec_mode_timing_init(int std)
|
||||
{
|
||||
if (std == V4L2_STD_NTSC) {
|
||||
/* NTSC 720x480 */
|
||||
reg32_write(VDEC_HACTS, 0x66);
|
||||
reg32_write(VDEC_HACTE, 0x24);
|
||||
|
||||
reg32_write(VDEC_VACTS, 0x29);
|
||||
reg32_write(VDEC_VACTE, 0x04);
|
||||
|
||||
/* set V Position */
|
||||
reg32_write(VDEC_VRTPOS, 0x2);
|
||||
} else if (std == V4L2_STD_PAL) {
|
||||
/* PAL 720x576 */
|
||||
reg32_write(VDEC_HACTS, 0x66);
|
||||
reg32_write(VDEC_HACTE, 0x24);
|
||||
|
||||
reg32_write(VDEC_VACTS, 0x29);
|
||||
reg32_write(VDEC_VACTE, 0x04);
|
||||
|
||||
/* set V Position */
|
||||
reg32_write(VDEC_VRTPOS, 0x6);
|
||||
} else
|
||||
pr_debug("Error not support video mode\n");
|
||||
|
||||
/* set H Position */
|
||||
reg32_write(VDEC_HZPOS, 0x60);
|
||||
|
||||
/* set H ignore start */
|
||||
reg32_write(VDEC_HSIGS, 0xf8);
|
||||
|
||||
/* set H ignore end */
|
||||
reg32_write(VDEC_HSIGE, 0x18);
|
||||
}
|
||||
|
||||
/*
|
||||
* vdec_init()
|
||||
* Initialises the VDEC registers
|
||||
* Returns: nothing
|
||||
*/
|
||||
static void vdec_init(struct vadc_state *vadc)
|
||||
{
|
||||
v4l2_std_id std;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
/* Get work mode PAL or NTSC */
|
||||
vadc_querystd(&vadc->sd, &std);
|
||||
|
||||
vdec_mode_timing_init(std);
|
||||
|
||||
/* vcr detect threshold high, automatic detections */
|
||||
reg32_write(VDEC_VSCON2, 0);
|
||||
|
||||
reg32_write(VDEC_BASE + 0x110, 0x01);
|
||||
|
||||
/* set the noramp mode on the Hloop PLL. */
|
||||
reg32_write(VDEC_BASE+(0x14*4), 0x10);
|
||||
|
||||
/* set the YC relative delay.*/
|
||||
reg32_write(VDEC_YCDEL, 0x90);
|
||||
|
||||
/* setup the Hpll */
|
||||
reg32_write(VDEC_BASE+(0x13*4), 0x13);
|
||||
|
||||
/* setup the 2d comb */
|
||||
/* set the gain of the Hdetail output to 3
|
||||
* set the notch alpha gain to 1 */
|
||||
reg32_write(VDEC_CFC2, 0x34);
|
||||
|
||||
/* setup various 2d comb bits.*/
|
||||
reg32_write(VDEC_BASE+(0x02*4), 0x01);
|
||||
reg32_write(VDEC_BASE+(0x03*4), 0x18);
|
||||
reg32_write(VDEC_BASE+(0x04*4), 0x34);
|
||||
|
||||
/* set the start of the burst gate */
|
||||
reg32_write(VDEC_BRSTGT, 0x30);
|
||||
|
||||
/* set 1f motion gain */
|
||||
reg32_write(VDEC_BASE+(0x0f*4), 0x20);
|
||||
|
||||
/* set the 1F chroma motion detector thresh
|
||||
* for colour reverse detection */
|
||||
reg32_write(VDEC_THSH1, 0x02);
|
||||
reg32_write(VDEC_BASE+(0x4a*4), 0x20);
|
||||
reg32_write(VDEC_BASE+(0x4b*4), 0x08);
|
||||
|
||||
reg32_write(VDEC_BASE+(0x4c*4), 0x08);
|
||||
|
||||
/* set the threshold for the narrow/wide adaptive chroma BW */
|
||||
reg32_write(VDEC_BASE+(0x20*4), 0x20);
|
||||
|
||||
/* turn up the colour with the new colour gain reg */
|
||||
/* hue: */
|
||||
reg32_write(VDEC_HUE, 0x00);
|
||||
|
||||
/* cbgain: 22 B4 */
|
||||
reg32_write(VDEC_CBGN, 0xb4);
|
||||
/* cr gain 80 */
|
||||
reg32_write(VDEC_CRGN, 0x80);
|
||||
/* luma gain (contrast) */
|
||||
reg32_write(VDEC_CNTR, 0x80);
|
||||
|
||||
/* setup the signed black level register, brightness */
|
||||
reg32_write(VDEC_BRT, 0x00);
|
||||
|
||||
/* filter the standard detection
|
||||
* enable the comb for the ntsc443 */
|
||||
reg32_write(VDEC_STDDBG, 0x20);
|
||||
|
||||
/* setup chroma kill thresh for no chroma */
|
||||
reg32_write(VDEC_CHBTH, 0x0);
|
||||
|
||||
/* set chroma loop to wider BW
|
||||
* no set it to normal BW. i fixed the bw problem.*/
|
||||
reg32_write(VDEC_YCDEL, 0x00);
|
||||
|
||||
/* set the compensation in the chroma loop for the Hloop
|
||||
* set the ratio for the nonarithmetic 3d comb modes.*/
|
||||
reg32_write(VDEC_BASE + (0x1d*4), 0x90);
|
||||
|
||||
/* set the threshold for the nonarithmetic mode for the 2d comb
|
||||
* the higher the value the more Fc Fh offset
|
||||
* we will tolerate before turning off the comb. */
|
||||
reg32_write(VDEC_BASE + (0x33*4), 0xa0);
|
||||
|
||||
/* setup the bluescreen output colour */
|
||||
reg32_write(VDEC_BASE + (0x3d*4), 35);
|
||||
reg32_write(VDEC_BLSCRCR, 114);
|
||||
reg32_write(VDEC_BLSCRCB, 212);
|
||||
|
||||
/* disable the active blanking */
|
||||
reg32_write(VDEC_BASE + (0x15*4), 0x02);
|
||||
|
||||
/* setup the luma agc for automatic gain. */
|
||||
reg32_write(VDEC_LMAGC2, 0x5e);
|
||||
reg32_write(VDEC_LMAGC1, 0x81);
|
||||
|
||||
/* setup chroma agc */
|
||||
reg32_write(VDEC_CHAGC2, 0xa0);
|
||||
reg32_write(VDEC_CHAGC1, 0x01);
|
||||
|
||||
/* setup the MV thresh lower nibble
|
||||
* setup the sync top cap, upper nibble */
|
||||
reg32_write(VDEC_BASE + (0x3a*4), 0x80);
|
||||
reg32_write(VDEC_SHPIMP, 0x00);
|
||||
|
||||
/* setup the vsync block */
|
||||
reg32_write(VDEC_VSCON1, 0x87);
|
||||
|
||||
/* set the nosignal threshold
|
||||
* set the vsync threshold */
|
||||
reg32_write(VDEC_VSSGTH, 0x35);
|
||||
|
||||
/* set length for min hphase filter
|
||||
* (or saturate limit if saturate is chosen) */
|
||||
reg32_write(VDEC_BASE + (0x45*4), 0x40);
|
||||
|
||||
/* enable the internal resampler,
|
||||
* select min filter not saturate for
|
||||
* hphase noise filter for vcr detect.
|
||||
* enable vcr pause mode different field lengths */
|
||||
reg32_write(VDEC_BASE + (0x46*4), 0x90);
|
||||
|
||||
/* disable VCR detection, lock to the Hsync rather than the Vsync */
|
||||
reg32_write(VDEC_VSCON2, 0x04);
|
||||
|
||||
/* set tiplevel goal for dc clamp. */
|
||||
reg32_write(VDEC_BASE + (0x3c*4), 0xB0);
|
||||
|
||||
/* override SECAM detection and force SECAM off */
|
||||
reg32_write(VDEC_BASE + (0x2f*4), 0x20);
|
||||
|
||||
/* Set r3d_hardblend in 3D control2 reg */
|
||||
reg32_write(VDEC_BASE + (0x0c*4), 0x04);
|
||||
}
|
||||
|
||||
/* set Input selector & input pull-downs */
|
||||
static void vadc_s_routing(int vadc_in)
|
||||
{
|
||||
switch (vadc_in) {
|
||||
case 0:
|
||||
reg32_write(AFE_INPFLT, 0x02);
|
||||
reg32_write(AFE_OFFDRV, 0x00);
|
||||
reg32_write(AFE_INPCONFIG, 0x1e);
|
||||
break;
|
||||
case 1:
|
||||
reg32_write(AFE_INPFLT, 0x02);
|
||||
reg32_write(AFE_OFFDRV, 0x00);
|
||||
reg32_write(AFE_INPCONFIG, 0x2d);
|
||||
break;
|
||||
case 2:
|
||||
reg32_write(AFE_INPFLT, 0x02);
|
||||
reg32_write(AFE_OFFDRV, 0x00);
|
||||
reg32_write(AFE_INPCONFIG, 0x4b);
|
||||
break;
|
||||
case 3:
|
||||
reg32_write(AFE_INPFLT, 0x02);
|
||||
reg32_write(AFE_OFFDRV, 0x00);
|
||||
reg32_write(AFE_INPCONFIG, 0x87);
|
||||
break;
|
||||
default:
|
||||
pr_debug("error video input %d\n", vadc_in);
|
||||
}
|
||||
}
|
||||
|
||||
static void vadc_power_up(struct vadc_state *state)
|
||||
{
|
||||
/* Power on vadc analog */
|
||||
reg32clrbit(state->gpc_reg + GPC_CNTR, 17);
|
||||
|
||||
/* Power down vadc ext power */
|
||||
reg32clrbit(state->gpc_reg + GPC_CNTR, 18);
|
||||
|
||||
/* software reset afe */
|
||||
regmap_update_bits(state->gpr, IOMUXC_GPR1,
|
||||
IMX6SX_GPR1_VADC_SW_RST_MASK,
|
||||
IMX6SX_GPR1_VADC_SW_RST_RESET);
|
||||
|
||||
msleep(10);
|
||||
|
||||
/* clock config for vadc */
|
||||
reg32_write(VDEC_BASE + 0x320, 0xe3);
|
||||
reg32_write(VDEC_BASE + 0x324, 0x38);
|
||||
reg32_write(VDEC_BASE + 0x328, 0x8e);
|
||||
reg32_write(VDEC_BASE + 0x32c, 0x23);
|
||||
|
||||
/* Release reset bit */
|
||||
regmap_update_bits(state->gpr, IOMUXC_GPR1,
|
||||
IMX6SX_GPR1_VADC_SW_RST_MASK,
|
||||
IMX6SX_GPR1_VADC_SW_RST_RELEASE);
|
||||
|
||||
/* Power on vadc ext power */
|
||||
reg32setbit(state->gpc_reg + GPC_CNTR, 18);
|
||||
}
|
||||
|
||||
static void vadc_power_down(struct vadc_state *state)
|
||||
{
|
||||
/* Power down vadc analog */
|
||||
reg32setbit(state->gpc_reg + GPC_CNTR, 17);
|
||||
|
||||
/* Power down vadc ext power */
|
||||
reg32clrbit(state->gpc_reg + GPC_CNTR, 18);
|
||||
|
||||
}
|
||||
static void vadc_init(struct vadc_state *vadc)
|
||||
{
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
vadc_power_up(vadc);
|
||||
|
||||
afe_init();
|
||||
|
||||
/* select Video Input 0-3 */
|
||||
vadc_s_routing(vadc->vadc_in);
|
||||
|
||||
afe_voltage_clampingmode();
|
||||
|
||||
vdec_init(vadc);
|
||||
|
||||
/*
|
||||
* current control loop will move sinewave input off below
|
||||
* the bottom of the signal range visible
|
||||
* when the testbus is viewed as magnitude,
|
||||
* so have to break before this point while capturing ENOB data:
|
||||
*/
|
||||
afe_alwayson_clampingmode();
|
||||
}
|
||||
|
||||
static inline struct vadc_state *to_state(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct vadc_state, sd);
|
||||
}
|
||||
|
||||
static int vadc_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
|
||||
{
|
||||
struct vadc_state *state = to_state(sd);
|
||||
|
||||
*std = state->fmt->v4l2_std;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Return attributes of current video standard.
|
||||
* Since this device autodetects the current standard, this function also
|
||||
* sets the values that need to be changed if the standard changes.
|
||||
* There is no set std equivalent function.
|
||||
*
|
||||
* @return None.
|
||||
*/
|
||||
static int vadc_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
|
||||
{
|
||||
struct vadc_state *state = to_state(sd);
|
||||
int mod;
|
||||
int idx;
|
||||
int i;
|
||||
|
||||
/* Read auto mode detected result */
|
||||
printk(KERN_INFO"wait vadc auto detect video mode....\n");
|
||||
for (i = 0; i < 10; i++) {
|
||||
msleep(200);
|
||||
mod = reg32_read(VDEC_VIDMOD);
|
||||
/* Check video signal states */
|
||||
if ((mod & VDEC_VIDMOD_SIGNAL_MASK)
|
||||
== VDEC_VIDMOD_SIGNAL_DETECT)
|
||||
break;
|
||||
}
|
||||
if (i == 10)
|
||||
printk(KERN_INFO"Timeout detect video signal mod=0x%x\n", mod);
|
||||
|
||||
if ((mod & VDEC_VIDMOD_PAL_MASK) || (mod & VDEC_VIDMOD_M625_MASK))
|
||||
idx = VADC_PAL;
|
||||
else
|
||||
idx = VADC_NTSC;
|
||||
|
||||
*std = video_fmts[idx].v4l2_std;
|
||||
state->fmt = &video_fmts[idx];
|
||||
|
||||
printk(KERN_INFO"video mode %s\n", video_fmts[idx].name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_enum_mbus_fmt(struct v4l2_subdev *sd,
|
||||
unsigned index, u32 *code)
|
||||
{
|
||||
/* support only one format */
|
||||
if (index >= 1)
|
||||
return -EINVAL;
|
||||
|
||||
*code = MEDIA_BUS_FMT_AYUV8_1X32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_mbus_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *fmt)
|
||||
{
|
||||
struct vadc_state *state = to_state(sd);
|
||||
|
||||
fmt->code = MEDIA_BUS_FMT_AYUV8_1X32;
|
||||
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
fmt->field = V4L2_FIELD_INTERLACED;
|
||||
fmt->width = 720;
|
||||
fmt->height = state->fmt->v4l2_std & V4L2_STD_NTSC ? 480 : 576;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_enum_framesizes(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_frame_size_enum *fse)
|
||||
{
|
||||
struct vadc_state *state = to_state(sd);
|
||||
if (fse->index >= 1)
|
||||
return -EINVAL;
|
||||
|
||||
fse->min_width = state->fmt->active_width;
|
||||
fse->max_width = state->fmt->active_width;
|
||||
fse->min_height = state->fmt->active_height;
|
||||
fse->max_height = state->fmt->active_height;
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int vadc_enum_frameintervals(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_frame_interval_enum *fie)
|
||||
{
|
||||
struct vadc_state *state = to_state(sd);
|
||||
|
||||
if (fie->index < 0 || fie->index >= 1)
|
||||
return -EINVAL;
|
||||
|
||||
fie->interval.numerator = 1;
|
||||
|
||||
fie->interval.denominator = state->fmt->framerates;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
|
||||
{
|
||||
struct vadc_state *state = to_state(sd);
|
||||
|
||||
if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
|
||||
if (parms->parm.capture.timeperframe.denominator
|
||||
!= state->fmt->framerates)
|
||||
parms->parm.capture.timeperframe.denominator
|
||||
= state->fmt->framerates;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops vadc_video_ops = {
|
||||
.querystd = vadc_querystd,
|
||||
.enum_mbus_fmt = vadc_enum_mbus_fmt,
|
||||
.try_mbus_fmt = vadc_mbus_fmt,
|
||||
.g_mbus_fmt = vadc_mbus_fmt,
|
||||
.s_mbus_fmt = vadc_mbus_fmt,
|
||||
.s_parm = vadc_s_parm,
|
||||
.g_std = vadc_g_std,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops vadc_pad_ops = {
|
||||
.enum_frame_size = vadc_enum_framesizes,
|
||||
.enum_frame_interval = vadc_enum_frameintervals,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops vadc_ops = {
|
||||
.video = &vadc_video_ops,
|
||||
.pad = &vadc_pad_ops,
|
||||
};
|
||||
|
||||
static const struct of_device_id fsl_vadc_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx6sx-vadc", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fsl_vadc_dt_ids);
|
||||
|
||||
static int vadc_of_init(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *gpc_np;
|
||||
struct vadc_state *state = platform_get_drvdata(pdev);
|
||||
int csi_id;
|
||||
int ret;
|
||||
|
||||
/* Get csi_id to setting vadc to csi mux in gpr */
|
||||
ret = of_property_read_u32(np, "csi_id", &csi_id);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to read of property csi_id\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
state->csi_id = csi_id;
|
||||
|
||||
/* remap GPR register */
|
||||
state->gpr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||
"gpr");
|
||||
if (IS_ERR(state->gpr)) {
|
||||
dev_dbg(&pdev->dev, "can not get gpr\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Configuration vadc-to-csi 0 or 1 */
|
||||
if (csi_id) {
|
||||
regmap_update_bits(state->gpr, IOMUXC_GPR5,
|
||||
IMX6SX_GPR5_CSI2_MUX_CTRL_MASK,
|
||||
IMX6SX_GPR5_CSI2_MUX_CTRL_CVD);
|
||||
} else {
|
||||
regmap_update_bits(state->gpr, IOMUXC_GPR5,
|
||||
IMX6SX_GPR5_CSI1_MUX_CTRL_MASK,
|
||||
IMX6SX_GPR5_CSI1_MUX_CTRL_CVD);
|
||||
}
|
||||
|
||||
/* Get default vadc_in number */
|
||||
ret = of_property_read_u32(np, "vadc_in", &state->vadc_in);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to read of property vadc_in\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* map GPC register */
|
||||
gpc_np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc");
|
||||
state->gpc_reg = of_iomap(gpc_np, 0);
|
||||
if (!state->gpc_reg) {
|
||||
dev_err(&pdev->dev, "ioremap failed with gpc base\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
iounmap(state->gpc_reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vadc_v4l2_subdev_init(struct v4l2_subdev *sd,
|
||||
struct platform_device *pdev,
|
||||
const struct v4l2_subdev_ops *ops)
|
||||
{
|
||||
struct vadc_state *state = platform_get_drvdata(pdev);
|
||||
int ret = 0;
|
||||
|
||||
v4l2_subdev_init(sd, ops);
|
||||
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
sd->owner = pdev->dev.driver->owner;
|
||||
sd->dev = &pdev->dev;
|
||||
|
||||
/* initialize name */
|
||||
snprintf(sd->name, sizeof(sd->name), "%s",
|
||||
pdev->dev.driver->name);
|
||||
|
||||
v4l2_set_subdevdata(sd, state);
|
||||
|
||||
ret = v4l2_async_register_subdev(sd);
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "%s--Async register faialed, ret=%d\n", __func__, ret);
|
||||
}
|
||||
|
||||
static int vadc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct vadc_state *state;
|
||||
struct v4l2_subdev *sd;
|
||||
struct resource *res;
|
||||
int ret = 0;
|
||||
|
||||
state = devm_kzalloc(&pdev->dev, sizeof(struct vadc_state), GFP_KERNEL);
|
||||
if (!state) {
|
||||
dev_err(&pdev->dev, "Cannot allocate device data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Set initial values for the sensor struct. */
|
||||
state->fmt = &video_fmts[VADC_NTSC];
|
||||
|
||||
sd = &state->sd;
|
||||
|
||||
/* map vafe address */
|
||||
res = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_MEM, VAFE_REGS_ADDR_RES_NAME);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "No vafe base address found.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
vafe_regbase = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (!vafe_regbase) {
|
||||
dev_err(&pdev->dev, "ioremap failed with vafe base\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* map vdec address */
|
||||
res = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_MEM, VDEC_REGS_ADDR_RES_NAME);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "No vdec base address found.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
vdec_regbase = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (!vdec_regbase) {
|
||||
dev_err(&pdev->dev, "ioremap failed with vdec base\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Get clock */
|
||||
state->vadc_clk = devm_clk_get(&pdev->dev, "vadc");
|
||||
if (IS_ERR(state->vadc_clk)) {
|
||||
ret = PTR_ERR(state->vadc_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
state->csi_clk = devm_clk_get(&pdev->dev, "csi");
|
||||
if (IS_ERR(state->csi_clk)) {
|
||||
ret = PTR_ERR(state->csi_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* clock */
|
||||
clk_prepare_enable(state->csi_clk);
|
||||
clk_prepare_enable(state->vadc_clk);
|
||||
|
||||
platform_set_drvdata(pdev, state);
|
||||
|
||||
vadc_v4l2_subdev_init(sd, pdev, &vadc_ops);
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
/* Init VADC */
|
||||
ret = vadc_of_init(pdev);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
vadc_init(state);
|
||||
|
||||
pr_info("vadc driver loaded\n");
|
||||
|
||||
return 0;
|
||||
err:
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
v4l2_async_unregister_subdev(&state->sd);
|
||||
clk_disable_unprepare(state->csi_clk);
|
||||
clk_disable_unprepare(state->vadc_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vadc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vadc_state *state = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
v4l2_async_unregister_subdev(&state->sd);
|
||||
clk_disable_unprepare(state->csi_clk);
|
||||
clk_disable_unprepare(state->vadc_clk);
|
||||
|
||||
vadc_power_down(state);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int vadc_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct vadc_state *state = platform_get_drvdata(pdev);
|
||||
|
||||
clk_disable(state->csi_clk);
|
||||
clk_disable(state->vadc_clk);
|
||||
|
||||
vadc_power_down(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct vadc_state *state = platform_get_drvdata(pdev);
|
||||
|
||||
clk_enable(state->csi_clk);
|
||||
clk_enable(state->vadc_clk);
|
||||
|
||||
vadc_init(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops vadc_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(vadc_suspend, vadc_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver vadc_driver = {
|
||||
.driver = {
|
||||
.name = "fsl_vadc",
|
||||
.of_match_table = of_match_ptr(fsl_vadc_dt_ids),
|
||||
.pm = &vadc_pm_ops,
|
||||
},
|
||||
.probe = vadc_probe,
|
||||
.remove = vadc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(vadc_driver);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("fsl VADC/VDEC driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MXC_VDEC_H
|
||||
#define MXC_VDEC_H
|
||||
|
||||
/*** define base address ***/
|
||||
#define VDEC_BASE vdec_regbase
|
||||
#define AFE_BASE vafe_regbase
|
||||
|
||||
/* AFE - Register offsets */
|
||||
#define AFE_BLOCK_ID_OFFSET 0x00000000
|
||||
#define AFE_PDBUF_OFFSET 0x00000004
|
||||
#define AFE_SWRST_OFFSET 0x00000008
|
||||
#define AFE_TSTSEL_OFFSET 0x0000000c
|
||||
#define AFE_TSTMSC_OFFSET 0x00000010
|
||||
#define AFE_ENPADIO_OFFSET 0x00000014
|
||||
#define AFE_BGREG_OFFSET 0x00000018
|
||||
#define AFE_ACCESSAR_ID_OFFSET 0x00000400
|
||||
#define AFE_PDADC_OFFSET 0x00000404
|
||||
#define AFE_PDSARH_OFFSET 0x00000408
|
||||
#define AFE_PDSARL_OFFSET 0x0000040C
|
||||
#define AFE_PDADCRFH_OFFSET 0x00000410
|
||||
#define AFE_PDADCRFL_OFFSET 0x00000414
|
||||
#define AFE_ACCTST_OFFSET 0x00000418
|
||||
#define AFE_ADCGN_OFFSET 0x0000041C
|
||||
#define AFE_ICTRL_OFFSET 0x00000420
|
||||
#define AFE_ICTLSTG_OFFSET 0x00000424
|
||||
#define AFE_RCTRLSTG_OFFSET 0x00000428
|
||||
#define AFE_TCTRLSTG_OFFSET 0x0000042c
|
||||
#define AFE_REFMOD_OFFSET 0x00000430
|
||||
#define AFE_REFTRIML_OFFSET 0x00000434
|
||||
#define AFE_REFTRIMH_OFFSET 0x00000438
|
||||
#define AFE_ADCR_OFFSET 0x0000043c
|
||||
#define AFE_DUMMY0_OFFSET 0x00000440
|
||||
#define AFE_DUMMY1_OFFSET 0x00000444
|
||||
#define AFE_DUMMY2_OFFSET 0x00000448
|
||||
#define AFE_DACAMP_OFFSET 0x0000044c
|
||||
#define AFE_CLMPTST_OFFSET 0x00000450
|
||||
#define AFE_CLMPDAT_OFFSET 0x00000454
|
||||
#define AFE_CLMPAMP_OFFSET 0x00000458
|
||||
#define AFE_CLAMP_OFFSET 0x0000045c
|
||||
#define AFE_INPBUF_OFFSET 0x00000460
|
||||
#define AFE_INPFLT_OFFSET 0x00000464
|
||||
#define AFE_ADCDGN_OFFSET 0x00000468
|
||||
#define AFE_OFFDRV_OFFSET 0x0000046c
|
||||
#define AFE_INPCONFIG_OFFSET 0x00000470
|
||||
#define AFE_PROGDELAY_OFFSET 0x00000474
|
||||
#define AFE_ADCOMT_OFFSET 0x00000478
|
||||
#define AFE_ALGDELAY_OFFSET 0x0000047c
|
||||
#define AFE_ACC_ID_OFFSET 0x00000800
|
||||
#define AFE_ACCSTA_OFFSET 0x00000804
|
||||
#define AFE_ACCNOSLI_OFFSET 0x00000808
|
||||
#define AFE_ACCCALCON_OFFSET 0x0000080c
|
||||
#define AFE_BWEWRICTRL_OFFSET 0x00000810
|
||||
#define AFE_SELSLI_OFFSET 0x00000814
|
||||
#define AFE_SELBYT_OFFSET 0x00000818
|
||||
#define AFE_REDVAL_OFFSET 0x00000820
|
||||
#define AFE_WRIBYT_OFFSET 0x00000824
|
||||
|
||||
/* AFE Register per module */
|
||||
#define AFE_BLOCK_ID (AFE_BASE + AFE_BLOCK_ID_OFFSET)
|
||||
#define AFE_PDBUF (AFE_BASE + AFE_PDBUF_OFFSET)
|
||||
#define AFE_SWRST (AFE_BASE + AFE_SWRST_OFFSET)
|
||||
#define AFE_TSTSEL (AFE_BASE + AFE_TSTSEL_OFFSET)
|
||||
#define AFE_TSTMSC (AFE_BASE + AFE_TSTMSC_OFFSET)
|
||||
#define AFE_ENPADIO (AFE_BASE + AFE_ENPADIO_OFFSET)
|
||||
#define AFE_BGREG (AFE_BASE + AFE_BGREG_OFFSET)
|
||||
#define AFE_ACCESSAR_ID (AFE_BASE + AFE_ACCESSAR_ID_OFFSET)
|
||||
#define AFE_PDADC (AFE_BASE + AFE_PDADC_OFFSET)
|
||||
#define AFE_PDSARH (AFE_BASE + AFE_PDSARH_OFFSET)
|
||||
#define AFE_PDSARL (AFE_BASE + AFE_PDSARL_OFFSET)
|
||||
#define AFE_PDADCRFH (AFE_BASE + AFE_PDADCRFH_OFFSET)
|
||||
#define AFE_PDADCRFL (AFE_BASE + AFE_PDADCRFL_OFFSET)
|
||||
#define AFE_ACCTST (AFE_BASE + AFE_ACCTST_OFFSET)
|
||||
#define AFE_ADCGN (AFE_BASE + AFE_ADCGN_OFFSET)
|
||||
#define AFE_ICTRL (AFE_BASE + AFE_ICTRL_OFFSET)
|
||||
#define AFE_ICTLSTG (AFE_BASE + AFE_ICTLSTG_OFFSET)
|
||||
#define AFE_RCTRLSTG (AFE_BASE + AFE_RCTRLSTG_OFFSET)
|
||||
#define AFE_TCTRLSTG (AFE_BASE + AFE_TCTRLSTG_OFFSET)
|
||||
#define AFE_REFMOD (AFE_BASE + AFE_REFMOD_OFFSET)
|
||||
#define AFE_REFTRIML (AFE_BASE + AFE_REFTRIML_OFFSET)
|
||||
#define AFE_REFTRIMH (AFE_BASE + AFE_REFTRIMH_OFFSET)
|
||||
#define AFE_ADCR (AFE_BASE + AFE_ADCR_OFFSET)
|
||||
#define AFE_DUMMY0 (AFE_BASE + AFE_DUMMY0_OFFSET)
|
||||
#define AFE_DUMMY1 (AFE_BASE + AFE_DUMMY1_OFFSET)
|
||||
#define AFE_DUMMY2 (AFE_BASE + AFE_DUMMY2_OFFSET)
|
||||
#define AFE_DACAMP (AFE_BASE + AFE_DACAMP_OFFSET)
|
||||
#define AFE_CLMPTST (AFE_BASE + AFE_CLMPTST_OFFSET)
|
||||
#define AFE_CLMPDAT (AFE_BASE + AFE_CLMPDAT_OFFSET)
|
||||
#define AFE_CLMPAMP (AFE_BASE + AFE_CLMPAMP_OFFSET)
|
||||
#define AFE_CLAMP (AFE_BASE + AFE_CLAMP_OFFSET)
|
||||
#define AFE_INPBUF (AFE_BASE + AFE_INPBUF_OFFSET)
|
||||
#define AFE_INPFLT (AFE_BASE + AFE_INPFLT_OFFSET)
|
||||
#define AFE_ADCDGN (AFE_BASE + AFE_ADCDGN_OFFSET)
|
||||
#define AFE_OFFDRV (AFE_BASE + AFE_OFFDRV_OFFSET)
|
||||
#define AFE_INPCONFIG (AFE_BASE + AFE_INPCONFIG_OFFSET)
|
||||
#define AFE_PROGDELAY (AFE_BASE + AFE_PROGDELAY_OFFSET)
|
||||
#define AFE_ADCOMT (AFE_BASE + AFE_ADCOMT_OFFSET)
|
||||
#define AFE_ALGDELAY (AFE_BASE + AFE_ALGDELAY_OFFSET)
|
||||
#define AFE_ACC_ID (AFE_BASE + AFE_ACC_ID_OFFSET)
|
||||
#define AFE_ACCSTA (AFE_BASE + AFE_ACCSTA_OFFSET)
|
||||
#define AFE_ACCNOSLI (AFE_BASE + AFE_ACCNOSLI_OFFSET)
|
||||
#define AFE_ACCCALCON (AFE_BASE + AFE_ACCCALCON_OFFSET)
|
||||
#define AFE_BWEWRICTRL (AFE_BASE + AFE_BWEWRICTRL_OFFSET)
|
||||
#define AFE_SELSLI (AFE_BASE + AFE_SELSLI_OFFSET)
|
||||
#define AFE_SELBYT (AFE_BASE + AFE_SELBYT_OFFSET)
|
||||
#define AFE_REDVAL (AFE_BASE + AFE_REDVAL_OFFSET)
|
||||
#define AFE_WRIBYT (AFE_BASE + AFE_WRIBYT_OFFSET)
|
||||
|
||||
/* VDEC - Register offsets */
|
||||
#define VDEC_CFC1_OFFSET 0x00000000
|
||||
#define VDEC_CFC2_OFFSET 0x00000004
|
||||
#define VDEC_BRSTGT_OFFSET 0x00000024
|
||||
#define VDEC_HZPOS_OFFSET 0x00000040
|
||||
#define VDEC_VRTPOS_OFFSET 0x00000044
|
||||
#define VDEC_HVSHIFT_OFFSET 0x00000054
|
||||
#define VDEC_HSIGS_OFFSET 0x00000058
|
||||
#define VDEC_HSIGE_OFFSET 0x0000005C
|
||||
#define VDEC_VSCON1_OFFSET 0x00000060
|
||||
#define VDEC_VSCON2_OFFSET 0x00000064
|
||||
#define VDEC_YCDEL_OFFSET 0x0000006C
|
||||
#define VDEC_AFTCLP_OFFSET 0x00000070
|
||||
#define VDEC_DCOFF_OFFSET 0x00000078
|
||||
#define VDEC_CSID_OFFSET 0x00000084
|
||||
#define VDEC_CBGN_OFFSET 0x00000088
|
||||
#define VDEC_CRGN_OFFSET 0x0000008C
|
||||
#define VDEC_CNTR_OFFSET 0x00000090
|
||||
#define VDEC_BRT_OFFSET 0x00000094
|
||||
#define VDEC_HUE_OFFSET 0x00000098
|
||||
#define VDEC_CHBTH_OFFSET 0x0000009C
|
||||
#define VDEC_SHPIMP_OFFSET 0x000000A4
|
||||
#define VDEC_CHPLLIM_OFFSET 0x000000A8
|
||||
#define VDEC_VIDMOD_OFFSET 0x000000AC
|
||||
#define VDEC_VIDSTS_OFFSET 0x000000B0
|
||||
#define VDEC_NOISE_OFFSET 0x000000B4
|
||||
#define VDEC_STDDBG_OFFSET 0x000000B8
|
||||
#define VDEC_MANOVR_OFFSET 0x000000BC
|
||||
#define VDEC_VSSGTH_OFFSET 0x000000C8
|
||||
#define VDEC_DBGFBH_OFFSET 0x000000D0
|
||||
#define VDEC_DBGFBL_OFFSET 0x000000D4
|
||||
#define VDEC_HACTS_OFFSET 0x000000D8
|
||||
#define VDEC_HACTE_OFFSET 0x000000DC
|
||||
#define VDEC_VACTS_OFFSET 0x000000E0
|
||||
#define VDEC_VACTE_OFFSET 0x000000E4
|
||||
#define VDEC_HSTIP_OFFSET 0x000000EC
|
||||
#define VDEC_BLSCRY_OFFSET 0x000000F4
|
||||
#define VDEC_BLSCRCR_OFFSET 0x000000F8
|
||||
#define VDEC_BLSCRCB_OFFSET 0x000000FC
|
||||
#define VDEC_LMAGC1_OFFSET 0x00000100
|
||||
#define VDEC_LMAGC2_OFFSET 0x00000104
|
||||
#define VDEC_CHAGC1_OFFSET 0x00000108
|
||||
#define VDEC_CHAGC2_OFFSET 0x0000010C
|
||||
#define VDEC_MINTH_OFFSET 0x00000114
|
||||
#define VDEC_VFRQOH_OFFSET 0x0000011C
|
||||
#define VDEC_VFRQOL_OFFSET 0x00000120
|
||||
#define VDEC_THSH1_OFFSET 0x00000124
|
||||
#define VDEC_THSH2_OFFSET 0x00000128
|
||||
#define VDEC_NCHTH_OFFSET 0x0000012C
|
||||
#define VDEC_TH1F_OFFSET 0x00000130
|
||||
|
||||
/* VDEC Register per module */
|
||||
#define VDEC_CFC1 (VDEC_BASE + VDEC_CFC1_OFFSET)
|
||||
#define VDEC_CFC2 (VDEC_BASE + VDEC_CFC2_OFFSET)
|
||||
#define VDEC_BRSTGT (VDEC_BASE + VDEC_BRSTGT_OFFSET)
|
||||
#define VDEC_HZPOS (VDEC_BASE + VDEC_HZPOS_OFFSET)
|
||||
#define VDEC_VRTPOS (VDEC_BASE + VDEC_VRTPOS_OFFSET)
|
||||
#define VDEC_HVSHIFT (VDEC_BASE + VDEC_HVSHIFT_OFFSET)
|
||||
#define VDEC_HSIGS (VDEC_BASE + VDEC_HSIGS_OFFSET)
|
||||
#define VDEC_HSIGE (VDEC_BASE + VDEC_HSIGE_OFFSET)
|
||||
#define VDEC_VSCON1 (VDEC_BASE + VDEC_VSCON1_OFFSET)
|
||||
#define VDEC_VSCON2 (VDEC_BASE + VDEC_VSCON2_OFFSET)
|
||||
#define VDEC_YCDEL (VDEC_BASE + VDEC_YCDEL_OFFSET)
|
||||
#define VDEC_AFTCLP (VDEC_BASE + VDEC_AFTCLP_OFFSET)
|
||||
#define VDEC_DCOFF (VDEC_BASE + VDEC_DCOFF_OFFSET)
|
||||
#define VDEC_CSID (VDEC_BASE + VDEC_CSID_OFFSET)
|
||||
#define VDEC_CBGN (VDEC_BASE + VDEC_CBGN_OFFSET)
|
||||
#define VDEC_CRGN (VDEC_BASE + VDEC_CRGN_OFFSET)
|
||||
#define VDEC_CNTR (VDEC_BASE + VDEC_CNTR_OFFSET)
|
||||
#define VDEC_BRT (VDEC_BASE + VDEC_BRT_OFFSET)
|
||||
#define VDEC_HUE (VDEC_BASE + VDEC_HUE_OFFSET)
|
||||
#define VDEC_CHBTH (VDEC_BASE + VDEC_CHBTH_OFFSET)
|
||||
#define VDEC_SHPIMP (VDEC_BASE + VDEC_SHPIMP_OFFSET)
|
||||
#define VDEC_CHPLLIM (VDEC_BASE + VDEC_CHPLLIM_OFFSET)
|
||||
#define VDEC_VIDMOD (VDEC_BASE + VDEC_VIDMOD_OFFSET)
|
||||
#define VDEC_VIDSTS (VDEC_BASE + VDEC_VIDSTS_OFFSET)
|
||||
#define VDEC_NOISE (VDEC_BASE + VDEC_NOISE_OFFSET)
|
||||
#define VDEC_STDDBG (VDEC_BASE + VDEC_STDDBG_OFFSET)
|
||||
#define VDEC_MANOVR (VDEC_BASE + VDEC_MANOVR_OFFSET)
|
||||
#define VDEC_VSSGTH (VDEC_BASE + VDEC_VSSGTH_OFFSET)
|
||||
#define VDEC_DBGFBH (VDEC_BASE + VDEC_DBGFBH_OFFSET)
|
||||
#define VDEC_DBGFBL (VDEC_BASE + VDEC_DBGFBL_OFFSET)
|
||||
#define VDEC_HACTS (VDEC_BASE + VDEC_HACTS_OFFSET)
|
||||
#define VDEC_HACTE (VDEC_BASE + VDEC_HACTE_OFFSET)
|
||||
#define VDEC_VACTS (VDEC_BASE + VDEC_VACTS_OFFSET)
|
||||
#define VDEC_VACTE (VDEC_BASE + VDEC_VACTE_OFFSET)
|
||||
#define VDEC_HSTIP (VDEC_BASE + VDEC_HSTIP_OFFSET)
|
||||
#define VDEC_BLSCRY (VDEC_BASE + VDEC_BLSCRY_OFFSET)
|
||||
#define VDEC_BLSCRCR (VDEC_BASE + VDEC_BLSCRCR_OFFSET)
|
||||
#define VDEC_BLSCRCB (VDEC_BASE + VDEC_BLSCRCB_OFFSET)
|
||||
#define VDEC_LMAGC1 (VDEC_BASE + VDEC_LMAGC1_OFFSET)
|
||||
#define VDEC_LMAGC2 (VDEC_BASE + VDEC_LMAGC2_OFFSET)
|
||||
#define VDEC_CHAGC1 (VDEC_BASE + VDEC_CHAGC1_OFFSET)
|
||||
#define VDEC_CHAGC2 (VDEC_BASE + VDEC_CHAGC2_OFFSET)
|
||||
#define VDEC_MINTH (VDEC_BASE + VDEC_MINTH_OFFSET)
|
||||
#define VDEC_VFRQOH (VDEC_BASE + VDEC_VFRQOH_OFFSET)
|
||||
#define VDEC_VFRQOL (VDEC_BASE + VDEC_VFRQOL_OFFSET)
|
||||
#define VDEC_THSH1 (VDEC_BASE + VDEC_THSH1_OFFSET)
|
||||
#define VDEC_THSH2 (VDEC_BASE + VDEC_THSH2_OFFSET)
|
||||
#define VDEC_NCHTH (VDEC_BASE + VDEC_NCHTH_OFFSET)
|
||||
#define VDEC_TH1F (VDEC_BASE + VDEC_TH1F_OFFSET)
|
||||
|
||||
#define VDEC_VIDMOD_SIGNAL_MASK 0x0F
|
||||
#define VDEC_VIDMOD_SIGNAL_DETECT 0x0F
|
||||
|
||||
#define VDEC_VIDMOD_M625_SHIFT 4
|
||||
#define VDEC_VIDMOD_M625_MASK (1 << VDEC_VIDMOD_M625_SHIFT)
|
||||
|
||||
#define VDEC_VIDMOD_PAL_SHIFT 7
|
||||
#define VDEC_VIDMOD_PAL_MASK (1 << VDEC_VIDMOD_PAL_SHIFT)
|
||||
/*** define base address ***/
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -15,6 +15,7 @@ source "drivers/mxc/mlb/Kconfig"
|
|||
source "drivers/mxc/ipu3/Kconfig"
|
||||
source "drivers/mxc/gpu-viv/Kconfig"
|
||||
source "drivers/mxc/sim/Kconfig"
|
||||
source "drivers/mxc/mipi/Kconfig"
|
||||
source "drivers/mxc/vpu/Kconfig"
|
||||
source "drivers/mxc/hdmi-cec/Kconfig"
|
||||
|
||||
|
|
|
@ -4,3 +4,4 @@ obj-$(CONFIG_MXC_VPU) += vpu/
|
|||
obj-$(CONFIG_MXC_IPU_V3) += ipu3/
|
||||
obj-$(CONFIG_MXC_HDMI_CEC) += hdmi-cec/
|
||||
obj-$(CONFIG_MXC_GPU_VIV) += gpu-viv/
|
||||
obj-$(CONFIG_MXC_MIPI_CSI2) += mipi/
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# MIPI configuration
|
||||
#
|
||||
|
||||
menu "MXC MIPI Support"
|
||||
|
||||
config MXC_MIPI_CSI2
|
||||
tristate "MIPI CSI2 support"
|
||||
depends on SOC_IMX6Q
|
||||
default n
|
||||
---help---
|
||||
Say Y to get the MIPI CSI2 support.
|
||||
|
||||
endmenu
|
|
@ -0,0 +1,4 @@
|
|||
#
|
||||
# Makefile for the mipi interface driver
|
||||
#
|
||||
obj-$(CONFIG_MXC_MIPI_CSI2) += mxc_mipi_csi2.o
|
|
@ -0,0 +1,540 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdesc.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fsl_devices.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <linux/mipi_csi2.h>
|
||||
|
||||
#include "mxc_mipi_csi2.h"
|
||||
|
||||
static struct mipi_csi2_info *gmipi_csi2;
|
||||
|
||||
void _mipi_csi2_lock(struct mipi_csi2_info *info)
|
||||
{
|
||||
if (!in_irq() && !in_softirq())
|
||||
mutex_lock(&info->mutex_lock);
|
||||
}
|
||||
|
||||
void _mipi_csi2_unlock(struct mipi_csi2_info *info)
|
||||
{
|
||||
if (!in_irq() && !in_softirq())
|
||||
mutex_unlock(&info->mutex_lock);
|
||||
}
|
||||
|
||||
static inline void mipi_csi2_write(struct mipi_csi2_info *info,
|
||||
unsigned value, unsigned offset)
|
||||
{
|
||||
writel(value, info->mipi_csi2_base + offset);
|
||||
}
|
||||
|
||||
static inline unsigned int mipi_csi2_read(struct mipi_csi2_info *info,
|
||||
unsigned offset)
|
||||
{
|
||||
return readl(info->mipi_csi2_base + offset);
|
||||
}
|
||||
|
||||
/*!
|
||||
* This function is called to enable the mipi csi2 interface.
|
||||
*
|
||||
* @param info mipi csi2 hander
|
||||
* @return Returns setted value
|
||||
*/
|
||||
bool mipi_csi2_enable(struct mipi_csi2_info *info)
|
||||
{
|
||||
bool status;
|
||||
|
||||
_mipi_csi2_lock(info);
|
||||
|
||||
if (!info->mipi_en) {
|
||||
info->mipi_en = true;
|
||||
clk_prepare_enable(info->cfg_clk);
|
||||
clk_prepare_enable(info->dphy_clk);
|
||||
} else
|
||||
mipi_dbg("mipi csi2 already enabled!\n");
|
||||
|
||||
status = info->mipi_en;
|
||||
|
||||
_mipi_csi2_unlock(info);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_enable);
|
||||
|
||||
/*!
|
||||
* This function is called to disable the mipi csi2 interface.
|
||||
*
|
||||
* @param info mipi csi2 hander
|
||||
* @return Returns setted value
|
||||
*/
|
||||
bool mipi_csi2_disable(struct mipi_csi2_info *info)
|
||||
{
|
||||
bool status;
|
||||
|
||||
_mipi_csi2_lock(info);
|
||||
|
||||
if (info->mipi_en) {
|
||||
info->mipi_en = false;
|
||||
clk_disable_unprepare(info->dphy_clk);
|
||||
clk_disable_unprepare(info->cfg_clk);
|
||||
} else
|
||||
mipi_dbg("mipi csi2 already disabled!\n");
|
||||
|
||||
status = info->mipi_en;
|
||||
|
||||
_mipi_csi2_unlock(info);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_disable);
|
||||
|
||||
/*!
|
||||
* This function is called to get mipi csi2 disable/enable status.
|
||||
*
|
||||
* @param info mipi csi2 hander
|
||||
* @return Returns mipi csi2 status
|
||||
*/
|
||||
bool mipi_csi2_get_status(struct mipi_csi2_info *info)
|
||||
{
|
||||
bool status;
|
||||
|
||||
_mipi_csi2_lock(info);
|
||||
status = info->mipi_en;
|
||||
_mipi_csi2_unlock(info);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_get_status);
|
||||
|
||||
/*!
|
||||
* This function is called to set mipi lanes.
|
||||
*
|
||||
* @param info mipi csi2 hander
|
||||
* @return Returns setted value
|
||||
*/
|
||||
unsigned int mipi_csi2_set_lanes(struct mipi_csi2_info *info)
|
||||
{
|
||||
unsigned int lanes;
|
||||
|
||||
_mipi_csi2_lock(info);
|
||||
mipi_csi2_write(info, info->lanes - 1, MIPI_CSI2_N_LANES);
|
||||
lanes = mipi_csi2_read(info, MIPI_CSI2_N_LANES);
|
||||
_mipi_csi2_unlock(info);
|
||||
|
||||
return lanes;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_set_lanes);
|
||||
|
||||
/*!
|
||||
* This function is called to set mipi data type.
|
||||
*
|
||||
* @param info mipi csi2 hander
|
||||
* @return Returns setted value
|
||||
*/
|
||||
unsigned int mipi_csi2_set_datatype(struct mipi_csi2_info *info,
|
||||
unsigned int datatype)
|
||||
{
|
||||
unsigned int dtype;
|
||||
|
||||
_mipi_csi2_lock(info);
|
||||
info->datatype = datatype;
|
||||
dtype = info->datatype;
|
||||
_mipi_csi2_unlock(info);
|
||||
|
||||
return dtype;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_set_datatype);
|
||||
|
||||
/*!
|
||||
* This function is called to get mipi data type.
|
||||
*
|
||||
* @param info mipi csi2 hander
|
||||
* @return Returns mipi data type
|
||||
*/
|
||||
unsigned int mipi_csi2_get_datatype(struct mipi_csi2_info *info)
|
||||
{
|
||||
unsigned int dtype;
|
||||
|
||||
_mipi_csi2_lock(info);
|
||||
dtype = info->datatype;
|
||||
_mipi_csi2_unlock(info);
|
||||
|
||||
return dtype;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_get_datatype);
|
||||
|
||||
/*!
|
||||
* This function is called to get mipi csi2 dphy status.
|
||||
*
|
||||
* @param info mipi csi2 hander
|
||||
* @return Returns dphy status
|
||||
*/
|
||||
unsigned int mipi_csi2_dphy_status(struct mipi_csi2_info *info)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
_mipi_csi2_lock(info);
|
||||
status = mipi_csi2_read(info, MIPI_CSI2_PHY_STATE);
|
||||
_mipi_csi2_unlock(info);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_dphy_status);
|
||||
|
||||
/*!
|
||||
* This function is called to get mipi csi2 error1 status.
|
||||
*
|
||||
* @param info mipi csi2 hander
|
||||
* @return Returns error1 value
|
||||
*/
|
||||
unsigned int mipi_csi2_get_error1(struct mipi_csi2_info *info)
|
||||
{
|
||||
unsigned int err1;
|
||||
|
||||
_mipi_csi2_lock(info);
|
||||
err1 = mipi_csi2_read(info, MIPI_CSI2_ERR1);
|
||||
_mipi_csi2_unlock(info);
|
||||
|
||||
return err1;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_get_error1);
|
||||
|
||||
/*!
|
||||
* This function is called to get mipi csi2 error1 status.
|
||||
*
|
||||
* @param info mipi csi2 hander
|
||||
* @return Returns error1 value
|
||||
*/
|
||||
unsigned int mipi_csi2_get_error2(struct mipi_csi2_info *info)
|
||||
{
|
||||
unsigned int err2;
|
||||
|
||||
_mipi_csi2_lock(info);
|
||||
err2 = mipi_csi2_read(info, MIPI_CSI2_ERR2);
|
||||
_mipi_csi2_unlock(info);
|
||||
|
||||
return err2;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_get_error2);
|
||||
|
||||
/*!
|
||||
* This function is called to enable mipi to ipu pixel clock.
|
||||
*
|
||||
* @param info mipi csi2 hander
|
||||
* @return Returns 0 on success or negative error code on fail
|
||||
*/
|
||||
int mipi_csi2_pixelclk_enable(struct mipi_csi2_info *info)
|
||||
{
|
||||
return clk_prepare_enable(info->pixel_clk);
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_pixelclk_enable);
|
||||
|
||||
/*!
|
||||
* This function is called to disable mipi to ipu pixel clock.
|
||||
*
|
||||
* @param info mipi csi2 hander
|
||||
* @return Returns 0 on success or negative error code on fail
|
||||
*/
|
||||
void mipi_csi2_pixelclk_disable(struct mipi_csi2_info *info)
|
||||
{
|
||||
clk_disable_unprepare(info->pixel_clk);
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_pixelclk_disable);
|
||||
|
||||
/*!
|
||||
* This function is called to power on mipi csi2.
|
||||
*
|
||||
* @param info mipi csi2 hander
|
||||
* @return Returns 0 on success or negative error code on fail
|
||||
*/
|
||||
int mipi_csi2_reset(struct mipi_csi2_info *info)
|
||||
{
|
||||
_mipi_csi2_lock(info);
|
||||
|
||||
mipi_csi2_write(info, 0x0, MIPI_CSI2_PHY_SHUTDOWNZ);
|
||||
mipi_csi2_write(info, 0x0, MIPI_CSI2_DPHY_RSTZ);
|
||||
mipi_csi2_write(info, 0x0, MIPI_CSI2_CSI2_RESETN);
|
||||
|
||||
mipi_csi2_write(info, 0x00000001, MIPI_CSI2_PHY_TST_CTRL0);
|
||||
mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL1);
|
||||
mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL0);
|
||||
mipi_csi2_write(info, 0x00000002, MIPI_CSI2_PHY_TST_CTRL0);
|
||||
mipi_csi2_write(info, 0x00010044, MIPI_CSI2_PHY_TST_CTRL1);
|
||||
mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL0);
|
||||
mipi_csi2_write(info, 0x00000014, MIPI_CSI2_PHY_TST_CTRL1);
|
||||
mipi_csi2_write(info, 0x00000002, MIPI_CSI2_PHY_TST_CTRL0);
|
||||
mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL0);
|
||||
|
||||
mipi_csi2_write(info, 0xffffffff, MIPI_CSI2_PHY_SHUTDOWNZ);
|
||||
mipi_csi2_write(info, 0xffffffff, MIPI_CSI2_DPHY_RSTZ);
|
||||
mipi_csi2_write(info, 0xffffffff, MIPI_CSI2_CSI2_RESETN);
|
||||
|
||||
_mipi_csi2_unlock(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_reset);
|
||||
|
||||
/*!
|
||||
* This function is called to get mipi csi2 info.
|
||||
*
|
||||
* @return Returns mipi csi2 info struct pointor
|
||||
*/
|
||||
struct mipi_csi2_info *mipi_csi2_get_info(void)
|
||||
{
|
||||
return gmipi_csi2;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_get_info);
|
||||
|
||||
/*!
|
||||
* This function is called to get mipi csi2 bind ipu num.
|
||||
*
|
||||
* @return Returns mipi csi2 bind ipu num
|
||||
*/
|
||||
int mipi_csi2_get_bind_ipu(struct mipi_csi2_info *info)
|
||||
{
|
||||
int ipu_id;
|
||||
|
||||
_mipi_csi2_lock(info);
|
||||
ipu_id = info->ipu_id;
|
||||
_mipi_csi2_unlock(info);
|
||||
|
||||
return ipu_id;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_get_bind_ipu);
|
||||
|
||||
/*!
|
||||
* This function is called to get mipi csi2 bind csi num.
|
||||
*
|
||||
* @return Returns mipi csi2 bind csi num
|
||||
*/
|
||||
unsigned int mipi_csi2_get_bind_csi(struct mipi_csi2_info *info)
|
||||
{
|
||||
unsigned int csi_id;
|
||||
|
||||
_mipi_csi2_lock(info);
|
||||
csi_id = info->csi_id;
|
||||
_mipi_csi2_unlock(info);
|
||||
|
||||
return csi_id;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_get_bind_csi);
|
||||
|
||||
/*!
|
||||
* This function is called to get mipi csi2 virtual channel.
|
||||
*
|
||||
* @return Returns mipi csi2 virtual channel num
|
||||
*/
|
||||
unsigned int mipi_csi2_get_virtual_channel(struct mipi_csi2_info *info)
|
||||
{
|
||||
unsigned int v_channel;
|
||||
|
||||
_mipi_csi2_lock(info);
|
||||
v_channel = info->v_channel;
|
||||
_mipi_csi2_unlock(info);
|
||||
|
||||
return v_channel;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_csi2_get_virtual_channel);
|
||||
|
||||
/**
|
||||
* This function is called by the driver framework to initialize the MIPI CSI2
|
||||
* device.
|
||||
*
|
||||
* @param pdev The device structure for the MIPI CSI2 passed in by the
|
||||
* driver framework.
|
||||
*
|
||||
* @return Returns 0 on success or negative error code on error
|
||||
*/
|
||||
static int mipi_csi2_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct resource *res;
|
||||
u32 mipi_csi2_dphy_ver;
|
||||
int ret;
|
||||
|
||||
gmipi_csi2 = kmalloc(sizeof(struct mipi_csi2_info), GFP_KERNEL);
|
||||
if (!gmipi_csi2) {
|
||||
ret = -ENOMEM;
|
||||
goto alloc_failed;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "ipu_id", &(gmipi_csi2->ipu_id));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "ipu_id missing or invalid\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "csi_id", &(gmipi_csi2->csi_id));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "csi_id missing or invalid\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "v_channel", &(gmipi_csi2->v_channel));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "v_channel missing or invalid\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "lanes", &(gmipi_csi2->lanes));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "lanes missing or invalid\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((gmipi_csi2->ipu_id < 0) || (gmipi_csi2->ipu_id > 1) ||
|
||||
(gmipi_csi2->csi_id > 1) || (gmipi_csi2->v_channel > 3) ||
|
||||
(gmipi_csi2->lanes > 4)) {
|
||||
dev_err(&pdev->dev, "invalid param for mipi csi2!\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* initialize mutex */
|
||||
mutex_init(&gmipi_csi2->mutex_lock);
|
||||
|
||||
/* get mipi csi2 informaiton */
|
||||
gmipi_csi2->pdev = pdev;
|
||||
gmipi_csi2->mipi_en = false;
|
||||
|
||||
gmipi_csi2->cfg_clk = devm_clk_get(dev, "cfg_clk");
|
||||
if (IS_ERR(gmipi_csi2->cfg_clk)) {
|
||||
dev_err(&pdev->dev, "failed to get cfg_clk\n");
|
||||
ret = PTR_ERR(gmipi_csi2->cfg_clk);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* get mipi dphy clk */
|
||||
gmipi_csi2->dphy_clk = devm_clk_get(dev, "dphy_clk");
|
||||
if (IS_ERR(gmipi_csi2->dphy_clk)) {
|
||||
dev_err(&pdev->dev, "failed to get dphy pll_ref_clk\n");
|
||||
ret = PTR_ERR(gmipi_csi2->dphy_clk);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* get mipi to ipu pixel clk */
|
||||
gmipi_csi2->pixel_clk = devm_clk_get(dev, "pixel_clk");
|
||||
if (IS_ERR(gmipi_csi2->pixel_clk)) {
|
||||
dev_err(&pdev->dev, "failed to get mipi pixel clk\n");
|
||||
ret = PTR_ERR(gmipi_csi2->pixel_clk);
|
||||
goto err;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* mipi register mapping */
|
||||
gmipi_csi2->mipi_csi2_base = ioremap(res->start, PAGE_SIZE);
|
||||
if (!gmipi_csi2->mipi_csi2_base) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* mipi dphy clk enable for register access */
|
||||
clk_prepare_enable(gmipi_csi2->dphy_clk);
|
||||
/* get mipi csi2 dphy version */
|
||||
mipi_csi2_dphy_ver = mipi_csi2_read(gmipi_csi2, MIPI_CSI2_VERSION);
|
||||
|
||||
clk_disable_unprepare(gmipi_csi2->dphy_clk);
|
||||
|
||||
platform_set_drvdata(pdev, gmipi_csi2);
|
||||
|
||||
dev_info(&pdev->dev, "i.MX MIPI CSI2 driver probed\n");
|
||||
dev_info(&pdev->dev, "i.MX MIPI CSI2 dphy version is 0x%x\n",
|
||||
mipi_csi2_dphy_ver);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
kfree(gmipi_csi2);
|
||||
alloc_failed:
|
||||
dev_err(&pdev->dev, "i.MX MIPI CSI2 driver probed - error\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mipi_csi2_remove(struct platform_device *pdev)
|
||||
{
|
||||
/* unmapping mipi register */
|
||||
iounmap(gmipi_csi2->mipi_csi2_base);
|
||||
|
||||
kfree(gmipi_csi2);
|
||||
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id imx_mipi_csi2_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx6q-mipi-csi2", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver mipi_csi2_driver = {
|
||||
.driver = {
|
||||
.name = "mxc_mipi_csi2",
|
||||
.of_match_table = imx_mipi_csi2_dt_ids,
|
||||
},
|
||||
.probe = mipi_csi2_probe,
|
||||
.remove = mipi_csi2_remove,
|
||||
};
|
||||
|
||||
static int __init mipi_csi2_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = platform_driver_register(&mipi_csi2_driver);
|
||||
if (err) {
|
||||
pr_err("mipi_csi2_driver register failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pr_info("MIPI CSI2 driver module loaded\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit mipi_csi2_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&mipi_csi2_driver);
|
||||
}
|
||||
|
||||
subsys_initcall(mipi_csi2_init);
|
||||
module_exit(mipi_csi2_cleanup);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("i.MX MIPI CSI2 driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __MXC_MIPI_CSI2_H__
|
||||
#define __MXC_MIPI_CSI2_H__
|
||||
|
||||
#ifdef DEBUG
|
||||
#define mipi_dbg(fmt, ...) \
|
||||
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
|
||||
#else
|
||||
#define mipi_dbg(fmt, ...)
|
||||
#endif
|
||||
|
||||
/* driver private data */
|
||||
struct mipi_csi2_info {
|
||||
bool mipi_en;
|
||||
int ipu_id;
|
||||
unsigned int csi_id;
|
||||
unsigned int v_channel;
|
||||
unsigned int lanes;
|
||||
unsigned int datatype;
|
||||
struct clk *cfg_clk;
|
||||
struct clk *dphy_clk;
|
||||
struct clk *pixel_clk;
|
||||
void __iomem *mipi_csi2_base;
|
||||
struct platform_device *pdev;
|
||||
|
||||
struct mutex mutex_lock;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDE_MIPI_CSI2_H
|
||||
#define __INCLUDE_MIPI_CSI2_H
|
||||
|
||||
/* MIPI CSI2 registers */
|
||||
#define MIPI_CSI2_REG(offset) (offset)
|
||||
|
||||
#define MIPI_CSI2_VERSION MIPI_CSI2_REG(0x000)
|
||||
#define MIPI_CSI2_N_LANES MIPI_CSI2_REG(0x004)
|
||||
#define MIPI_CSI2_PHY_SHUTDOWNZ MIPI_CSI2_REG(0x008)
|
||||
#define MIPI_CSI2_DPHY_RSTZ MIPI_CSI2_REG(0x00c)
|
||||
#define MIPI_CSI2_CSI2_RESETN MIPI_CSI2_REG(0x010)
|
||||
#define MIPI_CSI2_PHY_STATE MIPI_CSI2_REG(0x014)
|
||||
#define MIPI_CSI2_DATA_IDS_1 MIPI_CSI2_REG(0x018)
|
||||
#define MIPI_CSI2_DATA_IDS_2 MIPI_CSI2_REG(0x01c)
|
||||
#define MIPI_CSI2_ERR1 MIPI_CSI2_REG(0x020)
|
||||
#define MIPI_CSI2_ERR2 MIPI_CSI2_REG(0x024)
|
||||
#define MIPI_CSI2_MASK1 MIPI_CSI2_REG(0x028)
|
||||
#define MIPI_CSI2_MASK2 MIPI_CSI2_REG(0x02c)
|
||||
#define MIPI_CSI2_PHY_TST_CTRL0 MIPI_CSI2_REG(0x030)
|
||||
#define MIPI_CSI2_PHY_TST_CTRL1 MIPI_CSI2_REG(0x034)
|
||||
#define MIPI_CSI2_SFT_RESET MIPI_CSI2_REG(0xf00)
|
||||
|
||||
/* mipi data type */
|
||||
#define MIPI_DT_YUV420 0x18 /* YYY.../UYVY.... */
|
||||
#define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY... */
|
||||
#define MIPI_DT_YUV422 0x1e /* UYVY... */
|
||||
#define MIPI_DT_RGB444 0x20
|
||||
#define MIPI_DT_RGB555 0x21
|
||||
#define MIPI_DT_RGB565 0x22
|
||||
#define MIPI_DT_RGB666 0x23
|
||||
#define MIPI_DT_RGB888 0x24
|
||||
#define MIPI_DT_RAW6 0x28
|
||||
#define MIPI_DT_RAW7 0x29
|
||||
#define MIPI_DT_RAW8 0x2a
|
||||
#define MIPI_DT_RAW10 0x2b
|
||||
#define MIPI_DT_RAW12 0x2c
|
||||
#define MIPI_DT_RAW14 0x2d
|
||||
|
||||
|
||||
struct mipi_csi2_info;
|
||||
/* mipi csi2 API */
|
||||
struct mipi_csi2_info *mipi_csi2_get_info(void);
|
||||
|
||||
bool mipi_csi2_enable(struct mipi_csi2_info *info);
|
||||
|
||||
bool mipi_csi2_disable(struct mipi_csi2_info *info);
|
||||
|
||||
bool mipi_csi2_get_status(struct mipi_csi2_info *info);
|
||||
|
||||
int mipi_csi2_get_bind_ipu(struct mipi_csi2_info *info);
|
||||
|
||||
unsigned int mipi_csi2_get_bind_csi(struct mipi_csi2_info *info);
|
||||
|
||||
unsigned int mipi_csi2_get_virtual_channel(struct mipi_csi2_info *info);
|
||||
|
||||
unsigned int mipi_csi2_set_lanes(struct mipi_csi2_info *info);
|
||||
|
||||
unsigned int mipi_csi2_set_datatype(struct mipi_csi2_info *info,
|
||||
unsigned int datatype);
|
||||
|
||||
unsigned int mipi_csi2_get_datatype(struct mipi_csi2_info *info);
|
||||
|
||||
unsigned int mipi_csi2_dphy_status(struct mipi_csi2_info *info);
|
||||
|
||||
unsigned int mipi_csi2_get_error1(struct mipi_csi2_info *info);
|
||||
|
||||
unsigned int mipi_csi2_get_error2(struct mipi_csi2_info *info);
|
||||
|
||||
int mipi_csi2_pixelclk_enable(struct mipi_csi2_info *info);
|
||||
|
||||
void mipi_csi2_pixelclk_disable(struct mipi_csi2_info *info);
|
||||
|
||||
int mipi_csi2_reset(struct mipi_csi2_info *info);
|
||||
|
||||
#endif
|
|
@ -53,6 +53,11 @@ struct v4l2_mxc_offset {
|
|||
uint32_t v_offset;
|
||||
};
|
||||
|
||||
struct v4l2_mxc_dest_crop {
|
||||
__u32 type; /* enum v4l2_buf_type */
|
||||
struct v4l2_mxc_offset offset;
|
||||
};
|
||||
|
||||
/*
|
||||
* Private IOCTLs
|
||||
*
|
||||
|
@ -63,5 +68,6 @@ struct v4l2_mxc_offset {
|
|||
_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct v4l2_crop)
|
||||
#define VIDIOC_G_INPUT_CROP \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct v4l2_crop)
|
||||
|
||||
#define VIDIOC_S_DEST_CROP \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct v4l2_mxc_dest_crop)
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue