linux/drivers/gpu/drm/xilinx/xilinx_drm_plane.c
<<
>>
Prefs
   1/*
   2 * Xilinx DRM plane driver for Xilinx
   3 *
   4 *  Copyright (C) 2013 Xilinx, Inc.
   5 *
   6 *  Author: Hyun Woo Kwon <hyunk@xilinx.com>
   7 *
   8 * This software is licensed under the terms of the GNU General Public
   9 * License version 2, as published by the Free Software Foundation, and
  10 * may be copied, distributed, and modified under those terms.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 */
  17
  18#include <drm/drmP.h>
  19#include <drm/drm_crtc.h>
  20#include <drm/drm_fb_cma_helper.h>
  21#include <drm/drm_gem_cma_helper.h>
  22
  23#include <linux/device.h>
  24#include <linux/dmaengine.h>
  25#include <linux/of_dma.h>
  26#include <linux/platform_device.h>
  27
  28#include "xilinx_drm_dp_sub.h"
  29#include "xilinx_drm_drv.h"
  30#include "xilinx_drm_fb.h"
  31#include "xilinx_drm_plane.h"
  32
  33#include "xilinx_cresample.h"
  34#include "xilinx_osd.h"
  35#include "xilinx_rgb2yuv.h"
  36
  37#define MAX_NUM_SUB_PLANES      4
  38
  39/**
  40 * struct xilinx_drm_plane_dma - Xilinx drm plane VDMA object
  41 *
  42 * @chan: dma channel
  43 * @xt: dma interleaved configuration template
  44 * @sgl: data chunk for dma_interleaved_template
  45 * @is_active: flag if the DMA is active
  46 */
  47struct xilinx_drm_plane_dma {
  48        struct dma_chan *chan;
  49        struct dma_interleaved_template xt;
  50        struct data_chunk sgl[1];
  51        bool is_active;
  52};
  53
  54/**
  55 * struct xilinx_drm_plane - Xilinx drm plane object
  56 *
  57 * @base: base drm plane object
  58 * @id: plane id
  59 * @dpms: current dpms level
  60 * @zpos: user requested z-position value
  61 * @prio: actual layer priority
  62 * @alpha: alpha value
  63 * @alpha_enable: alpha enable value
  64 * @primary: flag for primary plane
  65 * @format: pixel format
  66 * @dma: dma object
  67 * @rgb2yuv: rgb2yuv instance
  68 * @cresample: cresample instance
  69 * @osd_layer: osd layer
  70 * @dp_layer: DisplayPort subsystem layer
  71 * @manager: plane manager
  72 */
  73struct xilinx_drm_plane {
  74        struct drm_plane base;
  75        int id;
  76        int dpms;
  77        unsigned int zpos;
  78        unsigned int prio;
  79        unsigned int alpha;
  80        unsigned int alpha_enable;
  81        bool primary;
  82        uint32_t format;
  83        struct xilinx_drm_plane_dma dma[MAX_NUM_SUB_PLANES];
  84        struct xilinx_rgb2yuv *rgb2yuv;
  85        struct xilinx_cresample *cresample;
  86        struct xilinx_osd_layer *osd_layer;
  87        struct xilinx_drm_dp_sub_layer *dp_layer;
  88        struct xilinx_drm_plane_manager *manager;
  89};
  90
  91#define MAX_PLANES 8
  92
  93/**
  94 * struct xilinx_drm_plane_manager - Xilinx drm plane manager object
  95 *
  96 * @drm: drm device
  97 * @node: plane device node
  98 * @osd: osd instance
  99 * @dp_sub: DisplayPort subsystem instance
 100 * @num_planes: number of available planes
 101 * @format: video format
 102 * @max_width: maximum width
 103 * @zpos_prop: z-position(priority) property
 104 * @alpha_prop: alpha value property
 105 * @alpha_enable_prop: alpha enable property
 106 * @default_alpha: default alpha value
 107 * @planes: xilinx drm planes
 108 */
 109struct xilinx_drm_plane_manager {
 110        struct drm_device *drm;
 111        struct device_node *node;
 112        struct xilinx_osd *osd;
 113        struct xilinx_drm_dp_sub *dp_sub;
 114        int num_planes;
 115        uint32_t format;
 116        int max_width;
 117        struct drm_property *zpos_prop;
 118        struct drm_property *alpha_prop;
 119        struct drm_property *alpha_enable_prop;
 120        unsigned int default_alpha;
 121        struct xilinx_drm_plane *planes[MAX_PLANES];
 122};
 123
 124#define to_xilinx_plane(x)      container_of(x, struct xilinx_drm_plane, base)
 125
 126/* set plane dpms */
 127void xilinx_drm_plane_dpms(struct drm_plane *base_plane, int dpms)
 128{
 129        struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
 130        struct xilinx_drm_plane_manager *manager = plane->manager;
 131        unsigned int i;
 132
 133        DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
 134        DRM_DEBUG_KMS("dpms: %d -> %d\n", plane->dpms, dpms);
 135
 136        if (plane->dpms == dpms)
 137                return;
 138
 139        plane->dpms = dpms;
 140        switch (dpms) {
 141        case DRM_MODE_DPMS_ON:
 142                if (manager->dp_sub) {
 143                        if (plane->primary) {
 144                                xilinx_drm_dp_sub_enable_alpha(manager->dp_sub,
 145                                                plane->alpha_enable);
 146                                xilinx_drm_dp_sub_set_alpha(manager->dp_sub,
 147                                                            plane->alpha);
 148                        }
 149                        xilinx_drm_dp_sub_layer_enable(manager->dp_sub,
 150                                                       plane->dp_layer);
 151                }
 152
 153                /* start dma engine */
 154                for (i = 0; i < MAX_NUM_SUB_PLANES; i++)
 155                        if (plane->dma[i].chan && plane->dma[i].is_active)
 156                                dma_async_issue_pending(plane->dma[i].chan);
 157
 158                if (plane->rgb2yuv)
 159                        xilinx_rgb2yuv_enable(plane->rgb2yuv);
 160
 161                if (plane->cresample)
 162                        xilinx_cresample_enable(plane->cresample);
 163
 164                /* enable osd */
 165                if (manager->osd) {
 166                        xilinx_osd_disable_rue(manager->osd);
 167
 168                        xilinx_osd_layer_set_priority(plane->osd_layer,
 169                                                      plane->prio);
 170                        xilinx_osd_layer_enable_alpha(plane->osd_layer,
 171                                                   plane->alpha_enable);
 172                        xilinx_osd_layer_set_alpha(plane->osd_layer,
 173                                                   plane->alpha);
 174                        xilinx_osd_layer_enable(plane->osd_layer);
 175
 176                        xilinx_osd_enable_rue(manager->osd);
 177                }
 178
 179                break;
 180        default:
 181                /* disable/reset osd */
 182                if (manager->osd) {
 183                        xilinx_osd_disable_rue(manager->osd);
 184
 185                        xilinx_osd_layer_set_dimension(plane->osd_layer,
 186                                                       0, 0, 0, 0);
 187                        xilinx_osd_layer_disable(plane->osd_layer);
 188
 189                        xilinx_osd_enable_rue(manager->osd);
 190                }
 191
 192                if (plane->cresample) {
 193                        xilinx_cresample_disable(plane->cresample);
 194                        xilinx_cresample_reset(plane->cresample);
 195                }
 196
 197                if (plane->rgb2yuv) {
 198                        xilinx_rgb2yuv_disable(plane->rgb2yuv);
 199                        xilinx_rgb2yuv_reset(plane->rgb2yuv);
 200                }
 201
 202                /* stop dma engine and release descriptors */
 203                for (i = 0; i < MAX_NUM_SUB_PLANES; i++) {
 204                        if (plane->dma[i].chan && plane->dma[i].is_active) {
 205                                dmaengine_terminate_all(plane->dma[i].chan);
 206                                plane->dma[i].is_active = false;
 207                        }
 208                }
 209
 210                if (manager->dp_sub)
 211                        xilinx_drm_dp_sub_layer_disable(manager->dp_sub,
 212                                                        plane->dp_layer);
 213
 214                break;
 215        }
 216}
 217
 218/* apply mode to plane pipe */
 219void xilinx_drm_plane_commit(struct drm_plane *base_plane)
 220{
 221        struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
 222        struct dma_async_tx_descriptor *desc;
 223        enum dma_ctrl_flags flags;
 224        unsigned int i;
 225
 226        DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
 227
 228        for (i = 0; i < MAX_NUM_SUB_PLANES; i++) {
 229                struct xilinx_drm_plane_dma *dma = &plane->dma[i];
 230
 231                if (dma->chan && dma->is_active) {
 232                        flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
 233                        desc = dmaengine_prep_interleaved_dma(dma->chan,
 234                                                              &dma->xt,
 235                                                              flags);
 236                        if (!desc) {
 237                                DRM_ERROR("failed to prepare DMA descriptor\n");
 238                                return;
 239                        }
 240
 241                        dmaengine_submit(desc);
 242
 243                        dma_async_issue_pending(dma->chan);
 244                }
 245        }
 246}
 247
 248/* mode set a plane */
 249int xilinx_drm_plane_mode_set(struct drm_plane *base_plane,
 250                              struct drm_framebuffer *fb,
 251                              int crtc_x, int crtc_y,
 252                              unsigned int crtc_w, unsigned int crtc_h,
 253                              uint32_t src_x, uint32_t src_y,
 254                              uint32_t src_w, uint32_t src_h)
 255{
 256        struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
 257        struct drm_gem_cma_object *obj;
 258        size_t offset;
 259        unsigned int hsub, vsub, i;
 260
 261        DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
 262
 263        /* configure cresample */
 264        if (plane->cresample)
 265                xilinx_cresample_configure(plane->cresample, crtc_w, crtc_h);
 266
 267        /* configure rgb2yuv */
 268        if (plane->rgb2yuv)
 269                xilinx_rgb2yuv_configure(plane->rgb2yuv, crtc_w, crtc_h);
 270
 271        DRM_DEBUG_KMS("h: %d(%d), v: %d(%d)\n",
 272                        src_w, crtc_x, src_h, crtc_y);
 273        DRM_DEBUG_KMS("bpp: %d\n", fb->bits_per_pixel / 8);
 274
 275        hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
 276        vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
 277
 278        for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
 279                unsigned int width = src_w / (i ? hsub : 1);
 280                unsigned int height = src_h / (i ? vsub : 1);
 281                unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, i);
 282
 283                if (!cpp)
 284                        cpp = xilinx_drm_format_bpp(fb->pixel_format) >> 3;
 285
 286                obj = xilinx_drm_fb_get_gem_obj(fb, i);
 287                if (!obj) {
 288                        DRM_ERROR("failed to get a gem obj for fb\n");
 289                        return -EINVAL;
 290                }
 291
 292                plane->dma[i].xt.numf = height;
 293                plane->dma[i].sgl[0].size = width * cpp;
 294                plane->dma[i].sgl[0].icg = fb->pitches[i] -
 295                                           plane->dma[i].sgl[0].size;
 296                offset = src_x * cpp + src_y * fb->pitches[i];
 297                offset += fb->offsets[i];
 298                plane->dma[i].xt.src_start = obj->paddr + offset;
 299                plane->dma[i].xt.frame_size = 1;
 300                plane->dma[i].xt.dir = DMA_MEM_TO_DEV;
 301                plane->dma[i].xt.src_sgl = true;
 302                plane->dma[i].xt.dst_sgl = false;
 303                plane->dma[i].is_active = true;
 304        }
 305
 306        for (; i < MAX_NUM_SUB_PLANES; i++)
 307                plane->dma[i].is_active = false;
 308
 309        /* set OSD dimensions */
 310        if (plane->manager->osd) {
 311                xilinx_osd_disable_rue(plane->manager->osd);
 312
 313                xilinx_osd_layer_set_dimension(plane->osd_layer, crtc_x, crtc_y,
 314                                               src_w, src_h);
 315
 316                xilinx_osd_enable_rue(plane->manager->osd);
 317        }
 318
 319        if (plane->manager->dp_sub) {
 320                int ret;
 321
 322                ret = xilinx_drm_dp_sub_layer_check_size(plane->manager->dp_sub,
 323                                                         plane->dp_layer,
 324                                                         src_w, src_h);
 325                if (ret)
 326                        return ret;
 327
 328                ret = xilinx_drm_dp_sub_layer_set_fmt(plane->manager->dp_sub,
 329                                                      plane->dp_layer,
 330                                                      fb->pixel_format);
 331                if (ret) {
 332                        DRM_ERROR("failed to set dp_sub layer fmt\n");
 333                        return ret;
 334                }
 335        }
 336
 337        return 0;
 338}
 339
 340/* update a plane. just call mode_set() with bit-shifted values */
 341static int xilinx_drm_plane_update(struct drm_plane *base_plane,
 342                                   struct drm_crtc *crtc,
 343                                   struct drm_framebuffer *fb,
 344                                   int crtc_x, int crtc_y,
 345                                   unsigned int crtc_w, unsigned int crtc_h,
 346                                   uint32_t src_x, uint32_t src_y,
 347                                   uint32_t src_w, uint32_t src_h)
 348{
 349        int ret;
 350
 351        ret = xilinx_drm_plane_mode_set(base_plane, fb,
 352                                        crtc_x, crtc_y, crtc_w, crtc_h,
 353                                        src_x >> 16, src_y >> 16,
 354                                        src_w >> 16, src_h >> 16);
 355        if (ret) {
 356                DRM_ERROR("failed to mode-set a plane\n");
 357                return ret;
 358        }
 359
 360        /* make sure a plane is on */
 361        xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_ON);
 362        /* apply the new fb addr */
 363        xilinx_drm_plane_commit(base_plane);
 364
 365        return 0;
 366}
 367
 368/* disable a plane */
 369static int xilinx_drm_plane_disable(struct drm_plane *base_plane)
 370{
 371        xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_OFF);
 372
 373        return 0;
 374}
 375
 376/* destroy a plane */
 377static void xilinx_drm_plane_destroy(struct drm_plane *base_plane)
 378{
 379        struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
 380        unsigned int i;
 381
 382        xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_OFF);
 383
 384        plane->manager->planes[plane->id] = NULL;
 385
 386        drm_plane_cleanup(base_plane);
 387
 388        for (i = 0; i < MAX_NUM_SUB_PLANES; i++)
 389                if (plane->dma[i].chan)
 390                        dma_release_channel(plane->dma[i].chan);
 391
 392        if (plane->manager->osd) {
 393                xilinx_osd_layer_disable(plane->osd_layer);
 394                xilinx_osd_layer_put(plane->osd_layer);
 395        }
 396
 397        if (plane->manager->dp_sub) {
 398                xilinx_drm_dp_sub_layer_disable(plane->manager->dp_sub,
 399                                                plane->dp_layer);
 400                xilinx_drm_dp_sub_layer_put(plane->manager->dp_sub,
 401                                            plane->dp_layer);
 402        }
 403}
 404
 405/**
 406 * xilinx_drm_plane_update_prio - Configure plane priorities based on zpos
 407 * @manager: the plane manager
 408 *
 409 * Z-position values are user requested position of planes. The priority is
 410 * the actual position of planes in hardware. Some hardware doesn't allow
 411 * any duplicate priority, so this function needs to be called when a duplicate
 412 * priority is found. Then planes are sorted by zpos value, and the priorities
 413 * are reconfigured. A plane with lower plane ID gets assigned to the lower
 414 * priority when planes have the same zpos value.
 415 */
 416static void
 417xilinx_drm_plane_update_prio(struct xilinx_drm_plane_manager *manager)
 418{
 419        struct xilinx_drm_plane *planes[MAX_PLANES];
 420        struct xilinx_drm_plane *plane;
 421        unsigned int i, j;
 422
 423        /* sort planes by zpos */
 424        for (i = 0; i < manager->num_planes; i++) {
 425                plane = manager->planes[i];
 426
 427                for (j = i; j > 0; --j) {
 428                        if (planes[j - 1]->zpos <= plane->zpos)
 429                                break;
 430                        planes[j] = planes[j - 1];
 431                }
 432
 433                planes[j] = plane;
 434        }
 435
 436        xilinx_osd_disable_rue(manager->osd);
 437
 438        /* remove duplicates by reassigning priority */
 439        for (i = 0; i < manager->num_planes; i++) {
 440                planes[i]->prio = i;
 441                xilinx_osd_layer_set_priority(planes[i]->osd_layer,
 442                                              planes[i]->prio);
 443        }
 444
 445        xilinx_osd_enable_rue(manager->osd);
 446}
 447
 448static void xilinx_drm_plane_set_zpos(struct drm_plane *base_plane,
 449                                      unsigned int zpos)
 450{
 451        struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
 452        struct xilinx_drm_plane_manager *manager = plane->manager;
 453        bool update = false;
 454        int i;
 455
 456        if (plane->zpos == zpos)
 457                return;
 458
 459        for (i = 0; i < manager->num_planes; i++) {
 460                if (manager->planes[i] != plane &&
 461                    manager->planes[i]->prio == zpos) {
 462                        update = true;
 463                        break;
 464                }
 465        }
 466
 467        plane->zpos = zpos;
 468
 469        if (update) {
 470                xilinx_drm_plane_update_prio(manager);
 471        } else {
 472                plane->prio = zpos;
 473                xilinx_osd_layer_set_priority(plane->osd_layer, plane->prio);
 474        }
 475}
 476
 477static void xilinx_drm_plane_set_alpha(struct drm_plane *base_plane,
 478                                       unsigned int alpha)
 479{
 480        struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
 481        struct xilinx_drm_plane_manager *manager = plane->manager;
 482
 483        if (plane->alpha == alpha)
 484                return;
 485
 486        plane->alpha = alpha;
 487
 488        if (plane->osd_layer)
 489                xilinx_osd_layer_set_alpha(plane->osd_layer, plane->alpha);
 490        else if (manager->dp_sub)
 491                xilinx_drm_dp_sub_set_alpha(manager->dp_sub, plane->alpha);
 492}
 493
 494static void xilinx_drm_plane_enable_alpha(struct drm_plane *base_plane,
 495                                          bool enable)
 496{
 497        struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
 498        struct xilinx_drm_plane_manager *manager = plane->manager;
 499
 500        if (plane->alpha_enable == enable)
 501                return;
 502
 503        plane->alpha_enable = enable;
 504
 505        if (plane->osd_layer)
 506                xilinx_osd_layer_enable_alpha(plane->osd_layer, enable);
 507        else if (manager->dp_sub)
 508                xilinx_drm_dp_sub_enable_alpha(manager->dp_sub, enable);
 509}
 510
 511/* set property of a plane */
 512static int xilinx_drm_plane_set_property(struct drm_plane *base_plane,
 513                                         struct drm_property *property,
 514                                         uint64_t val)
 515{
 516        struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
 517        struct xilinx_drm_plane_manager *manager = plane->manager;
 518
 519        if (property == manager->zpos_prop)
 520                xilinx_drm_plane_set_zpos(base_plane, val);
 521        else if (property == manager->alpha_prop)
 522                xilinx_drm_plane_set_alpha(base_plane, val);
 523        else if (property == manager->alpha_enable_prop)
 524                xilinx_drm_plane_enable_alpha(base_plane, val);
 525        else
 526                return -EINVAL;
 527
 528        drm_object_property_set_value(&base_plane->base, property, val);
 529
 530        return 0;
 531}
 532
 533static struct drm_plane_funcs xilinx_drm_plane_funcs = {
 534        .update_plane   = xilinx_drm_plane_update,
 535        .disable_plane  = xilinx_drm_plane_disable,
 536        .destroy        = xilinx_drm_plane_destroy,
 537        .set_property   = xilinx_drm_plane_set_property,
 538};
 539
 540/* get a plane max width */
 541int xilinx_drm_plane_get_max_width(struct drm_plane *base_plane)
 542{
 543        struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
 544
 545        return plane->manager->max_width;
 546}
 547
 548/* check if format is supported */
 549bool xilinx_drm_plane_check_format(struct xilinx_drm_plane_manager *manager,
 550                                   uint32_t format)
 551{
 552        int i;
 553
 554        for (i = 0; i < MAX_PLANES; i++)
 555                if (manager->planes[i] &&
 556                    (manager->planes[i]->format == format))
 557                        return true;
 558
 559        return false;
 560}
 561
 562/* get the number of planes */
 563int xilinx_drm_plane_get_num_planes(struct xilinx_drm_plane_manager *manager)
 564{
 565        return manager->num_planes;
 566}
 567
 568/**
 569 * xilinx_drm_plane_restore - Restore the plane states
 570 * @manager: the plane manager
 571 *
 572 * Restore the plane states to the default ones. Any state that needs to be
 573 * restored should be here. This improves consistency as applications see
 574 * the same default values, and removes mismatch between software and hardware
 575 * values as software values are updated as hardware values are reset.
 576 */
 577void xilinx_drm_plane_restore(struct xilinx_drm_plane_manager *manager)
 578{
 579        struct xilinx_drm_plane *plane;
 580        unsigned int i;
 581
 582        /*
 583         * Reinitialize property default values as they get reset by DPMS OFF
 584         * operation. User will read the correct default values later, and
 585         * planes will be initialized with default values.
 586         */
 587        for (i = 0; i < manager->num_planes; i++) {
 588                plane = manager->planes[i];
 589
 590                plane->prio = plane->zpos = plane->id;
 591                if (manager->zpos_prop)
 592                        drm_object_property_set_value(&plane->base.base,
 593                                                      manager->zpos_prop,
 594                                                      plane->prio);
 595
 596                plane->alpha = manager->default_alpha;
 597                if (manager->alpha_prop)
 598                        drm_object_property_set_value(&plane->base.base,
 599                                                      manager->alpha_prop,
 600                                                      plane->alpha);
 601
 602                plane->alpha_enable = true;
 603                if (manager->alpha_enable_prop)
 604                        drm_object_property_set_value(&plane->base.base,
 605                                        manager->alpha_enable_prop, true);
 606        }
 607}
 608
 609/* get the plane format */
 610uint32_t xilinx_drm_plane_get_format(struct drm_plane *base_plane)
 611{
 612        struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
 613        return plane->format;
 614}
 615
 616/**
 617 * xilinx_drm_plane_get_align - Get the alignment value for pitch
 618 * @base_plane: Base drm plane object
 619 *
 620 * Get the alignment value for pitch from the dma device
 621 *
 622 * Return: The alignment value if successful, or the error code.
 623 */
 624unsigned int xilinx_drm_plane_get_align(struct drm_plane *base_plane)
 625{
 626        struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
 627
 628        return 1 << plane->dma[0].chan->device->copy_align;
 629}
 630
 631/* create plane properties */
 632static void
 633xilinx_drm_plane_create_property(struct xilinx_drm_plane_manager *manager)
 634{
 635        if (manager->osd)
 636                manager->zpos_prop = drm_property_create_range(manager->drm, 0,
 637                                "zpos", 0, manager->num_planes - 1);
 638
 639        if (manager->osd || manager->dp_sub) {
 640                manager->alpha_prop = drm_property_create_range(manager->drm, 0,
 641                                "alpha", 0, manager->default_alpha);
 642                manager->alpha_enable_prop =
 643                        drm_property_create_bool(manager->drm, 0,
 644                                                 "global alpha enable");
 645        }
 646}
 647
 648/* attach plane properties */
 649static void xilinx_drm_plane_attach_property(struct drm_plane *base_plane)
 650{
 651        struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
 652        struct xilinx_drm_plane_manager *manager = plane->manager;
 653
 654        if (manager->zpos_prop)
 655                drm_object_attach_property(&base_plane->base,
 656                                           manager->zpos_prop,
 657                                           plane->id);
 658
 659        if (manager->alpha_prop) {
 660                if (manager->dp_sub && !plane->primary)
 661                        return;
 662
 663                drm_object_attach_property(&base_plane->base,
 664                                           manager->alpha_prop,
 665                                           manager->default_alpha);
 666                drm_object_attach_property(&base_plane->base,
 667                                           manager->alpha_enable_prop, false);
 668        }
 669
 670        plane->alpha_enable = true;
 671}
 672
 673/**
 674 * xilinx_drm_plane_manager_dpms - Set DPMS for the Xilinx plane manager
 675 * @manager: Xilinx plane manager object
 676 * @dpms: requested DPMS
 677 *
 678 * Set the Xilinx plane manager to the given DPMS state. This function is
 679 * usually called from the CRTC driver with calling xilinx_drm_plane_dpms().
 680 */
 681void xilinx_drm_plane_manager_dpms(struct xilinx_drm_plane_manager *manager,
 682                                   int dpms)
 683{
 684        switch (dpms) {
 685        case DRM_MODE_DPMS_ON:
 686                if (manager->dp_sub) {
 687                        xilinx_drm_dp_sub_set_bg_color(manager->dp_sub,
 688                                                       0, 0, 0);
 689                        xilinx_drm_dp_sub_enable(manager->dp_sub);
 690                }
 691
 692                if (manager->osd) {
 693                        xilinx_osd_disable_rue(manager->osd);
 694                        xilinx_osd_enable(manager->osd);
 695                        xilinx_osd_enable_rue(manager->osd);
 696                }
 697
 698                break;
 699        default:
 700                if (manager->osd)
 701                        xilinx_osd_reset(manager->osd);
 702
 703                if (manager->dp_sub)
 704                        xilinx_drm_dp_sub_disable(manager->dp_sub);
 705
 706                break;
 707        }
 708}
 709
 710/**
 711 * xilinx_drm_plane_manager_mode_set - Set the mode to the Xilinx plane manager
 712 * @manager: Xilinx plane manager object
 713 * @crtc_w: CRTC width
 714 * @crtc_h: CRTC height
 715 *
 716 * Set the width and height of the Xilinx plane manager. This function is uaully
 717 * called from the CRTC driver before calling the xilinx_drm_plane_mode_set().
 718 */
 719void xilinx_drm_plane_manager_mode_set(struct xilinx_drm_plane_manager *manager,
 720                                      unsigned int crtc_w, unsigned int crtc_h)
 721{
 722        if (manager->osd)
 723                xilinx_osd_set_dimension(manager->osd, crtc_w, crtc_h);
 724}
 725
 726/* create a plane */
 727static struct xilinx_drm_plane *
 728xilinx_drm_plane_create(struct xilinx_drm_plane_manager *manager,
 729                        unsigned int possible_crtcs, bool primary)
 730{
 731        struct xilinx_drm_plane *plane;
 732        struct device *dev = manager->drm->dev;
 733        char name[16];
 734        struct device_node *plane_node;
 735        struct device_node *sub_node;
 736        enum drm_plane_type type;
 737        uint32_t fmt_in = -1;
 738        uint32_t fmt_out = -1;
 739        const char *fmt;
 740        int i;
 741        int ret;
 742        uint32_t *fmts = NULL;
 743        unsigned int num_fmts = 0;
 744
 745        for (i = 0; i < manager->num_planes; i++)
 746                if (!manager->planes[i])
 747                        break;
 748
 749        if (i >= manager->num_planes) {
 750                DRM_ERROR("failed to allocate plane\n");
 751                return ERR_PTR(-ENODEV);
 752        }
 753
 754        snprintf(name, sizeof(name), "plane%d", i);
 755        plane_node = of_get_child_by_name(manager->node, name);
 756        if (!plane_node) {
 757                DRM_ERROR("failed to find a plane node\n");
 758                return ERR_PTR(-ENODEV);
 759        }
 760
 761        plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL);
 762        if (!plane) {
 763                ret = -ENOMEM;
 764                goto err_out;
 765        }
 766
 767        plane->primary = primary;
 768        plane->id = i;
 769        plane->prio = i;
 770        plane->zpos = i;
 771        plane->alpha = manager->default_alpha;
 772        plane->dpms = DRM_MODE_DPMS_OFF;
 773        plane->format = -1;
 774        DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
 775
 776        for (i = 0; i < MAX_NUM_SUB_PLANES; i++) {
 777                snprintf(name, sizeof(name), "dma%d", i);
 778                plane->dma[i].chan = of_dma_request_slave_channel(plane_node,
 779                                                                  name);
 780                if (PTR_ERR(plane->dma[i].chan) == -ENODEV) {
 781                        plane->dma[i].chan = NULL;
 782                        continue;
 783                }
 784
 785                if (IS_ERR(plane->dma[i].chan)) {
 786                        DRM_ERROR("failed to request dma channel\n");
 787                        ret = PTR_ERR(plane->dma[i].chan);
 788                        plane->dma[i].chan = NULL;
 789                        goto err_dma;
 790                }
 791        }
 792
 793        /* probe color space converter */
 794        sub_node = of_parse_phandle(plane_node, "xlnx,rgb2yuv", i);
 795        if (sub_node) {
 796                plane->rgb2yuv = xilinx_rgb2yuv_probe(dev, sub_node);
 797                of_node_put(sub_node);
 798                if (IS_ERR(plane->rgb2yuv)) {
 799                        DRM_ERROR("failed to probe a rgb2yuv\n");
 800                        ret = PTR_ERR(plane->rgb2yuv);
 801                        goto err_dma;
 802                }
 803
 804                /* rgb2yuv input format */
 805                plane->format = DRM_FORMAT_XRGB8888;
 806
 807                /* rgb2yuv output format */
 808                fmt_out = DRM_FORMAT_YUV444;
 809        }
 810
 811        /* probe chroma resampler */
 812        sub_node = of_parse_phandle(plane_node, "xlnx,cresample", i);
 813        if (sub_node) {
 814                plane->cresample = xilinx_cresample_probe(dev, sub_node);
 815                of_node_put(sub_node);
 816                if (IS_ERR(plane->cresample)) {
 817                        DRM_ERROR("failed to probe a cresample\n");
 818                        ret = PTR_ERR(plane->cresample);
 819                        goto err_dma;
 820                }
 821
 822                /* cresample input format */
 823                fmt = xilinx_cresample_get_input_format_name(plane->cresample);
 824                ret = xilinx_drm_format_by_name(fmt, &fmt_in);
 825                if (ret)
 826                        goto err_dma;
 827
 828                /* format sanity check */
 829                if ((fmt_out != -1) && (fmt_out != fmt_in)) {
 830                        DRM_ERROR("input/output format mismatch\n");
 831                        ret = -EINVAL;
 832                        goto err_dma;
 833                }
 834
 835                if (plane->format == -1)
 836                        plane->format = fmt_in;
 837
 838                /* cresample output format */
 839                fmt = xilinx_cresample_get_output_format_name(plane->cresample);
 840                ret = xilinx_drm_format_by_name(fmt, &fmt_out);
 841                if (ret)
 842                        goto err_dma;
 843        }
 844
 845        /* create an OSD layer when OSD is available */
 846        if (manager->osd) {
 847                /* format sanity check */
 848                if ((fmt_out != -1) && (fmt_out != manager->format)) {
 849                        DRM_ERROR("input/output format mismatch\n");
 850                        ret = -EINVAL;
 851                        goto err_dma;
 852                }
 853
 854                /* create an osd layer */
 855                plane->osd_layer = xilinx_osd_layer_get(manager->osd);
 856                if (IS_ERR(plane->osd_layer)) {
 857                        DRM_ERROR("failed to create a osd layer\n");
 858                        ret = PTR_ERR(plane->osd_layer);
 859                        plane->osd_layer = NULL;
 860                        goto err_dma;
 861                }
 862
 863                if (plane->format == -1)
 864                        plane->format = manager->format;
 865        }
 866
 867        if (manager->dp_sub) {
 868                plane->dp_layer = xilinx_drm_dp_sub_layer_get(manager->dp_sub,
 869                                                              primary);
 870                if (IS_ERR(plane->dp_layer)) {
 871                        DRM_ERROR("failed to create a dp_sub layer\n");
 872                        ret = PTR_ERR(plane->dp_layer);
 873                        plane->dp_layer = NULL;
 874                        goto err_dma;
 875                }
 876
 877                if (primary) {
 878                        ret = xilinx_drm_dp_sub_layer_set_fmt(manager->dp_sub,
 879                                                              plane->dp_layer,
 880                                                              manager->format);
 881                        if (ret) {
 882                                DRM_ERROR("failed to set dp_sub layer fmt\n");
 883                                goto err_dma;
 884                        }
 885                }
 886
 887                plane->format =
 888                        xilinx_drm_dp_sub_layer_get_fmt(manager->dp_sub,
 889                                                        plane->dp_layer);
 890                xilinx_drm_dp_sub_layer_get_fmts(manager->dp_sub,
 891                                                 plane->dp_layer, &fmts,
 892                                                 &num_fmts);
 893        }
 894
 895        /* If there's no IP other than VDMA, pick the manager's format */
 896        if (plane->format == -1)
 897                plane->format = manager->format;
 898
 899        /* initialize drm plane */
 900        type = primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
 901        ret = drm_universal_plane_init(manager->drm, &plane->base,
 902                                       possible_crtcs, &xilinx_drm_plane_funcs,
 903                                       fmts ? fmts : &plane->format,
 904                                       num_fmts ? num_fmts : 1, type, NULL);
 905        if (ret) {
 906                DRM_ERROR("failed to initialize plane\n");
 907                goto err_init;
 908        }
 909        plane->manager = manager;
 910        manager->planes[plane->id] = plane;
 911
 912        xilinx_drm_plane_attach_property(&plane->base);
 913
 914        of_node_put(plane_node);
 915
 916        return plane;
 917
 918err_init:
 919        if (manager->dp_sub) {
 920                xilinx_drm_dp_sub_layer_disable(manager->dp_sub,
 921                                                plane->dp_layer);
 922                xilinx_drm_dp_sub_layer_put(plane->manager->dp_sub,
 923                                            plane->dp_layer);
 924        }
 925        if (manager->osd) {
 926                xilinx_osd_layer_disable(plane->osd_layer);
 927                xilinx_osd_layer_put(plane->osd_layer);
 928        }
 929err_dma:
 930        for (i = 0; i < MAX_NUM_SUB_PLANES; i++)
 931                if (plane->dma[i].chan)
 932                        dma_release_channel(plane->dma[i].chan);
 933err_out:
 934        of_node_put(plane_node);
 935        return ERR_PTR(ret);
 936}
 937
 938/* create a primary plane */
 939struct drm_plane *
 940xilinx_drm_plane_create_primary(struct xilinx_drm_plane_manager *manager,
 941                                unsigned int possible_crtcs)
 942{
 943        struct xilinx_drm_plane *plane;
 944
 945        plane = xilinx_drm_plane_create(manager, possible_crtcs, true);
 946        if (IS_ERR(plane)) {
 947                DRM_ERROR("failed to allocate a primary plane\n");
 948                return ERR_CAST(plane);
 949        }
 950
 951        return &plane->base;
 952}
 953
 954/* create extra planes */
 955int xilinx_drm_plane_create_planes(struct xilinx_drm_plane_manager *manager,
 956                                   unsigned int possible_crtcs)
 957{
 958        struct xilinx_drm_plane *plane;
 959        int i;
 960
 961        /* find if there any available plane, and create if available */
 962        for (i = 0; i < manager->num_planes; i++) {
 963                if (manager->planes[i])
 964                        continue;
 965
 966                plane = xilinx_drm_plane_create(manager, possible_crtcs, false);
 967                if (IS_ERR(plane)) {
 968                        DRM_ERROR("failed to allocate a plane\n");
 969                        return PTR_ERR(plane);
 970                }
 971
 972                manager->planes[i] = plane;
 973        }
 974
 975        return 0;
 976}
 977
 978/* initialize a plane manager: num_planes, format, max_width */
 979static int
 980xilinx_drm_plane_init_manager(struct xilinx_drm_plane_manager *manager)
 981{
 982        unsigned int format;
 983        uint32_t drm_format;
 984        int ret = 0;
 985
 986        if (manager->osd) {
 987                manager->num_planes = xilinx_osd_get_num_layers(manager->osd);
 988                manager->max_width = xilinx_osd_get_max_width(manager->osd);
 989
 990                format = xilinx_osd_get_format(manager->osd);
 991                ret = xilinx_drm_format_by_code(format, &drm_format);
 992                if (drm_format != manager->format)
 993                        ret = -EINVAL;
 994        } else if (manager->dp_sub) {
 995                manager->num_planes = XILINX_DRM_DP_SUB_NUM_LAYERS;
 996                manager->max_width = XILINX_DRM_DP_SUB_MAX_WIDTH;
 997        } else {
 998                /* without osd, only one plane is supported */
 999                manager->num_planes = 1;
1000                manager->max_width = 4096;
1001        }
1002
1003        return ret;
1004}
1005
1006struct xilinx_drm_plane_manager *
1007xilinx_drm_plane_probe_manager(struct drm_device *drm)
1008{
1009        struct xilinx_drm_plane_manager *manager;
1010        struct device *dev = drm->dev;
1011        struct device_node *sub_node;
1012        const char *format;
1013        int ret;
1014
1015        manager = devm_kzalloc(dev, sizeof(*manager), GFP_KERNEL);
1016        if (!manager)
1017                return ERR_PTR(-ENOMEM);
1018
1019        /* this node is used to create a plane */
1020        manager->node = of_get_child_by_name(dev->of_node, "planes");
1021        if (!manager->node) {
1022                DRM_ERROR("failed to get a planes node\n");
1023                return ERR_PTR(-EINVAL);
1024        }
1025
1026        /* check the base pixel format of plane manager */
1027        ret = of_property_read_string(manager->node, "xlnx,pixel-format",
1028                                      &format);
1029        if (ret < 0) {
1030                DRM_ERROR("failed to get a plane manager format\n");
1031                return ERR_PTR(ret);
1032        }
1033
1034        ret = xilinx_drm_format_by_name(format, &manager->format);
1035        if (ret < 0) {
1036                DRM_ERROR("invalid plane manager format\n");
1037                return ERR_PTR(ret);
1038        }
1039
1040        manager->drm = drm;
1041
1042        /* probe an OSD. proceed even if there's no OSD */
1043        sub_node = of_parse_phandle(dev->of_node, "xlnx,osd", 0);
1044        if (sub_node) {
1045                manager->osd = xilinx_osd_probe(dev, sub_node);
1046                of_node_put(sub_node);
1047                if (IS_ERR(manager->osd)) {
1048                        of_node_put(manager->node);
1049                        DRM_ERROR("failed to probe an osd\n");
1050                        return ERR_CAST(manager->osd);
1051                }
1052                manager->default_alpha = OSD_MAX_ALPHA;
1053        }
1054
1055        manager->dp_sub = xilinx_drm_dp_sub_of_get(drm->dev->of_node);
1056        if (IS_ERR(manager->dp_sub)) {
1057                DRM_DEBUG_KMS("failed to get a dp_sub\n");
1058                return ERR_CAST(manager->dp_sub);
1059        } else if (manager->dp_sub != NULL) {
1060                manager->default_alpha = XILINX_DRM_DP_SUB_MAX_ALPHA;
1061        }
1062
1063        ret = xilinx_drm_plane_init_manager(manager);
1064        if (ret) {
1065                DRM_ERROR("failed to init a plane manager\n");
1066                return ERR_PTR(ret);
1067        }
1068
1069        xilinx_drm_plane_create_property(manager);
1070
1071        return manager;
1072}
1073
1074void xilinx_drm_plane_remove_manager(struct xilinx_drm_plane_manager *manager)
1075{
1076        xilinx_drm_dp_sub_put(manager->dp_sub);
1077        of_node_put(manager->node);
1078}
1079