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