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