354 lines
13 KiB
C
354 lines
13 KiB
C
/*
|
|
* linux-3.10/drivers/media/platform/sunxi-vin/vin-vipp/vipp_reg.c
|
|
*
|
|
* Copyright (c) 2007-2017 Allwinnertech Co., Ltd.
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
******************************************************************************
|
|
*
|
|
* vipp_reg.c
|
|
*
|
|
* VIPP - vipp_reg.c module
|
|
*
|
|
* Copyright (c) 2016 by Allwinnertech Co., Ltd. http://www.allwinnertech.com
|
|
*
|
|
* Version Author Date Description
|
|
*
|
|
* 1.0 Zhao Wei 2016/07/19 First Version
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include "vipp_reg_i.h"
|
|
#include "vipp_reg.h"
|
|
|
|
#include "../utility/vin_io.h"
|
|
|
|
/*#define VIPP_SCALER_DIRECTLY_WRITE_REG*/
|
|
#define VIPP_ADDR_BIT_R_SHIFT 2
|
|
|
|
volatile void __iomem *vipp_base[MAX_VIPP_NUM];
|
|
|
|
struct vipp_reg {
|
|
VIPP_MODULE_EN_REG_t *vipp_module_en;
|
|
VIPP_SCALER_CFG_REG_t *vipp_scaler_cfg;
|
|
VIPP_SCALER_OUTPUT_SIZE_REG_t *vipp_scaler_output_size;
|
|
VIPP_OUTPUT_FMT_REG_t *vipp_output_fmt;
|
|
VIPP_OSD_CFG_REG_t *vipp_osd_cfg;
|
|
VIPP_OSD_RGB2YUV_GAIN0_REG_t *vipp_osd_rgb2yuv_gain0;
|
|
VIPP_OSD_RGB2YUV_GAIN1_REG_t *vipp_osd_rgb2yuv_gain1;
|
|
VIPP_OSD_RGB2YUV_GAIN2_REG_t *vipp_osd_rgb2yuv_gain2;
|
|
VIPP_OSD_RGB2YUV_GAIN3_REG_t *vipp_osd_rgb2yuv_gain3;
|
|
VIPP_OSD_RGB2YUV_GAIN4_REG_t *vipp_osd_rgb2yuv_gain4;
|
|
VIPP_OSD_RGB2YUV_OFFSET_REG_t *vipp_osd_rgb2yuv_offset;
|
|
VIPP_CROP_START_POSITION_REG_t *vipp_crop_start;
|
|
VIPP_CROP_SIZE_REG_t *vipp_crop_size;
|
|
};
|
|
struct vipp_reg vipp_reg_load_addr[MAX_VIPP_NUM];
|
|
|
|
struct vipp_osd_para {
|
|
VIPP_OSD_OVERLAY_CFG_REG_t *vipp_osd_overlay_cfg;
|
|
VIPP_OSD_COVER_CFG_REG_t *vipp_osd_cover_cfg;
|
|
VIPP_OSD_COVER_DATA_REG_t *vipp_osd_cover_data;
|
|
};
|
|
struct vipp_osd_para vipp_osd_para_load_addr[MAX_VIPP_NUM];
|
|
|
|
|
|
int vipp_set_base_addr(unsigned int id, unsigned long addr)
|
|
{
|
|
if (id > MAX_VIPP_NUM - 1)
|
|
return -1;
|
|
vipp_base[id] = (volatile void __iomem *)addr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* open module */
|
|
|
|
void vipp_top_clk_en(unsigned int id, unsigned int en)
|
|
{
|
|
vin_reg_clr_set(vipp_base[id] + VIPP_TOP_EN_REG_OFF,
|
|
VIPP_CLK_GATING_EN_MASK, en << VIPP_CLK_GATING_EN);
|
|
}
|
|
|
|
void vipp_enable(unsigned int id)
|
|
{
|
|
vin_reg_clr_set(vipp_base[id] + VIPP_EN_REG_OFF,
|
|
VIPP_EN_MASK, 1 << VIPP_EN);
|
|
}
|
|
|
|
void vipp_disable(unsigned int id)
|
|
{
|
|
vin_reg_clr_set(vipp_base[id] + VIPP_EN_REG_OFF,
|
|
VIPP_EN_MASK, 0 << VIPP_EN);
|
|
}
|
|
|
|
void vipp_ver_en(unsigned int id, unsigned int en)
|
|
{
|
|
vin_reg_clr_set(vipp_base[id] + VIPP_EN_REG_OFF,
|
|
VIPP_VER_EN_MASK, en << VIPP_VER_EN);
|
|
}
|
|
|
|
void vipp_version_get(unsigned int id, struct vipp_version *v)
|
|
{
|
|
unsigned int reg_val = vin_reg_readl(vipp_base[id] + VIPP_VER_REG_OFF);
|
|
v->ver_small = (reg_val & VIPP_SMALL_VER_MASK) >> VIPP_SMALL_VER;
|
|
v->ver_big = (reg_val & VIPP_BIG_VER_MASK) >> VIPP_BIG_VER;
|
|
}
|
|
|
|
void vipp_feature_list_get(unsigned int id, struct vipp_feature_list *fl)
|
|
{
|
|
unsigned int reg_val = vin_reg_readl(vipp_base[id] + VIPP_FEATURE_REG_OFF);
|
|
fl->osd_exit = (reg_val & VIPP_OSD_EXIST_MASK) >> VIPP_OSD_EXIST;
|
|
fl->fbc_exit = (reg_val & VIPP_FBC_EXIST_MASK) >> VIPP_FBC_EXIST;
|
|
}
|
|
|
|
int vipp_get_para_ready(unsigned int id)
|
|
{
|
|
unsigned int reg_val = vin_reg_readl(vipp_base[id] + VIPP_CTRL_REG_OFF);
|
|
return (reg_val & VIPP_PARA_READY_MASK) >> VIPP_PARA_READY;
|
|
}
|
|
|
|
void vipp_set_para_ready(unsigned int id, enum vipp_ready_flag flag)
|
|
{
|
|
#ifndef VIPP_SCALER_DIRECTLY_WRITE_REG
|
|
vin_reg_clr_set(vipp_base[id] + VIPP_CTRL_REG_OFF,
|
|
VIPP_PARA_READY_MASK, flag << VIPP_PARA_READY);
|
|
#endif
|
|
}
|
|
|
|
int vipp_get_osd_ov_update(unsigned int id)
|
|
{
|
|
unsigned int reg_val = vin_reg_readl(vipp_base[id] + VIPP_CTRL_REG_OFF);
|
|
return (reg_val & VIPP_OSD_OV_UPDATE_MASK) >> VIPP_OSD_OV_UPDATE;
|
|
}
|
|
|
|
void vipp_set_osd_ov_update(unsigned int id, enum vipp_update_flag flag)
|
|
{
|
|
vin_reg_clr_set(vipp_base[id] + VIPP_CTRL_REG_OFF,
|
|
VIPP_OSD_OV_UPDATE_MASK, flag << VIPP_OSD_OV_UPDATE);
|
|
}
|
|
|
|
int vipp_get_osd_cv_update(unsigned int id)
|
|
{
|
|
unsigned int reg_val = vin_reg_readl(vipp_base[id] + VIPP_CTRL_REG_OFF);
|
|
return (reg_val & VIPP_OSD_CV_UPDATE_MASK) >> VIPP_OSD_CV_UPDATE;
|
|
}
|
|
|
|
void vipp_set_osd_cv_update(unsigned int id, enum vipp_update_flag flag)
|
|
{
|
|
vin_reg_clr_set(vipp_base[id] + VIPP_CTRL_REG_OFF,
|
|
VIPP_OSD_CV_UPDATE_MASK, flag << VIPP_OSD_CV_UPDATE);
|
|
}
|
|
|
|
void vipp_set_osd_para_load_addr(unsigned int id, unsigned long dma_addr)
|
|
{
|
|
vin_reg_writel(vipp_base[id] + VIPP_OSD_LOAD_ADDR_REG_OFF, dma_addr >> VIPP_ADDR_BIT_R_SHIFT);
|
|
}
|
|
|
|
int vipp_map_osd_para_load_addr(unsigned int id, unsigned long vaddr)
|
|
{
|
|
if (id > MAX_VIPP_NUM - 1)
|
|
return -1;
|
|
|
|
vipp_osd_para_load_addr[id].vipp_osd_overlay_cfg = (VIPP_OSD_OVERLAY_CFG_REG_t *)vaddr;
|
|
vipp_osd_para_load_addr[id].vipp_osd_cover_cfg = (VIPP_OSD_COVER_CFG_REG_t *)(vaddr + MAX_OVERLAY_NUM * 8);
|
|
vipp_osd_para_load_addr[id].vipp_osd_cover_data = (VIPP_OSD_COVER_DATA_REG_t *)(vaddr + MAX_OVERLAY_NUM * 8 + MAX_COVER_NUM * 8);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void vipp_set_osd_stat_load_addr(unsigned int id, unsigned long dma_addr)
|
|
{
|
|
vin_reg_writel(vipp_base[id] + VIPP_OSD_STAT_ADDR_REG_OFF, dma_addr >> VIPP_ADDR_BIT_R_SHIFT);
|
|
}
|
|
|
|
void vipp_set_osd_bm_load_addr(unsigned int id, unsigned long dma_addr)
|
|
{
|
|
vin_reg_writel(vipp_base[id] + VIPP_OSD_BM_ADDR_REG_OFF, dma_addr >> VIPP_ADDR_BIT_R_SHIFT);
|
|
}
|
|
|
|
void vipp_set_reg_load_addr(unsigned int id, unsigned long dma_addr)
|
|
{
|
|
vin_reg_writel(vipp_base[id] + VIPP_REG_LOAD_ADDR_REG_OFF, dma_addr >> VIPP_ADDR_BIT_R_SHIFT);
|
|
}
|
|
|
|
int vipp_map_reg_load_addr(unsigned int id, unsigned long vaddr)
|
|
{
|
|
if (id > MAX_VIPP_NUM - 1)
|
|
return -1;
|
|
|
|
vipp_reg_load_addr[id].vipp_module_en = (VIPP_MODULE_EN_REG_t *)(vaddr + VIPP_MODULE_EN_REG_OFF);
|
|
vipp_reg_load_addr[id].vipp_scaler_cfg = (VIPP_SCALER_CFG_REG_t *)(vaddr + VIPP_SC_CFG_REG_OFF);
|
|
vipp_reg_load_addr[id].vipp_scaler_output_size = (VIPP_SCALER_OUTPUT_SIZE_REG_t *)(vaddr + VIPP_SC_SIZE_REG_OFF);
|
|
vipp_reg_load_addr[id].vipp_output_fmt = (VIPP_OUTPUT_FMT_REG_t *)(vaddr + VIPP_MODE_REG_OFF);
|
|
vipp_reg_load_addr[id].vipp_osd_cfg = (VIPP_OSD_CFG_REG_t *)(vaddr + VIPP_OSD_CFG_REG_OFF);
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain0 = (VIPP_OSD_RGB2YUV_GAIN0_REG_t *)(vaddr + VIPP_OSD_GAIN0_REG_OFF);
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain1 = (VIPP_OSD_RGB2YUV_GAIN1_REG_t *)(vaddr + VIPP_OSD_GAIN1_REG_OFF);
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain2 = (VIPP_OSD_RGB2YUV_GAIN2_REG_t *)(vaddr + VIPP_OSD_GAIN2_REG_OFF);
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain3 = (VIPP_OSD_RGB2YUV_GAIN3_REG_t *)(vaddr + VIPP_OSD_GAIN3_REG_OFF);
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain4 = (VIPP_OSD_RGB2YUV_GAIN4_REG_t *)(vaddr + VIPP_OSD_GAIN4_REG_OFF);
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_offset = (VIPP_OSD_RGB2YUV_OFFSET_REG_t *)(vaddr + VIPP_OSD_OFFSET_REG_OFF);
|
|
vipp_reg_load_addr[id].vipp_crop_start = (VIPP_CROP_START_POSITION_REG_t *)(vaddr + VIPP_CROP_START_REG_OFF);
|
|
vipp_reg_load_addr[id].vipp_crop_size = (VIPP_CROP_SIZE_REG_t *)(vaddr + VIPP_CROP_SIZE_REG_OFF);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void vipp_get_status(unsigned int id, struct vipp_status *status)
|
|
{
|
|
unsigned int reg_val = vin_reg_readl(vipp_base[id] + VIPP_STA_REG_OFF);
|
|
status->reg_load_pd = (reg_val & VIPP_REG_LOAD_PD_MASK) >> VIPP_REG_LOAD_PD;
|
|
status->bm_error_pd = (reg_val & VIPP_BM_ERROR_PD_MASK) >> VIPP_BM_ERROR_PD;
|
|
}
|
|
|
|
void vipp_clr_status(unsigned int id, enum vipp_status_sel sel)
|
|
{
|
|
vin_reg_writel(vipp_base[id] + VIPP_STA_REG_OFF, sel);
|
|
}
|
|
|
|
void vipp_scaler_en(unsigned int id, unsigned int en)
|
|
{
|
|
#ifndef VIPP_SCALER_DIRECTLY_WRITE_REG
|
|
vipp_reg_load_addr[id].vipp_module_en->bits.sc_en = en;
|
|
#else
|
|
VIPP_MODULE_EN_REG_t vipp_module_en;
|
|
vipp_module_en.dwval = 0;
|
|
vipp_module_en.bits.sc_en = en;
|
|
vin_reg_writel(vipp_base[id] + VIPP_MODULE_EN_REG_OFF, vipp_module_en.dwval);
|
|
#endif
|
|
}
|
|
|
|
void vipp_osd_en(unsigned int id, unsigned int en)
|
|
{
|
|
vipp_reg_load_addr[id].vipp_module_en->bits.osd_en = en;
|
|
}
|
|
|
|
void vipp_chroma_ds_en(unsigned int id, unsigned int en)
|
|
{
|
|
vipp_reg_load_addr[id].vipp_module_en->bits.chroma_ds_en = en;
|
|
}
|
|
|
|
void vipp_scaler_cfg(unsigned int id, struct vipp_scaler_config *cfg)
|
|
{
|
|
#ifndef VIPP_SCALER_DIRECTLY_WRITE_REG
|
|
vipp_reg_load_addr[id].vipp_scaler_cfg->bits.sc_out_fmt = cfg->sc_out_fmt;
|
|
vipp_reg_load_addr[id].vipp_scaler_cfg->bits.sc_xratio = cfg->sc_x_ratio;
|
|
vipp_reg_load_addr[id].vipp_scaler_cfg->bits.sc_yratio = cfg->sc_y_ratio;
|
|
vipp_reg_load_addr[id].vipp_scaler_cfg->bits.sc_weight_shift = cfg->sc_w_shift;
|
|
#else
|
|
VIPP_SCALER_CFG_REG_t vipp_scaler_cfg;
|
|
vipp_scaler_cfg.dwval = 0;
|
|
vipp_scaler_cfg.bits.sc_out_fmt = cfg->sc_out_fmt;
|
|
vipp_scaler_cfg.bits.sc_xratio = cfg->sc_x_ratio;
|
|
vipp_scaler_cfg.bits.sc_yratio = cfg->sc_y_ratio;
|
|
vipp_scaler_cfg.bits.sc_weight_shift = cfg->sc_w_shift;
|
|
vin_reg_writel(vipp_base[id] + VIPP_SC_CFG_REG_OFF, vipp_scaler_cfg.dwval);
|
|
|
|
#endif
|
|
}
|
|
|
|
void vipp_scaler_output_fmt(unsigned int id, enum vipp_format fmt)
|
|
{
|
|
#ifndef VIPP_SCALER_DIRECTLY_WRITE_REG
|
|
vipp_reg_load_addr[id].vipp_scaler_cfg->bits.sc_out_fmt = fmt;
|
|
#else
|
|
vin_reg_clr_set(vipp_base[id] + VIPP_SC_CFG_REG_OFF, 0x1, fmt);
|
|
#endif
|
|
}
|
|
|
|
void vipp_scaler_output_size(unsigned int id, struct vipp_scaler_size *size)
|
|
{
|
|
#ifndef VIPP_SCALER_DIRECTLY_WRITE_REG
|
|
vipp_reg_load_addr[id].vipp_scaler_output_size->bits.sc_width = size->sc_width;
|
|
vipp_reg_load_addr[id].vipp_scaler_output_size->bits.sc_height = size->sc_height;
|
|
#else
|
|
VIPP_SCALER_OUTPUT_SIZE_REG_t vipp_scaler_output_size;
|
|
vipp_scaler_output_size.dwval = 0;
|
|
vipp_scaler_output_size.bits.sc_width = size->sc_width;
|
|
vipp_scaler_output_size.bits.sc_height = size->sc_height;
|
|
vin_reg_writel(vipp_base[id] + VIPP_SC_SIZE_REG_OFF, vipp_scaler_output_size.dwval);
|
|
#endif
|
|
}
|
|
|
|
void vipp_output_fmt_cfg(unsigned int id, enum vipp_format fmt)
|
|
{
|
|
#ifndef VIPP_SCALER_DIRECTLY_WRITE_REG
|
|
vipp_reg_load_addr[id].vipp_output_fmt->bits.vipp_out_fmt = fmt;
|
|
#else
|
|
VIPP_OUTPUT_FMT_REG_t vipp_output_fmt;
|
|
vipp_output_fmt.dwval = 0;
|
|
vipp_output_fmt.bits.vipp_out_fmt = fmt;
|
|
vin_reg_writel(vipp_base[id] + VIPP_MODE_REG_OFF, vipp_output_fmt.dwval);
|
|
#endif
|
|
}
|
|
|
|
void vipp_osd_cfg(unsigned int id, struct vipp_osd_config *cfg)
|
|
{
|
|
vipp_reg_load_addr[id].vipp_osd_cfg->bits.osd_ov_en = cfg->osd_ov_en;
|
|
vipp_reg_load_addr[id].vipp_osd_cfg->bits.osd_cv_en = cfg->osd_cv_en;
|
|
vipp_reg_load_addr[id].vipp_osd_cfg->bits.osd_argb_mode = cfg->osd_argb_mode;
|
|
vipp_reg_load_addr[id].vipp_osd_cfg->bits.osd_stat_en = cfg->osd_stat_en;
|
|
vipp_reg_load_addr[id].vipp_osd_cfg->bits.osd_ov_num = cfg->osd_ov_num;
|
|
vipp_reg_load_addr[id].vipp_osd_cfg->bits.osd_cv_num = cfg->osd_cv_num;
|
|
}
|
|
|
|
void vipp_osd_rgb2yuv(unsigned int id, struct vipp_rgb2yuv_factor *factor)
|
|
{
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain0->bits.jc0 = factor->jc0;
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain0->bits.jc1 = factor->jc1;
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain1->bits.jc2 = factor->jc2;
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain1->bits.jc3 = factor->jc3;
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain2->bits.jc4 = factor->jc4;
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain2->bits.jc5 = factor->jc5;
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain3->bits.jc6 = factor->jc6;
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain3->bits.jc7 = factor->jc7;
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_gain4->bits.jc8 = factor->jc8;
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_offset->bits.jc9 = factor->jc9;
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_offset->bits.jc10 = factor->jc10;
|
|
vipp_reg_load_addr[id].vipp_osd_rgb2yuv_offset->bits.jc11 = factor->jc11;
|
|
}
|
|
|
|
void vipp_set_crop(unsigned int id, struct vipp_crop *crop)
|
|
{
|
|
vipp_reg_load_addr[id].vipp_crop_start->bits.crop_hor_st = crop->hor;
|
|
vipp_reg_load_addr[id].vipp_crop_start->bits.crop_ver_st = crop->ver;
|
|
vipp_reg_load_addr[id].vipp_crop_size->bits.crop_width = crop->width;
|
|
vipp_reg_load_addr[id].vipp_crop_size->bits.crop_height = crop->height;
|
|
}
|
|
|
|
void vipp_osd_para_cfg(unsigned int id, struct vipp_osd_para_config *para,
|
|
struct vipp_osd_config *cfg)
|
|
{
|
|
int i;
|
|
for (i = 0; i < cfg->osd_ov_num; i++) {
|
|
vipp_osd_para_load_addr[id].vipp_osd_overlay_cfg[i].bits.h_start = para->overlay_cfg[i].h_start;
|
|
vipp_osd_para_load_addr[id].vipp_osd_overlay_cfg[i].bits.h_end = para->overlay_cfg[i].h_end;
|
|
vipp_osd_para_load_addr[id].vipp_osd_overlay_cfg[i].bits.v_start = para->overlay_cfg[i].v_start;
|
|
vipp_osd_para_load_addr[id].vipp_osd_overlay_cfg[i].bits.v_end = para->overlay_cfg[i].v_end;
|
|
vipp_osd_para_load_addr[id].vipp_osd_overlay_cfg[i].bits.alpha = para->overlay_cfg[i].alpha;
|
|
vipp_osd_para_load_addr[id].vipp_osd_overlay_cfg[i].bits.inverse_en = para->overlay_cfg[i].inverse_en;
|
|
}
|
|
|
|
for (i = 0; i < cfg->osd_cv_num; i++) {
|
|
vipp_osd_para_load_addr[id].vipp_osd_cover_cfg[i].bits.h_start = para->cover_cfg[i].h_start;
|
|
vipp_osd_para_load_addr[id].vipp_osd_cover_cfg[i].bits.h_end = para->cover_cfg[i].h_end;
|
|
vipp_osd_para_load_addr[id].vipp_osd_cover_cfg[i].bits.v_start = para->cover_cfg[i].v_start;
|
|
vipp_osd_para_load_addr[id].vipp_osd_cover_cfg[i].bits.v_end = para->cover_cfg[i].v_end;
|
|
vipp_osd_para_load_addr[id].vipp_osd_cover_data[i].bits.y = para->cover_data[i].y;
|
|
vipp_osd_para_load_addr[id].vipp_osd_cover_data[i].bits.u = para->cover_data[i].u;
|
|
vipp_osd_para_load_addr[id].vipp_osd_cover_data[i].bits.v = para->cover_data[i].v;
|
|
}
|
|
}
|