// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*
* Freescale VIU video driver
*
* Authors: Hongjun Chen <hong-jun.chen@freescale.com>
* Porting to 2.6.35 by DENX Software Engineering,
* Anatolij Gustschin <agust@denx.de>
*/
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
#include <media/videobuf-dma-contig.h>
#define DRV_NAME "fsl_viu"
#define VIU_VERSION "0.5.1"
#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
#define VIU_VID_MEM_LIMIT 4 /* Video memory limit, in Mb */
/* I2C address of video decoder chip is 0x4A */
#define VIU_VIDEO_DECODER_ADDR 0x25
static int info_level;
#define dprintk(level, fmt, arg...) \
do { \
if (level <= info_level) \
printk(KERN_DEBUG "viu: " fmt , ## arg); \
} while (0)
/*
* Basic structures
*/
struct viu_fmt {
u32 fourcc; /* v4l2 format id */
u32 pixelformat;
int depth;
};
static struct viu_fmt formats[] = {
{
.fourcc = V4L2_PIX_FMT_RGB565,
.pixelformat = V4L2_PIX_FMT_RGB565,
.depth = 16,
}, {
.fourcc = V4L2_PIX_FMT_RGB32,
.pixelformat = V4L2_PIX_FMT_RGB32,
.depth = 32,
}
};
struct viu_dev;
struct viu_buf;
/* buffer for one video frame */
struct viu_buf {
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb;
struct viu_fmt *fmt;
};
struct viu_dmaqueue {
struct viu_dev *dev;
struct list_head active;
struct list_head queued;
struct timer_list timeout;
};
struct viu_status {
u32 field_irq;
u32 vsync_irq;
u32 hsync_irq;
u32 vstart_irq;
u32 dma_end_irq;
u32 error_irq;
};
struct viu_reg {
u32 status_cfg;
u32 luminance;
u32 chroma_r;
u32 chroma_g;
u32 chroma_b;
u32 field_base_addr;
u32 dma_inc;
u32 picture_count;
u32 req_alarm;
u32 alpha;
} __attribute__ ((packed));
struct viu_dev {
struct v4l2_device v4l2_dev;
struct v4l2_ctrl_handler hdl;
struct mutex lock;
spinlock_t slock;
int users;
struct device *dev;
/* various device info */
struct video_device *vdev;
struct viu_dmaqueue vidq;
enum v4l2_field capfield;
int field;
int first;
int dma_done;
/* Hardware register area */
struct viu_reg __iomem *vr;
/* Interrupt vector */
int irq;
struct viu_status irqs;
/* video overlay */
struct v4l2_framebuffer ovbuf;
struct viu_fmt *ovfmt;
unsigned int ovenable;
enum v4l2_field ovfield;
/* crop */
struct v4l2_rect crop_current;
/* clock pointer */
struct clk *clk;
/* decoder */
struct v4l2_subdev *decoder;
v4l2_std_id std;
};
struct viu_fh {
/* must remain the first field of this struct */
struct v4l2_fh fh;
struct viu_dev *dev;
/* video capture */
struct videobuf_queue vb_vidq;
spinlock_t vbq_lock; /* spinlock for the videobuf queue */
/* video overlay */
struct v4l2_window win;
struct v4l2_clip clips[1];
/* video capture */
struct viu_fmt *fmt;
int width, height, sizeimage;
enum v4l2_buf_type type;
};
static struct viu_reg reg_val;
/*
* Macro definitions of VIU registers
*/
/* STATUS_CONFIG register */
enum status_config {
SOFT_RST = 1 << 0,
ERR_MASK = 0x0f << 4, /* Error code mask */
ERR_NO = 0x00, /* No error */
ERR_DMA_V = 0x01 << 4, /* DMA in vertical active */
ERR_DMA_VB = 0x02 << 4, /* DMA in vertical blanking */
ERR_LINE_TOO_LONG = 0x04 << 4, /* Line too long */
ERR_TOO_MANG_LINES = 0x05 << 4, /* Too many lines in field */
ERR_LINE_TOO_SHORT = 0x06 << 4, /* Line too short */
ERR_NOT_ENOUGH_LINE = 0x07 << 4, /* Not enough lines in field */
ERR_FIFO_OVERFLOW = 0x08 << 4, /* FIFO overflow */
ERR_FIFO_UNDERFLOW = 0x09 << 4, /* FIFO underflow */
ERR_1bit_ECC = 0x0a << 4, /* One bit ECC error */
ERR_MORE_ECC = 0x0b << 4, /* Two/more bits ECC error */
INT_FIELD_EN = 0x01 << 8, /* Enable field interrupt */
INT_VSYNC_EN = 0x01 << 9, /* Enable vsync interrupt */
INT_HSYNC_EN = 0x01 << 10, /* Enable hsync interrupt */
INT_VSTART_EN = 0x01 << 11, /* Enable vstart interrupt */
INT_DMA_END_EN = 0x01 << 12, /* Enable DMA end interrupt */
INT_ERROR_EN = 0x01 << 13, /* Enable error interrupt */
INT_ECC_EN = 0x01 << 14, /* Enable ECC interrupt */
INT_FIELD_STATUS = 0x01 << 16, /* field interru
|