1
0
Fork 0

mxc: IPU3: Forward IPUv3 common driver from imx_4.19.y kernel

This patch forwards IPUv3 common driver from imx_4.19.y kernel.
This includs IPUv3 common, IPUv3 prefetch engine and VDOA support.

[ Liu Ying: Fixed a minor build warning for PRE driver. ]
Signed-off-by: Liu Ying <victor.liu@nxp.com>
5.4-rM2-2.2.x-imx-squashed
Liu Ying 2019-08-23 15:20:43 +08:00 committed by Dong Aisheng
parent 2d4f90ebd9
commit bc77a44ba0
26 changed files with 17593 additions and 0 deletions

View File

@ -228,4 +228,5 @@ source "drivers/interconnect/Kconfig"
source "drivers/counter/Kconfig"
source "drivers/mxc/Kconfig"
endmenu

View File

@ -186,3 +186,4 @@ obj-$(CONFIG_SIOX) += siox/
obj-$(CONFIG_GNSS) += gnss/
obj-$(CONFIG_INTERCONNECT) += interconnect/
obj-$(CONFIG_COUNTER) += counter/
obj-y += mxc/

View File

@ -0,0 +1,18 @@
# drivers/mxc/Kconfig
if ARCH_MXC
menu "MXC support drivers"
config MXC_IPU
bool "Image Processing Unit Driver"
select MXC_IPU_V3
help
If you plan to use the Image Processing unit, say
Y here. IPU is needed by Framebuffer and V4L2 drivers.
source "drivers/mxc/ipu3/Kconfig"
endmenu
endif

View File

@ -0,0 +1 @@
obj-$(CONFIG_MXC_IPU_V3) += ipu3/

View File

@ -0,0 +1,21 @@
config MXC_IPU_V3
bool
config MXC_IPU_V3_PRG
tristate "i.MX IPUv3 prefetch gasket engine"
depends on MXC_IPU_V3 && MXC_IPU_V3_PRE
help
This enables support for the IPUv3 prefetch gasket engine to
support double buffer handshake control bewteen IPUv3 and
prefetch engine(PRE), snoop the AXI interface for display
refresh requests to memory and modify the request address to
fetch the double buffered row of blocks in OCRAM.
config MXC_IPU_V3_PRE
tristate "i.MX IPUv3 prefetch engine"
depends on MXC_IPU_V3
select MXC_IPU_V3_PRG
help
This enables support for the IPUv3 prefetch engine to improve
the system memory performance. The engine has the capability
to resolve framebuffers in tile pixel format to linear.

View File

@ -0,0 +1,7 @@
obj-$(CONFIG_MXC_IPU_V3) = mxc_ipu.o
obj-$(CONFIG_MXC_IPU_V3_PRG) += prg.o
obj-$(CONFIG_MXC_IPU_V3_PRE) += pre.o
mxc_ipu-objs := ipu_common.o ipu_ic.o ipu_disp.o ipu_capture.o ipu_device.o \
ipu_calc_stripes_sizes.o vdoa.o ipu_pixel_clk.o

View File

@ -0,0 +1,495 @@
/*
* Copyright 2009-2015 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*
* @file ipu_calc_stripes_sizes.c
*
* @brief IPU IC functions
*
* @ingroup IPU
*/
#include <linux/ipu-v3.h>
#include <linux/module.h>
#include <linux/math64.h>
#define BPP_32 0
#define BPP_16 3
#define BPP_8 5
#define BPP_24 1
#define BPP_12 4
#define BPP_18 2
static u32 truncate(u32 up, /* 0: down; else: up */
u64 a, /* must be non-negative */
u32 b)
{
u32 d;
u64 div;
div = div_u64(a, b);
d = b * (div >> 32);
if (up && (a > (((u64)d) << 32)))
return d+b;
else
return d;
}
static unsigned int f_calc(unsigned int pfs, unsigned int bpp, unsigned int *write)
{/* return input_f */
unsigned int f_calculated = 0;
switch (pfs) {
case IPU_PIX_FMT_YVU422P:
case IPU_PIX_FMT_YUV422P:
case IPU_PIX_FMT_YUV420P2:
case IPU_PIX_FMT_YUV420P:
case IPU_PIX_FMT_YVU420P:
case IPU_PIX_FMT_YUV444P:
f_calculated = 16;
break;
case IPU_PIX_FMT_RGB565:
case IPU_PIX_FMT_YUYV:
case IPU_PIX_FMT_UYVY:
f_calculated = 8;
break;
case IPU_PIX_FMT_NV12:
f_calculated = 8;
break;
default:
f_calculated = 0;
break;
}
if (!f_calculated) {
switch (bpp) {
case BPP_32:
f_calculated = 2;
break;
case BPP_16:
f_calculated = 4;
break;
case BPP_8:
case BPP_24:
f_calculated = 8;
break;
case BPP_12:
f_calculated = 16;
break;
case BPP_18:
f_calculated = 32;
break;
default:
f_calculated = 0;
break;
}
}
return f_calculated;
}
static unsigned int m_calc(unsigned int pfs)
{
unsigned int m_calculated = 0;
switch (pfs) {
case IPU_PIX_FMT_YUV420P2:
case IPU_PIX_FMT_YUV420P:
case IPU_PIX_FMT_YVU422P:
case IPU_PIX_FMT_YUV422P:
case IPU_PIX_FMT_YVU420P:
case IPU_PIX_FMT_YUV444P:
m_calculated = 16;
break;
case IPU_PIX_FMT_NV12:
case IPU_PIX_FMT_YUYV:
case IPU_PIX_FMT_UYVY:
m_calculated = 8;
break;
default:
m_calculated = 8;
break;
}
return m_calculated;
}
static int calc_split_resize_coeffs(unsigned int inSize, unsigned int outSize,
unsigned int *resizeCoeff,
unsigned int *downsizeCoeff)
{
uint32_t tempSize;
uint32_t tempDownsize;
if (inSize > 4096) {
pr_debug("IC input size(%d) cannot exceed 4096\n",
inSize);
return -EINVAL;
}
if (outSize > 1024) {
pr_debug("IC output size(%d) cannot exceed 1024\n",
outSize);
return -EINVAL;
}
if ((outSize << 3) < inSize) {
pr_debug("IC cannot downsize more than 8:1\n");
return -EINVAL;
}
/* Compute downsizing coefficient */
/* Output of downsizing unit cannot be more than 1024 */
tempDownsize = 0;
tempSize = inSize;
while (((tempSize > 1024) || (tempSize >= outSize * 2)) &&
(tempDownsize < 2)) {
tempSize >>= 1;
tempDownsize++;
}
*downsizeCoeff = tempDownsize;
/* compute resizing coefficient using the following equation:
resizeCoeff = M*(SI -1)/(SO - 1)
where M = 2^13, SI - input size, SO - output size */
*resizeCoeff = (8192L * (tempSize - 1)) / (outSize - 1);
if (*resizeCoeff >= 16384L) {
pr_debug("Overflow on IC resize coefficient.\n");
return -EINVAL;
}
pr_debug("resizing from %u -> %u pixels, "
"downsize=%u, resize=%u.%lu (reg=%u)\n", inSize, outSize,
*downsizeCoeff, (*resizeCoeff >= 8192L) ? 1 : 0,
((*resizeCoeff & 0x1FFF) * 10000L) / 8192L, *resizeCoeff);
return 0;
}
/* Stripe parameters calculator */
/**************************************************************************
Notes:
MSW = the maximal width allowed for a stripe
i.MX31: 720, i.MX35: 800, i.MX37/51/53: 1024
cirr = the maximal inverse resizing ratio for which overlap in the input
is requested; typically cirr~2
flags
bit 0 - equal_stripes
0 each stripe is allowed to have independent parameters
for maximal image quality
1 the stripes are requested to have identical parameters
(except the base address), for maximal performance
bit 1 - vertical/horizontal
0 horizontal
1 vertical
If performance is the top priority (above image quality)
Avoid overlap, by setting CIRR = 0
This will also force effectively identical_stripes = 1
Choose IF & OF that corresponds to the same IOX/SX for both stripes
Choose IFW & OFW such that
IFW/IM, IFW/IF, OFW/OM, OFW/OF are even integers
The function returns an error status:
0: no error
1: invalid input parameters -> aborted without result
Valid parameters should satisfy the following conditions
IFW <= OFW, otherwise downsizing is required
- which is not supported yet
4 <= IFW,OFW, so some interpolation may be needed even without overlap
IM, OM, IF, OF should not vanish
2*IF <= IFW
so the frame can be split to two equal stripes, even without overlap
2*(OF+IF/irr_opt) <= OFW
so a valid positive INW exists even for equal stripes
OF <= MSW, otherwise, the left stripe cannot be sufficiently large
MSW < OFW, so splitting to stripes is required
OFW <= 2*MSW, so two stripes are sufficient
(this also implies that 2<=MSW)
2: OF is not a multiple of OM - not fully-supported yet
Output is produced but OW is not guaranited to be a multiple of OM
4: OFW reduced to be a multiple of OM
8: CIRR > 1: truncated to 1
Overlap is not supported (and not needed) y for upsizing)
**************************************************************************/
int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
/* input frame width;>1 */
unsigned int output_frame_width, /* output frame width; >1 */
const unsigned int maximal_stripe_width,
/* the maximal width allowed for a stripe */
const unsigned long long cirr, /* see above */
const unsigned int flags, /* see above */
u32 input_pixelformat,/* pixel format after of read channel*/
u32 output_pixelformat,/* pixel format after of write channel*/
struct stripe_param *left,
struct stripe_param *right)
{
const unsigned int irr_frac_bits = 13;
const unsigned long irr_steps = 1 << irr_frac_bits;
const u64 dirr = ((u64)1) << (32 - 2);
/* The maximum relative difference allowed between the irrs */
const u64 cr = ((u64)4) << 32;
/* The importance ratio between the two terms in the cost function below */
unsigned int status;
unsigned int temp;
unsigned int onw_min;
unsigned int inw = 0, onw = 0, inw_best = 0;
/* number of pixels in the left stripe NOT hidden by the right stripe */
u64 irr_opt; /* the optimal inverse resizing ratio */
u64 rr_opt; /* the optimal resizing ratio = 1/irr_opt*/
u64 dinw; /* the misalignment between the stripes */
/* (measured in units of input columns) */
u64 difwl, difwr = 0;
/* The number of input columns not reflected in the output */
/* the resizing ratio used for the right stripe is */
/* left->irr and right->irr respectively */
u64 cost, cost_min;
u64 div; /* result of division */
bool equal_stripes = (flags & 0x1) != 0;
bool vertical = (flags & 0x2) != 0;
unsigned int input_m, input_f, output_m, output_f; /* parameters for upsizing by stripes */
unsigned int resize_coeff;
unsigned int downsize_coeff;
status = 0;
if (vertical) {
input_f = 2;
input_m = 8;
output_f = 8;
output_m = 2;
} else {
input_f = f_calc(input_pixelformat, 0, NULL);
input_m = m_calc(input_pixelformat);
output_f = input_m;
output_m = m_calc(output_pixelformat);
}
if ((input_frame_width < 4) || (output_frame_width < 4))
return 1;
irr_opt = div_u64((((u64)(input_frame_width - 1)) << 32),
(output_frame_width - 1));
rr_opt = div_u64((((u64)(output_frame_width - 1)) << 32),
(input_frame_width - 1));
if ((input_m == 0) || (output_m == 0) || (input_f == 0) || (output_f == 0)
|| (input_frame_width < (2 * input_f))
|| ((((u64)output_frame_width) << 32) <
(2 * ((((u64)output_f) << 32) + (input_f * rr_opt))))
|| (maximal_stripe_width < output_f)
|| ((output_frame_width <= maximal_stripe_width)
&& (equal_stripes == 0))
|| ((2 * maximal_stripe_width) < output_frame_width))
return 1;
if (output_f % output_m)
status += 2;
temp = truncate(0, (((u64)output_frame_width) << 32), output_m);
if (temp < output_frame_width) {
output_frame_width = temp;
status += 4;
}
pr_debug("---------------->\n"
"if = %d\n"
"im = %d\n"
"of = %d\n"
"om = %d\n"
"irr_opt = %llu\n"
"rr_opt = %llu\n"
"cirr = %llu\n"
"pixel in = %08x\n"
"pixel out = %08x\n"
"ifw = %d\n"
"ofwidth = %d\n",
input_f,
input_m,
output_f,
output_m,
irr_opt,
rr_opt,
cirr,
input_pixelformat,
output_pixelformat,
input_frame_width,
output_frame_width
);
if (equal_stripes) {
if ((irr_opt > cirr) /* overlap in the input is not requested */
&& ((input_frame_width % (input_m << 1)) == 0)
&& ((input_frame_width % (input_f << 1)) == 0)
&& ((output_frame_width % (output_m << 1)) == 0)
&& ((output_frame_width % (output_f << 1)) == 0)) {
/* without overlap */
left->input_width = right->input_width = right->input_column =
input_frame_width >> 1;
left->output_width = right->output_width = right->output_column =
output_frame_width >> 1;
left->input_column = 0;
left->output_column = 0;
div = div_u64(((((u64)irr_steps) << 32) *
(right->input_width - 1)), (right->output_width - 1));
left->irr = right->irr = truncate(0, div, 1);
} else { /* with overlap */
onw = truncate(0, (((u64)output_frame_width - 1) << 32) >> 1,
output_f);
inw = truncate(0, onw * irr_opt, input_f);
/* this is the maximal inw which allows the same resizing ratio */
/* in both stripes */
onw = truncate(1, (inw * rr_opt), output_f);
div = div_u64((((u64)(irr_steps * inw)) <<
32), onw);
left->irr = right->irr = truncate(0, div, 1);
left->output_width = right->output_width =
output_frame_width - onw;
/* These are valid assignments for output_width, */
/* assuming output_f is a multiple of output_m */
div = (((u64)(left->output_width-1) * (left->irr)) << 32);
div = (((u64)1) << 32) + div_u64(div, irr_steps);
left->input_width = right->input_width = truncate(1, div, input_m);
div = div_u64((((u64)((right->output_width - 1) * right->irr)) <<
32), irr_steps);
difwr = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
div = div_u64((difwr + (((u64)input_f) << 32)), 2);
left->input_column = truncate(0, div, input_f);
/* This splits the truncated input columns evenly */
/* between the left and right margins */
right->input_column = left->input_column + inw;
left->output_column = 0;
right->output_column = onw;
}
if (left->input_width > left->output_width) {
if (calc_split_resize_coeffs(left->input_width,
left->output_width,
&resize_coeff,
&downsize_coeff) < 0)
return -EINVAL;
if (downsize_coeff > 0) {
left->irr = right->irr =
(downsize_coeff << 14) | resize_coeff;
}
}
pr_debug("inw %d, onw %d, ilw %d, ilc %d, olw %d,"
" irw %d, irc %d, orw %d, orc %d, "
"difwr %llu, lirr %u\n",
inw, onw, left->input_width,
left->input_column, left->output_width,
right->input_width, right->input_column,
right->output_width,
right->output_column, difwr, left->irr);
} else { /* independent stripes */
onw_min = output_frame_width - maximal_stripe_width;
/* onw is a multiple of output_f, in the range */
/* [max(output_f,output_frame_width-maximal_stripe_width),*/
/*min(output_frame_width-2,maximal_stripe_width)] */
/* definitely beyond the cost of any valid setting */
cost_min = (((u64)input_frame_width) << 32) + cr;
onw = truncate(0, ((u64)maximal_stripe_width), output_f);
if (output_frame_width - onw == 1)
onw -= output_f; /* => onw and output_frame_width-1-onw are positive */
inw = truncate(0, onw * irr_opt, input_f);
/* this is the maximal inw which allows the same resizing ratio */
/* in both stripes */
onw = truncate(1, inw * rr_opt, output_f);
do {
div = div_u64((((u64)(irr_steps * inw)) << 32), onw);
left->irr = truncate(0, div, 1);
div = div_u64((((u64)(onw * left->irr)) << 32),
irr_steps);
dinw = (((u64)inw) << 32) - div;
div = div_u64((((u64)((output_frame_width - 1 - onw) * left->irr)) <<
32), irr_steps);
difwl = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
cost = difwl + (((u64)(cr * dinw)) >> 32);
if (cost < cost_min) {
inw_best = inw;
cost_min = cost;
}
inw -= input_f;
onw = truncate(1, inw * rr_opt, output_f);
/* This is the minimal onw which allows the same resizing ratio */
/* in both stripes */
} while (onw >= onw_min);
inw = inw_best;
onw = truncate(1, inw * rr_opt, output_f);
div = div_u64((((u64)(irr_steps * inw)) << 32), onw);
left->irr = truncate(0, div, 1);
left->output_width = onw;
right->output_width = output_frame_width - onw;
/* These are valid assignments for output_width, */
/* assuming output_f is a multiple of output_m */
left->input_width = truncate(1, ((u64)(inw + 1)) << 32, input_m);
right->input_width = truncate(1, ((u64)(input_frame_width - inw)) <<
32, input_m);
div = div_u64((((u64)(irr_steps * (input_frame_width - 1 - inw))) <<
32), (right->output_width - 1));
right->irr = truncate(0, div, 1);
temp = truncate(0, ((u64)left->irr) * ((((u64)1) << 32) + dirr), 1);
if (temp < right->irr)
right->irr = temp;
div = div_u64(((u64)((right->output_width - 1) * right->irr) <<
32), irr_steps);
difwr = (u64)(input_frame_width - 1 - inw) - div;
div = div_u64((difwr + (((u64)input_f) << 32)), 2);
left->input_column = truncate(0, div, input_f);
/* This splits the truncated input columns evenly */
/* between the left and right margins */
right->input_column = left->input_column + inw;
left->output_column = 0;
right->output_column = onw;
if (left->input_width > left->output_width) {
if (calc_split_resize_coeffs(left->input_width,
left->output_width,
&resize_coeff,
&downsize_coeff) < 0)
return -EINVAL;
left->irr = (downsize_coeff << 14) | resize_coeff;
}
if (right->input_width > right->output_width) {
if (calc_split_resize_coeffs(right->input_width,
right->output_width,
&resize_coeff,
&downsize_coeff) < 0)
return -EINVAL;
right->irr = (downsize_coeff << 14) | resize_coeff;
}
}
return status;
}
EXPORT_SYMBOL(ipu_calc_stripes_sizes);

View File

@ -0,0 +1,816 @@
/*
* Copyright 2008-2015 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*!
* @file ipu_capture.c
*
* @brief IPU capture dase functions
*
* @ingroup IPU
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ipu-v3.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include "ipu_prv.h"
#include "ipu_regs.h"
/*!
* _ipu_csi_mclk_set
*
* @param ipu ipu handler
* @param pixel_clk desired pixel clock frequency in Hz
* @param csi csi 0 or csi 1
*
* @return Returns 0 on success or negative error code on fail
*/
int _ipu_csi_mclk_set(struct ipu_soc *ipu, uint32_t pixel_clk, uint32_t csi)
{
uint32_t temp;
int32_t div_ratio;
div_ratio = (clk_get_rate(ipu->ipu_clk) / pixel_clk) - 1;
if (div_ratio > 0xFF || div_ratio < 0) {
dev_dbg(ipu->dev, "value of pixel_clk extends normal range\n");
return -EINVAL;
}
temp = ipu_csi_read(ipu, csi, CSI_SENS_CONF);
temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
ipu_csi_write(ipu, csi, temp |
(div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
CSI_SENS_CONF);
return 0;
}
/*!
* ipu_csi_init_interface
* Sets initial values for the CSI registers.
* The width and height of the sensor and the actual frame size will be
* set to the same values.
* @param ipu ipu handler
* @param width Sensor width
* @param height Sensor height
* @param pixel_fmt pixel format
* @param cfg_param ipu_csi_signal_cfg_t structure
* @param csi csi 0 or csi 1
*
* @return 0 for success, -EINVAL for error
*/
int32_t
ipu_csi_init_interface(struct ipu_soc *ipu, uint16_t width, uint16_t height,
uint32_t pixel_fmt, ipu_csi_signal_cfg_t cfg_param)
{
uint32_t data = 0;
uint32_t csi = cfg_param.csi;
/* Set SENS_DATA_FORMAT bits (8, 9 and 10)
RGB or YUV444 is 0 which is current value in data so not set
explicitly
This is also the default value if attempts are made to set it to
something invalid. */
switch (pixel_fmt) {
case IPU_PIX_FMT_YUYV:
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
break;
case IPU_PIX_FMT_UYVY:
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
break;
case IPU_PIX_FMT_RGB24:
case IPU_PIX_FMT_BGR24:
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
break;
case IPU_PIX_FMT_GENERIC:
case IPU_PIX_FMT_GENERIC_16:
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
break;
case IPU_PIX_FMT_RGB565:
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
break;
case IPU_PIX_FMT_RGB555:
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
break;
default:
return -EINVAL;
}
/* Set the CSI_SENS_CONF register remaining fields */
data |= cfg_param.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
cfg_param.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
cfg_param.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
cfg_param.Vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
cfg_param.Hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
cfg_param.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
cfg_param.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
cfg_param.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
cfg_param.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
cfg_param.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
cfg_param.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
_ipu_get(ipu);
mutex_lock(&ipu->mutex_lock);
ipu_csi_write(ipu, csi, data, CSI_SENS_CONF);
/* Setup sensor frame size */
ipu_csi_write(ipu, csi, (width - 1) | (height - 1) << 16, CSI_SENS_FRM_SIZE);
/* Set CCIR registers */
if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) {
ipu_csi_write(ipu, csi, 0x40030, CSI_CCIR_CODE_1);
ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
} else if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED) {
if (width == 720 && height == 625) {
/* PAL case */
/*
* Field0BlankEnd = 0x6, Field0BlankStart = 0x2,
* Field0ActiveEnd = 0x4, Field0ActiveStart = 0
*/
ipu_csi_write(ipu, csi, 0x40596, CSI_CCIR_CODE_1);
/*
* Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
* Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
*/
ipu_csi_write(ipu, csi, 0xD07DF, CSI_CCIR_CODE_2);
ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
} else if (width == 720 && height == 525) {
/* NTSC case */
/*
* Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
* Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1
*/
ipu_csi_write(ipu, csi, 0xD07DF, CSI_CCIR_CODE_1);
/*
* Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
* Field1ActiveEnd = 0x4, Field1ActiveStart = 0
*/
ipu_csi_write(ipu, csi, 0x40596, CSI_CCIR_CODE_2);
ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
} else {
dev_err(ipu->dev, "Unsupported CCIR656 interlaced "
"video mode\n");
mutex_unlock(&ipu->mutex_lock);
_ipu_put(ipu);
return -EINVAL;
}
_ipu_csi_ccir_err_detection_enable(ipu, csi);
} else if ((cfg_param.clk_mode ==
IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR) ||
(cfg_param.clk_mode ==
IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR) ||
(cfg_param.clk_mode ==
IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR) ||
(cfg_param.clk_mode ==
IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR)) {
ipu_csi_write(ipu, csi, 0x40030, CSI_CCIR_CODE_1);
ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
_ipu_csi_ccir_err_detection_enable(ipu, csi);
} else if ((cfg_param.clk_mode == IPU_CSI_CLK_MODE_GATED_CLK) ||
(cfg_param.clk_mode == IPU_CSI_CLK_MODE_NONGATED_CLK)) {
_ipu_csi_ccir_err_detection_disable(ipu, csi);
}
dev_dbg(ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
ipu_csi_read(ipu, csi, CSI_SENS_CONF));
dev_dbg(ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
ipu_csi_read(ipu, csi, CSI_ACT_FRM_SIZE));
mutex_unlock(&ipu->mutex_lock);
_ipu_put(ipu);
return 0;
}
EXPORT_SYMBOL(ipu_csi_init_interface);
/*!
* ipu_csi_get_sensor_protocol
*
* @param ipu ipu handler
* @param csi csi 0 or csi 1
*
* @return Returns sensor protocol
*/
int32_t ipu_csi_get_sensor_protocol(struct ipu_soc *ipu, uint32_t csi)
{
int ret;
_ipu_get(ipu);
ret = (ipu_csi_read(ipu, csi, CSI_SENS_CONF) &
CSI_SENS_CONF_SENS_PRTCL_MASK) >>
CSI_SENS_CONF_SENS_PRTCL_SHIFT;
_ipu_put(ipu);
return ret;
}
EXPORT_SYMBOL(ipu_csi_get_sensor_protocol);
/*!
* ipu_csi_enable_mclk
*
* @param ipu ipu handler
* @param csi csi 0 or csi 1
* @param flag true to enable mclk, false to disable mclk
* @param wait true to wait 100ms make clock stable, false not wait
*
* @return Returns 0 on success
*/
int ipu_csi_enable_mclk(struct ipu_soc *ipu, int csi, bool flag, bool wait)
{
/* Return immediately if there is no csi_clk to manage */
if (ipu->csi_clk[csi] == NULL)
return 0;
if (flag) {
clk_enable(ipu->csi_clk[csi]);
if (wait == true)
msleep(10);
} else {
clk_disable(ipu->csi_clk[csi]);
}
return 0;
}
EXPORT_SYMBOL(ipu_csi_enable_mclk);
/*!
* ipu_csi_get_window_size
*
* @param ipu ipu handler
* @param width pointer to window width
* @param height pointer to window height
* @param csi csi 0 or csi 1
*/
void ipu_csi_get_window_size(struct ipu_soc *ipu, uint32_t *width, uint32_t *height, uint32_t csi)
{
uint32_t reg;
_ipu_get(ipu);
mutex_lock(&ipu->mutex_lock);
reg = ipu_csi_read(ipu, csi, CSI_ACT_FRM_SIZE);
*width = (reg & 0xFFFF) + 1;
*height = (reg >> 16 & 0xFFFF) + 1;
mutex_unlock(&ipu->mutex_lock);
_ipu_put(ipu);
}
EXPORT_SYMBOL(ipu_csi_get_window_size);
/*!
* ipu_csi_set_window_size
*
* @param ipu ipu handler
* @param width window width
* @param height window height
* @param csi csi 0 or csi 1
*/
void ipu_csi_set_window_size(struct ipu_soc *ipu, uint32_t width, uint32_t height, uint32_t csi)
{
_ipu_get(ipu);
mutex_lock(&ipu->mutex_lock);
ipu_csi_write(ipu, csi, (width - 1) | (height - 1) << 16, CSI_ACT_FRM_SIZE);
mutex_unlock(&ipu->mutex_lock);
_ipu_put(ipu);
}
EXPORT_SYMBOL(ipu_csi_set_window_size);
/*!
* ipu_csi_set_window_pos
*
* @param ipu ipu handler
* @param left uint32 window x start
* @param top uint32 window y start
* @param csi csi 0 or csi 1
*/
void ipu_csi_set_window_pos(struct ipu_soc *ipu, uint32_t left, uint32_t top, uint32_t csi)
{
uint32_t temp;
_ipu_get(ipu);
mutex_lock(&ipu->mutex_lock);
temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
temp &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
temp |= ((top << CSI_VSC_SHIFT) | (left << CSI_HSC_SHIFT));
ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
mutex_unlock(&ipu->mutex_lock);
_ipu_put(ipu);
}
EXPORT_SYMBOL(ipu_csi_set_window_pos);
/*!
* _ipu_csi_horizontal_downsize_enable
* Enable horizontal downsizing(decimation) by 2.
*
* @param ipu ipu handler
* @param csi csi 0 or csi 1
*/
void _ipu_csi_horizontal_downsize_enable(struct ipu_soc *ipu, uint32_t csi)
{
uint32_t temp;
temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
temp |= CSI_HORI_DOWNSIZE_EN;
ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
}
/*!
* _ipu_csi_horizontal_downsize_disable
* Disable horizontal downsizing(decimation) by 2.
*
* @param ipu ipu handler
* @param csi csi 0 or csi 1
*/
void _ipu_csi_horizontal_downsize_disable(struct ipu_soc *ipu, uint32_t csi)
{
uint32_t temp;
temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
temp &= ~CSI_HORI_DOWNSIZE_EN;
ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
}
/*!
* _ipu_csi_vertical_downsize_enable
* Enable vertical downsizing(decimation) by 2.
*
* @param ipu ipu handler
* @param csi csi 0 or csi 1
*/
void _ipu_csi_vertical_downsize_enable(struct ipu_soc *ipu, uint32_t csi)
{
uint32_t temp;
temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
temp |= CSI_VERT_DOWNSIZE_EN;
ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
}
/*!
* _ipu_csi_vertical_downsize_disable
* Disable vertical downsizing(decimation) by 2.
*
* @param ipu ipu handler
* @param csi csi 0 or csi 1
*/
void _ipu_csi_vertical_downsize_disable(struct ipu_soc *ipu, uint32_t csi)
{
uint32_t temp;
temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
temp &= ~CSI_VERT_DOWNSIZE_EN;
ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
}
/*!
* _ipu_csi_set_test_generator
*
* @param ipu ipu handler
* @param active 1 for active and 0 for inactive
* @param r_value red value for the generated pattern of even pixel
* @param g_value green value for the generated pattern of even
* pixel
* @param b_value blue value for the generated pattern of even pixel
* @param pixel_clk desired pixel clock frequency in Hz
* @param csi csi 0 or csi 1
*/
void _ipu_csi_set_test_generator(struct ipu_soc *ipu, bool active, uint32_t r_value,
uint32_t g_value, uint32_t b_value, uint32_t pix_clk, uint32_t csi)
{
uint32_t temp;
temp = ipu_csi_read(ipu, csi, CSI_TST_CTRL);
if (active == false) {
temp &= ~CSI_TEST_GEN_MODE_EN;
ipu_csi_write(ipu, csi, temp, CSI_TST_CTRL);
} else {
/* Set sensb_mclk div_ratio*/
_ipu_csi_mclk_set(ipu, pix_clk, csi);
temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
CSI_TEST_GEN_B_MASK);
temp |= CSI_TEST_GEN_MODE_EN;
temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
(g_value << CSI_TEST_GEN_G_SHIFT) |
(b_value << CSI_TEST_GEN_B_SHIFT);
ipu_csi_write(ipu, csi, temp, CSI_TST_CTRL);
}
}
/*!
* _ipu_csi_ccir_err_detection_en
* Enable error detection and correction for
* CCIR interlaced mode with protection bit.
*
* @param ipu ipu handler
* @param csi csi 0 or csi 1
*/
void _ipu_csi_ccir_err_detection_enable(struct ipu_soc *ipu, uint32_t csi)
{
uint32_t temp;
temp = ipu_csi_read(ipu, csi, CSI_CCIR_CODE_1);
temp |= CSI_CCIR_ERR_DET_EN;
ipu_csi_write(ipu, csi, temp, CSI_CCIR_CODE_1);
}
/*!
* _ipu_csi_ccir_err_detection_disable
* Disable error detection and correction for
* CCIR interlaced mode with protection bit.
*
* @param ipu ipu handler
* @param csi csi 0 or csi 1
*/
void _ipu_csi_ccir_err_detection_disable(struct ipu_soc *ipu, uint32_t csi)
{
uint32_t temp;
temp = ipu_csi_read(ipu, csi, CSI_CCIR_CODE_1);
temp &= ~CSI_CCIR_ERR_DET_EN;
ipu_csi_write(ipu, csi, temp, CSI_CCIR_CODE_1);
}
/*!
* _ipu_csi_set_mipi_di
*
* @param ipu ipu handler
* @param num MIPI data identifier 0-3 handled by CSI
* @param di_val data identifier value
* @param csi csi 0 or csi 1
*
* @return Returns 0 on success or negative error code on fail
*/
int _ipu_csi_set_mipi_di(struct ipu_soc *ipu, uint32_t num, uint32_t di_val, uint32_t csi)
{
uint32_t temp;
int retval = 0;
if (di_val > 0xFFL) {
retval = -EINVAL;
goto err;
}
temp = ipu_csi_read(ipu, csi, CSI_MIPI_DI);
switch (num) {
case IPU_CSI_MIPI_DI0:
temp &= ~CSI_MIPI_DI0_MASK;
temp |= (di_val << CSI_MIPI_DI0_SHIFT);
ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
break;
case IPU_CSI_MIPI_DI1:
temp &= ~CSI_MIPI_DI1_MASK;
temp |= (di_val << CSI_MIPI_DI1_SHIFT);
ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
break;
case IPU_CSI_MIPI_DI2:
temp &= ~CSI_MIPI_DI2_MASK;
temp |= (di_val << CSI_MIPI_DI2_SHIFT);
ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
break;
case IPU_CSI_MIPI_DI3:
temp &= ~CSI_MIPI_DI3_MASK;
temp |= (di_val << CSI_MIPI_DI3_SHIFT);
ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
break;
default:
retval = -EINVAL;
}
err:
return retval;
}
/*!
* _ipu_csi_set_skip_isp
*
* @param ipu ipu handler
* @param skip select frames to be skipped and set the
* correspond bits to 1
* @param max_ratio number of frames in a skipping set and the
* maximum value of max_ratio is 5
* @param csi csi 0 or csi 1
*
* @return Returns 0 on success or negative error code on fail
*/
int _ipu_csi_set_skip_isp(struct ipu_soc *ipu, uint32_t skip, uint32_t max_ratio, uint32_t csi)
{
uint32_t temp;
int retval = 0;
if (max_ratio > 5) {
retval = -EINVAL;
goto err;
}
temp = ipu_csi_read(ipu, csi, CSI_SKIP);
temp &= ~(CSI_MAX_RATIO_SKIP_ISP_MASK | CSI_SKIP_ISP_MASK);
temp |= (max_ratio << CSI_MAX_RATIO_SKIP_ISP_SHIFT) |
(skip << CSI_SKIP_ISP_SHIFT);
ipu_csi_write(ipu, csi, temp, CSI_SKIP);
err:
return retval;
}
/*!
* _ipu_csi_set_skip_smfc
*
* @param ipu ipu handler
* @param skip select frames to be skipped and set the
* correspond bits to 1
* @param max_ratio number of frames in a skipping set and the
* maximum value of max_ratio is 5
* @param id csi to smfc skipping id
* @param csi csi 0 or csi 1
*
* @return Returns 0 on success or negative error code on fail
*/
int _ipu_csi_set_skip_smfc(struct ipu_soc *ipu, uint32_t skip,
uint32_t max_ratio, uint32_t id, uint32_t csi)
{
uint32_t temp;
int retval = 0;
if (max_ratio > 5 || id > 3) {
retval = -EINVAL;
goto err;
}
temp = ipu_csi_read(ipu, csi, CSI_SKIP);
temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
CSI_SKIP_SMFC_MASK);
temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
(id << CSI_ID_2_SKIP_SHIFT) |
(skip << CSI_SKIP_SMFC_SHIFT);
ipu_csi_write(ipu, csi, temp, CSI_SKIP);
err:
return retval;
}
/*!
* _ipu_smfc_init
* Map CSI frames to IDMAC channels.
*
* @param ipu ipu handler
* @param channel IDMAC channel 0-3
* @param mipi_id mipi id number 0-3
* @param csi csi0 or csi1
*/
void _ipu_smfc_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t mipi_id, uint32_t csi)
{
uint32_t temp;
temp = ipu_smfc_read(ipu, SMFC_MAP);
switch (channel) {
case CSI_MEM0:
temp &= ~SMFC_MAP_CH0_MASK;
temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH0_SHIFT;
break;
case CSI_MEM1:
temp &= ~SMFC_MAP_CH1_MASK;
temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH1_SHIFT;
break;
case CSI_MEM2:
temp &= ~SMFC_MAP_CH2_MASK;
temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH2_SHIFT;
break;
case CSI_MEM3:
temp &= ~SMFC_MAP_CH3_MASK;
temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH3_SHIFT;
break;
default:
return;
}
ipu_smfc_write(ipu, temp, SMFC_MAP);
}
/*!
* _ipu_smfc_set_wmc
* Caution: The number of required channels, the enabled channels
* and the FIFO size per channel are configured restrictedly.
*
* @param ipu ipu handler
* @param channel IDMAC channel 0-3
* @param set set 1 or clear 0
* @param level water mark level when FIFO is on the
* relative size
*/
void _ipu_smfc_set_wmc(struct ipu_soc *ipu, ipu_channel_t channel, bool set, uint32_t level)
{
uint32_t temp;
temp = ipu_smfc_read(ipu, SMFC_WMC);
switch (channel) {
case CSI_MEM0:
if (set == true) {
temp &= ~SMFC_WM0_SET_MASK;
temp |= level << SMFC_WM0_SET_SHIFT;
} else {
temp &= ~SMFC_WM0_CLR_MASK;
temp |= level << SMFC_WM0_CLR_SHIFT;
}
break;
case CSI_MEM1:
if (set == true) {
temp &= ~SMFC_WM1_SET_MASK;
temp |= level << SMFC_WM1_SET_SHIFT;
} else {
temp &= ~SMFC_WM1_CLR_MASK;
temp |= level << SMFC_WM1_CLR_SHIFT;
}
break;
case CSI_MEM2:
if (set == true) {
temp &= ~SMFC_WM2_SET_MASK;
temp |= level << SMFC_WM2_SET_SHIFT;
} else {
temp &= ~SMFC_WM2_CLR_MASK;
temp |= level << SMFC_WM2_CLR_SHIFT;
}
break;
case CSI_MEM3:
if (set == true) {
temp &= ~SMFC_WM3_SET_MASK;
temp |= level << SMFC_WM3_SET_SHIFT;
} else {
temp &= ~SMFC_WM3_CLR_MASK;
temp |= level << SMFC_WM3_CLR_SHIFT;
}
break;
default:
return;
}
ipu_smfc_write(ipu, temp, SMFC_WMC);
}
/*!
* _ipu_smfc_set_burst_size
*
* @param ipu ipu handler
* @param channel IDMAC channel 0-3
* @param bs burst size of IDMAC channel,
* the value programmed here shoud be BURST_SIZE-1
*/
void _ipu_smfc_set_burst_size(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t bs)
{
uint32_t temp;
temp = ipu_smfc_read(ipu, SMFC_BS);
switch (channel) {
case CSI_MEM0:
temp &= ~SMFC_BS0_MASK;
temp |= bs << SMFC_BS0_SHIFT;
break;
case CSI_MEM1:
temp &= ~SMFC_BS1_MASK;
temp |= bs << SMFC_BS1_SHIFT;
break;
case CSI_MEM2:
temp &= ~SMFC_BS2_MASK;
temp |= bs << SMFC_BS2_SHIFT;
break;
case CSI_MEM3:
temp &= ~SMFC_BS3_MASK;
temp |= bs << SMFC_BS3_SHIFT;
break;
default:
return;
}
ipu_smfc_write(ipu, temp, SMFC_BS);
}
/*!
* _ipu_csi_init
*
* @param ipu ipu handler
* @param channel IDMAC channel
* @param csi csi 0 or csi 1
*
* @return Returns 0 on success or negative error code on fail
*/
int _ipu_csi_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t csi)
{
uint32_t csi_sens_conf, csi_dest;
int retval = 0;
switch (channel) {
case CSI_MEM0:
case CSI_MEM1:
case CSI_MEM2:
case CSI_MEM3:
csi_dest = CSI_DATA_DEST_IDMAC;
break;
case CSI_PRP_ENC_MEM:
case CSI_PRP_VF_MEM:
csi_dest = CSI_DATA_DEST_IC;
break;
default:
retval = -EINVAL;
goto err;
}
csi_sens_conf = ipu_csi_read(ipu, csi, CSI_SENS_CONF);
csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
ipu_csi_write(ipu, csi, csi_sens_conf | (csi_dest <<
CSI_SENS_CONF_DATA_DEST_SHIFT), CSI_SENS_CONF);
err:
return retval;
}
/*!
* csi_irq_handler
*
* @param irq interrupt id
* @param dev_id pointer to ipu handler
*
* @return Returns if irq is handled
*/
static irqreturn_t csi_irq_handler(int irq, void *dev_id)
{
struct ipu_soc *ipu = dev_id;
struct completion *comp = &ipu->csi_comp;
complete(comp);
return IRQ_HANDLED;
}
/*!
* _ipu_csi_wait4eof
*
* @param ipu ipu handler
* @param channel IDMAC channel
*
*/
void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel)
{
int ret;
int irq = 0;
if (channel == CSI_MEM0)
irq = IPU_IRQ_CSI0_OUT_EOF;
else if (channel == CSI_MEM1)
irq = IPU_IRQ_CSI1_OUT_EOF;
else if (channel == CSI_MEM2)
irq = IPU_IRQ_CSI2_OUT_EOF;
else if (channel == CSI_MEM3)
irq = IPU_IRQ_CSI3_OUT_EOF;
else if (channel == CSI_PRP_ENC_MEM)
irq = IPU_IRQ_PRP_ENC_OUT_EOF;
else if (channel == CSI_PRP_VF_MEM)
irq = IPU_IRQ_PRP_VF_OUT_EOF;
else{
dev_err(ipu->dev, "Not a CSI channel\n");
return;
}
init_completion(&ipu->csi_comp);
ret = ipu_request_irq(ipu, irq, csi_irq_handler, 0, NULL, ipu);
if (ret < 0) {
dev_err(ipu->dev, "CSI irq %d in use\n", irq);
return;
}
ret = wait_for_completion_timeout(&ipu->csi_comp, msecs_to_jiffies(500));
ipu_free_irq(ipu, irq, ipu);
dev_dbg(ipu->dev, "CSI stop timeout - %d * 10ms\n", 5 - ret);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,924 @@
/*
* Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*
* @file ipu_ic.c
*
* @brief IPU IC functions
*
* @ingroup IPU
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ipu-v3.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include "ipu_param_mem.h"
#include "ipu_regs.h"
enum {
IC_TASK_VIEWFINDER,
IC_TASK_ENCODER,
IC_TASK_POST_PROCESSOR
};
static void _init_csc(struct ipu_soc *ipu, uint8_t ic_task, ipu_color_space_t in_format,
ipu_color_space_t out_format, int csc_index);
static int _calc_resize_coeffs(struct ipu_soc *ipu,
uint32_t inSize, uint32_t outSize,
uint32_t *resizeCoeff,
uint32_t *downsizeCoeff);
void _ipu_vdi_set_top_field_man(struct ipu_soc *ipu, bool top_field_0)
{
uint32_t reg;
reg = ipu_vdi_read(ipu, VDI_C);
if (top_field_0)
reg &= ~VDI_C_TOP_FIELD_MAN_1;
else
reg |= VDI_C_TOP_FIELD_MAN_1;
ipu_vdi_write(ipu, reg, VDI_C);
}
void _ipu_vdi_set_motion(struct ipu_soc *ipu, ipu_motion_sel motion_sel)
{
uint32_t reg;
reg = ipu_vdi_read(ipu, VDI_C);
reg &= ~(VDI_C_MOT_SEL_FULL | VDI_C_MOT_SEL_MED | VDI_C_MOT_SEL_LOW);
if (motion_sel == HIGH_MOTION)
reg |= VDI_C_MOT_SEL_FULL;
else if (motion_sel == MED_MOTION)
reg |= VDI_C_MOT_SEL_MED;
else
reg |= VDI_C_MOT_SEL_LOW;
ipu_vdi_write(ipu, reg, VDI_C);
dev_dbg(ipu->dev, "VDI_C = \t0x%08X\n", reg);
}
void ic_dump_register(struct ipu_soc *ipu)
{
printk(KERN_DEBUG "IC_CONF = \t0x%08X\n", ipu_ic_read(ipu, IC_CONF));
printk(KERN_DEBUG "IC_PRP_ENC_RSC = \t0x%08X\n",
ipu_ic_read(ipu, IC_PRP_ENC_RSC));
printk(KERN_DEBUG "IC_PRP_VF_RSC = \t0x%08X\n",
ipu_ic_read(ipu, IC_PRP_VF_RSC));
printk(KERN_DEBUG "IC_PP_RSC = \t0x%08X\n", ipu_ic_read(ipu, IC_PP_RSC));
printk(KERN_DEBUG "IC_IDMAC_1 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_1));
printk(KERN_DEBUG "IC_IDMAC_2 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_2));
printk(KERN_DEBUG "IC_IDMAC_3 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_3));
}
void _ipu_ic_enable_task(struct ipu_soc *ipu, ipu_channel_t channel)
{
uint32_t ic_conf;
ic_conf = ipu_ic_read(ipu, IC_CONF);
switch (channel) {
case CSI_PRP_VF_MEM:
case MEM_PRP_VF_MEM:
ic_conf |= IC_CONF_PRPVF_EN;
break;
case MEM_VDI_PRP_VF_MEM:
ic_conf |= IC_CONF_PRPVF_EN;
break;
case MEM_VDI_MEM:
ic_conf |= IC_CONF_PRPVF_EN | IC_CONF_RWS_EN ;
break;
case MEM_ROT_VF_MEM:
ic_conf |= IC_CONF_PRPVF_ROT_EN;
break;
case CSI_PRP_ENC_MEM:
case MEM_PRP_ENC_MEM:
ic_conf |= IC_CONF_PRPENC_EN;
break;
case MEM_ROT_ENC_MEM:
ic_conf |= IC_CONF_PRPENC_ROT_EN;
break;
case MEM_PP_MEM:
ic_conf |= IC_CONF_PP_EN;
break;
case MEM_ROT_PP_MEM:
ic_conf |= IC_CONF_PP_ROT_EN;
break;
default:
break;
}
ipu_ic_write(ipu, ic_conf, IC_CONF);
}
void _ipu_ic_disable_task(struct ipu_soc *ipu, ipu_channel_t channel)
{
uint32_t ic_conf;
ic_conf = ipu_ic_read(ipu, IC_CONF);
switch (channel) {
case CSI_PRP_VF_MEM:
case MEM_PRP_VF_MEM:
ic_conf &= ~IC_CONF_PRPVF_EN;
break;
case MEM_VDI_PRP_VF_MEM:
ic_conf &= ~IC_CONF_PRPVF_EN;
break;
case MEM_VDI_MEM:
ic_conf &= ~(IC_CONF_PRPVF_EN | IC_CONF_RWS_EN);
break;
case MEM_ROT_VF_MEM:
ic_conf &= ~IC_CONF_PRPVF_ROT_EN;
break;
case CSI_PRP_ENC_MEM:
case MEM_PRP_ENC_MEM:
ic_conf &= ~IC_CONF_PRPENC_EN;
break;
case MEM_ROT_ENC_MEM:
ic_conf &= ~IC_CONF_PRPENC_ROT_EN;
break;
case MEM_PP_MEM:
ic_conf &= ~IC_CONF_PP_EN;
break;
case MEM_ROT_PP_MEM:
ic_conf &= ~IC_CONF_PP_ROT_EN;
break;
default:
break;
}
ipu_ic_write(ipu, ic_conf, IC_CONF);
}
void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params)
{
uint32_t reg;
uint32_t pixel_fmt;
uint32_t pix_per_burst;
reg = ((params->mem_prp_vf_mem.in_height-1) << 16) |
(params->mem_prp_vf_mem.in_width-1);
ipu_vdi_write(ipu, reg, VDI_FSIZE);
/* Full motion, only vertical filter is used
Burst size is 4 accesses */
if (params->mem_prp_vf_mem.in_pixel_fmt ==
IPU_PIX_FMT_UYVY ||
params->mem_prp_vf_mem.in_pixel_fmt ==
IPU_PIX_FMT_YUYV) {
pixel_fmt = VDI_C_CH_422;
pix_per_burst = 32;
} else {
pixel_fmt = VDI_C_CH_420;
pix_per_burst = 64;
}
reg = ipu_vdi_read(ipu, VDI_C);
reg |= pixel_fmt;
switch (channel) {
case MEM_VDI_PRP_VF_MEM:
reg |= VDI_C_BURST_SIZE2_4;
break;
case MEM_VDI_PRP_VF_MEM_P:
reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_SET_1 | VDI_C_VWM1_CLR_2;
break;
case MEM_VDI_PRP_VF_MEM_N:
reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_SET_1 | VDI_C_VWM3_CLR_2;
break;
case MEM_VDI_MEM:
reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
<< VDI_C_BURST_SIZE2_OFFSET;
break;
case MEM_VDI_MEM_P:
reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
<< VDI_C_BURST_SIZE1_OFFSET;
reg |= VDI_C_VWM1_SET_2 | VDI_C_VWM1_CLR_2;
break;
case MEM_VDI_MEM_N:
reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
<< VDI_C_BURST_SIZE3_OFFSET;
reg |= VDI_C_VWM3_SET_2 | VDI_C_VWM3_CLR_2;
break;
default:
break;
}
ipu_vdi_write(ipu, reg, VDI_C);
if (params->mem_prp_vf_mem.field_fmt == IPU_DEINTERLACE_FIELD_TOP)
_ipu_vdi_set_top_field_man(ipu, true);
else if (params->mem_prp_vf_mem.field_fmt == IPU_DEINTERLACE_FIELD_BOTTOM)
_ipu_vdi_set_top_field_man(ipu, false);
_ipu_vdi_set_motion(ipu, params->mem_prp_vf_mem.motion_sel);
reg = ipu_ic_read(ipu, IC_CONF);
reg &= ~IC_CONF_RWS_EN;
ipu_ic_write(ipu, reg, IC_CONF);
}
void _ipu_vdi_uninit(struct ipu_soc *ipu)
{
ipu_vdi_write(ipu, 0, VDI_FSIZE);
ipu_vdi_write(ipu, 0, VDI_C);
}
int _ipu_ic_init_prpvf(struct ipu_soc *ipu, ipu_channel_params_t *params,
bool src_is_csi)
{
uint32_t reg, ic_conf;
uint32_t downsizeCoeff, resizeCoeff;
ipu_color_space_t in_fmt, out_fmt;
int ret = 0;
/* Setup vertical resizing */
if (!params->mem_prp_vf_mem.outv_resize_ratio) {
ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_height,
params->mem_prp_vf_mem.out_height,
&resizeCoeff, &downsizeCoeff);
if (ret < 0) {
dev_err(ipu->dev, "failed to calculate prpvf height "
"scaling coefficients\n");
return ret;
}
reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
} else
reg = (params->mem_prp_vf_mem.outv_resize_ratio) << 16;
/* Setup horizontal resizing */
if (!params->mem_prp_vf_mem.outh_resize_ratio) {
ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_width,
params->mem_prp_vf_mem.out_width,
&resizeCoeff, &downsizeCoeff);
if (ret < 0) {
dev_err(ipu->dev, "failed to calculate prpvf width "
"scaling coefficients\n");
return ret;
}
reg |= (downsizeCoeff << 14) | resizeCoeff;
} else
reg |= params->mem_prp_vf_mem.outh_resize_ratio;
ipu_ic_write(ipu, reg, IC_PRP_VF_RSC);
ic_conf = ipu_ic_read(ipu, IC_CONF);
/* Setup color space conversion */
in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_pixel_fmt);
out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
if (in_fmt == RGB) {
if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
/* Enable RGB->YCBCR CSC1 */
_init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 1);
ic_conf |= IC_CONF_PRPVF_CSC1;
}
}
if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
if (out_fmt == RGB) {
/* Enable YCBCR->RGB CSC1 */
_init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 1);
ic_conf |= IC_CONF_PRPVF_CSC1;
} else {
/* TODO: Support YUV<->YCbCr conversion? */
}
}
if (params->mem_prp_vf_mem.graphics_combine_en) {
ic_conf |= IC_CONF_PRPVF_CMB;
if (!(ic_conf & IC_CONF_PRPVF_CSC1)) {
/* need transparent CSC1 conversion */
_init_csc(ipu, IC_TASK_VIEWFINDER, RGB, RGB, 1);
ic_conf |= IC_CONF_PRPVF_CSC1; /* Enable RGB->RGB CSC */
}
in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_g_pixel_fmt);
out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
if (in_fmt == RGB) {
if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
/* Enable RGB->YCBCR CSC2 */
_init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 2);
ic_conf |= IC_CONF_PRPVF_CSC2;
}
}
if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
if (out_fmt == RGB) {
/* Enable YCBCR->RGB CSC2 */
_init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 2);
ic_conf |= IC_CONF_PRPVF_CSC2;
} else {
/* TODO: Support YUV<->YCbCr conversion? */
}
}
if (params->mem_prp_vf_mem.global_alpha_en) {
ic_conf |= IC_CONF_IC_GLB_LOC_A;
reg = ipu_ic_read(ipu, IC_CMBP_1);
reg &= ~(0xff);
reg |= params->mem_prp_vf_mem.alpha;
ipu_ic_write(ipu, reg, IC_CMBP_1);
} else
ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
if (params->mem_prp_vf_mem.key_color_en) {
ic_conf |= IC_CONF_KEY_COLOR_EN;
ipu_ic_write(ipu, params->mem_prp_vf_mem.key_color,
IC_CMBP_2);
} else
ic_conf &= ~IC_CONF_KEY_COLOR_EN;
} else {
ic_conf &= ~IC_CONF_PRPVF_CMB;
}
if (src_is_csi)
ic_conf &= ~IC_CONF_RWS_EN;
else
ic_conf |= IC_CONF_RWS_EN;
ipu_ic_write(ipu, ic_conf, IC_CONF);
return ret;
}
void _ipu_ic_uninit_prpvf(struct ipu_soc *ipu)
{
uint32_t reg;
reg = ipu_ic_read(ipu, IC_CONF);
reg &= ~(IC_CONF_PRPVF_EN | IC_CONF_PRPVF_CMB |
IC_CONF_PRPVF_CSC2 | IC_CONF_PRPVF_CSC1);
ipu_ic_write(ipu, reg, IC_CONF);
}
void _ipu_ic_init_rotate_vf(struct ipu_soc *ipu, ipu_channel_params_t *params)
{
}
void _ipu_ic_uninit_rotate_vf(struct ipu_soc *ipu)
{
uint32_t reg;
reg = ipu_ic_read(ipu, IC_CONF);
reg &= ~IC_CONF_PRPVF_ROT_EN;
ipu_ic_write(ipu, reg, IC_CONF);
}
int _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params,
bool src_is_csi)
{
uint32_t reg, ic_conf;
uint32_t downsizeCoeff, resizeCoeff;
ipu_color_space_t in_fmt, out_fmt;
int ret = 0;
/* Setup vertical resizing */
if (!params->mem_prp_enc_mem.outv_resize_ratio) {
ret = _calc_resize_coeffs(ipu,
params->mem_prp_enc_mem.in_height,
params->mem_prp_enc_mem.out_height,
&resizeCoeff, &downsizeCoeff);
if (ret < 0) {
dev_err(ipu->dev, "failed to calculate prpenc height "
"scaling coefficients\n");
return ret;
}
reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
} else
reg = (params->mem_prp_enc_mem.outv_resize_ratio) << 16;
/* Setup horizontal resizing */
if (!params->mem_prp_enc_mem.outh_resize_ratio) {
ret = _calc_resize_coeffs(ipu, params->mem_prp_enc_mem.in_width,
params->mem_prp_enc_mem.out_width,
&resizeCoeff, &downsizeCoeff);
if (ret < 0) {
dev_err(ipu->dev, "failed to calculate prpenc width "
"scaling coefficients\n");
return ret;
}
reg |= (downsizeCoeff << 14) | resizeCoeff;
} else
reg |= params->mem_prp_enc_mem.outh_resize_ratio;
ipu_ic_write(ipu, reg, IC_PRP_ENC_RSC);
ic_conf = ipu_ic_read(ipu, IC_CONF);
/* Setup color space conversion */
in_fmt = format_to_colorspace(params->mem_prp_enc_mem.in_pixel_fmt);
out_fmt = format_to_colorspace(params->mem_prp_enc_mem.out_pixel_fmt);
if (in_fmt == RGB) {
if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
/* Enable RGB->YCBCR CSC1 */
_init_csc(ipu, IC_TASK_ENCODER, RGB, out_fmt, 1);
ic_conf |= IC_CONF_PRPENC_CSC1;
}
}
if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
if (out_fmt == RGB) {
/* Enable YCBCR->RGB CSC1 */
_init_csc(ipu, IC_TASK_ENCODER, YCbCr, RGB, 1);
ic_conf |= IC_CONF_PRPENC_CSC1;
} else {
/* TODO: Support YUV<->YCbCr conversion? */
}
}
if (src_is_csi)
ic_conf &= ~IC_CONF_RWS_EN;
else
ic_conf |= IC_CONF_RWS_EN;
ipu_ic_write(ipu, ic_conf, IC_CONF);
return ret;
}
void _ipu_ic_uninit_prpenc(struct ipu_soc *ipu)
{
uint32_t reg;
reg = ipu_ic_read(ipu, IC_CONF);
reg &= ~(IC_CONF_PRPENC_EN | IC_CONF_PRPENC_CSC1);
ipu_ic_write(ipu, reg, IC_CONF);
}
void _ipu_ic_init_rotate_enc(struct ipu_soc *ipu, ipu_channel_params_t *params)
{
}
void _ipu_ic_uninit_rotate_enc(struct ipu_soc *ipu)
{
uint32_t reg;
reg = ipu_ic_read(ipu, IC_CONF);
reg &= ~(IC_CONF_PRPENC_ROT_EN);
ipu_ic_write(ipu, reg, IC_CONF);
}
int _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
{
uint32_t reg, ic_conf;
uint32_t downsizeCoeff, resizeCoeff;
ipu_color_space_t in_fmt, out_fmt;
int ret = 0;
/* Setup vertical resizing */
if (!params->mem_pp_mem.outv_resize_ratio) {
ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_height,
params->mem_pp_mem.out_height,
&resizeCoeff, &downsizeCoeff);
if (ret < 0) {
dev_err(ipu->dev, "failed to calculate pp height "
"scaling coefficients\n");
return ret;
}
reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
} else {
reg = (params->mem_pp_mem.outv_resize_ratio) << 16;
}
/* Setup horizontal resizing */
if (!params->mem_pp_mem.outh_resize_ratio) {
ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_width,
params->mem_pp_mem.out_width,
&resizeCoeff, &downsizeCoeff);
if (ret < 0) {
dev_err(ipu->dev, "failed to calculate pp width "
"scaling coefficients\n");
return ret;
}
reg |= (downsizeCoeff << 14) | resizeCoeff;
} else {
reg |= params->mem_pp_mem.outh_resize_ratio;
}
ipu_ic_write(ipu, reg, IC_PP_RSC);
ic_conf = ipu_ic_read(ipu, IC_CONF);
/* Setup color space conversion */
in_fmt = format_to_colorspace(params->mem_pp_mem.in_pixel_fmt);
out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
if (in_fmt == RGB) {
if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
/* Enable RGB->YCBCR CSC1 */
_init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 1);
ic_conf |= IC_CONF_PP_CSC1;
}
}
if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
if (out_fmt == RGB) {
/* Enable YCBCR->RGB CSC1 */
_init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 1);
ic_conf |= IC_CONF_PP_CSC1;
} else {
/* TODO: Support YUV<->YCbCr conversion? */
}
}
if (params->mem_pp_mem.graphics_combine_en) {
ic_conf |= IC_CONF_PP_CMB;
if (!(ic_conf & IC_CONF_PP_CSC1)) {
/* need transparent CSC1 conversion */
_init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, RGB, 1);
ic_conf |= IC_CONF_PP_CSC1; /* Enable RGB->RGB CSC */
}
in_fmt = format_to_colorspace(params->mem_pp_mem.in_g_pixel_fmt);
out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
if (in_fmt == RGB) {
if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
/* Enable RGB->YCBCR CSC2 */
_init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 2);
ic_conf |= IC_CONF_PP_CSC2;
}
}
if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
if (out_fmt == RGB) {
/* Enable YCBCR->RGB CSC2 */
_init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 2);
ic_conf |= IC_CONF_PP_CSC2;
} else {
/* TODO: Support YUV<->YCbCr conversion? */
}
}
if (params->mem_pp_mem.global_alpha_en) {
ic_conf |= IC_CONF_IC_GLB_LOC_A;
reg = ipu_ic_read(ipu, IC_CMBP_1);
reg &= ~(0xff00);
reg |= (params->mem_pp_mem.alpha << 8);
ipu_ic_write(ipu, reg, IC_CMBP_1);
} else
ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
if (params->mem_pp_mem.key_color_en) {
ic_conf |= IC_CONF_KEY_COLOR_EN;
ipu_ic_write(ipu, params->mem_pp_mem.key_color,
IC_CMBP_2);
} else
ic_conf &= ~IC_CONF_KEY_COLOR_EN;
} else {
ic_conf &= ~IC_CONF_PP_CMB;
}
ipu_ic_write(ipu, ic_conf, IC_CONF);
return ret;
}
void _ipu_ic_uninit_pp(struct ipu_soc *ipu)
{
uint32_t reg;
reg = ipu_ic_read(ipu, IC_CONF);
reg &= ~(IC_CONF_PP_EN | IC_CONF_PP_CSC1 | IC_CONF_PP_CSC2 |
IC_CONF_PP_CMB);
ipu_ic_write(ipu, reg, IC_CONF);
}
void _ipu_ic_init_rotate_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
{
}
void _ipu_ic_uninit_rotate_pp(struct ipu_soc *ipu)
{
uint32_t reg;
reg = ipu_ic_read(ipu, IC_CONF);
reg &= ~IC_CONF_PP_ROT_EN;
ipu_ic_write(ipu, reg, IC_CONF);
}
int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan,
uint16_t width, uint16_t height,
int burst_size, ipu_rotate_mode_t rot)
{
u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
u32 temp_rot = bitrev8(rot) >> 5;
bool need_hor_flip = false;
if ((burst_size != 8) && (burst_size != 16)) {
dev_dbg(ipu->dev, "Illegal burst length for IC\n");
return -EINVAL;
}
width--;
height--;
if (temp_rot & 0x2) /* Need horizontal flip */
need_hor_flip = true;
ic_idmac_1 = ipu_ic_read(ipu, IC_IDMAC_1);
ic_idmac_2 = ipu_ic_read(ipu, IC_IDMAC_2);
ic_idmac_3 = ipu_ic_read(ipu, IC_IDMAC_3);
if (dma_chan == 22) { /* PP output - CB2 */
if (burst_size == 16)
ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
else
ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
if (need_hor_flip)
ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
else
ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
} else if (dma_chan == 11) { /* PP Input - CB5 */
if (burst_size == 16)
ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
else
ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
} else if (dma_chan == 47) { /* PP Rot input */
ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
}
if (dma_chan == 12) { /* PRP Input - CB6 */
if (burst_size == 16)
ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
else
ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
}
if (dma_chan == 20) { /* PRP ENC output - CB0 */
if (burst_size == 16)
ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
else
ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
if (need_hor_flip)
ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
else
ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
} else if (dma_chan == 45) { /* PRP ENC Rot input */
ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
}
if (dma_chan == 21) { /* PRP VF output - CB1 */
if (burst_size == 16)
ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
else
ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
if (need_hor_flip)
ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
else
ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
} else if (dma_chan == 46) { /* PRP VF Rot input */
ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
}
if (dma_chan == 14) { /* PRP VF graphics combining input - CB3 */
if (burst_size == 16)
ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
else
ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
} else if (dma_chan == 15) { /* PP graphics combining input - CB4 */
if (burst_size == 16)
ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
else
ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
} else if (dma_chan == 5) { /* VDIC OUTPUT - CB7 */
if (burst_size == 16)
ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
else
ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
}
ipu_ic_write(ipu, ic_idmac_1, IC_IDMAC_1);
ipu_ic_write(ipu, ic_idmac_2, IC_IDMAC_2);
ipu_ic_write(ipu, ic_idmac_3, IC_IDMAC_3);
return 0;
}
static void _init_csc(struct ipu_soc *ipu, uint8_t ic_task, ipu_color_space_t in_format,
ipu_color_space_t out_format, int csc_index)
{
/*
* Y = 0.257 * R + 0.504 * G + 0.098 * B + 16;
* U = -0.148 * R - 0.291 * G + 0.439 * B + 128;
* V = 0.439 * R - 0.368 * G - 0.071 * B + 128;
*/
static const uint32_t rgb2ycbcr_coeff[4][3] = {
{0x0042, 0x0081, 0x0019},
{0x01DA, 0x01B6, 0x0070},
{0x0070, 0x01A2, 0x01EE},
{0x0040, 0x0200, 0x0200}, /* A0, A1, A2 */
};
/* transparent RGB->RGB matrix for combining
*/
static const uint32_t rgb2rgb_coeff[4][3] = {
{0x0080, 0x0000, 0x0000},
{0x0000, 0x0080, 0x0000},
{0x0000, 0x0000, 0x0080},
{0x0000, 0x0000, 0x0000}, /* A0, A1, A2 */
};
/* R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); */
static const uint32_t ycbcr2rgb_coeff[4][3] = {
{149, 0, 204},
{149, 462, 408},
{149, 255, 0},
{8192 - 446, 266, 8192 - 554}, /* A0, A1, A2 */
};
uint32_t param;
uint32_t *base = NULL;
if (ic_task == IC_TASK_ENCODER) {
base = (uint32_t *)ipu->tpmem_base + 0x2008 / 4;
} else if (ic_task == IC_TASK_VIEWFINDER) {
if (csc_index == 1)
base = (uint32_t *)ipu->tpmem_base + 0x4028 / 4;
else
base = (uint32_t *)ipu->tpmem_base + 0x4040 / 4;
} else if (ic_task == IC_TASK_POST_PROCESSOR) {
if (csc_index == 1)
base = (uint32_t *)ipu->tpmem_base + 0x6060 / 4;
else
base = (uint32_t *)ipu->tpmem_base + 0x6078 / 4;
} else {
BUG();
}
if ((in_format == YCbCr) && (out_format == RGB)) {
/* Init CSC (YCbCr->RGB) */
param = (ycbcr2rgb_coeff[3][0] << 27) |
(ycbcr2rgb_coeff[0][0] << 18) |
(ycbcr2rgb_coeff[1][1] << 9) | ycbcr2rgb_coeff[2][2];
writel(param, base++);
/* scale = 2, sat = 0 */
param = (ycbcr2rgb_coeff[3][0] >> 5) | (2L << (40 - 32));
writel(param, base++);
param = (ycbcr2rgb_coeff[3][1] << 27) |
(ycbcr2rgb_coeff[0][1] << 18) |
(ycbcr2rgb_coeff[1][0] << 9) | ycbcr2rgb_coeff[2][0];
writel(param, base++);
param = (ycbcr2rgb_coeff[3][1] >> 5);
writel(param, base++);
param = (ycbcr2rgb_coeff[3][2] << 27) |
(ycbcr2rgb_coeff[0][2] << 18) |
(ycbcr2rgb_coeff[1][2] << 9) | ycbcr2rgb_coeff[2][1];
writel(param, base++);
param = (ycbcr2rgb_coeff[3][2] >> 5);
writel(param, base++);
} else if ((in_format == RGB) && (out_format == YCbCr)) {
/* Init CSC (RGB->YCbCr) */
param = (rgb2ycbcr_coeff[3][0] << 27) |
(rgb2ycbcr_coeff[0][0] << 18) |
(rgb2ycbcr_coeff[1][1] << 9) | rgb2ycbcr_coeff[2][2];
writel(param, base++);
/* scale = 1, sat = 0 */
param = (rgb2ycbcr_coeff[3][0] >> 5) | (1UL << 8);
writel(param, base++);
param = (rgb2ycbcr_coeff[3][1] << 27) |
(rgb2ycbcr_coeff[0][1] << 18) |
(rgb2ycbcr_coeff[1][0] << 9) | rgb2ycbcr_coeff[2][0];
writel(param, base++);
param = (rgb2ycbcr_coeff[3][1] >> 5);
writel(param, base++);
param = (rgb2ycbcr_coeff[3][2] << 27) |
(rgb2ycbcr_coeff[0][2] << 18) |
(rgb2ycbcr_coeff[1][2] << 9) | rgb2ycbcr_coeff[2][1];
writel(param, base++);
param = (rgb2ycbcr_coeff[3][2] >> 5);
writel(param, base++);
} else if ((in_format == RGB) && (out_format == RGB)) {
/* Init CSC */
param =
(rgb2rgb_coeff[3][0] << 27) | (rgb2rgb_coeff[0][0] << 18) |
(rgb2rgb_coeff[1][1] << 9) | rgb2rgb_coeff[2][2];
writel(param, base++);
/* scale = 2, sat = 0 */
param = (rgb2rgb_coeff[3][0] >> 5) | (2UL << 8);
writel(param, base++);
param =
(rgb2rgb_coeff[3][1] << 27) | (rgb2rgb_coeff[0][1] << 18) |
(rgb2rgb_coeff[1][0] << 9) | rgb2rgb_coeff[2][0];
writel(param, base++);
param = (rgb2rgb_coeff[3][1] >> 5);
writel(param, base++);
param =
(rgb2rgb_coeff[3][2] << 27) | (rgb2rgb_coeff[0][2] << 18) |
(rgb2rgb_coeff[1][2] << 9) | rgb2rgb_coeff[2][1];
writel(param, base++);
param = (rgb2rgb_coeff[3][2] >> 5);
writel(param, base++);
} else {
dev_err(ipu->dev, "Unsupported color space conversion\n");
}
}
static int _calc_resize_coeffs(struct ipu_soc *ipu,
uint32_t inSize, uint32_t outSize,
uint32_t *resizeCoeff,
uint32_t *downsizeCoeff)
{
uint32_t tempSize;
uint32_t tempDownsize;
if (inSize > 4096) {
dev_err(ipu->dev, "IC input size(%d) cannot exceed 4096\n",
inSize);
return -EINVAL;
}
if (outSize > 1024) {
dev_err(ipu->dev, "IC output size(%d) cannot exceed 1024\n",
outSize);
return -EINVAL;
}
if ((outSize << 3) < inSize) {
dev_err(ipu->dev, "IC cannot downsize more than 8:1\n");
return -EINVAL;
}
/* Compute downsizing coefficient */
/* Output of downsizing unit cannot be more than 1024 */
tempDownsize = 0;
tempSize = inSize;
while (((tempSize > 1024) || (tempSize >= outSize * 2)) &&
(tempDownsize < 2)) {
tempSize >>= 1;
tempDownsize++;
}
*downsizeCoeff = tempDownsize;
/* compute resizing coefficient using the following equation:
resizeCoeff = M*(SI -1)/(SO - 1)
where M = 2^13, SI - input size, SO - output size */
*resizeCoeff = (8192L * (tempSize - 1)) / (outSize - 1);
if (*resizeCoeff >= 16384L) {
dev_err(ipu->dev, "Overflow on IC resize coefficient.\n");
return -EINVAL;
}
dev_dbg(ipu->dev, "resizing from %u -> %u pixels, "
"downsize=%u, resize=%u.%lu (reg=%u)\n", inSize, outSize,
*downsizeCoeff, (*resizeCoeff >= 8192L) ? 1 : 0,
((*resizeCoeff & 0x1FFF) * 10000L) / 8192L, *resizeCoeff);
return 0;
}
void _ipu_vdi_toggle_top_field_man(struct ipu_soc *ipu)
{
uint32_t reg;
uint32_t mask_reg;
reg = ipu_vdi_read(ipu, VDI_C);
mask_reg = reg & VDI_C_TOP_FIELD_MAN_1;
if (mask_reg == VDI_C_TOP_FIELD_MAN_1)
reg &= ~VDI_C_TOP_FIELD_MAN_1;
else
reg |= VDI_C_TOP_FIELD_MAN_1;
ipu_vdi_write(ipu, reg, VDI_C);
}

View File

@ -0,0 +1,998 @@
/*
* Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef __INCLUDE_IPU_PARAM_MEM_H__
#define __INCLUDE_IPU_PARAM_MEM_H__
#include <linux/bitrev.h>
#include <linux/types.h>
#include "ipu_prv.h"
extern u32 *ipu_cpmem_base;
struct ipu_ch_param_word {
uint32_t data[5];
uint32_t res[3];
};
struct ipu_ch_param {
struct ipu_ch_param_word word[2];
};
#define ipu_ch_param_addr(ipu, ch) \
(((struct ipu_ch_param *)(ipu)->cpmem_base) + (ch))
#define _param_word(base, w) \
(((struct ipu_ch_param *)(base))->word[(w)].data)
#define ipu_ch_param_set_field(base, w, bit, size, v) { \
int i = (bit) / 32; \
int off = (bit) % 32; \
_param_word((base), (w))[i] |= (v) << off; \
if (((bit)+(size)-1)/32 > i) { \
_param_word((base), (w))[i + 1] |= \
(v) >> (off ? (32 - off) : 0); \
} \
}
#define ipu_ch_param_set_field_io(base, w, bit, size, v) { \
int i = (bit) / 32; \
int off = (bit) % 32; \
unsigned reg_offset; \
u32 temp; \
reg_offset = sizeof(struct ipu_ch_param_word) * (w) / 4; \
reg_offset += i; \
temp = readl((u32 *)(base) + reg_offset); \
temp |= (v) << off; \
writel(temp, (u32 *)(base) + reg_offset); \
if (((bit)+(size)-1)/32 > i) { \
reg_offset++; \
temp = readl((u32 *)(base) + reg_offset); \
temp |= (v) >> (off ? (32 - off) : 0); \
writel(temp, (u32 *)(base) + reg_offset); \
} \
}
#define ipu_ch_param_mod_field(base, w, bit, size, v) { \
int i = (bit) / 32; \
int off = (bit) % 32; \
u32 mask = (1UL << (size)) - 1; \
u32 temp = _param_word((base), (w))[i]; \
temp &= ~(mask << off); \
_param_word((base), (w))[i] = temp | (v) << off; \
if (((bit)+(size)-1)/32 > i) { \
temp = _param_word((base), (w))[i + 1]; \
temp &= ~(mask >> (32 - off)); \
_param_word((base), (w))[i + 1] = \
temp | ((v) >> (off ? (32 - off) : 0)); \
} \
}
#define ipu_ch_param_mod_field_io(base, w, bit, size, v) { \
int i = (bit) / 32; \
int off = (bit) % 32; \
u32 mask = (1UL << (size)) - 1; \
unsigned reg_offset; \
u32 temp; \
reg_offset = sizeof(struct ipu_ch_param_word) * (w) / 4; \
reg_offset += i; \
temp = readl((u32 *)(base) + reg_offset); \
temp &= ~(mask << off); \
temp |= (v) << off; \
writel(temp, (u32 *)(base) + reg_offset); \
if (((bit)+(size)-1)/32 > i) { \
reg_offset++; \
temp = readl((u32 *)(base) + reg_offset); \
temp &= ~(mask >> (32 - off)); \
temp |= ((v) >> (off ? (32 - off) : 0)); \
writel(temp, (u32 *)(base) + reg_offset); \
} \
}
#define ipu_ch_param_read_field(base, w, bit, size) ({ \
u32 temp2; \
int i = (bit) / 32; \
int off = (bit) % 32; \
u32 mask = (1UL << (size)) - 1; \
u32 temp1 = _param_word((base), (w))[i]; \
temp1 = mask & (temp1 >> off); \
if (((bit)+(size)-1)/32 > i) { \
temp2 = _param_word((base), (w))[i + 1]; \
temp2 &= mask >> (off ? (32 - off) : 0); \
temp1 |= temp2 << (off ? (32 - off) : 0); \
} \
temp1; \
})
#define ipu_ch_param_read_field_io(base, w, bit, size) ({ \
u32 temp1, temp2; \
int i = (bit) / 32; \
int off = (bit) % 32; \
u32 mask = (1UL << (size)) - 1; \
unsigned reg_offset; \
reg_offset = sizeof(struct ipu_ch_param_word) * (w) / 4; \
reg_offset += i; \
temp1 = readl((u32 *)(base) + reg_offset); \
temp1 = mask & (temp1 >> off); \
if (((bit)+(size)-1)/32 > i) { \
reg_offset++; \
temp2 = readl((u32 *)(base) + reg_offset); \
temp2 &= mask >> (off ? (32 - off) : 0); \
temp1 |= temp2 << (off ? (32 - off) : 0); \
} \
temp1; \
})
static inline int __ipu_ch_get_third_buf_cpmem_num(int ch)
{
switch (ch) {
case 8:
return 64;
case 9:
return 65;
case 10:
return 66;
case 13:
return 67;
case 21:
return 68;
case 23:
return 69;
case 27:
return 70;
case 28:
return 71;
default:
return -EINVAL;
}
return 0;
}
static inline void _ipu_ch_params_set_packing(struct ipu_ch_param *p,
int red_width, int red_offset,
int green_width, int green_offset,
int blue_width, int blue_offset,
int alpha_width, int alpha_offset)
{
/* Setup red width and offset */
ipu_ch_param_set_field(p, 1, 116, 3, red_width - 1);
ipu_ch_param_set_field(p, 1, 128, 5, red_offset);
/* Setup green width and offset */
ipu_ch_param_set_field(p, 1, 119, 3, green_width - 1);
ipu_ch_param_set_field(p, 1, 133, 5, green_offset);
/* Setup blue width and offset */
ipu_ch_param_set_field(p, 1, 122, 3, blue_width - 1);
ipu_ch_param_set_field(p, 1, 138, 5, blue_offset);
/* Setup alpha width and offset */
ipu_ch_param_set_field(p, 1, 125, 3, alpha_width - 1);
ipu_ch_param_set_field(p, 1, 143, 5, alpha_offset);
}
static inline void _ipu_ch_param_dump(struct ipu_soc *ipu, int ch)
{
struct ipu_ch_param *p = ipu_ch_param_addr(ipu, ch);
dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", ch,
p->word[0].data[0], p->word[0].data[1], p->word[0].data[2],
p->word[0].data[3], p->word[0].data[4]);
dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", ch,
p->word[1].data[0], p->word[1].data[1], p->word[1].data[2],
p->word[1].data[3], p->word[1].data[4]);
dev_dbg(ipu->dev, "PFS 0x%x, ",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 85, 4));
dev_dbg(ipu->dev, "BPP 0x%x, ",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 107, 3));
dev_dbg(ipu->dev, "NPB 0x%x\n",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7));
dev_dbg(ipu->dev, "FW %d, ",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 125, 13));
dev_dbg(ipu->dev, "FH %d, ",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 138, 12));
dev_dbg(ipu->dev, "EBA0 0x%x\n",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 0, 29) << 3);
dev_dbg(ipu->dev, "EBA1 0x%x\n",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 29, 29) << 3);
dev_dbg(ipu->dev, "Stride %d\n",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14));
dev_dbg(ipu->dev, "scan_order %d\n",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1));
dev_dbg(ipu->dev, "uv_stride %d\n",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 128, 14));
dev_dbg(ipu->dev, "u_offset 0x%x\n",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22) << 3);
dev_dbg(ipu->dev, "v_offset 0x%x\n",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22) << 3);
dev_dbg(ipu->dev, "Width0 %d+1, ",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 116, 3));
dev_dbg(ipu->dev, "Width1 %d+1, ",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 119, 3));
dev_dbg(ipu->dev, "Width2 %d+1, ",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 122, 3));
dev_dbg(ipu->dev, "Width3 %d+1, ",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 125, 3));
dev_dbg(ipu->dev, "Offset0 %d, ",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 128, 5));
dev_dbg(ipu->dev, "Offset1 %d, ",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 133, 5));
dev_dbg(ipu->dev, "Offset2 %d, ",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 138, 5));
dev_dbg(ipu->dev, "Offset3 %d\n",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 143, 5));
}
static inline void fill_cpmem(struct ipu_soc *ipu, int ch, struct ipu_ch_param *params)
{
int i, w;
void *addr = ipu_ch_param_addr(ipu, ch);
/* 2 words, 5 valid data */
for (w = 0; w < 2; w++) {
for (i = 0; i < 5; i++) {
writel(params->word[w].data[i], addr);
addr += 4;
}
addr += 12;
}
}
static inline void _ipu_ch_param_init(struct ipu_soc *ipu, int ch,
uint32_t pixel_fmt, uint32_t width,
uint32_t height, uint32_t stride,
uint32_t u, uint32_t v,
uint32_t uv_stride, dma_addr_t addr0,
dma_addr_t addr1, dma_addr_t addr2)
{
uint32_t u_offset = 0;
uint32_t v_offset = 0;
uint32_t bs = 0;
int32_t sub_ch = 0;
struct ipu_ch_param params;
memset(&params, 0, sizeof(params));
ipu_ch_param_set_field(&params, 0, 125, 13, width - 1);
if (((ch == 8) || (ch == 9) || (ch == 10)) && !ipu->vdoa_en) {
ipu_ch_param_set_field(&params, 0, 138, 12, (height / 2) - 1);
ipu_ch_param_set_field(&params, 1, 102, 14, (stride * 2) - 1);
} else {
/* note: for vdoa+vdi- ch8/9/10, always use band mode */
ipu_ch_param_set_field(&params, 0, 138, 12, height - 1);
ipu_ch_param_set_field(&params, 1, 102, 14, stride - 1);
}
/* EBA is 8-byte aligned */
ipu_ch_param_set_field(&params, 1, 0, 29, addr0 >> 3);
ipu_ch_param_set_field(&params, 1, 29, 29, addr1 >> 3);
if (addr0%8)
dev_warn(ipu->dev,
"IDMAC%d's EBA0 is not 8-byte aligned\n", ch);
if (addr1%8)
dev_warn(ipu->dev,
"IDMAC%d's EBA1 is not 8-byte aligned\n", ch);
switch (pixel_fmt) {
case IPU_PIX_FMT_GENERIC:
/*Represents 8-bit Generic data */
ipu_ch_param_set_field(&params, 0, 107, 3, 5); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 6); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 63); /* burst size */
break;
case IPU_PIX_FMT_GENERIC_16:
/* Represents 16-bit generic data */
ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 6); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
break;
case IPU_PIX_FMT_GENERIC_32:
/*Represents 32-bit Generic data */
break;
case IPU_PIX_FMT_RGB565:
ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
_ipu_ch_params_set_packing(&params, 5, 0, 6, 5, 5, 11, 8, 16);
break;
case IPU_PIX_FMT_BGRA4444:
ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
_ipu_ch_params_set_packing(&params, 4, 4, 4, 8, 4, 12, 4, 0);
break;
case IPU_PIX_FMT_BGRA5551:
ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
_ipu_ch_params_set_packing(&params, 5, 1, 5, 6, 5, 11, 1, 0);
break;
case IPU_PIX_FMT_BGR24:
ipu_ch_param_set_field(&params, 0, 107, 3, 1); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 19); /* burst size */
_ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
break;
case IPU_PIX_FMT_RGB24:
case IPU_PIX_FMT_YUV444:
ipu_ch_param_set_field(&params, 0, 107, 3, 1); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 19); /* burst size */
_ipu_ch_params_set_packing(&params, 8, 16, 8, 8, 8, 0, 8, 24);
break;
case IPU_PIX_FMT_VYU444:
ipu_ch_param_set_field(&params, 0, 107, 3, 1); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 19); /* burst size */
_ipu_ch_params_set_packing(&params, 8, 8, 8, 0, 8, 16, 8, 24);
break;
case IPU_PIX_FMT_AYUV:
ipu_ch_param_set_field(&params, 0, 107, 3, 0); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
_ipu_ch_params_set_packing(&params, 8, 8, 8, 16, 8, 24, 8, 0);
break;
case IPU_PIX_FMT_BGRA32:
case IPU_PIX_FMT_BGR32:
ipu_ch_param_set_field(&params, 0, 107, 3, 0); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
_ipu_ch_params_set_packing(&params, 8, 8, 8, 16, 8, 24, 8, 0);
break;
case IPU_PIX_FMT_RGBA32:
case IPU_PIX_FMT_RGB32:
ipu_ch_param_set_field(&params, 0, 107, 3, 0); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
_ipu_ch_params_set_packing(&params, 8, 24, 8, 16, 8, 8, 8, 0);
break;
case IPU_PIX_FMT_ABGR32:
ipu_ch_param_set_field(&params, 0, 107, 3, 0); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
_ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
break;
case IPU_PIX_FMT_UYVY:
ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 0xA); /* pix format */
if ((ch == 8) || (ch == 9) || (ch == 10)) {
ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
} else {
ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
}
break;
case IPU_PIX_FMT_YUYV:
ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 0x8); /* pix format */
if ((ch == 8) || (ch == 9) || (ch == 10)) {
if (ipu->vdoa_en) {
ipu_ch_param_set_field(&params, 1, 78, 7, 31);
} else {
ipu_ch_param_set_field(&params, 1, 78, 7, 15);
}
} else {
ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
}
break;
case IPU_PIX_FMT_YUV420P2:
case IPU_PIX_FMT_YUV420P:
ipu_ch_param_set_field(&params, 1, 85, 4, 2); /* pix format */
if (uv_stride < stride / 2)
uv_stride = stride / 2;
u_offset = stride * height;
v_offset = u_offset + (uv_stride * height / 2);
if ((ch == 8) || (ch == 9) || (ch == 10)) {
ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
uv_stride = uv_stride*2;
} else {
if (_ipu_is_smfc_chan(ch) &&
ipu->smfc_idmac_12bit_3planar_bs_fixup)
bs = 15;
else
bs = 31;
ipu_ch_param_set_field(&params, 1, 78, 7, bs); /* burst size */
}
break;
case IPU_PIX_FMT_YVU420P:
ipu_ch_param_set_field(&params, 1, 85, 4, 2); /* pix format */
if (uv_stride < stride / 2)
uv_stride = stride / 2;
v_offset = stride * height;
u_offset = v_offset + (uv_stride * height / 2);
if ((ch == 8) || (ch == 9) || (ch == 10)) {
ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
uv_stride = uv_stride*2;
} else {
if (_ipu_is_smfc_chan(ch) &&
ipu->smfc_idmac_12bit_3planar_bs_fixup)
bs = 15;
else
bs = 31;
ipu_ch_param_set_field(&params, 1, 78, 7, bs); /* burst size */
}
break;
case IPU_PIX_FMT_YVU422P:
/* BPP & pixel format */
ipu_ch_param_set_field(&params, 1, 85, 4, 1); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
if (uv_stride < stride / 2)
uv_stride = stride / 2;
v_offset = (v == 0) ? stride * height : v;
u_offset = (u == 0) ? v_offset + v_offset / 2 : u;
break;
case IPU_PIX_FMT_YUV422P:
/* BPP & pixel format */
ipu_ch_param_set_field(&params, 1, 85, 4, 1); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
if (uv_stride < stride / 2)
uv_stride = stride / 2;
u_offset = (u == 0) ? stride * height : u;
v_offset = (v == 0) ? u_offset + u_offset / 2 : v;
break;
case IPU_PIX_FMT_YUV444P:
/* BPP & pixel format */
ipu_ch_param_set_field(&params, 1, 85, 4, 0); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
uv_stride = stride;
u_offset = (u == 0) ? stride * height : u;
v_offset = (v == 0) ? u_offset * 2 : v;
break;
case IPU_PIX_FMT_NV16:
ipu_ch_param_set_field(&params, 1, 85, 4, 1); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
uv_stride = stride;
u_offset = (u == 0) ? stride * height : u;
break;
case IPU_PIX_FMT_NV12:
/* BPP & pixel format */
ipu_ch_param_set_field(&params, 1, 85, 4, 4); /* pix format */
uv_stride = stride;
u_offset = (u == 0) ? stride * height : u;
if ((ch == 8) || (ch == 9) || (ch == 10)) {
if (ipu->vdoa_en) {
/* one field buffer, memory width 64bits */
ipu_ch_param_set_field(&params, 1, 78, 7, 63);
} else {
ipu_ch_param_set_field(&params, 1, 78, 7, 15);
/* top/bottom field in one buffer*/
uv_stride = uv_stride*2;
}
} else {
ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
}
break;
default:
dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n");
break;
}
/*set burst size to 16*/
if (uv_stride)
ipu_ch_param_set_field(&params, 1, 128, 14, uv_stride - 1);
/* Get the uv offset from user when need cropping */
if (u || v) {
u_offset = u;
v_offset = v;
}
/* UBO and VBO are 22-bit and 8-byte aligned */
if (u_offset/8 > 0x3fffff)
dev_warn(ipu->dev,
"IDMAC%d's U offset exceeds IPU limitation\n", ch);
if (v_offset/8 > 0x3fffff)
dev_warn(ipu->dev,
"IDMAC%d's V offset exceeds IPU limitation\n", ch);
if (u_offset%8)
dev_warn(ipu->dev,
"IDMAC%d's U offset is not 8-byte aligned\n", ch);
if (v_offset%8)
dev_warn(ipu->dev,
"IDMAC%d's V offset is not 8-byte aligned\n", ch);
ipu_ch_param_set_field(&params, 0, 46, 22, u_offset / 8);
ipu_ch_param_set_field(&params, 0, 68, 22, v_offset / 8);
dev_dbg(ipu->dev, "initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ipu, ch));
fill_cpmem(ipu, ch, &params);
if (addr2) {
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
if (sub_ch <= 0)
return;
ipu_ch_param_set_field(&params, 1, 0, 29, addr2 >> 3);
ipu_ch_param_set_field(&params, 1, 29, 29, 0);
if (addr2%8)
dev_warn(ipu->dev,
"IDMAC%d's sub-CPMEM entry%d EBA0 is not "
"8-byte aligned\n", ch, sub_ch);
dev_dbg(ipu->dev, "initializing idma ch %d @ %p sub cpmem\n", ch,
ipu_ch_param_addr(ipu, sub_ch));
fill_cpmem(ipu, sub_ch, &params);
}
};
static inline void _ipu_ch_param_set_burst_size(struct ipu_soc *ipu,
uint32_t ch,
uint16_t burst_pixels)
{
int32_t sub_ch = 0;
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7,
burst_pixels - 1);
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
if (sub_ch <= 0)
return;
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 78, 7,
burst_pixels - 1);
};
static inline int _ipu_ch_param_get_burst_size(struct ipu_soc *ipu, uint32_t ch)
{
return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7) + 1;
};
static inline int _ipu_ch_param_get_bpp(struct ipu_soc *ipu, uint32_t ch)
{
return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 107, 3);
};
static inline void _ipu_ch_param_set_buffer(struct ipu_soc *ipu, uint32_t ch,
int bufNum, dma_addr_t phyaddr)
{
if (bufNum == 2) {
ch = __ipu_ch_get_third_buf_cpmem_num(ch);
if (ch <= 0)
return;
bufNum = 0;
}
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 29 * bufNum, 29,
phyaddr / 8);
};
static inline void _ipu_ch_param_set_rotation(struct ipu_soc *ipu, uint32_t ch,
ipu_rotate_mode_t rot)
{
u32 temp_rot = bitrev8(rot) >> 5;
int32_t sub_ch = 0;
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 119, 3, temp_rot);
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
if (sub_ch <= 0)
return;
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 119, 3, temp_rot);
};
static inline void _ipu_ch_param_set_block_mode(struct ipu_soc *ipu, uint32_t ch)
{
int32_t sub_ch = 0;
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 117, 2, 1);
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
if (sub_ch <= 0)
return;
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 117, 2, 1);
};
static inline void _ipu_ch_param_set_alpha_use_separate_channel(struct ipu_soc *ipu,
uint32_t ch,
bool option)
{
int32_t sub_ch = 0;
if (option) {
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 1);
} else {
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 0);
}
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
if (sub_ch <= 0)
return;
if (option) {
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 1);
} else {
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 0);
}
};
static inline void _ipu_ch_param_set_alpha_condition_read(struct ipu_soc *ipu, uint32_t ch)
{
int32_t sub_ch = 0;
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 149, 1, 1);
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
if (sub_ch <= 0)
return;
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 149, 1, 1);
};
static inline void _ipu_ch_param_set_alpha_buffer_memory(struct ipu_soc *ipu, uint32_t ch)
{
int alp_mem_idx;
int32_t sub_ch = 0;
switch (ch) {
case 14: /* PRP graphic */
alp_mem_idx = 0;
break;
case 15: /* PP graphic */
alp_mem_idx = 1;
break;
case 23: /* DP BG SYNC graphic */
alp_mem_idx = 4;
break;
case 27: /* DP FG SYNC graphic */
alp_mem_idx = 2;
break;
default:
dev_err(ipu->dev, "unsupported correlative channel of local "
"alpha channel\n");
return;
}
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 90, 3, alp_mem_idx);
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
if (sub_ch <= 0)
return;
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 90, 3, alp_mem_idx);
};
static inline void _ipu_ch_param_set_interlaced_scan(struct ipu_soc *ipu, uint32_t ch)
{
u32 stride;
int32_t sub_ch = 0;
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1, 1);
if (sub_ch > 0)
ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 113, 1, 1);
stride = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14) + 1;
/* ILO is 20-bit and 8-byte aligned */
if (stride/8 > 0xfffff)
dev_warn(ipu->dev,
"IDMAC%d's ILO exceeds IPU limitation\n", ch);
if (stride%8)
dev_warn(ipu->dev,
"IDMAC%d's ILO is not 8-byte aligned\n", ch);
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 58, 20, stride / 8);
if (sub_ch > 0)
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 58, 20,
stride / 8);
stride *= 2;
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14, stride - 1);
if (sub_ch > 0)
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 102, 14,
stride - 1);
};
static inline void _ipu_ch_param_set_axi_id(struct ipu_soc *ipu, uint32_t ch, uint32_t id)
{
int32_t sub_ch = 0;
id %= 4;
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 93, 2, id);
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
if (sub_ch <= 0)
return;
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 93, 2, id);
};
static inline int _ipu_ch_param_get_axi_id(struct ipu_soc *ipu, uint32_t ch)
{
return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 93, 2);
}
static inline int __ipu_ch_offset_calc(uint32_t pixel_fmt,
uint32_t width,
uint32_t height,
uint32_t stride,
uint32_t u,
uint32_t v,
uint32_t uv_stride,
uint32_t vertical_offset,
uint32_t horizontal_offset,
uint32_t *u_offset,
uint32_t *v_offset)
{
uint32_t u_fix = 0;
uint32_t v_fix = 0;
switch (pixel_fmt) {
case IPU_PIX_FMT_GENERIC:
case IPU_PIX_FMT_GENERIC_16:
case IPU_PIX_FMT_GENERIC_32:
case IPU_PIX_FMT_RGB565:
case IPU_PIX_FMT_BGR24:
case IPU_PIX_FMT_RGB24:
case IPU_PIX_FMT_YUV444:
case IPU_PIX_FMT_BGRA32:
case IPU_PIX_FMT_BGR32:
case IPU_PIX_FMT_RGBA32:
case IPU_PIX_FMT_RGB32:
case IPU_PIX_FMT_ABGR32:
case IPU_PIX_FMT_UYVY:
case IPU_PIX_FMT_YUYV:
case IPU_PIX_FMT_GPU32_SB_ST:
case IPU_PIX_FMT_GPU32_SB_SRT:
case IPU_PIX_FMT_GPU32_ST:
case IPU_PIX_FMT_GPU32_SRT:
case IPU_PIX_FMT_GPU16_SB_ST:
case IPU_PIX_FMT_GPU16_SB_SRT:
case IPU_PIX_FMT_GPU16_ST:
case IPU_PIX_FMT_GPU16_SRT:
*u_offset = 0;
*v_offset = 0;
break;
case IPU_PIX_FMT_YUV420P2:
case IPU_PIX_FMT_YUV420P:
if (uv_stride < stride / 2)
uv_stride = stride / 2;
*u_offset = stride * (height - vertical_offset - 1) +
(stride - horizontal_offset) +
(uv_stride * vertical_offset / 2) +
horizontal_offset / 2;
*v_offset = *u_offset + (uv_stride * height / 2);
u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
(horizontal_offset / 2) -
(stride * vertical_offset) - (horizontal_offset)) :
*u_offset;
v_fix = v ? (v + (uv_stride * vertical_offset / 2) +
(horizontal_offset / 2) -
(stride * vertical_offset) - (horizontal_offset)) :
*v_offset;
break;
case IPU_PIX_FMT_YVU420P:
if (uv_stride < stride / 2)
uv_stride = stride / 2;
*v_offset = stride * (height - vertical_offset - 1) +
(stride - horizontal_offset) +
(uv_stride * vertical_offset / 2) +
horizontal_offset / 2;
*u_offset = *v_offset + (uv_stride * height / 2);
u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
(horizontal_offset / 2) -
(stride * vertical_offset) - (horizontal_offset)) :
*u_offset;
v_fix = v ? (v + (uv_stride * vertical_offset / 2) +
(horizontal_offset / 2) -
(stride * vertical_offset) - (horizontal_offset)) :
*v_offset;
break;
case IPU_PIX_FMT_YVU422P:
if (uv_stride < stride / 2)
uv_stride = stride / 2;
*v_offset = stride * (height - vertical_offset - 1) +
(stride - horizontal_offset) +
(uv_stride * vertical_offset) +
horizontal_offset / 2;
*u_offset = *v_offset + uv_stride * height;
u_fix = u ? (u + (uv_stride * vertical_offset) +
horizontal_offset / 2 -
(stride * vertical_offset) - (horizontal_offset)) :
*u_offset;
v_fix = v ? (v + (uv_stride * vertical_offset) +
horizontal_offset / 2 -
(stride * vertical_offset) - (horizontal_offset)) :
*v_offset;
break;
case IPU_PIX_FMT_YUV422P:
if (uv_stride < stride / 2)
uv_stride = stride / 2;
*u_offset = stride * (height - vertical_offset - 1) +
(stride - horizontal_offset) +
(uv_stride * vertical_offset) +
horizontal_offset / 2;
*v_offset = *u_offset + uv_stride * height;
u_fix = u ? (u + (uv_stride * vertical_offset) +
horizontal_offset / 2 -
(stride * vertical_offset) - (horizontal_offset)) :
*u_offset;
v_fix = v ? (v + (uv_stride * vertical_offset) +
horizontal_offset / 2 -
(stride * vertical_offset) - (horizontal_offset)) :
*v_offset;
break;
case IPU_PIX_FMT_YUV444P:
uv_stride = stride;
*u_offset = stride * (height - vertical_offset - 1) +
(stride - horizontal_offset) +
(uv_stride * vertical_offset) +
horizontal_offset;
*v_offset = *u_offset + uv_stride * height;
u_fix = u ? (u + (uv_stride * vertical_offset) +
horizontal_offset -
(stride * vertical_offset) -
(horizontal_offset)) :
*u_offset;
v_fix = v ? (v + (uv_stride * vertical_offset) +
horizontal_offset -
(stride * vertical_offset) -
(horizontal_offset)) :
*v_offset;
break;
case IPU_PIX_FMT_NV12:
case IPU_PIX_FMT_NV16:
case PRE_PIX_FMT_NV21:
case PRE_PIX_FMT_NV61:
uv_stride = stride;
*u_offset = stride * (height - vertical_offset - 1) +
(stride - horizontal_offset) +
(uv_stride * vertical_offset / 2) +
horizontal_offset;
*v_offset = 0;
u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
horizontal_offset -
(stride * vertical_offset) - (horizontal_offset)) :
*u_offset;
break;
default:
return -EINVAL;
}
if (u_fix > *u_offset)
*u_offset = u_fix;
if (v_fix > *v_offset)
*v_offset = v_fix;
return 0;
}
/* IDMAC U/V offset changing support */
/* U and V input is not affected, */
/* the update is done by new calculation according to */
/* vertical_offset and horizontal_offset */
static inline void _ipu_ch_offset_update(struct ipu_soc *ipu,
int ch,
uint32_t pixel_fmt,
uint32_t width,
uint32_t height,
uint32_t stride,
uint32_t u,
uint32_t v,
uint32_t uv_stride,
uint32_t vertical_offset,
uint32_t horizontal_offset)
{
uint32_t u_offset = 0;
uint32_t v_offset = 0;
uint32_t old_offset = 0;
int32_t sub_ch = 0;
int ret;
ret = __ipu_ch_offset_calc(pixel_fmt, width, height, stride,
u, v, uv_stride,
vertical_offset, horizontal_offset,
&u_offset, &v_offset);
if (ret) {
dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n");
return;
}
/* UBO and VBO are 22-bit and 8-byte aligned */
if (u_offset/8 > 0x3fffff)
dev_warn(ipu->dev,
"IDMAC%d's U offset exceeds IPU limitation\n", ch);
if (v_offset/8 > 0x3fffff)
dev_warn(ipu->dev,
"IDMAC%d's V offset exceeds IPU limitation\n", ch);
if (u_offset%8)
dev_warn(ipu->dev,
"IDMAC%d's U offset is not 8-byte aligned\n", ch);
if (v_offset%8)
dev_warn(ipu->dev,
"IDMAC%d's V offset is not 8-byte aligned\n", ch);
old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22);
if (old_offset != u_offset / 8)
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22, u_offset / 8);
old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22);
if (old_offset != v_offset / 8)
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22, v_offset / 8);
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
if (sub_ch <= 0)
return;
old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22);
if (old_offset != u_offset / 8)
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22, u_offset / 8);
old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22);
if (old_offset != v_offset / 8)
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22, v_offset / 8);
};
static inline void _ipu_ch_params_set_alpha_width(struct ipu_soc *ipu, uint32_t ch, int alpha_width)
{
int32_t sub_ch = 0;
ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 1, 125, 3, alpha_width - 1);
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
if (sub_ch <= 0)
return;
ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 125, 3, alpha_width - 1);
};
static inline void _ipu_ch_param_set_bandmode(struct ipu_soc *ipu,
uint32_t ch, uint32_t band_height)
{
int32_t sub_ch = 0;
ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch),
0, 114, 3, band_height - 1);
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
if (sub_ch <= 0)
return;
ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch),
0, 114, 3, band_height - 1);
dev_dbg(ipu->dev, "BNDM 0x%x, ",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 114, 3));
}
/*
* The IPUv3 IDMAC has a bug to read 32bpp pixels from a graphics plane
* whose alpha component is at the most significant 8 bits. The bug only
* impacts on cases in which the relevant separate alpha channel is enabled.
*
* Return true on bad alpha component position, otherwise, return false.
*/
static inline bool _ipu_ch_param_bad_alpha_pos(uint32_t pixel_fmt)
{
switch (pixel_fmt) {
case IPU_PIX_FMT_BGRA32:
case IPU_PIX_FMT_BGR32:
case IPU_PIX_FMT_RGBA32:
case IPU_PIX_FMT_RGB32:
return true;
}
return false;
}
#endif

View File

@ -0,0 +1,317 @@
/*
* Copyright (C) 2013-2015 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*!
* @file ipu_pixel_clk.c
*
* @brief IPU pixel clock implementation
*
* @ingroup IPU
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/ipu-v3.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include "ipu_prv.h"
#include "ipu_regs.h"
/*
* muxd clock implementation
*/
struct clk_di_mux {
struct clk_hw hw;
u8 ipu_id;
u8 di_id;
u8 flags;
u8 index;
};
#define to_clk_di_mux(_hw) container_of(_hw, struct clk_di_mux, hw)
static int _ipu_pixel_clk_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_di_mux *mux = to_clk_di_mux(hw);
struct ipu_soc *ipu = ipu_get_soc(mux->ipu_id);
u32 di_gen;
di_gen = ipu_di_read(ipu, mux->di_id, DI_GENERAL);
if (index == 0)
/* ipu1_clk or ipu2_clk internal clk */
di_gen &= ~DI_GEN_DI_CLK_EXT;
else
di_gen |= DI_GEN_DI_CLK_EXT;
ipu_di_write(ipu, mux->di_id, di_gen, DI_GENERAL);
mux->index = index;
pr_debug("ipu_pixel_clk: di_clk_ext:0x%x, di_gen reg:0x%x.\n",
!(di_gen & DI_GEN_DI_CLK_EXT), di_gen);
return 0;
}
static u8 _ipu_pixel_clk_get_parent(struct clk_hw *hw)
{
struct clk_di_mux *mux = to_clk_di_mux(hw);
return mux->index;
}
const struct clk_ops clk_mux_di_ops = {
.get_parent = _ipu_pixel_clk_get_parent,
.set_parent = _ipu_pixel_clk_set_parent,
};
struct clk *clk_register_mux_pix_clk(struct device *dev, const char *name,
const char **parent_names, u8 num_parents, unsigned long flags,
u8 ipu_id, u8 di_id, u8 clk_mux_flags)
{
struct clk_di_mux *mux;
struct clk *clk;
struct clk_init_data init;
mux = kzalloc(sizeof(struct clk_di_mux), GFP_KERNEL);
if (!mux)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &clk_mux_di_ops;
init.flags = flags;
init.parent_names = parent_names;
init.num_parents = num_parents;
mux->ipu_id = ipu_id;
mux->di_id = di_id;
mux->flags = clk_mux_flags | CLK_SET_RATE_PARENT;
mux->hw.init = &init;
clk = clk_register(dev, &mux->hw);
if (IS_ERR(clk))
kfree(mux);
return clk;
}
/*
* Gated clock implementation
*/
struct clk_di_div {
struct clk_hw hw;
u8 ipu_id;
u8 di_id;
u8 flags;
};
#define to_clk_di_div(_hw) container_of(_hw, struct clk_di_div, hw)
static unsigned long _ipu_pixel_clk_div_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_di_div *di_div = to_clk_di_div(hw);
struct ipu_soc *ipu = ipu_get_soc(di_div->ipu_id);
u32 div;
u64 final_rate = (unsigned long long)parent_rate * 16;
_ipu_get(ipu);
div = ipu_di_read(ipu, di_div->di_id, DI_BS_CLKGEN0);
_ipu_put(ipu);
pr_debug("ipu_di%d read BS_CLKGEN0 div:%d, final_rate:%lld, prate:%ld\n",
di_div->di_id, div, final_rate, parent_rate);
if (div == 0)
return 0;
do_div(final_rate, div);
return (unsigned long)final_rate;
}
static long _ipu_pixel_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_clk_rate)
{
u64 div, final_rate;
u32 remainder;
u64 parent_rate = (unsigned long long)(*parent_clk_rate) * 16;
/*
* Calculate divider
* Fractional part is 4 bits,
* so simply multiply by 2^4 to get fractional part.
*/
div = parent_rate;
remainder = do_div(div, rate);
/* Round the divider value */
if (remainder > (rate/2))
div++;
if (div < 0x10) /* Min DI disp clock divider is 1 */
div = 0x10;
if (div & ~0xFEF)
div &= 0xFF8;
else {
/* Round up divider if it gets us closer to desired pix clk */
if ((div & 0xC) == 0xC) {
div += 0x10;
div &= ~0xF;
}
}
final_rate = parent_rate;
do_div(final_rate, div);
return final_rate;
}
static int _ipu_pixel_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_clk_rate)
{
struct clk_di_div *di_div = to_clk_di_div(hw);
struct ipu_soc *ipu = ipu_get_soc(di_div->ipu_id);
u64 div, parent_rate;
u32 remainder;
parent_rate = (unsigned long long)parent_clk_rate * 16;
div = parent_rate;
remainder = do_div(div, rate);
/* Round the divider value */
if (remainder > (rate/2))
div++;
/* Round up divider if it gets us closer to desired pix clk */
if ((div & 0xC) == 0xC) {
div += 0x10;
div &= ~0xF;
}
if (div > 0x1000)
pr_err("Overflow, di:%d, DI_BS_CLKGEN0 div:0x%x\n",
di_div->di_id, (u32)div);
_ipu_get(ipu);
ipu_di_write(ipu, di_div->di_id, (u32)div, DI_BS_CLKGEN0);
/* Setup pixel clock timing */
/* FIXME: needs to be more flexible */
/* Down time is half of period */
ipu_di_write(ipu, di_div->di_id, ((u32)div / 16) << 16, DI_BS_CLKGEN1);
_ipu_put(ipu);
return 0;
}
static struct clk_ops clk_div_ops = {
.recalc_rate = _ipu_pixel_clk_div_recalc_rate,
.round_rate = _ipu_pixel_clk_div_round_rate,
.set_rate = _ipu_pixel_clk_div_set_rate,
};
struct clk *clk_register_div_pix_clk(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
u8 ipu_id, u8 di_id, u8 clk_div_flags)
{
struct clk_di_div *di_div;
struct clk *clk;
struct clk_init_data init;
di_div = kzalloc(sizeof(struct clk_di_div), GFP_KERNEL);
if (!di_div)
return ERR_PTR(-ENOMEM);
/* struct clk_di_div assignments */
di_div->ipu_id = ipu_id;
di_div->di_id = di_id;
di_div->flags = clk_div_flags;
init.name = name;
init.ops = &clk_div_ops;
init.flags = flags | CLK_SET_RATE_PARENT;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
di_div->hw.init = &init;
clk = clk_register(dev, &di_div->hw);
if (IS_ERR(clk))
kfree(di_div);
return clk;
}
/*
* Gated clock implementation
*/
struct clk_di_gate {
struct clk_hw hw;
u8 ipu_id;
u8 di_id;
u8 flags;
};
#define to_clk_di_gate(_hw) container_of(_hw, struct clk_di_gate, hw)
static int _ipu_pixel_clk_enable(struct clk_hw *hw)
{
struct clk_di_gate *gate = to_clk_di_gate(hw);
struct ipu_soc *ipu = ipu_get_soc(gate->ipu_id);
u32 disp_gen;
disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
disp_gen |= gate->di_id ? DI1_COUNTER_RELEASE : DI0_COUNTER_RELEASE;
ipu_cm_write(ipu, disp_gen, IPU_DISP_GEN);
return 0;
}
static void _ipu_pixel_clk_disable(struct clk_hw *hw)
{
struct clk_di_gate *gate = to_clk_di_gate(hw);
struct ipu_soc *ipu = ipu_get_soc(gate->ipu_id);
u32 disp_gen;
disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
disp_gen &= gate->di_id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
ipu_cm_write(ipu, disp_gen, IPU_DISP_GEN);
}
static struct clk_ops clk_gate_di_ops = {
.enable = _ipu_pixel_clk_enable,
.disable = _ipu_pixel_clk_disable,
};
struct clk *clk_register_gate_pix_clk(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
u8 ipu_id, u8 di_id, u8 clk_gate_flags)
{
struct clk_di_gate *gate;
struct clk *clk;
struct clk_init_data init;
gate = kzalloc(sizeof(struct clk_di_gate), GFP_KERNEL);
if (!gate)
return ERR_PTR(-ENOMEM);
gate->ipu_id = ipu_id;
gate->di_id = di_id;
gate->flags = clk_gate_flags;
init.name = name;
init.ops = &clk_gate_di_ops;
init.flags = flags | CLK_SET_RATE_PARENT;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
gate->hw.init = &init;
clk = clk_register(dev, &gate->hw);
if (IS_ERR(clk))
kfree(gate);
return clk;
}

View File

@ -0,0 +1,369 @@
/*
* Copyright 2005-2016 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef __INCLUDE_IPU_PRV_H__
#define __INCLUDE_IPU_PRV_H__
#include <linux/clkdev.h>
#include <linux/device.h>
#include <linux/fsl_devices.h>
#include <linux/interrupt.h>
#include <linux/ipu-v3.h>
#include <linux/types.h>
#define MXC_IPU_MAX_NUM 2
#define MXC_DI_NUM_PER_IPU 2
/* Globals */
extern int dmfc_type_setup;
#define IDMA_CHAN_INVALID 0xFF
#define HIGH_RESOLUTION_WIDTH 1024
enum ipuv3_type {
IPUv3D, /* i.MX37 */
IPUv3EX, /* i.MX51 */
IPUv3M, /* i.MX53 */
IPUv3H, /* i.MX6Q/SDL */
};
#define IPU_MAX_VDI_IN_WIDTH(type) ({ (type) >= IPUv3M ? 968 : 720; })
struct ipu_irq_node {
irqreturn_t(*handler) (int, void *); /*!< the ISR */
const char *name; /*!< device associated with the interrupt */
void *dev_id; /*!< some unique information for the ISR */
__u32 flags; /*!< not used */
};
enum csc_type_t {
RGB2YUV = 0,
YUV2RGB,
RGB2RGB,
YUV2YUV,
CSC_NONE,
CSC_NUM
};
struct ipu_soc {
unsigned int id;
unsigned int devtype;
bool online;
/*clk*/
struct clk *ipu_clk;
struct clk *di_clk[2];
struct clk *di_clk_sel[2];
struct clk *pixel_clk[2];
bool pixel_clk_en[2];
struct clk *pixel_clk_sel[2];
struct clk *csi_clk[2];
struct clk *prg_clk;
/*irq*/
int irq_sync;
int irq_err;
struct ipu_irq_node irq_list[IPU_IRQ_COUNT];
/*reg*/
void __iomem *cm_reg;
void __iomem *idmac_reg;
void __iomem *dp_reg;
void __iomem *ic_reg;
void __iomem *dc_reg;
void __iomem *dc_tmpl_reg;
void __iomem *dmfc_reg;
void __iomem *di_reg[2];
void __iomem *smfc_reg;
void __iomem *csi_reg[2];
void __iomem *cpmem_base;
void __iomem *tpmem_base;
void __iomem *vdi_reg;
struct device *dev;
ipu_channel_t csi_channel[2];
ipu_channel_t using_ic_dirct_ch;
unsigned char dc_di_assignment[10];
bool sec_chan_en[IPU_MAX_CH];
bool thrd_chan_en[IPU_MAX_CH];
bool chan_is_interlaced[52];
uint32_t channel_init_mask;
uint32_t channel_enable_mask;
/*use count*/
int dc_use_count;
int dp_use_count;
int dmfc_use_count;
int smfc_use_count;
int ic_use_count;
int rot_use_count;
int vdi_use_count;
int di_use_count[2];
int csi_use_count[2];
struct mutex mutex_lock;
spinlock_t int_reg_spin_lock;
spinlock_t rdy_reg_spin_lock;
int dmfc_size_28;
int dmfc_size_29;
int dmfc_size_24;
int dmfc_size_27;
int dmfc_size_23;
enum csc_type_t fg_csc_type;
enum csc_type_t bg_csc_type;
bool color_key_4rgb;
bool dc_swap;
struct completion dc_comp;
struct completion csi_comp;
struct rot_mem {
void *vaddr;
dma_addr_t paddr;
int size;
} rot_dma[2];
int vdoa_en;
struct task_struct *thread[2];
/*
* Bypass reset to avoid display channel being
* stopped by probe since it may starts to work
* in bootloader.
*/
bool bypass_reset;
unsigned int ch0123_axi;
unsigned int ch23_axi;
unsigned int ch27_axi;
unsigned int ch28_axi;
unsigned int normal_axi;
bool smfc_idmac_12bit_3planar_bs_fixup; /* workaround little stripes */
};
struct ipu_channel {
u8 video_in_dma;
u8 alpha_in_dma;
u8 graph_in_dma;
u8 out_dma;
};
enum ipu_dmfc_type {
DMFC_NORMAL = 0,
DMFC_HIGH_RESOLUTION_DC,
DMFC_HIGH_RESOLUTION_DP,
DMFC_HIGH_RESOLUTION_ONLY_DP,
};
static inline int _ipu_is_smfc_chan(uint32_t dma_chan)
{
return dma_chan <= 3;
}
static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
{
return readl(ipu->cm_reg + offset);
}
static inline void ipu_cm_write(struct ipu_soc *ipu,
u32 value, unsigned offset)
{
writel(value, ipu->cm_reg + offset);
}
static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
{
return readl(ipu->idmac_reg + offset);
}
static inline void ipu_idmac_write(struct ipu_soc *ipu,
u32 value, unsigned offset)
{
writel(value, ipu->idmac_reg + offset);
}
static inline u32 ipu_dc_read(struct ipu_soc *ipu, unsigned offset)
{
return readl(ipu->dc_reg + offset);
}
static inline void ipu_dc_write(struct ipu_soc *ipu,
u32 value, unsigned offset)
{
writel(value, ipu->dc_reg + offset);
}
static inline u32 ipu_dc_tmpl_read(struct ipu_soc *ipu, unsigned offset)
{
return readl(ipu->dc_tmpl_reg + offset);
}
static inline void ipu_dc_tmpl_write(struct ipu_soc *ipu,
u32 value, unsigned offset)
{
writel(value, ipu->dc_tmpl_reg + offset);
}
static inline u32 ipu_dmfc_read(struct ipu_soc *ipu, unsigned offset)
{
return readl(ipu->dmfc_reg + offset);
}
static inline void ipu_dmfc_write(struct ipu_soc *ipu,
u32 value, unsigned offset)
{
writel(value, ipu->dmfc_reg + offset);
}
static inline u32 ipu_dp_read(struct ipu_soc *ipu, unsigned offset)
{
return readl(ipu->dp_reg + offset);
}
static inline void ipu_dp_write(struct ipu_soc *ipu,
u32 value, unsigned offset)
{
writel(value, ipu->dp_reg + offset);
}
static inline u32 ipu_di_read(struct ipu_soc *ipu, int di, unsigned offset)
{
return readl(ipu->di_reg[di] + offset);
}
static inline void ipu_di_write(struct ipu_soc *ipu, int di,
u32 value, unsigned offset)
{
writel(value, ipu->di_reg[di] + offset);
}
static inline u32 ipu_csi_read(struct ipu_soc *ipu, int csi, unsigned offset)
{
return readl(ipu->csi_reg[csi] + offset);
}
static inline void ipu_csi_write(struct ipu_soc *ipu, int csi,
u32 value, unsigned offset)
{
writel(value, ipu->csi_reg[csi] + offset);
}
static inline u32 ipu_smfc_read(struct ipu_soc *ipu, unsigned offset)
{
return readl(ipu->smfc_reg + offset);
}
static inline void ipu_smfc_write(struct ipu_soc *ipu,
u32 value, unsigned offset)
{
writel(value, ipu->smfc_reg + offset);
}
static inline u32 ipu_vdi_read(struct ipu_soc *ipu, unsigned offset)
{
return readl(ipu->vdi_reg + offset);
}
static inline void ipu_vdi_write(struct ipu_soc *ipu,
u32 value, unsigned offset)
{
writel(value, ipu->vdi_reg + offset);
}
static inline u32 ipu_ic_read(struct ipu_soc *ipu, unsigned offset)
{
return readl(ipu->ic_reg + offset);
}
static inline void ipu_ic_write(struct ipu_soc *ipu,
u32 value, unsigned offset)
{
writel(value, ipu->ic_reg + offset);
}
int register_ipu_device(struct ipu_soc *ipu, int id);
void unregister_ipu_device(struct ipu_soc *ipu, int id);
ipu_color_space_t format_to_colorspace(uint32_t fmt);
bool ipu_pixel_format_has_alpha(uint32_t fmt);
void ipu_dump_registers(struct ipu_soc *ipu);
uint32_t _ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel);
void ipu_disp_init(struct ipu_soc *ipu);
void _ipu_init_dc_mappings(struct ipu_soc *ipu);
int _ipu_dp_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t in_pixel_fmt,
uint32_t out_pixel_fmt);
void _ipu_dp_uninit(struct ipu_soc *ipu, ipu_channel_t channel);
void _ipu_dc_init(struct ipu_soc *ipu, int dc_chan, int di, bool interlaced, uint32_t pixel_fmt);
void _ipu_dc_uninit(struct ipu_soc *ipu, int dc_chan);
void _ipu_dp_dc_enable(struct ipu_soc *ipu, ipu_channel_t channel);
void _ipu_dp_dc_disable(struct ipu_soc *ipu, ipu_channel_t channel, bool swap);
void _ipu_dmfc_init(struct ipu_soc *ipu, int dmfc_type, int first);
void _ipu_dmfc_set_wait4eot(struct ipu_soc *ipu, int dma_chan, int width);
void _ipu_dmfc_set_burst_size(struct ipu_soc *ipu, int dma_chan, int burst_size);
int _ipu_disp_chan_is_interlaced(struct ipu_soc *ipu, ipu_channel_t channel);
void _ipu_ic_enable_task(struct ipu_soc *ipu, ipu_channel_t channel);
void _ipu_ic_disable_task(struct ipu_soc *ipu, ipu_channel_t channel);
int _ipu_ic_init_prpvf(struct ipu_soc *ipu, ipu_channel_params_t *params,
bool src_is_csi);
void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params);
void _ipu_vdi_uninit(struct ipu_soc *ipu);
void _ipu_ic_uninit_prpvf(struct ipu_soc *ipu);
void _ipu_ic_init_rotate_vf(struct ipu_soc *ipu, ipu_channel_params_t *params);
void _ipu_ic_uninit_rotate_vf(struct ipu_soc *ipu);
void _ipu_ic_init_csi(struct ipu_soc *ipu, ipu_channel_params_t *params);
void _ipu_ic_uninit_csi(struct ipu_soc *ipu);
int _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params,
bool src_is_csi);
void _ipu_ic_uninit_prpenc(struct ipu_soc *ipu);
void _ipu_ic_init_rotate_enc(struct ipu_soc *ipu, ipu_channel_params_t *params);
void _ipu_ic_uninit_rotate_enc(struct ipu_soc *ipu);
int _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params);
void _ipu_ic_uninit_pp(struct ipu_soc *ipu);
void _ipu_ic_init_rotate_pp(struct ipu_soc *ipu, ipu_channel_params_t *params);
void _ipu_ic_uninit_rotate_pp(struct ipu_soc *ipu);
int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan, uint16_t width, uint16_t height,
int burst_size, ipu_rotate_mode_t rot);
void _ipu_vdi_toggle_top_field_man(struct ipu_soc *ipu);
int _ipu_csi_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t csi);
int _ipu_csi_set_mipi_di(struct ipu_soc *ipu, uint32_t num, uint32_t di_val, uint32_t csi);
void ipu_csi_set_test_generator(struct ipu_soc *ipu, bool active, uint32_t r_value,
uint32_t g_value, uint32_t b_value,
uint32_t pix_clk, uint32_t csi);
void _ipu_csi_ccir_err_detection_enable(struct ipu_soc *ipu, uint32_t csi);
void _ipu_csi_ccir_err_detection_disable(struct ipu_soc *ipu, uint32_t csi);
void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel);
void _ipu_smfc_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t mipi_id, uint32_t csi);
void _ipu_smfc_set_burst_size(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t bs);
void _ipu_dp_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3]);
int32_t _ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
int16_t x_pos, int16_t y_pos);
int32_t _ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
int16_t *x_pos, int16_t *y_pos);
void _ipu_get(struct ipu_soc *ipu);
void _ipu_put(struct ipu_soc *ipu);
struct clk *clk_register_mux_pix_clk(struct device *dev, const char *name,
const char **parent_names, u8 num_parents, unsigned long flags,
u8 ipu_id, u8 di_id, u8 clk_mux_flags);
struct clk *clk_register_div_pix_clk(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
u8 ipu_id, u8 di_id, u8 clk_div_flags);
struct clk *clk_register_gate_pix_clk(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
u8 ipu_id, u8 di_id, u8 clk_gate_flags);
#endif /* __INCLUDE_IPU_PRV_H__ */

View File

@ -0,0 +1,702 @@
/*
* Copyright (C) 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*
* @file ipu_regs.h
*
* @brief IPU Register definitions
*
* @ingroup IPU
*/
#ifndef __IPU_REGS_INCLUDED__
#define __IPU_REGS_INCLUDED__
#include "ipu_prv.h"
#define IPU_MCU_T_DEFAULT 8
/* Register addresses */
/* IPU Common registers */
#define IPU_CM_REG(offset) (offset)
#define IPU_CONF IPU_CM_REG(0)
#define IPU_SRM_PRI1 IPU_CM_REG(0x00A0)
#define IPU_SRM_PRI2 IPU_CM_REG(0x00A4)
#define IPU_FS_PROC_FLOW1 IPU_CM_REG(0x00A8)
#define IPU_FS_PROC_FLOW2 IPU_CM_REG(0x00AC)
#define IPU_FS_PROC_FLOW3 IPU_CM_REG(0x00B0)
#define IPU_FS_DISP_FLOW1 IPU_CM_REG(0x00B4)
#define IPU_FS_DISP_FLOW2 IPU_CM_REG(0x00B8)
#define IPU_SKIP IPU_CM_REG(0x00BC)
#define IPU_DISP_ALT_CONF IPU_CM_REG(0x00C0)
#define IPU_DISP_GEN IPU_CM_REG(0x00C4)
#define IPU_DISP_ALT1 IPU_CM_REG(0x00C8)
#define IPU_DISP_ALT2 IPU_CM_REG(0x00CC)
#define IPU_DISP_ALT3 IPU_CM_REG(0x00D0)
#define IPU_DISP_ALT4 IPU_CM_REG(0x00D4)
#define IPU_SNOOP IPU_CM_REG(0x00D8)
#define IPU_MEM_RST IPU_CM_REG(0x00DC)
#define IPU_PM IPU_CM_REG(0x00E0)
#define IPU_GPR IPU_CM_REG(0x00E4)
#define IPU_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
#define IPU_ALT_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
/*
* IPUv3D doesn't support triple buffer, so point
* IPU_CHA_TRB_MODE_SEL, IPU_CHA_TRIPLE_CUR_BUF and
* IPU_CHA_BUF2_RDY to readonly
* IPU_ALT_CUR_BUF0 for IPUv3D.
*/
#define IPU_CHA_TRB_MODE_SEL(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x0178 + 4 * ((ch) / 32)) : \
(0x012C); })
#define IPU_CHA_TRIPLE_CUR_BUF(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x0258 + \
4 * (((ch) * 2) / 32)) : \
(0x012C); })
#define IPU_CHA_BUF2_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x0288 + 4 * ((ch) / 32)) : \
(0x012C); })
#define IPU_CHA_CUR_BUF(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x023C + 4 * ((ch) / 32)) : \
(0x0124 + 4 * ((ch) / 32)); })
#define IPU_ALT_CUR_BUF0(type) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x0244) : \
(0x012C); })
#define IPU_ALT_CUR_BUF1(type) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x0248) : \
(0x0130); })
#define IPU_SRM_STAT(type) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x024C) : \
(0x0134); })
#define IPU_PROC_TASK_STAT(type) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x0250) : \
(0x0138); })
#define IPU_DISP_TASK_STAT(type) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x0254) : \
(0x013C); })
#define IPU_CHA_BUF0_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x0268 + 4 * ((ch) / 32)) : \
(0x0140 + 4 * ((ch) / 32)); })
#define IPU_CHA_BUF1_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x0270 + 4 * ((ch) / 32)) : \
(0x0148 + 4 * ((ch) / 32)); })
#define IPU_ALT_CHA_BUF0_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x0278 + 4 * ((ch) / 32)) : \
(0x0158 + 4 * ((ch) / 32)); })
#define IPU_ALT_CHA_BUF1_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x0280 + 4 * ((ch) / 32)) : \
(0x0160 + 4 * ((ch) / 32)); })
#define IPU_INT_CTRL(n) IPU_CM_REG(0x003C + 4 * ((n) - 1))
#define IPU_INT_STAT(type, n) IPU_CM_REG({(type) >= IPUv3EX ? \
(0x0200 + 4 * ((n) - 1)) : \
(0x00E8 + 4 * ((n) - 1)); })
#define IPUIRQ_2_STATREG(type, irq) IPU_CM_REG(IPU_INT_STAT((type), 1) + 4 \
* ((irq) / 32))
#define IPUIRQ_2_CTRLREG(irq) IPU_CM_REG(IPU_INT_CTRL(1) + 4 * ((irq) / 32))
#define IPUIRQ_2_MASK(irq) (1UL << ((irq) & 0x1F))
/* IPU VDI registers */
#define IPU_VDI_REG(offset) (offset)
#define VDI_FSIZE IPU_VDI_REG(0)
#define VDI_C IPU_VDI_REG(0x0004)
/* IPU CSI Registers */
#define IPU_CSI_REG(offset) (offset)
#define CSI_SENS_CONF IPU_CSI_REG(0)
#define CSI_SENS_FRM_SIZE IPU_CSI_REG(0x0004)
#define CSI_ACT_FRM_SIZE IPU_CSI_REG(0x0008)
#define CSI_OUT_FRM_CTRL IPU_CSI_REG(0x000C)
#define CSI_TST_CTRL IPU_CSI_REG(0x0010)
#define CSI_CCIR_CODE_1 IPU_CSI_REG(0x0014)
#define CSI_CCIR_CODE_2 IPU_CSI_REG(0x0018)
#define CSI_CCIR_CODE_3 IPU_CSI_REG(0x001C)
#define CSI_MIPI_DI IPU_CSI_REG(0x0020)
#define CSI_SKIP IPU_CSI_REG(0x0024)
#define CSI_CPD_CTRL IPU_CSI_REG(0x0028)
#define CSI_CPD_RC(n) IPU_CSI_REG(0x002C + 4 * (n))
#define CSI_CPD_RS(n) IPU_CSI_REG(0x004C + 4 * (n))
#define CSI_CPD_GRC(n) IPU_CSI_REG(0x005C + 4 * (n))
#define CSI_CPD_GRS(n) IPU_CSI_REG(0x007C + 4 * (n))
#define CSI_CPD_GBC(n) IPU_CSI_REG(0x008C + 4 * (n))
#define CSI_CPD_GBS(n) IPU_CSI_REG(0x00AC + 4 * (n))
#define CSI_CPD_BC(n) IPU_CSI_REG(0x00BC + 4 * (n))
#define CSI_CPD_BS(n) IPU_CSI_REG(0x00DC + 4 * (n))
#define CSI_CPD_OFFSET1 IPU_CSI_REG(0x00EC)
#define CSI_CPD_OFFSET2 IPU_CSI_REG(0x00F0)
/* IPU SMFC Registers */
#define IPU_SMFC_REG(offset) (offset)
#define SMFC_MAP IPU_SMFC_REG(0)
#define SMFC_WMC IPU_SMFC_REG(0x0004)
#define SMFC_BS IPU_SMFC_REG(0x0008)
/* IPU IC Registers */
#define IPU_IC_REG(offset) (offset)
#define IC_CONF IPU_IC_REG(0)
#define IC_PRP_ENC_RSC IPU_IC_REG(0x0004)
#define IC_PRP_VF_RSC IPU_IC_REG(0x0008)
#define IC_PP_RSC IPU_IC_REG(0x000C)
#define IC_CMBP_1 IPU_IC_REG(0x0010)
#define IC_CMBP_2 IPU_IC_REG(0x0014)
#define IC_IDMAC_1 IPU_IC_REG(0x0018)
#define IC_IDMAC_2 IPU_IC_REG(0x001C)
#define IC_IDMAC_3 IPU_IC_REG(0x0020)
#define IC_IDMAC_4 IPU_IC_REG(0x0024)
/* IPU IDMAC Registers */
#define IPU_IDMAC_REG(offset) (offset)
#define IDMAC_CONF IPU_IDMAC_REG(0x0000)
#define IDMAC_CHA_EN(ch) IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
#define IDMAC_SEP_ALPHA IPU_IDMAC_REG(0x000C)
#define IDMAC_ALT_SEP_ALPHA IPU_IDMAC_REG(0x0010)
#define IDMAC_CHA_PRI(ch) IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
#define IDMAC_WM_EN(ch) IPU_IDMAC_REG(0x001C + 4 * ((ch) / 32))
#define IDMAC_CH_LOCK_EN_1(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
(0x0024) : 0; })
#define IDMAC_CH_LOCK_EN_2(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
(0x0028) : \
(0x0024); })
#define IDMAC_SUB_ADDR_0(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
(0x002C) : \
(0x0028); })
#define IDMAC_SUB_ADDR_1(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
(0x0030) : \
(0x002C); })
#define IDMAC_SUB_ADDR_2(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
(0x0034) : \
(0x0030); })
/*
* IPUv3D doesn't support IDMAC_SUB_ADDR_3 and IDMAC_SUB_ADDR_4,
* so point them to readonly IDMAC_CHA_BUSY1 for IPUv3D.
*/
#define IDMAC_SUB_ADDR_3(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
(0x0038) : \
(0x0040); })
#define IDMAC_SUB_ADDR_4(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
(0x003C) : \
(0x0040); })
#define IDMAC_BAND_EN(type, ch) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
(0x0040 + 4 * ((ch) / 32)) : \
(0x0034 + 4 * ((ch) / 32)); })
#define IDMAC_CHA_BUSY(type, ch) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
(0x0100 + 4 * ((ch) / 32)) : \
(0x0040 + 4 * ((ch) / 32)); })
/* IPU DI Registers */
#define IPU_DI_REG(offset) (offset)
#define DI_GENERAL IPU_DI_REG(0)
#define DI_BS_CLKGEN0 IPU_DI_REG(0x0004)
#define DI_BS_CLKGEN1 IPU_DI_REG(0x0008)
#define DI_SW_GEN0(gen) IPU_DI_REG(0x000C + 4 * ((gen) - 1))
#define DI_SW_GEN1(gen) IPU_DI_REG(0x0030 + 4 * ((gen) - 1))
#define DI_STP_REP(gen) IPU_DI_REG(0x0148 + 4 * (((gen) - 1) / 2))
#define DI_SYNC_AS_GEN IPU_DI_REG(0x0054)
#define DI_DW_GEN(gen) IPU_DI_REG(0x0058 + 4 * (gen))
#define DI_DW_SET(gen, set) IPU_DI_REG(0x0088 + 4 * ((gen) + 0xC * (set)))
#define DI_SER_CONF IPU_DI_REG(0x015C)
#define DI_SSC IPU_DI_REG(0x0160)
#define DI_POL IPU_DI_REG(0x0164)
#define DI_AW0 IPU_DI_REG(0x0168)
#define DI_AW1 IPU_DI_REG(0x016C)
#define DI_SCR_CONF IPU_DI_REG(0x0170)
#define DI_STAT IPU_DI_REG(0x0174)
/* IPU DMFC Registers */
#define IPU_DMFC_REG(offset) (offset)
#define DMFC_RD_CHAN IPU_DMFC_REG(0)
#define DMFC_WR_CHAN IPU_DMFC_REG(0x0004)
#define DMFC_WR_CHAN_DEF IPU_DMFC_REG(0x0008)
#define DMFC_DP_CHAN IPU_DMFC_REG(0x000C)
#define DMFC_DP_CHAN_DEF IPU_DMFC_REG(0x0010)
#define DMFC_GENERAL1 IPU_DMFC_REG(0x0014)
#define DMFC_GENERAL2 IPU_DMFC_REG(0x0018)
#define DMFC_IC_CTRL IPU_DMFC_REG(0x001C)
#define DMFC_STAT IPU_DMFC_REG(0x0020)
/* IPU DC Registers */
#define IPU_DC_REG(offset) (offset)
#define DC_MAP_CONF_PTR(n) IPU_DC_REG(0x0108 + ((n) & ~0x1) * 2)
#define DC_MAP_CONF_VAL(n) IPU_DC_REG(0x0144 + ((n) & ~0x1) * 2)
#define _RL_CH_2_OFFSET(ch) (((ch) == 0) ? 8 : ( \
((ch) == 1) ? 0x24 : ( \
((ch) == 2) ? 0x40 : ( \
((ch) == 5) ? 0x64 : ( \
((ch) == 6) ? 0x80 : ( \
((ch) == 8) ? 0x9C : ( \
((ch) == 9) ? 0xBC : (-1))))))))
#define DC_RL_CH(ch, evt) IPU_DC_REG(_RL_CH_2_OFFSET(ch) + \
((evt) & ~0x1) * 2)
#define DC_EVT_NF 0
#define DC_EVT_NL 1
#define DC_EVT_EOF 2
#define DC_EVT_NFIELD 3
#define DC_EVT_EOL 4
#define DC_EVT_EOFIELD 5
#define DC_EVT_NEW_ADDR 6
#define DC_EVT_NEW_CHAN 7
#define DC_EVT_NEW_DATA 8
#define DC_EVT_NEW_ADDR_W_0 0
#define DC_EVT_NEW_ADDR_W_1 1
#define DC_EVT_NEW_CHAN_W_0 2
#define DC_EVT_NEW_CHAN_W_1 3
#define DC_EVT_NEW_DATA_W_0 4
#define DC_EVT_NEW_DATA_W_1 5
#define DC_EVT_NEW_ADDR_R_0 6
#define DC_EVT_NEW_ADDR_R_1 7
#define DC_EVT_NEW_CHAN_R_0 8
#define DC_EVT_NEW_CHAN_R_1 9
#define DC_EVT_NEW_DATA_R_0 10
#define DC_EVT_NEW_DATA_R_1 11
#define DC_EVEN_UGDE0 12
#define DC_ODD_UGDE0 13
#define DC_EVEN_UGDE1 14
#define DC_ODD_UGDE1 15
#define DC_EVEN_UGDE2 16
#define DC_ODD_UGDE2 17
#define DC_EVEN_UGDE3 18
#define DC_ODD_UGDE3 19
#define dc_ch_offset(ch) \
({ \
const u8 _offset[] = { \
0, 0x1C, 0x38, 0x54, 0x58, 0x5C, 0x78, 0, 0x94, 0xB4}; \
_offset[ch]; \
})
#define DC_WR_CH_CONF(ch) IPU_DC_REG(dc_ch_offset(ch))
#define DC_WR_CH_ADDR(ch) IPU_DC_REG(dc_ch_offset(ch) + 4)
#define DC_WR_CH_CONF_1 IPU_DC_REG(0x001C)
#define DC_WR_CH_ADDR_1 IPU_DC_REG(0x0020)
#define DC_WR_CH_CONF_5 IPU_DC_REG(0x005C)
#define DC_WR_CH_ADDR_5 IPU_DC_REG(0x0060)
#define DC_GEN IPU_DC_REG(0x00D4)
#define DC_DISP_CONF1(disp) IPU_DC_REG(0x00D8 + 4 * (disp))
#define DC_DISP_CONF2(disp) IPU_DC_REG(0x00E8 + 4 * (disp))
#define DC_STAT IPU_DC_REG(0x01C8)
#define DC_UGDE_0(evt) IPU_DC_REG(0x0174 + 16 * (evt))
#define DC_UGDE_1(evt) IPU_DC_REG(0x0178 + 16 * (evt))
#define DC_UGDE_2(evt) IPU_DC_REG(0x017C + 16 * (evt))
#define DC_UGDE_3(evt) IPU_DC_REG(0x0180 + 16 * (evt))
/* IPU DP Registers */
#define IPU_DP_REG(offset) (offset)
#define DP_SYNC 0
#define DP_ASYNC0 0x60
#define DP_ASYNC1 0xBC
#define DP_COM_CONF(flow) IPU_DP_REG(flow)
#define DP_GRAPH_WIND_CTRL(flow) IPU_DP_REG(0x0004 + (flow))
#define DP_FG_POS(flow) IPU_DP_REG(0x0008 + (flow))
#define DP_GAMMA_C(flow, i) IPU_DP_REG(0x0014 + (flow) + 4 * (i))
#define DP_GAMMA_S(flow, i) IPU_DP_REG(0x0034 + (flow) + 4 * (i))
#define DP_CSC_A_0(flow) IPU_DP_REG(0x0044 + (flow))
#define DP_CSC_A_1(flow) IPU_DP_REG(0x0048 + (flow))
#define DP_CSC_A_2(flow) IPU_DP_REG(0x004C + (flow))
#define DP_CSC_A_3(flow) IPU_DP_REG(0x0050 + (flow))
#define DP_CSC_0(flow) IPU_DP_REG(0x0054 + (flow))
#define DP_CSC_1(flow) IPU_DP_REG(0x0058 + (flow))
enum {
IPU_CONF_CSI0_EN = 0x00000001,
IPU_CONF_CSI1_EN = 0x00000002,
IPU_CONF_IC_EN = 0x00000004,
IPU_CONF_ROT_EN = 0x00000008,
IPU_CONF_ISP_EN = 0x00000010,
IPU_CONF_DP_EN = 0x00000020,
IPU_CONF_DI0_EN = 0x00000040,
IPU_CONF_DI1_EN = 0x00000080,
IPU_CONF_DMFC_EN = 0x00000400,
IPU_CONF_SMFC_EN = 0x00000100,
IPU_CONF_DC_EN = 0x00000200,
IPU_CONF_VDI_EN = 0x00001000,
IPU_CONF_IDMAC_DIS = 0x00400000,
IPU_CONF_IC_DMFC_SEL = 0x02000000,
IPU_CONF_IC_DMFC_SYNC = 0x04000000,
IPU_CONF_VDI_DMFC_SYNC = 0x08000000,
IPU_CONF_CSI0_DATA_SOURCE = 0x10000000,
IPU_CONF_CSI0_DATA_SOURCE_OFFSET = 28,
IPU_CONF_CSI1_DATA_SOURCE = 0x20000000,
IPU_CONF_IC_INPUT = 0x40000000,
IPU_CONF_CSI_SEL = 0x80000000,
DI0_COUNTER_RELEASE = 0x01000000,
DI1_COUNTER_RELEASE = 0x02000000,
FS_PRPVF_ROT_SRC_SEL_MASK = 0x00000F00,
FS_PRPVF_ROT_SRC_SEL_OFFSET = 8,
FS_PRPENC_ROT_SRC_SEL_MASK = 0x0000000F,
FS_PRPENC_ROT_SRC_SEL_OFFSET = 0,
FS_PP_ROT_SRC_SEL_MASK = 0x000F0000,
FS_PP_ROT_SRC_SEL_OFFSET = 16,
FS_PP_SRC_SEL_MASK = 0x0000F000,
FS_PP_SRC_SEL_VDOA = 0x00008000,
FS_PP_SRC_SEL_OFFSET = 12,
FS_PRP_SRC_SEL_MASK = 0x0F000000,
FS_PRP_SRC_SEL_OFFSET = 24,
FS_VF_IN_VALID = 0x80000000,
FS_ENC_IN_VALID = 0x40000000,
FS_VDI_SRC_SEL_MASK = 0x30000000,
FS_VDI_SRC_SEL_VDOA = 0x20000000,
FS_VDOA_DEST_SEL_MASK = 0x00030000,
FS_VDOA_DEST_SEL_VDI = 0x00020000,
FS_VDOA_DEST_SEL_IC = 0x00010000,
FS_VDI_SRC_SEL_OFFSET = 28,
FS_PRPENC_DEST_SEL_MASK = 0x0000000F,
FS_PRPENC_DEST_SEL_OFFSET = 0,
FS_PRPVF_DEST_SEL_MASK = 0x000000F0,
FS_PRPVF_DEST_SEL_OFFSET = 4,
FS_PRPVF_ROT_DEST_SEL_MASK = 0x00000F00,
FS_PRPVF_ROT_DEST_SEL_OFFSET = 8,
FS_PP_DEST_SEL_MASK = 0x0000F000,
FS_PP_DEST_SEL_OFFSET = 12,
FS_PP_ROT_DEST_SEL_MASK = 0x000F0000,
FS_PP_ROT_DEST_SEL_OFFSET = 16,
FS_PRPENC_ROT_DEST_SEL_MASK = 0x00F00000,
FS_PRPENC_ROT_DEST_SEL_OFFSET = 20,
FS_SMFC0_DEST_SEL_MASK = 0x0000000F,
FS_SMFC0_DEST_SEL_OFFSET = 0,
FS_SMFC1_DEST_SEL_MASK = 0x00000070,
FS_SMFC1_DEST_SEL_OFFSET = 4,
FS_SMFC2_DEST_SEL_MASK = 0x00000780,
FS_SMFC2_DEST_SEL_OFFSET = 7,
FS_SMFC3_DEST_SEL_MASK = 0x00003800,
FS_SMFC3_DEST_SEL_OFFSET = 11,
FS_DC1_SRC_SEL_MASK = 0x00F00000,
FS_DC1_SRC_SEL_OFFSET = 20,
FS_DC2_SRC_SEL_MASK = 0x000F0000,
FS_DC2_SRC_SEL_OFFSET = 16,
FS_DP_SYNC0_SRC_SEL_MASK = 0x0000000F,
FS_DP_SYNC0_SRC_SEL_OFFSET = 0,
FS_DP_SYNC1_SRC_SEL_MASK = 0x000000F0,
FS_DP_SYNC1_SRC_SEL_OFFSET = 4,
FS_DP_ASYNC0_SRC_SEL_MASK = 0x00000F00,
FS_DP_ASYNC0_SRC_SEL_OFFSET = 8,
FS_DP_ASYNC1_SRC_SEL_MASK = 0x0000F000,
FS_DP_ASYNC1_SRC_SEL_OFFSET = 12,
FS_AUTO_REF_PER_MASK = 0,
FS_AUTO_REF_PER_OFFSET = 16,
TSTAT_VF_MASK = 0x0000000C,
TSTAT_VF_OFFSET = 2,
TSTAT_VF_ROT_MASK = 0x00000300,
TSTAT_VF_ROT_OFFSET = 8,
TSTAT_ENC_MASK = 0x00000003,
TSTAT_ENC_OFFSET = 0,
TSTAT_ENC_ROT_MASK = 0x000000C0,
TSTAT_ENC_ROT_OFFSET = 6,
TSTAT_PP_MASK = 0x00000030,
TSTAT_PP_OFFSET = 4,
TSTAT_PP_ROT_MASK = 0x00000C00,
TSTAT_PP_ROT_OFFSET = 10,
TASK_STAT_IDLE = 0,
TASK_STAT_ACTIVE = 1,
TASK_STAT_WAIT4READY = 2,
/* IDMAC register bits */
IDMAC_CONF_USED_BUFS_EN_R = 0x02000000,
IDMAC_CONF_USED_BUFS_MAX_R_MASK = 0x01E00000,
IDMAC_CONF_USED_BUFS_MAX_R_OFFSET = 21,
IDMAC_CONF_USED_BUFS_EN_W = 0x00100000,
IDMAC_CONF_USED_BUFS_MAX_W_MASK = 0x000E0000,
IDMAC_CONF_USED_BUFS_MAX_W_OFFSET = 17,
/* Image Converter Register bits */
IC_CONF_PRPENC_EN = 0x00000001,
IC_CONF_PRPENC_CSC1 = 0x00000002,
IC_CONF_PRPENC_ROT_EN = 0x00000004,
IC_CONF_PRPVF_EN = 0x00000100,
IC_CONF_PRPVF_CSC1 = 0x00000200,
IC_CONF_PRPVF_CSC2 = 0x00000400,
IC_CONF_PRPVF_CMB = 0x00000800,
IC_CONF_PRPVF_ROT_EN = 0x00001000,
IC_CONF_PP_EN = 0x00010000,
IC_CONF_PP_CSC1 = 0x00020000,
IC_CONF_PP_CSC2 = 0x00040000,
IC_CONF_PP_CMB = 0x00080000,
IC_CONF_PP_ROT_EN = 0x00100000,
IC_CONF_IC_GLB_LOC_A = 0x10000000,
IC_CONF_KEY_COLOR_EN = 0x20000000,
IC_CONF_RWS_EN = 0x40000000,
IC_CONF_CSI_MEM_WR_EN = 0x80000000,
IC_RSZ_MAX_RESIZE_RATIO = 0x00004000,
IC_IDMAC_1_CB0_BURST_16 = 0x00000001,
IC_IDMAC_1_CB1_BURST_16 = 0x00000002,
IC_IDMAC_1_CB2_BURST_16 = 0x00000004,
IC_IDMAC_1_CB3_BURST_16 = 0x00000008,
IC_IDMAC_1_CB4_BURST_16 = 0x00000010,
IC_IDMAC_1_CB5_BURST_16 = 0x00000020,
IC_IDMAC_1_CB6_BURST_16 = 0x00000040,
IC_IDMAC_1_CB7_BURST_16 = 0x00000080,
IC_IDMAC_1_PRPENC_ROT_MASK = 0x00003800,
IC_IDMAC_1_PRPENC_ROT_OFFSET = 11,
IC_IDMAC_1_PRPVF_ROT_MASK = 0x0001C000,
IC_IDMAC_1_PRPVF_ROT_OFFSET = 14,
IC_IDMAC_1_PP_ROT_MASK = 0x000E0000,
IC_IDMAC_1_PP_ROT_OFFSET = 17,
IC_IDMAC_1_PP_FLIP_RS = 0x00400000,
IC_IDMAC_1_PRPVF_FLIP_RS = 0x00200000,
IC_IDMAC_1_PRPENC_FLIP_RS = 0x00100000,
IC_IDMAC_2_PRPENC_HEIGHT_MASK = 0x000003FF,
IC_IDMAC_2_PRPENC_HEIGHT_OFFSET = 0,
IC_IDMAC_2_PRPVF_HEIGHT_MASK = 0x000FFC00,
IC_IDMAC_2_PRPVF_HEIGHT_OFFSET = 10,
IC_IDMAC_2_PP_HEIGHT_MASK = 0x3FF00000,
IC_IDMAC_2_PP_HEIGHT_OFFSET = 20,
IC_IDMAC_3_PRPENC_WIDTH_MASK = 0x000003FF,
IC_IDMAC_3_PRPENC_WIDTH_OFFSET = 0,
IC_IDMAC_3_PRPVF_WIDTH_MASK = 0x000FFC00,
IC_IDMAC_3_PRPVF_WIDTH_OFFSET = 10,
IC_IDMAC_3_PP_WIDTH_MASK = 0x3FF00000,
IC_IDMAC_3_PP_WIDTH_OFFSET = 20,
CSI_SENS_CONF_DATA_FMT_SHIFT = 8,
CSI_SENS_CONF_DATA_FMT_MASK = 0x00000700,
CSI_SENS_CONF_DATA_FMT_RGB_YUV444 = 0L,
CSI_SENS_CONF_DATA_FMT_YUV422_YUYV = 1L,
CSI_SENS_CONF_DATA_FMT_YUV422_UYVY = 2L,
CSI_SENS_CONF_DATA_FMT_BAYER = 3L,
CSI_SENS_CONF_DATA_FMT_RGB565 = 4L,
CSI_SENS_CONF_DATA_FMT_RGB555 = 5L,
CSI_SENS_CONF_DATA_FMT_RGB444 = 6L,
CSI_SENS_CONF_DATA_FMT_JPEG = 7L,
CSI_SENS_CONF_VSYNC_POL_SHIFT = 0,
CSI_SENS_CONF_HSYNC_POL_SHIFT = 1,
CSI_SENS_CONF_DATA_POL_SHIFT = 2,
CSI_SENS_CONF_PIX_CLK_POL_SHIFT = 3,
CSI_SENS_CONF_SENS_PRTCL_MASK = 0x00000070L,
CSI_SENS_CONF_SENS_PRTCL_SHIFT = 4,
CSI_SENS_CONF_PACK_TIGHT_SHIFT = 7,
CSI_SENS_CONF_DATA_WIDTH_SHIFT = 11,
CSI_SENS_CONF_EXT_VSYNC_SHIFT = 15,
CSI_SENS_CONF_DIVRATIO_SHIFT = 16,
CSI_SENS_CONF_DIVRATIO_MASK = 0x00FF0000L,
CSI_SENS_CONF_DATA_DEST_SHIFT = 24,
CSI_SENS_CONF_DATA_DEST_MASK = 0x07000000L,
CSI_SENS_CONF_JPEG8_EN_SHIFT = 27,
CSI_SENS_CONF_JPEG_EN_SHIFT = 28,
CSI_SENS_CONF_FORCE_EOF_SHIFT = 29,
CSI_SENS_CONF_DATA_EN_POL_SHIFT = 31,
CSI_DATA_DEST_ISP = 1L,
CSI_DATA_DEST_IC = 2L,
CSI_DATA_DEST_IDMAC = 4L,
CSI_CCIR_ERR_DET_EN = 0x01000000L,
CSI_HORI_DOWNSIZE_EN = 0x80000000L,
CSI_VERT_DOWNSIZE_EN = 0x40000000L,
CSI_TEST_GEN_MODE_EN = 0x01000000L,
CSI_HSC_MASK = 0x1FFF0000,
CSI_HSC_SHIFT = 16,
CSI_VSC_MASK = 0x00000FFF,
CSI_VSC_SHIFT = 0,
CSI_TEST_GEN_R_MASK = 0x000000FFL,
CSI_TEST_GEN_R_SHIFT = 0,
CSI_TEST_GEN_G_MASK = 0x0000FF00L,
CSI_TEST_GEN_G_SHIFT = 8,
CSI_TEST_GEN_B_MASK = 0x00FF0000L,
CSI_TEST_GEN_B_SHIFT = 16,
CSI_MIPI_DI0_MASK = 0x000000FFL,
CSI_MIPI_DI0_SHIFT = 0,
CSI_MIPI_DI1_MASK = 0x0000FF00L,
CSI_MIPI_DI1_SHIFT = 8,
CSI_MIPI_DI2_MASK = 0x00FF0000L,
CSI_MIPI_DI2_SHIFT = 16,
CSI_MIPI_DI3_MASK = 0xFF000000L,
CSI_MIPI_DI3_SHIFT = 24,
CSI_MAX_RATIO_SKIP_ISP_MASK = 0x00070000L,
CSI_MAX_RATIO_SKIP_ISP_SHIFT = 16,
CSI_SKIP_ISP_MASK = 0x00F80000L,
CSI_SKIP_ISP_SHIFT = 19,
CSI_MAX_RATIO_SKIP_SMFC_MASK = 0x00000007L,
CSI_MAX_RATIO_SKIP_SMFC_SHIFT = 0,
CSI_SKIP_SMFC_MASK = 0x000000F8L,
CSI_SKIP_SMFC_SHIFT = 3,
CSI_ID_2_SKIP_MASK = 0x00000300L,
CSI_ID_2_SKIP_SHIFT = 8,
CSI_COLOR_FIRST_ROW_MASK = 0x00000002L,
CSI_COLOR_FIRST_COMP_MASK = 0x00000001L,
SMFC_MAP_CH0_MASK = 0x00000007L,
SMFC_MAP_CH0_SHIFT = 0,
SMFC_MAP_CH1_MASK = 0x00000038L,
SMFC_MAP_CH1_SHIFT = 3,
SMFC_MAP_CH2_MASK = 0x000001C0L,
SMFC_MAP_CH2_SHIFT = 6,
SMFC_MAP_CH3_MASK = 0x00000E00L,
SMFC_MAP_CH3_SHIFT = 9,
SMFC_WM0_SET_MASK = 0x00000007L,
SMFC_WM0_SET_SHIFT = 0,
SMFC_WM1_SET_MASK = 0x000001C0L,
SMFC_WM1_SET_SHIFT = 6,
SMFC_WM2_SET_MASK = 0x00070000L,
SMFC_WM2_SET_SHIFT = 16,
SMFC_WM3_SET_MASK = 0x01C00000L,
SMFC_WM3_SET_SHIFT = 22,
SMFC_WM0_CLR_MASK = 0x00000038L,
SMFC_WM0_CLR_SHIFT = 3,
SMFC_WM1_CLR_MASK = 0x00000E00L,
SMFC_WM1_CLR_SHIFT = 9,
SMFC_WM2_CLR_MASK = 0x00380000L,
SMFC_WM2_CLR_SHIFT = 19,
SMFC_WM3_CLR_MASK = 0x0E000000L,
SMFC_WM3_CLR_SHIFT = 25,
SMFC_BS0_MASK = 0x0000000FL,
SMFC_BS0_SHIFT = 0,
SMFC_BS1_MASK = 0x000000F0L,
SMFC_BS1_SHIFT = 4,
SMFC_BS2_MASK = 0x00000F00L,
SMFC_BS2_SHIFT = 8,
SMFC_BS3_MASK = 0x0000F000L,
SMFC_BS3_SHIFT = 12,
PF_CONF_TYPE_MASK = 0x00000007,
PF_CONF_TYPE_SHIFT = 0,
PF_CONF_PAUSE_EN = 0x00000010,
PF_CONF_RESET = 0x00008000,
PF_CONF_PAUSE_ROW_MASK = 0x00FF0000,
PF_CONF_PAUSE_ROW_SHIFT = 16,
DI_DW_GEN_ACCESS_SIZE_OFFSET = 24,
DI_DW_GEN_COMPONENT_SIZE_OFFSET = 16,
DI_GEN_DI_CLK_EXT = 0x100000,
DI_GEN_POLARITY_DISP_CLK = 0x00020000,
DI_GEN_POLARITY_1 = 0x00000001,
DI_GEN_POLARITY_2 = 0x00000002,
DI_GEN_POLARITY_3 = 0x00000004,
DI_GEN_POLARITY_4 = 0x00000008,
DI_GEN_POLARITY_5 = 0x00000010,
DI_GEN_POLARITY_6 = 0x00000020,
DI_GEN_POLARITY_7 = 0x00000040,
DI_GEN_POLARITY_8 = 0x00000080,
DI_POL_DRDY_DATA_POLARITY = 0x00000080,
DI_POL_DRDY_POLARITY_15 = 0x00000010,
DI_VSYNC_SEL_OFFSET = 13,
DC_WR_CH_CONF_FIELD_MODE = 0x00000200,
DC_WR_CH_CONF_PROG_TYPE_OFFSET = 5,
DC_WR_CH_CONF_PROG_TYPE_MASK = 0x000000E0,
DC_WR_CH_CONF_PROG_DI_ID = 0x00000004,
DC_WR_CH_CONF_PROG_DISP_ID_OFFSET = 3,
DC_WR_CH_CONF_PROG_DISP_ID_MASK = 0x00000018,
DC_UGDE_0_ODD_EN = 0x02000000,
DC_UGDE_0_ID_CODED_MASK = 0x00000007,
DC_UGDE_0_ID_CODED_OFFSET = 0,
DC_UGDE_0_EV_PRIORITY_MASK = 0x00000078,
DC_UGDE_0_EV_PRIORITY_OFFSET = 3,
DP_COM_CONF_FG_EN = 0x00000001,
DP_COM_CONF_GWSEL = 0x00000002,
DP_COM_CONF_GWAM = 0x00000004,
DP_COM_CONF_GWCKE = 0x00000008,
DP_COM_CONF_CSC_DEF_MASK = 0x00000300,
DP_COM_CONF_CSC_DEF_OFFSET = 8,
DP_COM_CONF_CSC_DEF_FG = 0x00000300,
DP_COM_CONF_CSC_DEF_BG = 0x00000200,
DP_COM_CONF_CSC_DEF_BOTH = 0x00000100,
DP_COM_CONF_GAMMA_EN = 0x00001000,
DP_COM_CONF_GAMMA_YUV_EN = 0x00002000,
DI_SER_CONF_LLA_SER_ACCESS = 0x00000020,
DI_SER_CONF_SERIAL_CLK_POL = 0x00000010,
DI_SER_CONF_SERIAL_DATA_POL = 0x00000008,
DI_SER_CONF_SERIAL_RS_POL = 0x00000004,
DI_SER_CONF_SERIAL_CS_POL = 0x00000002,
DI_SER_CONF_WAIT4SERIAL = 0x00000001,
VDI_C_CH_420 = 0x00000000,
VDI_C_CH_422 = 0x00000002,
VDI_C_MOT_SEL_FULL = 0x00000008,
VDI_C_MOT_SEL_LOW = 0x00000004,
VDI_C_MOT_SEL_MED = 0x00000000,
VDI_C_BURST_SIZE1_4 = 0x00000030,
VDI_C_BURST_SIZE2_4 = 0x00000300,
VDI_C_BURST_SIZE3_4 = 0x00003000,
VDI_C_BURST_SIZE_MASK = 0xF,
VDI_C_BURST_SIZE1_OFFSET = 4,
VDI_C_BURST_SIZE2_OFFSET = 8,
VDI_C_BURST_SIZE3_OFFSET = 12,
VDI_C_VWM1_SET_1 = 0x00000000,
VDI_C_VWM1_SET_2 = 0x00010000,
VDI_C_VWM1_CLR_2 = 0x00080000,
VDI_C_VWM3_SET_1 = 0x00000000,
VDI_C_VWM3_SET_2 = 0x00400000,
VDI_C_VWM3_CLR_2 = 0x02000000,
VDI_C_TOP_FIELD_MAN_1 = 0x40000000,
VDI_C_TOP_FIELD_AUTO_1 = 0x80000000,
};
enum di_pins {
DI_PIN11 = 0,
DI_PIN12 = 1,
DI_PIN13 = 2,
DI_PIN14 = 3,
DI_PIN15 = 4,
DI_PIN16 = 5,
DI_PIN17 = 6,
DI_PIN_CS = 7,
DI_PIN_SER_CLK = 0,
DI_PIN_SER_RS = 1,
};
enum di_sync_wave {
DI_SYNC_NONE = -1,
DI_SYNC_CLK = 0,
DI_SYNC_INT_HSYNC = 1,
DI_SYNC_HSYNC = 2,
DI_SYNC_VSYNC = 3,
DI_SYNC_DE = 5,
};
/* DC template opcodes */
#define WROD(lf) (0x18 | ((lf) << 1))
#define WRG (0x01)
#endif

View File

@ -0,0 +1,480 @@
/*
* Freescale PRE Register Definitions
*
* Copyright 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef __ARCH_ARM___PRE_H
#define __ARCH_ARM___PRE_H
#define HW_PRE_CTRL (0x00000000)
#define HW_PRE_CTRL_SET (0x00000004)
#define HW_PRE_CTRL_CLR (0x00000008)
#define HW_PRE_CTRL_TOG (0x0000000c)
#define BM_PRE_CTRL_SFTRST 0x80000000
#define BF_PRE_CTRL_SFTRST(v) \
(((v) << 31) & BM_PRE_CTRL_SFTRST)
#define BM_PRE_CTRL_CLKGATE 0x40000000
#define BF_PRE_CTRL_CLKGATE(v) \
(((v) << 30) & BM_PRE_CTRL_CLKGATE)
#define BM_PRE_CTRL_TPR_RESET_SEL 0x20000000
#define BF_PRE_CTRL_TPR_RESET_SEL(v) \
(((v) << 29) & BM_PRE_CTRL_TPR_RESET_SEL)
#define BM_PRE_CTRL_EN_REPEAT 0x10000000
#define BF_PRE_CTRL_EN_REPEAT(v) \
(((v) << 28) & BM_PRE_CTRL_EN_REPEAT)
#define BP_PRE_CTRL_RSVD2 16
#define BM_PRE_CTRL_RSVD2 0x0FFF0000
#define BF_PRE_CTRL_RSVD2(v) \
(((v) << 16) & BM_PRE_CTRL_RSVD2)
#define BP_PRE_CTRL_RSVD1 12
#define BM_PRE_CTRL_RSVD1 0x0000F000
#define BF_PRE_CTRL_RSVD1(v) \
(((v) << 12) & BM_PRE_CTRL_RSVD1)
#define BM_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN 0x00000800
#define BF_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN(v) \
(((v) << 11) & BM_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN)
#define BV_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN__0 0x0
#define BV_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN__1 0x1
#define BP_PRE_CTRL_HANDSHAKE_LINE_NUM 9
#define BM_PRE_CTRL_HANDSHAKE_LINE_NUM 0x00000600
#define BF_PRE_CTRL_HANDSHAKE_LINE_NUM(v) \
(((v) << 9) & BM_PRE_CTRL_HANDSHAKE_LINE_NUM)
#define BV_PRE_CTRL_HANDSHAKE_LINE_NUM__0 0x0
#define BV_PRE_CTRL_HANDSHAKE_LINE_NUM__1 0x1
#define BV_PRE_CTRL_HANDSHAKE_LINE_NUM__2 0x2
#define BM_PRE_CTRL_HANDSHAKE_EN 0x00000100
#define BF_PRE_CTRL_HANDSHAKE_EN(v) \
(((v) << 8) & BM_PRE_CTRL_HANDSHAKE_EN)
#define BV_PRE_CTRL_HANDSHAKE_EN__0 0x0
#define BV_PRE_CTRL_HANDSHAKE_EN__1 0x1
#define BM_PRE_CTRL_INTERLACED_FIELD 0x00000080
#define BF_PRE_CTRL_INTERLACED_FIELD(v) \
(((v) << 7) & BM_PRE_CTRL_INTERLACED_FIELD)
#define BM_PRE_CTRL_SO 0x00000040
#define BF_PRE_CTRL_SO(v) \
(((v) << 6) & BM_PRE_CTRL_SO)
#define BM_PRE_CTRL_VFLIP 0x00000020
#define BF_PRE_CTRL_VFLIP(v) \
(((v) << 5) & BM_PRE_CTRL_VFLIP)
#define BM_PRE_CTRL_SDW_UPDATE 0x00000010
#define BF_PRE_CTRL_SDW_UPDATE(v) \
(((v) << 4) & BM_PRE_CTRL_SDW_UPDATE)
#define BM_PRE_CTRL_RSVD0 0x00000008
#define BF_PRE_CTRL_RSVD0(v) \
(((v) << 3) & BM_PRE_CTRL_RSVD0)
#define BM_PRE_CTRL_BLOCK_16 0x00000004
#define BF_PRE_CTRL_BLOCK_16(v) \
(((v) << 2) & BM_PRE_CTRL_BLOCK_16)
#define BV_PRE_CTRL_BLOCK_16__32x4 0x0
#define BV_PRE_CTRL_BLOCK_16__16x4 0x1
#define BM_PRE_CTRL_BLOCK_EN 0x00000002
#define BF_PRE_CTRL_BLOCK_EN(v) \
(((v) << 1) & BM_PRE_CTRL_BLOCK_EN)
#define BV_PRE_CTRL_BLOCK_EN__0 0x0
#define BV_PRE_CTRL_BLOCK_EN__1 0x1
#define BM_PRE_CTRL_ENABLE 0x00000001
#define BF_PRE_CTRL_ENABLE(v) \
(((v) << 0) & BM_PRE_CTRL_ENABLE)
#define HW_PRE_IRQ_MASK (0x00000010)
#define HW_PRE_IRQ_MASK_SET (0x00000014)
#define HW_PRE_IRQ_MASK_CLR (0x00000018)
#define HW_PRE_IRQ_MASK_TOG (0x0000001c)
#define BP_PRE_IRQ_MASK_RSVD1 4
#define BM_PRE_IRQ_MASK_RSVD1 0xFFFFFFF0
#define BF_PRE_IRQ_MASK_RSVD1(v) \
(((v) << 4) & BM_PRE_IRQ_MASK_RSVD1)
#define BM_PRE_IRQ_MASK_TPR_RD_NUM_BYTES_OVFL_IRQ_EN 0x00000008
#define BF_PRE_IRQ_MASK_TPR_RD_NUM_BYTES_OVFL_IRQ_EN(v) \
(((v) << 3) & BM_PRE_IRQ_MASK_TPR_RD_NUM_BYTES_OVFL_IRQ_EN)
#define BM_PRE_IRQ_MASK_HANDSHAKE_ABORT_IRQ_EN 0x00000004
#define BF_PRE_IRQ_MASK_HANDSHAKE_ABORT_IRQ_EN(v) \
(((v) << 2) & BM_PRE_IRQ_MASK_HANDSHAKE_ABORT_IRQ_EN)
#define BM_PRE_IRQ_MASK_STORE_IRQ_EN 0x00000002
#define BF_PRE_IRQ_MASK_STORE_IRQ_EN(v) \
(((v) << 1) & BM_PRE_IRQ_MASK_STORE_IRQ_EN)
#define BM_PRE_IRQ_MASK_PREFETCH_IRQ_EN 0x00000001
#define BF_PRE_IRQ_MASK_PREFETCH_IRQ_EN(v) \
(((v) << 0) & BM_PRE_IRQ_MASK_PREFETCH_IRQ_EN)
#define HW_PRE_IRQ (0x00000020)
#define HW_PRE_IRQ_SET (0x00000024)
#define HW_PRE_IRQ_CLR (0x00000028)
#define HW_PRE_IRQ_TOG (0x0000002c)
#define BP_PRE_IRQ_RSVD1 14
#define BM_PRE_IRQ_RSVD1 0xFFFFC000
#define BF_PRE_IRQ_RSVD1(v) \
(((v) << 14) & BM_PRE_IRQ_RSVD1)
#define BP_PRE_IRQ_AXI_ERROR_ID 10
#define BM_PRE_IRQ_AXI_ERROR_ID 0x00003C00
#define BF_PRE_IRQ_AXI_ERROR_ID(v) \
(((v) << 10) & BM_PRE_IRQ_AXI_ERROR_ID)
#define BM_PRE_IRQ_AXI_READ_ERROR 0x00000200
#define BF_PRE_IRQ_AXI_READ_ERROR(v) \
(((v) << 9) & BM_PRE_IRQ_AXI_READ_ERROR)
#define BM_PRE_IRQ_AXI_WRITE_ERROR 0x00000100
#define BF_PRE_IRQ_AXI_WRITE_ERROR(v) \
(((v) << 8) & BM_PRE_IRQ_AXI_WRITE_ERROR)
#define BP_PRE_IRQ_RSVD0 5
#define BM_PRE_IRQ_RSVD0 0x000000E0
#define BF_PRE_IRQ_RSVD0(v) \
(((v) << 5) & BM_PRE_IRQ_RSVD0)
#define BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ 0x00000010
#define BF_PRE_IRQ_HANDSHAKE_ERROR_IRQ(v) \
(((v) << 4) & BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ)
#define BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ 0x00000008
#define BF_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ(v) \
(((v) << 3) & BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ)
#define BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ 0x00000004
#define BF_PRE_IRQ_HANDSHAKE_ABORT_IRQ(v) \
(((v) << 2) & BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ)
#define BM_PRE_IRQ_STORE_IRQ 0x00000002
#define BF_PRE_IRQ_STORE_IRQ(v) \
(((v) << 1) & BM_PRE_IRQ_STORE_IRQ)
#define BM_PRE_IRQ_PREFETCH_IRQ 0x00000001
#define BF_PRE_IRQ_PREFETCH_IRQ(v) \
(((v) << 0) & BM_PRE_IRQ_PREFETCH_IRQ)
#define HW_PRE_CUR_BUF (0x00000030)
#define BP_PRE_CUR_BUF_ADDR 0
#define BM_PRE_CUR_BUF_ADDR 0xFFFFFFFF
#define BF_PRE_CUR_BUF_ADDR(v) (v)
#define HW_PRE_NEXT_BUF (0x00000040)
#define BP_PRE_NEXT_BUF_ADDR 0
#define BM_PRE_NEXT_BUF_ADDR 0xFFFFFFFF
#define BF_PRE_NEXT_BUF_ADDR(v) (v)
#define HW_PRE_U_BUF_OFFSET (0x00000050)
#define BP_PRE_U_BUF_OFFSET_RSVD0 25
#define BM_PRE_U_BUF_OFFSET_RSVD0 0xFE000000
#define BF_PRE_U_BUF_OFFSET_RSVD0(v) \
(((v) << 25) & BM_PRE_U_BUF_OFFSET_RSVD0)
#define BP_PRE_U_BUF_OFFSET_UBO 0
#define BM_PRE_U_BUF_OFFSET_UBO 0x01FFFFFF
#define BF_PRE_U_BUF_OFFSET_UBO(v) \
(((v) << 0) & BM_PRE_U_BUF_OFFSET_UBO)
#define HW_PRE_V_BUF_OFFSET (0x00000060)
#define BP_PRE_V_BUF_OFFSET_RSVD0 25
#define BM_PRE_V_BUF_OFFSET_RSVD0 0xFE000000
#define BF_PRE_V_BUF_OFFSET_RSVD0(v) \
(((v) << 25) & BM_PRE_V_BUF_OFFSET_RSVD0)
#define BP_PRE_V_BUF_OFFSET_VBO 0
#define BM_PRE_V_BUF_OFFSET_VBO 0x01FFFFFF
#define BF_PRE_V_BUF_OFFSET_VBO(v) \
(((v) << 0) & BM_PRE_V_BUF_OFFSET_VBO)
#define HW_PRE_TPR_CTRL (0x00000070)
#define HW_PRE_TPR_CTRL_SET (0x00000074)
#define HW_PRE_TPR_CTRL_CLR (0x00000078)
#define HW_PRE_TPR_CTRL_TOG (0x0000007c)
#define BP_PRE_TPR_CTRL_RSVD 8
#define BM_PRE_TPR_CTRL_RSVD 0xFFFFFF00
#define BF_PRE_TPR_CTRL_RSVD(v) \
(((v) << 8) & BM_PRE_TPR_CTRL_RSVD)
#define BP_PRE_TPR_CTRL_TILE_FORMAT 0
#define BM_PRE_TPR_CTRL_TILE_FORMAT 0x000000FF
#define BF_PRE_TPR_CTRL_TILE_FORMAT(v) \
(((v) << 0) & BM_PRE_TPR_CTRL_TILE_FORMAT)
#define BV_PRE_TPR_CTRL_TILE_FORMAT__BYPASS 0x00
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_SB_ST 0x10
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_SB_SRT 0x50
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_ST 0x20
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_SRT 0x60
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_MST 0xA0
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_MSRT 0xE0
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_SB_ST 0x11
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_SB_SRT 0x51
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_ST 0x21
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_SRT 0x61
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_MST 0xA1
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_MSRT 0xE1
#define BV_PRE_TPR_CTRL_TILE_FORMAT__VPU8_PRO 0x22
#define BV_PRE_TPR_CTRL_TILE_FORMAT__VPU8_SB_INT 0x13
#define HW_PRE_PREFETCH_ENGINE_CTRL (0x00000080)
#define HW_PRE_PREFETCH_ENGINE_CTRL_SET (0x00000084)
#define HW_PRE_PREFETCH_ENGINE_CTRL_CLR (0x00000088)
#define HW_PRE_PREFETCH_ENGINE_CTRL_TOG (0x0000008c)
#define BP_PRE_PREFETCH_ENGINE_CTRL_RSVD1 16
#define BM_PRE_PREFETCH_ENGINE_CTRL_RSVD1 0xFFFF0000
#define BF_PRE_PREFETCH_ENGINE_CTRL_RSVD1(v) \
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_CTRL_RSVD1)
#define BM_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN 0x00008000
#define BF_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN(v) \
(((v) << 15) & BM_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN)
#define BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP 0x00004000
#define BF_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP(v) \
(((v) << 14) & BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP)
#define BM_PRE_PREFETCH_ENGINE_CTRL_CROP_EN 0x00002000
#define BF_PRE_PREFETCH_ENGINE_CTRL_CROP_EN(v) \
(((v) << 13) & BM_PRE_PREFETCH_ENGINE_CTRL_CROP_EN)
#define BV_PRE_PREFETCH_ENGINE_CTRL_CROP_EN__0 0x0
#define BV_PRE_PREFETCH_ENGINE_CTRL_CROP_EN__1 0x1
#define BM_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE 0x00001000
#define BF_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE(v) \
(((v) << 12) & BM_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE)
#define BV_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE__0 0x0
#define BV_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE__1 0x1
#define BM_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS 0x00000800
#define BF_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS(v) \
(((v) << 11) & BM_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS)
#define BV_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS__0 0x0
#define BV_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS__1 0x1
#define BP_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT 8
#define BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT 0x00000700
#define BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(v) \
(((v) << 8) & BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT)
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__0 0x0
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__1 0x1
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__2 0x2
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__3 0x3
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__4 0x4
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__5 0x5
#define BP_PRE_PREFETCH_ENGINE_CTRL_RSVD0 6
#define BM_PRE_PREFETCH_ENGINE_CTRL_RSVD0 0x000000C0
#define BF_PRE_PREFETCH_ENGINE_CTRL_RSVD0(v) \
(((v) << 6) & BM_PRE_PREFETCH_ENGINE_CTRL_RSVD0)
#define BP_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP 4
#define BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP 0x00000030
#define BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(v) \
(((v) << 4) & BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP)
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__0 0x0
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__1 0x1
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__2 0x2
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__3 0x3
#define BP_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES 1
#define BM_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES 0x0000000E
#define BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(v) \
(((v) << 1) & BM_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES)
#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__8_bytes 0x0
#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__16_bytes 0x1
#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__32_bytes 0x2
#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__64_bytes 0x3
#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__128_bytes 0x4
#define BM_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN 0x00000001
#define BF_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN(v) \
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN)
#define BV_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN__0 0x0
#define BV_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN__1 0x1
#define HW_PRE_PREFETCH_ENGINE_STATUS (0x00000090)
#define BP_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y 16
#define BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y 0x3FFF0000
#define BF_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y(v) \
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y)
#define BP_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X 0
#define BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X 0x0000FFFF
#define BF_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X(v) \
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X)
#define HW_PRE_PREFETCH_ENGINE_INPUT_SIZE (0x000000a0)
#define BP_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT 16
#define BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT 0xFFFF0000
#define BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT(v) \
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT)
#define BP_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH 0
#define BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH 0x0000FFFF
#define BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH(v) \
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH)
#define HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC (0x000000b0)
#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y 16
#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y 0xFFFF0000
#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y(v) \
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y)
#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X 0
#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X 0x0000FFFF
#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X(v) \
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X)
#define HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC (0x000000c0)
#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y 16
#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y 0xFFFF0000
#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y(v) \
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y)
#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X 0
#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X 0x0000FFFF
#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X(v) \
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X)
#define HW_PRE_PREFETCH_ENGINE_PITCH (0x000000d0)
#define BP_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH 16
#define BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH 0xFFFF0000
#define BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH(v) \
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH)
#define BP_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH 0
#define BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH 0x0000FFFF
#define BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH(v) \
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH)
#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET (0x000000e0)
#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_SET (0x000000e4)
#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_CLR (0x000000e8)
#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_TOG (0x000000ec)
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0 29
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0 0xE0000000
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0(v) \
(((v) << 29) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0)
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3 24
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3 0x1F000000
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3(v) \
(((v) << 24) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3)
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1 21
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1 0x00E00000
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1(v) \
(((v) << 21) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1)
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2 16
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2 0x001F0000
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2(v) \
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2)
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2 13
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2 0x0000E000
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2(v) \
(((v) << 13) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2)
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1 8
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1 0x00001F00
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1(v) \
(((v) << 8) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1)
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3 5
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3 0x000000E0
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3(v) \
(((v) << 5) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3)
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0 0
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0 0x0000001F
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0(v) \
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0)
#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH (0x000000f0)
#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_SET (0x000000f4)
#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_CLR (0x000000f8)
#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_TOG (0x000000fc)
#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0 16
#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0 0xFFFF0000
#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0(v) \
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0)
#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3 12
#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3 0x0000F000
#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3(v) \
(((v) << 12) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3)
#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2 8
#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2 0x00000F00
#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2(v) \
(((v) << 8) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2)
#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1 4
#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1 0x000000F0
#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1(v) \
(((v) << 4) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1)
#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0 0
#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0 0x0000000F
#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0(v) \
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0)
#define HW_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET (0x00000100)
#define BP_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0 23
#define BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0 0xFF800000
#define BF_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0(v) \
(((v) << 23) & BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0)
#define BP_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET 0
#define BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET 0xFFFFFFFF
#define BF_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET(v) \
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET)
#define HW_PRE_STORE_ENGINE_CTRL (0x00000110)
#define HW_PRE_STORE_ENGINE_CTRL_SET (0x00000114)
#define HW_PRE_STORE_ENGINE_CTRL_CLR (0x00000118)
#define HW_PRE_STORE_ENGINE_CTRL_TOG (0x0000011c)
#define BP_PRE_STORE_ENGINE_CTRL_RSVD0 6
#define BM_PRE_STORE_ENGINE_CTRL_RSVD0 0xFFFFFFC0
#define BF_PRE_STORE_ENGINE_CTRL_RSVD0(v) \
(((v) << 6) & BM_PRE_STORE_ENGINE_CTRL_RSVD0)
#define BP_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP 4
#define BM_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP 0x00000030
#define BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(v) \
(((v) << 4) & BM_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP)
#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__8_bits 0x0
#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__16_bits 0x1
#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__32_bits 0x2
#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__64_bits 0x3
#define BP_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES 1
#define BM_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES 0x0000000E
#define BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(v) \
(((v) << 1) & BM_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES)
#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__8_bytes 0x0
#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__16_bytes 0x1
#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__32_bytes 0x2
#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__64_bytes 0x3
#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__128_bytes 0x4
#define BM_PRE_STORE_ENGINE_CTRL_STORE_EN 0x00000001
#define BF_PRE_STORE_ENGINE_CTRL_STORE_EN(v) \
(((v) << 0) & BM_PRE_STORE_ENGINE_CTRL_STORE_EN)
#define BV_PRE_STORE_ENGINE_CTRL_STORE_EN__0 0x0
#define BV_PRE_STORE_ENGINE_CTRL_STORE_EN__1 0x1
#define HW_PRE_STORE_ENGINE_STATUS (0x00000120)
#define BP_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y 16
#define BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y 0x3FFF0000
#define BF_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y(v) \
(((v) << 16) & BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y)
#define BP_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X 0
#define BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X 0x0000FFFF
#define BF_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X(v) \
(((v) << 0) & BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X)
#define HW_PRE_STORE_ENGINE_SIZE (0x00000130)
#define BP_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT 16
#define BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT 0xFFFF0000
#define BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT(v) \
(((v) << 16) & BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT)
#define BP_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH 0
#define BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH 0x0000FFFF
#define BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH(v) \
(((v) << 0) & BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH)
#define HW_PRE_STORE_ENGINE_PITCH (0x00000140)
#define BP_PRE_STORE_ENGINE_PITCH_RSVD0 16
#define BM_PRE_STORE_ENGINE_PITCH_RSVD0 0xFFFF0000
#define BF_PRE_STORE_ENGINE_PITCH_RSVD0(v) \
(((v) << 16) & BM_PRE_STORE_ENGINE_PITCH_RSVD0)
#define BP_PRE_STORE_ENGINE_PITCH_OUT_PITCH 0
#define BM_PRE_STORE_ENGINE_PITCH_OUT_PITCH 0x0000FFFF
#define BF_PRE_STORE_ENGINE_PITCH_OUT_PITCH(v) \
(((v) << 0) & BM_PRE_STORE_ENGINE_PITCH_OUT_PITCH)
#define HW_PRE_STORE_ENGINE_ADDR (0x00000150)
#define BP_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR 0
#define BM_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR 0xFFFFFFFF
#define BF_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR(v) (v)
#endif /* __ARCH_ARM___PRE_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,70 @@
/*
* Freescale IPU PRG Register Definitions
*
* Copyright 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/bitops.h>
#ifndef __IPU_PRG_H__
#define __IPU_PRG_H__
#define IPU_PR_CTRL 0x00
#define IPU_PR_STATUS 0x04
#define IPU_PR_QOS 0x08
#define IPU_PR_REG_UPDATE 0x0c
#define IPU_PR_STRIDE(ch) (0x10 + (ch) * 4)
#define IPU_PR_CROP_LINE 0x1c
#define IPU_PR_ADDR_THD 0x20
#define IPU_PR_CH_BADDR(ch) (0x24 + (ch) * 4)
#define IPU_PR_CH_OFFSET(ch) (0x30 + (ch) * 4)
#define IPU_PR_CH_ILO(ch) (0x3c + (ch) * 4)
#define IPU_PR_CH_HEIGHT(ch) (0x48 + (ch) * 4)
#define IPU_PR_CTRL_CH_BYPASS(ch) (0x1 << (ch))
#define IPU_PR_CTRL_SOFT_CH_ARID(ch, n) ((n) << ((ch) * 2 + 8))
#define IPU_PR_CTRL_SOFT_CH_ARID_MASK(ch) (0x3 << ((ch) * 2 + 8))
#define IPU_PR_CTRL_CH_SO(ch, interlace) ((interlace) << ((ch) + 16))
#define IPU_PR_CTRL_CH_SO_MASK(ch) (0x1 << ((ch) + 16))
#define IPU_PR_CTRL_CH_VFLIP(ch, vflip) ((vflip) << ((ch) + 19))
#define IPU_PR_CTRL_CH_VFLIP_MASK(ch) (0x1 << ((ch) + 19))
#define IPU_PR_CTRL_CH_BLOCK_MODE(ch, mode) ((mode) << ((ch) + 22))
#define IPU_PR_CTRL_CH_BLOCK_MODE_MASK(ch) (0x1 << ((ch) + 22))
#define IPU_PR_CTRL_CH_CNT_LOAD_EN(ch) (0x1 << ((ch) + 25))
#define IPU_PR_CTRL_CH_CNT_LOAD_EN_MASK (0x7 << 25)
#define IPU_PR_CTRL_SOFTRST BIT(30)
#define IPU_PR_CTRL_SHADOW_EN BIT(31)
#define IPU_PR_STATUS_BUF_RDY(ch, buf) (1 << ((ch) * 2 + (buf)))
#define IPU_PR_QOS_PRI(id, qos) ((qos) << ((id) * 4))
#define IPU_PR_QOS_MASK(id) (0xf << ((id) * 4))
#define IPU_PR_REG_UPDATE_EN BIT(0)
#define IPU_PR_STRIDE_MASK 0x3fff
#define IPU_PR_CROP_LINE_NUM(ch, n) ((n) << ((ch) * 4))
#define IPU_PR_CROP_LINE_MASK(ch) (0xf << ((ch) * 4))
#define IPU_PR_ADDR_THD_MASK 0xffffffff
#define IPU_PR_CH_BADDR_MASK 0xffffffff
#define IPU_PR_CH_OFFSET_MASK 0xffffffff
#define IPU_PR_CH_ILO_MASK 0x007fffff
#define IPU_PR_CH_ILO_NUM(ilo) ((ilo) & IPU_PR_CH_ILO_MASK)
#define IPU_PR_CH_HEIGHT_MASK 0x00000fff
#define IPU_PR_CH_HEIGHT_NUM(fh) (((fh) - 1) & IPU_PR_CH_HEIGHT_MASK)
#define IPU_PR_CH_IPU_HEIGHT_MASK 0x0fff0000
#define IPU_PR_CH_IPU_HEIGHT_NUM(fh) ((((fh) - 1) << 16) & IPU_PR_CH_IPU_HEIGHT_MASK)
#endif /* __IPU_PRG_H__ */

View File

@ -0,0 +1,506 @@
/*
* Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ipu-v3-prg.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "prg-regs.h"
#define PRG_CHAN_NUM 3
struct prg_chan {
unsigned int pre_num;
struct mutex mutex; /* for in_use */
bool in_use;
};
struct ipu_prg_data {
unsigned int id;
void __iomem *base;
unsigned long memory;
struct clk *axi_clk;
struct clk *apb_clk;
struct list_head list;
struct device *dev;
struct prg_chan chan[PRG_CHAN_NUM];
struct regmap *regmap;
struct regmap_field *pre_prg_sel[2];
spinlock_t lock;
};
static LIST_HEAD(prg_list);
static DEFINE_MUTEX(prg_lock);
static inline void prg_write(struct ipu_prg_data *prg,
u32 value, unsigned int offset)
{
writel(value, prg->base + offset);
}
static inline u32 prg_read(struct ipu_prg_data *prg, unsigned offset)
{
return readl(prg->base + offset);
}
static struct ipu_prg_data *get_prg(unsigned int ipu_id)
{
struct ipu_prg_data *prg;
mutex_lock(&prg_lock);
list_for_each_entry(prg, &prg_list, list) {
if (prg->id == ipu_id) {
mutex_unlock(&prg_lock);
return prg;
}
}
mutex_unlock(&prg_lock);
return NULL;
}
static int assign_prg_chan(struct ipu_prg_data *prg, unsigned int pre_num,
ipu_channel_t ipu_ch)
{
int prg_ch;
if (!prg)
return -EINVAL;
switch (ipu_ch) {
case MEM_BG_SYNC:
prg_ch = 0;
break;
case MEM_FG_SYNC:
prg_ch = 1;
break;
case MEM_DC_SYNC:
prg_ch = 2;
break;
default:
dev_err(prg->dev, "wrong ipu channel type\n");
return -EINVAL;
}
mutex_lock(&prg->chan[prg_ch].mutex);
if (!prg->chan[prg_ch].in_use) {
prg->chan[prg_ch].in_use = true;
prg->chan[prg_ch].pre_num = pre_num;
if (prg_ch != 0) {
unsigned int pmux, psel; /* primary */
unsigned int smux, ssel; /* secondary */
struct regmap_field *pfield, *sfield;
psel = pre_num - 1;
ssel = psel ? 0 : 1;
pfield = prg->pre_prg_sel[psel];
sfield = prg->pre_prg_sel[ssel];
pmux = (prg_ch - 1) + (prg->id << 1);
mutex_lock(&prg_lock);
regmap_field_write(pfield, pmux);
/*
* PRE1 and PRE2 cannot bind with a same channel of
* one PRG even if one of the two PREs is disabled.
*/
regmap_field_read(sfield, &smux);
if (smux == pmux) {
smux = pmux ^ 0x1;
regmap_field_write(sfield, smux);
}
mutex_unlock(&prg_lock);
}
mutex_unlock(&prg->chan[prg_ch].mutex);
dev_dbg(prg->dev, "bind prg%u ch%d with pre%u\n",
prg->id, prg_ch, pre_num);
return prg_ch;
}
mutex_unlock(&prg->chan[prg_ch].mutex);
return -EBUSY;
}
static inline int get_prg_chan(struct ipu_prg_data *prg, unsigned int pre_num)
{
int i;
if (!prg)
return -EINVAL;
for (i = 0; i < PRG_CHAN_NUM; i++) {
mutex_lock(&prg->chan[i].mutex);
if (prg->chan[i].in_use &&
prg->chan[i].pre_num == pre_num) {
mutex_unlock(&prg->chan[i].mutex);
return i;
}
mutex_unlock(&prg->chan[i].mutex);
}
return -ENOENT;
}
int ipu_prg_config(struct ipu_prg_config *config)
{
struct ipu_prg_data *prg = get_prg(config->id);
struct ipu_soc *ipu = ipu_get_soc(config->id);
int prg_ch, axi_id;
u32 reg;
if (!prg || config->crop_line > 3 || !ipu)
return -EINVAL;
if (config->height & ~IPU_PR_CH_HEIGHT_MASK)
return -EINVAL;
prg_ch = assign_prg_chan(prg, config->pre_num, config->ipu_ch);
if (prg_ch < 0)
return prg_ch;
axi_id = ipu_ch_param_get_axi_id(ipu, config->ipu_ch, IPU_INPUT_BUFFER);
clk_prepare_enable(prg->axi_clk);
clk_prepare_enable(prg->apb_clk);
spin_lock(&prg->lock);
/* clear all load enable to impact other channels */
reg = prg_read(prg, IPU_PR_CTRL);
reg &= ~IPU_PR_CTRL_CH_CNT_LOAD_EN_MASK;
prg_write(prg, reg, IPU_PR_CTRL);
/* counter load enable */
reg = prg_read(prg, IPU_PR_CTRL);
reg |= IPU_PR_CTRL_CH_CNT_LOAD_EN(prg_ch);
prg_write(prg, reg, IPU_PR_CTRL);
/* AXI ID */
reg = prg_read(prg, IPU_PR_CTRL);
reg &= ~IPU_PR_CTRL_SOFT_CH_ARID_MASK(prg_ch);
reg |= IPU_PR_CTRL_SOFT_CH_ARID(prg_ch, axi_id);
prg_write(prg, reg, IPU_PR_CTRL);
/* so */
reg = prg_read(prg, IPU_PR_CTRL);
reg &= ~IPU_PR_CTRL_CH_SO_MASK(prg_ch);
reg |= IPU_PR_CTRL_CH_SO(prg_ch, config->so);
prg_write(prg, reg, IPU_PR_CTRL);
/* vflip */
reg = prg_read(prg, IPU_PR_CTRL);
reg &= ~IPU_PR_CTRL_CH_VFLIP_MASK(prg_ch);
reg |= IPU_PR_CTRL_CH_VFLIP(prg_ch, config->vflip);
prg_write(prg, reg, IPU_PR_CTRL);
/* block mode */
reg = prg_read(prg, IPU_PR_CTRL);
reg &= ~IPU_PR_CTRL_CH_BLOCK_MODE_MASK(prg_ch);
reg |= IPU_PR_CTRL_CH_BLOCK_MODE(prg_ch, config->block_mode);
prg_write(prg, reg, IPU_PR_CTRL);
/* disable bypass */
reg = prg_read(prg, IPU_PR_CTRL);
reg &= ~IPU_PR_CTRL_CH_BYPASS(prg_ch);
prg_write(prg, reg, IPU_PR_CTRL);
/* stride */
reg = prg_read(prg, IPU_PR_STRIDE(prg_ch));
reg &= ~IPU_PR_STRIDE_MASK;
reg |= config->stride - 1;
prg_write(prg, reg, IPU_PR_STRIDE(prg_ch));
/* ilo */
reg = prg_read(prg, IPU_PR_CH_ILO(prg_ch));
reg &= ~IPU_PR_CH_ILO_MASK;
reg |= IPU_PR_CH_ILO_NUM(config->ilo);
prg_write(prg, reg, IPU_PR_CH_ILO(prg_ch));
/* height */
reg = prg_read(prg, IPU_PR_CH_HEIGHT(prg_ch));
reg &= ~IPU_PR_CH_HEIGHT_MASK;
reg |= IPU_PR_CH_HEIGHT_NUM(config->height);
prg_write(prg, reg, IPU_PR_CH_HEIGHT(prg_ch));
/* ipu height */
reg = prg_read(prg, IPU_PR_CH_HEIGHT(prg_ch));
reg &= ~IPU_PR_CH_IPU_HEIGHT_MASK;
reg |= IPU_PR_CH_IPU_HEIGHT_NUM(config->ipu_height);
prg_write(prg, reg, IPU_PR_CH_HEIGHT(prg_ch));
/* crop */
reg = prg_read(prg, IPU_PR_CROP_LINE);
reg &= ~IPU_PR_CROP_LINE_MASK(prg_ch);
reg |= IPU_PR_CROP_LINE_NUM(prg_ch, config->crop_line);
prg_write(prg, reg, IPU_PR_CROP_LINE);
/* buffer address */
reg = prg_read(prg, IPU_PR_CH_BADDR(prg_ch));
reg &= ~IPU_PR_CH_BADDR_MASK;
reg |= config->baddr;
prg_write(prg, reg, IPU_PR_CH_BADDR(prg_ch));
/* offset */
reg = prg_read(prg, IPU_PR_CH_OFFSET(prg_ch));
reg &= ~IPU_PR_CH_OFFSET_MASK;
reg |= config->offset;
prg_write(prg, reg, IPU_PR_CH_OFFSET(prg_ch));
/* threshold */
reg = prg_read(prg, IPU_PR_ADDR_THD);
reg &= ~IPU_PR_ADDR_THD_MASK;
reg |= prg->memory;
prg_write(prg, reg, IPU_PR_ADDR_THD);
/* shadow enable */
reg = prg_read(prg, IPU_PR_CTRL);
reg |= IPU_PR_CTRL_SHADOW_EN;
prg_write(prg, reg, IPU_PR_CTRL);
/* register update */
reg = prg_read(prg, IPU_PR_REG_UPDATE);
reg |= IPU_PR_REG_UPDATE_EN;
prg_write(prg, reg, IPU_PR_REG_UPDATE);
spin_unlock(&prg->lock);
clk_disable_unprepare(prg->apb_clk);
return 0;
}
EXPORT_SYMBOL(ipu_prg_config);
int ipu_prg_disable(unsigned int ipu_id, unsigned int pre_num)
{
struct ipu_prg_data *prg = get_prg(ipu_id);
int prg_ch;
u32 reg;
if (!prg)
return -EINVAL;
prg_ch = get_prg_chan(prg, pre_num);
if (prg_ch < 0)
return prg_ch;
clk_prepare_enable(prg->apb_clk);
spin_lock(&prg->lock);
/* clear all load enable to impact other channels */
reg = prg_read(prg, IPU_PR_CTRL);
reg &= ~IPU_PR_CTRL_CH_CNT_LOAD_EN_MASK;
prg_write(prg, reg, IPU_PR_CTRL);
/* counter load enable */
reg = prg_read(prg, IPU_PR_CTRL);
reg |= IPU_PR_CTRL_CH_CNT_LOAD_EN(prg_ch);
prg_write(prg, reg, IPU_PR_CTRL);
/* enable bypass */
reg = prg_read(prg, IPU_PR_CTRL);
reg |= IPU_PR_CTRL_CH_BYPASS(prg_ch);
prg_write(prg, reg, IPU_PR_CTRL);
/* shadow enable */
reg = prg_read(prg, IPU_PR_CTRL);
reg |= IPU_PR_CTRL_SHADOW_EN;
prg_write(prg, reg, IPU_PR_CTRL);
/* register update */
reg = prg_read(prg, IPU_PR_REG_UPDATE);
reg |= IPU_PR_REG_UPDATE_EN;
prg_write(prg, reg, IPU_PR_REG_UPDATE);
spin_unlock(&prg->lock);
clk_disable_unprepare(prg->apb_clk);
clk_disable_unprepare(prg->axi_clk);
mutex_lock(&prg->chan[prg_ch].mutex);
prg->chan[prg_ch].in_use = false;
mutex_unlock(&prg->chan[prg_ch].mutex);
return 0;
}
EXPORT_SYMBOL(ipu_prg_disable);
int ipu_prg_wait_buf_ready(unsigned int ipu_id, unsigned int pre_num,
unsigned int hsk_line_num,
int pre_store_out_height)
{
struct ipu_prg_data *prg = get_prg(ipu_id);
int prg_ch, timeout = 1000;
u32 reg;
if (!prg)
return -EINVAL;
prg_ch = get_prg_chan(prg, pre_num);
if (prg_ch < 0)
return prg_ch;
clk_prepare_enable(prg->apb_clk);
spin_lock(&prg->lock);
if (pre_store_out_height <= (4 << hsk_line_num)) {
do {
reg = prg_read(prg, IPU_PR_STATUS);
udelay(1000);
timeout--;
} while (!(reg & IPU_PR_STATUS_BUF_RDY(prg_ch, 0)) && timeout);
} else {
do {
reg = prg_read(prg, IPU_PR_STATUS);
udelay(1000);
timeout--;
} while ((!(reg & IPU_PR_STATUS_BUF_RDY(prg_ch, 0)) ||
!(reg & IPU_PR_STATUS_BUF_RDY(prg_ch, 1))) && timeout);
}
spin_unlock(&prg->lock);
clk_disable_unprepare(prg->apb_clk);
if (!timeout)
dev_err(prg->dev, "wait for buffer ready timeout\n");
return 0;
}
EXPORT_SYMBOL(ipu_prg_wait_buf_ready);
static int ipu_prg_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node, *memory;
struct ipu_prg_data *prg;
struct resource *res;
struct reg_field reg_field0 = REG_FIELD(IOMUXC_GPR5,
IMX6Q_GPR5_PRE_PRG_SEL0_LSB,
IMX6Q_GPR5_PRE_PRG_SEL0_MSB);
struct reg_field reg_field1 = REG_FIELD(IOMUXC_GPR5,
IMX6Q_GPR5_PRE_PRG_SEL1_LSB,
IMX6Q_GPR5_PRE_PRG_SEL1_MSB);
int id, i;
prg = devm_kzalloc(&pdev->dev, sizeof(*prg), GFP_KERNEL);
if (!prg)
return -ENOMEM;
prg->dev = &pdev->dev;
for (i = 0; i < PRG_CHAN_NUM; i++)
mutex_init(&prg->chan[i].mutex);
spin_lock_init(&prg->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
prg->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(prg->base))
return PTR_ERR(prg->base);
prg->axi_clk = devm_clk_get(&pdev->dev, "axi");
if (IS_ERR(prg->axi_clk)) {
dev_err(&pdev->dev, "failed to get the axi clk\n");
return PTR_ERR(prg->axi_clk);
}
prg->apb_clk = devm_clk_get(&pdev->dev, "apb");
if (IS_ERR(prg->apb_clk)) {
dev_err(&pdev->dev, "failed to get the apb clk\n");
return PTR_ERR(prg->apb_clk);
}
prg->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
if (IS_ERR(prg->regmap)) {
dev_err(&pdev->dev, "failed to get regmap\n");
return PTR_ERR(prg->regmap);
}
prg->pre_prg_sel[0] = devm_regmap_field_alloc(&pdev->dev, prg->regmap,
reg_field0);
if (IS_ERR(prg->pre_prg_sel[0]))
return PTR_ERR(prg->pre_prg_sel[0]);
prg->pre_prg_sel[1] = devm_regmap_field_alloc(&pdev->dev, prg->regmap,
reg_field1);
if (IS_ERR(prg->pre_prg_sel[1]))
return PTR_ERR(prg->pre_prg_sel[1]);
memory = of_parse_phandle(np, "memory-region", 0);
if (!memory)
return -ENODEV;
prg->memory = of_translate_address(memory,
of_get_address(memory, 0, NULL, NULL));
id = of_alias_get_id(np, "prg");
if (id < 0) {
dev_err(&pdev->dev, "failed to get PRG id\n");
return id;
}
prg->id = id;
mutex_lock(&prg_lock);
list_add_tail(&prg->list, &prg_list);
mutex_unlock(&prg_lock);
platform_set_drvdata(pdev, prg);
dev_info(&pdev->dev, "driver probed\n");
return 0;
}
static int ipu_prg_remove(struct platform_device *pdev)
{
struct ipu_prg_data *prg = platform_get_drvdata(pdev);
mutex_lock(&prg_lock);
list_del(&prg->list);
mutex_unlock(&prg_lock);
return 0;
}
static const struct of_device_id imx_ipu_prg_dt_ids[] = {
{ .compatible = "fsl,imx6q-prg", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_ipu_prg_dt_ids);
static struct platform_driver ipu_prg_driver = {
.driver = {
.name = "imx-prg",
.of_match_table = of_match_ptr(imx_ipu_prg_dt_ids),
},
.probe = ipu_prg_probe,
.remove = ipu_prg_remove,
};
static int __init ipu_prg_init(void)
{
return platform_driver_register(&ipu_prg_driver);
}
subsys_initcall(ipu_prg_init);
static void __exit ipu_prg_exit(void)
{
platform_driver_unregister(&ipu_prg_driver);
}
module_exit(ipu_prg_exit);
MODULE_DESCRIPTION("i.MX PRG driver");
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,538 @@
/*
* Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2018 NXP
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/ipu.h>
#include <linux/genalloc.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#include "vdoa.h"
/* 6band(3field* double buffer) * (width*2) * bandline(8)
= 6x1024x2x8 = 96k or 72k(1.5byte) */
#define MAX_VDOA_IRAM_SIZE (1024*96)
#define VDOA_IRAM_SIZE (1024*72)
#define VDOAC_BAND_HEIGHT_32LINES (32)
#define VDOAC_BAND_HEIGHT_16LINES (16)
#define VDOAC_BAND_HEIGHT_8LINES (8)
#define VDOAC_THREE_FRAMES (0x1 << 2)
#define VDOAC_SYNC_BAND_MODE (0x1 << 3)
#define VDOAC_SCAN_ORDER_INTERLACED (0x1 << 4)
#define VDOAC_PFS_YUYV (0x1 << 5)
#define VDOAC_IPU_SEL_1 (0x1 << 6)
#define VDOAFP_FH_MASK (0x1FFF)
#define VDOAFP_FH_SHIFT (16)
#define VDOAFP_FW_MASK (0x3FFF)
#define VDOAFP_FW_SHIFT (0)
#define VDOASL_VSLY_MASK (0x3FFF)
#define VDOASL_VSLY_SHIFT (16)
#define VDOASL_ISLY_MASK (0x7FFF)
#define VDOASL_ISLY_SHIFT (0)
#define VDOASRR_START_XFER (0x2)
#define VDOASRR_SWRST (0x1)
#define VDOAIEIST_TRANSFER_ERR (0x2)
#define VDOAIEIST_TRANSFER_END (0x1)
#define VDOAC (0x0) /* Control Register */
#define VDOASRR (0x4) /* Start and Reset Register */
#define VDOAIE (0x8) /* Interrupt Enable Register */
#define VDOAIST (0xc) /* Interrupt Status Register */
#define VDOAFP (0x10) /* Frame Parameters Register */
#define VDOAIEBA00 (0x14) /* External Buffer n Frame m Address Register */
#define VDOAIEBA01 (0x18) /* External Buffer n Frame m Address Register */
#define VDOAIEBA02 (0x1c) /* External Buffer n Frame m Address Register */
#define VDOAIEBA10 (0x20) /* External Buffer n Frame m Address Register */
#define VDOAIEBA11 (0x24) /* External Buffer n Frame m Address Register */
#define VDOAIEBA12 (0x28) /* External Buffer n Frame m Address Register */
#define VDOASL (0x2c) /* IPU Stride Line Register */
#define VDOAIUBO (0x30) /* IPU Chroma Buffer Offset Register */
#define VDOAVEBA0 (0x34) /* External Buffer m Address Register */
#define VDOAVEBA1 (0x38) /* External Buffer m Address Register */
#define VDOAVEBA2 (0x3c) /* External Buffer m Address Register */
#define VDOAVUBO (0x40) /* VPU Chroma Buffer Offset */
#define VDOASR (0x44) /* Status Register */
#define VDOATD (0x48) /* Test Debug Register */
enum {
VDOA_INIT = 0x1,
VDOA_GET = 0x2,
VDOA_SETUP = 0x4,
VDOA_GET_OBUF = 0x8,
VDOA_START = 0x10,
VDOA_INIRQ = 0x20,
VDOA_STOP = 0x40,
VDOA_PUT = VDOA_INIT,
};
enum {
VDOA_NULL = 0,
VDOA_FRAME = 1,
VDOA_PREV_FIELD = 2,
VDOA_CURR_FIELD = 3,
VDOA_NEXT_FIELD = 4,
};
#define CHECK_STATE(expect, retcode) \
do { \
if (!((expect) & vdoa->state)) { \
dev_err(vdoa->dev, "ERR: %s state:0x%x, expect:0x%x.\n",\
__func__, vdoa->state, (expect)); \
retcode; \
} \
} while (0)
#define CHECK_NULL_PTR(ptr) \
do { \
pr_debug("vdoa_ptr:0x%p in %s state:0x%x.\n", \
vdoa, __func__, vdoa->state); \
if (NULL == (ptr)) { \
pr_err("ERR vdoa: %s state:0x%x null ptr.\n", \
__func__, vdoa->state); \
} \
} while (0)
struct vdoa_info {
int state;
struct device *dev;
struct clk *vdoa_clk;
void __iomem *reg_base;
struct gen_pool *iram_pool;
unsigned long iram_base;
unsigned long iram_paddr;
int irq;
int field;
struct completion comp;
};
static struct vdoa_info *g_vdoa;
static unsigned long iram_size;
static DEFINE_MUTEX(vdoa_lock);
static inline void vdoa_read_register(struct vdoa_info *vdoa,
u32 reg, u32 *val)
{
*val = ioread32(vdoa->reg_base + reg);
dev_dbg(vdoa->dev, "read_reg:0x%02x, val:0x%08x.\n", reg, *val);
}
static inline void vdoa_write_register(struct vdoa_info *vdoa,
u32 reg, u32 val)
{
iowrite32(val, vdoa->reg_base + reg);
dev_dbg(vdoa->dev, "\t\twrite_reg:0x%02x, val:0x%08x.\n", reg, val);
}
static void dump_registers(struct vdoa_info *vdoa)
{
int i;
u32 data;
for (i = VDOAC; i < VDOATD; i += 4)
vdoa_read_register(vdoa, i, &data);
}
int vdoa_setup(vdoa_handle_t handle, struct vdoa_params *params)
{
int band_size;
int total_band_size = 0;
int ipu_stride;
u32 data;
struct vdoa_info *vdoa = (struct vdoa_info *)handle;
CHECK_NULL_PTR(vdoa);
CHECK_STATE(VDOA_GET | VDOA_GET_OBUF | VDOA_STOP, return -EINVAL);
if (VDOA_GET == vdoa->state) {
dev_dbg(vdoa->dev, "w:%d, h:%d.\n",
params->width, params->height);
data = (params->band_lines == VDOAC_BAND_HEIGHT_32LINES) ? 2 :
((params->band_lines == VDOAC_BAND_HEIGHT_16LINES) ?
1 : 0);
data |= params->scan_order ? VDOAC_SCAN_ORDER_INTERLACED : 0;
data |= params->band_mode ? VDOAC_SYNC_BAND_MODE : 0;
data |= params->pfs ? VDOAC_PFS_YUYV : 0;
data |= params->ipu_num ? VDOAC_IPU_SEL_1 : 0;
vdoa_write_register(vdoa, VDOAC, data);
data = ((params->width & VDOAFP_FW_MASK) << VDOAFP_FW_SHIFT) |
((params->height & VDOAFP_FH_MASK) << VDOAFP_FH_SHIFT);
vdoa_write_register(vdoa, VDOAFP, data);
ipu_stride = params->pfs ? params->width << 1 : params->width;
data = ((params->vpu_stride & VDOASL_VSLY_MASK) <<
VDOASL_VSLY_SHIFT) |
((ipu_stride & VDOASL_ISLY_MASK) << VDOASL_ISLY_SHIFT);
vdoa_write_register(vdoa, VDOASL, data);
dev_dbg(vdoa->dev, "band_mode:%d, band_line:%d, base:0x%lx.\n",
params->band_mode, params->band_lines, vdoa->iram_paddr);
}
/*
* band size = (luma_per_line + chroma_per_line) * bandLines
* = width * (3/2 or 2) * bandLines
* double buffer mode used.
*/
if (params->pfs)
band_size = (params->width << 1) * params->band_lines;
else
band_size = ((params->width * 3) >> 1) *
params->band_lines;
if (params->interlaced) {
total_band_size = 6 * band_size; /* 3 frames*double buffer */
if (iram_size < total_band_size) {
dev_err(vdoa->dev, "iram_size:0x%lx is smaller than "
"request:0x%x!\n", iram_size, total_band_size);
return -EINVAL;
}
if (params->vfield_buf.prev_veba) {
if (params->band_mode) {
vdoa_write_register(vdoa, VDOAIEBA00,
vdoa->iram_paddr);
vdoa_write_register(vdoa, VDOAIEBA10,
vdoa->iram_paddr + band_size);
} else
vdoa_write_register(vdoa, VDOAIEBA00,
params->ieba0);
vdoa_write_register(vdoa, VDOAVEBA0,
params->vfield_buf.prev_veba);
vdoa->field = VDOA_PREV_FIELD;
}
if (params->vfield_buf.cur_veba) {
if (params->band_mode) {
vdoa_write_register(vdoa, VDOAIEBA01,
vdoa->iram_paddr + band_size * 2);
vdoa_write_register(vdoa, VDOAIEBA11,
vdoa->iram_paddr + band_size * 3);
} else
vdoa_write_register(vdoa, VDOAIEBA01,
params->ieba1);
vdoa_write_register(vdoa, VDOAVEBA1,
params->vfield_buf.cur_veba);
vdoa->field = VDOA_CURR_FIELD;
}
if (params->vfield_buf.next_veba) {
if (params->band_mode) {
vdoa_write_register(vdoa, VDOAIEBA02,
vdoa->iram_paddr + band_size * 4);
vdoa_write_register(vdoa, VDOAIEBA12,
vdoa->iram_paddr + band_size * 5);
} else
vdoa_write_register(vdoa, VDOAIEBA02,
params->ieba2);
vdoa_write_register(vdoa, VDOAVEBA2,
params->vfield_buf.next_veba);
vdoa->field = VDOA_NEXT_FIELD;
vdoa_read_register(vdoa, VDOAC, &data);
data |= VDOAC_THREE_FRAMES;
vdoa_write_register(vdoa, VDOAC, data);
}
if (!params->pfs)
vdoa_write_register(vdoa, VDOAIUBO,
params->width * params->band_lines);
vdoa_write_register(vdoa, VDOAVUBO,
params->vfield_buf.vubo);
dev_dbg(vdoa->dev, "total band_size:0x%x.\n", band_size*6);
} else if (params->band_mode) {
/* used for progressive frame resize on PrP channel */
BUG(); /* currently not support */
/* progressvie frame: band mode */
vdoa_write_register(vdoa, VDOAIEBA00, vdoa->iram_paddr);
vdoa_write_register(vdoa, VDOAIEBA10,
vdoa->iram_paddr + band_size);
if (!params->pfs)
vdoa_write_register(vdoa, VDOAIUBO,
params->width * params->band_lines);
dev_dbg(vdoa->dev, "total band_size:0x%x\n", band_size*2);
} else {
/* progressive frame: mem->mem, non-band mode */
vdoa->field = VDOA_FRAME;
vdoa_write_register(vdoa, VDOAVEBA0, params->vframe_buf.veba);
vdoa_write_register(vdoa, VDOAVUBO, params->vframe_buf.vubo);
vdoa_write_register(vdoa, VDOAIEBA00, params->ieba0);
if (!params->pfs)
/* note: iubo is relative value, based on ieba0 */
vdoa_write_register(vdoa, VDOAIUBO,
params->width * params->height);
}
vdoa->state = VDOA_SETUP;
return 0;
}
void vdoa_get_output_buf(vdoa_handle_t handle, struct vdoa_ipu_buf *buf)
{
u32 data;
struct vdoa_info *vdoa = (struct vdoa_info *)handle;
CHECK_NULL_PTR(vdoa);
CHECK_STATE(VDOA_SETUP, return);
vdoa->state = VDOA_GET_OBUF;
memset(buf, 0, sizeof(*buf));
vdoa_read_register(vdoa, VDOAC, &data);
switch (vdoa->field) {
case VDOA_FRAME:
case VDOA_PREV_FIELD:
vdoa_read_register(vdoa, VDOAIEBA00, &buf->ieba0);
if (data & VDOAC_SYNC_BAND_MODE)
vdoa_read_register(vdoa, VDOAIEBA10, &buf->ieba1);
break;
case VDOA_CURR_FIELD:
vdoa_read_register(vdoa, VDOAIEBA01, &buf->ieba0);
vdoa_read_register(vdoa, VDOAIEBA11, &buf->ieba1);
break;
case VDOA_NEXT_FIELD:
vdoa_read_register(vdoa, VDOAIEBA02, &buf->ieba0);
vdoa_read_register(vdoa, VDOAIEBA12, &buf->ieba1);
break;
default:
BUG();
break;
}
if (!(data & VDOAC_PFS_YUYV))
vdoa_read_register(vdoa, VDOAIUBO, &buf->iubo);
}
int vdoa_start(vdoa_handle_t handle, int timeout_ms)
{
int ret;
struct vdoa_info *vdoa = (struct vdoa_info *)handle;
CHECK_NULL_PTR(vdoa);
CHECK_STATE(VDOA_GET_OBUF, return -EINVAL);
vdoa->state = VDOA_START;
init_completion(&vdoa->comp);
vdoa_write_register(vdoa, VDOAIST,
VDOAIEIST_TRANSFER_ERR | VDOAIEIST_TRANSFER_END);
vdoa_write_register(vdoa, VDOAIE,
VDOAIEIST_TRANSFER_ERR | VDOAIEIST_TRANSFER_END);
enable_irq(vdoa->irq);
vdoa_write_register(vdoa, VDOASRR, VDOASRR_START_XFER);
dump_registers(vdoa);
ret = wait_for_completion_timeout(&vdoa->comp,
msecs_to_jiffies(timeout_ms));
return ret > 0 ? 0 : -ETIMEDOUT;
}
void vdoa_stop(vdoa_handle_t handle)
{
struct vdoa_info *vdoa = (struct vdoa_info *)handle;
CHECK_NULL_PTR(vdoa);
CHECK_STATE(VDOA_GET | VDOA_START | VDOA_INIRQ, return);
vdoa->state = VDOA_STOP;
disable_irq(vdoa->irq);
vdoa_write_register(vdoa, VDOASRR, VDOASRR_SWRST);
}
void vdoa_get_handle(vdoa_handle_t *handle)
{
struct vdoa_info *vdoa = g_vdoa;
CHECK_NULL_PTR(handle);
*handle = (vdoa_handle_t *)NULL;
CHECK_STATE(VDOA_INIT, return);
mutex_lock(&vdoa_lock);
clk_prepare_enable(vdoa->vdoa_clk);
vdoa->state = VDOA_GET;
vdoa->field = VDOA_NULL;
vdoa_write_register(vdoa, VDOASRR, VDOASRR_SWRST);
*handle = (vdoa_handle_t *)vdoa;
}
void vdoa_put_handle(vdoa_handle_t *handle)
{
struct vdoa_info *vdoa = (struct vdoa_info *)(*handle);
CHECK_NULL_PTR(vdoa);
CHECK_STATE(VDOA_STOP, return);
if (vdoa != g_vdoa)
BUG();
clk_disable_unprepare(vdoa->vdoa_clk);
vdoa->state = VDOA_PUT;
*handle = (vdoa_handle_t *)NULL;
mutex_unlock(&vdoa_lock);
}
static irqreturn_t vdoa_irq_handler(int irq, void *data)
{
u32 status, mask, val;
struct vdoa_info *vdoa = data;
CHECK_NULL_PTR(vdoa);
CHECK_STATE(VDOA_START, return IRQ_HANDLED);
vdoa->state = VDOA_INIRQ;
vdoa_read_register(vdoa, VDOAIST, &status);
vdoa_read_register(vdoa, VDOAIE, &mask);
val = status & mask;
vdoa_write_register(vdoa, VDOAIST, val);
if (VDOAIEIST_TRANSFER_ERR & val)
dev_err(vdoa->dev, "vdoa Transfer err irq!\n");
if (VDOAIEIST_TRANSFER_END & val)
dev_dbg(vdoa->dev, "vdoa Transfer end irq!\n");
if (0 == val) {
dev_err(vdoa->dev, "vdoa unknown irq!\n");
BUG();
}
complete(&vdoa->comp);
return IRQ_HANDLED;
}
/* IRAM Size in Kbytes, example:vdoa_iram_size=64, 64KBytes */
static int __init vdoa_iram_size_setup(char *options)
{
int ret;
ret = kstrtoul(options, 0, &iram_size);
if (ret)
iram_size = 0;
else
iram_size *= SZ_1K;
return 1;
}
__setup("vdoa_iram_size=", vdoa_iram_size_setup);
static const struct of_device_id imx_vdoa_dt_ids[] = {
{ .compatible = "fsl,imx6q-vdoa", },
{ /* sentinel */ }
};
static int vdoa_probe(struct platform_device *pdev)
{
int ret;
struct vdoa_info *vdoa;
struct resource *res;
struct resource *res_irq;
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "can't get device resources\n");
return -ENOENT;
}
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res_irq) {
dev_err(dev, "failed to get irq resource\n");
return -ENOENT;
}
vdoa = devm_kzalloc(dev, sizeof(struct vdoa_info), GFP_KERNEL);
if (!vdoa)
return -ENOMEM;
vdoa->dev = dev;
vdoa->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (!vdoa->reg_base)
return -EBUSY;
vdoa->irq = res_irq->start;
ret = devm_request_irq(dev, vdoa->irq, vdoa_irq_handler, 0,
"vdoa", vdoa);
if (ret) {
dev_err(dev, "can't claim irq %d\n", vdoa->irq);
return ret;
}
disable_irq(vdoa->irq);
vdoa->vdoa_clk = devm_clk_get(dev, NULL);
if (IS_ERR(vdoa->vdoa_clk)) {
dev_err(dev, "failed to get vdoa_clk\n");
return PTR_ERR(vdoa->vdoa_clk);
}
vdoa->iram_pool = of_gen_pool_get(np, "iram", 0);
if (!vdoa->iram_pool) {
dev_err(&pdev->dev, "iram pool not available\n");
return -ENOMEM;
}
if ((iram_size == 0) || (iram_size > MAX_VDOA_IRAM_SIZE))
iram_size = VDOA_IRAM_SIZE;
vdoa->iram_base = gen_pool_alloc(vdoa->iram_pool, iram_size);
if (!vdoa->iram_base) {
dev_err(&pdev->dev, "unable to alloc iram\n");
return -ENOMEM;
}
vdoa->iram_paddr = gen_pool_virt_to_phys(vdoa->iram_pool,
vdoa->iram_base);
dev_dbg(dev, "iram_base:0x%lx,iram_paddr:0x%lx,size:0x%lx\n",
vdoa->iram_base, vdoa->iram_paddr, iram_size);
vdoa->state = VDOA_INIT;
dev_set_drvdata(dev, vdoa);
g_vdoa = vdoa;
dev_info(dev, "i.MX Video Data Order Adapter(VDOA) driver probed\n");
return 0;
}
static int vdoa_remove(struct platform_device *pdev)
{
struct vdoa_info *vdoa = dev_get_drvdata(&pdev->dev);
gen_pool_free(vdoa->iram_pool, vdoa->iram_base, iram_size);
kfree(vdoa);
dev_set_drvdata(&pdev->dev, NULL);
return 0;
}
static struct platform_driver vdoa_driver = {
.driver = {
.name = "mxc_vdoa",
.of_match_table = imx_vdoa_dt_ids,
},
.probe = vdoa_probe,
.remove = vdoa_remove,
};
static int __init vdoa_init(void)
{
int err;
err = platform_driver_register(&vdoa_driver);
if (err) {
pr_err("vdoa_driver register failed\n");
return -ENODEV;
}
return 0;
}
static void __exit vdoa_cleanup(void)
{
platform_driver_unregister(&vdoa_driver);
}
subsys_initcall(vdoa_init);
module_exit(vdoa_cleanup);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("i.MX Video Data Order Adapter(VDOA) driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef __VDOA_H__
#define __VDOA_H__
#define VDOA_PFS_YUYV (1)
#define VDOA_PFS_NV12 (0)
struct vfield_buf {
u32 prev_veba;
u32 cur_veba;
u32 next_veba;
u32 vubo;
};
struct vframe_buf {
u32 veba;
u32 vubo;
};
struct vdoa_params {
u32 width;
u32 height;
int vpu_stride;
int interlaced;
int scan_order;
int ipu_num;
int band_lines;
int band_mode;
int pfs;
u32 ieba0;
u32 ieba1;
u32 ieba2;
struct vframe_buf vframe_buf;
struct vfield_buf vfield_buf;
};
struct vdoa_ipu_buf {
u32 ieba0;
u32 ieba1;
u32 iubo;
};
struct vdoa_info;
typedef void *vdoa_handle_t;
int vdoa_setup(vdoa_handle_t handle, struct vdoa_params *params);
void vdoa_get_output_buf(vdoa_handle_t handle, struct vdoa_ipu_buf *buf);
int vdoa_start(vdoa_handle_t handle, int timeout_ms);
void vdoa_stop(vdoa_handle_t handle);
void vdoa_get_handle(vdoa_handle_t *handle);
void vdoa_put_handle(vdoa_handle_t *handle);
#endif

View File

@ -0,0 +1,155 @@
/*
* Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef __LINUX_IPU_V3_PRE_H_
#define __LINUX_IPU_V3_PRE_H_
#define IPU_PRE_MAX_WIDTH 1920
#define IPU_PRE_MAX_BPP 4
#define IPU_PRE_SMALL_LINE 9 /* to workaround errata ERR009624*/
struct ipu_rect {
int left;
int top;
int width;
int height;
};
struct ipu_pre_context {
bool repeat;
bool vflip;
bool handshake_en;
bool hsk_abort_en;
unsigned int hsk_line_num;
bool sdw_update;
unsigned int block_size;
unsigned int interlaced;
unsigned int prefetch_mode;
unsigned long cur_buf;
unsigned long next_buf;
unsigned int tile_fmt;
unsigned int read_burst;
unsigned int prefetch_input_bpp;
unsigned int prefetch_input_pixel_fmt;
unsigned int prefetch_shift_offset;
unsigned int prefetch_shift_width;
bool shift_bypass;
bool field_inverse;
bool tpr_coor_offset_en;
/* the output of prefetch is
* also the input of store
*/
struct ipu_rect prefetch_output_size;
unsigned int prefetch_input_active_width;
unsigned int prefetch_input_width;
unsigned int prefetch_input_height;
unsigned int store_pitch;
int interlace_offset;
bool store_en;
unsigned int write_burst;
unsigned int store_output_bpp;
unsigned int sec_buf_off;
unsigned int trd_buf_off;
/* return for IPU fb caller */
unsigned long store_addr;
};
/*
* In order to workaround the PRE SoC bug recorded by errata ERR009624,
* the software cannot write the PRE_CTRL register when the PRE writes
* the PRE_CTRL register automatically to set the ENABLE bit(bit0) to 1
* in the PRE repeat mode.
* The software mechanism to set the PRE_CTRL register is different for
* PRE Y resolution higher than 9 lines and lower or equal to 9 lines.
* Use this helper to check the Y resolution.
*/
static inline bool ipu_pre_yres_is_small(unsigned int yres)
{
return yres <= IPU_PRE_SMALL_LINE;
}
#ifdef CONFIG_MXC_IPU_V3_PRE
int ipu_pre_alloc(int ipu_id, ipu_channel_t ipu_ch);
void ipu_pre_free(unsigned int *id);
unsigned long ipu_pre_alloc_double_buffer(unsigned int id, unsigned int size);
void ipu_pre_free_double_buffer(unsigned int id);
int ipu_pre_config(int id, struct ipu_pre_context *config);
int ipu_pre_set_ctrl(unsigned int id, struct ipu_pre_context *config);
int ipu_pre_enable(int id);
void ipu_pre_disable(int id);
int ipu_pre_set_fb_buffer(int id, bool resolve,
unsigned long fb_paddr,
unsigned int y_res,
unsigned int x_crop,
unsigned int y_crop,
unsigned int sec_buf_off,
unsigned int trd_buf_off);
int ipu_pre_sdw_update(int id);
#else
int ipu_pre_alloc(int ipu_id, ipu_channel_t channel)
{
return -ENODEV;
}
void ipu_pre_free(unsigned int *id)
{
}
unsigned long ipu_pre_alloc_double_buffer(unsigned int id, unsigned int size)
{
return -ENODEV;
}
void ipu_pre_free_double_buffer(unsigned int id)
{
}
int ipu_pre_config(int id, struct ipu_pre_context *config)
{
return -ENODEV;
}
int ipu_pre_set_ctrl(unsigned int id, struct ipu_pre_context *config)
{
return -ENODEV;
}
int ipu_pre_enable(int id)
{
return -ENODEV;
}
void ipu_pre_disable(int id)
{
return;
}
int ipu_pre_set_fb_buffer(int id, bool resolve,
unsigned long fb_paddr,
unsigned int y_res,
unsigned int x_crop,
unsigned int y_crop,
unsigned int sec_buf_off,
unsigned int trd_buf_off)
{
return -ENODEV;
}
int ipu_pre_sdw_update(int id)
{
return -ENODEV;
}
#endif
#endif /* __LINUX_IPU_V3_PRE_H_ */

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef __LINUX_IPU_V3_PRG_H_
#define __LINUX_IPU_V3_PRG_H_
#include <linux/ipu-v3.h>
#define PRG_SO_INTERLACE 1
#define PRG_SO_PROGRESSIVE 0
#define PRG_BLOCK_MODE 1
#define PRG_SCAN_MODE 0
struct ipu_prg_config {
unsigned int id;
unsigned int pre_num;
ipu_channel_t ipu_ch;
unsigned int stride;
unsigned int height;
unsigned int ipu_height;
unsigned int crop_line;
unsigned int so;
unsigned int ilo;
unsigned int block_mode;
bool vflip;
u32 baddr;
u32 offset;
};
#ifdef CONFIG_MXC_IPU_V3_PRG
int ipu_prg_config(struct ipu_prg_config *config);
int ipu_prg_disable(unsigned int ipu_id, unsigned int pre_num);
int ipu_prg_wait_buf_ready(unsigned int ipu_id, unsigned int pre_num,
unsigned int hsk_line_num,
int pre_store_out_height);
#else
int ipu_prg_config(struct ipu_prg_config *config)
{
return -ENODEV;
}
int ipu_prg_disable(unsigned int ipu_id, unsigned int pre_num)
{
return -ENODEV;
}
int ipu_prg_wait_buf_ready(unsigned int ipu_id, unsigned int pre_num,
unsigned int hsk_line_num,
int pre_store_out_height)
{
return -ENODEV;
}
#endif
#endif /* __LINUX_IPU_V3_PRG_H_ */

View File

@ -0,0 +1,770 @@
/*
* Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
* Copyright (C) 2011-2015 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* 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.
*/
#ifndef __LINUX_IPU_V3_H_
#define __LINUX_IPU_V3_H_
#include <linux/ipu.h>
/* IPU Driver channels definitions. */
/* Note these are different from IDMA channels */
#define IPU_MAX_CH 32
#define _MAKE_CHAN(num, v_in, g_in, a_in, out) \
((num << 24) | (v_in << 18) | (g_in << 12) | (a_in << 6) | out)
#define _MAKE_ALT_CHAN(ch) (ch | (IPU_MAX_CH << 24))
#define IPU_CHAN_ID(ch) (ch >> 24)
#define IPU_CHAN_ALT(ch) (ch & 0x02000000)
#define IPU_CHAN_ALPHA_IN_DMA(ch) ((uint32_t) (ch >> 6) & 0x3F)
#define IPU_CHAN_GRAPH_IN_DMA(ch) ((uint32_t) (ch >> 12) & 0x3F)
#define IPU_CHAN_VIDEO_IN_DMA(ch) ((uint32_t) (ch >> 18) & 0x3F)
#define IPU_CHAN_OUT_DMA(ch) ((uint32_t) (ch & 0x3F))
#define NO_DMA 0x3F
#define ALT 1
/*!
* Enumeration of IPU logical channels. An IPU logical channel is defined as a
* combination of an input (memory to IPU), output (IPU to memory), and/or
* secondary input IDMA channels and in some cases an Image Converter task.
* Some channels consist of only an input or output.
*/
typedef enum {
CHAN_NONE = -1,
MEM_ROT_ENC_MEM = _MAKE_CHAN(1, 45, NO_DMA, NO_DMA, 48),
MEM_ROT_VF_MEM = _MAKE_CHAN(2, 46, NO_DMA, NO_DMA, 49),
MEM_ROT_PP_MEM = _MAKE_CHAN(3, 47, NO_DMA, NO_DMA, 50),
MEM_PRP_ENC_MEM = _MAKE_CHAN(4, 12, 14, 17, 20),
MEM_PRP_VF_MEM = _MAKE_CHAN(5, 12, 14, 17, 21),
MEM_PP_MEM = _MAKE_CHAN(6, 11, 15, 18, 22),
MEM_DC_SYNC = _MAKE_CHAN(7, 28, NO_DMA, NO_DMA, NO_DMA),
MEM_DC_ASYNC = _MAKE_CHAN(8, 41, NO_DMA, NO_DMA, NO_DMA),
MEM_BG_SYNC = _MAKE_CHAN(9, 23, NO_DMA, 51, NO_DMA),
MEM_FG_SYNC = _MAKE_CHAN(10, 27, NO_DMA, 31, NO_DMA),
MEM_BG_ASYNC0 = _MAKE_CHAN(11, 24, NO_DMA, 52, NO_DMA),
MEM_FG_ASYNC0 = _MAKE_CHAN(12, 29, NO_DMA, 33, NO_DMA),
MEM_BG_ASYNC1 = _MAKE_ALT_CHAN(MEM_BG_ASYNC0),
MEM_FG_ASYNC1 = _MAKE_ALT_CHAN(MEM_FG_ASYNC0),
DIRECT_ASYNC0 = _MAKE_CHAN(13, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
DIRECT_ASYNC1 = _MAKE_CHAN(14, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
CSI_MEM0 = _MAKE_CHAN(15, NO_DMA, NO_DMA, NO_DMA, 0),
CSI_MEM1 = _MAKE_CHAN(16, NO_DMA, NO_DMA, NO_DMA, 1),
CSI_MEM2 = _MAKE_CHAN(17, NO_DMA, NO_DMA, NO_DMA, 2),
CSI_MEM3 = _MAKE_CHAN(18, NO_DMA, NO_DMA, NO_DMA, 3),
CSI_MEM = CSI_MEM0,
CSI_PRP_ENC_MEM = _MAKE_CHAN(19, NO_DMA, NO_DMA, NO_DMA, 20),
CSI_PRP_VF_MEM = _MAKE_CHAN(20, NO_DMA, NO_DMA, NO_DMA, 21),
/* for vdi mem->vdi->ic->mem , add graphics plane and alpha*/
MEM_VDI_PRP_VF_MEM_P = _MAKE_CHAN(21, 8, 14, 17, 21),
MEM_VDI_PRP_VF_MEM = _MAKE_CHAN(22, 9, 14, 17, 21),
MEM_VDI_PRP_VF_MEM_N = _MAKE_CHAN(23, 10, 14, 17, 21),
/* for vdi mem->vdi->mem */
MEM_VDI_MEM_P = _MAKE_CHAN(24, 8, NO_DMA, NO_DMA, 5),
MEM_VDI_MEM = _MAKE_CHAN(25, 9, NO_DMA, NO_DMA, 5),
MEM_VDI_MEM_N = _MAKE_CHAN(26, 10, NO_DMA, NO_DMA, 5),
/* fake channel for vdoa to link with IPU */
MEM_VDOA_MEM = _MAKE_CHAN(27, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
MEM_PP_ADC = CHAN_NONE,
ADC_SYS2 = CHAN_NONE,
} ipu_channel_t;
/*!
* Enumeration of types of buffers for a logical channel.
*/
typedef enum {
IPU_OUTPUT_BUFFER = 0, /*!< Buffer for output from IPU */
IPU_ALPHA_IN_BUFFER = 1, /*!< Buffer for input to IPU */
IPU_GRAPH_IN_BUFFER = 2, /*!< Buffer for input to IPU */
IPU_VIDEO_IN_BUFFER = 3, /*!< Buffer for input to IPU */
IPU_INPUT_BUFFER = IPU_VIDEO_IN_BUFFER,
IPU_SEC_INPUT_BUFFER = IPU_GRAPH_IN_BUFFER,
} ipu_buffer_t;
#define IPU_PANEL_SERIAL 1
#define IPU_PANEL_PARALLEL 2
/*!
* Enumeration of ADC channel operation mode.
*/
typedef enum {
Disable,
WriteTemplateNonSeq,
ReadTemplateNonSeq,
WriteTemplateUnCon,
ReadTemplateUnCon,
WriteDataWithRS,
WriteDataWoRS,
WriteCmd
} mcu_mode_t;
/*!
* Enumeration of ADC channel addressing mode.
*/
typedef enum {
FullWoBE,
FullWithBE,
XY
} display_addressing_t;
/*!
* Union of initialization parameters for a logical channel.
*/
typedef union {
struct {
uint32_t csi;
uint32_t mipi_id;
uint32_t mipi_vc;
bool mipi_en;
bool interlaced;
} csi_mem;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
uint32_t outh_resize_ratio;
uint32_t outv_resize_ratio;
uint32_t csi;
uint32_t mipi_id;
uint32_t mipi_vc;
bool mipi_en;
} csi_prp_enc_mem;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
uint32_t outh_resize_ratio;
uint32_t outv_resize_ratio;
} mem_prp_enc_mem;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
} mem_rot_enc_mem;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
uint32_t outh_resize_ratio;
uint32_t outv_resize_ratio;
bool graphics_combine_en;
bool global_alpha_en;
bool key_color_en;
uint32_t in_g_pixel_fmt;
uint8_t alpha;
uint32_t key_color;
bool alpha_chan_en;
ipu_motion_sel motion_sel;
enum v4l2_field field_fmt;
uint32_t csi;
uint32_t mipi_id;
uint32_t mipi_vc;
bool mipi_en;
} csi_prp_vf_mem;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
bool graphics_combine_en;
bool global_alpha_en;
bool key_color_en;
display_port_t disp;
uint32_t out_left;
uint32_t out_top;
} csi_prp_vf_adc;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
uint32_t outh_resize_ratio;
uint32_t outv_resize_ratio;
bool graphics_combine_en;
bool global_alpha_en;
bool key_color_en;
uint32_t in_g_pixel_fmt;
uint8_t alpha;
uint32_t key_color;
bool alpha_chan_en;
ipu_motion_sel motion_sel;
enum v4l2_field field_fmt;
} mem_prp_vf_mem;
struct {
uint32_t temp;
} mem_prp_vf_adc;
struct {
uint32_t temp;
} mem_rot_vf_mem;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
uint32_t outh_resize_ratio;
uint32_t outv_resize_ratio;
bool graphics_combine_en;
bool global_alpha_en;
bool key_color_en;
uint32_t in_g_pixel_fmt;
uint8_t alpha;
uint32_t key_color;
bool alpha_chan_en;
} mem_pp_mem;
struct {
uint32_t temp;
} mem_rot_mem;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
bool graphics_combine_en;
bool global_alpha_en;
bool key_color_en;
display_port_t disp;
uint32_t out_left;
uint32_t out_top;
} mem_pp_adc;
struct {
uint32_t di;
bool interlaced;
uint32_t in_pixel_fmt;
uint32_t out_pixel_fmt;
} mem_dc_sync;
struct {
uint32_t temp;
} mem_sdc_fg;
struct {
uint32_t di;
bool interlaced;
uint32_t in_pixel_fmt;
uint32_t out_pixel_fmt;
bool alpha_chan_en;
} mem_dp_bg_sync;
struct {
uint32_t temp;
} mem_sdc_bg;
struct {
uint32_t di;
bool interlaced;
uint32_t in_pixel_fmt;
uint32_t out_pixel_fmt;
bool alpha_chan_en;
} mem_dp_fg_sync;
struct {
uint32_t di;
} direct_async;
struct {
display_port_t disp;
mcu_mode_t ch_mode;
uint32_t out_left;
uint32_t out_top;
} adc_sys1;
struct {
display_port_t disp;
mcu_mode_t ch_mode;
uint32_t out_left;
uint32_t out_top;
} adc_sys2;
} ipu_channel_params_t;
/*
* IPU_IRQF_ONESHOT - Interrupt is not reenabled after the irq handler finished.
*/
#define IPU_IRQF_NONE 0x00000000
#define IPU_IRQF_ONESHOT 0x00000001
/*!
* Enumeration of IPU interrupt sources.
*/
enum ipu_irq_line {
IPU_IRQ_CSI0_OUT_EOF = 0,
IPU_IRQ_CSI1_OUT_EOF = 1,
IPU_IRQ_CSI2_OUT_EOF = 2,
IPU_IRQ_CSI3_OUT_EOF = 3,
IPU_IRQ_VDIC_OUT_EOF = 5,
IPU_IRQ_VDI_P_IN_EOF = 8,
IPU_IRQ_VDI_C_IN_EOF = 9,
IPU_IRQ_VDI_N_IN_EOF = 10,
IPU_IRQ_PP_IN_EOF = 11,
IPU_IRQ_PRP_IN_EOF = 12,
IPU_IRQ_PRP_GRAPH_IN_EOF = 14,
IPU_IRQ_PP_GRAPH_IN_EOF = 15,
IPU_IRQ_PRP_ALPHA_IN_EOF = 17,
IPU_IRQ_PP_ALPHA_IN_EOF = 18,
IPU_IRQ_PRP_ENC_OUT_EOF = 20,
IPU_IRQ_PRP_VF_OUT_EOF = 21,
IPU_IRQ_PP_OUT_EOF = 22,
IPU_IRQ_BG_SYNC_EOF = 23,
IPU_IRQ_BG_ASYNC_EOF = 24,
IPU_IRQ_FG_SYNC_EOF = 27,
IPU_IRQ_DC_SYNC_EOF = 28,
IPU_IRQ_FG_ASYNC_EOF = 29,
IPU_IRQ_FG_ALPHA_SYNC_EOF = 31,
IPU_IRQ_FG_ALPHA_ASYNC_EOF = 33,
IPU_IRQ_DC_READ_EOF = 40,
IPU_IRQ_DC_ASYNC_EOF = 41,
IPU_IRQ_DC_CMD1_EOF = 42,
IPU_IRQ_DC_CMD2_EOF = 43,
IPU_IRQ_DC_MASK_EOF = 44,
IPU_IRQ_PRP_ENC_ROT_IN_EOF = 45,
IPU_IRQ_PRP_VF_ROT_IN_EOF = 46,
IPU_IRQ_PP_ROT_IN_EOF = 47,
IPU_IRQ_PRP_ENC_ROT_OUT_EOF = 48,
IPU_IRQ_PRP_VF_ROT_OUT_EOF = 49,
IPU_IRQ_PP_ROT_OUT_EOF = 50,
IPU_IRQ_BG_ALPHA_SYNC_EOF = 51,
IPU_IRQ_BG_ALPHA_ASYNC_EOF = 52,
IPU_IRQ_BG_SYNC_NFACK = 64 + 23,
IPU_IRQ_FG_SYNC_NFACK = 64 + 27,
IPU_IRQ_DC_SYNC_NFACK = 64 + 28,
IPU_IRQ_DP_SF_START = 448 + 2,
IPU_IRQ_DP_SF_END = 448 + 3,
IPU_IRQ_BG_SF_END = IPU_IRQ_DP_SF_END,
IPU_IRQ_DC_FC_0 = 448 + 8,
IPU_IRQ_DC_FC_1 = 448 + 9,
IPU_IRQ_DC_FC_2 = 448 + 10,
IPU_IRQ_DC_FC_3 = 448 + 11,
IPU_IRQ_DC_FC_4 = 448 + 12,
IPU_IRQ_DC_FC_6 = 448 + 13,
IPU_IRQ_VSYNC_PRE_0 = 448 + 14,
IPU_IRQ_VSYNC_PRE_1 = 448 + 15,
IPU_IRQ_COUNT
};
/*!
* Bitfield of Display Interface signal polarities.
*/
typedef struct {
unsigned datamask_en:1;
unsigned int_clk:1;
unsigned interlaced:1;
unsigned odd_field_first:1;
unsigned clksel_en:1;
unsigned clkidle_en:1;
unsigned data_pol:1; /* true = inverted */
unsigned clk_pol:1; /* true = rising edge */
unsigned enable_pol:1;
unsigned Hsync_pol:1; /* true = active high */
unsigned Vsync_pol:1;
} ipu_di_signal_cfg_t;
/*!
* Bitfield of CSI signal polarities and modes.
*/
typedef struct {
unsigned data_width:4;
unsigned clk_mode:3;
unsigned ext_vsync:1;
unsigned Vsync_pol:1;
unsigned Hsync_pol:1;
unsigned pixclk_pol:1;
unsigned data_pol:1;
unsigned sens_clksrc:1;
unsigned pack_tight:1;
unsigned force_eof:1;
unsigned data_en_pol:1;
unsigned data_fmt;
unsigned csi;
unsigned mclk;
} ipu_csi_signal_cfg_t;
/*!
* Enumeration of CSI data bus widths.
*/
enum {
IPU_CSI_DATA_WIDTH_4 = 0,
IPU_CSI_DATA_WIDTH_8 = 1,
IPU_CSI_DATA_WIDTH_10 = 3,
IPU_CSI_DATA_WIDTH_16 = 9,
};
/*!
* Enumeration of CSI clock modes.
*/
enum {
IPU_CSI_CLK_MODE_GATED_CLK,
IPU_CSI_CLK_MODE_NONGATED_CLK,
IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
};
enum {
IPU_CSI_MIPI_DI0,
IPU_CSI_MIPI_DI1,
IPU_CSI_MIPI_DI2,
IPU_CSI_MIPI_DI3,
};
typedef enum {
RGB,
YCbCr,
YUV
} ipu_color_space_t;
/*!
* Enumeration of ADC vertical sync mode.
*/
typedef enum {
VsyncNone,
VsyncInternal,
VsyncCSI,
VsyncExternal
} vsync_t;
typedef enum {
DAT,
CMD
} cmddata_t;
/*!
* Enumeration of ADC display update mode.
*/
typedef enum {
IPU_ADC_REFRESH_NONE,
IPU_ADC_AUTO_REFRESH,
IPU_ADC_AUTO_REFRESH_SNOOP,
IPU_ADC_SNOOPING,
} ipu_adc_update_mode_t;
/*!
* Enumeration of ADC display interface types (serial or parallel).
*/
enum {
IPU_ADC_IFC_MODE_SYS80_TYPE1,
IPU_ADC_IFC_MODE_SYS80_TYPE2,
IPU_ADC_IFC_MODE_SYS68K_TYPE1,
IPU_ADC_IFC_MODE_SYS68K_TYPE2,
IPU_ADC_IFC_MODE_3WIRE_SERIAL,
IPU_ADC_IFC_MODE_4WIRE_SERIAL,
IPU_ADC_IFC_MODE_5WIRE_SERIAL_CLK,
IPU_ADC_IFC_MODE_5WIRE_SERIAL_CS,
};
enum {
IPU_ADC_IFC_WIDTH_8,
IPU_ADC_IFC_WIDTH_16,
};
/*!
* Enumeration of ADC display interface burst mode.
*/
enum {
IPU_ADC_BURST_WCS,
IPU_ADC_BURST_WBLCK,
IPU_ADC_BURST_NONE,
IPU_ADC_BURST_SERIAL,
};
/*!
* Enumeration of ADC display interface RW signal timing modes.
*/
enum {
IPU_ADC_SER_NO_RW,
IPU_ADC_SER_RW_BEFORE_RS,
IPU_ADC_SER_RW_AFTER_RS,
};
/*!
* Bitfield of ADC signal polarities and modes.
*/
typedef struct {
unsigned data_pol:1;
unsigned clk_pol:1;
unsigned cs_pol:1;
unsigned rs_pol:1;
unsigned addr_pol:1;
unsigned read_pol:1;
unsigned write_pol:1;
unsigned Vsync_pol:1;
unsigned burst_pol:1;
unsigned burst_mode:2;
unsigned ifc_mode:3;
unsigned ifc_width:5;
unsigned ser_preamble_len:4;
unsigned ser_preamble:8;
unsigned ser_rw_mode:2;
} ipu_adc_sig_cfg_t;
/*!
* Enumeration of ADC template commands.
*/
enum {
RD_DATA,
RD_ACK,
RD_WAIT,
WR_XADDR,
WR_YADDR,
WR_ADDR,
WR_CMND,
WR_DATA,
};
/*!
* Enumeration of ADC template command flow control.
*/
enum {
SINGLE_STEP,
PAUSE,
STOP,
};
/*Define template constants*/
#define ATM_ADDR_RANGE 0x20 /*offset address of DISP */
#define TEMPLATE_BUF_SIZE 0x20 /*size of template */
/*!
* Define to create ADC template command entry.
*/
#define ipu_adc_template_gen(oc, rs, fc, dat) (((rs) << 29) | ((fc) << 27) | \
((oc) << 24) | (dat))
typedef struct {
u32 reg;
u32 value;
} ipu_lpmc_reg_t;
#define IPU_LPMC_REG_READ 0x80000000L
#define CSI_MCLK_VF 1
#define CSI_MCLK_ENC 2
#define CSI_MCLK_RAW 4
#define CSI_MCLK_I2C 8
struct ipu_soc;
/* Common IPU API */
struct ipu_soc *ipu_get_soc(int id);
int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params);
void ipu_uninit_channel(struct ipu_soc *ipu, ipu_channel_t channel);
void ipu_disable_hsp_clk(struct ipu_soc *ipu);
static inline bool ipu_can_rotate_in_place(ipu_rotate_mode_t rot)
{
#ifdef CONFIG_MXC_IPU_V3D
return (rot < IPU_ROTATE_HORIZ_FLIP);
#else
return (rot < IPU_ROTATE_90_RIGHT);
#endif
}
int32_t ipu_init_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
uint32_t pixel_fmt,
uint16_t width, uint16_t height,
uint32_t stride,
ipu_rotate_mode_t rot_mode,
dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
dma_addr_t phyaddr_2,
uint32_t u_offset, uint32_t v_offset);
int32_t ipu_update_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
uint32_t bufNum, dma_addr_t phyaddr);
int32_t ipu_update_channel_offset(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
uint32_t pixel_fmt,
uint16_t width, uint16_t height,
uint32_t stride,
uint32_t u, uint32_t v,
uint32_t vertical_offset, uint32_t horizontal_offset);
int32_t ipu_get_channel_offset(uint32_t pixel_fmt,
uint16_t width, uint16_t height,
uint32_t stride,
uint32_t u, uint32_t v,
uint32_t vertical_offset, uint32_t horizontal_offset,
uint32_t *u_offset, uint32_t *v_offset);
int32_t ipu_select_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
ipu_buffer_t type, uint32_t bufNum);
int32_t ipu_select_multi_vdi_buffer(struct ipu_soc *ipu, uint32_t bufNum);
int32_t ipu_link_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel_t dest_ch);
int32_t ipu_unlink_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel_t dest_ch);
int32_t ipu_is_channel_busy(struct ipu_soc *ipu, ipu_channel_t channel);
int32_t ipu_check_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
uint32_t bufNum);
void ipu_clear_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
uint32_t bufNum);
uint32_t ipu_get_cur_buffer_idx(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type);
int32_t ipu_enable_channel(struct ipu_soc *ipu, ipu_channel_t channel);
int32_t ipu_disable_channel(struct ipu_soc *ipu, ipu_channel_t channel, bool wait_for_stop);
int32_t ipu_swap_channel(struct ipu_soc *ipu, ipu_channel_t from_ch, ipu_channel_t to_ch);
uint32_t ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel);
int32_t ipu_enable_csi(struct ipu_soc *ipu, uint32_t csi);
int32_t ipu_disable_csi(struct ipu_soc *ipu, uint32_t csi);
int ipu_lowpwr_display_enable(void);
int ipu_lowpwr_display_disable(void);
int ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq);
void ipu_disable_irq(struct ipu_soc *ipu, uint32_t irq);
void ipu_clear_irq(struct ipu_soc *ipu, uint32_t irq);
int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq,
irqreturn_t(*handler) (int, void *),
uint32_t irq_flags, const char *devname, void *dev_id);
void ipu_free_irq(struct ipu_soc *ipu, uint32_t irq, void *dev_id);
bool ipu_get_irq_status(struct ipu_soc *ipu, uint32_t irq);
void ipu_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3]);
int32_t ipu_set_channel_bandmode(struct ipu_soc *ipu, ipu_channel_t channel,
ipu_buffer_t type, uint32_t band_height);
/* two stripe calculations */
struct stripe_param{
unsigned int input_width; /* width of the input stripe */
unsigned int output_width; /* width of the output stripe */
unsigned int input_column; /* the first column on the input stripe */
unsigned int output_column; /* the first column on the output stripe */
unsigned int idr;
/* inverse downisizing ratio parameter; expressed as a power of 2 */
unsigned int irr;
/* inverse resizing ratio parameter; expressed as a multiple of 2^-13 */
};
int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
unsigned int output_frame_width,
const unsigned int maximal_stripe_width,
const unsigned long long cirr,
const unsigned int equal_stripes,
u32 input_pixelformat,
u32 output_pixelformat,
struct stripe_param *left,
struct stripe_param *right);
/* SDC API */
int32_t ipu_init_sync_panel(struct ipu_soc *ipu, int disp,
uint32_t pixel_clk,
uint16_t width, uint16_t height,
uint32_t pixel_fmt,
uint16_t h_start_width, uint16_t h_sync_width,
uint16_t h_end_width, uint16_t v_start_width,
uint16_t v_sync_width, uint16_t v_end_width,
uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig);
void ipu_uninit_sync_panel(struct ipu_soc *ipu, int disp);
int32_t ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel, int16_t x_pos,
int16_t y_pos);
int32_t ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel, int16_t *x_pos,
int16_t *y_pos);
int32_t ipu_disp_set_global_alpha(struct ipu_soc *ipu, ipu_channel_t channel, bool enable,
uint8_t alpha);
int32_t ipu_disp_set_color_key(struct ipu_soc *ipu, ipu_channel_t channel, bool enable,
uint32_t colorKey);
int32_t ipu_disp_set_gamma_correction(struct ipu_soc *ipu, ipu_channel_t channel, bool enable,
int constk[], int slopek[]);
int ipu_init_async_panel(struct ipu_soc *ipu, int disp, int type, uint32_t cycle_time,
uint32_t pixel_fmt, ipu_adc_sig_cfg_t sig);
void ipu_reset_disp_panel(struct ipu_soc *ipu);
/* CMOS Sensor Interface API */
int32_t ipu_csi_init_interface(struct ipu_soc *ipu, uint16_t width, uint16_t height,
uint32_t pixel_fmt, ipu_csi_signal_cfg_t sig);
int32_t ipu_csi_get_sensor_protocol(struct ipu_soc *ipu, uint32_t csi);
int32_t ipu_csi_enable_mclk(struct ipu_soc *ipu, int src, bool flag, bool wait);
static inline int32_t ipu_csi_enable_mclk_if(struct ipu_soc *ipu, int src, uint32_t csi,
bool flag, bool wait)
{
return ipu_csi_enable_mclk(ipu, csi, flag, wait);
}
int ipu_csi_read_mclk_flag(void);
void ipu_csi_flash_strobe(bool flag);
void ipu_csi_get_window_size(struct ipu_soc *ipu, uint32_t *width, uint32_t *height, uint32_t csi);
void ipu_csi_set_window_size(struct ipu_soc *ipu, uint32_t width, uint32_t height, uint32_t csi);
void ipu_csi_set_window_pos(struct ipu_soc *ipu, uint32_t left, uint32_t top, uint32_t csi);
uint32_t bytes_per_pixel(uint32_t fmt);
bool ipu_ch_param_bad_alpha_pos(uint32_t fmt);
int ipu_ch_param_get_axi_id(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type);
ipu_color_space_t format_to_colorspace(uint32_t fmt);
bool ipu_pixel_format_is_gpu_tile(uint32_t fmt);
bool ipu_pixel_format_is_split_gpu_tile(uint32_t fmt);
bool ipu_pixel_format_is_pre_yuv(uint32_t fmt);
bool ipu_pixel_format_is_multiplanar_yuv(uint32_t fmt);
struct ipuv3_fb_platform_data {
char disp_dev[32];
u32 interface_pix_fmt;
char *mode_str;
int default_bpp;
bool int_clk;
/* reserved mem */
resource_size_t res_base[2];
resource_size_t res_size[2];
/*
* Late init to avoid display channel being
* re-initialized as we've probably setup the
* channel in bootloader.
*/
bool late_init;
/* Enable prefetch engine or not? */
bool prefetch;
/* Enable the PRE resolve engine or not? */
bool resolve;
};
#endif /* __LINUX_IPU_V3_H_ */

View File

@ -0,0 +1,38 @@
/*
* Copyright 2005-2015 Freescale Semiconductor, Inc.
*/
/*
* The code contained herein is licensed under the GNU Lesser General
* Public License. You may obtain a copy of the GNU Lesser General
* Public License Version 2.1 or later at the following locations:
*
* http://www.opensource.org/licenses/lgpl-license.html
* http://www.gnu.org/copyleft/lgpl.html
*/
/*!
* @defgroup IPU MXC Image Processing Unit (IPU) Driver
*/
/*!
* @file linux/ipu.h
*
* @brief This file contains the IPU driver API declarations.
*
* @ingroup IPU
*/
#ifndef __LINUX_IPU_H__
#define __LINUX_IPU_H__
#include <linux/interrupt.h>
#include <uapi/linux/ipu.h>
unsigned int fmt_to_bpp(unsigned int pixelformat);
cs_t colorspaceofpixel(int fmt);
int need_csc(int ifmt, int ofmt);
int ipu_queue_task(struct ipu_task *task);
int ipu_check_task(struct ipu_task *task);
#endif