linux/drivers/gpu/drm/vc4/vc4_txp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright © 2018 Broadcom
   4 *
   5 * Authors:
   6 *      Eric Anholt <eric@anholt.net>
   7 *      Boris Brezillon <boris.brezillon@bootlin.com>
   8 */
   9
  10#include <linux/clk.h>
  11#include <linux/component.h>
  12#include <linux/of_graph.h>
  13#include <linux/of_platform.h>
  14#include <linux/pm_runtime.h>
  15
  16#include <drm/drm_atomic.h>
  17#include <drm/drm_atomic_helper.h>
  18#include <drm/drm_edid.h>
  19#include <drm/drm_fb_cma_helper.h>
  20#include <drm/drm_fourcc.h>
  21#include <drm/drm_panel.h>
  22#include <drm/drm_probe_helper.h>
  23#include <drm/drm_vblank.h>
  24#include <drm/drm_writeback.h>
  25
  26#include "vc4_drv.h"
  27#include "vc4_regs.h"
  28
  29/* Base address of the output.  Raster formats must be 4-byte aligned,
  30 * T and LT must be 16-byte aligned or maybe utile-aligned (docs are
  31 * inconsistent, but probably utile).
  32 */
  33#define TXP_DST_PTR             0x00
  34
  35/* Pitch in bytes for raster images, 16-byte aligned.  For tiled, it's
  36 * the width in tiles.
  37 */
  38#define TXP_DST_PITCH           0x04
  39/* For T-tiled imgaes, DST_PITCH should be the number of tiles wide,
  40 * shifted up.
  41 */
  42# define TXP_T_TILE_WIDTH_SHIFT         7
  43/* For LT-tiled images, DST_PITCH should be the number of utiles wide,
  44 * shifted up.
  45 */
  46# define TXP_LT_TILE_WIDTH_SHIFT        4
  47
  48/* Pre-rotation width/height of the image.  Must match HVS config.
  49 *
  50 * If TFORMAT and 32-bit, limit is 1920 for 32-bit and 3840 to 16-bit
  51 * and width/height must be tile or utile-aligned as appropriate.  If
  52 * transposing (rotating), width is limited to 1920.
  53 *
  54 * Height is limited to various numbers between 4088 and 4095.  I'd
  55 * just use 4088 to be safe.
  56 */
  57#define TXP_DIM                 0x08
  58# define TXP_HEIGHT_SHIFT               16
  59# define TXP_HEIGHT_MASK                GENMASK(31, 16)
  60# define TXP_WIDTH_SHIFT                0
  61# define TXP_WIDTH_MASK                 GENMASK(15, 0)
  62
  63#define TXP_DST_CTRL            0x0c
  64/* These bits are set to 0x54 */
  65#define TXP_PILOT_SHIFT                 24
  66#define TXP_PILOT_MASK                  GENMASK(31, 24)
  67/* Bits 22-23 are set to 0x01 */
  68#define TXP_VERSION_SHIFT               22
  69#define TXP_VERSION_MASK                GENMASK(23, 22)
  70
  71/* Powers down the internal memory. */
  72# define TXP_POWERDOWN                  BIT(21)
  73
  74/* Enables storing the alpha component in 8888/4444, instead of
  75 * filling with ~ALPHA_INVERT.
  76 */
  77# define TXP_ALPHA_ENABLE               BIT(20)
  78
  79/* 4 bits, each enables stores for a channel in each set of 4 bytes.
  80 * Set to 0xf for normal operation.
  81 */
  82# define TXP_BYTE_ENABLE_SHIFT          16
  83# define TXP_BYTE_ENABLE_MASK           GENMASK(19, 16)
  84
  85/* Debug: Generate VSTART again at EOF. */
  86# define TXP_VSTART_AT_EOF              BIT(15)
  87
  88/* Debug: Terminate the current frame immediately.  Stops AXI
  89 * writes.
  90 */
  91# define TXP_ABORT                      BIT(14)
  92
  93# define TXP_DITHER                     BIT(13)
  94
  95/* Inverts alpha if TXP_ALPHA_ENABLE, chooses fill value for
  96 * !TXP_ALPHA_ENABLE.
  97 */
  98# define TXP_ALPHA_INVERT               BIT(12)
  99
 100/* Note: I've listed the channels here in high bit (in byte 3/2/1) to
 101 * low bit (in byte 0) order.
 102 */
 103# define TXP_FORMAT_SHIFT               8
 104# define TXP_FORMAT_MASK                GENMASK(11, 8)
 105# define TXP_FORMAT_ABGR4444            0
 106# define TXP_FORMAT_ARGB4444            1
 107# define TXP_FORMAT_BGRA4444            2
 108# define TXP_FORMAT_RGBA4444            3
 109# define TXP_FORMAT_BGR565              6
 110# define TXP_FORMAT_RGB565              7
 111/* 888s are non-rotated, raster-only */
 112# define TXP_FORMAT_BGR888              8
 113# define TXP_FORMAT_RGB888              9
 114# define TXP_FORMAT_ABGR8888            12
 115# define TXP_FORMAT_ARGB8888            13
 116# define TXP_FORMAT_BGRA8888            14
 117# define TXP_FORMAT_RGBA8888            15
 118
 119/* If TFORMAT is set, generates LT instead of T format. */
 120# define TXP_LINEAR_UTILE               BIT(7)
 121
 122/* Rotate output by 90 degrees. */
 123# define TXP_TRANSPOSE                  BIT(6)
 124
 125/* Generate a tiled format for V3D. */
 126# define TXP_TFORMAT                    BIT(5)
 127
 128/* Generates some undefined test mode output. */
 129# define TXP_TEST_MODE                  BIT(4)
 130
 131/* Request odd field from HVS. */
 132# define TXP_FIELD                      BIT(3)
 133
 134/* Raise interrupt when idle. */
 135# define TXP_EI                         BIT(2)
 136
 137/* Set when generating a frame, clears when idle. */
 138# define TXP_BUSY                       BIT(1)
 139
 140/* Starts a frame.  Self-clearing. */
 141# define TXP_GO                         BIT(0)
 142
 143/* Number of lines received and committed to memory. */
 144#define TXP_PROGRESS            0x10
 145
 146#define TXP_READ(offset) readl(txp->regs + (offset))
 147#define TXP_WRITE(offset, val) writel(val, txp->regs + (offset))
 148
 149struct vc4_txp {
 150        struct vc4_crtc base;
 151
 152        struct platform_device *pdev;
 153
 154        struct drm_writeback_connector connector;
 155
 156        void __iomem *regs;
 157        struct debugfs_regset32 regset;
 158};
 159
 160static inline struct vc4_txp *encoder_to_vc4_txp(struct drm_encoder *encoder)
 161{
 162        return container_of(encoder, struct vc4_txp, connector.encoder);
 163}
 164
 165static inline struct vc4_txp *connector_to_vc4_txp(struct drm_connector *conn)
 166{
 167        return container_of(conn, struct vc4_txp, connector.base);
 168}
 169
 170static const struct debugfs_reg32 txp_regs[] = {
 171        VC4_REG32(TXP_DST_PTR),
 172        VC4_REG32(TXP_DST_PITCH),
 173        VC4_REG32(TXP_DIM),
 174        VC4_REG32(TXP_DST_CTRL),
 175        VC4_REG32(TXP_PROGRESS),
 176};
 177
 178static int vc4_txp_connector_get_modes(struct drm_connector *connector)
 179{
 180        struct drm_device *dev = connector->dev;
 181
 182        return drm_add_modes_noedid(connector, dev->mode_config.max_width,
 183                                    dev->mode_config.max_height);
 184}
 185
 186static enum drm_mode_status
 187vc4_txp_connector_mode_valid(struct drm_connector *connector,
 188                             struct drm_display_mode *mode)
 189{
 190        struct drm_device *dev = connector->dev;
 191        struct drm_mode_config *mode_config = &dev->mode_config;
 192        int w = mode->hdisplay, h = mode->vdisplay;
 193
 194        if (w < mode_config->min_width || w > mode_config->max_width)
 195                return MODE_BAD_HVALUE;
 196
 197        if (h < mode_config->min_height || h > mode_config->max_height)
 198                return MODE_BAD_VVALUE;
 199
 200        return MODE_OK;
 201}
 202
 203static const u32 drm_fmts[] = {
 204        DRM_FORMAT_RGB888,
 205        DRM_FORMAT_BGR888,
 206        DRM_FORMAT_XRGB8888,
 207        DRM_FORMAT_XBGR8888,
 208        DRM_FORMAT_ARGB8888,
 209        DRM_FORMAT_ABGR8888,
 210        DRM_FORMAT_RGBX8888,
 211        DRM_FORMAT_BGRX8888,
 212        DRM_FORMAT_RGBA8888,
 213        DRM_FORMAT_BGRA8888,
 214};
 215
 216static const u32 txp_fmts[] = {
 217        TXP_FORMAT_RGB888,
 218        TXP_FORMAT_BGR888,
 219        TXP_FORMAT_ARGB8888,
 220        TXP_FORMAT_ABGR8888,
 221        TXP_FORMAT_ARGB8888,
 222        TXP_FORMAT_ABGR8888,
 223        TXP_FORMAT_RGBA8888,
 224        TXP_FORMAT_BGRA8888,
 225        TXP_FORMAT_RGBA8888,
 226        TXP_FORMAT_BGRA8888,
 227};
 228
 229static void vc4_txp_armed(struct drm_crtc_state *state)
 230{
 231        struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
 232
 233        vc4_state->txp_armed = true;
 234}
 235
 236static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
 237                                          struct drm_atomic_state *state)
 238{
 239        struct drm_connector_state *conn_state;
 240        struct drm_crtc_state *crtc_state;
 241        struct drm_framebuffer *fb;
 242        int i;
 243
 244        conn_state = drm_atomic_get_new_connector_state(state, conn);
 245        if (!conn_state->writeback_job)
 246                return 0;
 247
 248        crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
 249
 250        fb = conn_state->writeback_job->fb;
 251        if (fb->width != crtc_state->mode.hdisplay ||
 252            fb->height != crtc_state->mode.vdisplay) {
 253                DRM_DEBUG_KMS("Invalid framebuffer size %ux%u\n",
 254                              fb->width, fb->height);
 255                return -EINVAL;
 256        }
 257
 258        for (i = 0; i < ARRAY_SIZE(drm_fmts); i++) {
 259                if (fb->format->format == drm_fmts[i])
 260                        break;
 261        }
 262
 263        if (i == ARRAY_SIZE(drm_fmts))
 264                return -EINVAL;
 265
 266        /* Pitch must be aligned on 16 bytes. */
 267        if (fb->pitches[0] & GENMASK(3, 0))
 268                return -EINVAL;
 269
 270        vc4_txp_armed(crtc_state);
 271
 272        return 0;
 273}
 274
 275static void vc4_txp_connector_atomic_commit(struct drm_connector *conn,
 276                                        struct drm_atomic_state *state)
 277{
 278        struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state,
 279                                                                                    conn);
 280        struct vc4_txp *txp = connector_to_vc4_txp(conn);
 281        struct drm_gem_cma_object *gem;
 282        struct drm_display_mode *mode;
 283        struct drm_framebuffer *fb;
 284        u32 ctrl;
 285        int i;
 286
 287        if (WARN_ON(!conn_state->writeback_job))
 288                return;
 289
 290        mode = &conn_state->crtc->state->adjusted_mode;
 291        fb = conn_state->writeback_job->fb;
 292
 293        for (i = 0; i < ARRAY_SIZE(drm_fmts); i++) {
 294                if (fb->format->format == drm_fmts[i])
 295                        break;
 296        }
 297
 298        if (WARN_ON(i == ARRAY_SIZE(drm_fmts)))
 299                return;
 300
 301        ctrl = TXP_GO | TXP_VSTART_AT_EOF | TXP_EI |
 302               VC4_SET_FIELD(0xf, TXP_BYTE_ENABLE) |
 303               VC4_SET_FIELD(txp_fmts[i], TXP_FORMAT);
 304
 305        if (fb->format->has_alpha)
 306                ctrl |= TXP_ALPHA_ENABLE;
 307
 308        gem = drm_fb_cma_get_gem_obj(fb, 0);
 309        TXP_WRITE(TXP_DST_PTR, gem->paddr + fb->offsets[0]);
 310        TXP_WRITE(TXP_DST_PITCH, fb->pitches[0]);
 311        TXP_WRITE(TXP_DIM,
 312                  VC4_SET_FIELD(mode->hdisplay, TXP_WIDTH) |
 313                  VC4_SET_FIELD(mode->vdisplay, TXP_HEIGHT));
 314
 315        TXP_WRITE(TXP_DST_CTRL, ctrl);
 316
 317        drm_writeback_queue_job(&txp->connector, conn_state);
 318}
 319
 320static const struct drm_connector_helper_funcs vc4_txp_connector_helper_funcs = {
 321        .get_modes = vc4_txp_connector_get_modes,
 322        .mode_valid = vc4_txp_connector_mode_valid,
 323        .atomic_check = vc4_txp_connector_atomic_check,
 324        .atomic_commit = vc4_txp_connector_atomic_commit,
 325};
 326
 327static enum drm_connector_status
 328vc4_txp_connector_detect(struct drm_connector *connector, bool force)
 329{
 330        return connector_status_connected;
 331}
 332
 333static void vc4_txp_connector_destroy(struct drm_connector *connector)
 334{
 335        drm_connector_unregister(connector);
 336        drm_connector_cleanup(connector);
 337}
 338
 339static const struct drm_connector_funcs vc4_txp_connector_funcs = {
 340        .detect = vc4_txp_connector_detect,
 341        .fill_modes = drm_helper_probe_single_connector_modes,
 342        .destroy = vc4_txp_connector_destroy,
 343        .reset = drm_atomic_helper_connector_reset,
 344        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 345        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 346};
 347
 348static void vc4_txp_encoder_disable(struct drm_encoder *encoder)
 349{
 350        struct vc4_txp *txp = encoder_to_vc4_txp(encoder);
 351
 352        if (TXP_READ(TXP_DST_CTRL) & TXP_BUSY) {
 353                unsigned long timeout = jiffies + msecs_to_jiffies(1000);
 354
 355                TXP_WRITE(TXP_DST_CTRL, TXP_ABORT);
 356
 357                while (TXP_READ(TXP_DST_CTRL) & TXP_BUSY &&
 358                       time_before(jiffies, timeout))
 359                        ;
 360
 361                WARN_ON(TXP_READ(TXP_DST_CTRL) & TXP_BUSY);
 362        }
 363
 364        TXP_WRITE(TXP_DST_CTRL, TXP_POWERDOWN);
 365}
 366
 367static const struct drm_encoder_helper_funcs vc4_txp_encoder_helper_funcs = {
 368        .disable = vc4_txp_encoder_disable,
 369};
 370
 371static int vc4_txp_enable_vblank(struct drm_crtc *crtc)
 372{
 373        return 0;
 374}
 375
 376static void vc4_txp_disable_vblank(struct drm_crtc *crtc) {}
 377
 378static const struct drm_crtc_funcs vc4_txp_crtc_funcs = {
 379        .set_config             = drm_atomic_helper_set_config,
 380        .destroy                = vc4_crtc_destroy,
 381        .page_flip              = vc4_page_flip,
 382        .reset                  = vc4_crtc_reset,
 383        .atomic_duplicate_state = vc4_crtc_duplicate_state,
 384        .atomic_destroy_state   = vc4_crtc_destroy_state,
 385        .enable_vblank          = vc4_txp_enable_vblank,
 386        .disable_vblank         = vc4_txp_disable_vblank,
 387};
 388
 389static int vc4_txp_atomic_check(struct drm_crtc *crtc,
 390                                struct drm_atomic_state *state)
 391{
 392        struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
 393                                                                          crtc);
 394        struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
 395        int ret;
 396
 397        ret = vc4_hvs_atomic_check(crtc, state);
 398        if (ret)
 399                return ret;
 400
 401        crtc_state->no_vblank = true;
 402        vc4_state->feed_txp = true;
 403
 404        return 0;
 405}
 406
 407static void vc4_txp_atomic_enable(struct drm_crtc *crtc,
 408                                  struct drm_atomic_state *state)
 409{
 410        drm_crtc_vblank_on(crtc);
 411        vc4_hvs_atomic_enable(crtc, state);
 412}
 413
 414static void vc4_txp_atomic_disable(struct drm_crtc *crtc,
 415                                   struct drm_atomic_state *state)
 416{
 417        struct drm_device *dev = crtc->dev;
 418
 419        /* Disable vblank irq handling before crtc is disabled. */
 420        drm_crtc_vblank_off(crtc);
 421
 422        vc4_hvs_atomic_disable(crtc, state);
 423
 424        /*
 425         * Make sure we issue a vblank event after disabling the CRTC if
 426         * someone was waiting it.
 427         */
 428        if (crtc->state->event) {
 429                unsigned long flags;
 430
 431                spin_lock_irqsave(&dev->event_lock, flags);
 432                drm_crtc_send_vblank_event(crtc, crtc->state->event);
 433                crtc->state->event = NULL;
 434                spin_unlock_irqrestore(&dev->event_lock, flags);
 435        }
 436}
 437
 438static const struct drm_crtc_helper_funcs vc4_txp_crtc_helper_funcs = {
 439        .atomic_check   = vc4_txp_atomic_check,
 440        .atomic_flush   = vc4_hvs_atomic_flush,
 441        .atomic_enable  = vc4_txp_atomic_enable,
 442        .atomic_disable = vc4_txp_atomic_disable,
 443};
 444
 445static irqreturn_t vc4_txp_interrupt(int irq, void *data)
 446{
 447        struct vc4_txp *txp = data;
 448        struct vc4_crtc *vc4_crtc = &txp->base;
 449
 450        TXP_WRITE(TXP_DST_CTRL, TXP_READ(TXP_DST_CTRL) & ~TXP_EI);
 451        vc4_crtc_handle_vblank(vc4_crtc);
 452        drm_writeback_signal_completion(&txp->connector, 0);
 453
 454        return IRQ_HANDLED;
 455}
 456
 457static const struct vc4_crtc_data vc4_txp_crtc_data = {
 458        .hvs_available_channels = BIT(2),
 459        .hvs_output = 2,
 460};
 461
 462static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
 463{
 464        struct platform_device *pdev = to_platform_device(dev);
 465        struct drm_device *drm = dev_get_drvdata(master);
 466        struct vc4_dev *vc4 = to_vc4_dev(drm);
 467        struct vc4_crtc *vc4_crtc;
 468        struct vc4_txp *txp;
 469        struct drm_crtc *crtc;
 470        struct drm_encoder *encoder;
 471        int ret, irq;
 472
 473        irq = platform_get_irq(pdev, 0);
 474        if (irq < 0)
 475                return irq;
 476
 477        txp = devm_kzalloc(dev, sizeof(*txp), GFP_KERNEL);
 478        if (!txp)
 479                return -ENOMEM;
 480        vc4_crtc = &txp->base;
 481        crtc = &vc4_crtc->base;
 482
 483        vc4_crtc->pdev = pdev;
 484        vc4_crtc->data = &vc4_txp_crtc_data;
 485
 486        txp->pdev = pdev;
 487
 488        txp->regs = vc4_ioremap_regs(pdev, 0);
 489        if (IS_ERR(txp->regs))
 490                return PTR_ERR(txp->regs);
 491        txp->regset.base = txp->regs;
 492        txp->regset.regs = txp_regs;
 493        txp->regset.nregs = ARRAY_SIZE(txp_regs);
 494
 495        drm_connector_helper_add(&txp->connector.base,
 496                                 &vc4_txp_connector_helper_funcs);
 497        ret = drm_writeback_connector_init(drm, &txp->connector,
 498                                           &vc4_txp_connector_funcs,
 499                                           &vc4_txp_encoder_helper_funcs,
 500                                           drm_fmts, ARRAY_SIZE(drm_fmts));
 501        if (ret)
 502                return ret;
 503
 504        ret = vc4_crtc_init(drm, vc4_crtc,
 505                            &vc4_txp_crtc_funcs, &vc4_txp_crtc_helper_funcs);
 506        if (ret)
 507                return ret;
 508
 509        encoder = &txp->connector.encoder;
 510        encoder->possible_crtcs = drm_crtc_mask(crtc);
 511
 512        ret = devm_request_irq(dev, irq, vc4_txp_interrupt, 0,
 513                               dev_name(dev), txp);
 514        if (ret)
 515                return ret;
 516
 517        dev_set_drvdata(dev, txp);
 518        vc4->txp = txp;
 519
 520        vc4_debugfs_add_regset32(drm, "txp_regs", &txp->regset);
 521
 522        return 0;
 523}
 524
 525static void vc4_txp_unbind(struct device *dev, struct device *master,
 526                           void *data)
 527{
 528        struct drm_device *drm = dev_get_drvdata(master);
 529        struct vc4_dev *vc4 = to_vc4_dev(drm);
 530        struct vc4_txp *txp = dev_get_drvdata(dev);
 531
 532        vc4_txp_connector_destroy(&txp->connector.base);
 533
 534        vc4->txp = NULL;
 535}
 536
 537static const struct component_ops vc4_txp_ops = {
 538        .bind   = vc4_txp_bind,
 539        .unbind = vc4_txp_unbind,
 540};
 541
 542static int vc4_txp_probe(struct platform_device *pdev)
 543{
 544        return component_add(&pdev->dev, &vc4_txp_ops);
 545}
 546
 547static int vc4_txp_remove(struct platform_device *pdev)
 548{
 549        component_del(&pdev->dev, &vc4_txp_ops);
 550        return 0;
 551}
 552
 553static const struct of_device_id vc4_txp_dt_match[] = {
 554        { .compatible = "brcm,bcm2835-txp" },
 555        { /* sentinel */ },
 556};
 557
 558struct platform_driver vc4_txp_driver = {
 559        .probe = vc4_txp_probe,
 560        .remove = vc4_txp_remove,
 561        .driver = {
 562                .name = "vc4_txp",
 563                .of_match_table = vc4_txp_dt_match,
 564        },
 565};
 566