blob: 311f05f049276d86dccbf5adb66c1b4f0b03f46c [file] [log] [blame]
/*
* Copyright (C) 2014 Freescale Semiconductor, Inc. All Rights Reserved.
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*!
* @file fsl_csi.c, this file is derived from mx27_csi.c
*
* @brief mx25 CMOS Sensor interface functions
*
* @ingroup CSI
*/
#include <common.h>
#include <malloc.h>
#include <asm/arch/imx-regs.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <linux/string.h>
#include <linux/list.h>
#include "mxc_csi.h"
enum {
STD_NTSC = 0,
STD_PAL,
};
void __iomem *csi_regbase;
static void csihw_reset_frame_count(void)
{
__raw_writel(__raw_readl(CSI_CSICR3) | BIT_FRMCNT_RST, CSI_CSICR3);
}
static void csihw_reset(void)
{
csihw_reset_frame_count();
__raw_writel(CSICR1_RESET_VAL, CSI_CSICR1);
__raw_writel(CSICR2_RESET_VAL, CSI_CSICR2);
__raw_writel(CSICR3_RESET_VAL, CSI_CSICR3);
}
/*!
* csi_init_interface
* Init csi interface
*/
void csi_init_interface(void)
{
unsigned int val = 0;
unsigned int imag_para;
val |= BIT_SOF_POL;
val |= BIT_REDGE;
val |= BIT_GCLK_MODE;
val |= BIT_HSYNC_POL;
val |= BIT_FCC;
val |= 1 << SHIFT_MCLKDIV;
val |= BIT_MCLKEN;
__raw_writel(val, CSI_CSICR1);
imag_para = (640 << 16) | 960;
__raw_writel(imag_para, CSI_CSIIMAG_PARA);
val = 0x1010;
val |= BIT_DMA_REFLASH_RFF;
__raw_writel(val, CSI_CSICR3);
}
void csi_format_swap16(bool enable)
{
unsigned int val;
val = __raw_readl(CSI_CSICR1);
if (enable) {
val |= BIT_PACK_DIR;
val |= BIT_SWAP16_EN;
} else {
val &= ~BIT_PACK_DIR;
val &= ~BIT_SWAP16_EN;
}
__raw_writel(val, CSI_CSICR1);
}
void csi_enable_int(int arg)
{
unsigned long cr1 = __raw_readl(CSI_CSICR1);
if (arg == 1) {
/* still capture needs DMA intterrupt */
cr1 |= BIT_FB1_DMA_DONE_INTEN;
cr1 |= BIT_FB2_DMA_DONE_INTEN;
}
__raw_writel(cr1, CSI_CSICR1);
}
void csi_disable_int(void)
{
unsigned long cr1 = __raw_readl(CSI_CSICR1);
cr1 &= ~BIT_FB1_DMA_DONE_INTEN;
cr1 &= ~BIT_FB2_DMA_DONE_INTEN;
__raw_writel(cr1, CSI_CSICR1);
}
void csi_enable(int arg)
{
unsigned long cr = __raw_readl(CSI_CSICR18);
if (arg == 1)
cr |= BIT_CSI_ENABLE;
else
cr &= ~BIT_CSI_ENABLE;
__raw_writel(cr, CSI_CSICR18);
}
void csi_buf_stride_set(u32 stride)
{
__raw_writel(stride, CSI_CSIFBUF_PARA);
}
void csi_deinterlace_enable(bool enable)
{
unsigned long cr18 = __raw_readl(CSI_CSICR18);
if (enable == true)
cr18 |= BIT_DEINTERLACE_EN;
else
cr18 &= ~BIT_DEINTERLACE_EN;
__raw_writel(cr18, CSI_CSICR18);
}
void csi_deinterlace_mode(int mode)
{
unsigned long cr18 = __raw_readl(CSI_CSICR18);
if (mode == STD_NTSC)
cr18 |= BIT_NTSC_EN;
else
cr18 &= ~BIT_NTSC_EN;
__raw_writel(cr18, CSI_CSICR18);
}
void csi_tvdec_enable(bool enable)
{
unsigned long cr18 = __raw_readl(CSI_CSICR18);
unsigned long cr1 = __raw_readl(CSI_CSICR1);
if (enable == true) {
cr18 |= (BIT_TVDECODER_IN_EN | BIT_BASEADDR_SWITCH_EN);
cr1 |= BIT_CCIR_MODE | BIT_EXT_VSYNC;
cr1 &= ~(BIT_SOF_POL | BIT_REDGE);
} else {
cr18 &= ~(BIT_TVDECODER_IN_EN | BIT_BASEADDR_SWITCH_EN);
cr1 &= ~(BIT_CCIR_MODE | BIT_EXT_VSYNC);
cr1 |= BIT_SOF_POL | BIT_REDGE;
}
__raw_writel(cr18, CSI_CSICR18);
__raw_writel(cr1, CSI_CSICR1);
}
void csi_set_32bit_imagpara(int width, int height)
{
int imag_para = 0;
unsigned long cr3 = __raw_readl(CSI_CSICR3);
imag_para = (width << 16) | height;
__raw_writel(imag_para, CSI_CSIIMAG_PARA);
/* reflash the embeded DMA controller */
__raw_writel(cr3 | BIT_DMA_REFLASH_RFF, CSI_CSICR3);
}
void csi_set_16bit_imagpara(int width, int height)
{
int imag_para = 0;
unsigned long cr3 = __raw_readl(CSI_CSICR3);
imag_para = (width << 16) | (height * 2);
__raw_writel(imag_para, CSI_CSIIMAG_PARA);
/* reflash the embeded DMA controller */
__raw_writel(cr3 | BIT_DMA_REFLASH_RFF, CSI_CSICR3);
}
void csi_set_12bit_imagpara(int width, int height)
{
int imag_para = 0;
unsigned long cr3 = __raw_readl(CSI_CSICR3);
imag_para = (width << 16) | (height * 3 / 2);
__raw_writel(imag_para, CSI_CSIIMAG_PARA);
/* reflash the embeded DMA controller */
__raw_writel(cr3 | BIT_DMA_REFLASH_RFF, CSI_CSICR3);
}
void csi_dmareq_rff_enable(void)
{
unsigned long cr3 = __raw_readl(CSI_CSICR3);
cr3 |= BIT_DMA_REQ_EN_RFF;
cr3 |= BIT_HRESP_ERR_EN;
__raw_writel(cr3, CSI_CSICR3);
}
void csi_dmareq_rff_disable(void)
{
unsigned long cr3 = __raw_readl(CSI_CSICR3);
cr3 &= ~BIT_DMA_REQ_EN_RFF;
cr3 &= ~BIT_HRESP_ERR_EN;
__raw_writel(cr3, CSI_CSICR3);
}
void csi_disable(void)
{
csi_dmareq_rff_disable();
csi_disable_int();
csi_buf_stride_set(0);
csi_deinterlace_enable(false);
csi_tvdec_enable(false);
csi_enable(0);
}
void csi_config(struct csi_conf_param *csi_conf)
{
csi_regbase = (u32 *)CSI1_BASE_ADDR;
csihw_reset();
csi_init_interface();
csi_dmareq_rff_disable();
switch (csi_conf->bpp) {
case 32:
csi_set_32bit_imagpara(csi_conf->width, csi_conf->height);
break;
case 16:
csi_set_16bit_imagpara(csi_conf->width, csi_conf->height);
break;
default:
printf(" %s case not supported, bpp=%d\n",
__func__, csi_conf->bpp);
return;
}
__raw_writel((u32)csi_conf->fb0addr, CSI_CSIDMASA_FB1);
__raw_writel((u32)csi_conf->fb1addr, CSI_CSIDMASA_FB2);
csi_buf_stride_set(0);
if (csi_conf->btvmode) {
/* Enable csi PAL/NTSC deinterlace mode */
csi_buf_stride_set(csi_conf->width);
csi_deinterlace_mode(csi_conf->std);
csi_deinterlace_enable(true);
csi_tvdec_enable(true);
}
/* start csi */
csi_dmareq_rff_enable();
csi_enable_int(1);
csi_enable(1);
}