linux/drivers/gpu/drm/sti/sti_tvout.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) STMicroelectronics SA 2014
   4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
   5 *          Vincent Abriou <vincent.abriou@st.com>
   6 *          for STMicroelectronics.
   7 */
   8
   9#include <linux/clk.h>
  10#include <linux/component.h>
  11#include <linux/io.h>
  12#include <linux/module.h>
  13#include <linux/of_platform.h>
  14#include <linux/platform_device.h>
  15#include <linux/reset.h>
  16#include <linux/seq_file.h>
  17
  18#include <drm/drm_atomic_helper.h>
  19#include <drm/drm_debugfs.h>
  20#include <drm/drm_device.h>
  21#include <drm/drm_file.h>
  22#include <drm/drm_print.h>
  23
  24#include "sti_crtc.h"
  25#include "sti_drv.h"
  26#include "sti_vtg.h"
  27
  28/* glue registers */
  29#define TVO_CSC_MAIN_M0                  0x000
  30#define TVO_CSC_MAIN_M1                  0x004
  31#define TVO_CSC_MAIN_M2                  0x008
  32#define TVO_CSC_MAIN_M3                  0x00c
  33#define TVO_CSC_MAIN_M4                  0x010
  34#define TVO_CSC_MAIN_M5                  0x014
  35#define TVO_CSC_MAIN_M6                  0x018
  36#define TVO_CSC_MAIN_M7                  0x01c
  37#define TVO_MAIN_IN_VID_FORMAT           0x030
  38#define TVO_CSC_AUX_M0                   0x100
  39#define TVO_CSC_AUX_M1                   0x104
  40#define TVO_CSC_AUX_M2                   0x108
  41#define TVO_CSC_AUX_M3                   0x10c
  42#define TVO_CSC_AUX_M4                   0x110
  43#define TVO_CSC_AUX_M5                   0x114
  44#define TVO_CSC_AUX_M6                   0x118
  45#define TVO_CSC_AUX_M7                   0x11c
  46#define TVO_AUX_IN_VID_FORMAT            0x130
  47#define TVO_VIP_HDF                      0x400
  48#define TVO_HD_SYNC_SEL                  0x418
  49#define TVO_HD_DAC_CFG_OFF               0x420
  50#define TVO_VIP_HDMI                     0x500
  51#define TVO_HDMI_FORCE_COLOR_0           0x504
  52#define TVO_HDMI_FORCE_COLOR_1           0x508
  53#define TVO_HDMI_CLIP_VALUE_B_CB         0x50c
  54#define TVO_HDMI_CLIP_VALUE_Y_G          0x510
  55#define TVO_HDMI_CLIP_VALUE_R_CR         0x514
  56#define TVO_HDMI_SYNC_SEL                0x518
  57#define TVO_HDMI_DFV_OBS                 0x540
  58#define TVO_VIP_DVO                      0x600
  59#define TVO_DVO_SYNC_SEL                 0x618
  60#define TVO_DVO_CONFIG                   0x620
  61
  62#define TVO_IN_FMT_SIGNED                BIT(0)
  63#define TVO_SYNC_EXT                     BIT(4)
  64
  65#define TVO_VIP_REORDER_R_SHIFT          24
  66#define TVO_VIP_REORDER_G_SHIFT          20
  67#define TVO_VIP_REORDER_B_SHIFT          16
  68#define TVO_VIP_REORDER_MASK             0x3
  69#define TVO_VIP_REORDER_Y_G_SEL          0
  70#define TVO_VIP_REORDER_CB_B_SEL         1
  71#define TVO_VIP_REORDER_CR_R_SEL         2
  72
  73#define TVO_VIP_CLIP_SHIFT               8
  74#define TVO_VIP_CLIP_MASK                0x7
  75#define TVO_VIP_CLIP_DISABLED            0
  76#define TVO_VIP_CLIP_EAV_SAV             1
  77#define TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y 2
  78#define TVO_VIP_CLIP_LIMITED_RANGE_CB_CR 3
  79#define TVO_VIP_CLIP_PROG_RANGE          4
  80
  81#define TVO_VIP_RND_SHIFT                4
  82#define TVO_VIP_RND_MASK                 0x3
  83#define TVO_VIP_RND_8BIT_ROUNDED         0
  84#define TVO_VIP_RND_10BIT_ROUNDED        1
  85#define TVO_VIP_RND_12BIT_ROUNDED        2
  86
  87#define TVO_VIP_SEL_INPUT_MASK           0xf
  88#define TVO_VIP_SEL_INPUT_MAIN           0x0
  89#define TVO_VIP_SEL_INPUT_AUX            0x8
  90#define TVO_VIP_SEL_INPUT_FORCE_COLOR    0xf
  91#define TVO_VIP_SEL_INPUT_BYPASS_MASK    0x1
  92#define TVO_VIP_SEL_INPUT_BYPASSED       1
  93
  94#define TVO_SYNC_MAIN_VTG_SET_REF        0x00
  95#define TVO_SYNC_AUX_VTG_SET_REF         0x10
  96
  97#define TVO_SYNC_HD_DCS_SHIFT            8
  98
  99#define TVO_SYNC_DVO_PAD_HSYNC_SHIFT     8
 100#define TVO_SYNC_DVO_PAD_VSYNC_SHIFT     16
 101
 102#define ENCODER_CRTC_MASK                (BIT(0) | BIT(1))
 103
 104#define TVO_MIN_HD_HEIGHT                720
 105
 106/* enum listing the supported output data format */
 107enum sti_tvout_video_out_type {
 108        STI_TVOUT_VIDEO_OUT_RGB,
 109        STI_TVOUT_VIDEO_OUT_YUV,
 110};
 111
 112struct sti_tvout {
 113        struct device *dev;
 114        struct drm_device *drm_dev;
 115        void __iomem *regs;
 116        struct reset_control *reset;
 117        struct drm_encoder *hdmi;
 118        struct drm_encoder *hda;
 119        struct drm_encoder *dvo;
 120        bool debugfs_registered;
 121};
 122
 123struct sti_tvout_encoder {
 124        struct drm_encoder encoder;
 125        struct sti_tvout *tvout;
 126};
 127
 128#define to_sti_tvout_encoder(x) \
 129        container_of(x, struct sti_tvout_encoder, encoder)
 130
 131#define to_sti_tvout(x) to_sti_tvout_encoder(x)->tvout
 132
 133/* preformatter conversion matrix */
 134static const u32 rgb_to_ycbcr_601[8] = {
 135        0xF927082E, 0x04C9FEAB, 0x01D30964, 0xFA95FD3D,
 136        0x0000082E, 0x00002000, 0x00002000, 0x00000000
 137};
 138
 139/* 709 RGB to YCbCr */
 140static const u32 rgb_to_ycbcr_709[8] = {
 141        0xF891082F, 0x0367FF40, 0x01280B71, 0xF9B1FE20,
 142        0x0000082F, 0x00002000, 0x00002000, 0x00000000
 143};
 144
 145static u32 tvout_read(struct sti_tvout *tvout, int offset)
 146{
 147        return readl(tvout->regs + offset);
 148}
 149
 150static void tvout_write(struct sti_tvout *tvout, u32 val, int offset)
 151{
 152        writel(val, tvout->regs + offset);
 153}
 154
 155/**
 156 * tvout_vip_set_color_order - Set the clipping mode of a VIP
 157 *
 158 * @tvout: tvout structure
 159 * @reg: register to set
 160 * @cr_r: red chroma or red order
 161 * @y_g: y or green order
 162 * @cb_b: blue chroma or blue order
 163 */
 164static void tvout_vip_set_color_order(struct sti_tvout *tvout, int reg,
 165                                      u32 cr_r, u32 y_g, u32 cb_b)
 166{
 167        u32 val = tvout_read(tvout, reg);
 168
 169        val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT);
 170        val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT);
 171        val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_B_SHIFT);
 172        val |= cr_r << TVO_VIP_REORDER_R_SHIFT;
 173        val |= y_g << TVO_VIP_REORDER_G_SHIFT;
 174        val |= cb_b << TVO_VIP_REORDER_B_SHIFT;
 175
 176        tvout_write(tvout, val, reg);
 177}
 178
 179/**
 180 * tvout_vip_set_clip_mode - Set the clipping mode of a VIP
 181 *
 182 * @tvout: tvout structure
 183 * @reg: register to set
 184 * @range: clipping range
 185 */
 186static void tvout_vip_set_clip_mode(struct sti_tvout *tvout, int reg, u32 range)
 187{
 188        u32 val = tvout_read(tvout, reg);
 189
 190        val &= ~(TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT);
 191        val |= range << TVO_VIP_CLIP_SHIFT;
 192        tvout_write(tvout, val, reg);
 193}
 194
 195/**
 196 * tvout_vip_set_rnd - Set the rounded value of a VIP
 197 *
 198 * @tvout: tvout structure
 199 * @reg: register to set
 200 * @rnd: rounded val per component
 201 */
 202static void tvout_vip_set_rnd(struct sti_tvout *tvout, int reg, u32 rnd)
 203{
 204        u32 val = tvout_read(tvout, reg);
 205
 206        val &= ~(TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT);
 207        val |= rnd << TVO_VIP_RND_SHIFT;
 208        tvout_write(tvout, val, reg);
 209}
 210
 211/**
 212 * tvout_vip_set_sel_input - Select the VIP input
 213 *
 214 * @tvout: tvout structure
 215 * @reg: register to set
 216 * @main_path: main or auxiliary path
 217 * @video_out: selected_input (main/aux + conv)
 218 */
 219static void tvout_vip_set_sel_input(struct sti_tvout *tvout,
 220                                    int reg,
 221                                    bool main_path,
 222                                    enum sti_tvout_video_out_type video_out)
 223{
 224        u32 sel_input;
 225        u32 val = tvout_read(tvout, reg);
 226
 227        if (main_path)
 228                sel_input = TVO_VIP_SEL_INPUT_MAIN;
 229        else
 230                sel_input = TVO_VIP_SEL_INPUT_AUX;
 231
 232        switch (video_out) {
 233        case STI_TVOUT_VIDEO_OUT_RGB:
 234                sel_input |= TVO_VIP_SEL_INPUT_BYPASSED;
 235                break;
 236        case STI_TVOUT_VIDEO_OUT_YUV:
 237                sel_input &= ~TVO_VIP_SEL_INPUT_BYPASSED;
 238                break;
 239        }
 240
 241        /* on stih407 chip the sel_input bypass mode logic is inverted */
 242        sel_input = sel_input ^ TVO_VIP_SEL_INPUT_BYPASS_MASK;
 243
 244        val &= ~TVO_VIP_SEL_INPUT_MASK;
 245        val |= sel_input;
 246        tvout_write(tvout, val, reg);
 247}
 248
 249/**
 250 * tvout_vip_set_in_vid_fmt - Select the input video signed or unsigned
 251 *
 252 * @tvout: tvout structure
 253 * @reg: register to set
 254 * @in_vid_fmt: used video input format
 255 */
 256static void tvout_vip_set_in_vid_fmt(struct sti_tvout *tvout,
 257                int reg, u32 in_vid_fmt)
 258{
 259        u32 val = tvout_read(tvout, reg);
 260
 261        val &= ~TVO_IN_FMT_SIGNED;
 262        val |= in_vid_fmt;
 263        tvout_write(tvout, val, reg);
 264}
 265
 266/**
 267 * tvout_preformatter_set_matrix - Set preformatter matrix
 268 *
 269 * @tvout: tvout structure
 270 * @mode: display mode structure
 271 */
 272static void tvout_preformatter_set_matrix(struct sti_tvout *tvout,
 273                                          struct drm_display_mode *mode)
 274{
 275        unsigned int i;
 276        const u32 *pf_matrix;
 277
 278        if (mode->vdisplay >= TVO_MIN_HD_HEIGHT)
 279                pf_matrix = rgb_to_ycbcr_709;
 280        else
 281                pf_matrix = rgb_to_ycbcr_601;
 282
 283        for (i = 0; i < 8; i++) {
 284                tvout_write(tvout, *(pf_matrix + i),
 285                            TVO_CSC_MAIN_M0 + (i * 4));
 286                tvout_write(tvout, *(pf_matrix + i),
 287                            TVO_CSC_AUX_M0 + (i * 4));
 288        }
 289}
 290
 291/**
 292 * tvout_dvo_start - Start VIP block for DVO output
 293 *
 294 * @tvout: pointer on tvout structure
 295 * @main_path: true if main path has to be used in the vip configuration
 296 *        else aux path is used.
 297 */
 298static void tvout_dvo_start(struct sti_tvout *tvout, bool main_path)
 299{
 300        u32 tvo_in_vid_format;
 301        int val, tmp;
 302
 303        dev_dbg(tvout->dev, "%s\n", __func__);
 304
 305        if (main_path) {
 306                DRM_DEBUG_DRIVER("main vip for DVO\n");
 307                /* Select the input sync for dvo */
 308                tmp = TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_DVO;
 309                val  = tmp << TVO_SYNC_DVO_PAD_VSYNC_SHIFT;
 310                val |= tmp << TVO_SYNC_DVO_PAD_HSYNC_SHIFT;
 311                val |= tmp;
 312                tvout_write(tvout, val, TVO_DVO_SYNC_SEL);
 313                tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT;
 314        } else {
 315                DRM_DEBUG_DRIVER("aux vip for DVO\n");
 316                /* Select the input sync for dvo */
 317                tmp = TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_DVO;
 318                val  = tmp << TVO_SYNC_DVO_PAD_VSYNC_SHIFT;
 319                val |= tmp << TVO_SYNC_DVO_PAD_HSYNC_SHIFT;
 320                val |= tmp;
 321                tvout_write(tvout, val, TVO_DVO_SYNC_SEL);
 322                tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT;
 323        }
 324
 325        /* Set color channel order */
 326        tvout_vip_set_color_order(tvout, TVO_VIP_DVO,
 327                                  TVO_VIP_REORDER_CR_R_SEL,
 328                                  TVO_VIP_REORDER_Y_G_SEL,
 329                                  TVO_VIP_REORDER_CB_B_SEL);
 330
 331        /* Set clipping mode */
 332        tvout_vip_set_clip_mode(tvout, TVO_VIP_DVO, TVO_VIP_CLIP_DISABLED);
 333
 334        /* Set round mode (rounded to 8-bit per component) */
 335        tvout_vip_set_rnd(tvout, TVO_VIP_DVO, TVO_VIP_RND_8BIT_ROUNDED);
 336
 337        /* Set input video format */
 338        tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, TVO_IN_FMT_SIGNED);
 339
 340        /* Input selection */
 341        tvout_vip_set_sel_input(tvout, TVO_VIP_DVO, main_path,
 342                                STI_TVOUT_VIDEO_OUT_RGB);
 343}
 344
 345/**
 346 * tvout_hdmi_start - Start VIP block for HDMI output
 347 *
 348 * @tvout: pointer on tvout structure
 349 * @main_path: true if main path has to be used in the vip configuration
 350 *        else aux path is used.
 351 */
 352static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path)
 353{
 354        u32 tvo_in_vid_format;
 355
 356        dev_dbg(tvout->dev, "%s\n", __func__);
 357
 358        if (main_path) {
 359                DRM_DEBUG_DRIVER("main vip for hdmi\n");
 360                /* select the input sync for hdmi */
 361                tvout_write(tvout,
 362                            TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_HDMI,
 363                            TVO_HDMI_SYNC_SEL);
 364                tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT;
 365        } else {
 366                DRM_DEBUG_DRIVER("aux vip for hdmi\n");
 367                /* select the input sync for hdmi */
 368                tvout_write(tvout,
 369                            TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_HDMI,
 370                            TVO_HDMI_SYNC_SEL);
 371                tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT;
 372        }
 373
 374        /* set color channel order */
 375        tvout_vip_set_color_order(tvout, TVO_VIP_HDMI,
 376                                  TVO_VIP_REORDER_CR_R_SEL,
 377                                  TVO_VIP_REORDER_Y_G_SEL,
 378                                  TVO_VIP_REORDER_CB_B_SEL);
 379
 380        /* set clipping mode */
 381        tvout_vip_set_clip_mode(tvout, TVO_VIP_HDMI, TVO_VIP_CLIP_DISABLED);
 382
 383        /* set round mode (rounded to 8-bit per component) */
 384        tvout_vip_set_rnd(tvout, TVO_VIP_HDMI, TVO_VIP_RND_8BIT_ROUNDED);
 385
 386        /* set input video format */
 387        tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, TVO_IN_FMT_SIGNED);
 388
 389        /* input selection */
 390        tvout_vip_set_sel_input(tvout, TVO_VIP_HDMI, main_path,
 391                                STI_TVOUT_VIDEO_OUT_RGB);
 392}
 393
 394/**
 395 * tvout_hda_start - Start HDF VIP and HD DAC
 396 *
 397 * @tvout: pointer on tvout structure
 398 * @main_path: true if main path has to be used in the vip configuration
 399 *        else aux path is used.
 400 */
 401static void tvout_hda_start(struct sti_tvout *tvout, bool main_path)
 402{
 403        u32 tvo_in_vid_format;
 404        int val;
 405
 406        dev_dbg(tvout->dev, "%s\n", __func__);
 407
 408        if (main_path) {
 409                DRM_DEBUG_DRIVER("main vip for HDF\n");
 410                /* Select the input sync for HD analog and HD DCS */
 411                val  = TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_HDDCS;
 412                val  = val << TVO_SYNC_HD_DCS_SHIFT;
 413                val |= TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_HDF;
 414                tvout_write(tvout, val, TVO_HD_SYNC_SEL);
 415                tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT;
 416        } else {
 417                DRM_DEBUG_DRIVER("aux vip for HDF\n");
 418                /* Select the input sync for HD analog and HD DCS */
 419                val  = TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_HDDCS;
 420                val  = val << TVO_SYNC_HD_DCS_SHIFT;
 421                val |= TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_HDF;
 422                tvout_write(tvout, val, TVO_HD_SYNC_SEL);
 423                tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT;
 424        }
 425
 426        /* set color channel order */
 427        tvout_vip_set_color_order(tvout, TVO_VIP_HDF,
 428                                  TVO_VIP_REORDER_CR_R_SEL,
 429                                  TVO_VIP_REORDER_Y_G_SEL,
 430                                  TVO_VIP_REORDER_CB_B_SEL);
 431
 432        /* set clipping mode */
 433        tvout_vip_set_clip_mode(tvout, TVO_VIP_HDF, TVO_VIP_CLIP_DISABLED);
 434
 435        /* set round mode (rounded to 10-bit per component) */
 436        tvout_vip_set_rnd(tvout, TVO_VIP_HDF, TVO_VIP_RND_10BIT_ROUNDED);
 437
 438        /* Set input video format */
 439        tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, TVO_IN_FMT_SIGNED);
 440
 441        /* Input selection */
 442        tvout_vip_set_sel_input(tvout, TVO_VIP_HDF, main_path,
 443                                STI_TVOUT_VIDEO_OUT_YUV);
 444
 445        /* power up HD DAC */
 446        tvout_write(tvout, 0, TVO_HD_DAC_CFG_OFF);
 447}
 448
 449#define DBGFS_DUMP(reg) seq_printf(s, "\n  %-25s 0x%08X", #reg, \
 450                                   readl(tvout->regs + reg))
 451
 452static void tvout_dbg_vip(struct seq_file *s, int val)
 453{
 454        int r, g, b, tmp, mask;
 455        char *const reorder[] = {"Y_G", "Cb_B", "Cr_R"};
 456        char *const clipping[] = {"No", "EAV/SAV", "Limited range RGB/Y",
 457                                  "Limited range Cb/Cr", "decided by register"};
 458        char *const round[] = {"8-bit", "10-bit", "12-bit"};
 459        char *const input_sel[] = {"Main (color matrix enabled)",
 460                                   "Main (color matrix by-passed)",
 461                                   "", "", "", "", "", "",
 462                                   "Aux (color matrix enabled)",
 463                                   "Aux (color matrix by-passed)",
 464                                   "", "", "", "", "", "Force value"};
 465
 466        seq_putc(s, '\t');
 467        mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT;
 468        r = (val & mask) >> TVO_VIP_REORDER_R_SHIFT;
 469        mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT;
 470        g = (val & mask) >> TVO_VIP_REORDER_G_SHIFT;
 471        mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_B_SHIFT;
 472        b = (val & mask) >> TVO_VIP_REORDER_B_SHIFT;
 473        seq_printf(s, "%-24s %s->%s %s->%s %s->%s\n", "Reorder:",
 474                   reorder[r], reorder[TVO_VIP_REORDER_CR_R_SEL],
 475                   reorder[g], reorder[TVO_VIP_REORDER_Y_G_SEL],
 476                   reorder[b], reorder[TVO_VIP_REORDER_CB_B_SEL]);
 477        seq_puts(s, "\t\t\t\t\t");
 478        mask = TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT;
 479        tmp = (val & mask) >> TVO_VIP_CLIP_SHIFT;
 480        seq_printf(s, "%-24s %s\n", "Clipping:", clipping[tmp]);
 481        seq_puts(s, "\t\t\t\t\t");
 482        mask = TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT;
 483        tmp = (val & mask) >> TVO_VIP_RND_SHIFT;
 484        seq_printf(s, "%-24s input data rounded to %s per component\n",
 485                   "Round:", round[tmp]);
 486        seq_puts(s, "\t\t\t\t\t");
 487        tmp = (val & TVO_VIP_SEL_INPUT_MASK);
 488        seq_printf(s, "%-24s %s", "Input selection:", input_sel[tmp]);
 489}
 490
 491static void tvout_dbg_hd_dac_cfg(struct seq_file *s, int val)
 492{
 493        seq_printf(s, "\t%-24s %s", "HD DAC:",
 494                   val & 1 ? "disabled" : "enabled");
 495}
 496
 497static int tvout_dbg_show(struct seq_file *s, void *data)
 498{
 499        struct drm_info_node *node = s->private;
 500        struct sti_tvout *tvout = (struct sti_tvout *)node->info_ent->data;
 501        struct drm_crtc *crtc;
 502
 503        seq_printf(s, "TVOUT: (vaddr = 0x%p)", tvout->regs);
 504
 505        seq_puts(s, "\n\n  HDMI encoder: ");
 506        crtc = tvout->hdmi->crtc;
 507        if (crtc) {
 508                seq_printf(s, "connected to %s path",
 509                           sti_crtc_is_main(crtc) ? "main" : "aux");
 510                DBGFS_DUMP(TVO_HDMI_SYNC_SEL);
 511                DBGFS_DUMP(TVO_VIP_HDMI);
 512                tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_HDMI));
 513        } else {
 514                seq_puts(s, "disabled");
 515        }
 516
 517        seq_puts(s, "\n\n  DVO encoder: ");
 518        crtc = tvout->dvo->crtc;
 519        if (crtc) {
 520                seq_printf(s, "connected to %s path",
 521                           sti_crtc_is_main(crtc) ? "main" : "aux");
 522                DBGFS_DUMP(TVO_DVO_SYNC_SEL);
 523                DBGFS_DUMP(TVO_DVO_CONFIG);
 524                DBGFS_DUMP(TVO_VIP_DVO);
 525                tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_DVO));
 526        } else {
 527                seq_puts(s, "disabled");
 528        }
 529
 530        seq_puts(s, "\n\n  HDA encoder: ");
 531        crtc = tvout->hda->crtc;
 532        if (crtc) {
 533                seq_printf(s, "connected to %s path",
 534                           sti_crtc_is_main(crtc) ? "main" : "aux");
 535                DBGFS_DUMP(TVO_HD_SYNC_SEL);
 536                DBGFS_DUMP(TVO_HD_DAC_CFG_OFF);
 537                tvout_dbg_hd_dac_cfg(s,
 538                                     readl(tvout->regs + TVO_HD_DAC_CFG_OFF));
 539                DBGFS_DUMP(TVO_VIP_HDF);
 540                tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_HDF));
 541        } else {
 542                seq_puts(s, "disabled");
 543        }
 544
 545        seq_puts(s, "\n\n  main path configuration");
 546        DBGFS_DUMP(TVO_CSC_MAIN_M0);
 547        DBGFS_DUMP(TVO_CSC_MAIN_M1);
 548        DBGFS_DUMP(TVO_CSC_MAIN_M2);
 549        DBGFS_DUMP(TVO_CSC_MAIN_M3);
 550        DBGFS_DUMP(TVO_CSC_MAIN_M4);
 551        DBGFS_DUMP(TVO_CSC_MAIN_M5);
 552        DBGFS_DUMP(TVO_CSC_MAIN_M6);
 553        DBGFS_DUMP(TVO_CSC_MAIN_M7);
 554        DBGFS_DUMP(TVO_MAIN_IN_VID_FORMAT);
 555
 556        seq_puts(s, "\n\n  auxiliary path configuration");
 557        DBGFS_DUMP(TVO_CSC_AUX_M0);
 558        DBGFS_DUMP(TVO_CSC_AUX_M2);
 559        DBGFS_DUMP(TVO_CSC_AUX_M3);
 560        DBGFS_DUMP(TVO_CSC_AUX_M4);
 561        DBGFS_DUMP(TVO_CSC_AUX_M5);
 562        DBGFS_DUMP(TVO_CSC_AUX_M6);
 563        DBGFS_DUMP(TVO_CSC_AUX_M7);
 564        DBGFS_DUMP(TVO_AUX_IN_VID_FORMAT);
 565        seq_putc(s, '\n');
 566        return 0;
 567}
 568
 569static struct drm_info_list tvout_debugfs_files[] = {
 570        { "tvout", tvout_dbg_show, 0, NULL },
 571};
 572
 573static void tvout_debugfs_init(struct sti_tvout *tvout, struct drm_minor *minor)
 574{
 575        unsigned int i;
 576
 577        for (i = 0; i < ARRAY_SIZE(tvout_debugfs_files); i++)
 578                tvout_debugfs_files[i].data = tvout;
 579
 580        drm_debugfs_create_files(tvout_debugfs_files,
 581                                 ARRAY_SIZE(tvout_debugfs_files),
 582                                 minor->debugfs_root, minor);
 583}
 584
 585static void sti_tvout_encoder_dpms(struct drm_encoder *encoder, int mode)
 586{
 587}
 588
 589static void sti_tvout_encoder_mode_set(struct drm_encoder *encoder,
 590                                       struct drm_display_mode *mode,
 591                                       struct drm_display_mode *adjusted_mode)
 592{
 593}
 594
 595static void sti_tvout_encoder_destroy(struct drm_encoder *encoder)
 596{
 597        struct sti_tvout_encoder *sti_encoder = to_sti_tvout_encoder(encoder);
 598
 599        drm_encoder_cleanup(encoder);
 600        kfree(sti_encoder);
 601}
 602
 603static int sti_tvout_late_register(struct drm_encoder *encoder)
 604{
 605        struct sti_tvout *tvout = to_sti_tvout(encoder);
 606
 607        if (tvout->debugfs_registered)
 608                return 0;
 609
 610        tvout_debugfs_init(tvout, encoder->dev->primary);
 611
 612        tvout->debugfs_registered = true;
 613        return 0;
 614}
 615
 616static void sti_tvout_early_unregister(struct drm_encoder *encoder)
 617{
 618        struct sti_tvout *tvout = to_sti_tvout(encoder);
 619
 620        if (!tvout->debugfs_registered)
 621                return;
 622
 623        tvout->debugfs_registered = false;
 624}
 625
 626static const struct drm_encoder_funcs sti_tvout_encoder_funcs = {
 627        .destroy = sti_tvout_encoder_destroy,
 628        .late_register = sti_tvout_late_register,
 629        .early_unregister = sti_tvout_early_unregister,
 630};
 631
 632static void sti_dvo_encoder_enable(struct drm_encoder *encoder)
 633{
 634        struct sti_tvout *tvout = to_sti_tvout(encoder);
 635
 636        tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode);
 637
 638        tvout_dvo_start(tvout, sti_crtc_is_main(encoder->crtc));
 639}
 640
 641static void sti_dvo_encoder_disable(struct drm_encoder *encoder)
 642{
 643        struct sti_tvout *tvout = to_sti_tvout(encoder);
 644
 645        /* Reset VIP register */
 646        tvout_write(tvout, 0x0, TVO_VIP_DVO);
 647}
 648
 649static const struct drm_encoder_helper_funcs sti_dvo_encoder_helper_funcs = {
 650        .dpms = sti_tvout_encoder_dpms,
 651        .mode_set = sti_tvout_encoder_mode_set,
 652        .enable = sti_dvo_encoder_enable,
 653        .disable = sti_dvo_encoder_disable,
 654};
 655
 656static struct drm_encoder *
 657sti_tvout_create_dvo_encoder(struct drm_device *dev,
 658                             struct sti_tvout *tvout)
 659{
 660        struct sti_tvout_encoder *encoder;
 661        struct drm_encoder *drm_encoder;
 662
 663        encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL);
 664        if (!encoder)
 665                return NULL;
 666
 667        encoder->tvout = tvout;
 668
 669        drm_encoder = &encoder->encoder;
 670
 671        drm_encoder->possible_crtcs = ENCODER_CRTC_MASK;
 672
 673        drm_encoder_init(dev, drm_encoder,
 674                         &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_LVDS,
 675                         NULL);
 676
 677        drm_encoder_helper_add(drm_encoder, &sti_dvo_encoder_helper_funcs);
 678
 679        return drm_encoder;
 680}
 681
 682static void sti_hda_encoder_enable(struct drm_encoder *encoder)
 683{
 684        struct sti_tvout *tvout = to_sti_tvout(encoder);
 685
 686        tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode);
 687
 688        tvout_hda_start(tvout, sti_crtc_is_main(encoder->crtc));
 689}
 690
 691static void sti_hda_encoder_disable(struct drm_encoder *encoder)
 692{
 693        struct sti_tvout *tvout = to_sti_tvout(encoder);
 694
 695        /* reset VIP register */
 696        tvout_write(tvout, 0x0, TVO_VIP_HDF);
 697
 698        /* power down HD DAC */
 699        tvout_write(tvout, 1, TVO_HD_DAC_CFG_OFF);
 700}
 701
 702static const struct drm_encoder_helper_funcs sti_hda_encoder_helper_funcs = {
 703        .dpms = sti_tvout_encoder_dpms,
 704        .mode_set = sti_tvout_encoder_mode_set,
 705        .commit = sti_hda_encoder_enable,
 706        .disable = sti_hda_encoder_disable,
 707};
 708
 709static struct drm_encoder *sti_tvout_create_hda_encoder(struct drm_device *dev,
 710                struct sti_tvout *tvout)
 711{
 712        struct sti_tvout_encoder *encoder;
 713        struct drm_encoder *drm_encoder;
 714
 715        encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL);
 716        if (!encoder)
 717                return NULL;
 718
 719        encoder->tvout = tvout;
 720
 721        drm_encoder = &encoder->encoder;
 722
 723        drm_encoder->possible_crtcs = ENCODER_CRTC_MASK;
 724
 725        drm_encoder_init(dev, drm_encoder,
 726                        &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_DAC, NULL);
 727
 728        drm_encoder_helper_add(drm_encoder, &sti_hda_encoder_helper_funcs);
 729
 730        return drm_encoder;
 731}
 732
 733static void sti_hdmi_encoder_enable(struct drm_encoder *encoder)
 734{
 735        struct sti_tvout *tvout = to_sti_tvout(encoder);
 736
 737        tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode);
 738
 739        tvout_hdmi_start(tvout, sti_crtc_is_main(encoder->crtc));
 740}
 741
 742static void sti_hdmi_encoder_disable(struct drm_encoder *encoder)
 743{
 744        struct sti_tvout *tvout = to_sti_tvout(encoder);
 745
 746        /* reset VIP register */
 747        tvout_write(tvout, 0x0, TVO_VIP_HDMI);
 748}
 749
 750static const struct drm_encoder_helper_funcs sti_hdmi_encoder_helper_funcs = {
 751        .dpms = sti_tvout_encoder_dpms,
 752        .mode_set = sti_tvout_encoder_mode_set,
 753        .commit = sti_hdmi_encoder_enable,
 754        .disable = sti_hdmi_encoder_disable,
 755};
 756
 757static struct drm_encoder *sti_tvout_create_hdmi_encoder(struct drm_device *dev,
 758                struct sti_tvout *tvout)
 759{
 760        struct sti_tvout_encoder *encoder;
 761        struct drm_encoder *drm_encoder;
 762
 763        encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL);
 764        if (!encoder)
 765                return NULL;
 766
 767        encoder->tvout = tvout;
 768
 769        drm_encoder = &encoder->encoder;
 770
 771        drm_encoder->possible_crtcs = ENCODER_CRTC_MASK;
 772
 773        drm_encoder_init(dev, drm_encoder,
 774                        &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL);
 775
 776        drm_encoder_helper_add(drm_encoder, &sti_hdmi_encoder_helper_funcs);
 777
 778        return drm_encoder;
 779}
 780
 781static void sti_tvout_create_encoders(struct drm_device *dev,
 782                struct sti_tvout *tvout)
 783{
 784        tvout->hdmi = sti_tvout_create_hdmi_encoder(dev, tvout);
 785        tvout->hda = sti_tvout_create_hda_encoder(dev, tvout);
 786        tvout->dvo = sti_tvout_create_dvo_encoder(dev, tvout);
 787
 788        tvout->hdmi->possible_clones = drm_encoder_mask(tvout->hdmi) |
 789                drm_encoder_mask(tvout->hda) | drm_encoder_mask(tvout->dvo);
 790        tvout->hda->possible_clones = drm_encoder_mask(tvout->hdmi) |
 791                drm_encoder_mask(tvout->hda) | drm_encoder_mask(tvout->dvo);
 792        tvout->dvo->possible_clones = drm_encoder_mask(tvout->hdmi) |
 793                drm_encoder_mask(tvout->hda) | drm_encoder_mask(tvout->dvo);
 794}
 795
 796static void sti_tvout_destroy_encoders(struct sti_tvout *tvout)
 797{
 798        if (tvout->hdmi)
 799                drm_encoder_cleanup(tvout->hdmi);
 800        tvout->hdmi = NULL;
 801
 802        if (tvout->hda)
 803                drm_encoder_cleanup(tvout->hda);
 804        tvout->hda = NULL;
 805
 806        if (tvout->dvo)
 807                drm_encoder_cleanup(tvout->dvo);
 808        tvout->dvo = NULL;
 809}
 810
 811static int sti_tvout_bind(struct device *dev, struct device *master, void *data)
 812{
 813        struct sti_tvout *tvout = dev_get_drvdata(dev);
 814        struct drm_device *drm_dev = data;
 815
 816        tvout->drm_dev = drm_dev;
 817
 818        sti_tvout_create_encoders(drm_dev, tvout);
 819
 820        return 0;
 821}
 822
 823static void sti_tvout_unbind(struct device *dev, struct device *master,
 824        void *data)
 825{
 826        struct sti_tvout *tvout = dev_get_drvdata(dev);
 827
 828        sti_tvout_destroy_encoders(tvout);
 829}
 830
 831static const struct component_ops sti_tvout_ops = {
 832        .bind   = sti_tvout_bind,
 833        .unbind = sti_tvout_unbind,
 834};
 835
 836static int sti_tvout_probe(struct platform_device *pdev)
 837{
 838        struct device *dev = &pdev->dev;
 839        struct device_node *node = dev->of_node;
 840        struct sti_tvout *tvout;
 841        struct resource *res;
 842
 843        DRM_INFO("%s\n", __func__);
 844
 845        if (!node)
 846                return -ENODEV;
 847
 848        tvout = devm_kzalloc(dev, sizeof(*tvout), GFP_KERNEL);
 849        if (!tvout)
 850                return -ENOMEM;
 851
 852        tvout->dev = dev;
 853
 854        /* get memory resources */
 855        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tvout-reg");
 856        if (!res) {
 857                DRM_ERROR("Invalid glue resource\n");
 858                return -ENOMEM;
 859        }
 860        tvout->regs = devm_ioremap(dev, res->start, resource_size(res));
 861        if (!tvout->regs)
 862                return -ENOMEM;
 863
 864        /* get reset resources */
 865        tvout->reset = devm_reset_control_get(dev, "tvout");
 866        /* take tvout out of reset */
 867        if (!IS_ERR(tvout->reset))
 868                reset_control_deassert(tvout->reset);
 869
 870        platform_set_drvdata(pdev, tvout);
 871
 872        return component_add(dev, &sti_tvout_ops);
 873}
 874
 875static int sti_tvout_remove(struct platform_device *pdev)
 876{
 877        component_del(&pdev->dev, &sti_tvout_ops);
 878        return 0;
 879}
 880
 881static const struct of_device_id tvout_of_match[] = {
 882        { .compatible = "st,stih407-tvout", },
 883        { /* end node */ }
 884};
 885MODULE_DEVICE_TABLE(of, tvout_of_match);
 886
 887struct platform_driver sti_tvout_driver = {
 888        .driver = {
 889                .name = "sti-tvout",
 890                .owner = THIS_MODULE,
 891                .of_match_table = tvout_of_match,
 892        },
 893        .probe = sti_tvout_probe,
 894        .remove = sti_tvout_remove,
 895};
 896
 897MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
 898MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
 899MODULE_LICENSE("GPL");
 900