| /* SPDX-License-Identifier: GPL-2.0+ */ |
| /* |
| * Copyright (C) 2014 Freescale Semiconductor, Inc. All Rights Reserved. |
| * |
| */ |
| |
| /*! |
| * @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); |
| } |
| |