Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: v4l: vsp1: Allow entities to participate in the partition algorithm

The configuration of the pipeline and entities directly affects the
inputs required to each entity for the partition algorithm. Thus it
makes sense to involve those entities in the decision making process.

Extend the entity ops API to provide an optional .partition() operation.
This allows entities that affect the partition window to adapt the
window based on their configuration.

Entities implementing this operation must update the window parameter in
place, which will then be passed up the pipeline. This creates a process
whereby each entity describes what is required to satisfy the required
output to its predecessor in the pipeline.

Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Hans Verkuil <hansverk@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

authored by

Kieran Bingham and committed by
Mauro Carvalho Chehab
ab45e858 3609e7ba

+166 -33
+7
drivers/media/platform/vsp1/vsp1_entity.h
··· 21 21 struct vsp1_device; 22 22 struct vsp1_dl_list; 23 23 struct vsp1_pipeline; 24 + struct vsp1_partition; 25 + struct vsp1_partition_window; 24 26 25 27 enum vsp1_entity_type { 26 28 VSP1_ENTITY_BRU, ··· 83 81 * selection rectangles, ...) 84 82 * @max_width: Return the max supported width of data that the entity can 85 83 * process in a single operation. 84 + * @partition: Process the partition construction based on this entity's 85 + * configuration. 86 86 */ 87 87 struct vsp1_entity_operations { 88 88 void (*destroy)(struct vsp1_entity *); 89 89 void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *, 90 90 struct vsp1_dl_list *, enum vsp1_entity_params); 91 91 unsigned int (*max_width)(struct vsp1_entity *, struct vsp1_pipeline *); 92 + void (*partition)(struct vsp1_entity *, struct vsp1_pipeline *, 93 + struct vsp1_partition *, unsigned int, 94 + struct vsp1_partition_window *); 92 95 }; 93 96 94 97 struct vsp1_entity {
+22
drivers/media/platform/vsp1/vsp1_pipe.c
··· 382 382 vsp1_uds_set_alpha(pipe->uds, dl, alpha); 383 383 } 384 384 385 + /* 386 + * Propagate the partition calculations through the pipeline 387 + * 388 + * Work backwards through the pipe, allowing each entity to update the partition 389 + * parameters based on its configuration, and the entity connected to its 390 + * source. Each entity must produce the partition required for the previous 391 + * entity in the pipeline. 392 + */ 393 + void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe, 394 + struct vsp1_partition *partition, 395 + unsigned int index, 396 + struct vsp1_partition_window *window) 397 + { 398 + struct vsp1_entity *entity; 399 + 400 + list_for_each_entry_reverse(entity, &pipe->entities, list_pipe) { 401 + if (entity->ops->partition) 402 + entity->ops->partition(entity, pipe, partition, index, 403 + window); 404 + } 405 + } 406 + 385 407 void vsp1_pipelines_suspend(struct vsp1_device *vsp1) 386 408 { 387 409 unsigned long flags;
+28 -2
drivers/media/platform/vsp1/vsp1_pipe.h
··· 58 58 }; 59 59 60 60 /* 61 - * struct vsp1_partition - A description of a slice for the partition algorithm 61 + * struct vsp1_partition_window - Partition window coordinates 62 62 * @left: horizontal coordinate of the partition start in pixels relative to the 63 63 * left edge of the image 64 64 * @width: partition width in pixels 65 65 */ 66 - struct vsp1_partition { 66 + struct vsp1_partition_window { 67 67 unsigned int left; 68 68 unsigned int width; 69 + }; 70 + 71 + /* 72 + * struct vsp1_partition - A description of a slice for the partition algorithm 73 + * @rpf: The RPF partition window configuration 74 + * @uds_sink: The UDS input partition window configuration 75 + * @uds_source: The UDS output partition window configuration 76 + * @sru: The SRU partition window configuration 77 + * @wpf: The WPF partition window configuration 78 + */ 79 + struct vsp1_partition { 80 + struct vsp1_partition_window rpf; 81 + struct vsp1_partition_window uds_sink; 82 + struct vsp1_partition_window uds_source; 83 + struct vsp1_partition_window sru; 84 + struct vsp1_partition_window wpf; 69 85 }; 70 86 71 87 /* ··· 136 120 struct vsp1_entity *uds; 137 121 struct vsp1_entity *uds_input; 138 122 123 + /* 124 + * The order of this list must be identical to the order of the entities 125 + * in the pipeline, as it is assumed by the partition algorithm that we 126 + * can walk this list in sequence. 127 + */ 139 128 struct list_head entities; 140 129 141 130 struct vsp1_dl_list *dl; ··· 162 141 163 142 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, 164 143 struct vsp1_dl_list *dl, unsigned int alpha); 144 + 145 + void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe, 146 + struct vsp1_partition *partition, 147 + unsigned int index, 148 + struct vsp1_partition_window *window); 165 149 166 150 void vsp1_pipelines_suspend(struct vsp1_device *vsp1); 167 151 void vsp1_pipelines_resume(struct vsp1_device *vsp1);
+12 -15
drivers/media/platform/vsp1/vsp1_rpf.c
··· 97 97 * 'width' need to be adjusted. 98 98 */ 99 99 if (pipe->partitions > 1) { 100 - const struct v4l2_mbus_framefmt *output; 101 - struct vsp1_entity *wpf = &pipe->output->entity; 102 - unsigned int input_width = crop.width; 103 - 104 - /* 105 - * Scale the partition window based on the configuration 106 - * of the pipeline. 107 - */ 108 - output = vsp1_entity_get_pad_format(wpf, wpf->config, 109 - RWPF_PAD_SINK); 110 - 111 - crop.width = pipe->partition->width * input_width 112 - / output->width; 113 - crop.left += pipe->partition->left * input_width 114 - / output->width; 100 + crop.width = pipe->partition->rpf.width; 101 + crop.left += pipe->partition->rpf.left; 115 102 } 116 103 117 104 vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE, ··· 247 260 248 261 } 249 262 263 + static void rpf_partition(struct vsp1_entity *entity, 264 + struct vsp1_pipeline *pipe, 265 + struct vsp1_partition *partition, 266 + unsigned int partition_idx, 267 + struct vsp1_partition_window *window) 268 + { 269 + partition->rpf = *window; 270 + } 271 + 250 272 static const struct vsp1_entity_operations rpf_entity_ops = { 251 273 .configure = rpf_configure, 274 + .partition = rpf_partition, 252 275 }; 253 276 254 277 /* -----------------------------------------------------------------------------
+26
drivers/media/platform/vsp1/vsp1_sru.c
··· 18 18 19 19 #include "vsp1.h" 20 20 #include "vsp1_dl.h" 21 + #include "vsp1_pipe.h" 21 22 #include "vsp1_sru.h" 22 23 23 24 #define SRU_MIN_SIZE 4U ··· 326 325 return 256; 327 326 } 328 327 328 + static void sru_partition(struct vsp1_entity *entity, 329 + struct vsp1_pipeline *pipe, 330 + struct vsp1_partition *partition, 331 + unsigned int partition_idx, 332 + struct vsp1_partition_window *window) 333 + { 334 + struct vsp1_sru *sru = to_sru(&entity->subdev); 335 + struct v4l2_mbus_framefmt *input; 336 + struct v4l2_mbus_framefmt *output; 337 + 338 + input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, 339 + SRU_PAD_SINK); 340 + output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, 341 + SRU_PAD_SOURCE); 342 + 343 + /* Adapt if SRUx2 is enabled */ 344 + if (input->width != output->width) { 345 + window->width /= 2; 346 + window->left /= 2; 347 + } 348 + 349 + partition->sru = *window; 350 + } 351 + 329 352 static const struct vsp1_entity_operations sru_entity_ops = { 330 353 .configure = sru_configure, 331 354 .max_width = sru_max_width, 355 + .partition = sru_partition, 332 356 }; 333 357 334 358 /* -----------------------------------------------------------------------------
+40 -1
drivers/media/platform/vsp1/vsp1_uds.c
··· 279 279 if (params == VSP1_ENTITY_PARAMS_PARTITION) { 280 280 struct vsp1_partition *partition = pipe->partition; 281 281 282 + /* Input size clipping */ 283 + vsp1_uds_write(uds, dl, VI6_UDS_HSZCLIP, VI6_UDS_HSZCLIP_HCEN | 284 + (0 << VI6_UDS_HSZCLIP_HCL_OFST_SHIFT) | 285 + (partition->uds_sink.width 286 + << VI6_UDS_HSZCLIP_HCL_SIZE_SHIFT)); 287 + 288 + /* Output size clipping */ 282 289 vsp1_uds_write(uds, dl, VI6_UDS_CLIP_SIZE, 283 - (partition->width 290 + (partition->uds_source.width 284 291 << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) | 285 292 (output->height 286 293 << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT)); ··· 352 345 return 2048; 353 346 } 354 347 348 + /* ----------------------------------------------------------------------------- 349 + * Partition Algorithm Support 350 + */ 351 + 352 + static void uds_partition(struct vsp1_entity *entity, 353 + struct vsp1_pipeline *pipe, 354 + struct vsp1_partition *partition, 355 + unsigned int partition_idx, 356 + struct vsp1_partition_window *window) 357 + { 358 + struct vsp1_uds *uds = to_uds(&entity->subdev); 359 + const struct v4l2_mbus_framefmt *output; 360 + const struct v4l2_mbus_framefmt *input; 361 + 362 + /* Initialise the partition state */ 363 + partition->uds_sink = *window; 364 + partition->uds_source = *window; 365 + 366 + input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, 367 + UDS_PAD_SINK); 368 + output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, 369 + UDS_PAD_SOURCE); 370 + 371 + partition->uds_sink.width = window->width * input->width 372 + / output->width; 373 + partition->uds_sink.left = window->left * input->width 374 + / output->width; 375 + 376 + *window = partition->uds_sink; 377 + } 378 + 355 379 static const struct vsp1_entity_operations uds_entity_ops = { 356 380 .configure = uds_configure, 357 381 .max_width = uds_max_width, 382 + .partition = uds_partition, 358 383 }; 359 384 360 385 /* -----------------------------------------------------------------------------
+14 -8
drivers/media/platform/vsp1/vsp1_video.c
··· 196 196 unsigned int index) 197 197 { 198 198 const struct v4l2_mbus_framefmt *format; 199 + struct vsp1_partition_window window; 199 200 unsigned int modulus; 200 201 201 202 /* ··· 209 208 210 209 /* A single partition simply processes the output size in full. */ 211 210 if (pipe->partitions <= 1) { 212 - partition->left = 0; 213 - partition->width = format->width; 211 + window.left = 0; 212 + window.width = format->width; 213 + 214 + vsp1_pipeline_propagate_partition(pipe, partition, index, 215 + &window); 214 216 return; 215 217 } 216 218 217 219 /* Initialise the partition with sane starting conditions. */ 218 - partition->left = index * div_size; 219 - partition->width = div_size; 220 + window.left = index * div_size; 221 + window.width = div_size; 220 222 221 223 modulus = format->width % div_size; 222 224 ··· 242 238 if (modulus < div_size / 2) { 243 239 if (index == partitions - 1) { 244 240 /* Halve the penultimate partition. */ 245 - partition->width = div_size / 2; 241 + window.width = div_size / 2; 246 242 } else if (index == partitions) { 247 243 /* Increase the final partition. */ 248 - partition->width = (div_size / 2) + modulus; 249 - partition->left -= div_size / 2; 244 + window.width = (div_size / 2) + modulus; 245 + window.left -= div_size / 2; 250 246 } 251 247 } else if (index == partitions) { 252 - partition->width = modulus; 248 + window.width = modulus; 253 249 } 254 250 } 251 + 252 + vsp1_pipeline_propagate_partition(pipe, partition, index, &window); 255 253 } 256 254 257 255 static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
+17 -7
drivers/media/platform/vsp1/vsp1_wpf.c
··· 291 291 * multiple slices. 292 292 */ 293 293 if (pipe->partitions > 1) 294 - width = pipe->partition->width; 294 + width = pipe->partition->wpf.width; 295 295 296 296 vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | 297 297 (0 << VI6_WPF_SZCLIP_OFST_SHIFT) | ··· 320 320 * is applied horizontally or vertically accordingly. 321 321 */ 322 322 if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate) 323 - offset = format->width - pipe->partition->left 324 - - pipe->partition->width; 323 + offset = format->width - pipe->partition->wpf.left 324 + - pipe->partition->wpf.width; 325 325 else if (flip & BIT(WPF_CTRL_VFLIP) && wpf->flip.rotate) 326 - offset = format->height - pipe->partition->left 327 - - pipe->partition->width; 326 + offset = format->height - pipe->partition->wpf.left 327 + - pipe->partition->wpf.width; 328 328 else 329 - offset = pipe->partition->left; 329 + offset = pipe->partition->wpf.left; 330 330 331 331 for (i = 0; i < format->num_planes; ++i) { 332 332 unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; ··· 348 348 * image height. 349 349 */ 350 350 if (wpf->flip.rotate) 351 - height = pipe->partition->width; 351 + height = pipe->partition->wpf.width; 352 352 else 353 353 height = format->height; 354 354 ··· 471 471 return wpf->flip.rotate ? 256 : wpf->max_width; 472 472 } 473 473 474 + static void wpf_partition(struct vsp1_entity *entity, 475 + struct vsp1_pipeline *pipe, 476 + struct vsp1_partition *partition, 477 + unsigned int partition_idx, 478 + struct vsp1_partition_window *window) 479 + { 480 + partition->wpf = *window; 481 + } 482 + 474 483 static const struct vsp1_entity_operations wpf_entity_ops = { 475 484 .destroy = vsp1_wpf_destroy, 476 485 .configure = wpf_configure, 477 486 .max_width = wpf_max_width, 487 + .partition = wpf_partition, 478 488 }; 479 489 480 490 /* -----------------------------------------------------------------------------