| .. | .. |
|---|
| 232 | 232 | vsp1_dlm_destroy(wpf->dlm); |
|---|
| 233 | 233 | } |
|---|
| 234 | 234 | |
|---|
| 235 | +static int wpf_configure_writeback_chain(struct vsp1_rwpf *wpf, |
|---|
| 236 | + struct vsp1_dl_list *dl) |
|---|
| 237 | +{ |
|---|
| 238 | + unsigned int index = wpf->entity.index; |
|---|
| 239 | + struct vsp1_dl_list *dl_next; |
|---|
| 240 | + struct vsp1_dl_body *dlb; |
|---|
| 241 | + |
|---|
| 242 | + dl_next = vsp1_dl_list_get(wpf->dlm); |
|---|
| 243 | + if (!dl_next) { |
|---|
| 244 | + dev_err(wpf->entity.vsp1->dev, |
|---|
| 245 | + "Failed to obtain a dl list, disabling writeback\n"); |
|---|
| 246 | + return -ENOMEM; |
|---|
| 247 | + } |
|---|
| 248 | + |
|---|
| 249 | + dlb = vsp1_dl_list_get_body0(dl_next); |
|---|
| 250 | + vsp1_dl_body_write(dlb, VI6_WPF_WRBCK_CTRL(index), 0); |
|---|
| 251 | + vsp1_dl_list_add_chain(dl, dl_next); |
|---|
| 252 | + |
|---|
| 253 | + return 0; |
|---|
| 254 | +} |
|---|
| 255 | + |
|---|
| 235 | 256 | static void wpf_configure_stream(struct vsp1_entity *entity, |
|---|
| 236 | 257 | struct vsp1_pipeline *pipe, |
|---|
| 258 | + struct vsp1_dl_list *dl, |
|---|
| 237 | 259 | struct vsp1_dl_body *dlb) |
|---|
| 238 | 260 | { |
|---|
| 239 | 261 | struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); |
|---|
| 240 | 262 | struct vsp1_device *vsp1 = wpf->entity.vsp1; |
|---|
| 241 | 263 | const struct v4l2_mbus_framefmt *source_format; |
|---|
| 242 | 264 | const struct v4l2_mbus_framefmt *sink_format; |
|---|
| 265 | + unsigned int index = wpf->entity.index; |
|---|
| 243 | 266 | unsigned int i; |
|---|
| 244 | 267 | u32 outfmt = 0; |
|---|
| 245 | 268 | u32 srcrpf = 0; |
|---|
| 269 | + int ret; |
|---|
| 246 | 270 | |
|---|
| 247 | 271 | sink_format = vsp1_entity_get_pad_format(&wpf->entity, |
|---|
| 248 | 272 | wpf->entity.config, |
|---|
| .. | .. |
|---|
| 250 | 274 | source_format = vsp1_entity_get_pad_format(&wpf->entity, |
|---|
| 251 | 275 | wpf->entity.config, |
|---|
| 252 | 276 | RWPF_PAD_SOURCE); |
|---|
| 277 | + |
|---|
| 253 | 278 | /* Format */ |
|---|
| 254 | | - if (!pipe->lif) { |
|---|
| 279 | + if (!pipe->lif || wpf->writeback) { |
|---|
| 255 | 280 | const struct v4l2_pix_format_mplane *format = &wpf->format; |
|---|
| 256 | 281 | const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; |
|---|
| 257 | 282 | |
|---|
| .. | .. |
|---|
| 276 | 301 | |
|---|
| 277 | 302 | vsp1_wpf_write(wpf, dlb, VI6_WPF_DSWAP, fmtinfo->swap); |
|---|
| 278 | 303 | |
|---|
| 279 | | - if (vsp1_feature(vsp1, VSP1_HAS_WPF_HFLIP) && |
|---|
| 280 | | - wpf->entity.index == 0) |
|---|
| 304 | + if (vsp1_feature(vsp1, VSP1_HAS_WPF_HFLIP) && index == 0) |
|---|
| 281 | 305 | vsp1_wpf_write(wpf, dlb, VI6_WPF_ROT_CTRL, |
|---|
| 282 | 306 | VI6_WPF_ROT_CTRL_LN16 | |
|---|
| 283 | 307 | (256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT)); |
|---|
| .. | .. |
|---|
| 288 | 312 | |
|---|
| 289 | 313 | wpf->outfmt = outfmt; |
|---|
| 290 | 314 | |
|---|
| 291 | | - vsp1_dl_body_write(dlb, VI6_DPR_WPF_FPORCH(wpf->entity.index), |
|---|
| 315 | + vsp1_dl_body_write(dlb, VI6_DPR_WPF_FPORCH(index), |
|---|
| 292 | 316 | VI6_DPR_WPF_FPORCH_FP_WPFN); |
|---|
| 293 | | - |
|---|
| 294 | | - vsp1_dl_body_write(dlb, VI6_WPF_WRBCK_CTRL, 0); |
|---|
| 295 | 317 | |
|---|
| 296 | 318 | /* |
|---|
| 297 | 319 | * Sources. If the pipeline has a single input and BRx is not used, |
|---|
| .. | .. |
|---|
| 317 | 339 | |
|---|
| 318 | 340 | vsp1_wpf_write(wpf, dlb, VI6_WPF_SRCRPF, srcrpf); |
|---|
| 319 | 341 | |
|---|
| 320 | | - /* Enable interrupts */ |
|---|
| 321 | | - vsp1_dl_body_write(dlb, VI6_WPF_IRQ_STA(wpf->entity.index), 0); |
|---|
| 322 | | - vsp1_dl_body_write(dlb, VI6_WPF_IRQ_ENB(wpf->entity.index), |
|---|
| 342 | + /* Enable interrupts. */ |
|---|
| 343 | + vsp1_dl_body_write(dlb, VI6_WPF_IRQ_STA(index), 0); |
|---|
| 344 | + vsp1_dl_body_write(dlb, VI6_WPF_IRQ_ENB(index), |
|---|
| 323 | 345 | VI6_WFP_IRQ_ENB_DFEE); |
|---|
| 346 | + |
|---|
| 347 | + /* |
|---|
| 348 | + * Configure writeback for display pipelines (the wpf writeback flag is |
|---|
| 349 | + * never set for memory-to-memory pipelines). Start by adding a chained |
|---|
| 350 | + * display list to disable writeback after a single frame, and process |
|---|
| 351 | + * to enable writeback. If the display list allocation fails don't |
|---|
| 352 | + * enable writeback as we wouldn't be able to safely disable it, |
|---|
| 353 | + * resulting in possible memory corruption. |
|---|
| 354 | + */ |
|---|
| 355 | + if (wpf->writeback) { |
|---|
| 356 | + ret = wpf_configure_writeback_chain(wpf, dl); |
|---|
| 357 | + if (ret < 0) |
|---|
| 358 | + wpf->writeback = false; |
|---|
| 359 | + } |
|---|
| 360 | + |
|---|
| 361 | + vsp1_dl_body_write(dlb, VI6_WPF_WRBCK_CTRL(index), |
|---|
| 362 | + wpf->writeback ? VI6_WPF_WRBCK_CTRL_WBMD : 0); |
|---|
| 324 | 363 | } |
|---|
| 325 | 364 | |
|---|
| 326 | 365 | static void wpf_configure_frame(struct vsp1_entity *entity, |
|---|
| .. | .. |
|---|
| 362 | 401 | const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; |
|---|
| 363 | 402 | unsigned int width; |
|---|
| 364 | 403 | unsigned int height; |
|---|
| 404 | + unsigned int left; |
|---|
| 365 | 405 | unsigned int offset; |
|---|
| 366 | 406 | unsigned int flip; |
|---|
| 367 | 407 | unsigned int i; |
|---|
| .. | .. |
|---|
| 371 | 411 | RWPF_PAD_SINK); |
|---|
| 372 | 412 | width = sink_format->width; |
|---|
| 373 | 413 | height = sink_format->height; |
|---|
| 414 | + left = 0; |
|---|
| 374 | 415 | |
|---|
| 375 | 416 | /* |
|---|
| 376 | 417 | * Cropping. The partition algorithm can split the image into |
|---|
| 377 | 418 | * multiple slices. |
|---|
| 378 | 419 | */ |
|---|
| 379 | | - if (pipe->partitions > 1) |
|---|
| 420 | + if (pipe->partitions > 1) { |
|---|
| 380 | 421 | width = pipe->partition->wpf.width; |
|---|
| 422 | + left = pipe->partition->wpf.left; |
|---|
| 423 | + } |
|---|
| 381 | 424 | |
|---|
| 382 | 425 | vsp1_wpf_write(wpf, dlb, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | |
|---|
| 383 | 426 | (0 << VI6_WPF_SZCLIP_OFST_SHIFT) | |
|---|
| .. | .. |
|---|
| 386 | 429 | (0 << VI6_WPF_SZCLIP_OFST_SHIFT) | |
|---|
| 387 | 430 | (height << VI6_WPF_SZCLIP_SIZE_SHIFT)); |
|---|
| 388 | 431 | |
|---|
| 389 | | - if (pipe->lif) |
|---|
| 432 | + /* |
|---|
| 433 | + * For display pipelines without writeback enabled there's no memory |
|---|
| 434 | + * address to configure, return now. |
|---|
| 435 | + */ |
|---|
| 436 | + if (pipe->lif && !wpf->writeback) |
|---|
| 390 | 437 | return; |
|---|
| 391 | 438 | |
|---|
| 392 | 439 | /* |
|---|
| .. | .. |
|---|
| 408 | 455 | flip = wpf->flip.active; |
|---|
| 409 | 456 | |
|---|
| 410 | 457 | if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate) |
|---|
| 411 | | - offset = format->width - pipe->partition->wpf.left |
|---|
| 412 | | - - pipe->partition->wpf.width; |
|---|
| 458 | + offset = format->width - left - width; |
|---|
| 413 | 459 | else if (flip & BIT(WPF_CTRL_VFLIP) && wpf->flip.rotate) |
|---|
| 414 | | - offset = format->height - pipe->partition->wpf.left |
|---|
| 415 | | - - pipe->partition->wpf.width; |
|---|
| 460 | + offset = format->height - left - width; |
|---|
| 416 | 461 | else |
|---|
| 417 | | - offset = pipe->partition->wpf.left; |
|---|
| 462 | + offset = left; |
|---|
| 418 | 463 | |
|---|
| 419 | 464 | for (i = 0; i < format->num_planes; ++i) { |
|---|
| 420 | 465 | unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; |
|---|
| .. | .. |
|---|
| 436 | 481 | * image height. |
|---|
| 437 | 482 | */ |
|---|
| 438 | 483 | if (wpf->flip.rotate) |
|---|
| 439 | | - height = pipe->partition->wpf.width; |
|---|
| 484 | + height = width; |
|---|
| 440 | 485 | else |
|---|
| 441 | 486 | height = format->height; |
|---|
| 442 | 487 | |
|---|
| .. | .. |
|---|
| 477 | 522 | vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]); |
|---|
| 478 | 523 | vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]); |
|---|
| 479 | 524 | vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]); |
|---|
| 525 | + |
|---|
| 526 | + /* |
|---|
| 527 | + * Writeback operates in single-shot mode and lasts for a single frame, |
|---|
| 528 | + * reset the writeback flag to false for the next frame. |
|---|
| 529 | + */ |
|---|
| 530 | + wpf->writeback = false; |
|---|
| 480 | 531 | } |
|---|
| 481 | 532 | |
|---|
| 482 | 533 | static unsigned int wpf_max_width(struct vsp1_entity *entity, |
|---|