linux/drivers/gpu/drm/xilinx/xilinx_drm_crtc.c
<<
>>
Prefs
   1/*
   2 * Xilinx DRM crtc 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_crtc_helper.h>
  21#include <drm/drm_fb_cma_helper.h>
  22#include <drm/drm_gem_cma_helper.h>
  23
  24#include <linux/clk.h>
  25#include <linux/delay.h>
  26#include <linux/device.h>
  27#include <linux/i2c.h>
  28
  29#include <video/videomode.h>
  30
  31#include "xilinx_drm_crtc.h"
  32#include "xilinx_drm_dp_sub.h"
  33#include "xilinx_drm_drv.h"
  34#include "xilinx_drm_plane.h"
  35
  36#include "xilinx_cresample.h"
  37#include "xilinx_rgb2yuv.h"
  38#include "xilinx_vtc.h"
  39
  40struct xilinx_drm_crtc {
  41        struct drm_crtc base;
  42        struct xilinx_cresample *cresample;
  43        struct xilinx_rgb2yuv *rgb2yuv;
  44        struct clk *pixel_clock;
  45        bool pixel_clock_enabled;
  46        struct xilinx_vtc *vtc;
  47        struct xilinx_drm_plane_manager *plane_manager;
  48        int dpms;
  49        unsigned int alpha;
  50        struct drm_pending_vblank_event *event;
  51        struct xilinx_drm_dp_sub *dp_sub;
  52};
  53
  54#define to_xilinx_crtc(x)       container_of(x, struct xilinx_drm_crtc, base)
  55
  56/* set crtc dpms */
  57static void xilinx_drm_crtc_dpms(struct drm_crtc *base_crtc, int dpms)
  58{
  59        struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
  60        int ret;
  61
  62        DRM_DEBUG_KMS("dpms: %d -> %d\n", crtc->dpms, dpms);
  63
  64        if (crtc->dpms == dpms)
  65                return;
  66
  67        crtc->dpms = dpms;
  68
  69        switch (dpms) {
  70        case DRM_MODE_DPMS_ON:
  71                if (!crtc->pixel_clock_enabled) {
  72                        ret = clk_prepare_enable(crtc->pixel_clock);
  73                        if (ret) {
  74                                DRM_ERROR("failed to enable a pixel clock\n");
  75                                crtc->pixel_clock_enabled = false;
  76                        }
  77                }
  78                crtc->pixel_clock_enabled = true;
  79
  80                xilinx_drm_plane_manager_dpms(crtc->plane_manager, dpms);
  81                xilinx_drm_plane_dpms(base_crtc->primary, dpms);
  82                if (crtc->rgb2yuv)
  83                        xilinx_rgb2yuv_enable(crtc->rgb2yuv);
  84                if (crtc->cresample)
  85                        xilinx_cresample_enable(crtc->cresample);
  86                if (crtc->vtc)
  87                        xilinx_vtc_enable(crtc->vtc);
  88                break;
  89        default:
  90                if (crtc->vtc) {
  91                        xilinx_vtc_disable(crtc->vtc);
  92                        xilinx_vtc_reset(crtc->vtc);
  93                }
  94                if (crtc->cresample) {
  95                        xilinx_cresample_disable(crtc->cresample);
  96                        xilinx_cresample_reset(crtc->cresample);
  97                }
  98                if (crtc->rgb2yuv) {
  99                        xilinx_rgb2yuv_disable(crtc->rgb2yuv);
 100                        xilinx_rgb2yuv_reset(crtc->rgb2yuv);
 101                }
 102                xilinx_drm_plane_dpms(base_crtc->primary, dpms);
 103                xilinx_drm_plane_manager_dpms(crtc->plane_manager, dpms);
 104                if (crtc->pixel_clock_enabled) {
 105                        clk_disable_unprepare(crtc->pixel_clock);
 106                        crtc->pixel_clock_enabled = false;
 107                }
 108                break;
 109        }
 110}
 111
 112/* prepare crtc */
 113static void xilinx_drm_crtc_prepare(struct drm_crtc *base_crtc)
 114{
 115        xilinx_drm_crtc_dpms(base_crtc, DRM_MODE_DPMS_OFF);
 116}
 117
 118/* apply mode to crtc pipe */
 119static void xilinx_drm_crtc_commit(struct drm_crtc *base_crtc)
 120{
 121        xilinx_drm_crtc_dpms(base_crtc, DRM_MODE_DPMS_ON);
 122        xilinx_drm_plane_commit(base_crtc->primary);
 123}
 124
 125/* fix mode */
 126static bool xilinx_drm_crtc_mode_fixup(struct drm_crtc *base_crtc,
 127                                       const struct drm_display_mode *mode,
 128                                       struct drm_display_mode *adjusted_mode)
 129{
 130        /* no op */
 131        return true;
 132}
 133
 134/* set new mode in crtc pipe */
 135static int xilinx_drm_crtc_mode_set(struct drm_crtc *base_crtc,
 136                                    struct drm_display_mode *mode,
 137                                    struct drm_display_mode *adjusted_mode,
 138                                    int x, int y,
 139                                    struct drm_framebuffer *old_fb)
 140{
 141        struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
 142        struct videomode vm;
 143        long diff;
 144        int ret;
 145
 146        if (crtc->pixel_clock_enabled) {
 147                clk_disable_unprepare(crtc->pixel_clock);
 148                crtc->pixel_clock_enabled = false;
 149        }
 150
 151        /* set pixel clock */
 152        ret = clk_set_rate(crtc->pixel_clock, adjusted_mode->clock * 1000);
 153        if (ret) {
 154                DRM_ERROR("failed to set a pixel clock\n");
 155                return ret;
 156        }
 157
 158        diff = clk_get_rate(crtc->pixel_clock) - adjusted_mode->clock * 1000;
 159        if (abs(diff) > (adjusted_mode->clock * 1000) / 20)
 160                DRM_DEBUG_KMS("actual pixel clock rate(%d) is off by %ld\n",
 161                                adjusted_mode->clock, diff);
 162
 163        if (crtc->vtc) {
 164                /* set video timing */
 165                vm.hactive = adjusted_mode->hdisplay;
 166                vm.hfront_porch = adjusted_mode->hsync_start -
 167                                  adjusted_mode->hdisplay;
 168                vm.hback_porch = adjusted_mode->htotal -
 169                                 adjusted_mode->hsync_end;
 170                vm.hsync_len = adjusted_mode->hsync_end -
 171                               adjusted_mode->hsync_start;
 172
 173                vm.vactive = adjusted_mode->vdisplay;
 174                vm.vfront_porch = adjusted_mode->vsync_start -
 175                                  adjusted_mode->vdisplay;
 176                vm.vback_porch = adjusted_mode->vtotal -
 177                                 adjusted_mode->vsync_end;
 178                vm.vsync_len = adjusted_mode->vsync_end -
 179                               adjusted_mode->vsync_start;
 180
 181                xilinx_vtc_config_sig(crtc->vtc, &vm);
 182        }
 183
 184        /* configure cresample and rgb2yuv */
 185        if (crtc->cresample)
 186                xilinx_cresample_configure(crtc->cresample,
 187                                           adjusted_mode->hdisplay,
 188                                           adjusted_mode->vdisplay);
 189        if (crtc->rgb2yuv)
 190                xilinx_rgb2yuv_configure(crtc->rgb2yuv,
 191                                         adjusted_mode->hdisplay,
 192                                         adjusted_mode->vdisplay);
 193
 194        /* configure a plane: vdma and osd layer */
 195        xilinx_drm_plane_manager_mode_set(crtc->plane_manager,
 196                                          adjusted_mode->hdisplay,
 197                                          adjusted_mode->vdisplay);
 198        ret = xilinx_drm_plane_mode_set(base_crtc->primary,
 199                                        base_crtc->primary->fb, 0, 0,
 200                                        adjusted_mode->hdisplay,
 201                                        adjusted_mode->vdisplay,
 202                                        x, y,
 203                                        adjusted_mode->hdisplay,
 204                                        adjusted_mode->vdisplay);
 205        if (ret) {
 206                DRM_ERROR("failed to mode set a plane\n");
 207                return ret;
 208        }
 209
 210        return 0;
 211}
 212
 213static int _xilinx_drm_crtc_mode_set_base(struct drm_crtc *base_crtc,
 214                                          struct drm_framebuffer *fb,
 215                                          int x, int y)
 216{
 217        struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
 218        int ret;
 219
 220        /* configure a plane */
 221        xilinx_drm_plane_manager_mode_set(crtc->plane_manager,
 222                                          base_crtc->hwmode.hdisplay,
 223                                          base_crtc->hwmode.vdisplay);
 224        ret = xilinx_drm_plane_mode_set(base_crtc->primary,
 225                                        fb, 0, 0,
 226                                        base_crtc->hwmode.hdisplay,
 227                                        base_crtc->hwmode.vdisplay,
 228                                        x, y,
 229                                        base_crtc->hwmode.hdisplay,
 230                                        base_crtc->hwmode.vdisplay);
 231        if (ret) {
 232                DRM_ERROR("failed to mode set a plane\n");
 233                return ret;
 234        }
 235
 236        /* apply the new fb addr */
 237        xilinx_drm_crtc_commit(base_crtc);
 238
 239        return 0;
 240}
 241
 242/* update address and information from fb */
 243static int xilinx_drm_crtc_mode_set_base(struct drm_crtc *base_crtc,
 244                                         int x, int y,
 245                                         struct drm_framebuffer *old_fb)
 246{
 247        /* configure a plane */
 248        return _xilinx_drm_crtc_mode_set_base(base_crtc, base_crtc->primary->fb,
 249               x, y);
 250}
 251
 252/* load rgb LUT for crtc */
 253static void xilinx_drm_crtc_load_lut(struct drm_crtc *base_crtc)
 254{
 255        /* no op */
 256}
 257
 258static struct drm_crtc_helper_funcs xilinx_drm_crtc_helper_funcs = {
 259        .dpms           = xilinx_drm_crtc_dpms,
 260        .prepare        = xilinx_drm_crtc_prepare,
 261        .commit         = xilinx_drm_crtc_commit,
 262        .mode_fixup     = xilinx_drm_crtc_mode_fixup,
 263        .mode_set       = xilinx_drm_crtc_mode_set,
 264        .mode_set_base  = xilinx_drm_crtc_mode_set_base,
 265        .load_lut       = xilinx_drm_crtc_load_lut,
 266};
 267
 268/* destroy crtc */
 269void xilinx_drm_crtc_destroy(struct drm_crtc *base_crtc)
 270{
 271        struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
 272
 273        /* make sure crtc is off */
 274        xilinx_drm_crtc_dpms(base_crtc, DRM_MODE_DPMS_OFF);
 275
 276        drm_crtc_cleanup(base_crtc);
 277
 278        if (crtc->dp_sub)
 279                xilinx_drm_dp_sub_put(crtc->dp_sub);
 280
 281        if (crtc->pixel_clock_enabled) {
 282                clk_disable_unprepare(crtc->pixel_clock);
 283                crtc->pixel_clock_enabled = false;
 284        }
 285
 286        xilinx_drm_plane_remove_manager(crtc->plane_manager);
 287}
 288
 289/* crtc set config helper */
 290int xilinx_drm_crtc_helper_set_config(struct drm_mode_set *set)
 291{
 292        struct drm_device *drm = set->crtc->dev;
 293
 294        xilinx_drm_set_config(drm, set);
 295
 296        return drm_crtc_helper_set_config(set);
 297}
 298
 299/* cancel page flip functions */
 300void xilinx_drm_crtc_cancel_page_flip(struct drm_crtc *base_crtc,
 301                                      struct drm_file *file)
 302{
 303        struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
 304        struct drm_device *drm = base_crtc->dev;
 305        struct drm_pending_vblank_event *event;
 306        unsigned long flags;
 307
 308        spin_lock_irqsave(&drm->event_lock, flags);
 309        event = crtc->event;
 310        if (event && (event->base.file_priv == file)) {
 311                crtc->event = NULL;
 312                kfree(&event->base);
 313                drm_crtc_vblank_put(base_crtc);
 314        }
 315        spin_unlock_irqrestore(&drm->event_lock, flags);
 316}
 317
 318/* finish page flip functions */
 319static void xilinx_drm_crtc_finish_page_flip(struct drm_crtc *base_crtc)
 320{
 321        struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
 322        struct drm_device *drm = base_crtc->dev;
 323        struct drm_pending_vblank_event *event;
 324        unsigned long flags;
 325
 326        spin_lock_irqsave(&drm->event_lock, flags);
 327        event = crtc->event;
 328        crtc->event = NULL;
 329        if (event) {
 330                drm_crtc_send_vblank_event(base_crtc, event);
 331                drm_crtc_vblank_put(base_crtc);
 332        }
 333        spin_unlock_irqrestore(&drm->event_lock, flags);
 334}
 335
 336/* page flip functions */
 337static int xilinx_drm_crtc_page_flip(struct drm_crtc *base_crtc,
 338                                     struct drm_framebuffer *fb,
 339                                     struct drm_pending_vblank_event *event,
 340                                     uint32_t page_flip_flags)
 341{
 342        struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
 343        struct drm_device *drm = base_crtc->dev;
 344        unsigned long flags;
 345        int ret;
 346
 347        spin_lock_irqsave(&drm->event_lock, flags);
 348        if (crtc->event != NULL) {
 349                spin_unlock_irqrestore(&drm->event_lock, flags);
 350                return -EBUSY;
 351        }
 352        spin_unlock_irqrestore(&drm->event_lock, flags);
 353
 354        /* configure a plane */
 355        ret = _xilinx_drm_crtc_mode_set_base(base_crtc, fb,
 356                                             base_crtc->x, base_crtc->y);
 357        if (ret) {
 358                DRM_ERROR("failed to mode set a plane\n");
 359                return ret;
 360        }
 361
 362        base_crtc->primary->fb = fb;
 363
 364        if (event) {
 365                event->pipe = 0;
 366                drm_crtc_vblank_get(base_crtc);
 367                spin_lock_irqsave(&drm->event_lock, flags);
 368                crtc->event = event;
 369                spin_unlock_irqrestore(&drm->event_lock, flags);
 370        }
 371
 372        return 0;
 373}
 374
 375/* vblank interrupt handler */
 376static void xilinx_drm_crtc_vblank_handler(void *data)
 377{
 378        struct drm_crtc *base_crtc = data;
 379        struct drm_device *drm;
 380
 381        if (!base_crtc)
 382                return;
 383
 384        drm = base_crtc->dev;
 385
 386        drm_handle_vblank(drm, 0);
 387        xilinx_drm_crtc_finish_page_flip(base_crtc);
 388}
 389
 390/* enable vblank interrupt */
 391void xilinx_drm_crtc_enable_vblank(struct drm_crtc *base_crtc)
 392{
 393        struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
 394
 395        if (crtc->vtc)
 396                xilinx_vtc_enable_vblank_intr(crtc->vtc,
 397                                              xilinx_drm_crtc_vblank_handler,
 398                                              base_crtc);
 399        if (crtc->dp_sub)
 400                xilinx_drm_dp_sub_enable_vblank(crtc->dp_sub,
 401                                                xilinx_drm_crtc_vblank_handler,
 402                                                base_crtc);
 403}
 404
 405/* disable vblank interrupt */
 406void xilinx_drm_crtc_disable_vblank(struct drm_crtc *base_crtc)
 407{
 408        struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
 409
 410        if (crtc->dp_sub)
 411                xilinx_drm_dp_sub_disable_vblank(crtc->dp_sub);
 412        if (crtc->vtc)
 413                xilinx_vtc_disable_vblank_intr(crtc->vtc);
 414}
 415
 416/**
 417 * xilinx_drm_crtc_restore - Restore the crtc states
 418 * @base_crtc: base crtc object
 419 *
 420 * Restore the crtc states to the default ones. The request is propagated
 421 * to the plane driver.
 422 */
 423void xilinx_drm_crtc_restore(struct drm_crtc *base_crtc)
 424{
 425        struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
 426
 427        xilinx_drm_plane_restore(crtc->plane_manager);
 428}
 429
 430/* check max width */
 431unsigned int xilinx_drm_crtc_get_max_width(struct drm_crtc *base_crtc)
 432{
 433        return xilinx_drm_plane_get_max_width(base_crtc->primary);
 434}
 435
 436/* check format */
 437bool xilinx_drm_crtc_check_format(struct drm_crtc *base_crtc, uint32_t fourcc)
 438{
 439        struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
 440
 441        return xilinx_drm_plane_check_format(crtc->plane_manager, fourcc);
 442}
 443
 444/* get format */
 445uint32_t xilinx_drm_crtc_get_format(struct drm_crtc *base_crtc)
 446{
 447        return xilinx_drm_plane_get_format(base_crtc->primary);
 448}
 449
 450/**
 451 * xilinx_drm_crtc_get_align - Get the alignment value for pitch
 452 * @base_crtc: Base crtc object
 453 *
 454 * Get the alignment value for pitch from the plane
 455 *
 456 * Return: The alignment value if successful, or the error code.
 457 */
 458unsigned int xilinx_drm_crtc_get_align(struct drm_crtc *base_crtc)
 459{
 460        return xilinx_drm_plane_get_align(base_crtc->primary);
 461}
 462
 463static struct drm_crtc_funcs xilinx_drm_crtc_funcs = {
 464        .destroy        = xilinx_drm_crtc_destroy,
 465        .set_config     = xilinx_drm_crtc_helper_set_config,
 466        .page_flip      = xilinx_drm_crtc_page_flip,
 467};
 468
 469/* create crtc */
 470struct drm_crtc *xilinx_drm_crtc_create(struct drm_device *drm)
 471{
 472        struct xilinx_drm_crtc *crtc;
 473        struct drm_plane *primary_plane;
 474        struct device_node *sub_node;
 475        int possible_crtcs = 1;
 476        int ret;
 477
 478        crtc = devm_kzalloc(drm->dev, sizeof(*crtc), GFP_KERNEL);
 479        if (!crtc)
 480                return ERR_PTR(-ENOMEM);
 481
 482        /* probe chroma resampler and enable */
 483        sub_node = of_parse_phandle(drm->dev->of_node, "xlnx,cresample", 0);
 484        if (sub_node) {
 485                crtc->cresample = xilinx_cresample_probe(drm->dev, sub_node);
 486                of_node_put(sub_node);
 487                if (IS_ERR(crtc->cresample)) {
 488                        DRM_ERROR("failed to probe a cresample\n");
 489                        return ERR_CAST(crtc->cresample);
 490                }
 491        }
 492
 493        /* probe color space converter and enable */
 494        sub_node = of_parse_phandle(drm->dev->of_node, "xlnx,rgb2yuv", 0);
 495        if (sub_node) {
 496                crtc->rgb2yuv = xilinx_rgb2yuv_probe(drm->dev, sub_node);
 497                of_node_put(sub_node);
 498                if (IS_ERR(crtc->rgb2yuv)) {
 499                        DRM_ERROR("failed to probe a rgb2yuv\n");
 500                        return ERR_CAST(crtc->rgb2yuv);
 501                }
 502        }
 503
 504        /* probe a plane manager */
 505        crtc->plane_manager = xilinx_drm_plane_probe_manager(drm);
 506        if (IS_ERR(crtc->plane_manager)) {
 507                if (PTR_ERR(crtc->plane_manager) != -EPROBE_DEFER)
 508                        DRM_ERROR("failed to probe a plane manager\n");
 509                return ERR_CAST(crtc->plane_manager);
 510        }
 511
 512        /* create a primary plane. there's only one crtc now */
 513        primary_plane = xilinx_drm_plane_create_primary(crtc->plane_manager,
 514                                                        possible_crtcs);
 515        if (IS_ERR(primary_plane)) {
 516                DRM_ERROR("failed to create a primary plane for crtc\n");
 517                ret = PTR_ERR(primary_plane);
 518                goto err_plane;
 519        }
 520
 521        /* create extra planes */
 522        xilinx_drm_plane_create_planes(crtc->plane_manager, possible_crtcs);
 523
 524        crtc->pixel_clock = devm_clk_get(drm->dev, NULL);
 525        if (IS_ERR(crtc->pixel_clock)) {
 526                if (PTR_ERR(crtc->pixel_clock) == -EPROBE_DEFER) {
 527                        ret = PTR_ERR(crtc->pixel_clock);
 528                        goto err_plane;
 529                } else {
 530                        DRM_DEBUG_KMS("failed to get pixel clock\n");
 531                        crtc->pixel_clock = NULL;
 532                }
 533
 534        }
 535
 536        ret = clk_prepare_enable(crtc->pixel_clock);
 537        if (ret) {
 538                DRM_ERROR("failed to enable a pixel clock\n");
 539                crtc->pixel_clock_enabled = false;
 540                goto err_plane;
 541        }
 542        crtc->pixel_clock_enabled = true;
 543
 544        sub_node = of_parse_phandle(drm->dev->of_node, "xlnx,vtc", 0);
 545        if (sub_node) {
 546                crtc->vtc = xilinx_vtc_probe(drm->dev, sub_node);
 547                of_node_put(sub_node);
 548                if (IS_ERR(crtc->vtc)) {
 549                        DRM_ERROR("failed to probe video timing controller\n");
 550                        ret = PTR_ERR(crtc->vtc);
 551                        goto err_pixel_clk;
 552                }
 553        }
 554
 555        crtc->dp_sub = xilinx_drm_dp_sub_of_get(drm->dev->of_node);
 556        if (IS_ERR(crtc->dp_sub)) {
 557                ret = PTR_ERR(crtc->dp_sub);
 558                if (ret != -EPROBE_DEFER)
 559                        DRM_ERROR("failed to get a dp_sub\n");
 560                goto err_pixel_clk;
 561        }
 562
 563        crtc->dpms = DRM_MODE_DPMS_OFF;
 564
 565        /* initialize drm crtc */
 566        ret = drm_crtc_init_with_planes(drm, &crtc->base, primary_plane,
 567                                        NULL, &xilinx_drm_crtc_funcs, NULL);
 568        if (ret) {
 569                DRM_ERROR("failed to initialize crtc\n");
 570                goto err_pixel_clk;
 571        }
 572        drm_crtc_helper_add(&crtc->base, &xilinx_drm_crtc_helper_funcs);
 573
 574        return &crtc->base;
 575
 576err_pixel_clk:
 577        if (crtc->pixel_clock_enabled) {
 578                clk_disable_unprepare(crtc->pixel_clock);
 579                crtc->pixel_clock_enabled = false;
 580        }
 581err_plane:
 582        xilinx_drm_plane_remove_manager(crtc->plane_manager);
 583        return ERR_PTR(ret);
 584}
 585