linux/drivers/gpu/drm/vc4/vc4_vec.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2016 Broadcom
   3 *
   4 * This program is free software; you can redistribute it and/or modify it
   5 * under the terms of the GNU General Public License version 2 as published by
   6 * the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful, but WITHOUT
   9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  11 * more details.
  12 *
  13 * You should have received a copy of the GNU General Public License along with
  14 * this program.  If not, see <http://www.gnu.org/licenses/>.
  15 */
  16
  17/**
  18 * DOC: VC4 SDTV module
  19 *
  20 * The VEC encoder generates PAL or NTSC composite video output.
  21 *
  22 * TV mode selection is done by an atomic property on the encoder,
  23 * because a drm_mode_modeinfo is insufficient to distinguish between
  24 * PAL and PAL-M or NTSC and NTSC-J.
  25 */
  26
  27#include <drm/drm_atomic_helper.h>
  28#include <drm/drm_crtc_helper.h>
  29#include <drm/drm_edid.h>
  30#include <drm/drm_panel.h>
  31#include <linux/clk.h>
  32#include <linux/component.h>
  33#include <linux/of_graph.h>
  34#include <linux/of_platform.h>
  35#include <linux/pm_runtime.h>
  36
  37#include "vc4_drv.h"
  38#include "vc4_regs.h"
  39
  40/* WSE Registers */
  41#define VEC_WSE_RESET                   0xc0
  42
  43#define VEC_WSE_CONTROL                 0xc4
  44#define VEC_WSE_WSS_ENABLE              BIT(7)
  45
  46#define VEC_WSE_WSS_DATA                0xc8
  47#define VEC_WSE_VPS_DATA1               0xcc
  48#define VEC_WSE_VPS_CONTROL             0xd0
  49
  50/* VEC Registers */
  51#define VEC_REVID                       0x100
  52
  53#define VEC_CONFIG0                     0x104
  54#define VEC_CONFIG0_YDEL_MASK           GENMASK(28, 26)
  55#define VEC_CONFIG0_YDEL(x)             ((x) << 26)
  56#define VEC_CONFIG0_CDEL_MASK           GENMASK(25, 24)
  57#define VEC_CONFIG0_CDEL(x)             ((x) << 24)
  58#define VEC_CONFIG0_PBPR_FIL            BIT(18)
  59#define VEC_CONFIG0_CHROMA_GAIN_MASK    GENMASK(17, 16)
  60#define VEC_CONFIG0_CHROMA_GAIN_UNITY   (0 << 16)
  61#define VEC_CONFIG0_CHROMA_GAIN_1_32    (1 << 16)
  62#define VEC_CONFIG0_CHROMA_GAIN_1_16    (2 << 16)
  63#define VEC_CONFIG0_CHROMA_GAIN_1_8     (3 << 16)
  64#define VEC_CONFIG0_CBURST_GAIN_MASK    GENMASK(14, 13)
  65#define VEC_CONFIG0_CBURST_GAIN_UNITY   (0 << 13)
  66#define VEC_CONFIG0_CBURST_GAIN_1_128   (1 << 13)
  67#define VEC_CONFIG0_CBURST_GAIN_1_64    (2 << 13)
  68#define VEC_CONFIG0_CBURST_GAIN_1_32    (3 << 13)
  69#define VEC_CONFIG0_CHRBW1              BIT(11)
  70#define VEC_CONFIG0_CHRBW0              BIT(10)
  71#define VEC_CONFIG0_SYNCDIS             BIT(9)
  72#define VEC_CONFIG0_BURDIS              BIT(8)
  73#define VEC_CONFIG0_CHRDIS              BIT(7)
  74#define VEC_CONFIG0_PDEN                BIT(6)
  75#define VEC_CONFIG0_YCDELAY             BIT(4)
  76#define VEC_CONFIG0_RAMPEN              BIT(2)
  77#define VEC_CONFIG0_YCDIS               BIT(2)
  78#define VEC_CONFIG0_STD_MASK            GENMASK(1, 0)
  79#define VEC_CONFIG0_NTSC_STD            0
  80#define VEC_CONFIG0_PAL_BDGHI_STD       1
  81#define VEC_CONFIG0_PAL_N_STD           3
  82
  83#define VEC_SCHPH                       0x108
  84#define VEC_SOFT_RESET                  0x10c
  85#define VEC_CLMP0_START                 0x144
  86#define VEC_CLMP0_END                   0x148
  87#define VEC_FREQ3_2                     0x180
  88#define VEC_FREQ1_0                     0x184
  89
  90#define VEC_CONFIG1                     0x188
  91#define VEC_CONFIG_VEC_RESYNC_OFF       BIT(18)
  92#define VEC_CONFIG_RGB219               BIT(17)
  93#define VEC_CONFIG_CBAR_EN              BIT(16)
  94#define VEC_CONFIG_TC_OBB               BIT(15)
  95#define VEC_CONFIG1_OUTPUT_MODE_MASK    GENMASK(12, 10)
  96#define VEC_CONFIG1_C_Y_CVBS            (0 << 10)
  97#define VEC_CONFIG1_CVBS_Y_C            (1 << 10)
  98#define VEC_CONFIG1_PR_Y_PB             (2 << 10)
  99#define VEC_CONFIG1_RGB                 (4 << 10)
 100#define VEC_CONFIG1_Y_C_CVBS            (5 << 10)
 101#define VEC_CONFIG1_C_CVBS_Y            (6 << 10)
 102#define VEC_CONFIG1_C_CVBS_CVBS         (7 << 10)
 103#define VEC_CONFIG1_DIS_CHR             BIT(9)
 104#define VEC_CONFIG1_DIS_LUMA            BIT(8)
 105#define VEC_CONFIG1_YCBCR_IN            BIT(6)
 106#define VEC_CONFIG1_DITHER_TYPE_LFSR    0
 107#define VEC_CONFIG1_DITHER_TYPE_COUNTER BIT(5)
 108#define VEC_CONFIG1_DITHER_EN           BIT(4)
 109#define VEC_CONFIG1_CYDELAY             BIT(3)
 110#define VEC_CONFIG1_LUMADIS             BIT(2)
 111#define VEC_CONFIG1_COMPDIS             BIT(1)
 112#define VEC_CONFIG1_CUSTOM_FREQ         BIT(0)
 113
 114#define VEC_CONFIG2                     0x18c
 115#define VEC_CONFIG2_PROG_SCAN           BIT(15)
 116#define VEC_CONFIG2_SYNC_ADJ_MASK       GENMASK(14, 12)
 117#define VEC_CONFIG2_SYNC_ADJ(x)         (((x) / 2) << 12)
 118#define VEC_CONFIG2_PBPR_EN             BIT(10)
 119#define VEC_CONFIG2_UV_DIG_DIS          BIT(6)
 120#define VEC_CONFIG2_RGB_DIG_DIS         BIT(5)
 121#define VEC_CONFIG2_TMUX_MASK           GENMASK(3, 2)
 122#define VEC_CONFIG2_TMUX_DRIVE0         (0 << 2)
 123#define VEC_CONFIG2_TMUX_RG_COMP        (1 << 2)
 124#define VEC_CONFIG2_TMUX_UV_YC          (2 << 2)
 125#define VEC_CONFIG2_TMUX_SYNC_YC        (3 << 2)
 126
 127#define VEC_INTERRUPT_CONTROL           0x190
 128#define VEC_INTERRUPT_STATUS            0x194
 129#define VEC_FCW_SECAM_B                 0x198
 130#define VEC_SECAM_GAIN_VAL              0x19c
 131
 132#define VEC_CONFIG3                     0x1a0
 133#define VEC_CONFIG3_HORIZ_LEN_STD       (0 << 0)
 134#define VEC_CONFIG3_HORIZ_LEN_MPEG1_SIF (1 << 0)
 135#define VEC_CONFIG3_SHAPE_NON_LINEAR    BIT(1)
 136
 137#define VEC_STATUS0                     0x200
 138#define VEC_MASK0                       0x204
 139
 140#define VEC_CFG                         0x208
 141#define VEC_CFG_SG_MODE_MASK            GENMASK(6, 5)
 142#define VEC_CFG_SG_MODE(x)              ((x) << 5)
 143#define VEC_CFG_SG_EN                   BIT(4)
 144#define VEC_CFG_VEC_EN                  BIT(3)
 145#define VEC_CFG_MB_EN                   BIT(2)
 146#define VEC_CFG_ENABLE                  BIT(1)
 147#define VEC_CFG_TB_EN                   BIT(0)
 148
 149#define VEC_DAC_TEST                    0x20c
 150
 151#define VEC_DAC_CONFIG                  0x210
 152#define VEC_DAC_CONFIG_LDO_BIAS_CTRL(x) ((x) << 24)
 153#define VEC_DAC_CONFIG_DRIVER_CTRL(x)   ((x) << 16)
 154#define VEC_DAC_CONFIG_DAC_CTRL(x)      (x)
 155
 156#define VEC_DAC_MISC                    0x214
 157#define VEC_DAC_MISC_VCD_CTRL_MASK      GENMASK(31, 16)
 158#define VEC_DAC_MISC_VCD_CTRL(x)        ((x) << 16)
 159#define VEC_DAC_MISC_VID_ACT            BIT(8)
 160#define VEC_DAC_MISC_VCD_PWRDN          BIT(6)
 161#define VEC_DAC_MISC_BIAS_PWRDN         BIT(5)
 162#define VEC_DAC_MISC_DAC_PWRDN          BIT(2)
 163#define VEC_DAC_MISC_LDO_PWRDN          BIT(1)
 164#define VEC_DAC_MISC_DAC_RST_N          BIT(0)
 165
 166
 167/* General VEC hardware state. */
 168struct vc4_vec {
 169        struct platform_device *pdev;
 170
 171        struct drm_encoder *encoder;
 172        struct drm_connector *connector;
 173
 174        void __iomem *regs;
 175
 176        struct clk *clock;
 177
 178        const struct vc4_vec_tv_mode *tv_mode;
 179};
 180
 181#define VEC_READ(offset) readl(vec->regs + (offset))
 182#define VEC_WRITE(offset, val) writel(val, vec->regs + (offset))
 183
 184/* VC4 VEC encoder KMS struct */
 185struct vc4_vec_encoder {
 186        struct vc4_encoder base;
 187        struct vc4_vec *vec;
 188};
 189
 190static inline struct vc4_vec_encoder *
 191to_vc4_vec_encoder(struct drm_encoder *encoder)
 192{
 193        return container_of(encoder, struct vc4_vec_encoder, base.base);
 194}
 195
 196/* VC4 VEC connector KMS struct */
 197struct vc4_vec_connector {
 198        struct drm_connector base;
 199        struct vc4_vec *vec;
 200
 201        /* Since the connector is attached to just the one encoder,
 202         * this is the reference to it so we can do the best_encoder()
 203         * hook.
 204         */
 205        struct drm_encoder *encoder;
 206};
 207
 208static inline struct vc4_vec_connector *
 209to_vc4_vec_connector(struct drm_connector *connector)
 210{
 211        return container_of(connector, struct vc4_vec_connector, base);
 212}
 213
 214enum vc4_vec_tv_mode_id {
 215        VC4_VEC_TV_MODE_NTSC,
 216        VC4_VEC_TV_MODE_NTSC_J,
 217        VC4_VEC_TV_MODE_PAL,
 218        VC4_VEC_TV_MODE_PAL_M,
 219};
 220
 221struct vc4_vec_tv_mode {
 222        const struct drm_display_mode *mode;
 223        void (*mode_set)(struct vc4_vec *vec);
 224};
 225
 226#define VEC_REG(reg) { reg, #reg }
 227static const struct {
 228        u32 reg;
 229        const char *name;
 230} vec_regs[] = {
 231        VEC_REG(VEC_WSE_CONTROL),
 232        VEC_REG(VEC_WSE_WSS_DATA),
 233        VEC_REG(VEC_WSE_VPS_DATA1),
 234        VEC_REG(VEC_WSE_VPS_CONTROL),
 235        VEC_REG(VEC_REVID),
 236        VEC_REG(VEC_CONFIG0),
 237        VEC_REG(VEC_SCHPH),
 238        VEC_REG(VEC_CLMP0_START),
 239        VEC_REG(VEC_CLMP0_END),
 240        VEC_REG(VEC_FREQ3_2),
 241        VEC_REG(VEC_FREQ1_0),
 242        VEC_REG(VEC_CONFIG1),
 243        VEC_REG(VEC_CONFIG2),
 244        VEC_REG(VEC_INTERRUPT_CONTROL),
 245        VEC_REG(VEC_INTERRUPT_STATUS),
 246        VEC_REG(VEC_FCW_SECAM_B),
 247        VEC_REG(VEC_SECAM_GAIN_VAL),
 248        VEC_REG(VEC_CONFIG3),
 249        VEC_REG(VEC_STATUS0),
 250        VEC_REG(VEC_MASK0),
 251        VEC_REG(VEC_CFG),
 252        VEC_REG(VEC_DAC_TEST),
 253        VEC_REG(VEC_DAC_CONFIG),
 254        VEC_REG(VEC_DAC_MISC),
 255};
 256
 257#ifdef CONFIG_DEBUG_FS
 258int vc4_vec_debugfs_regs(struct seq_file *m, void *unused)
 259{
 260        struct drm_info_node *node = (struct drm_info_node *)m->private;
 261        struct drm_device *dev = node->minor->dev;
 262        struct vc4_dev *vc4 = to_vc4_dev(dev);
 263        struct vc4_vec *vec = vc4->vec;
 264        int i;
 265
 266        if (!vec)
 267                return 0;
 268
 269        for (i = 0; i < ARRAY_SIZE(vec_regs); i++) {
 270                seq_printf(m, "%s (0x%04x): 0x%08x\n",
 271                           vec_regs[i].name, vec_regs[i].reg,
 272                           VEC_READ(vec_regs[i].reg));
 273        }
 274
 275        return 0;
 276}
 277#endif
 278
 279static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec)
 280{
 281        VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN);
 282        VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
 283}
 284
 285static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec)
 286{
 287        VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD);
 288        VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
 289}
 290
 291static const struct drm_display_mode ntsc_mode = {
 292        DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
 293                 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
 294                 480, 480 + 3, 480 + 3 + 3, 480 + 3 + 3 + 16, 0,
 295                 DRM_MODE_FLAG_INTERLACE)
 296};
 297
 298static void vc4_vec_pal_mode_set(struct vc4_vec *vec)
 299{
 300        VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
 301        VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
 302}
 303
 304static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec)
 305{
 306        VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
 307        VEC_WRITE(VEC_CONFIG1,
 308                  VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ);
 309        VEC_WRITE(VEC_FREQ3_2, 0x223b);
 310        VEC_WRITE(VEC_FREQ1_0, 0x61d1);
 311}
 312
 313static const struct drm_display_mode pal_mode = {
 314        DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
 315                 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
 316                 576, 576 + 2, 576 + 2 + 3, 576 + 2 + 3 + 20, 0,
 317                 DRM_MODE_FLAG_INTERLACE)
 318};
 319
 320static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
 321        [VC4_VEC_TV_MODE_NTSC] = {
 322                .mode = &ntsc_mode,
 323                .mode_set = vc4_vec_ntsc_mode_set,
 324        },
 325        [VC4_VEC_TV_MODE_NTSC_J] = {
 326                .mode = &ntsc_mode,
 327                .mode_set = vc4_vec_ntsc_j_mode_set,
 328        },
 329        [VC4_VEC_TV_MODE_PAL] = {
 330                .mode = &pal_mode,
 331                .mode_set = vc4_vec_pal_mode_set,
 332        },
 333        [VC4_VEC_TV_MODE_PAL_M] = {
 334                .mode = &pal_mode,
 335                .mode_set = vc4_vec_pal_m_mode_set,
 336        },
 337};
 338
 339static enum drm_connector_status
 340vc4_vec_connector_detect(struct drm_connector *connector, bool force)
 341{
 342        return connector_status_unknown;
 343}
 344
 345static void vc4_vec_connector_destroy(struct drm_connector *connector)
 346{
 347        drm_connector_unregister(connector);
 348        drm_connector_cleanup(connector);
 349}
 350
 351static int vc4_vec_connector_get_modes(struct drm_connector *connector)
 352{
 353        struct drm_connector_state *state = connector->state;
 354        struct drm_display_mode *mode;
 355
 356        mode = drm_mode_duplicate(connector->dev,
 357                                  vc4_vec_tv_modes[state->tv.mode].mode);
 358        if (!mode) {
 359                DRM_ERROR("Failed to create a new display mode\n");
 360                return -ENOMEM;
 361        }
 362
 363        drm_mode_probed_add(connector, mode);
 364
 365        return 1;
 366}
 367
 368static const struct drm_connector_funcs vc4_vec_connector_funcs = {
 369        .detect = vc4_vec_connector_detect,
 370        .fill_modes = drm_helper_probe_single_connector_modes,
 371        .destroy = vc4_vec_connector_destroy,
 372        .reset = drm_atomic_helper_connector_reset,
 373        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 374        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 375};
 376
 377static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = {
 378        .get_modes = vc4_vec_connector_get_modes,
 379};
 380
 381static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev,
 382                                                    struct vc4_vec *vec)
 383{
 384        struct drm_connector *connector = NULL;
 385        struct vc4_vec_connector *vec_connector;
 386
 387        vec_connector = devm_kzalloc(dev->dev, sizeof(*vec_connector),
 388                                     GFP_KERNEL);
 389        if (!vec_connector)
 390                return ERR_PTR(-ENOMEM);
 391
 392        connector = &vec_connector->base;
 393        connector->interlace_allowed = true;
 394
 395        vec_connector->encoder = vec->encoder;
 396        vec_connector->vec = vec;
 397
 398        drm_connector_init(dev, connector, &vc4_vec_connector_funcs,
 399                           DRM_MODE_CONNECTOR_Composite);
 400        drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs);
 401
 402        drm_object_attach_property(&connector->base,
 403                                   dev->mode_config.tv_mode_property,
 404                                   VC4_VEC_TV_MODE_NTSC);
 405        vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC];
 406
 407        drm_mode_connector_attach_encoder(connector, vec->encoder);
 408
 409        return connector;
 410}
 411
 412static const struct drm_encoder_funcs vc4_vec_encoder_funcs = {
 413        .destroy = drm_encoder_cleanup,
 414};
 415
 416static void vc4_vec_encoder_disable(struct drm_encoder *encoder)
 417{
 418        struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
 419        struct vc4_vec *vec = vc4_vec_encoder->vec;
 420        int ret;
 421
 422        VEC_WRITE(VEC_CFG, 0);
 423        VEC_WRITE(VEC_DAC_MISC,
 424                  VEC_DAC_MISC_VCD_PWRDN |
 425                  VEC_DAC_MISC_BIAS_PWRDN |
 426                  VEC_DAC_MISC_DAC_PWRDN |
 427                  VEC_DAC_MISC_LDO_PWRDN);
 428
 429        clk_disable_unprepare(vec->clock);
 430
 431        ret = pm_runtime_put(&vec->pdev->dev);
 432        if (ret < 0) {
 433                DRM_ERROR("Failed to release power domain: %d\n", ret);
 434                return;
 435        }
 436}
 437
 438static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
 439{
 440        struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
 441        struct vc4_vec *vec = vc4_vec_encoder->vec;
 442        int ret;
 443
 444        ret = pm_runtime_get_sync(&vec->pdev->dev);
 445        if (ret < 0) {
 446                DRM_ERROR("Failed to retain power domain: %d\n", ret);
 447                return;
 448        }
 449
 450        /*
 451         * We need to set the clock rate each time we enable the encoder
 452         * because there's a chance we share the same parent with the HDMI
 453         * clock, and both drivers are requesting different rates.
 454         * The good news is, these 2 encoders cannot be enabled at the same
 455         * time, thus preventing incompatible rate requests.
 456         */
 457        ret = clk_set_rate(vec->clock, 108000000);
 458        if (ret) {
 459                DRM_ERROR("Failed to set clock rate: %d\n", ret);
 460                return;
 461        }
 462
 463        ret = clk_prepare_enable(vec->clock);
 464        if (ret) {
 465                DRM_ERROR("Failed to turn on core clock: %d\n", ret);
 466                return;
 467        }
 468
 469        /* Reset the different blocks */
 470        VEC_WRITE(VEC_WSE_RESET, 1);
 471        VEC_WRITE(VEC_SOFT_RESET, 1);
 472
 473        /* Disable the CGSM-A and WSE blocks */
 474        VEC_WRITE(VEC_WSE_CONTROL, 0);
 475
 476        /* Write config common to all modes. */
 477
 478        /*
 479         * Color subcarrier phase: phase = 360 * SCHPH / 256.
 480         * 0x28 <=> 39.375 deg.
 481         */
 482        VEC_WRITE(VEC_SCHPH, 0x28);
 483
 484        /*
 485         * Reset to default values.
 486         */
 487        VEC_WRITE(VEC_CLMP0_START, 0xac);
 488        VEC_WRITE(VEC_CLMP0_END, 0xec);
 489        VEC_WRITE(VEC_CONFIG2,
 490                  VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS);
 491        VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
 492        VEC_WRITE(VEC_DAC_CONFIG,
 493                  VEC_DAC_CONFIG_DAC_CTRL(0xc) |
 494                  VEC_DAC_CONFIG_DRIVER_CTRL(0xc) |
 495                  VEC_DAC_CONFIG_LDO_BIAS_CTRL(0x46));
 496
 497        /* Mask all interrupts. */
 498        VEC_WRITE(VEC_MASK0, 0);
 499
 500        vec->tv_mode->mode_set(vec);
 501
 502        VEC_WRITE(VEC_DAC_MISC,
 503                  VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N);
 504        VEC_WRITE(VEC_CFG, VEC_CFG_VEC_EN);
 505}
 506
 507
 508static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder,
 509                                       const struct drm_display_mode *mode,
 510                                       struct drm_display_mode *adjusted_mode)
 511{
 512        return true;
 513}
 514
 515static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder,
 516                                        struct drm_crtc_state *crtc_state,
 517                                        struct drm_connector_state *conn_state)
 518{
 519        struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
 520        struct vc4_vec *vec = vc4_vec_encoder->vec;
 521
 522        vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
 523}
 524
 525static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
 526                                        struct drm_crtc_state *crtc_state,
 527                                        struct drm_connector_state *conn_state)
 528{
 529        const struct vc4_vec_tv_mode *vec_mode;
 530
 531        vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
 532
 533        if (conn_state->crtc &&
 534            !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
 535                return -EINVAL;
 536
 537        return 0;
 538}
 539
 540static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
 541        .disable = vc4_vec_encoder_disable,
 542        .enable = vc4_vec_encoder_enable,
 543        .mode_fixup = vc4_vec_encoder_mode_fixup,
 544        .atomic_check = vc4_vec_encoder_atomic_check,
 545        .atomic_mode_set = vc4_vec_encoder_atomic_mode_set,
 546};
 547
 548static const struct of_device_id vc4_vec_dt_match[] = {
 549        { .compatible = "brcm,bcm2835-vec", .data = NULL },
 550        { /* sentinel */ },
 551};
 552
 553static const char * const tv_mode_names[] = {
 554        [VC4_VEC_TV_MODE_NTSC] = "NTSC",
 555        [VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
 556        [VC4_VEC_TV_MODE_PAL] = "PAL",
 557        [VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
 558};
 559
 560static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
 561{
 562        struct platform_device *pdev = to_platform_device(dev);
 563        struct drm_device *drm = dev_get_drvdata(master);
 564        struct vc4_dev *vc4 = to_vc4_dev(drm);
 565        struct vc4_vec *vec;
 566        struct vc4_vec_encoder *vc4_vec_encoder;
 567        int ret;
 568
 569        ret = drm_mode_create_tv_properties(drm, ARRAY_SIZE(tv_mode_names),
 570                                            tv_mode_names);
 571        if (ret)
 572                return ret;
 573
 574        vec = devm_kzalloc(dev, sizeof(*vec), GFP_KERNEL);
 575        if (!vec)
 576                return -ENOMEM;
 577
 578        vc4_vec_encoder = devm_kzalloc(dev, sizeof(*vc4_vec_encoder),
 579                                       GFP_KERNEL);
 580        if (!vc4_vec_encoder)
 581                return -ENOMEM;
 582        vc4_vec_encoder->base.type = VC4_ENCODER_TYPE_VEC;
 583        vc4_vec_encoder->vec = vec;
 584        vec->encoder = &vc4_vec_encoder->base.base;
 585
 586        vec->pdev = pdev;
 587        vec->regs = vc4_ioremap_regs(pdev, 0);
 588        if (IS_ERR(vec->regs))
 589                return PTR_ERR(vec->regs);
 590
 591        vec->clock = devm_clk_get(dev, NULL);
 592        if (IS_ERR(vec->clock)) {
 593                ret = PTR_ERR(vec->clock);
 594                if (ret != -EPROBE_DEFER)
 595                        DRM_ERROR("Failed to get clock: %d\n", ret);
 596                return ret;
 597        }
 598
 599        pm_runtime_enable(dev);
 600
 601        drm_encoder_init(drm, vec->encoder, &vc4_vec_encoder_funcs,
 602                         DRM_MODE_ENCODER_TVDAC, NULL);
 603        drm_encoder_helper_add(vec->encoder, &vc4_vec_encoder_helper_funcs);
 604
 605        vec->connector = vc4_vec_connector_init(drm, vec);
 606        if (IS_ERR(vec->connector)) {
 607                ret = PTR_ERR(vec->connector);
 608                goto err_destroy_encoder;
 609        }
 610
 611        dev_set_drvdata(dev, vec);
 612
 613        vc4->vec = vec;
 614
 615        return 0;
 616
 617err_destroy_encoder:
 618        drm_encoder_cleanup(vec->encoder);
 619        pm_runtime_disable(dev);
 620
 621        return ret;
 622}
 623
 624static void vc4_vec_unbind(struct device *dev, struct device *master,
 625                           void *data)
 626{
 627        struct drm_device *drm = dev_get_drvdata(master);
 628        struct vc4_dev *vc4 = to_vc4_dev(drm);
 629        struct vc4_vec *vec = dev_get_drvdata(dev);
 630
 631        vc4_vec_connector_destroy(vec->connector);
 632        drm_encoder_cleanup(vec->encoder);
 633        pm_runtime_disable(dev);
 634
 635        vc4->vec = NULL;
 636}
 637
 638static const struct component_ops vc4_vec_ops = {
 639        .bind   = vc4_vec_bind,
 640        .unbind = vc4_vec_unbind,
 641};
 642
 643static int vc4_vec_dev_probe(struct platform_device *pdev)
 644{
 645        return component_add(&pdev->dev, &vc4_vec_ops);
 646}
 647
 648static int vc4_vec_dev_remove(struct platform_device *pdev)
 649{
 650        component_del(&pdev->dev, &vc4_vec_ops);
 651        return 0;
 652}
 653
 654struct platform_driver vc4_vec_driver = {
 655        .probe = vc4_vec_dev_probe,
 656        .remove = vc4_vec_dev_remove,
 657        .driver = {
 658                .name = "vc4_vec",
 659                .of_match_table = vc4_vec_dt_match,
 660        },
 661};
 662