root/drivers/media/platform/vsp1/vsp1_wpf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vsp1_wpf_write
  2. vsp1_wpf_set_rotation
  3. vsp1_wpf_s_ctrl
  4. wpf_init_controls
  5. wpf_s_stream
  6. vsp1_wpf_destroy
  7. wpf_configure_writeback_chain
  8. wpf_configure_stream
  9. wpf_configure_frame
  10. wpf_configure_partition
  11. wpf_max_width
  12. wpf_partition
  13. vsp1_wpf_create

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * vsp1_wpf.c  --  R-Car VSP1 Write 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 WPF_GEN2_MAX_WIDTH                      2048U
  21 #define WPF_GEN2_MAX_HEIGHT                     2048U
  22 #define WPF_GEN3_MAX_WIDTH                      8190U
  23 #define WPF_GEN3_MAX_HEIGHT                     8190U
  24 
  25 /* -----------------------------------------------------------------------------
  26  * Device Access
  27  */
  28 
  29 static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf,
  30                                   struct vsp1_dl_body *dlb, u32 reg, u32 data)
  31 {
  32         vsp1_dl_body_write(dlb, reg + wpf->entity.index * VI6_WPF_OFFSET, data);
  33 }
  34 
  35 /* -----------------------------------------------------------------------------
  36  * Controls
  37  */
  38 
  39 enum wpf_flip_ctrl {
  40         WPF_CTRL_VFLIP = 0,
  41         WPF_CTRL_HFLIP = 1,
  42 };
  43 
  44 static int vsp1_wpf_set_rotation(struct vsp1_rwpf *wpf, unsigned int rotation)
  45 {
  46         struct vsp1_video *video = wpf->video;
  47         struct v4l2_mbus_framefmt *sink_format;
  48         struct v4l2_mbus_framefmt *source_format;
  49         bool rotate;
  50         int ret = 0;
  51 
  52         /*
  53          * Only consider the 0°/180° from/to 90°/270° modifications, the rest
  54          * is taken care of by the flipping configuration.
  55          */
  56         rotate = rotation == 90 || rotation == 270;
  57         if (rotate == wpf->flip.rotate)
  58                 return 0;
  59 
  60         /* Changing rotation isn't allowed when buffers are allocated. */
  61         mutex_lock(&video->lock);
  62 
  63         if (vb2_is_busy(&video->queue)) {
  64                 ret = -EBUSY;
  65                 goto done;
  66         }
  67 
  68         sink_format = vsp1_entity_get_pad_format(&wpf->entity,
  69                                                  wpf->entity.config,
  70                                                  RWPF_PAD_SINK);
  71         source_format = vsp1_entity_get_pad_format(&wpf->entity,
  72                                                    wpf->entity.config,
  73                                                    RWPF_PAD_SOURCE);
  74 
  75         mutex_lock(&wpf->entity.lock);
  76 
  77         if (rotate) {
  78                 source_format->width = sink_format->height;
  79                 source_format->height = sink_format->width;
  80         } else {
  81                 source_format->width = sink_format->width;
  82                 source_format->height = sink_format->height;
  83         }
  84 
  85         wpf->flip.rotate = rotate;
  86 
  87         mutex_unlock(&wpf->entity.lock);
  88 
  89 done:
  90         mutex_unlock(&video->lock);
  91         return ret;
  92 }
  93 
  94 static int vsp1_wpf_s_ctrl(struct v4l2_ctrl *ctrl)
  95 {
  96         struct vsp1_rwpf *wpf =
  97                 container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
  98         unsigned int rotation;
  99         u32 flip = 0;
 100         int ret;
 101 
 102         /* Update the rotation. */
 103         rotation = wpf->flip.ctrls.rotate ? wpf->flip.ctrls.rotate->val : 0;
 104         ret = vsp1_wpf_set_rotation(wpf, rotation);
 105         if (ret < 0)
 106                 return ret;
 107 
 108         /*
 109          * Compute the flip value resulting from all three controls, with
 110          * rotation by 180° flipping the image in both directions. Store the
 111          * result in the pending flip field for the next frame that will be
 112          * processed.
 113          */
 114         if (wpf->flip.ctrls.vflip->val)
 115                 flip |= BIT(WPF_CTRL_VFLIP);
 116 
 117         if (wpf->flip.ctrls.hflip && wpf->flip.ctrls.hflip->val)
 118                 flip |= BIT(WPF_CTRL_HFLIP);
 119 
 120         if (rotation == 180 || rotation == 270)
 121                 flip ^= BIT(WPF_CTRL_VFLIP) | BIT(WPF_CTRL_HFLIP);
 122 
 123         spin_lock_irq(&wpf->flip.lock);
 124         wpf->flip.pending = flip;
 125         spin_unlock_irq(&wpf->flip.lock);
 126 
 127         return 0;
 128 }
 129 
 130 static const struct v4l2_ctrl_ops vsp1_wpf_ctrl_ops = {
 131         .s_ctrl = vsp1_wpf_s_ctrl,
 132 };
 133 
 134 static int wpf_init_controls(struct vsp1_rwpf *wpf)
 135 {
 136         struct vsp1_device *vsp1 = wpf->entity.vsp1;
 137         unsigned int num_flip_ctrls;
 138 
 139         spin_lock_init(&wpf->flip.lock);
 140 
 141         if (wpf->entity.index != 0) {
 142                 /* Only WPF0 supports flipping. */
 143                 num_flip_ctrls = 0;
 144         } else if (vsp1_feature(vsp1, VSP1_HAS_WPF_HFLIP)) {
 145                 /*
 146                  * When horizontal flip is supported the WPF implements three
 147                  * controls (horizontal flip, vertical flip and rotation).
 148                  */
 149                 num_flip_ctrls = 3;
 150         } else if (vsp1_feature(vsp1, VSP1_HAS_WPF_VFLIP)) {
 151                 /*
 152                  * When only vertical flip is supported the WPF implements a
 153                  * single control (vertical flip).
 154                  */
 155                 num_flip_ctrls = 1;
 156         } else {
 157                 /* Otherwise flipping is not supported. */
 158                 num_flip_ctrls = 0;
 159         }
 160 
 161         vsp1_rwpf_init_ctrls(wpf, num_flip_ctrls);
 162 
 163         if (num_flip_ctrls >= 1) {
 164                 wpf->flip.ctrls.vflip =
 165                         v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
 166                                           V4L2_CID_VFLIP, 0, 1, 1, 0);
 167         }
 168 
 169         if (num_flip_ctrls == 3) {
 170                 wpf->flip.ctrls.hflip =
 171                         v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
 172                                           V4L2_CID_HFLIP, 0, 1, 1, 0);
 173                 wpf->flip.ctrls.rotate =
 174                         v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
 175                                           V4L2_CID_ROTATE, 0, 270, 90, 0);
 176                 v4l2_ctrl_cluster(3, &wpf->flip.ctrls.vflip);
 177         }
 178 
 179         if (wpf->ctrls.error) {
 180                 dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
 181                         wpf->entity.index);
 182                 return wpf->ctrls.error;
 183         }
 184 
 185         return 0;
 186 }
 187 
 188 /* -----------------------------------------------------------------------------
 189  * V4L2 Subdevice Core Operations
 190  */
 191 
 192 static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 193 {
 194         struct vsp1_rwpf *wpf = to_rwpf(subdev);
 195         struct vsp1_device *vsp1 = wpf->entity.vsp1;
 196 
 197         if (enable)
 198                 return 0;
 199 
 200         /*
 201          * Write to registers directly when stopping the stream as there will be
 202          * no pipeline run to apply the display list.
 203          */
 204         vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
 205         vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET +
 206                    VI6_WPF_SRCRPF, 0);
 207 
 208         return 0;
 209 }
 210 
 211 /* -----------------------------------------------------------------------------
 212  * V4L2 Subdevice Operations
 213  */
 214 
 215 static const struct v4l2_subdev_video_ops wpf_video_ops = {
 216         .s_stream = wpf_s_stream,
 217 };
 218 
 219 static const struct v4l2_subdev_ops wpf_ops = {
 220         .video  = &wpf_video_ops,
 221         .pad    = &vsp1_rwpf_pad_ops,
 222 };
 223 
 224 /* -----------------------------------------------------------------------------
 225  * VSP1 Entity Operations
 226  */
 227 
 228 static void vsp1_wpf_destroy(struct vsp1_entity *entity)
 229 {
 230         struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
 231 
 232         vsp1_dlm_destroy(wpf->dlm);
 233 }
 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 
 256 static void wpf_configure_stream(struct vsp1_entity *entity,
 257                                  struct vsp1_pipeline *pipe,
 258                                  struct vsp1_dl_list *dl,
 259                                  struct vsp1_dl_body *dlb)
 260 {
 261         struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
 262         struct vsp1_device *vsp1 = wpf->entity.vsp1;
 263         const struct v4l2_mbus_framefmt *source_format;
 264         const struct v4l2_mbus_framefmt *sink_format;
 265         unsigned int index = wpf->entity.index;
 266         unsigned int i;
 267         u32 outfmt = 0;
 268         u32 srcrpf = 0;
 269         int ret;
 270 
 271         sink_format = vsp1_entity_get_pad_format(&wpf->entity,
 272                                                  wpf->entity.config,
 273                                                  RWPF_PAD_SINK);
 274         source_format = vsp1_entity_get_pad_format(&wpf->entity,
 275                                                    wpf->entity.config,
 276                                                    RWPF_PAD_SOURCE);
 277 
 278         /* Format */
 279         if (!pipe->lif || wpf->writeback) {
 280                 const struct v4l2_pix_format_mplane *format = &wpf->format;
 281                 const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
 282 
 283                 outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT;
 284 
 285                 if (wpf->flip.rotate)
 286                         outfmt |= VI6_WPF_OUTFMT_ROT;
 287 
 288                 if (fmtinfo->alpha)
 289                         outfmt |= VI6_WPF_OUTFMT_PXA;
 290                 if (fmtinfo->swap_yc)
 291                         outfmt |= VI6_WPF_OUTFMT_SPYCS;
 292                 if (fmtinfo->swap_uv)
 293                         outfmt |= VI6_WPF_OUTFMT_SPUVS;
 294 
 295                 /* Destination stride and byte swapping. */
 296                 vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_STRIDE_Y,
 297                                format->plane_fmt[0].bytesperline);
 298                 if (format->num_planes > 1)
 299                         vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_STRIDE_C,
 300                                        format->plane_fmt[1].bytesperline);
 301 
 302                 vsp1_wpf_write(wpf, dlb, VI6_WPF_DSWAP, fmtinfo->swap);
 303 
 304                 if (vsp1_feature(vsp1, VSP1_HAS_WPF_HFLIP) && index == 0)
 305                         vsp1_wpf_write(wpf, dlb, VI6_WPF_ROT_CTRL,
 306                                        VI6_WPF_ROT_CTRL_LN16 |
 307                                        (256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT));
 308         }
 309 
 310         if (sink_format->code != source_format->code)
 311                 outfmt |= VI6_WPF_OUTFMT_CSC;
 312 
 313         wpf->outfmt = outfmt;
 314 
 315         vsp1_dl_body_write(dlb, VI6_DPR_WPF_FPORCH(index),
 316                            VI6_DPR_WPF_FPORCH_FP_WPFN);
 317 
 318         /*
 319          * Sources. If the pipeline has a single input and BRx is not used,
 320          * configure it as the master layer. Otherwise configure all
 321          * inputs as sub-layers and select the virtual RPF as the master
 322          * layer.
 323          */
 324         for (i = 0; i < vsp1->info->rpf_count; ++i) {
 325                 struct vsp1_rwpf *input = pipe->inputs[i];
 326 
 327                 if (!input)
 328                         continue;
 329 
 330                 srcrpf |= (!pipe->brx && pipe->num_inputs == 1)
 331                         ? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index)
 332                         : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index);
 333         }
 334 
 335         if (pipe->brx)
 336                 srcrpf |= pipe->brx->type == VSP1_ENTITY_BRU
 337                         ? VI6_WPF_SRCRPF_VIRACT_MST
 338                         : VI6_WPF_SRCRPF_VIRACT2_MST;
 339 
 340         vsp1_wpf_write(wpf, dlb, VI6_WPF_SRCRPF, srcrpf);
 341 
 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),
 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);
 363 }
 364 
 365 static void wpf_configure_frame(struct vsp1_entity *entity,
 366                                 struct vsp1_pipeline *pipe,
 367                                 struct vsp1_dl_list *dl,
 368                                 struct vsp1_dl_body *dlb)
 369 {
 370         const unsigned int mask = BIT(WPF_CTRL_VFLIP)
 371                                 | BIT(WPF_CTRL_HFLIP);
 372         struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
 373         unsigned long flags;
 374         u32 outfmt;
 375 
 376         spin_lock_irqsave(&wpf->flip.lock, flags);
 377         wpf->flip.active = (wpf->flip.active & ~mask)
 378                          | (wpf->flip.pending & mask);
 379         spin_unlock_irqrestore(&wpf->flip.lock, flags);
 380 
 381         outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt;
 382 
 383         if (wpf->flip.active & BIT(WPF_CTRL_VFLIP))
 384                 outfmt |= VI6_WPF_OUTFMT_FLP;
 385         if (wpf->flip.active & BIT(WPF_CTRL_HFLIP))
 386                 outfmt |= VI6_WPF_OUTFMT_HFLP;
 387 
 388         vsp1_wpf_write(wpf, dlb, VI6_WPF_OUTFMT, outfmt);
 389 }
 390 
 391 static void wpf_configure_partition(struct vsp1_entity *entity,
 392                                     struct vsp1_pipeline *pipe,
 393                                     struct vsp1_dl_list *dl,
 394                                     struct vsp1_dl_body *dlb)
 395 {
 396         struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
 397         struct vsp1_device *vsp1 = wpf->entity.vsp1;
 398         struct vsp1_rwpf_memory mem = wpf->mem;
 399         const struct v4l2_mbus_framefmt *sink_format;
 400         const struct v4l2_pix_format_mplane *format = &wpf->format;
 401         const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
 402         unsigned int width;
 403         unsigned int height;
 404         unsigned int left;
 405         unsigned int offset;
 406         unsigned int flip;
 407         unsigned int i;
 408 
 409         sink_format = vsp1_entity_get_pad_format(&wpf->entity,
 410                                                  wpf->entity.config,
 411                                                  RWPF_PAD_SINK);
 412         width = sink_format->width;
 413         height = sink_format->height;
 414         left = 0;
 415 
 416         /*
 417          * Cropping. The partition algorithm can split the image into
 418          * multiple slices.
 419          */
 420         if (pipe->partitions > 1) {
 421                 width = pipe->partition->wpf.width;
 422                 left = pipe->partition->wpf.left;
 423         }
 424 
 425         vsp1_wpf_write(wpf, dlb, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
 426                        (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
 427                        (width << VI6_WPF_SZCLIP_SIZE_SHIFT));
 428         vsp1_wpf_write(wpf, dlb, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
 429                        (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
 430                        (height << VI6_WPF_SZCLIP_SIZE_SHIFT));
 431 
 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)
 437                 return;
 438 
 439         /*
 440          * Update the memory offsets based on flipping configuration.
 441          * The destination addresses point to the locations where the
 442          * VSP starts writing to memory, which can be any corner of the
 443          * image depending on the combination of flipping and rotation.
 444          */
 445 
 446         /*
 447          * First take the partition left coordinate into account.
 448          * Compute the offset to order the partitions correctly on the
 449          * output based on whether flipping is enabled. Consider
 450          * horizontal flipping when rotation is disabled but vertical
 451          * flipping when rotation is enabled, as rotating the image
 452          * switches the horizontal and vertical directions. The offset
 453          * is applied horizontally or vertically accordingly.
 454          */
 455         flip = wpf->flip.active;
 456 
 457         if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate)
 458                 offset = format->width - left - width;
 459         else if (flip & BIT(WPF_CTRL_VFLIP) && wpf->flip.rotate)
 460                 offset = format->height - left - width;
 461         else
 462                 offset = left;
 463 
 464         for (i = 0; i < format->num_planes; ++i) {
 465                 unsigned int hsub = i > 0 ? fmtinfo->hsub : 1;
 466                 unsigned int vsub = i > 0 ? fmtinfo->vsub : 1;
 467 
 468                 if (wpf->flip.rotate)
 469                         mem.addr[i] += offset / vsub
 470                                      * format->plane_fmt[i].bytesperline;
 471                 else
 472                         mem.addr[i] += offset / hsub
 473                                      * fmtinfo->bpp[i] / 8;
 474         }
 475 
 476         if (flip & BIT(WPF_CTRL_VFLIP)) {
 477                 /*
 478                  * When rotating the output (after rotation) image
 479                  * height is equal to the partition width (before
 480                  * rotation). Otherwise it is equal to the output
 481                  * image height.
 482                  */
 483                 if (wpf->flip.rotate)
 484                         height = width;
 485                 else
 486                         height = format->height;
 487 
 488                 mem.addr[0] += (height - 1)
 489                              * format->plane_fmt[0].bytesperline;
 490 
 491                 if (format->num_planes > 1) {
 492                         offset = (height / fmtinfo->vsub - 1)
 493                                * format->plane_fmt[1].bytesperline;
 494                         mem.addr[1] += offset;
 495                         mem.addr[2] += offset;
 496                 }
 497         }
 498 
 499         if (wpf->flip.rotate && !(flip & BIT(WPF_CTRL_HFLIP))) {
 500                 unsigned int hoffset = max(0, (int)format->width - 16);
 501 
 502                 /*
 503                  * Compute the output coordinate. The partition
 504                  * horizontal (left) offset becomes a vertical offset.
 505                  */
 506                 for (i = 0; i < format->num_planes; ++i) {
 507                         unsigned int hsub = i > 0 ? fmtinfo->hsub : 1;
 508 
 509                         mem.addr[i] += hoffset / hsub
 510                                      * fmtinfo->bpp[i] / 8;
 511                 }
 512         }
 513 
 514         /*
 515          * On Gen3 hardware the SPUVS bit has no effect on 3-planar
 516          * formats. Swap the U and V planes manually in that case.
 517          */
 518         if (vsp1->info->gen == 3 && format->num_planes == 3 &&
 519             fmtinfo->swap_uv)
 520                 swap(mem.addr[1], mem.addr[2]);
 521 
 522         vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]);
 523         vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]);
 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;
 531 }
 532 
 533 static unsigned int wpf_max_width(struct vsp1_entity *entity,
 534                                   struct vsp1_pipeline *pipe)
 535 {
 536         struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
 537 
 538         return wpf->flip.rotate ? 256 : wpf->max_width;
 539 }
 540 
 541 static void wpf_partition(struct vsp1_entity *entity,
 542                           struct vsp1_pipeline *pipe,
 543                           struct vsp1_partition *partition,
 544                           unsigned int partition_idx,
 545                           struct vsp1_partition_window *window)
 546 {
 547         partition->wpf = *window;
 548 }
 549 
 550 static const struct vsp1_entity_operations wpf_entity_ops = {
 551         .destroy = vsp1_wpf_destroy,
 552         .configure_stream = wpf_configure_stream,
 553         .configure_frame = wpf_configure_frame,
 554         .configure_partition = wpf_configure_partition,
 555         .max_width = wpf_max_width,
 556         .partition = wpf_partition,
 557 };
 558 
 559 /* -----------------------------------------------------------------------------
 560  * Initialization and Cleanup
 561  */
 562 
 563 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 564 {
 565         struct vsp1_rwpf *wpf;
 566         char name[6];
 567         int ret;
 568 
 569         wpf = devm_kzalloc(vsp1->dev, sizeof(*wpf), GFP_KERNEL);
 570         if (wpf == NULL)
 571                 return ERR_PTR(-ENOMEM);
 572 
 573         if (vsp1->info->gen == 2) {
 574                 wpf->max_width = WPF_GEN2_MAX_WIDTH;
 575                 wpf->max_height = WPF_GEN2_MAX_HEIGHT;
 576         } else {
 577                 wpf->max_width = WPF_GEN3_MAX_WIDTH;
 578                 wpf->max_height = WPF_GEN3_MAX_HEIGHT;
 579         }
 580 
 581         wpf->entity.ops = &wpf_entity_ops;
 582         wpf->entity.type = VSP1_ENTITY_WPF;
 583         wpf->entity.index = index;
 584 
 585         sprintf(name, "wpf.%u", index);
 586         ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops,
 587                                MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER);
 588         if (ret < 0)
 589                 return ERR_PTR(ret);
 590 
 591         /* Initialize the display list manager. */
 592         wpf->dlm = vsp1_dlm_create(vsp1, index, 64);
 593         if (!wpf->dlm) {
 594                 ret = -ENOMEM;
 595                 goto error;
 596         }
 597 
 598         /* Initialize the control handler. */
 599         ret = wpf_init_controls(wpf);
 600         if (ret < 0) {
 601                 dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
 602                         index);
 603                 goto error;
 604         }
 605 
 606         v4l2_ctrl_handler_setup(&wpf->ctrls);
 607 
 608         return wpf;
 609 
 610 error:
 611         vsp1_entity_destroy(&wpf->entity);
 612         return ERR_PTR(ret);
 613 }

/* [<][>][^][v][top][bottom][index][help] */