diff options
Diffstat (limited to 'drivers/media/platform/vsp1/vsp1_rpf.c')
| -rw-r--r-- | drivers/media/platform/vsp1/vsp1_rpf.c | 382 |
1 files changed, 0 insertions, 382 deletions
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c deleted file mode 100644 index 85587c1b6a37..000000000000 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ /dev/null @@ -1,382 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * vsp1_rpf.c -- R-Car VSP1 Read Pixel Formatter - * - * Copyright (C) 2013-2014 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#include <linux/device.h> - -#include <media/v4l2-subdev.h> - -#include "vsp1.h" -#include "vsp1_dl.h" -#include "vsp1_pipe.h" -#include "vsp1_rwpf.h" -#include "vsp1_video.h" - -#define RPF_MAX_WIDTH 8190 -#define RPF_MAX_HEIGHT 8190 - -/* Pre extended display list command data structure. */ -struct vsp1_extcmd_auto_fld_body { - u32 top_y0; - u32 bottom_y0; - u32 top_c0; - u32 bottom_c0; - u32 top_c1; - u32 bottom_c1; - u32 reserved0; - u32 reserved1; -} __packed; - -/* ----------------------------------------------------------------------------- - * Device Access - */ - -static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, - struct vsp1_dl_body *dlb, u32 reg, u32 data) -{ - vsp1_dl_body_write(dlb, reg + rpf->entity.index * VI6_RPF_OFFSET, - data); -} - -/* ----------------------------------------------------------------------------- - * V4L2 Subdevice Operations - */ - -static const struct v4l2_subdev_ops rpf_ops = { - .pad = &vsp1_rwpf_pad_ops, -}; - -/* ----------------------------------------------------------------------------- - * VSP1 Entity Operations - */ - -static void rpf_configure_stream(struct vsp1_entity *entity, - struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl, - struct vsp1_dl_body *dlb) -{ - struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); - const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; - const struct v4l2_pix_format_mplane *format = &rpf->format; - const struct v4l2_mbus_framefmt *source_format; - const struct v4l2_mbus_framefmt *sink_format; - unsigned int left = 0; - unsigned int top = 0; - u32 pstride; - u32 infmt; - - /* Stride */ - pstride = format->plane_fmt[0].bytesperline - << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT; - if (format->num_planes > 1) - pstride |= format->plane_fmt[1].bytesperline - << VI6_RPF_SRCM_PSTRIDE_C_SHIFT; - - /* - * pstride has both STRIDE_Y and STRIDE_C, but multiplying the whole - * of pstride by 2 is conveniently OK here as we are multiplying both - * values. - */ - if (pipe->interlaced) - pstride *= 2; - - vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_PSTRIDE, pstride); - - /* Format */ - sink_format = vsp1_entity_get_pad_format(&rpf->entity, - rpf->entity.config, - RWPF_PAD_SINK); - source_format = vsp1_entity_get_pad_format(&rpf->entity, - rpf->entity.config, - RWPF_PAD_SOURCE); - - infmt = VI6_RPF_INFMT_CIPM - | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT); - - if (fmtinfo->swap_yc) - infmt |= VI6_RPF_INFMT_SPYCS; - if (fmtinfo->swap_uv) - infmt |= VI6_RPF_INFMT_SPUVS; - - if (sink_format->code != source_format->code) - infmt |= VI6_RPF_INFMT_CSC; - - vsp1_rpf_write(rpf, dlb, VI6_RPF_INFMT, infmt); - vsp1_rpf_write(rpf, dlb, VI6_RPF_DSWAP, fmtinfo->swap); - - /* Output location. */ - if (pipe->brx) { - const struct v4l2_rect *compose; - - compose = vsp1_entity_get_pad_selection(pipe->brx, - pipe->brx->config, - rpf->brx_input, - V4L2_SEL_TGT_COMPOSE); - left = compose->left; - top = compose->top; - } - - if (pipe->interlaced) - top /= 2; - - vsp1_rpf_write(rpf, dlb, VI6_RPF_LOC, - (left << VI6_RPF_LOC_HCOORD_SHIFT) | - (top << VI6_RPF_LOC_VCOORD_SHIFT)); - - /* - * On Gen2 use the alpha channel (extended to 8 bits) when available or - * a fixed alpha value set through the V4L2_CID_ALPHA_COMPONENT control - * otherwise. - * - * The Gen3 RPF has extended alpha capability and can both multiply the - * alpha channel by a fixed global alpha value, and multiply the pixel - * components to convert the input to premultiplied alpha. - * - * As alpha premultiplication is available in the BRx for both Gen2 and - * Gen3 we handle it there and use the Gen3 alpha multiplier for global - * alpha multiplication only. This however prevents conversion to - * premultiplied alpha if no BRx is present in the pipeline. If that use - * case turns out to be useful we will revisit the implementation (for - * Gen3 only). - * - * We enable alpha multiplication on Gen3 using the fixed alpha value - * set through the V4L2_CID_ALPHA_COMPONENT control when the input - * contains an alpha channel. On Gen2 the global alpha is ignored in - * that case. - * - * In all cases, disable color keying. - */ - vsp1_rpf_write(rpf, dlb, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT | - (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED - : VI6_RPF_ALPH_SEL_ASEL_FIXED)); - - if (entity->vsp1->info->gen == 3) { - u32 mult; - - if (fmtinfo->alpha) { - /* - * When the input contains an alpha channel enable the - * alpha multiplier. If the input is premultiplied we - * need to multiply both the alpha channel and the pixel - * components by the global alpha value to keep them - * premultiplied. Otherwise multiply the alpha channel - * only. - */ - bool premultiplied = format->flags - & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA; - - mult = VI6_RPF_MULT_ALPHA_A_MMD_RATIO - | (premultiplied ? - VI6_RPF_MULT_ALPHA_P_MMD_RATIO : - VI6_RPF_MULT_ALPHA_P_MMD_NONE); - } else { - /* - * When the input doesn't contain an alpha channel the - * global alpha value is applied in the unpacking unit, - * the alpha multiplier isn't needed and must be - * disabled. - */ - mult = VI6_RPF_MULT_ALPHA_A_MMD_NONE - | VI6_RPF_MULT_ALPHA_P_MMD_NONE; - } - - rpf->mult_alpha = mult; - } - - vsp1_rpf_write(rpf, dlb, VI6_RPF_MSK_CTRL, 0); - vsp1_rpf_write(rpf, dlb, VI6_RPF_CKEY_CTRL, 0); - -} - -static void vsp1_rpf_configure_autofld(struct vsp1_rwpf *rpf, - struct vsp1_dl_list *dl) -{ - const struct v4l2_pix_format_mplane *format = &rpf->format; - struct vsp1_dl_ext_cmd *cmd; - struct vsp1_extcmd_auto_fld_body *auto_fld; - u32 offset_y, offset_c; - - cmd = vsp1_dl_get_pre_cmd(dl); - if (WARN_ONCE(!cmd, "Failed to obtain an autofld cmd")) - return; - - /* Re-index our auto_fld to match the current RPF. */ - auto_fld = cmd->data; - auto_fld = &auto_fld[rpf->entity.index]; - - auto_fld->top_y0 = rpf->mem.addr[0]; - auto_fld->top_c0 = rpf->mem.addr[1]; - auto_fld->top_c1 = rpf->mem.addr[2]; - - offset_y = format->plane_fmt[0].bytesperline; - offset_c = format->plane_fmt[1].bytesperline; - - auto_fld->bottom_y0 = rpf->mem.addr[0] + offset_y; - auto_fld->bottom_c0 = rpf->mem.addr[1] + offset_c; - auto_fld->bottom_c1 = rpf->mem.addr[2] + offset_c; - - cmd->flags |= VI6_DL_EXT_AUTOFLD_INT | BIT(16 + rpf->entity.index); -} - -static void rpf_configure_frame(struct vsp1_entity *entity, - struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl, - struct vsp1_dl_body *dlb) -{ - struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); - - vsp1_rpf_write(rpf, dlb, VI6_RPF_VRTCOL_SET, - rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); - vsp1_rpf_write(rpf, dlb, VI6_RPF_MULT_ALPHA, rpf->mult_alpha | - (rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT)); - - vsp1_pipeline_propagate_alpha(pipe, dlb, rpf->alpha); -} - -static void rpf_configure_partition(struct vsp1_entity *entity, - struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl, - struct vsp1_dl_body *dlb) -{ - struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); - struct vsp1_rwpf_memory mem = rpf->mem; - struct vsp1_device *vsp1 = rpf->entity.vsp1; - const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; - const struct v4l2_pix_format_mplane *format = &rpf->format; - struct v4l2_rect crop; - - /* - * Source size and crop offsets. - * - * The crop offsets correspond to the location of the crop - * rectangle top left corner in the plane buffer. Only two - * offsets are needed, as planes 2 and 3 always have identical - * strides. - */ - crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.config); - - /* - * Partition Algorithm Control - * - * The partition algorithm can split this frame into multiple - * slices. We must scale our partition window based on the pipe - * configuration to match the destination partition window. - * To achieve this, we adjust our crop to provide a 'sub-crop' - * matching the expected partition window. Only 'left' and - * 'width' need to be adjusted. - */ - if (pipe->partitions > 1) { - crop.width = pipe->partition->rpf.width; - crop.left += pipe->partition->rpf.left; - } - - if (pipe->interlaced) { - crop.height = round_down(crop.height / 2, fmtinfo->vsub); - crop.top = round_down(crop.top / 2, fmtinfo->vsub); - } - - vsp1_rpf_write(rpf, dlb, VI6_RPF_SRC_BSIZE, - (crop.width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) | - (crop.height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT)); - vsp1_rpf_write(rpf, dlb, VI6_RPF_SRC_ESIZE, - (crop.width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | - (crop.height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); - - mem.addr[0] += crop.top * format->plane_fmt[0].bytesperline - + crop.left * fmtinfo->bpp[0] / 8; - - if (format->num_planes > 1) { - unsigned int offset; - - offset = crop.top * format->plane_fmt[1].bytesperline - + crop.left / fmtinfo->hsub - * fmtinfo->bpp[1] / 8; - mem.addr[1] += offset; - mem.addr[2] += offset; - } - - /* - * On Gen3 hardware the SPUVS bit has no effect on 3-planar - * formats. Swap the U and V planes manually in that case. - */ - if (vsp1->info->gen == 3 && format->num_planes == 3 && - fmtinfo->swap_uv) - swap(mem.addr[1], mem.addr[2]); - - /* - * Interlaced pipelines will use the extended pre-cmd to process - * SRCM_ADDR_{Y,C0,C1}. - */ - if (pipe->interlaced) { - vsp1_rpf_configure_autofld(rpf, dl); - } else { - vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_Y, mem.addr[0]); - vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_C0, mem.addr[1]); - vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_C1, mem.addr[2]); - } -} - -static void rpf_partition(struct vsp1_entity *entity, - struct vsp1_pipeline *pipe, - struct vsp1_partition *partition, - unsigned int partition_idx, - struct vsp1_partition_window *window) -{ - partition->rpf = *window; -} - -static const struct vsp1_entity_operations rpf_entity_ops = { - .configure_stream = rpf_configure_stream, - .configure_frame = rpf_configure_frame, - .configure_partition = rpf_configure_partition, - .partition = rpf_partition, -}; - -/* ----------------------------------------------------------------------------- - * Initialization and Cleanup - */ - -struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) -{ - struct vsp1_rwpf *rpf; - char name[6]; - int ret; - - rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL); - if (rpf == NULL) - return ERR_PTR(-ENOMEM); - - rpf->max_width = RPF_MAX_WIDTH; - rpf->max_height = RPF_MAX_HEIGHT; - - rpf->entity.ops = &rpf_entity_ops; - rpf->entity.type = VSP1_ENTITY_RPF; - rpf->entity.index = index; - - sprintf(name, "rpf.%u", index); - ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops, - MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); - if (ret < 0) - return ERR_PTR(ret); - - /* Initialize the control handler. */ - ret = vsp1_rwpf_init_ctrls(rpf, 0); - if (ret < 0) { - dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n", - index); - goto error; - } - - v4l2_ctrl_handler_setup(&rpf->ctrls); - - return rpf; - -error: - vsp1_entity_destroy(&rpf->entity); - return ERR_PTR(ret); -} |
