// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2008-2009 Texas Instruments Inc
*
* Image Sensor Interface (ISIF) driver
*
* This driver is for configuring the ISIF IP available on DM365 or any other
* TI SoCs. This is used for capturing yuv or bayer video or image data
* from a decoder or sensor. This IP is similar to the CCDC IP on DM355
* and DM6446, but with enhanced or additional ip blocks. The driver
* configures the ISIF upon commands from the vpfe bridge driver through
* ccdc_hw_device interface.
*
* TODO: 1) Raw bayer parameter settings and bayer capture
* 2) Add support for control ioctl
*/
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/videodev2.h>
#include <linux/err.h>
#include <linux/module.h>
#include <media/davinci/isif.h>
#include <media/davinci/vpss.h>
#include "isif_regs.h"
#include "ccdc_hw_device.h"
/* Defaults for module configuration parameters */
static struct isif_config_params_raw isif_config_defaults = {
.linearize = {
.en = 0,
.corr_shft = ISIF_NO_SHIFT,
.scale_fact = {1, 0},
},
.df_csc = {
.df_or_csc = 0,
.csc = {
.en = 0,
},
},
.dfc = {
.en = 0,
},
.bclamp = {
.en = 0,
},
.gain_offset = {
.gain = {
.r_ye = {1, 0},
.gr_cy = {1, 0},
.gb_g = {1, 0},
.b_mg = {1, 0},
},
},
.culling = {
.hcpat_odd = 0xff,
.hcpat_even = 0xff,
.vcpat = 0xff,
},
.compress = {
.alg = ISIF_ALAW,
},
};
/* ISIF operation configuration */
static struct isif_oper_config {
struct device *dev;
enum vpfe_hw_if_type if_type;
struct isif_ycbcr_config ycbcr;
struct isif_params_raw bayer;
enum isif_data_pack data_pack;
/* ISIF base address */
void __iomem *base_addr;
/* ISIF Linear Table 0 */
void __iomem *linear_tbl0_addr;
/* ISIF Linear Table 1 */
void __iomem *linear_tbl1_addr;
} isif_cfg = {
.ycbcr = {
.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
.frm_fmt = CCDC_FRMFMT_INTERLACED,
.win = ISIF_WIN_NTSC,
.fid_pol = VPFE_PINPOL_POSITIVE,
.vd_pol = VPFE_PINPOL_POSITIVE,
.hd_pol = VPFE_PINPOL_POSITIVE,
.pix_order = CCDC_PIXORDER_CBYCRY,
.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED,
},
.bayer = {
.pix_fmt = CCDC_PIXFMT_RAW,
.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
.win = ISIF_WIN_VGA,
.fid_pol = VPFE_PINPOL_POSITIVE,
.vd_pol = VPFE_PINPOL_POSITIVE,
.hd_pol = VPFE_PINPOL_POSITIVE,
.gain = {
.r_ye = {1, 0},
.gr_cy = {1, 0},
.gb_g = {1, 0},
.b_mg = {1, 0},
},
.cfa_pat = ISIF_CFA_PAT_MOSAIC,
.data_msb = ISIF_BIT_MSB_11,
.config_params = {
.data_shift = ISIF_NO_SHIFT,
.col_pat_field0 = {
.olop = ISIF_GREEN_BLUE,
.olep = ISIF_BLUE,
.elop = ISIF_RED,
.elep = ISIF_GREEN_RED,
},
.col_pat_field1 = {
.olop = ISIF_GREEN_BLUE,
.olep = ISIF_BLUE,
.elop = ISIF_RED,
.elep = ISIF_GREEN_RED,
},
.test_pat_gen = 0,
},
},
.data_pack = ISIF_DATA_PACK8,
};
/* Raw Bayer formats */
static const u32 isif_raw_bayer_pix_formats[] = {
V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
/* Raw YUV formats */
static const u32 isif_raw_yuv_pix_formats[] = {
V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
/* register access routines */
static inline u32 regr(u32 offset)
{
return __raw_readl(isif_cfg.base_addr + offset);
}
static inline void regw(u32 val, u32 offset)
{
__raw_writel(val, isif_cfg.base_addr + offset);
}
/* reg_modify() - read, modify and write register */
static inline u32 reg_modify(u32 mask, u32 val, u32 offset)
{
u32 new_val = (regr(offset) & ~mask) | (val & mask);
regw(new_val, offset);
return new_val;
}
static inline void regw_lin_tbl(u32 val, u32 offset, int i)
{
if (!i)
__raw_writel(val, isif_cfg.linear_tbl0_addr + offset);
else
__raw_writel