1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * vsp1_rpf.c -- R-Car VSP1 Read Pixel Formatter 4 * 5 * Copyright (C) 2013-2014 Renesas Electronics Corporation 6 * 7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 8 */ 9 10 #include <linux/device.h> 11 12 #include <media/v4l2-subdev.h> 13 14 #include "vsp1.h" 15 #include "vsp1_dl.h" 16 #include "vsp1_pipe.h" 17 #include "vsp1_rwpf.h" 18 #include "vsp1_video.h" 19 20 #define RPF_MAX_WIDTH 8190 21 #define RPF_MAX_HEIGHT 8190 22 23 /* Pre extended display list command data structure. */ 24 struct vsp1_extcmd_auto_fld_body { 25 u32 top_y0; 26 u32 bottom_y0; 27 u32 top_c0; 28 u32 bottom_c0; 29 u32 top_c1; 30 u32 bottom_c1; 31 u32 reserved0; 32 u32 reserved1; 33 } __packed; 34 35 /* ----------------------------------------------------------------------------- 36 * Device Access 37 */ 38 39 static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, 40 struct vsp1_dl_body *dlb, u32 reg, u32 data) 41 { 42 vsp1_dl_body_write(dlb, reg + rpf->entity.index * VI6_RPF_OFFSET, 43 data); 44 } 45 46 /* ----------------------------------------------------------------------------- 47 * V4L2 Subdevice Operations 48 */ 49 50 static const struct v4l2_subdev_ops rpf_ops = { 51 .pad = &vsp1_rwpf_pad_ops, 52 }; 53 54 /* ----------------------------------------------------------------------------- 55 * VSP1 Entity Operations 56 */ 57 58 static void rpf_configure_stream(struct vsp1_entity *entity, 59 struct vsp1_pipeline *pipe, 60 struct vsp1_dl_list *dl, 61 struct vsp1_dl_body *dlb) 62 { 63 struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); 64 const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; 65 const struct v4l2_pix_format_mplane *format = &rpf->format; 66 const struct v4l2_mbus_framefmt *source_format; 67 const struct v4l2_mbus_framefmt *sink_format; 68 unsigned int left = 0; 69 unsigned int top = 0; 70 u32 pstride; 71 u32 infmt; 72 73 /* Stride */ 74 pstride = format->plane_fmt[0].bytesperline 75 << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT; 76 if (format->num_planes > 1) 77 pstride |= format->plane_fmt[1].bytesperline 78 << VI6_RPF_SRCM_PSTRIDE_C_SHIFT; 79 80 /* 81 * pstride has both STRIDE_Y and STRIDE_C, but multiplying the whole 82 * of pstride by 2 is conveniently OK here as we are multiplying both 83 * values. 84 */ 85 if (pipe->interlaced) 86 pstride *= 2; 87 88 vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_PSTRIDE, pstride); 89 90 /* Format */ 91 sink_format = vsp1_entity_get_pad_format(&rpf->entity, 92 rpf->entity.config, 93 RWPF_PAD_SINK); 94 source_format = vsp1_entity_get_pad_format(&rpf->entity, 95 rpf->entity.config, 96 RWPF_PAD_SOURCE); 97 98 infmt = VI6_RPF_INFMT_CIPM 99 | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT); 100 101 if (fmtinfo->swap_yc) 102 infmt |= VI6_RPF_INFMT_SPYCS; 103 if (fmtinfo->swap_uv) 104 infmt |= VI6_RPF_INFMT_SPUVS; 105 106 if (sink_format->code != source_format->code) 107 infmt |= VI6_RPF_INFMT_CSC; 108 109 vsp1_rpf_write(rpf, dlb, VI6_RPF_INFMT, infmt); 110 vsp1_rpf_write(rpf, dlb, VI6_RPF_DSWAP, fmtinfo->swap); 111 112 if (entity->vsp1->info->gen == 4) { 113 u32 ext_infmt0; 114 u32 ext_infmt1; 115 u32 ext_infmt2; 116 117 switch (fmtinfo->fourcc) { 118 case V4L2_PIX_FMT_RGBX1010102: 119 ext_infmt0 = VI6_RPF_EXT_INFMT0_BYPP_M1_RGB10; 120 ext_infmt1 = VI6_RPF_EXT_INFMT1_PACK_CPOS(0, 10, 20, 0); 121 ext_infmt2 = VI6_RPF_EXT_INFMT2_PACK_CLEN(10, 10, 10, 0); 122 break; 123 124 case V4L2_PIX_FMT_RGBA1010102: 125 ext_infmt0 = VI6_RPF_EXT_INFMT0_BYPP_M1_RGB10; 126 ext_infmt1 = VI6_RPF_EXT_INFMT1_PACK_CPOS(0, 10, 20, 30); 127 ext_infmt2 = VI6_RPF_EXT_INFMT2_PACK_CLEN(10, 10, 10, 2); 128 break; 129 130 case V4L2_PIX_FMT_ARGB2101010: 131 ext_infmt0 = VI6_RPF_EXT_INFMT0_BYPP_M1_RGB10; 132 ext_infmt1 = VI6_RPF_EXT_INFMT1_PACK_CPOS(2, 12, 22, 0); 133 ext_infmt2 = VI6_RPF_EXT_INFMT2_PACK_CLEN(10, 10, 10, 2); 134 break; 135 136 case V4L2_PIX_FMT_Y210: 137 ext_infmt0 = VI6_RPF_EXT_INFMT0_F2B | 138 VI6_RPF_EXT_INFMT0_IPBD_Y_10 | 139 VI6_RPF_EXT_INFMT0_IPBD_C_10; 140 ext_infmt1 = 0x0; 141 ext_infmt2 = 0x0; 142 break; 143 144 case V4L2_PIX_FMT_Y212: 145 ext_infmt0 = VI6_RPF_EXT_INFMT0_F2B | 146 VI6_RPF_EXT_INFMT0_IPBD_Y_12 | 147 VI6_RPF_EXT_INFMT0_IPBD_C_12; 148 ext_infmt1 = 0x0; 149 ext_infmt2 = 0x0; 150 break; 151 152 default: 153 ext_infmt0 = 0; 154 ext_infmt1 = 0; 155 ext_infmt2 = 0; 156 break; 157 } 158 159 vsp1_rpf_write(rpf, dlb, VI6_RPF_EXT_INFMT0, ext_infmt0); 160 vsp1_rpf_write(rpf, dlb, VI6_RPF_EXT_INFMT1, ext_infmt1); 161 vsp1_rpf_write(rpf, dlb, VI6_RPF_EXT_INFMT2, ext_infmt2); 162 } 163 164 /* Output location. */ 165 if (pipe->brx) { 166 const struct v4l2_rect *compose; 167 168 compose = vsp1_entity_get_pad_selection(pipe->brx, 169 pipe->brx->config, 170 rpf->brx_input, 171 V4L2_SEL_TGT_COMPOSE); 172 left = compose->left; 173 top = compose->top; 174 } 175 176 if (pipe->interlaced) 177 top /= 2; 178 179 vsp1_rpf_write(rpf, dlb, VI6_RPF_LOC, 180 (left << VI6_RPF_LOC_HCOORD_SHIFT) | 181 (top << VI6_RPF_LOC_VCOORD_SHIFT)); 182 183 /* 184 * On Gen2 use the alpha channel (extended to 8 bits) when available or 185 * a fixed alpha value set through the V4L2_CID_ALPHA_COMPONENT control 186 * otherwise. 187 * 188 * The Gen3+ RPF has extended alpha capability and can both multiply the 189 * alpha channel by a fixed global alpha value, and multiply the pixel 190 * components to convert the input to premultiplied alpha. 191 * 192 * As alpha premultiplication is available in the BRx for both Gen2 and 193 * Gen3+ we handle it there and use the Gen3 alpha multiplier for global 194 * alpha multiplication only. This however prevents conversion to 195 * premultiplied alpha if no BRx is present in the pipeline. If that use 196 * case turns out to be useful we will revisit the implementation (for 197 * Gen3 only). 198 * 199 * We enable alpha multiplication on Gen3+ using the fixed alpha value 200 * set through the V4L2_CID_ALPHA_COMPONENT control when the input 201 * contains an alpha channel. On Gen2 the global alpha is ignored in 202 * that case. 203 * 204 * In all cases, disable color keying. 205 */ 206 vsp1_rpf_write(rpf, dlb, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT | 207 (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED 208 : VI6_RPF_ALPH_SEL_ASEL_FIXED)); 209 210 if (entity->vsp1->info->gen >= 3) { 211 u32 mult; 212 213 if (fmtinfo->alpha) { 214 /* 215 * When the input contains an alpha channel enable the 216 * alpha multiplier. If the input is premultiplied we 217 * need to multiply both the alpha channel and the pixel 218 * components by the global alpha value to keep them 219 * premultiplied. Otherwise multiply the alpha channel 220 * only. 221 */ 222 bool premultiplied = format->flags 223 & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA; 224 225 mult = VI6_RPF_MULT_ALPHA_A_MMD_RATIO 226 | (premultiplied ? 227 VI6_RPF_MULT_ALPHA_P_MMD_RATIO : 228 VI6_RPF_MULT_ALPHA_P_MMD_NONE); 229 } else { 230 /* 231 * When the input doesn't contain an alpha channel the 232 * global alpha value is applied in the unpacking unit, 233 * the alpha multiplier isn't needed and must be 234 * disabled. 235 */ 236 mult = VI6_RPF_MULT_ALPHA_A_MMD_NONE 237 | VI6_RPF_MULT_ALPHA_P_MMD_NONE; 238 } 239 240 rpf->mult_alpha = mult; 241 } 242 243 vsp1_rpf_write(rpf, dlb, VI6_RPF_MSK_CTRL, 0); 244 vsp1_rpf_write(rpf, dlb, VI6_RPF_CKEY_CTRL, 0); 245 246 } 247 248 static void vsp1_rpf_configure_autofld(struct vsp1_rwpf *rpf, 249 struct vsp1_dl_list *dl) 250 { 251 const struct v4l2_pix_format_mplane *format = &rpf->format; 252 struct vsp1_dl_ext_cmd *cmd; 253 struct vsp1_extcmd_auto_fld_body *auto_fld; 254 u32 offset_y, offset_c; 255 256 cmd = vsp1_dl_get_pre_cmd(dl); 257 if (WARN_ONCE(!cmd, "Failed to obtain an autofld cmd")) 258 return; 259 260 /* Re-index our auto_fld to match the current RPF. */ 261 auto_fld = cmd->data; 262 auto_fld = &auto_fld[rpf->entity.index]; 263 264 auto_fld->top_y0 = rpf->mem.addr[0]; 265 auto_fld->top_c0 = rpf->mem.addr[1]; 266 auto_fld->top_c1 = rpf->mem.addr[2]; 267 268 offset_y = format->plane_fmt[0].bytesperline; 269 offset_c = format->plane_fmt[1].bytesperline; 270 271 auto_fld->bottom_y0 = rpf->mem.addr[0] + offset_y; 272 auto_fld->bottom_c0 = rpf->mem.addr[1] + offset_c; 273 auto_fld->bottom_c1 = rpf->mem.addr[2] + offset_c; 274 275 cmd->flags |= VI6_DL_EXT_AUTOFLD_INT | BIT(16 + rpf->entity.index); 276 } 277 278 static void rpf_configure_frame(struct vsp1_entity *entity, 279 struct vsp1_pipeline *pipe, 280 struct vsp1_dl_list *dl, 281 struct vsp1_dl_body *dlb) 282 { 283 struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); 284 285 vsp1_rpf_write(rpf, dlb, VI6_RPF_VRTCOL_SET, 286 rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); 287 vsp1_rpf_write(rpf, dlb, VI6_RPF_MULT_ALPHA, rpf->mult_alpha | 288 (rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT)); 289 290 vsp1_pipeline_propagate_alpha(pipe, dlb, rpf->alpha); 291 } 292 293 static void rpf_configure_partition(struct vsp1_entity *entity, 294 struct vsp1_pipeline *pipe, 295 struct vsp1_dl_list *dl, 296 struct vsp1_dl_body *dlb) 297 { 298 struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); 299 struct vsp1_rwpf_memory mem = rpf->mem; 300 struct vsp1_device *vsp1 = rpf->entity.vsp1; 301 const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; 302 const struct v4l2_pix_format_mplane *format = &rpf->format; 303 struct v4l2_rect crop; 304 305 /* 306 * Source size and crop offsets. 307 * 308 * The crop offsets correspond to the location of the crop 309 * rectangle top left corner in the plane buffer. Only two 310 * offsets are needed, as planes 2 and 3 always have identical 311 * strides. 312 */ 313 crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.config); 314 315 /* 316 * Partition Algorithm Control 317 * 318 * The partition algorithm can split this frame into multiple 319 * slices. We must scale our partition window based on the pipe 320 * configuration to match the destination partition window. 321 * To achieve this, we adjust our crop to provide a 'sub-crop' 322 * matching the expected partition window. Only 'left' and 323 * 'width' need to be adjusted. 324 */ 325 if (pipe->partitions > 1) { 326 crop.width = pipe->partition->rpf.width; 327 crop.left += pipe->partition->rpf.left; 328 } 329 330 if (pipe->interlaced) { 331 crop.height = round_down(crop.height / 2, fmtinfo->vsub); 332 crop.top = round_down(crop.top / 2, fmtinfo->vsub); 333 } 334 335 vsp1_rpf_write(rpf, dlb, VI6_RPF_SRC_BSIZE, 336 (crop.width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) | 337 (crop.height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT)); 338 vsp1_rpf_write(rpf, dlb, VI6_RPF_SRC_ESIZE, 339 (crop.width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | 340 (crop.height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); 341 342 mem.addr[0] += crop.top * format->plane_fmt[0].bytesperline 343 + crop.left * fmtinfo->bpp[0] / 8; 344 345 if (format->num_planes > 1) { 346 unsigned int bpl = format->plane_fmt[1].bytesperline; 347 unsigned int offset; 348 349 offset = crop.top / fmtinfo->vsub * bpl 350 + crop.left / fmtinfo->hsub * fmtinfo->bpp[1] / 8; 351 mem.addr[1] += offset; 352 mem.addr[2] += offset; 353 } 354 355 /* 356 * On Gen3+ hardware the SPUVS bit has no effect on 3-planar 357 * formats. Swap the U and V planes manually in that case. 358 */ 359 if (vsp1->info->gen >= 3 && format->num_planes == 3 && 360 fmtinfo->swap_uv) 361 swap(mem.addr[1], mem.addr[2]); 362 363 /* 364 * Interlaced pipelines will use the extended pre-cmd to process 365 * SRCM_ADDR_{Y,C0,C1}. 366 */ 367 if (pipe->interlaced) { 368 vsp1_rpf_configure_autofld(rpf, dl); 369 } else { 370 vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_Y, mem.addr[0]); 371 vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_C0, mem.addr[1]); 372 vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_C1, mem.addr[2]); 373 } 374 } 375 376 static void rpf_partition(struct vsp1_entity *entity, 377 struct vsp1_pipeline *pipe, 378 struct vsp1_partition *partition, 379 unsigned int partition_idx, 380 struct vsp1_partition_window *window) 381 { 382 partition->rpf = *window; 383 } 384 385 static const struct vsp1_entity_operations rpf_entity_ops = { 386 .configure_stream = rpf_configure_stream, 387 .configure_frame = rpf_configure_frame, 388 .configure_partition = rpf_configure_partition, 389 .partition = rpf_partition, 390 }; 391 392 /* ----------------------------------------------------------------------------- 393 * Initialization and Cleanup 394 */ 395 396 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) 397 { 398 struct vsp1_rwpf *rpf; 399 char name[6]; 400 int ret; 401 402 rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL); 403 if (rpf == NULL) 404 return ERR_PTR(-ENOMEM); 405 406 rpf->max_width = RPF_MAX_WIDTH; 407 rpf->max_height = RPF_MAX_HEIGHT; 408 409 rpf->entity.ops = &rpf_entity_ops; 410 rpf->entity.type = VSP1_ENTITY_RPF; 411 rpf->entity.index = index; 412 413 sprintf(name, "rpf.%u", index); 414 ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops, 415 MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); 416 if (ret < 0) 417 return ERR_PTR(ret); 418 419 /* Initialize the control handler. */ 420 ret = vsp1_rwpf_init_ctrls(rpf, 0); 421 if (ret < 0) { 422 dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n", 423 index); 424 goto error; 425 } 426 427 v4l2_ctrl_handler_setup(&rpf->ctrls); 428 429 return rpf; 430 431 error: 432 vsp1_entity_destroy(&rpf->entity); 433 return ERR_PTR(ret); 434 } 435