media: staging/intel-ipu3: Add dual pipe support

This patch adds support to run dual pipes simultaneously.
A private ioctl to configure the pipe mode (video or still)
is also implemented.

IPU3 hardware supports a maximum of 2 streams per pipe.
With the support of dual pipes, more than 2 stream outputs
can be achieved.

This helps to support advanced camera features like
Continuous View Finder (CVF) and Snapshot During Video(SDV).

Extend ipu3 IMGU driver to support dual pipes

    1. Extend current IMGU device to contain 2 groups
       of video nodes and 2 subdevs
    2. Extend current css to support 2 pipeline and make
       CSS APIs to support 2 pipe
    3. Add a v4l2 ctrl to allow user to specify the mode
       of the pipe
    4. Check media pipeline link status to get enabled
       pipes

Signed-off-by: Bingbu Cao <bingbu.cao@intel.com>
Signed-off-by: Tian Shu Qiu <tian.shu.qiu@intel.com>
Signed-off-by: Yong Zhi <yong.zhi@intel.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
Bingbu Cao 2018-12-06 20:03:39 -05:00 committed by Mauro Carvalho Chehab
parent 41158dabfd
commit 51abe041c5
10 changed files with 1457 additions and 955 deletions

View File

@ -12,6 +12,16 @@
#define V4L2_META_FMT_IPU3_PARAMS v4l2_fourcc('i', 'p', '3', 'p') /* IPU3 processing parameters */
#define V4L2_META_FMT_IPU3_STAT_3A v4l2_fourcc('i', 'p', '3', 's') /* IPU3 3A statistics */
/* from include/uapi/linux/v4l2-controls.h */
#define V4L2_CID_INTEL_IPU3_BASE (V4L2_CID_USER_BASE + 0x10c0)
#define V4L2_CID_INTEL_IPU3_MODE (V4L2_CID_INTEL_IPU3_BASE + 1)
/* custom ctrl to set pipe mode */
enum ipu3_running_mode {
IPU3_RUNNING_MODE_VIDEO = 0,
IPU3_RUNNING_MODE_STILL = 1,
};
/******************* ipu3_uapi_stats_3a *******************/
#define IPU3_UAPI_MAX_STRIPES 2

View File

@ -69,16 +69,17 @@ unsigned int ipu3_css_fw_obgrid_size(const struct imgu_fw_info *bi)
return obgrid_size;
}
void *ipu3_css_fw_pipeline_params(struct ipu3_css *css,
enum imgu_abi_param_class c,
enum imgu_abi_memories m,
void *ipu3_css_fw_pipeline_params(struct ipu3_css *css, unsigned int pipe,
enum imgu_abi_param_class cls,
enum imgu_abi_memories mem,
struct imgu_fw_isp_parameter *par,
size_t par_size, void *binary_params)
{
struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
struct imgu_fw_info *bi =
&css->fwp->binary_header[css->pipes[pipe].bindex];
if (par->offset + par->size >
bi->info.isp.sp.mem_initializers.params[c][m].size)
bi->info.isp.sp.mem_initializers.params[cls][mem].size)
return NULL;
if (par->size != par_size)

View File

@ -179,9 +179,9 @@ int ipu3_css_fw_init(struct ipu3_css *css);
void ipu3_css_fw_cleanup(struct ipu3_css *css);
unsigned int ipu3_css_fw_obgrid_size(const struct imgu_fw_info *bi);
void *ipu3_css_fw_pipeline_params(struct ipu3_css *css,
enum imgu_abi_param_class c,
enum imgu_abi_memories m,
void *ipu3_css_fw_pipeline_params(struct ipu3_css *css, unsigned int pipe,
enum imgu_abi_param_class cls,
enum imgu_abi_memories mem,
struct imgu_fw_isp_parameter *par,
size_t par_size, void *binary_params);

View File

@ -364,55 +364,59 @@ static int ipu3_css_osys_calc_frame_and_stripe_params(
struct ipu3_css_scaler_info *scaler_luma,
struct ipu3_css_scaler_info *scaler_chroma,
struct ipu3_css_frame_params frame_params[],
struct ipu3_css_stripe_params stripe_params[])
struct ipu3_css_stripe_params stripe_params[],
unsigned int pipe)
{
u32 input_width = css->rect[IPU3_CSS_RECT_GDC].width;
u32 input_height = css->rect[IPU3_CSS_RECT_GDC].height;
u32 target_width = css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
u32 target_height = css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
unsigned int procmode = 0;
struct ipu3_css_reso reso;
unsigned int output_width, pin, s;
u32 input_width, input_height, target_width, target_height;
unsigned int procmode = 0;
struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
input_width = css_pipe->rect[IPU3_CSS_RECT_GDC].width;
input_height = css_pipe->rect[IPU3_CSS_RECT_GDC].height;
target_width = css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
target_height = css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
/* Frame parameters */
/* Input width for Output System is output width of DVS (with GDC) */
reso.input_width = css->rect[IPU3_CSS_RECT_GDC].width;
reso.input_width = css_pipe->rect[IPU3_CSS_RECT_GDC].width;
/* Input height for Output System is output height of DVS (with GDC) */
reso.input_height = css->rect[IPU3_CSS_RECT_GDC].height;
reso.input_height = css_pipe->rect[IPU3_CSS_RECT_GDC].height;
reso.input_format =
css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
reso.pin_width[IMGU_ABI_OSYS_PIN_OUT] =
css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
reso.pin_height[IMGU_ABI_OSYS_PIN_OUT] =
css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
reso.pin_stride[IMGU_ABI_OSYS_PIN_OUT] =
css->queue[IPU3_CSS_QUEUE_OUT].width_pad;
css_pipe->queue[IPU3_CSS_QUEUE_OUT].width_pad;
reso.pin_format[IMGU_ABI_OSYS_PIN_OUT] =
css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
reso.pin_width[IMGU_ABI_OSYS_PIN_VF] =
css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
reso.pin_height[IMGU_ABI_OSYS_PIN_VF] =
css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
reso.pin_stride[IMGU_ABI_OSYS_PIN_VF] =
css->queue[IPU3_CSS_QUEUE_VF].width_pad;
css_pipe->queue[IPU3_CSS_QUEUE_VF].width_pad;
reso.pin_format[IMGU_ABI_OSYS_PIN_VF] =
css->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
css_pipe->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
/* Configure the frame parameters for all output pins */
frame_params[IMGU_ABI_OSYS_PIN_OUT].width =
css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
frame_params[IMGU_ABI_OSYS_PIN_OUT].height =
css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
frame_params[IMGU_ABI_OSYS_PIN_VF].width =
css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
frame_params[IMGU_ABI_OSYS_PIN_VF].height =
css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
frame_params[IMGU_ABI_OSYS_PIN_VF].crop_top = 0;
frame_params[IMGU_ABI_OSYS_PIN_VF].crop_left = 0;
@ -842,16 +846,18 @@ static int ipu3_css_osys_calc_frame_and_stripe_params(
* This function configures the Output Formatter System, given the number of
* stripes, scaler luma and chrome parameters
*/
static int ipu3_css_osys_calc(struct ipu3_css *css, unsigned int stripes,
struct imgu_abi_osys_config *osys,
struct ipu3_css_scaler_info *scaler_luma,
struct ipu3_css_scaler_info *scaler_chroma,
struct imgu_abi_stripes block_stripes[])
static int ipu3_css_osys_calc(struct ipu3_css *css, unsigned int pipe,
unsigned int stripes,
struct imgu_abi_osys_config *osys,
struct ipu3_css_scaler_info *scaler_luma,
struct ipu3_css_scaler_info *scaler_chroma,
struct imgu_abi_stripes block_stripes[])
{
struct ipu3_css_frame_params frame_params[IMGU_ABI_OSYS_PINS];
struct ipu3_css_stripe_params stripe_params[IPU3_UAPI_MAX_STRIPES];
struct imgu_abi_osys_formatter_params *param;
unsigned int pin, s;
struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
memset(osys, 0, sizeof(*osys));
@ -860,7 +866,7 @@ static int ipu3_css_osys_calc(struct ipu3_css *css, unsigned int stripes,
scaler_luma,
scaler_chroma,
frame_params,
stripe_params))
stripe_params, pipe))
return -EINVAL;
/* Output formatter system parameters */
@ -1183,19 +1189,20 @@ static int ipu3_css_osys_calc(struct ipu3_css *css, unsigned int stripes,
block_stripes[0].height = stripe_params[0].input_height;
} else {
struct imgu_fw_info *bi =
&css->fwp->binary_header[css->current_binary];
unsigned int sp_block_width = IPU3_UAPI_ISP_VEC_ELEMS *
bi->info.isp.sp.block.block_width;
&css->fwp->binary_header[css_pipe->bindex];
unsigned int sp_block_width =
bi->info.isp.sp.block.block_width *
IPU3_UAPI_ISP_VEC_ELEMS;
block_stripes[0].width = roundup(stripe_params[0].input_width,
sp_block_width);
block_stripes[1].offset =
rounddown(css->rect[IPU3_CSS_RECT_GDC].width -
rounddown(css_pipe->rect[IPU3_CSS_RECT_GDC].width -
stripe_params[1].input_width, sp_block_width);
block_stripes[1].width =
roundup(css->rect[IPU3_CSS_RECT_GDC].width -
roundup(css_pipe->rect[IPU3_CSS_RECT_GDC].width -
block_stripes[1].offset, sp_block_width);
block_stripes[0].height = css->rect[IPU3_CSS_RECT_GDC].height;
block_stripes[0].height = css_pipe->rect[IPU3_CSS_RECT_GDC].height;
block_stripes[1].height = block_stripes[0].height;
}
@ -1625,15 +1632,17 @@ ipu3_css_acc_process_lines(const struct process_lines *pl,
return 0;
}
static int ipu3_css_af_ops_calc(struct ipu3_css *css,
static int ipu3_css_af_ops_calc(struct ipu3_css *css, unsigned int pipe,
struct imgu_abi_af_config *af_config)
{
struct imgu_abi_af_intra_frame_operations_data *to =
&af_config->operations_data;
struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
struct imgu_fw_info *bi =
&css->fwp->binary_header[css_pipe->bindex];
struct process_lines pl = {
.image_height = css->rect[IPU3_CSS_RECT_BDS].height,
.image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
.grid_height = af_config->config.grid_cfg.height,
.block_height =
1 << af_config->config.grid_cfg.block_height_log2,
@ -1651,14 +1660,16 @@ static int ipu3_css_af_ops_calc(struct ipu3_css *css,
}
static int
ipu3_css_awb_fr_ops_calc(struct ipu3_css *css,
ipu3_css_awb_fr_ops_calc(struct ipu3_css *css, unsigned int pipe,
struct imgu_abi_awb_fr_config *awb_fr_config)
{
struct imgu_abi_awb_fr_intra_frame_operations_data *to =
&awb_fr_config->operations_data;
struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
struct imgu_fw_info *bi =
&css->fwp->binary_header[css_pipe->bindex];
struct process_lines pl = {
.image_height = css->rect[IPU3_CSS_RECT_BDS].height,
.image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
.grid_height = awb_fr_config->config.grid_cfg.height,
.block_height =
1 << awb_fr_config->config.grid_cfg.block_height_log2,
@ -1675,15 +1686,17 @@ ipu3_css_awb_fr_ops_calc(struct ipu3_css *css,
NULL);
}
static int ipu3_css_awb_ops_calc(struct ipu3_css *css,
static int ipu3_css_awb_ops_calc(struct ipu3_css *css, unsigned int pipe,
struct imgu_abi_awb_config *awb_config)
{
struct imgu_abi_awb_intra_frame_operations_data *to =
&awb_config->operations_data;
struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
struct imgu_fw_info *bi =
&css->fwp->binary_header[css_pipe->bindex];
struct process_lines pl = {
.image_height = css->rect[IPU3_CSS_RECT_BDS].height,
.image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
.grid_height = awb_config->config.grid.height,
.block_height =
1 << awb_config->config.grid.block_height_log2,
@ -1715,21 +1728,22 @@ static void ipu3_css_grid_end_calc(struct ipu3_uapi_grid_config *grid_cfg)
/****************** config computation *****************************/
static int ipu3_css_cfg_acc_stripe(struct ipu3_css *css,
static int ipu3_css_cfg_acc_stripe(struct ipu3_css *css, unsigned int pipe,
struct imgu_abi_acc_param *acc)
{
struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
const struct imgu_fw_info *bi =
&css->fwp->binary_header[css->current_binary];
const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
const unsigned int F = IPU3_UAPI_ISP_VEC_ELEMS * 2;
&css->fwp->binary_header[css_pipe->bindex];
struct ipu3_css_scaler_info scaler_luma, scaler_chroma;
const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
const unsigned int f = IPU3_UAPI_ISP_VEC_ELEMS * 2;
unsigned int bds_ds, i;
memset(acc, 0, sizeof(*acc));
/* acc_param: osys_config */
if (ipu3_css_osys_calc(css, stripes, &acc->osys, &scaler_luma,
if (ipu3_css_osys_calc(css, pipe, stripes, &acc->osys, &scaler_luma,
&scaler_chroma, acc->stripe.block_stripes))
return -EINVAL;
@ -1746,77 +1760,78 @@ static int ipu3_css_cfg_acc_stripe(struct ipu3_css *css,
acc->stripe.num_of_stripes = stripes;
acc->stripe.input_frame.width =
css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
acc->stripe.input_frame.height =
css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
acc->stripe.input_frame.bayer_order =
css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
for (i = 0; i < stripes; i++)
acc->stripe.bds_out_stripes[i].height =
css->rect[IPU3_CSS_RECT_BDS].height;
css_pipe->rect[IPU3_CSS_RECT_BDS].height;
acc->stripe.bds_out_stripes[0].offset = 0;
if (stripes <= 1) {
acc->stripe.bds_out_stripes[0].width =
ALIGN(css->rect[IPU3_CSS_RECT_BDS].width, F);
ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f);
} else {
/* Image processing is divided into two stripes */
acc->stripe.bds_out_stripes[0].width =
acc->stripe.bds_out_stripes[1].width =
(css->rect[IPU3_CSS_RECT_BDS].width / 2 & ~(F - 1)) + F;
(css_pipe->rect[IPU3_CSS_RECT_BDS].width / 2 & ~(f - 1)) + f;
/*
* Sum of width of the two stripes should not be smaller
* than output width and must be even times of overlapping
* unit f.
*/
if ((css->rect[IPU3_CSS_RECT_BDS].width / F & 1) !=
!!(css->rect[IPU3_CSS_RECT_BDS].width & (F - 1)))
acc->stripe.bds_out_stripes[0].width += F;
if ((css->rect[IPU3_CSS_RECT_BDS].width / F & 1) &&
(css->rect[IPU3_CSS_RECT_BDS].width & (F - 1))) {
acc->stripe.bds_out_stripes[0].width += F;
acc->stripe.bds_out_stripes[1].width += F;
if ((css_pipe->rect[IPU3_CSS_RECT_BDS].width / f & 1) !=
!!(css_pipe->rect[IPU3_CSS_RECT_BDS].width & (f - 1)))
acc->stripe.bds_out_stripes[0].width += f;
if ((css_pipe->rect[IPU3_CSS_RECT_BDS].width / f & 1) &&
(css_pipe->rect[IPU3_CSS_RECT_BDS].width & (f - 1))) {
acc->stripe.bds_out_stripes[0].width += f;
acc->stripe.bds_out_stripes[1].width += f;
}
/* Overlap between stripes is IPU3_UAPI_ISP_VEC_ELEMS * 4 */
acc->stripe.bds_out_stripes[1].offset =
acc->stripe.bds_out_stripes[0].width - 2 * F;
acc->stripe.bds_out_stripes[0].width - 2 * f;
}
acc->stripe.effective_stripes[0].height =
css->rect[IPU3_CSS_RECT_EFFECTIVE].height;
css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
acc->stripe.effective_stripes[0].offset = 0;
acc->stripe.bds_out_stripes_no_overlap[0].height =
css->rect[IPU3_CSS_RECT_BDS].height;
css_pipe->rect[IPU3_CSS_RECT_BDS].height;
acc->stripe.bds_out_stripes_no_overlap[0].offset = 0;
acc->stripe.output_stripes[0].height =
css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
acc->stripe.output_stripes[0].offset = 0;
if (stripes <= 1) {
acc->stripe.down_scaled_stripes[0].width =
css->rect[IPU3_CSS_RECT_BDS].width;
css_pipe->rect[IPU3_CSS_RECT_BDS].width;
acc->stripe.down_scaled_stripes[0].height =
css->rect[IPU3_CSS_RECT_BDS].height;
css_pipe->rect[IPU3_CSS_RECT_BDS].height;
acc->stripe.down_scaled_stripes[0].offset = 0;
acc->stripe.effective_stripes[0].width =
css->rect[IPU3_CSS_RECT_EFFECTIVE].width;
css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width;
acc->stripe.bds_out_stripes_no_overlap[0].width =
ALIGN(css->rect[IPU3_CSS_RECT_BDS].width, F);
ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f);
acc->stripe.output_stripes[0].width =
css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
} else { /* Two stripes */
bds_ds = css->rect[IPU3_CSS_RECT_EFFECTIVE].width *
bds_ds = css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width *
IMGU_BDS_GRANULARITY /
css->rect[IPU3_CSS_RECT_BDS].width;
css_pipe->rect[IPU3_CSS_RECT_BDS].width;
acc->stripe.down_scaled_stripes[0] =
acc->stripe.bds_out_stripes[0];
acc->stripe.down_scaled_stripes[1] =
acc->stripe.bds_out_stripes[1];
if (!IS_ALIGNED(css->rect[IPU3_CSS_RECT_BDS].width, F))
acc->stripe.down_scaled_stripes[1].width += -F +
(css->rect[IPU3_CSS_RECT_BDS].width & (F - 1));
if (!IS_ALIGNED(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f))
acc->stripe.down_scaled_stripes[1].width +=
(css_pipe->rect[IPU3_CSS_RECT_BDS].width
& (f - 1)) - f;
acc->stripe.effective_stripes[0].width = bds_ds *
acc->stripe.down_scaled_stripes[0].width /
@ -1825,55 +1840,55 @@ static int ipu3_css_cfg_acc_stripe(struct ipu3_css *css,
acc->stripe.down_scaled_stripes[1].width /
IMGU_BDS_GRANULARITY;
acc->stripe.effective_stripes[1].height =
css->rect[IPU3_CSS_RECT_EFFECTIVE].height;
css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
acc->stripe.effective_stripes[1].offset = bds_ds *
acc->stripe.down_scaled_stripes[1].offset /
IMGU_BDS_GRANULARITY;
acc->stripe.bds_out_stripes_no_overlap[0].width =
acc->stripe.bds_out_stripes_no_overlap[1].offset =
ALIGN(css->rect[IPU3_CSS_RECT_BDS].width, 2 * F) / 2;
ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, 2 * f) / 2;
acc->stripe.bds_out_stripes_no_overlap[1].width =
DIV_ROUND_UP(css->rect[IPU3_CSS_RECT_BDS].width, F) /
2 * F;
DIV_ROUND_UP(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f)
/ 2 * f;
acc->stripe.bds_out_stripes_no_overlap[1].height =
css->rect[IPU3_CSS_RECT_BDS].height;
css_pipe->rect[IPU3_CSS_RECT_BDS].height;
acc->stripe.output_stripes[0].width =
acc->stripe.down_scaled_stripes[0].width - F;
acc->stripe.down_scaled_stripes[0].width - f;
acc->stripe.output_stripes[1].width =
acc->stripe.down_scaled_stripes[1].width - F;
acc->stripe.down_scaled_stripes[1].width - f;
acc->stripe.output_stripes[1].height =
css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
acc->stripe.output_stripes[1].offset =
acc->stripe.output_stripes[0].width;
}
acc->stripe.output_system_in_frame_width =
css->rect[IPU3_CSS_RECT_GDC].width;
css_pipe->rect[IPU3_CSS_RECT_GDC].width;
acc->stripe.output_system_in_frame_height =
css->rect[IPU3_CSS_RECT_GDC].height;
css_pipe->rect[IPU3_CSS_RECT_GDC].height;
acc->stripe.effective_frame_width =
css->rect[IPU3_CSS_RECT_EFFECTIVE].width;
acc->stripe.bds_frame_width = css->rect[IPU3_CSS_RECT_BDS].width;
css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width;
acc->stripe.bds_frame_width = css_pipe->rect[IPU3_CSS_RECT_BDS].width;
acc->stripe.out_frame_width =
css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
acc->stripe.out_frame_height =
css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
acc->stripe.gdc_in_buffer_width =
css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline /
css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel;
css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline /
css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel;
acc->stripe.gdc_in_buffer_height =
css->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
acc->stripe.gdc_in_buffer_offset_x = IMGU_GDC_BUF_X;
acc->stripe.gdc_in_buffer_offset_y = IMGU_GDC_BUF_Y;
acc->stripe.display_frame_width =
css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
acc->stripe.display_frame_height =
css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
acc->stripe.bds_aligned_frame_width =
roundup(css->rect[IPU3_CSS_RECT_BDS].width,
roundup(css_pipe->rect[IPU3_CSS_RECT_BDS].width,
2 * IPU3_UAPI_ISP_VEC_ELEMS);
if (stripes > 1)
@ -1886,13 +1901,15 @@ static int ipu3_css_cfg_acc_stripe(struct ipu3_css *css,
}
static void ipu3_css_cfg_acc_dvs(struct ipu3_css *css,
struct imgu_abi_acc_param *acc)
struct imgu_abi_acc_param *acc,
unsigned int pipe)
{
unsigned int i;
struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
/* Disable DVS statistics */
acc->dvs_stat.operations_data.process_lines_data[0].lines =
css->rect[IPU3_CSS_RECT_BDS].height;
css_pipe->rect[IPU3_CSS_RECT_BDS].height;
acc->dvs_stat.operations_data.process_lines_data[0].cfg_set = 0;
acc->dvs_stat.operations_data.ops[0].op_type =
IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
@ -1904,8 +1921,10 @@ static void ipu3_css_cfg_acc_dvs(struct ipu3_css *css,
static void acc_bds_per_stripe_data(struct ipu3_css *css,
struct imgu_abi_acc_param *acc,
const int i)
const int i, unsigned int pipe)
{
struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_en = 0;
acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_start = 0;
acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_end = 0;
@ -1916,7 +1935,7 @@ static void acc_bds_per_stripe_data(struct ipu3_css *css,
acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_width =
acc->stripe.down_scaled_stripes[i].width;
acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_height =
css->rect[IPU3_CSS_RECT_BDS].height;
css_pipe->rect[IPU3_CSS_RECT_BDS].height;
}
/*
@ -1925,19 +1944,21 @@ static void acc_bds_per_stripe_data(struct ipu3_css *css,
* telling which fields to take from the old values (or generate if it is NULL)
* and which to take from the new user values.
*/
int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
int ipu3_css_cfg_acc(struct ipu3_css *css, unsigned int pipe,
struct ipu3_uapi_flags *use,
struct imgu_abi_acc_param *acc,
struct imgu_abi_acc_param *acc_old,
struct ipu3_uapi_acc_param *acc_user)
{
struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
const struct imgu_fw_info *bi =
&css->fwp->binary_header[css->current_binary];
&css->fwp->binary_header[css_pipe->bindex];
const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
const unsigned int tnr_frame_width =
acc->stripe.bds_aligned_frame_width;
const unsigned int min_overlap = 10;
const struct v4l2_pix_format_mplane *pixm =
&css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix;
&css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix;
const struct ipu3_css_bds_config *cfg_bds;
struct imgu_abi_input_feeder_data *feeder_data;
@ -1946,22 +1967,22 @@ int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
/* Update stripe using chroma and luma */
if (ipu3_css_cfg_acc_stripe(css, acc))
if (ipu3_css_cfg_acc_stripe(css, pipe, acc))
return -EINVAL;
/* acc_param: input_feeder_config */
ofs_x = ((pixm->width -
css->rect[IPU3_CSS_RECT_EFFECTIVE].width) >> 1) & ~1;
ofs_x += css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width) >> 1) & ~1;
ofs_x += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
IMGU_ABI_BAYER_ORDER_RGGB ||
css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0;
ofs_y = ((pixm->height -
css->rect[IPU3_CSS_RECT_EFFECTIVE].height) >> 1) & ~1;
ofs_y += css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height) >> 1) & ~1;
ofs_y += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
IMGU_ABI_BAYER_ORDER_BGGR ||
css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0;
acc->input_feeder.data.row_stride = pixm->plane_fmt[0].bytesperline;
acc->input_feeder.data.start_row_address =
@ -2117,11 +2138,11 @@ int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
acc->shd.shd.grid.grid_height_per_slice;
if (ipu3_css_shd_ops_calc(&acc->shd.shd_ops, &acc->shd.shd.grid,
css->rect[IPU3_CSS_RECT_BDS].height))
css_pipe->rect[IPU3_CSS_RECT_BDS].height))
return -EINVAL;
/* acc_param: dvs_stat_config */
ipu3_css_cfg_acc_dvs(css, acc);
ipu3_css_cfg_acc_dvs(css, acc, pipe);
/* acc_param: yuvp1_iefd_config */
@ -2263,8 +2284,8 @@ int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
/* acc_param: bds_config */
bds_ds = (css->rect[IPU3_CSS_RECT_EFFECTIVE].height *
IMGU_BDS_GRANULARITY) / css->rect[IPU3_CSS_RECT_BDS].height;
bds_ds = (css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height *
IMGU_BDS_GRANULARITY) / css_pipe->rect[IPU3_CSS_RECT_BDS].height;
if (bds_ds < IMGU_BDS_MIN_SF_INV ||
bds_ds - IMGU_BDS_MIN_SF_INV >= ARRAY_SIZE(ipu3_css_bds_configs))
return -EINVAL;
@ -2279,11 +2300,11 @@ int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
acc->bds.hor.hor_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL;
acc->bds.hor.hor_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL;
acc->bds.hor.hor_ctrl0.out_frame_width =
css->rect[IPU3_CSS_RECT_BDS].width;
css_pipe->rect[IPU3_CSS_RECT_BDS].width;
acc->bds.hor.hor_ptrn_arr = cfg_bds->ptrn_arr;
acc->bds.hor.hor_phase_arr = cfg_bds->hor_phase_arr;
acc->bds.hor.hor_ctrl2.input_frame_height =
css->rect[IPU3_CSS_RECT_EFFECTIVE].height;
css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
acc->bds.ver.ver_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL;
acc->bds.ver.ver_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL;
acc->bds.ver.ver_ctrl0.sample_patrn_length =
@ -2292,11 +2313,11 @@ int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
acc->bds.ver.ver_ptrn_arr = cfg_bds->ptrn_arr;
acc->bds.ver.ver_phase_arr = cfg_bds->ver_phase_arr;
acc->bds.ver.ver_ctrl1.out_frame_width =
css->rect[IPU3_CSS_RECT_BDS].width;
css_pipe->rect[IPU3_CSS_RECT_BDS].width;
acc->bds.ver.ver_ctrl1.out_frame_height =
css->rect[IPU3_CSS_RECT_BDS].height;
css_pipe->rect[IPU3_CSS_RECT_BDS].height;
for (i = 0; i < stripes; i++)
acc_bds_per_stripe_data(css, acc, i);
acc_bds_per_stripe_data(css, acc, i, pipe);
acc->bds.enabled = cfg_bds->hor_ds_en || cfg_bds->ver_ds_en;
@ -2326,15 +2347,15 @@ int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
acc->anr.transform.enable = 1;
acc->anr.tile2strm.enable = 1;
acc->anr.tile2strm.frame_width =
ALIGN(css->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
acc->anr.search.frame_width = acc->anr.tile2strm.frame_width;
acc->anr.stitch.frame_width = acc->anr.tile2strm.frame_width;
acc->anr.tile2strm.frame_height = css->rect[IPU3_CSS_RECT_BDS].height;
acc->anr.tile2strm.frame_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height;
acc->anr.search.frame_height = acc->anr.tile2strm.frame_height;
acc->anr.stitch.frame_height = acc->anr.tile2strm.frame_height;
width = ALIGN(css->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
height = css->rect[IPU3_CSS_RECT_BDS].height;
width = ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
height = css_pipe->rect[IPU3_CSS_RECT_BDS].height;
if (acc->anr.transform.xreset + width > IPU3_UAPI_ANR_MAX_RESET)
acc->anr.transform.xreset = IPU3_UAPI_ANR_MAX_RESET - width;
@ -2418,7 +2439,7 @@ int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
acc->awb_fr.stripes[i].grid_cfg.height_per_slice = 1;
}
if (ipu3_css_awb_fr_ops_calc(css, &acc->awb_fr))
if (ipu3_css_awb_fr_ops_calc(css, pipe, &acc->awb_fr))
return -EINVAL;
/* acc_param: ae_config */
@ -2519,9 +2540,9 @@ int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
acc->af.config.grid_cfg.height_per_slice =
IMGU_ABI_AF_MAX_CELLS_PER_SET / acc->af.config.grid_cfg.width;
acc->af.config.frame_size.width =
ALIGN(css->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
acc->af.config.frame_size.height =
css->rect[IPU3_CSS_RECT_BDS].height;
css_pipe->rect[IPU3_CSS_RECT_BDS].height;
if (acc->stripe.bds_out_stripes[0].width <= min_overlap)
return -EINVAL;
@ -2529,7 +2550,7 @@ int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
for (i = 0; i < stripes; i++) {
acc->af.stripes[i].grid_cfg = acc->af.config.grid_cfg;
acc->af.stripes[i].frame_size.height =
css->rect[IPU3_CSS_RECT_BDS].height;
css_pipe->rect[IPU3_CSS_RECT_BDS].height;
acc->af.stripes[i].frame_size.width =
acc->stripe.bds_out_stripes[i].width;
}
@ -2580,7 +2601,7 @@ int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
acc->af.stripes[i].grid_cfg.height_per_slice = 1;
}
if (ipu3_css_af_ops_calc(css, &acc->af))
if (ipu3_css_af_ops_calc(css, pipe, &acc->af))
return -EINVAL;
/* acc_param: awb_config */
@ -2649,7 +2670,7 @@ int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
acc->awb.stripes[i].grid.height_per_slice = 1;
}
if (ipu3_css_awb_ops_calc(css, &acc->awb))
if (ipu3_css_awb_ops_calc(css, pipe, &acc->awb))
return -EINVAL;
return 0;
@ -2664,7 +2685,8 @@ int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
* to the structure inside `new_binary_params'. In that case the caller
* should calculate and fill the structure from scratch.
*/
static void *ipu3_css_cfg_copy(struct ipu3_css *css, bool use_user,
static void *ipu3_css_cfg_copy(struct ipu3_css *css,
unsigned int pipe, bool use_user,
void *user_setting, void *old_binary_params,
void *new_binary_params,
enum imgu_abi_memories m,
@ -2674,8 +2696,8 @@ static void *ipu3_css_cfg_copy(struct ipu3_css *css, bool use_user,
const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
void *new_setting, *old_setting;
new_setting = ipu3_css_fw_pipeline_params(css, c, m, par, par_size,
new_binary_params);
new_setting = ipu3_css_fw_pipeline_params(css, pipe, c, m, par,
par_size, new_binary_params);
if (!new_setting)
return ERR_PTR(-EPROTO); /* Corrupted firmware */
@ -2684,7 +2706,7 @@ static void *ipu3_css_cfg_copy(struct ipu3_css *css, bool use_user,
memcpy(new_setting, user_setting, par_size);
} else if (old_binary_params) {
/* Take previous value */
old_setting = ipu3_css_fw_pipeline_params(css, c, m, par,
old_setting = ipu3_css_fw_pipeline_params(css, pipe, c, m, par,
par_size,
old_binary_params);
if (!old_setting)
@ -2700,12 +2722,13 @@ static void *ipu3_css_cfg_copy(struct ipu3_css *css, bool use_user,
/*
* Configure VMEM0 parameters (late binding parameters).
*/
int ipu3_css_cfg_vmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
int ipu3_css_cfg_vmem0(struct ipu3_css *css, unsigned int pipe,
struct ipu3_uapi_flags *use,
void *vmem0, void *vmem0_old,
struct ipu3_uapi_params *user)
{
const struct imgu_fw_info *bi =
&css->fwp->binary_header[css->current_binary];
&css->fwp->binary_header[css->pipes[pipe].bindex];
struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp +
bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM];
struct ipu3_uapi_isp_lin_vmem_params *lin_vmem = NULL;
@ -2721,7 +2744,7 @@ int ipu3_css_cfg_vmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
/* Configure Linearization VMEM0 parameters */
lin_vmem = ipu3_css_cfg_copy(css, use && use->lin_vmem_params,
lin_vmem = ipu3_css_cfg_copy(css, pipe, use && use->lin_vmem_params,
&user->lin_vmem_params, vmem0_old, vmem0,
m, &pofs->vmem.lin, sizeof(*lin_vmem));
if (!IS_ERR_OR_NULL(lin_vmem)) {
@ -2740,8 +2763,9 @@ int ipu3_css_cfg_vmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
}
/* Configure TNR3 VMEM parameters */
if (css->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
tnr_vmem = ipu3_css_cfg_copy(css, use && use->tnr3_vmem_params,
if (css->pipes[pipe].pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
tnr_vmem = ipu3_css_cfg_copy(css, pipe,
use && use->tnr3_vmem_params,
&user->tnr3_vmem_params,
vmem0_old, vmem0, m,
&pofs->vmem.tnr3,
@ -2756,7 +2780,7 @@ int ipu3_css_cfg_vmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
/* Configure XNR3 VMEM parameters */
xnr_vmem = ipu3_css_cfg_copy(css, use && use->xnr3_vmem_params,
xnr_vmem = ipu3_css_cfg_copy(css, pipe, use && use->xnr3_vmem_params,
&user->xnr3_vmem_params, vmem0_old, vmem0,
m, &pofs->vmem.xnr3, sizeof(*xnr_vmem));
if (!IS_ERR_OR_NULL(xnr_vmem)) {
@ -2777,12 +2801,14 @@ int ipu3_css_cfg_vmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
/*
* Configure DMEM0 parameters (late binding parameters).
*/
int ipu3_css_cfg_dmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
int ipu3_css_cfg_dmem0(struct ipu3_css *css, unsigned int pipe,
struct ipu3_uapi_flags *use,
void *dmem0, void *dmem0_old,
struct ipu3_uapi_params *user)
{
struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
const struct imgu_fw_info *bi =
&css->fwp->binary_header[css->current_binary];
&css->fwp->binary_header[css_pipe->bindex];
struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp +
bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM];
@ -2797,10 +2823,12 @@ int ipu3_css_cfg_dmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
memset(dmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size);
/* Configure TNR3 DMEM0 parameters */
if (css->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
tnr_dmem = ipu3_css_cfg_copy(css, use && use->tnr3_dmem_params,
&user->tnr3_dmem_params, dmem0_old,
dmem0, m, &pofs->dmem.tnr3,
if (css_pipe->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
tnr_dmem = ipu3_css_cfg_copy(css, pipe,
use && use->tnr3_dmem_params,
&user->tnr3_dmem_params,
dmem0_old, dmem0, m,
&pofs->dmem.tnr3,
sizeof(*tnr_dmem));
if (!IS_ERR_OR_NULL(tnr_dmem)) {
/* Generate parameter from scratch */
@ -2811,7 +2839,7 @@ int ipu3_css_cfg_dmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
/* Configure XNR3 DMEM0 parameters */
xnr_dmem = ipu3_css_cfg_copy(css, use && use->xnr3_dmem_params,
xnr_dmem = ipu3_css_cfg_copy(css, pipe, use && use->xnr3_dmem_params,
&user->xnr3_dmem_params, dmem0_old, dmem0,
m, &pofs->dmem.xnr3, sizeof(*xnr_dmem));
if (!IS_ERR_OR_NULL(xnr_dmem)) {

View File

@ -4,16 +4,19 @@
#ifndef __IPU3_PARAMS_H
#define __IPU3_PARAMS_H
int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
int ipu3_css_cfg_acc(struct ipu3_css *css, unsigned int pipe,
struct ipu3_uapi_flags *use,
struct imgu_abi_acc_param *acc,
struct imgu_abi_acc_param *acc_old,
struct ipu3_uapi_acc_param *acc_user);
int ipu3_css_cfg_vmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
int ipu3_css_cfg_vmem0(struct ipu3_css *css, unsigned int pipe,
struct ipu3_uapi_flags *use,
void *vmem0, void *vmem0_old,
struct ipu3_uapi_params *user);
int ipu3_css_cfg_dmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
int ipu3_css_cfg_dmem0(struct ipu3_css *css, unsigned int pipe,
struct ipu3_uapi_flags *use,
void *dmem0, void *dmem0_old,
struct ipu3_uapi_params *user);

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,7 @@
/* 2 stages for split isp pipeline, 1 for scaling */
#define IMGU_NUM_SP 2
#define IMGU_MAX_PIPELINE_NUM 20
#define IMGU_MAX_PIPE_NUM 2
/* For DVS etc., format FRAME_FMT_YUV420_16 */
#define IPU3_CSS_AUX_FRAME_REF 0
@ -57,12 +58,6 @@ struct ipu3_css_resolution {
u32 h;
};
enum ipu3_css_vf_status {
IPU3_NODE_VF_ENABLED,
IPU3_NODE_PV_ENABLED,
IPU3_NODE_VF_DISABLED
};
enum ipu3_css_buffer_state {
IPU3_CSS_BUFFER_NEW, /* Not yet queued */
IPU3_CSS_BUFFER_QUEUED, /* Queued, waiting to be filled */
@ -77,6 +72,7 @@ struct ipu3_css_buffer {
enum ipu3_css_buffer_state state;
struct list_head list;
u8 queue_pos;
unsigned int pipe;
};
struct ipu3_css_format {
@ -100,33 +96,32 @@ struct ipu3_css_queue {
} fmt;
const struct ipu3_css_format *css_fmt;
unsigned int width_pad; /* bytesperline / byp */
unsigned int width_pad;
struct list_head bufs;
};
/* IPU3 Camera Sub System structure */
struct ipu3_css {
struct device *dev;
void __iomem *base;
const struct firmware *fw;
struct imgu_fw_header *fwp;
int iomem_length;
int fw_bl, fw_sp[IMGU_NUM_SP]; /* Indices of bl and SP binaries */
struct ipu3_css_map *binary; /* fw binaries mapped to device */
unsigned int current_binary; /* Currently selected binary */
bool streaming; /* true when streaming is enabled */
enum ipu3_css_pipe_id pipe_id; /* CSS pipe ID. */
struct ipu3_css_pipe {
enum ipu3_css_pipe_id pipe_id;
unsigned int bindex;
struct ipu3_css_queue queue[IPU3_CSS_QUEUES];
struct v4l2_rect rect[IPU3_CSS_RECTS];
bool vf_output_en;
/* Protect access to queue[IPU3_CSS_QUEUES] */
spinlock_t qlock;
/* Data structures shared with IMGU and driver, always allocated */
struct ipu3_css_map sp_ddr_ptrs;
struct ipu3_css_map xmem_sp_stage_ptrs[IPU3_CSS_PIPE_ID_NUM]
[IMGU_ABI_MAX_STAGES];
struct ipu3_css_map xmem_isp_stage_ptrs[IPU3_CSS_PIPE_ID_NUM]
[IMGU_ABI_MAX_STAGES];
struct ipu3_css_map sp_ddr_ptrs;
struct ipu3_css_map xmem_sp_group_ptrs;
/* Data structures shared with IMGU and driver, binary specific */
/* PARAM_CLASS_CONFIG and PARAM_CLASS_STATE parameters */
/*
* Data structures shared with IMGU and driver, binary specific.
* PARAM_CLASS_CONFIG and PARAM_CLASS_STATE parameters.
*/
struct ipu3_css_map binary_params_cs[IMGU_ABI_PARAM_CLASS_NUM - 1]
[IMGU_ABI_NUM_MEMORIES];
@ -138,11 +133,6 @@ struct ipu3_css {
unsigned int bytesperpixel;
} aux_frames[IPU3_CSS_AUX_FRAME_TYPES];
struct ipu3_css_queue queue[IPU3_CSS_QUEUES];
struct v4l2_rect rect[IPU3_CSS_RECTS];
struct ipu3_css_map abi_buffers[IPU3_CSS_QUEUES]
[IMGU_ABI_HOST2SP_BUFQ_SIZE];
struct {
struct ipu3_css_pool parameter_set_info;
struct ipu3_css_pool acc;
@ -152,9 +142,26 @@ struct ipu3_css {
struct ipu3_css_pool binary_params_p[IMGU_ABI_NUM_MEMORIES];
} pool;
enum ipu3_css_vf_status vf_output_en;
/* Protect access to css->queue[] */
spinlock_t qlock;
struct ipu3_css_map abi_buffers[IPU3_CSS_QUEUES]
[IMGU_ABI_HOST2SP_BUFQ_SIZE];
};
/* IPU3 Camera Sub System structure */
struct ipu3_css {
struct device *dev;
void __iomem *base;
const struct firmware *fw;
struct imgu_fw_header *fwp;
int iomem_length;
int fw_bl, fw_sp[IMGU_NUM_SP]; /* Indices of bl and SP binaries */
struct ipu3_css_map *binary; /* fw binaries mapped to device */
bool streaming; /* true when streaming is enabled */
struct ipu3_css_pipe pipes[IMGU_MAX_PIPE_NUM];
struct ipu3_css_map xmem_sp_group_ptrs;
/* enabled pipe(s) */
DECLARE_BITMAP(enabled_pipes, IMGU_MAX_PIPE_NUM);
};
/******************* css v4l *******************/
@ -163,17 +170,21 @@ int ipu3_css_init(struct device *dev, struct ipu3_css *css,
void ipu3_css_cleanup(struct ipu3_css *css);
int ipu3_css_fmt_try(struct ipu3_css *css,
struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
struct v4l2_rect *rects[IPU3_CSS_RECTS]);
struct v4l2_rect *rects[IPU3_CSS_RECTS],
unsigned int pipe);
int ipu3_css_fmt_set(struct ipu3_css *css,
struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
struct v4l2_rect *rects[IPU3_CSS_RECTS]);
struct v4l2_rect *rects[IPU3_CSS_RECTS],
unsigned int pipe);
int ipu3_css_meta_fmt_set(struct v4l2_meta_format *fmt);
int ipu3_css_buf_queue(struct ipu3_css *css, struct ipu3_css_buffer *b);
int ipu3_css_buf_queue(struct ipu3_css *css, unsigned int pipe,
struct ipu3_css_buffer *b);
struct ipu3_css_buffer *ipu3_css_buf_dequeue(struct ipu3_css *css);
int ipu3_css_start_streaming(struct ipu3_css *css);
void ipu3_css_stop_streaming(struct ipu3_css *css);
bool ipu3_css_queue_empty(struct ipu3_css *css);
bool ipu3_css_is_streaming(struct ipu3_css *css);
bool ipu3_css_pipe_queue_empty(struct ipu3_css *css, unsigned int pipe);
/******************* css hw *******************/
int ipu3_css_set_powerup(struct device *dev, void __iomem *base);
@ -181,10 +192,10 @@ void ipu3_css_set_powerdown(struct device *dev, void __iomem *base);
int ipu3_css_irq_ack(struct ipu3_css *css);
/******************* set parameters ************/
int ipu3_css_set_parameters(struct ipu3_css *css,
int ipu3_css_set_parameters(struct ipu3_css *css, unsigned int pipe,
struct ipu3_uapi_params *set_params);
/******************* css misc *******************/
/******************* auxiliary helpers *******************/
static inline enum ipu3_css_buffer_state
ipu3_css_buf_state(struct ipu3_css_buffer *b)
{

File diff suppressed because it is too large Load Diff

View File

@ -45,7 +45,6 @@ static const struct imgu_node_mapping imgu_node_map[IMGU_NODE_NUM] = {
[IMGU_NODE_PARAMS] = {IPU3_CSS_QUEUE_PARAMS, "parameters"},
[IMGU_NODE_OUT] = {IPU3_CSS_QUEUE_OUT, "output"},
[IMGU_NODE_VF] = {IPU3_CSS_QUEUE_VF, "viewfinder"},
[IMGU_NODE_PV] = {IPU3_CSS_QUEUE_VF, "postview"},
[IMGU_NODE_STAT_3A] = {IPU3_CSS_QUEUE_STAT_3A, "3a stat"},
};
@ -58,10 +57,6 @@ unsigned int imgu_map_node(struct imgu_device *imgu, unsigned int css_queue)
{
unsigned int i;
if (css_queue == IPU3_CSS_QUEUE_VF)
return imgu->nodes[IMGU_NODE_VF].enabled ?
IMGU_NODE_VF : IMGU_NODE_PV;
for (i = 0; i < IMGU_NODE_NUM; i++)
if (imgu_node_map[i].css_queue == css_queue)
break;
@ -71,18 +66,22 @@ unsigned int imgu_map_node(struct imgu_device *imgu, unsigned int css_queue)
/**************** Dummy buffers ****************/
static void imgu_dummybufs_cleanup(struct imgu_device *imgu)
static void imgu_dummybufs_cleanup(struct imgu_device *imgu, unsigned int pipe)
{
unsigned int i;
struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
for (i = 0; i < IPU3_CSS_QUEUES; i++)
ipu3_dmamap_free(imgu, &imgu->queues[i].dmap);
ipu3_dmamap_free(imgu,
&imgu_pipe->queues[i].dmap);
}
static int imgu_dummybufs_preallocate(struct imgu_device *imgu)
static int imgu_dummybufs_preallocate(struct imgu_device *imgu,
unsigned int pipe)
{
unsigned int i;
size_t size;
struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
for (i = 0; i < IPU3_CSS_QUEUES; i++) {
size = css_queue_buf_size_map[i];
@ -94,8 +93,9 @@ static int imgu_dummybufs_preallocate(struct imgu_device *imgu)
if (i == IMGU_QUEUE_MASTER || size == 0)
continue;
if (!ipu3_dmamap_alloc(imgu, &imgu->queues[i].dmap, size)) {
imgu_dummybufs_cleanup(imgu);
if (!ipu3_dmamap_alloc(imgu,
&imgu_pipe->queues[i].dmap, size)) {
imgu_dummybufs_cleanup(imgu, pipe);
return -ENOMEM;
}
}
@ -103,45 +103,46 @@ static int imgu_dummybufs_preallocate(struct imgu_device *imgu)
return 0;
}
static int imgu_dummybufs_init(struct imgu_device *imgu)
static int imgu_dummybufs_init(struct imgu_device *imgu, unsigned int pipe)
{
const struct v4l2_pix_format_mplane *mpix;
const struct v4l2_meta_format *meta;
unsigned int i, j, node;
unsigned int i, k, node;
size_t size;
struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
/* Allocate a dummy buffer for each queue where buffer is optional */
for (i = 0; i < IPU3_CSS_QUEUES; i++) {
node = imgu_map_node(imgu, i);
if (!imgu->queue_enabled[node] || i == IMGU_QUEUE_MASTER)
if (!imgu_pipe->queue_enabled[node] || i == IMGU_QUEUE_MASTER)
continue;
if (!imgu->nodes[IMGU_NODE_VF].enabled &&
!imgu->nodes[IMGU_NODE_PV].enabled &&
if (!imgu_pipe->nodes[IMGU_NODE_VF].enabled &&
i == IPU3_CSS_QUEUE_VF)
/*
* Do not enable dummy buffers for VF/PV if it is not
* Do not enable dummy buffers for VF if it is not
* requested by the user.
*/
continue;
meta = &imgu->nodes[node].vdev_fmt.fmt.meta;
mpix = &imgu->nodes[node].vdev_fmt.fmt.pix_mp;
meta = &imgu_pipe->nodes[node].vdev_fmt.fmt.meta;
mpix = &imgu_pipe->nodes[node].vdev_fmt.fmt.pix_mp;
if (node == IMGU_NODE_STAT_3A || node == IMGU_NODE_PARAMS)
size = meta->buffersize;
else
size = mpix->plane_fmt[0].sizeimage;
if (ipu3_css_dma_buffer_resize(imgu, &imgu->queues[i].dmap,
if (ipu3_css_dma_buffer_resize(imgu,
&imgu_pipe->queues[i].dmap,
size)) {
imgu_dummybufs_cleanup(imgu);
imgu_dummybufs_cleanup(imgu, pipe);
return -ENOMEM;
}
for (j = 0; j < IMGU_MAX_QUEUE_DEPTH; j++)
ipu3_css_buf_init(&imgu->queues[i].dummybufs[j], i,
imgu->queues[i].dmap.daddr);
for (k = 0; k < IMGU_MAX_QUEUE_DEPTH; k++)
ipu3_css_buf_init(&imgu_pipe->queues[i].dummybufs[k], i,
imgu_pipe->queues[i].dmap.daddr);
}
return 0;
@ -149,40 +150,43 @@ static int imgu_dummybufs_init(struct imgu_device *imgu)
/* May be called from atomic context */
static struct ipu3_css_buffer *imgu_dummybufs_get(struct imgu_device *imgu,
int queue)
int queue, unsigned int pipe)
{
unsigned int i;
struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
/* dummybufs are not allocated for master q */
if (queue == IPU3_CSS_QUEUE_IN)
return NULL;
if (WARN_ON(!imgu->queues[queue].dmap.vaddr))
if (WARN_ON(!imgu_pipe->queues[queue].dmap.vaddr))
/* Buffer should not be allocated here */
return NULL;
for (i = 0; i < IMGU_MAX_QUEUE_DEPTH; i++)
if (ipu3_css_buf_state(&imgu->queues[queue].dummybufs[i]) !=
if (ipu3_css_buf_state(&imgu_pipe->queues[queue].dummybufs[i]) !=
IPU3_CSS_BUFFER_QUEUED)
break;
if (i == IMGU_MAX_QUEUE_DEPTH)
return NULL;
ipu3_css_buf_init(&imgu->queues[queue].dummybufs[i], queue,
imgu->queues[queue].dmap.daddr);
ipu3_css_buf_init(&imgu_pipe->queues[queue].dummybufs[i], queue,
imgu_pipe->queues[queue].dmap.daddr);
return &imgu->queues[queue].dummybufs[i];
return &imgu_pipe->queues[queue].dummybufs[i];
}
/* Check if given buffer is a dummy buffer */
static bool imgu_dummybufs_check(struct imgu_device *imgu,
struct ipu3_css_buffer *buf)
struct ipu3_css_buffer *buf,
unsigned int pipe)
{
unsigned int i;
struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
for (i = 0; i < IMGU_MAX_QUEUE_DEPTH; i++)
if (buf == &imgu->queues[buf->queue].dummybufs[i])
if (buf == &imgu_pipe->queues[buf->queue].dummybufs[i])
break;
return i < IMGU_MAX_QUEUE_DEPTH;
@ -197,63 +201,64 @@ static void imgu_buffer_done(struct imgu_device *imgu, struct vb2_buffer *vb,
}
static struct ipu3_css_buffer *imgu_queue_getbuf(struct imgu_device *imgu,
unsigned int node)
unsigned int node,
unsigned int pipe)
{
struct imgu_buffer *buf;
struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
if (WARN_ON(node >= IMGU_NODE_NUM))
return NULL;
/* Find first free buffer from the node */
list_for_each_entry(buf, &imgu->nodes[node].buffers, vid_buf.list) {
list_for_each_entry(buf, &imgu_pipe->nodes[node].buffers, vid_buf.list) {
if (ipu3_css_buf_state(&buf->css_buf) == IPU3_CSS_BUFFER_NEW)
return &buf->css_buf;
}
/* There were no free buffers, try to return a dummy buffer */
return imgu_dummybufs_get(imgu, imgu_node_map[node].css_queue);
return imgu_dummybufs_get(imgu, imgu_node_map[node].css_queue, pipe);
}
/*
* Queue as many buffers to CSS as possible. If all buffers don't fit into
* CSS buffer queues, they remain unqueued and will be queued later.
*/
int imgu_queue_buffers(struct imgu_device *imgu, bool initial)
int imgu_queue_buffers(struct imgu_device *imgu, bool initial, unsigned int pipe)
{
unsigned int node;
int r = 0;
struct imgu_buffer *ibuf;
struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
if (!ipu3_css_is_streaming(&imgu->css))
return 0;
dev_dbg(&imgu->pci_dev->dev, "Queue buffers to pipe %d", pipe);
mutex_lock(&imgu->lock);
/* Buffer set is queued to FW only when input buffer is ready */
for (node = IMGU_NODE_NUM - 1;
imgu_queue_getbuf(imgu, IMGU_NODE_IN);
imgu_queue_getbuf(imgu, IMGU_NODE_IN, pipe);
node = node ? node - 1 : IMGU_NODE_NUM - 1) {
if (node == IMGU_NODE_VF &&
(imgu->css.pipe_id == IPU3_CSS_PIPE_ID_CAPTURE ||
!imgu->nodes[IMGU_NODE_VF].enabled)) {
!imgu_pipe->nodes[IMGU_NODE_VF].enabled) {
dev_warn(&imgu->pci_dev->dev,
"Vf not enabled, ignore queue");
continue;
} else if (node == IMGU_NODE_PV &&
(imgu->css.pipe_id == IPU3_CSS_PIPE_ID_VIDEO ||
!imgu->nodes[IMGU_NODE_PV].enabled)) {
continue;
} else if (imgu->queue_enabled[node]) {
} else if (imgu_pipe->queue_enabled[node]) {
struct ipu3_css_buffer *buf =
imgu_queue_getbuf(imgu, node);
imgu_queue_getbuf(imgu, node, pipe);
int dummy;
if (!buf)
break;
r = ipu3_css_buf_queue(&imgu->css, buf);
r = ipu3_css_buf_queue(&imgu->css, pipe, buf);
if (r)
break;
dummy = imgu_dummybufs_check(imgu, buf);
dummy = imgu_dummybufs_check(imgu, buf, pipe);
if (!dummy)
ibuf = container_of(buf, struct imgu_buffer,
css_buf);
@ -288,14 +293,15 @@ failed:
for (node = 0; node < IMGU_NODE_NUM; node++) {
struct imgu_buffer *buf, *buf0;
if (!imgu->queue_enabled[node])
if (!imgu_pipe->queue_enabled[node])
continue; /* Skip disabled queues */
mutex_lock(&imgu->lock);
list_for_each_entry_safe(buf, buf0, &imgu->nodes[node].buffers,
list_for_each_entry_safe(buf, buf0,
&imgu_pipe->nodes[node].buffers,
vid_buf.list) {
if (ipu3_css_buf_state(&buf->css_buf) ==
IPU3_CSS_BUFFER_QUEUED)
IPU3_CSS_BUFFER_QUEUED)
continue; /* Was already queued, skip */
imgu_v4l2_buffer_done(&buf->vid_buf.vbb.vb2_buf,
@ -328,10 +334,7 @@ static void imgu_powerdown(struct imgu_device *imgu)
int imgu_s_stream(struct imgu_device *imgu, int enable)
{
struct device *dev = &imgu->pci_dev->dev;
struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES] = { NULL };
struct v4l2_rect *rects[IPU3_CSS_RECTS] = { NULL };
unsigned int i, node;
int r;
int r, pipe;
if (!enable) {
/* Stop streaming */
@ -347,54 +350,6 @@ int imgu_s_stream(struct imgu_device *imgu, int enable)
return 0;
}
/* Start streaming */
dev_dbg(dev, "stream on\n");
for (i = 0; i < IMGU_NODE_NUM; i++)
imgu->queue_enabled[i] = imgu->nodes[i].enabled;
/*
* CSS library expects that the following queues are
* always enabled; if buffers are not provided to some of the
* queues, it stalls due to lack of buffers.
* Force the queues to be enabled and if the user really hasn't
* enabled them, use dummy buffers.
*/
imgu->queue_enabled[IMGU_NODE_OUT] = true;
imgu->queue_enabled[IMGU_NODE_VF] = true;
imgu->queue_enabled[IMGU_NODE_PV] = true;
imgu->queue_enabled[IMGU_NODE_STAT_3A] = true;
/* This is handled specially */
imgu->queue_enabled[IPU3_CSS_QUEUE_PARAMS] = false;
/* Initialize CSS formats */
for (i = 0; i < IPU3_CSS_QUEUES; i++) {
node = imgu_map_node(imgu, i);
/* No need to reconfig meta nodes */
if (node == IMGU_NODE_STAT_3A || node == IMGU_NODE_PARAMS)
continue;
fmts[i] = imgu->queue_enabled[node] ?
&imgu->nodes[node].vdev_fmt.fmt.pix_mp : NULL;
}
/* Enable VF output only when VF or PV queue requested by user */
imgu->css.vf_output_en = IPU3_NODE_VF_DISABLED;
if (imgu->nodes[IMGU_NODE_VF].enabled)
imgu->css.vf_output_en = IPU3_NODE_VF_ENABLED;
else if (imgu->nodes[IMGU_NODE_PV].enabled)
imgu->css.vf_output_en = IPU3_NODE_PV_ENABLED;
rects[IPU3_CSS_RECT_EFFECTIVE] = &imgu->rect.eff;
rects[IPU3_CSS_RECT_BDS] = &imgu->rect.bds;
rects[IPU3_CSS_RECT_GDC] = &imgu->rect.gdc;
r = ipu3_css_fmt_set(&imgu->css, fmts, rects);
if (r) {
dev_err(dev, "failed to set initial formats (%d)", r);
return r;
}
/* Set Power */
r = pm_runtime_get_sync(dev);
if (r < 0) {
@ -417,24 +372,26 @@ int imgu_s_stream(struct imgu_device *imgu, int enable)
goto fail_start_streaming;
}
/* Initialize dummy buffers */
r = imgu_dummybufs_init(imgu);
if (r) {
dev_err(dev, "failed to initialize dummy buffers (%d)", r);
goto fail_dummybufs;
}
for_each_set_bit(pipe, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM) {
/* Initialize dummy buffers */
r = imgu_dummybufs_init(imgu, pipe);
if (r) {
dev_err(dev, "failed to initialize dummy buffers (%d)", r);
goto fail_dummybufs;
}
/* Queue as many buffers from queue as possible */
r = imgu_queue_buffers(imgu, true);
if (r) {
dev_err(dev, "failed to queue initial buffers (%d)", r);
goto fail_queueing;
/* Queue as many buffers from queue as possible */
r = imgu_queue_buffers(imgu, true, pipe);
if (r) {
dev_err(dev, "failed to queue initial buffers (%d)", r);
goto fail_queueing;
}
}
return 0;
fail_queueing:
imgu_dummybufs_cleanup(imgu);
for_each_set_bit(pipe, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM)
imgu_dummybufs_cleanup(imgu, pipe);
fail_dummybufs:
ipu3_css_stop_streaming(&imgu->css);
fail_start_streaming:
@ -447,51 +404,66 @@ static int imgu_video_nodes_init(struct imgu_device *imgu)
{
struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES] = { NULL };
struct v4l2_rect *rects[IPU3_CSS_RECTS] = { NULL };
unsigned int i;
struct imgu_media_pipe *imgu_pipe;
unsigned int i, j;
int r;
imgu->buf_struct_size = sizeof(struct imgu_buffer);
for (i = 0; i < IMGU_NODE_NUM; i++) {
imgu->nodes[i].name = imgu_node_map[i].name;
imgu->nodes[i].output = i < IMGU_QUEUE_FIRST_INPUT;
imgu->nodes[i].immutable = false;
imgu->nodes[i].enabled = false;
for (j = 0; j < IMGU_MAX_PIPE_NUM; j++) {
imgu_pipe = &imgu->imgu_pipe[j];
if (i != IMGU_NODE_PARAMS && i != IMGU_NODE_STAT_3A)
fmts[imgu_node_map[i].css_queue] =
&imgu->nodes[i].vdev_fmt.fmt.pix_mp;
atomic_set(&imgu->nodes[i].sequence, 0);
for (i = 0; i < IMGU_NODE_NUM; i++) {
imgu_pipe->nodes[i].name = imgu_node_map[i].name;
imgu_pipe->nodes[i].output = i < IMGU_QUEUE_FIRST_INPUT;
imgu_pipe->nodes[i].enabled = false;
if (i != IMGU_NODE_PARAMS && i != IMGU_NODE_STAT_3A)
fmts[imgu_node_map[i].css_queue] =
&imgu_pipe->nodes[i].vdev_fmt.fmt.pix_mp;
atomic_set(&imgu_pipe->nodes[i].sequence, 0);
}
}
/* Master queue is always enabled */
imgu->nodes[IMGU_QUEUE_MASTER].immutable = true;
imgu->nodes[IMGU_QUEUE_MASTER].enabled = true;
r = imgu_v4l2_register(imgu);
if (r)
return r;
/* Set initial formats and initialize formats of video nodes */
rects[IPU3_CSS_RECT_EFFECTIVE] = &imgu->rect.eff;
rects[IPU3_CSS_RECT_BDS] = &imgu->rect.bds;
ipu3_css_fmt_set(&imgu->css, fmts, rects);
for (j = 0; j < IMGU_MAX_PIPE_NUM; j++) {
imgu_pipe = &imgu->imgu_pipe[j];
/* Pre-allocate dummy buffers */
r = imgu_dummybufs_preallocate(imgu);
if (r) {
dev_err(&imgu->pci_dev->dev,
"failed to pre-allocate dummy buffers (%d)", r);
imgu_dummybufs_cleanup(imgu);
imgu_v4l2_unregister(imgu);
rects[IPU3_CSS_RECT_EFFECTIVE] = &imgu_pipe->imgu_sd.rect.eff;
rects[IPU3_CSS_RECT_BDS] = &imgu_pipe->imgu_sd.rect.bds;
ipu3_css_fmt_set(&imgu->css, fmts, rects, j);
/* Pre-allocate dummy buffers */
r = imgu_dummybufs_preallocate(imgu, j);
if (r) {
dev_err(&imgu->pci_dev->dev,
"failed to pre-allocate dummy buffers (%d)", r);
goto out_cleanup;
}
}
return 0;
out_cleanup:
for (j = 0; j < IMGU_MAX_PIPE_NUM; j++)
imgu_dummybufs_cleanup(imgu, j);
imgu_v4l2_unregister(imgu);
return r;
}
static void imgu_video_nodes_exit(struct imgu_device *imgu)
{
imgu_dummybufs_cleanup(imgu);
int i;
for (i = 0; i < IMGU_MAX_PIPE_NUM; i++)
imgu_dummybufs_cleanup(imgu, i);
imgu_v4l2_unregister(imgu);
}
@ -500,13 +472,15 @@ static void imgu_video_nodes_exit(struct imgu_device *imgu)
static irqreturn_t imgu_isr_threaded(int irq, void *imgu_ptr)
{
struct imgu_device *imgu = imgu_ptr;
struct imgu_media_pipe *imgu_pipe;
int p;
/* Dequeue / queue buffers */
do {
u64 ns = ktime_get_ns();
struct ipu3_css_buffer *b;
struct imgu_buffer *buf;
unsigned int node;
unsigned int node, pipe;
bool dummy;
do {
@ -525,25 +499,31 @@ static irqreturn_t imgu_isr_threaded(int irq, void *imgu_ptr)
}
node = imgu_map_node(imgu, b->queue);
dummy = imgu_dummybufs_check(imgu, b);
pipe = b->pipe;
dummy = imgu_dummybufs_check(imgu, b, pipe);
if (!dummy)
buf = container_of(b, struct imgu_buffer, css_buf);
dev_dbg(&imgu->pci_dev->dev,
"dequeue %s %s buffer %d from css\n",
"dequeue %s %s buffer %d daddr 0x%x from css\n",
dummy ? "dummy" : "user",
imgu_node_map[node].name,
dummy ? 0 : buf->vid_buf.vbb.vb2_buf.index);
dummy ? 0 : buf->vid_buf.vbb.vb2_buf.index,
(u32)b->daddr);
if (dummy)
/* It was a dummy buffer, skip it */
continue;
/* Fill vb2 buffer entries and tell it's ready */
if (!imgu->nodes[node].output) {
imgu_pipe = &imgu->imgu_pipe[pipe];
if (!imgu_pipe->nodes[node].output) {
buf->vid_buf.vbb.vb2_buf.timestamp = ns;
buf->vid_buf.vbb.field = V4L2_FIELD_NONE;
buf->vid_buf.vbb.sequence =
atomic_inc_return(&imgu->nodes[node].sequence);
atomic_inc_return(
&imgu_pipe->nodes[node].sequence);
dev_dbg(&imgu->pci_dev->dev, "vb2 buffer sequence %d",
buf->vid_buf.vbb.sequence);
}
imgu_buffer_done(imgu, &buf->vid_buf.vbb.vb2_buf,
ipu3_css_buf_state(&buf->css_buf) ==
@ -562,7 +542,8 @@ static irqreturn_t imgu_isr_threaded(int irq, void *imgu_ptr)
* to be queued to CSS.
*/
if (!atomic_read(&imgu->qbuf_barrier))
imgu_queue_buffers(imgu, false);
for_each_set_bit(p, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM)
imgu_queue_buffers(imgu, false, p);
return IRQ_HANDLED;
}
@ -772,6 +753,7 @@ static int __maybe_unused imgu_resume(struct device *dev)
struct pci_dev *pci_dev = to_pci_dev(dev);
struct imgu_device *imgu = pci_get_drvdata(pci_dev);
int r = 0;
unsigned int pipe;
dev_dbg(dev, "enter %s\n", __func__);
@ -793,9 +775,13 @@ static int __maybe_unused imgu_resume(struct device *dev)
goto out;
}
r = imgu_queue_buffers(imgu, true);
if (r)
dev_err(dev, "failed to queue buffers (%d)", r);
for_each_set_bit(pipe, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM) {
r = imgu_queue_buffers(imgu, true, pipe);
if (r)
dev_err(dev, "failed to queue buffers to pipe %d (%d)",
pipe, r);
}
out:
dev_dbg(dev, "leave %s\n", __func__);

View File

@ -7,6 +7,7 @@
#include <linux/iova.h>
#include <linux/pci.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/videobuf2-dma-sg.h>
@ -28,9 +29,8 @@
#define IMGU_NODE_PARAMS 1 /* Input parameters */
#define IMGU_NODE_OUT 2 /* Main output for still or video */
#define IMGU_NODE_VF 3 /* Preview */
#define IMGU_NODE_PV 4 /* Postview for still capture */
#define IMGU_NODE_STAT_3A 5 /* 3A statistics */
#define IMGU_NODE_NUM 6
#define IMGU_NODE_STAT_3A 4 /* 3A statistics */
#define IMGU_NODE_NUM 5
#define file_to_intel_ipu3_node(__file) \
container_of(video_devdata(__file), struct imgu_video_device, vdev)
@ -71,7 +71,6 @@ struct imgu_node_mapping {
struct imgu_video_device {
const char *name;
bool output;
bool immutable; /* Can not be enabled/disabled */
bool enabled;
struct v4l2_format vdev_fmt; /* Currently set format */
@ -84,6 +83,37 @@ struct imgu_video_device {
/* Protect vb2_queue and vdev structs*/
struct mutex lock;
atomic_t sequence;
unsigned int id;
unsigned int pipe;
};
struct imgu_v4l2_subdev {
unsigned int pipe;
struct v4l2_subdev subdev;
struct media_pad subdev_pads[IMGU_NODE_NUM];
struct {
struct v4l2_rect eff; /* effective resolution */
struct v4l2_rect bds; /* bayer-domain scaled resolution*/
struct v4l2_rect gdc; /* gdc output resolution */
} rect;
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_ctrl *ctrl;
atomic_t running_mode;
bool active;
};
struct imgu_media_pipe {
unsigned int pipe;
/* Internally enabled queues */
struct {
struct ipu3_css_map dmap;
struct ipu3_css_buffer dummybufs[IMGU_MAX_QUEUE_DEPTH];
} queues[IPU3_CSS_QUEUES];
struct imgu_video_device nodes[IMGU_NODE_NUM];
bool queue_enabled[IMGU_NODE_NUM];
struct media_pipeline pipeline;
struct imgu_v4l2_subdev imgu_sd;
};
/*
@ -93,25 +123,15 @@ struct imgu_device {
struct pci_dev *pci_dev;
void __iomem *base;
/* Internally enabled queues */
struct {
struct ipu3_css_map dmap;
struct ipu3_css_buffer dummybufs[IMGU_MAX_QUEUE_DEPTH];
} queues[IPU3_CSS_QUEUES];
struct imgu_video_device nodes[IMGU_NODE_NUM];
bool queue_enabled[IMGU_NODE_NUM];
/* Public fields, fill before registering */
unsigned int buf_struct_size;
bool streaming; /* Public read only */
struct v4l2_ctrl_handler *ctrl_handler;
struct imgu_media_pipe imgu_pipe[IMGU_MAX_PIPE_NUM];
/* Private fields */
struct v4l2_device v4l2_dev;
struct media_device media_dev;
struct media_pipeline pipeline;
struct v4l2_subdev subdev;
struct media_pad subdev_pads[IMGU_NODE_NUM];
struct v4l2_file_operations v4l2_file_ops;
/* MMU driver for css */
@ -128,11 +148,6 @@ struct imgu_device {
struct mutex lock;
/* Forbit streaming and buffer queuing during system suspend. */
atomic_t qbuf_barrier;
struct {
struct v4l2_rect eff; /* effective resolution */
struct v4l2_rect bds; /* bayer-domain scaled resolution*/
struct v4l2_rect gdc; /* gdc output resolution */
} rect;
/* Indicate if system suspend take place while imgu is streaming. */
bool suspend_in_stream;
/* Used to wait for FW buffer queue drain. */
@ -141,7 +156,8 @@ struct imgu_device {
unsigned int imgu_node_to_queue(unsigned int node);
unsigned int imgu_map_node(struct imgu_device *imgu, unsigned int css_queue);
int imgu_queue_buffers(struct imgu_device *imgu, bool initial);
int imgu_queue_buffers(struct imgu_device *imgu, bool initial,
unsigned int pipe);
int imgu_v4l2_register(struct imgu_device *dev);
int imgu_v4l2_unregister(struct imgu_device *dev);