linux/drivers/media/platform/vsp1/vsp1_drm.c
<<
>>
Prefs
   1/*
   2 * vsp1_drm.c  --  R-Car VSP1 DRM API
   3 *
   4 * Copyright (C) 2015 Renesas Electronics Corporation
   5 *
   6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 */
  13
  14#include <linux/device.h>
  15#include <linux/dma-mapping.h>
  16#include <linux/slab.h>
  17
  18#include <media/media-entity.h>
  19#include <media/v4l2-subdev.h>
  20#include <media/vsp1.h>
  21
  22#include "vsp1.h"
  23#include "vsp1_bru.h"
  24#include "vsp1_dl.h"
  25#include "vsp1_drm.h"
  26#include "vsp1_lif.h"
  27#include "vsp1_pipe.h"
  28#include "vsp1_rwpf.h"
  29
  30#define BRU_NAME(e)     (e)->type == VSP1_ENTITY_BRU ? "BRU" : "BRS"
  31
  32/* -----------------------------------------------------------------------------
  33 * Interrupt Handling
  34 */
  35
  36static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe,
  37                                       bool completed)
  38{
  39        struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
  40
  41        if (drm_pipe->du_complete)
  42                drm_pipe->du_complete(drm_pipe->du_private, completed);
  43}
  44
  45/* -----------------------------------------------------------------------------
  46 * DU Driver API
  47 */
  48
  49int vsp1_du_init(struct device *dev)
  50{
  51        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
  52
  53        if (!vsp1)
  54                return -EPROBE_DEFER;
  55
  56        return 0;
  57}
  58EXPORT_SYMBOL_GPL(vsp1_du_init);
  59
  60/**
  61 * vsp1_du_setup_lif - Setup the output part of the VSP pipeline
  62 * @dev: the VSP device
  63 * @pipe_index: the DRM pipeline index
  64 * @cfg: the LIF configuration
  65 *
  66 * Configure the output part of VSP DRM pipeline for the given frame @cfg.width
  67 * and @cfg.height. This sets up formats on the blend unit (BRU or BRS) source
  68 * pad, the WPF sink and source pads, and the LIF sink pad.
  69 *
  70 * The @pipe_index argument selects which DRM pipeline to setup. The number of
  71 * available pipelines depend on the VSP instance.
  72 *
  73 * As the media bus code on the blend unit source pad is conditioned by the
  74 * configuration of its sink 0 pad, we also set up the formats on all blend unit
  75 * sinks, even if the configuration will be overwritten later by
  76 * vsp1_du_setup_rpf(). This ensures that the blend unit configuration is set to
  77 * a well defined state.
  78 *
  79 * Return 0 on success or a negative error code on failure.
  80 */
  81int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
  82                      const struct vsp1_du_lif_config *cfg)
  83{
  84        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
  85        struct vsp1_drm_pipeline *drm_pipe;
  86        struct vsp1_pipeline *pipe;
  87        struct vsp1_bru *bru;
  88        struct vsp1_entity *entity;
  89        struct vsp1_entity *next;
  90        struct vsp1_dl_list *dl;
  91        struct v4l2_subdev_format format;
  92        unsigned long flags;
  93        unsigned int i;
  94        int ret;
  95
  96        if (pipe_index >= vsp1->info->lif_count)
  97                return -EINVAL;
  98
  99        drm_pipe = &vsp1->drm->pipe[pipe_index];
 100        pipe = &drm_pipe->pipe;
 101        bru = to_bru(&pipe->bru->subdev);
 102
 103        if (!cfg) {
 104                /*
 105                 * NULL configuration means the CRTC is being disabled, stop
 106                 * the pipeline and turn the light off.
 107                 */
 108                ret = vsp1_pipeline_stop(pipe);
 109                if (ret == -ETIMEDOUT)
 110                        dev_err(vsp1->dev, "DRM pipeline stop timeout\n");
 111
 112                media_pipeline_stop(&pipe->output->entity.subdev.entity);
 113
 114                for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) {
 115                        struct vsp1_rwpf *rpf = pipe->inputs[i];
 116
 117                        if (!rpf)
 118                                continue;
 119
 120                        /*
 121                         * Remove the RPF from the pipe and the list of BRU
 122                         * inputs.
 123                         */
 124                        WARN_ON(list_empty(&rpf->entity.list_pipe));
 125                        list_del_init(&rpf->entity.list_pipe);
 126                        pipe->inputs[i] = NULL;
 127
 128                        bru->inputs[rpf->bru_input].rpf = NULL;
 129                }
 130
 131                drm_pipe->du_complete = NULL;
 132                pipe->num_inputs = 0;
 133
 134                vsp1_dlm_reset(pipe->output->dlm);
 135                vsp1_device_put(vsp1);
 136
 137                dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
 138
 139                return 0;
 140        }
 141
 142        dev_dbg(vsp1->dev, "%s: configuring LIF%u with format %ux%u\n",
 143                __func__, pipe_index, cfg->width, cfg->height);
 144
 145        /*
 146         * Configure the format at the BRU sinks and propagate it through the
 147         * pipeline.
 148         */
 149        memset(&format, 0, sizeof(format));
 150        format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 151
 152        for (i = 0; i < pipe->bru->source_pad; ++i) {
 153                format.pad = i;
 154
 155                format.format.width = cfg->width;
 156                format.format.height = cfg->height;
 157                format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
 158                format.format.field = V4L2_FIELD_NONE;
 159
 160                ret = v4l2_subdev_call(&pipe->bru->subdev, pad,
 161                                       set_fmt, NULL, &format);
 162                if (ret < 0)
 163                        return ret;
 164
 165                dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n",
 166                        __func__, format.format.width, format.format.height,
 167                        format.format.code, BRU_NAME(pipe->bru), i);
 168        }
 169
 170        format.pad = pipe->bru->source_pad;
 171        format.format.width = cfg->width;
 172        format.format.height = cfg->height;
 173        format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
 174        format.format.field = V4L2_FIELD_NONE;
 175
 176        ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_fmt, NULL,
 177                               &format);
 178        if (ret < 0)
 179                return ret;
 180
 181        dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n",
 182                __func__, format.format.width, format.format.height,
 183                format.format.code, BRU_NAME(pipe->bru), i);
 184
 185        format.pad = RWPF_PAD_SINK;
 186        ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, set_fmt, NULL,
 187                               &format);
 188        if (ret < 0)
 189                return ret;
 190
 191        dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on WPF%u sink\n",
 192                __func__, format.format.width, format.format.height,
 193                format.format.code, pipe->output->entity.index);
 194
 195        format.pad = RWPF_PAD_SOURCE;
 196        ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, get_fmt, NULL,
 197                               &format);
 198        if (ret < 0)
 199                return ret;
 200
 201        dev_dbg(vsp1->dev, "%s: got format %ux%u (%x) on WPF%u source\n",
 202                __func__, format.format.width, format.format.height,
 203                format.format.code, pipe->output->entity.index);
 204
 205        format.pad = LIF_PAD_SINK;
 206        ret = v4l2_subdev_call(&pipe->lif->subdev, pad, set_fmt, NULL,
 207                               &format);
 208        if (ret < 0)
 209                return ret;
 210
 211        dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on LIF%u sink\n",
 212                __func__, format.format.width, format.format.height,
 213                format.format.code, pipe_index);
 214
 215        /*
 216         * Verify that the format at the output of the pipeline matches the
 217         * requested frame size and media bus code.
 218         */
 219        if (format.format.width != cfg->width ||
 220            format.format.height != cfg->height ||
 221            format.format.code != MEDIA_BUS_FMT_ARGB8888_1X32) {
 222                dev_dbg(vsp1->dev, "%s: format mismatch\n", __func__);
 223                return -EPIPE;
 224        }
 225
 226        /*
 227         * Mark the pipeline as streaming and enable the VSP1. This will store
 228         * the pipeline pointer in all entities, which the s_stream handlers
 229         * will need. We don't start the entities themselves right at this point
 230         * as there's no plane configured yet, so we can't start processing
 231         * buffers.
 232         */
 233        ret = vsp1_device_get(vsp1);
 234        if (ret < 0)
 235                return ret;
 236
 237        /*
 238         * Register a callback to allow us to notify the DRM driver of frame
 239         * completion events.
 240         */
 241        drm_pipe->du_complete = cfg->callback;
 242        drm_pipe->du_private = cfg->callback_data;
 243
 244        ret = media_pipeline_start(&pipe->output->entity.subdev.entity,
 245                                          &pipe->pipe);
 246        if (ret < 0) {
 247                dev_dbg(vsp1->dev, "%s: pipeline start failed\n", __func__);
 248                vsp1_device_put(vsp1);
 249                return ret;
 250        }
 251
 252        /* Disable the display interrupts. */
 253        vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0);
 254        vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0);
 255
 256        /* Configure all entities in the pipeline. */
 257        dl = vsp1_dl_list_get(pipe->output->dlm);
 258
 259        list_for_each_entry_safe(entity, next, &pipe->entities, list_pipe) {
 260                vsp1_entity_route_setup(entity, pipe, dl);
 261
 262                if (entity->ops->configure) {
 263                        entity->ops->configure(entity, pipe, dl,
 264                                               VSP1_ENTITY_PARAMS_INIT);
 265                        entity->ops->configure(entity, pipe, dl,
 266                                               VSP1_ENTITY_PARAMS_RUNTIME);
 267                        entity->ops->configure(entity, pipe, dl,
 268                                               VSP1_ENTITY_PARAMS_PARTITION);
 269                }
 270        }
 271
 272        vsp1_dl_list_commit(dl);
 273
 274        /* Start the pipeline. */
 275        spin_lock_irqsave(&pipe->irqlock, flags);
 276        vsp1_pipeline_run(pipe);
 277        spin_unlock_irqrestore(&pipe->irqlock, flags);
 278
 279        dev_dbg(vsp1->dev, "%s: pipeline enabled\n", __func__);
 280
 281        return 0;
 282}
 283EXPORT_SYMBOL_GPL(vsp1_du_setup_lif);
 284
 285/**
 286 * vsp1_du_atomic_begin - Prepare for an atomic update
 287 * @dev: the VSP device
 288 * @pipe_index: the DRM pipeline index
 289 */
 290void vsp1_du_atomic_begin(struct device *dev, unsigned int pipe_index)
 291{
 292        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 293        struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
 294
 295        drm_pipe->enabled = drm_pipe->pipe.num_inputs != 0;
 296}
 297EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
 298
 299/**
 300 * vsp1_du_atomic_update - Setup one RPF input of the VSP pipeline
 301 * @dev: the VSP device
 302 * @pipe_index: the DRM pipeline index
 303 * @rpf_index: index of the RPF to setup (0-based)
 304 * @cfg: the RPF configuration
 305 *
 306 * Configure the VSP to perform image composition through RPF @rpf_index as
 307 * described by the @cfg configuration. The image to compose is referenced by
 308 * @cfg.mem and composed using the @cfg.src crop rectangle and the @cfg.dst
 309 * composition rectangle. The Z-order is configurable with higher @zpos values
 310 * displayed on top.
 311 *
 312 * If the @cfg configuration is NULL, the RPF will be disabled. Calling the
 313 * function on a disabled RPF is allowed.
 314 *
 315 * Image format as stored in memory is expressed as a V4L2 @cfg.pixelformat
 316 * value. The memory pitch is configurable to allow for padding at end of lines,
 317 * or simply for images that extend beyond the crop rectangle boundaries. The
 318 * @cfg.pitch value is expressed in bytes and applies to all planes for
 319 * multiplanar formats.
 320 *
 321 * The source memory buffer is referenced by the DMA address of its planes in
 322 * the @cfg.mem array. Up to two planes are supported. The second plane DMA
 323 * address is ignored for formats using a single plane.
 324 *
 325 * This function isn't reentrant, the caller needs to serialize calls.
 326 *
 327 * Return 0 on success or a negative error code on failure.
 328 */
 329int vsp1_du_atomic_update(struct device *dev, unsigned int pipe_index,
 330                          unsigned int rpf_index,
 331                          const struct vsp1_du_atomic_config *cfg)
 332{
 333        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 334        struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
 335        const struct vsp1_format_info *fmtinfo;
 336        struct vsp1_rwpf *rpf;
 337
 338        if (rpf_index >= vsp1->info->rpf_count)
 339                return -EINVAL;
 340
 341        rpf = vsp1->rpf[rpf_index];
 342
 343        if (!cfg) {
 344                dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__,
 345                        rpf_index);
 346
 347                /*
 348                 * Remove the RPF from the pipe's inputs. The atomic flush
 349                 * handler will disable the input and remove the entity from the
 350                 * pipe's entities list.
 351                 */
 352                drm_pipe->pipe.inputs[rpf_index] = NULL;
 353                return 0;
 354        }
 355
 356        dev_dbg(vsp1->dev,
 357                "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad, %pad } zpos %u\n",
 358                __func__, rpf_index,
 359                cfg->src.left, cfg->src.top, cfg->src.width, cfg->src.height,
 360                cfg->dst.left, cfg->dst.top, cfg->dst.width, cfg->dst.height,
 361                cfg->pixelformat, cfg->pitch, &cfg->mem[0], &cfg->mem[1],
 362                &cfg->mem[2], cfg->zpos);
 363
 364        /*
 365         * Store the format, stride, memory buffer address, crop and compose
 366         * rectangles and Z-order position and for the input.
 367         */
 368        fmtinfo = vsp1_get_format_info(vsp1, cfg->pixelformat);
 369        if (!fmtinfo) {
 370                dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n",
 371                        cfg->pixelformat);
 372                return -EINVAL;
 373        }
 374
 375        rpf->fmtinfo = fmtinfo;
 376        rpf->format.num_planes = fmtinfo->planes;
 377        rpf->format.plane_fmt[0].bytesperline = cfg->pitch;
 378        rpf->format.plane_fmt[1].bytesperline = cfg->pitch;
 379        rpf->alpha = cfg->alpha;
 380
 381        rpf->mem.addr[0] = cfg->mem[0];
 382        rpf->mem.addr[1] = cfg->mem[1];
 383        rpf->mem.addr[2] = cfg->mem[2];
 384
 385        vsp1->drm->inputs[rpf_index].crop = cfg->src;
 386        vsp1->drm->inputs[rpf_index].compose = cfg->dst;
 387        vsp1->drm->inputs[rpf_index].zpos = cfg->zpos;
 388
 389        drm_pipe->pipe.inputs[rpf_index] = rpf;
 390
 391        return 0;
 392}
 393EXPORT_SYMBOL_GPL(vsp1_du_atomic_update);
 394
 395static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1,
 396                                  struct vsp1_pipeline *pipe,
 397                                  struct vsp1_rwpf *rpf, unsigned int bru_input)
 398{
 399        struct v4l2_subdev_selection sel;
 400        struct v4l2_subdev_format format;
 401        const struct v4l2_rect *crop;
 402        int ret;
 403
 404        /*
 405         * Configure the format on the RPF sink pad and propagate it up to the
 406         * BRU sink pad.
 407         */
 408        crop = &vsp1->drm->inputs[rpf->entity.index].crop;
 409
 410        memset(&format, 0, sizeof(format));
 411        format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 412        format.pad = RWPF_PAD_SINK;
 413        format.format.width = crop->width + crop->left;
 414        format.format.height = crop->height + crop->top;
 415        format.format.code = rpf->fmtinfo->mbus;
 416        format.format.field = V4L2_FIELD_NONE;
 417
 418        ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
 419                               &format);
 420        if (ret < 0)
 421                return ret;
 422
 423        dev_dbg(vsp1->dev,
 424                "%s: set format %ux%u (%x) on RPF%u sink\n",
 425                __func__, format.format.width, format.format.height,
 426                format.format.code, rpf->entity.index);
 427
 428        memset(&sel, 0, sizeof(sel));
 429        sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 430        sel.pad = RWPF_PAD_SINK;
 431        sel.target = V4L2_SEL_TGT_CROP;
 432        sel.r = *crop;
 433
 434        ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_selection, NULL,
 435                               &sel);
 436        if (ret < 0)
 437                return ret;
 438
 439        dev_dbg(vsp1->dev,
 440                "%s: set selection (%u,%u)/%ux%u on RPF%u sink\n",
 441                __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
 442                rpf->entity.index);
 443
 444        /*
 445         * RPF source, hardcode the format to ARGB8888 to turn on format
 446         * conversion if needed.
 447         */
 448        format.pad = RWPF_PAD_SOURCE;
 449
 450        ret = v4l2_subdev_call(&rpf->entity.subdev, pad, get_fmt, NULL,
 451                               &format);
 452        if (ret < 0)
 453                return ret;
 454
 455        dev_dbg(vsp1->dev,
 456                "%s: got format %ux%u (%x) on RPF%u source\n",
 457                __func__, format.format.width, format.format.height,
 458                format.format.code, rpf->entity.index);
 459
 460        format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
 461
 462        ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
 463                               &format);
 464        if (ret < 0)
 465                return ret;
 466
 467        /* BRU sink, propagate the format from the RPF source. */
 468        format.pad = bru_input;
 469
 470        ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_fmt, NULL,
 471                               &format);
 472        if (ret < 0)
 473                return ret;
 474
 475        dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n",
 476                __func__, format.format.width, format.format.height,
 477                format.format.code, BRU_NAME(pipe->bru), format.pad);
 478
 479        sel.pad = bru_input;
 480        sel.target = V4L2_SEL_TGT_COMPOSE;
 481        sel.r = vsp1->drm->inputs[rpf->entity.index].compose;
 482
 483        ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_selection, NULL,
 484                               &sel);
 485        if (ret < 0)
 486                return ret;
 487
 488        dev_dbg(vsp1->dev, "%s: set selection (%u,%u)/%ux%u on %s pad %u\n",
 489                __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
 490                BRU_NAME(pipe->bru), sel.pad);
 491
 492        return 0;
 493}
 494
 495static unsigned int rpf_zpos(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf)
 496{
 497        return vsp1->drm->inputs[rpf->entity.index].zpos;
 498}
 499
 500/**
 501 * vsp1_du_atomic_flush - Commit an atomic update
 502 * @dev: the VSP device
 503 * @pipe_index: the DRM pipeline index
 504 */
 505void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index)
 506{
 507        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 508        struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
 509        struct vsp1_pipeline *pipe = &drm_pipe->pipe;
 510        struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, };
 511        struct vsp1_bru *bru = to_bru(&pipe->bru->subdev);
 512        struct vsp1_entity *entity;
 513        struct vsp1_entity *next;
 514        struct vsp1_dl_list *dl;
 515        unsigned int i;
 516        int ret;
 517
 518        /* Prepare the display list. */
 519        dl = vsp1_dl_list_get(pipe->output->dlm);
 520
 521        /* Count the number of enabled inputs and sort them by Z-order. */
 522        pipe->num_inputs = 0;
 523
 524        for (i = 0; i < vsp1->info->rpf_count; ++i) {
 525                struct vsp1_rwpf *rpf = vsp1->rpf[i];
 526                unsigned int j;
 527
 528                /*
 529                 * Make sure we don't accept more inputs than the hardware can
 530                 * handle. This is a temporary fix to avoid display stall, we
 531                 * need to instead allocate the BRU or BRS to display pipelines
 532                 * dynamically based on the number of planes they each use.
 533                 */
 534                if (pipe->num_inputs >= pipe->bru->source_pad)
 535                        pipe->inputs[i] = NULL;
 536
 537                if (!pipe->inputs[i])
 538                        continue;
 539
 540                /* Insert the RPF in the sorted RPFs array. */
 541                for (j = pipe->num_inputs++; j > 0; --j) {
 542                        if (rpf_zpos(vsp1, inputs[j-1]) <= rpf_zpos(vsp1, rpf))
 543                                break;
 544                        inputs[j] = inputs[j-1];
 545                }
 546
 547                inputs[j] = rpf;
 548        }
 549
 550        /* Setup the RPF input pipeline for every enabled input. */
 551        for (i = 0; i < pipe->bru->source_pad; ++i) {
 552                struct vsp1_rwpf *rpf = inputs[i];
 553
 554                if (!rpf) {
 555                        bru->inputs[i].rpf = NULL;
 556                        continue;
 557                }
 558
 559                if (list_empty(&rpf->entity.list_pipe))
 560                        list_add_tail(&rpf->entity.list_pipe, &pipe->entities);
 561
 562                bru->inputs[i].rpf = rpf;
 563                rpf->bru_input = i;
 564                rpf->entity.sink = pipe->bru;
 565                rpf->entity.sink_pad = i;
 566
 567                dev_dbg(vsp1->dev, "%s: connecting RPF.%u to %s:%u\n",
 568                        __func__, rpf->entity.index, BRU_NAME(pipe->bru), i);
 569
 570                ret = vsp1_du_setup_rpf_pipe(vsp1, pipe, rpf, i);
 571                if (ret < 0)
 572                        dev_err(vsp1->dev,
 573                                "%s: failed to setup RPF.%u\n",
 574                                __func__, rpf->entity.index);
 575        }
 576
 577        /* Configure all entities in the pipeline. */
 578        list_for_each_entry_safe(entity, next, &pipe->entities, list_pipe) {
 579                /* Disconnect unused RPFs from the pipeline. */
 580                if (entity->type == VSP1_ENTITY_RPF &&
 581                    !pipe->inputs[entity->index]) {
 582                        vsp1_dl_list_write(dl, entity->route->reg,
 583                                           VI6_DPR_NODE_UNUSED);
 584
 585                        list_del_init(&entity->list_pipe);
 586
 587                        continue;
 588                }
 589
 590                vsp1_entity_route_setup(entity, pipe, dl);
 591
 592                if (entity->ops->configure) {
 593                        entity->ops->configure(entity, pipe, dl,
 594                                               VSP1_ENTITY_PARAMS_INIT);
 595                        entity->ops->configure(entity, pipe, dl,
 596                                               VSP1_ENTITY_PARAMS_RUNTIME);
 597                        entity->ops->configure(entity, pipe, dl,
 598                                               VSP1_ENTITY_PARAMS_PARTITION);
 599                }
 600        }
 601
 602        vsp1_dl_list_commit(dl);
 603}
 604EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush);
 605
 606int vsp1_du_map_sg(struct device *dev, struct sg_table *sgt)
 607{
 608        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 609
 610        /*
 611         * As all the buffers allocated by the DU driver are coherent, we can
 612         * skip cache sync. This will need to be revisited when support for
 613         * non-coherent buffers will be added to the DU driver.
 614         */
 615        return dma_map_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents,
 616                                DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
 617}
 618EXPORT_SYMBOL_GPL(vsp1_du_map_sg);
 619
 620void vsp1_du_unmap_sg(struct device *dev, struct sg_table *sgt)
 621{
 622        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 623
 624        dma_unmap_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents,
 625                           DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
 626}
 627EXPORT_SYMBOL_GPL(vsp1_du_unmap_sg);
 628
 629/* -----------------------------------------------------------------------------
 630 * Initialization
 631 */
 632
 633int vsp1_drm_init(struct vsp1_device *vsp1)
 634{
 635        unsigned int i;
 636
 637        vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL);
 638        if (!vsp1->drm)
 639                return -ENOMEM;
 640
 641        /* Create one DRM pipeline per LIF. */
 642        for (i = 0; i < vsp1->info->lif_count; ++i) {
 643                struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[i];
 644                struct vsp1_pipeline *pipe = &drm_pipe->pipe;
 645
 646                vsp1_pipeline_init(pipe);
 647
 648                /*
 649                 * The DRM pipeline is static, add entities manually. The first
 650                 * pipeline uses the BRU and the second pipeline the BRS.
 651                 */
 652                pipe->bru = i == 0 ? &vsp1->bru->entity : &vsp1->brs->entity;
 653                pipe->lif = &vsp1->lif[i]->entity;
 654                pipe->output = vsp1->wpf[i];
 655                pipe->output->pipe = pipe;
 656                pipe->frame_end = vsp1_du_pipeline_frame_end;
 657
 658                pipe->bru->sink = &pipe->output->entity;
 659                pipe->bru->sink_pad = 0;
 660                pipe->output->entity.sink = pipe->lif;
 661                pipe->output->entity.sink_pad = 0;
 662
 663                list_add_tail(&pipe->bru->list_pipe, &pipe->entities);
 664                list_add_tail(&pipe->lif->list_pipe, &pipe->entities);
 665                list_add_tail(&pipe->output->entity.list_pipe, &pipe->entities);
 666        }
 667
 668        /* Disable all RPFs initially. */
 669        for (i = 0; i < vsp1->info->rpf_count; ++i) {
 670                struct vsp1_rwpf *input = vsp1->rpf[i];
 671
 672                INIT_LIST_HEAD(&input->entity.list_pipe);
 673        }
 674
 675        return 0;
 676}
 677
 678void vsp1_drm_cleanup(struct vsp1_device *vsp1)
 679{
 680}
 681