18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * vsp1_rpf.c -- R-Car VSP1 Read Pixel Formatter 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013-2014 Renesas Electronics Corporation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "vsp1.h" 158c2ecf20Sopenharmony_ci#include "vsp1_dl.h" 168c2ecf20Sopenharmony_ci#include "vsp1_pipe.h" 178c2ecf20Sopenharmony_ci#include "vsp1_rwpf.h" 188c2ecf20Sopenharmony_ci#include "vsp1_video.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define RPF_MAX_WIDTH 8190 218c2ecf20Sopenharmony_ci#define RPF_MAX_HEIGHT 8190 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Pre extended display list command data structure. */ 248c2ecf20Sopenharmony_cistruct vsp1_extcmd_auto_fld_body { 258c2ecf20Sopenharmony_ci u32 top_y0; 268c2ecf20Sopenharmony_ci u32 bottom_y0; 278c2ecf20Sopenharmony_ci u32 top_c0; 288c2ecf20Sopenharmony_ci u32 bottom_c0; 298c2ecf20Sopenharmony_ci u32 top_c1; 308c2ecf20Sopenharmony_ci u32 bottom_c1; 318c2ecf20Sopenharmony_ci u32 reserved0; 328c2ecf20Sopenharmony_ci u32 reserved1; 338c2ecf20Sopenharmony_ci} __packed; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 368c2ecf20Sopenharmony_ci * Device Access 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, 408c2ecf20Sopenharmony_ci struct vsp1_dl_body *dlb, u32 reg, u32 data) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci vsp1_dl_body_write(dlb, reg + rpf->entity.index * VI6_RPF_OFFSET, 438c2ecf20Sopenharmony_ci data); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 478c2ecf20Sopenharmony_ci * V4L2 Subdevice Operations 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops rpf_ops = { 518c2ecf20Sopenharmony_ci .pad = &vsp1_rwpf_pad_ops, 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 558c2ecf20Sopenharmony_ci * VSP1 Entity Operations 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void rpf_configure_stream(struct vsp1_entity *entity, 598c2ecf20Sopenharmony_ci struct vsp1_pipeline *pipe, 608c2ecf20Sopenharmony_ci struct vsp1_dl_list *dl, 618c2ecf20Sopenharmony_ci struct vsp1_dl_body *dlb) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); 648c2ecf20Sopenharmony_ci const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; 658c2ecf20Sopenharmony_ci const struct v4l2_pix_format_mplane *format = &rpf->format; 668c2ecf20Sopenharmony_ci const struct v4l2_mbus_framefmt *source_format; 678c2ecf20Sopenharmony_ci const struct v4l2_mbus_framefmt *sink_format; 688c2ecf20Sopenharmony_ci unsigned int left = 0; 698c2ecf20Sopenharmony_ci unsigned int top = 0; 708c2ecf20Sopenharmony_ci u32 pstride; 718c2ecf20Sopenharmony_ci u32 infmt; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* Stride */ 748c2ecf20Sopenharmony_ci pstride = format->plane_fmt[0].bytesperline 758c2ecf20Sopenharmony_ci << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT; 768c2ecf20Sopenharmony_ci if (format->num_planes > 1) 778c2ecf20Sopenharmony_ci pstride |= format->plane_fmt[1].bytesperline 788c2ecf20Sopenharmony_ci << VI6_RPF_SRCM_PSTRIDE_C_SHIFT; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* 818c2ecf20Sopenharmony_ci * pstride has both STRIDE_Y and STRIDE_C, but multiplying the whole 828c2ecf20Sopenharmony_ci * of pstride by 2 is conveniently OK here as we are multiplying both 838c2ecf20Sopenharmony_ci * values. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci if (pipe->interlaced) 868c2ecf20Sopenharmony_ci pstride *= 2; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_PSTRIDE, pstride); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* Format */ 918c2ecf20Sopenharmony_ci sink_format = vsp1_entity_get_pad_format(&rpf->entity, 928c2ecf20Sopenharmony_ci rpf->entity.config, 938c2ecf20Sopenharmony_ci RWPF_PAD_SINK); 948c2ecf20Sopenharmony_ci source_format = vsp1_entity_get_pad_format(&rpf->entity, 958c2ecf20Sopenharmony_ci rpf->entity.config, 968c2ecf20Sopenharmony_ci RWPF_PAD_SOURCE); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci infmt = VI6_RPF_INFMT_CIPM 998c2ecf20Sopenharmony_ci | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (fmtinfo->swap_yc) 1028c2ecf20Sopenharmony_ci infmt |= VI6_RPF_INFMT_SPYCS; 1038c2ecf20Sopenharmony_ci if (fmtinfo->swap_uv) 1048c2ecf20Sopenharmony_ci infmt |= VI6_RPF_INFMT_SPUVS; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (sink_format->code != source_format->code) 1078c2ecf20Sopenharmony_ci infmt |= VI6_RPF_INFMT_CSC; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_INFMT, infmt); 1108c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_DSWAP, fmtinfo->swap); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Output location. */ 1138c2ecf20Sopenharmony_ci if (pipe->brx) { 1148c2ecf20Sopenharmony_ci const struct v4l2_rect *compose; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci compose = vsp1_entity_get_pad_selection(pipe->brx, 1178c2ecf20Sopenharmony_ci pipe->brx->config, 1188c2ecf20Sopenharmony_ci rpf->brx_input, 1198c2ecf20Sopenharmony_ci V4L2_SEL_TGT_COMPOSE); 1208c2ecf20Sopenharmony_ci left = compose->left; 1218c2ecf20Sopenharmony_ci top = compose->top; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (pipe->interlaced) 1258c2ecf20Sopenharmony_ci top /= 2; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_LOC, 1288c2ecf20Sopenharmony_ci (left << VI6_RPF_LOC_HCOORD_SHIFT) | 1298c2ecf20Sopenharmony_ci (top << VI6_RPF_LOC_VCOORD_SHIFT)); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* 1328c2ecf20Sopenharmony_ci * On Gen2 use the alpha channel (extended to 8 bits) when available or 1338c2ecf20Sopenharmony_ci * a fixed alpha value set through the V4L2_CID_ALPHA_COMPONENT control 1348c2ecf20Sopenharmony_ci * otherwise. 1358c2ecf20Sopenharmony_ci * 1368c2ecf20Sopenharmony_ci * The Gen3 RPF has extended alpha capability and can both multiply the 1378c2ecf20Sopenharmony_ci * alpha channel by a fixed global alpha value, and multiply the pixel 1388c2ecf20Sopenharmony_ci * components to convert the input to premultiplied alpha. 1398c2ecf20Sopenharmony_ci * 1408c2ecf20Sopenharmony_ci * As alpha premultiplication is available in the BRx for both Gen2 and 1418c2ecf20Sopenharmony_ci * Gen3 we handle it there and use the Gen3 alpha multiplier for global 1428c2ecf20Sopenharmony_ci * alpha multiplication only. This however prevents conversion to 1438c2ecf20Sopenharmony_ci * premultiplied alpha if no BRx is present in the pipeline. If that use 1448c2ecf20Sopenharmony_ci * case turns out to be useful we will revisit the implementation (for 1458c2ecf20Sopenharmony_ci * Gen3 only). 1468c2ecf20Sopenharmony_ci * 1478c2ecf20Sopenharmony_ci * We enable alpha multiplication on Gen3 using the fixed alpha value 1488c2ecf20Sopenharmony_ci * set through the V4L2_CID_ALPHA_COMPONENT control when the input 1498c2ecf20Sopenharmony_ci * contains an alpha channel. On Gen2 the global alpha is ignored in 1508c2ecf20Sopenharmony_ci * that case. 1518c2ecf20Sopenharmony_ci * 1528c2ecf20Sopenharmony_ci * In all cases, disable color keying. 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT | 1558c2ecf20Sopenharmony_ci (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED 1568c2ecf20Sopenharmony_ci : VI6_RPF_ALPH_SEL_ASEL_FIXED)); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (entity->vsp1->info->gen == 3) { 1598c2ecf20Sopenharmony_ci u32 mult; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (fmtinfo->alpha) { 1628c2ecf20Sopenharmony_ci /* 1638c2ecf20Sopenharmony_ci * When the input contains an alpha channel enable the 1648c2ecf20Sopenharmony_ci * alpha multiplier. If the input is premultiplied we 1658c2ecf20Sopenharmony_ci * need to multiply both the alpha channel and the pixel 1668c2ecf20Sopenharmony_ci * components by the global alpha value to keep them 1678c2ecf20Sopenharmony_ci * premultiplied. Otherwise multiply the alpha channel 1688c2ecf20Sopenharmony_ci * only. 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci bool premultiplied = format->flags 1718c2ecf20Sopenharmony_ci & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci mult = VI6_RPF_MULT_ALPHA_A_MMD_RATIO 1748c2ecf20Sopenharmony_ci | (premultiplied ? 1758c2ecf20Sopenharmony_ci VI6_RPF_MULT_ALPHA_P_MMD_RATIO : 1768c2ecf20Sopenharmony_ci VI6_RPF_MULT_ALPHA_P_MMD_NONE); 1778c2ecf20Sopenharmony_ci } else { 1788c2ecf20Sopenharmony_ci /* 1798c2ecf20Sopenharmony_ci * When the input doesn't contain an alpha channel the 1808c2ecf20Sopenharmony_ci * global alpha value is applied in the unpacking unit, 1818c2ecf20Sopenharmony_ci * the alpha multiplier isn't needed and must be 1828c2ecf20Sopenharmony_ci * disabled. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci mult = VI6_RPF_MULT_ALPHA_A_MMD_NONE 1858c2ecf20Sopenharmony_ci | VI6_RPF_MULT_ALPHA_P_MMD_NONE; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci rpf->mult_alpha = mult; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_MSK_CTRL, 0); 1928c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_CKEY_CTRL, 0); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void vsp1_rpf_configure_autofld(struct vsp1_rwpf *rpf, 1978c2ecf20Sopenharmony_ci struct vsp1_dl_list *dl) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci const struct v4l2_pix_format_mplane *format = &rpf->format; 2008c2ecf20Sopenharmony_ci struct vsp1_dl_ext_cmd *cmd; 2018c2ecf20Sopenharmony_ci struct vsp1_extcmd_auto_fld_body *auto_fld; 2028c2ecf20Sopenharmony_ci u32 offset_y, offset_c; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci cmd = vsp1_dl_get_pre_cmd(dl); 2058c2ecf20Sopenharmony_ci if (WARN_ONCE(!cmd, "Failed to obtain an autofld cmd")) 2068c2ecf20Sopenharmony_ci return; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* Re-index our auto_fld to match the current RPF. */ 2098c2ecf20Sopenharmony_ci auto_fld = cmd->data; 2108c2ecf20Sopenharmony_ci auto_fld = &auto_fld[rpf->entity.index]; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci auto_fld->top_y0 = rpf->mem.addr[0]; 2138c2ecf20Sopenharmony_ci auto_fld->top_c0 = rpf->mem.addr[1]; 2148c2ecf20Sopenharmony_ci auto_fld->top_c1 = rpf->mem.addr[2]; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci offset_y = format->plane_fmt[0].bytesperline; 2178c2ecf20Sopenharmony_ci offset_c = format->plane_fmt[1].bytesperline; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci auto_fld->bottom_y0 = rpf->mem.addr[0] + offset_y; 2208c2ecf20Sopenharmony_ci auto_fld->bottom_c0 = rpf->mem.addr[1] + offset_c; 2218c2ecf20Sopenharmony_ci auto_fld->bottom_c1 = rpf->mem.addr[2] + offset_c; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci cmd->flags |= VI6_DL_EXT_AUTOFLD_INT | BIT(16 + rpf->entity.index); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic void rpf_configure_frame(struct vsp1_entity *entity, 2278c2ecf20Sopenharmony_ci struct vsp1_pipeline *pipe, 2288c2ecf20Sopenharmony_ci struct vsp1_dl_list *dl, 2298c2ecf20Sopenharmony_ci struct vsp1_dl_body *dlb) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_VRTCOL_SET, 2348c2ecf20Sopenharmony_ci rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); 2358c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_MULT_ALPHA, rpf->mult_alpha | 2368c2ecf20Sopenharmony_ci (rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT)); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci vsp1_pipeline_propagate_alpha(pipe, dlb, rpf->alpha); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic void rpf_configure_partition(struct vsp1_entity *entity, 2428c2ecf20Sopenharmony_ci struct vsp1_pipeline *pipe, 2438c2ecf20Sopenharmony_ci struct vsp1_dl_list *dl, 2448c2ecf20Sopenharmony_ci struct vsp1_dl_body *dlb) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); 2478c2ecf20Sopenharmony_ci struct vsp1_rwpf_memory mem = rpf->mem; 2488c2ecf20Sopenharmony_ci struct vsp1_device *vsp1 = rpf->entity.vsp1; 2498c2ecf20Sopenharmony_ci const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; 2508c2ecf20Sopenharmony_ci const struct v4l2_pix_format_mplane *format = &rpf->format; 2518c2ecf20Sopenharmony_ci struct v4l2_rect crop; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* 2548c2ecf20Sopenharmony_ci * Source size and crop offsets. 2558c2ecf20Sopenharmony_ci * 2568c2ecf20Sopenharmony_ci * The crop offsets correspond to the location of the crop 2578c2ecf20Sopenharmony_ci * rectangle top left corner in the plane buffer. Only two 2588c2ecf20Sopenharmony_ci * offsets are needed, as planes 2 and 3 always have identical 2598c2ecf20Sopenharmony_ci * strides. 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ci crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.config); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* 2648c2ecf20Sopenharmony_ci * Partition Algorithm Control 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * The partition algorithm can split this frame into multiple 2678c2ecf20Sopenharmony_ci * slices. We must scale our partition window based on the pipe 2688c2ecf20Sopenharmony_ci * configuration to match the destination partition window. 2698c2ecf20Sopenharmony_ci * To achieve this, we adjust our crop to provide a 'sub-crop' 2708c2ecf20Sopenharmony_ci * matching the expected partition window. Only 'left' and 2718c2ecf20Sopenharmony_ci * 'width' need to be adjusted. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci if (pipe->partitions > 1) { 2748c2ecf20Sopenharmony_ci crop.width = pipe->partition->rpf.width; 2758c2ecf20Sopenharmony_ci crop.left += pipe->partition->rpf.left; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (pipe->interlaced) { 2798c2ecf20Sopenharmony_ci crop.height = round_down(crop.height / 2, fmtinfo->vsub); 2808c2ecf20Sopenharmony_ci crop.top = round_down(crop.top / 2, fmtinfo->vsub); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_SRC_BSIZE, 2848c2ecf20Sopenharmony_ci (crop.width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) | 2858c2ecf20Sopenharmony_ci (crop.height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT)); 2868c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_SRC_ESIZE, 2878c2ecf20Sopenharmony_ci (crop.width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | 2888c2ecf20Sopenharmony_ci (crop.height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci mem.addr[0] += crop.top * format->plane_fmt[0].bytesperline 2918c2ecf20Sopenharmony_ci + crop.left * fmtinfo->bpp[0] / 8; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (format->num_planes > 1) { 2948c2ecf20Sopenharmony_ci unsigned int bpl = format->plane_fmt[1].bytesperline; 2958c2ecf20Sopenharmony_ci unsigned int offset; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci offset = crop.top / fmtinfo->vsub * bpl 2988c2ecf20Sopenharmony_ci + crop.left / fmtinfo->hsub * fmtinfo->bpp[1] / 8; 2998c2ecf20Sopenharmony_ci mem.addr[1] += offset; 3008c2ecf20Sopenharmony_ci mem.addr[2] += offset; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* 3048c2ecf20Sopenharmony_ci * On Gen3 hardware the SPUVS bit has no effect on 3-planar 3058c2ecf20Sopenharmony_ci * formats. Swap the U and V planes manually in that case. 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_ci if (vsp1->info->gen == 3 && format->num_planes == 3 && 3088c2ecf20Sopenharmony_ci fmtinfo->swap_uv) 3098c2ecf20Sopenharmony_ci swap(mem.addr[1], mem.addr[2]); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* 3128c2ecf20Sopenharmony_ci * Interlaced pipelines will use the extended pre-cmd to process 3138c2ecf20Sopenharmony_ci * SRCM_ADDR_{Y,C0,C1}. 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci if (pipe->interlaced) { 3168c2ecf20Sopenharmony_ci vsp1_rpf_configure_autofld(rpf, dl); 3178c2ecf20Sopenharmony_ci } else { 3188c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_Y, mem.addr[0]); 3198c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_C0, mem.addr[1]); 3208c2ecf20Sopenharmony_ci vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_C1, mem.addr[2]); 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic void rpf_partition(struct vsp1_entity *entity, 3258c2ecf20Sopenharmony_ci struct vsp1_pipeline *pipe, 3268c2ecf20Sopenharmony_ci struct vsp1_partition *partition, 3278c2ecf20Sopenharmony_ci unsigned int partition_idx, 3288c2ecf20Sopenharmony_ci struct vsp1_partition_window *window) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci partition->rpf = *window; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic const struct vsp1_entity_operations rpf_entity_ops = { 3348c2ecf20Sopenharmony_ci .configure_stream = rpf_configure_stream, 3358c2ecf20Sopenharmony_ci .configure_frame = rpf_configure_frame, 3368c2ecf20Sopenharmony_ci .configure_partition = rpf_configure_partition, 3378c2ecf20Sopenharmony_ci .partition = rpf_partition, 3388c2ecf20Sopenharmony_ci}; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 3418c2ecf20Sopenharmony_ci * Initialization and Cleanup 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistruct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct vsp1_rwpf *rpf; 3478c2ecf20Sopenharmony_ci char name[6]; 3488c2ecf20Sopenharmony_ci int ret; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL); 3518c2ecf20Sopenharmony_ci if (rpf == NULL) 3528c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci rpf->max_width = RPF_MAX_WIDTH; 3558c2ecf20Sopenharmony_ci rpf->max_height = RPF_MAX_HEIGHT; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci rpf->entity.ops = &rpf_entity_ops; 3588c2ecf20Sopenharmony_ci rpf->entity.type = VSP1_ENTITY_RPF; 3598c2ecf20Sopenharmony_ci rpf->entity.index = index; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci sprintf(name, "rpf.%u", index); 3628c2ecf20Sopenharmony_ci ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops, 3638c2ecf20Sopenharmony_ci MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); 3648c2ecf20Sopenharmony_ci if (ret < 0) 3658c2ecf20Sopenharmony_ci return ERR_PTR(ret); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* Initialize the control handler. */ 3688c2ecf20Sopenharmony_ci ret = vsp1_rwpf_init_ctrls(rpf, 0); 3698c2ecf20Sopenharmony_ci if (ret < 0) { 3708c2ecf20Sopenharmony_ci dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n", 3718c2ecf20Sopenharmony_ci index); 3728c2ecf20Sopenharmony_ci goto error; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci v4l2_ctrl_handler_setup(&rpf->ctrls); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci return rpf; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cierror: 3808c2ecf20Sopenharmony_ci vsp1_entity_destroy(&rpf->entity); 3818c2ecf20Sopenharmony_ci return ERR_PTR(ret); 3828c2ecf20Sopenharmony_ci} 383