linux/drivers/gpu/drm/tidss/tidss_crtc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
   4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
   5 */
   6
   7#include <drm/drm_atomic.h>
   8#include <drm/drm_atomic_helper.h>
   9#include <drm/drm_crtc.h>
  10#include <drm/drm_crtc_helper.h>
  11#include <drm/drm_fb_cma_helper.h>
  12#include <drm/drm_gem_cma_helper.h>
  13#include <drm/drm_plane_helper.h>
  14#include <drm/drm_vblank.h>
  15
  16#include "tidss_crtc.h"
  17#include "tidss_dispc.h"
  18#include "tidss_drv.h"
  19#include "tidss_irq.h"
  20#include "tidss_plane.h"
  21
  22/* Page flip and frame done IRQs */
  23
  24static void tidss_crtc_finish_page_flip(struct tidss_crtc *tcrtc)
  25{
  26        struct drm_device *ddev = tcrtc->crtc.dev;
  27        struct tidss_device *tidss = to_tidss(ddev);
  28        struct drm_pending_vblank_event *event;
  29        unsigned long flags;
  30        bool busy;
  31
  32        spin_lock_irqsave(&ddev->event_lock, flags);
  33
  34        /*
  35         * New settings are taken into use at VFP, and GO bit is cleared at
  36         * the same time. This happens before the vertical blank interrupt.
  37         * So there is a small change that the driver sets GO bit after VFP, but
  38         * before vblank, and we have to check for that case here.
  39         */
  40        busy = dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport);
  41        if (busy) {
  42                spin_unlock_irqrestore(&ddev->event_lock, flags);
  43                return;
  44        }
  45
  46        event = tcrtc->event;
  47        tcrtc->event = NULL;
  48
  49        if (!event) {
  50                spin_unlock_irqrestore(&ddev->event_lock, flags);
  51                return;
  52        }
  53
  54        drm_crtc_send_vblank_event(&tcrtc->crtc, event);
  55
  56        spin_unlock_irqrestore(&ddev->event_lock, flags);
  57
  58        drm_crtc_vblank_put(&tcrtc->crtc);
  59}
  60
  61void tidss_crtc_vblank_irq(struct drm_crtc *crtc)
  62{
  63        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
  64
  65        drm_crtc_handle_vblank(crtc);
  66
  67        tidss_crtc_finish_page_flip(tcrtc);
  68}
  69
  70void tidss_crtc_framedone_irq(struct drm_crtc *crtc)
  71{
  72        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
  73
  74        complete(&tcrtc->framedone_completion);
  75}
  76
  77void tidss_crtc_error_irq(struct drm_crtc *crtc, u64 irqstatus)
  78{
  79        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
  80
  81        dev_err_ratelimited(crtc->dev->dev, "CRTC%u SYNC LOST: (irq %llx)\n",
  82                            tcrtc->hw_videoport, irqstatus);
  83}
  84
  85/* drm_crtc_helper_funcs */
  86
  87static int tidss_crtc_atomic_check(struct drm_crtc *crtc,
  88                                   struct drm_atomic_state *state)
  89{
  90        struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
  91                                                                          crtc);
  92        struct drm_device *ddev = crtc->dev;
  93        struct tidss_device *tidss = to_tidss(ddev);
  94        struct dispc_device *dispc = tidss->dispc;
  95        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
  96        u32 hw_videoport = tcrtc->hw_videoport;
  97        const struct drm_display_mode *mode;
  98        enum drm_mode_status ok;
  99
 100        dev_dbg(ddev->dev, "%s\n", __func__);
 101
 102        if (!crtc_state->enable)
 103                return 0;
 104
 105        mode = &crtc_state->adjusted_mode;
 106
 107        ok = dispc_vp_mode_valid(dispc, hw_videoport, mode);
 108        if (ok != MODE_OK) {
 109                dev_dbg(ddev->dev, "%s: bad mode: %ux%u pclk %u kHz\n",
 110                        __func__, mode->hdisplay, mode->vdisplay, mode->clock);
 111                return -EINVAL;
 112        }
 113
 114        return dispc_vp_bus_check(dispc, hw_videoport, crtc_state);
 115}
 116
 117/*
 118 * This needs all affected planes to be present in the atomic
 119 * state. The untouched planes are added to the state in
 120 * tidss_atomic_check().
 121 */
 122static void tidss_crtc_position_planes(struct tidss_device *tidss,
 123                                       struct drm_crtc *crtc,
 124                                       struct drm_crtc_state *old_state,
 125                                       bool newmodeset)
 126{
 127        struct drm_atomic_state *ostate = old_state->state;
 128        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
 129        struct drm_crtc_state *cstate = crtc->state;
 130        int layer;
 131
 132        if (!newmodeset && !cstate->zpos_changed &&
 133            !to_tidss_crtc_state(cstate)->plane_pos_changed)
 134                return;
 135
 136        for (layer = 0; layer < tidss->feat->num_planes; layer++) {
 137                struct drm_plane_state *pstate;
 138                struct drm_plane *plane;
 139                bool layer_active = false;
 140                int i;
 141
 142                for_each_new_plane_in_state(ostate, plane, pstate, i) {
 143                        if (pstate->crtc != crtc || !pstate->visible)
 144                                continue;
 145
 146                        if (pstate->normalized_zpos == layer) {
 147                                layer_active = true;
 148                                break;
 149                        }
 150                }
 151
 152                if (layer_active) {
 153                        struct tidss_plane *tplane = to_tidss_plane(plane);
 154
 155                        dispc_ovr_set_plane(tidss->dispc, tplane->hw_plane_id,
 156                                            tcrtc->hw_videoport,
 157                                            pstate->crtc_x, pstate->crtc_y,
 158                                            layer);
 159                }
 160                dispc_ovr_enable_layer(tidss->dispc, tcrtc->hw_videoport, layer,
 161                                       layer_active);
 162        }
 163}
 164
 165static void tidss_crtc_atomic_flush(struct drm_crtc *crtc,
 166                                    struct drm_atomic_state *state)
 167{
 168        struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
 169                                                                              crtc);
 170        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
 171        struct drm_device *ddev = crtc->dev;
 172        struct tidss_device *tidss = to_tidss(ddev);
 173        unsigned long flags;
 174
 175        dev_dbg(ddev->dev,
 176                "%s: %s enabled %d, needs modeset %d, event %p\n", __func__,
 177                crtc->name, drm_atomic_crtc_needs_modeset(crtc->state),
 178                crtc->state->enable, crtc->state->event);
 179
 180        /* There is nothing to do if CRTC is not going to be enabled. */
 181        if (!crtc->state->enable)
 182                return;
 183
 184        /*
 185         * Flush CRTC changes with go bit only if new modeset is not
 186         * coming, so CRTC is enabled trough out the commit.
 187         */
 188        if (drm_atomic_crtc_needs_modeset(crtc->state))
 189                return;
 190
 191        /* If the GO bit is stuck we better quit here. */
 192        if (WARN_ON(dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport)))
 193                return;
 194
 195        /* We should have event if CRTC is enabled through out this commit. */
 196        if (WARN_ON(!crtc->state->event))
 197                return;
 198
 199        /* Write vp properties to HW if needed. */
 200        dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, false);
 201
 202        /* Update plane positions if needed. */
 203        tidss_crtc_position_planes(tidss, crtc, old_crtc_state, false);
 204
 205        WARN_ON(drm_crtc_vblank_get(crtc) != 0);
 206
 207        spin_lock_irqsave(&ddev->event_lock, flags);
 208        dispc_vp_go(tidss->dispc, tcrtc->hw_videoport);
 209
 210        WARN_ON(tcrtc->event);
 211
 212        tcrtc->event = crtc->state->event;
 213        crtc->state->event = NULL;
 214
 215        spin_unlock_irqrestore(&ddev->event_lock, flags);
 216}
 217
 218static void tidss_crtc_atomic_enable(struct drm_crtc *crtc,
 219                                     struct drm_atomic_state *state)
 220{
 221        struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
 222                                                                         crtc);
 223        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
 224        struct drm_device *ddev = crtc->dev;
 225        struct tidss_device *tidss = to_tidss(ddev);
 226        const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
 227        unsigned long flags;
 228        int r;
 229
 230        dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event);
 231
 232        tidss_runtime_get(tidss);
 233
 234        r = dispc_vp_set_clk_rate(tidss->dispc, tcrtc->hw_videoport,
 235                                  mode->clock * 1000);
 236        if (r != 0)
 237                return;
 238
 239        r = dispc_vp_enable_clk(tidss->dispc, tcrtc->hw_videoport);
 240        if (r != 0)
 241                return;
 242
 243        dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, true);
 244        tidss_crtc_position_planes(tidss, crtc, old_state, true);
 245
 246        /* Turn vertical blanking interrupt reporting on. */
 247        drm_crtc_vblank_on(crtc);
 248
 249        dispc_vp_prepare(tidss->dispc, tcrtc->hw_videoport, crtc->state);
 250
 251        dispc_vp_enable(tidss->dispc, tcrtc->hw_videoport, crtc->state);
 252
 253        spin_lock_irqsave(&ddev->event_lock, flags);
 254
 255        if (crtc->state->event) {
 256                drm_crtc_send_vblank_event(crtc, crtc->state->event);
 257                crtc->state->event = NULL;
 258        }
 259
 260        spin_unlock_irqrestore(&ddev->event_lock, flags);
 261}
 262
 263static void tidss_crtc_atomic_disable(struct drm_crtc *crtc,
 264                                      struct drm_atomic_state *state)
 265{
 266        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
 267        struct drm_device *ddev = crtc->dev;
 268        struct tidss_device *tidss = to_tidss(ddev);
 269        unsigned long flags;
 270
 271        dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event);
 272
 273        reinit_completion(&tcrtc->framedone_completion);
 274
 275        dispc_vp_disable(tidss->dispc, tcrtc->hw_videoport);
 276
 277        if (!wait_for_completion_timeout(&tcrtc->framedone_completion,
 278                                         msecs_to_jiffies(500)))
 279                dev_err(tidss->dev, "Timeout waiting for framedone on crtc %d",
 280                        tcrtc->hw_videoport);
 281
 282        dispc_vp_unprepare(tidss->dispc, tcrtc->hw_videoport);
 283
 284        spin_lock_irqsave(&ddev->event_lock, flags);
 285        if (crtc->state->event) {
 286                drm_crtc_send_vblank_event(crtc, crtc->state->event);
 287                crtc->state->event = NULL;
 288        }
 289        spin_unlock_irqrestore(&ddev->event_lock, flags);
 290
 291        drm_crtc_vblank_off(crtc);
 292
 293        dispc_vp_disable_clk(tidss->dispc, tcrtc->hw_videoport);
 294
 295        tidss_runtime_put(tidss);
 296}
 297
 298static
 299enum drm_mode_status tidss_crtc_mode_valid(struct drm_crtc *crtc,
 300                                           const struct drm_display_mode *mode)
 301{
 302        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
 303        struct drm_device *ddev = crtc->dev;
 304        struct tidss_device *tidss = to_tidss(ddev);
 305
 306        return dispc_vp_mode_valid(tidss->dispc, tcrtc->hw_videoport, mode);
 307}
 308
 309static const struct drm_crtc_helper_funcs tidss_crtc_helper_funcs = {
 310        .atomic_check = tidss_crtc_atomic_check,
 311        .atomic_flush = tidss_crtc_atomic_flush,
 312        .atomic_enable = tidss_crtc_atomic_enable,
 313        .atomic_disable = tidss_crtc_atomic_disable,
 314
 315        .mode_valid = tidss_crtc_mode_valid,
 316};
 317
 318/* drm_crtc_funcs */
 319
 320static int tidss_crtc_enable_vblank(struct drm_crtc *crtc)
 321{
 322        struct drm_device *ddev = crtc->dev;
 323        struct tidss_device *tidss = to_tidss(ddev);
 324
 325        dev_dbg(ddev->dev, "%s\n", __func__);
 326
 327        tidss_runtime_get(tidss);
 328
 329        tidss_irq_enable_vblank(crtc);
 330
 331        return 0;
 332}
 333
 334static void tidss_crtc_disable_vblank(struct drm_crtc *crtc)
 335{
 336        struct drm_device *ddev = crtc->dev;
 337        struct tidss_device *tidss = to_tidss(ddev);
 338
 339        dev_dbg(ddev->dev, "%s\n", __func__);
 340
 341        tidss_irq_disable_vblank(crtc);
 342
 343        tidss_runtime_put(tidss);
 344}
 345
 346static void tidss_crtc_reset(struct drm_crtc *crtc)
 347{
 348        struct tidss_crtc_state *tcrtc;
 349
 350        if (crtc->state)
 351                __drm_atomic_helper_crtc_destroy_state(crtc->state);
 352
 353        kfree(crtc->state);
 354
 355        tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL);
 356        if (!tcrtc) {
 357                crtc->state = NULL;
 358                return;
 359        }
 360
 361        __drm_atomic_helper_crtc_reset(crtc, &tcrtc->base);
 362}
 363
 364static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc)
 365{
 366        struct tidss_crtc_state *state, *current_state;
 367
 368        if (WARN_ON(!crtc->state))
 369                return NULL;
 370
 371        current_state = to_tidss_crtc_state(crtc->state);
 372
 373        state = kmalloc(sizeof(*state), GFP_KERNEL);
 374        if (!state)
 375                return NULL;
 376
 377        __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
 378
 379        state->plane_pos_changed = false;
 380
 381        state->bus_format = current_state->bus_format;
 382        state->bus_flags = current_state->bus_flags;
 383
 384        return &state->base;
 385}
 386
 387static void tidss_crtc_destroy(struct drm_crtc *crtc)
 388{
 389        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
 390
 391        drm_crtc_cleanup(crtc);
 392        kfree(tcrtc);
 393}
 394
 395static const struct drm_crtc_funcs tidss_crtc_funcs = {
 396        .reset = tidss_crtc_reset,
 397        .destroy = tidss_crtc_destroy,
 398        .set_config = drm_atomic_helper_set_config,
 399        .page_flip = drm_atomic_helper_page_flip,
 400        .atomic_duplicate_state = tidss_crtc_duplicate_state,
 401        .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
 402        .enable_vblank = tidss_crtc_enable_vblank,
 403        .disable_vblank = tidss_crtc_disable_vblank,
 404};
 405
 406struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
 407                                     u32 hw_videoport,
 408                                     struct drm_plane *primary)
 409{
 410        struct tidss_crtc *tcrtc;
 411        struct drm_crtc *crtc;
 412        unsigned int gamma_lut_size = 0;
 413        bool has_ctm = tidss->feat->vp_feat.color.has_ctm;
 414        int ret;
 415
 416        tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL);
 417        if (!tcrtc)
 418                return ERR_PTR(-ENOMEM);
 419
 420        tcrtc->hw_videoport = hw_videoport;
 421        init_completion(&tcrtc->framedone_completion);
 422
 423        crtc =  &tcrtc->crtc;
 424
 425        ret = drm_crtc_init_with_planes(&tidss->ddev, crtc, primary,
 426                                        NULL, &tidss_crtc_funcs, NULL);
 427        if (ret < 0) {
 428                kfree(tcrtc);
 429                return ERR_PTR(ret);
 430        }
 431
 432        drm_crtc_helper_add(crtc, &tidss_crtc_helper_funcs);
 433
 434        /*
 435         * The dispc gamma functions adapt to what ever size we ask
 436         * from it no matter what HW supports. X-server assumes 256
 437         * element gamma tables so lets use that.
 438         */
 439        if (tidss->feat->vp_feat.color.gamma_size)
 440                gamma_lut_size = 256;
 441
 442        drm_crtc_enable_color_mgmt(crtc, 0, has_ctm, gamma_lut_size);
 443        if (gamma_lut_size)
 444                drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size);
 445
 446        return tcrtc;
 447}
 448