linux/drivers/gpu/drm/meson/meson_dw_hdmi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) 2016 BayLibre, SAS
   4 * Author: Neil Armstrong <narmstrong@baylibre.com>
   5 * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/module.h>
  10#include <linux/component.h>
  11#include <linux/of_device.h>
  12#include <linux/of_graph.h>
  13#include <linux/reset.h>
  14#include <linux/clk.h>
  15#include <linux/regulator/consumer.h>
  16
  17#include <drm/drmP.h>
  18#include <drm/drm_atomic_helper.h>
  19#include <drm/drm_edid.h>
  20#include <drm/drm_probe_helper.h>
  21#include <drm/bridge/dw_hdmi.h>
  22
  23#include <uapi/linux/media-bus-format.h>
  24#include <uapi/linux/videodev2.h>
  25
  26#include "meson_drv.h"
  27#include "meson_venc.h"
  28#include "meson_vclk.h"
  29#include "meson_dw_hdmi.h"
  30#include "meson_registers.h"
  31
  32#define DRIVER_NAME "meson-dw-hdmi"
  33#define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver"
  34
  35/**
  36 * DOC: HDMI Output
  37 *
  38 * HDMI Output is composed of :
  39 *
  40 * - A Synopsys DesignWare HDMI Controller IP
  41 * - A TOP control block controlling the Clocks and PHY
  42 * - A custom HDMI PHY in order convert video to TMDS signal
  43 *
  44 * .. code::
  45 *
  46 *    ___________________________________
  47 *   |            HDMI TOP               |<= HPD
  48 *   |___________________________________|
  49 *   |                  |                |
  50 *   |  Synopsys HDMI   |   HDMI PHY     |=> TMDS
  51 *   |    Controller    |________________|
  52 *   |___________________________________|<=> DDC
  53 *
  54 *
  55 * The HDMI TOP block only supports HPD sensing.
  56 * The Synopsys HDMI Controller interrupt is routed
  57 * through the TOP Block interrupt.
  58 * Communication to the TOP Block and the Synopsys
  59 * HDMI Controller is done a pair of addr+read/write
  60 * registers.
  61 * The HDMI PHY is configured by registers in the
  62 * HHI register block.
  63 *
  64 * Pixel data arrives in 4:4:4 format from the VENC
  65 * block and the VPU HDMI mux selects either the ENCI
  66 * encoder for the 576i or 480i formats or the ENCP
  67 * encoder for all the other formats including
  68 * interlaced HD formats.
  69 * The VENC uses a DVI encoder on top of the ENCI
  70 * or ENCP encoders to generate DVI timings for the
  71 * HDMI controller.
  72 *
  73 * GXBB, GXL and GXM embeds the Synopsys DesignWare
  74 * HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF
  75 * audio source interfaces.
  76 *
  77 * We handle the following features :
  78 *
  79 * - HPD Rise & Fall interrupt
  80 * - HDMI Controller Interrupt
  81 * - HDMI PHY Init for 480i to 1080p60
  82 * - VENC & HDMI Clock setup for 480i to 1080p60
  83 * - VENC Mode setup for 480i to 1080p60
  84 *
  85 * What is missing :
  86 *
  87 * - PHY, Clock and Mode setup for 2k && 4k modes
  88 * - SDDC Scrambling mode for HDMI 2.0a
  89 * - HDCP Setup
  90 * - CEC Management
  91 */
  92
  93/* TOP Block Communication Channel */
  94#define HDMITX_TOP_ADDR_REG     0x0
  95#define HDMITX_TOP_DATA_REG     0x4
  96#define HDMITX_TOP_CTRL_REG     0x8
  97#define HDMITX_TOP_G12A_OFFSET  0x8000
  98
  99/* Controller Communication Channel */
 100#define HDMITX_DWC_ADDR_REG     0x10
 101#define HDMITX_DWC_DATA_REG     0x14
 102#define HDMITX_DWC_CTRL_REG     0x18
 103
 104/* HHI Registers */
 105#define HHI_MEM_PD_REG0         0x100 /* 0x40 */
 106#define HHI_HDMI_CLK_CNTL       0x1cc /* 0x73 */
 107#define HHI_HDMI_PHY_CNTL0      0x3a0 /* 0xe8 */
 108#define HHI_HDMI_PHY_CNTL1      0x3a4 /* 0xe9 */
 109#define HHI_HDMI_PHY_CNTL2      0x3a8 /* 0xea */
 110#define HHI_HDMI_PHY_CNTL3      0x3ac /* 0xeb */
 111#define HHI_HDMI_PHY_CNTL4      0x3b0 /* 0xec */
 112#define HHI_HDMI_PHY_CNTL5      0x3b4 /* 0xed */
 113
 114static DEFINE_SPINLOCK(reg_lock);
 115
 116enum meson_venc_source {
 117        MESON_VENC_SOURCE_NONE = 0,
 118        MESON_VENC_SOURCE_ENCI = 1,
 119        MESON_VENC_SOURCE_ENCP = 2,
 120};
 121
 122struct meson_dw_hdmi;
 123
 124struct meson_dw_hdmi_data {
 125        unsigned int    (*top_read)(struct meson_dw_hdmi *dw_hdmi,
 126                                    unsigned int addr);
 127        void            (*top_write)(struct meson_dw_hdmi *dw_hdmi,
 128                                     unsigned int addr, unsigned int data);
 129        unsigned int    (*dwc_read)(struct meson_dw_hdmi *dw_hdmi,
 130                                    unsigned int addr);
 131        void            (*dwc_write)(struct meson_dw_hdmi *dw_hdmi,
 132                                     unsigned int addr, unsigned int data);
 133};
 134
 135struct meson_dw_hdmi {
 136        struct drm_encoder encoder;
 137        struct dw_hdmi_plat_data dw_plat_data;
 138        struct meson_drm *priv;
 139        struct device *dev;
 140        void __iomem *hdmitx;
 141        const struct meson_dw_hdmi_data *data;
 142        struct reset_control *hdmitx_apb;
 143        struct reset_control *hdmitx_ctrl;
 144        struct reset_control *hdmitx_phy;
 145        struct clk *hdmi_pclk;
 146        struct clk *venci_clk;
 147        struct regulator *hdmi_supply;
 148        u32 irq_stat;
 149        struct dw_hdmi *hdmi;
 150};
 151#define encoder_to_meson_dw_hdmi(x) \
 152        container_of(x, struct meson_dw_hdmi, encoder)
 153
 154static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi,
 155                                        const char *compat)
 156{
 157        return of_device_is_compatible(dw_hdmi->dev->of_node, compat);
 158}
 159
 160/* PHY (via TOP bridge) and Controller dedicated register interface */
 161
 162static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi,
 163                                     unsigned int addr)
 164{
 165        unsigned long flags;
 166        unsigned int data;
 167
 168        spin_lock_irqsave(&reg_lock, flags);
 169
 170        /* ADDR must be written twice */
 171        writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
 172        writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
 173
 174        /* Read needs a second DATA read */
 175        data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
 176        data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
 177
 178        spin_unlock_irqrestore(&reg_lock, flags);
 179
 180        return data;
 181}
 182
 183static unsigned int dw_hdmi_g12a_top_read(struct meson_dw_hdmi *dw_hdmi,
 184                                          unsigned int addr)
 185{
 186        return readl(dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2));
 187}
 188
 189static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi,
 190                                     unsigned int addr, unsigned int data)
 191{
 192        unsigned long flags;
 193
 194        spin_lock_irqsave(&reg_lock, flags);
 195
 196        /* ADDR must be written twice */
 197        writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
 198        writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
 199
 200        /* Write needs single DATA write */
 201        writel(data, dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
 202
 203        spin_unlock_irqrestore(&reg_lock, flags);
 204}
 205
 206static inline void dw_hdmi_g12a_top_write(struct meson_dw_hdmi *dw_hdmi,
 207                                          unsigned int addr, unsigned int data)
 208{
 209        writel(data, dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2));
 210}
 211
 212/* Helper to change specific bits in PHY registers */
 213static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi,
 214                                          unsigned int addr,
 215                                          unsigned int mask,
 216                                          unsigned int val)
 217{
 218        unsigned int data = dw_hdmi->data->top_read(dw_hdmi, addr);
 219
 220        data &= ~mask;
 221        data |= val;
 222
 223        dw_hdmi->data->top_write(dw_hdmi, addr, data);
 224}
 225
 226static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi,
 227                                     unsigned int addr)
 228{
 229        unsigned long flags;
 230        unsigned int data;
 231
 232        spin_lock_irqsave(&reg_lock, flags);
 233
 234        /* ADDR must be written twice */
 235        writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
 236        writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
 237
 238        /* Read needs a second DATA read */
 239        data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
 240        data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
 241
 242        spin_unlock_irqrestore(&reg_lock, flags);
 243
 244        return data;
 245}
 246
 247static unsigned int dw_hdmi_g12a_dwc_read(struct meson_dw_hdmi *dw_hdmi,
 248                                          unsigned int addr)
 249{
 250        return readb(dw_hdmi->hdmitx + addr);
 251}
 252
 253static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi,
 254                                     unsigned int addr, unsigned int data)
 255{
 256        unsigned long flags;
 257
 258        spin_lock_irqsave(&reg_lock, flags);
 259
 260        /* ADDR must be written twice */
 261        writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
 262        writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
 263
 264        /* Write needs single DATA write */
 265        writel(data, dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
 266
 267        spin_unlock_irqrestore(&reg_lock, flags);
 268}
 269
 270static inline void dw_hdmi_g12a_dwc_write(struct meson_dw_hdmi *dw_hdmi,
 271                                          unsigned int addr, unsigned int data)
 272{
 273        writeb(data, dw_hdmi->hdmitx + addr);
 274}
 275
 276/* Helper to change specific bits in controller registers */
 277static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi,
 278                                          unsigned int addr,
 279                                          unsigned int mask,
 280                                          unsigned int val)
 281{
 282        unsigned int data = dw_hdmi->data->dwc_read(dw_hdmi, addr);
 283
 284        data &= ~mask;
 285        data |= val;
 286
 287        dw_hdmi->data->dwc_write(dw_hdmi, addr, data);
 288}
 289
 290/* Bridge */
 291
 292/* Setup PHY bandwidth modes */
 293static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi,
 294                                      struct drm_display_mode *mode)
 295{
 296        struct meson_drm *priv = dw_hdmi->priv;
 297        unsigned int pixel_clock = mode->clock;
 298
 299        if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
 300            dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) {
 301                if (pixel_clock >= 371250) {
 302                        /* 5.94Gbps, 3.7125Gbps */
 303                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x333d3282);
 304                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2136315b);
 305                } else if (pixel_clock >= 297000) {
 306                        /* 2.97Gbps */
 307                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303382);
 308                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2036315b);
 309                } else if (pixel_clock >= 148500) {
 310                        /* 1.485Gbps */
 311                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303362);
 312                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2016315b);
 313                } else {
 314                        /* 742.5Mbps, and below */
 315                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33604142);
 316                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x0016315b);
 317                }
 318        } else if (dw_hdmi_is_compatible(dw_hdmi,
 319                                         "amlogic,meson-gxbb-dw-hdmi")) {
 320                if (pixel_clock >= 371250) {
 321                        /* 5.94Gbps, 3.7125Gbps */
 322                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33353245);
 323                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2100115b);
 324                } else if (pixel_clock >= 297000) {
 325                        /* 2.97Gbps */
 326                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33634283);
 327                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0xb000115b);
 328                } else {
 329                        /* 1.485Gbps, and below */
 330                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122);
 331                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b);
 332                }
 333        } else if (dw_hdmi_is_compatible(dw_hdmi,
 334                                         "amlogic,meson-g12a-dw-hdmi")) {
 335                if (pixel_clock >= 371250) {
 336                        /* 5.94Gbps, 3.7125Gbps */
 337                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x37eb65c4);
 338                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
 339                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x0000080b);
 340                } else if (pixel_clock >= 297000) {
 341                        /* 2.97Gbps */
 342                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb6262);
 343                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
 344                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003);
 345                } else {
 346                        /* 1.485Gbps, and below */
 347                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb4242);
 348                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
 349                        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003);
 350                }
 351        }
 352}
 353
 354static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
 355{
 356        struct meson_drm *priv = dw_hdmi->priv;
 357
 358        /* Enable and software reset */
 359        regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xf);
 360
 361        mdelay(2);
 362
 363        /* Enable and unreset */
 364        regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xe);
 365
 366        mdelay(2);
 367}
 368
 369static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
 370                             struct drm_display_mode *mode)
 371{
 372        struct meson_drm *priv = dw_hdmi->priv;
 373        int vic = drm_match_cea_mode(mode);
 374        unsigned int vclk_freq;
 375        unsigned int venc_freq;
 376        unsigned int hdmi_freq;
 377
 378        vclk_freq = mode->clock;
 379
 380        if (!vic) {
 381                meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, vclk_freq,
 382                                 vclk_freq, vclk_freq, false);
 383                return;
 384        }
 385
 386        if (mode->flags & DRM_MODE_FLAG_DBLCLK)
 387                vclk_freq *= 2;
 388
 389        venc_freq = vclk_freq;
 390        hdmi_freq = vclk_freq;
 391
 392        if (meson_venc_hdmi_venc_repeat(vic))
 393                venc_freq *= 2;
 394
 395        vclk_freq = max(venc_freq, hdmi_freq);
 396
 397        if (mode->flags & DRM_MODE_FLAG_DBLCLK)
 398                venc_freq /= 2;
 399
 400        DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n",
 401                vclk_freq, venc_freq, hdmi_freq,
 402                priv->venc.hdmi_use_enci);
 403
 404        meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, vclk_freq,
 405                         venc_freq, hdmi_freq, priv->venc.hdmi_use_enci);
 406}
 407
 408static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
 409                            struct drm_display_mode *mode)
 410{
 411        struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
 412        struct meson_drm *priv = dw_hdmi->priv;
 413        unsigned int wr_clk =
 414                readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING));
 415
 416        DRM_DEBUG_DRIVER("\"%s\" div%d\n", mode->name,
 417                         mode->clock > 340000 ? 40 : 10);
 418
 419        /* Enable clocks */
 420        regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
 421
 422        /* Bring HDMITX MEM output of power down */
 423        regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
 424
 425        /* Bring out of reset */
 426        dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_SW_RESET,  0);
 427
 428        /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */
 429        dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
 430                               0x3, 0x3);
 431        dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
 432                               0x3 << 4, 0x3 << 4);
 433
 434        /* Enable normal output to PHY */
 435        dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
 436
 437        /* TMDS pattern setup (TOFIX Handle the YUV420 case) */
 438        if (mode->clock > 340000) {
 439                dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
 440                                  0);
 441                dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
 442                                  0x03ff03ff);
 443        } else {
 444                dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
 445                                  0x001f001f);
 446                dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
 447                                  0x001f001f);
 448        }
 449
 450        /* Load TMDS pattern */
 451        dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
 452        msleep(20);
 453        dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2);
 454
 455        /* Setup PHY parameters */
 456        meson_hdmi_phy_setup_mode(dw_hdmi, mode);
 457
 458        /* Setup PHY */
 459        regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
 460                           0xffff << 16, 0x0390 << 16);
 461
 462        /* BIT_INVERT */
 463        if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
 464            dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi") ||
 465            dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-g12a-dw-hdmi"))
 466                regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
 467                                   BIT(17), 0);
 468        else
 469                regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
 470                                   BIT(17), BIT(17));
 471
 472        /* Disable clock, fifo, fifo_wr */
 473        regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0);
 474
 475        dw_hdmi_set_high_tmds_clock_ratio(hdmi);
 476
 477        msleep(100);
 478
 479        /* Reset PHY 3 times in a row */
 480        meson_dw_hdmi_phy_reset(dw_hdmi);
 481        meson_dw_hdmi_phy_reset(dw_hdmi);
 482        meson_dw_hdmi_phy_reset(dw_hdmi);
 483
 484        /* Temporary Disable VENC video stream */
 485        if (priv->venc.hdmi_use_enci)
 486                writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
 487        else
 488                writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
 489
 490        /* Temporary Disable HDMI video stream to HDMI-TX */
 491        writel_bits_relaxed(0x3, 0,
 492                            priv->io_base + _REG(VPU_HDMI_SETTING));
 493        writel_bits_relaxed(0xf << 8, 0,
 494                            priv->io_base + _REG(VPU_HDMI_SETTING));
 495
 496        /* Re-Enable VENC video stream */
 497        if (priv->venc.hdmi_use_enci)
 498                writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
 499        else
 500                writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
 501
 502        /* Push back HDMI clock settings */
 503        writel_bits_relaxed(0xf << 8, wr_clk & (0xf << 8),
 504                            priv->io_base + _REG(VPU_HDMI_SETTING));
 505
 506        /* Enable and Select HDMI video source for HDMI-TX */
 507        if (priv->venc.hdmi_use_enci)
 508                writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCI,
 509                                    priv->io_base + _REG(VPU_HDMI_SETTING));
 510        else
 511                writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCP,
 512                                    priv->io_base + _REG(VPU_HDMI_SETTING));
 513
 514        return 0;
 515}
 516
 517static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi,
 518                                void *data)
 519{
 520        struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
 521        struct meson_drm *priv = dw_hdmi->priv;
 522
 523        DRM_DEBUG_DRIVER("\n");
 524
 525        regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0);
 526}
 527
 528static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi,
 529                             void *data)
 530{
 531        struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
 532
 533        return !!dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_STAT0) ?
 534                connector_status_connected : connector_status_disconnected;
 535}
 536
 537static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi,
 538                              void *data)
 539{
 540        struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
 541
 542        /* Setup HPD Filter */
 543        dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER,
 544                          (0xa << 12) | 0xa0);
 545
 546        /* Clear interrupts */
 547        dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
 548                          HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
 549
 550        /* Unmask interrupts */
 551        dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_INTR_MASKN,
 552                        HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL,
 553                        HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
 554}
 555
 556static const struct dw_hdmi_phy_ops meson_dw_hdmi_phy_ops = {
 557        .init = dw_hdmi_phy_init,
 558        .disable = dw_hdmi_phy_disable,
 559        .read_hpd = dw_hdmi_read_hpd,
 560        .setup_hpd = dw_hdmi_setup_hpd,
 561};
 562
 563static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id)
 564{
 565        struct meson_dw_hdmi *dw_hdmi = dev_id;
 566        u32 stat;
 567
 568        stat = dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_INTR_STAT);
 569        dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat);
 570
 571        /* HPD Events, handle in the threaded interrupt handler */
 572        if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
 573                dw_hdmi->irq_stat = stat;
 574                return IRQ_WAKE_THREAD;
 575        }
 576
 577        /* HDMI Controller Interrupt */
 578        if (stat & 1)
 579                return IRQ_NONE;
 580
 581        /* TOFIX Handle HDCP Interrupts */
 582
 583        return IRQ_HANDLED;
 584}
 585
 586/* Threaded interrupt handler to manage HPD events */
 587static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id)
 588{
 589        struct meson_dw_hdmi *dw_hdmi = dev_id;
 590        u32 stat = dw_hdmi->irq_stat;
 591
 592        /* HPD Events */
 593        if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
 594                bool hpd_connected = false;
 595
 596                if (stat & HDMITX_TOP_INTR_HPD_RISE)
 597                        hpd_connected = true;
 598
 599                dw_hdmi_setup_rx_sense(dw_hdmi->hdmi, hpd_connected,
 600                                       hpd_connected);
 601
 602                drm_helper_hpd_irq_event(dw_hdmi->encoder.dev);
 603        }
 604
 605        return IRQ_HANDLED;
 606}
 607
 608static enum drm_mode_status
 609dw_hdmi_mode_valid(struct drm_connector *connector,
 610                   const struct drm_display_mode *mode)
 611{
 612        struct meson_drm *priv = connector->dev->dev_private;
 613        unsigned int vclk_freq;
 614        unsigned int venc_freq;
 615        unsigned int hdmi_freq;
 616        int vic = drm_match_cea_mode(mode);
 617        enum drm_mode_status status;
 618
 619        DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
 620
 621        /* If sink max TMDS clock, we reject the mode */
 622        if (connector->display_info.max_tmds_clock &&
 623            mode->clock > connector->display_info.max_tmds_clock)
 624                return MODE_BAD;
 625
 626        /* Check against non-VIC supported modes */
 627        if (!vic) {
 628                status = meson_venc_hdmi_supported_mode(mode);
 629                if (status != MODE_OK)
 630                        return status;
 631
 632                return meson_vclk_dmt_supported_freq(priv, mode->clock);
 633        /* Check against supported VIC modes */
 634        } else if (!meson_venc_hdmi_supported_vic(vic))
 635                return MODE_BAD;
 636
 637        vclk_freq = mode->clock;
 638
 639        /* 480i/576i needs global pixel doubling */
 640        if (mode->flags & DRM_MODE_FLAG_DBLCLK)
 641                vclk_freq *= 2;
 642
 643        venc_freq = vclk_freq;
 644        hdmi_freq = vclk_freq;
 645
 646        /* VENC double pixels for 1080i and 720p modes */
 647        if (meson_venc_hdmi_venc_repeat(vic))
 648                venc_freq *= 2;
 649
 650        vclk_freq = max(venc_freq, hdmi_freq);
 651
 652        if (mode->flags & DRM_MODE_FLAG_DBLCLK)
 653                venc_freq /= 2;
 654
 655        dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
 656                vclk_freq, venc_freq, hdmi_freq);
 657
 658        return meson_vclk_vic_supported_freq(vclk_freq);
 659}
 660
 661/* Encoder */
 662
 663static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder)
 664{
 665        drm_encoder_cleanup(encoder);
 666}
 667
 668static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = {
 669        .destroy        = meson_venc_hdmi_encoder_destroy,
 670};
 671
 672static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
 673                                        struct drm_crtc_state *crtc_state,
 674                                        struct drm_connector_state *conn_state)
 675{
 676        return 0;
 677}
 678
 679static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
 680{
 681        struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
 682        struct meson_drm *priv = dw_hdmi->priv;
 683
 684        DRM_DEBUG_DRIVER("\n");
 685
 686        writel_bits_relaxed(0x3, 0,
 687                            priv->io_base + _REG(VPU_HDMI_SETTING));
 688
 689        writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
 690        writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
 691}
 692
 693static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
 694{
 695        struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
 696        struct meson_drm *priv = dw_hdmi->priv;
 697
 698        DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
 699
 700        if (priv->venc.hdmi_use_enci)
 701                writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
 702        else
 703                writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
 704}
 705
 706static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
 707                                   struct drm_display_mode *mode,
 708                                   struct drm_display_mode *adjusted_mode)
 709{
 710        struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
 711        struct meson_drm *priv = dw_hdmi->priv;
 712        int vic = drm_match_cea_mode(mode);
 713
 714        DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic);
 715
 716        /* VENC + VENC-DVI Mode setup */
 717        meson_venc_hdmi_mode_set(priv, vic, mode);
 718
 719        /* VCLK Set clock */
 720        dw_hdmi_set_vclk(dw_hdmi, mode);
 721
 722        /* Setup YUV444 to HDMI-TX, no 10bit diphering */
 723        writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
 724}
 725
 726static const struct drm_encoder_helper_funcs
 727                                meson_venc_hdmi_encoder_helper_funcs = {
 728        .atomic_check   = meson_venc_hdmi_encoder_atomic_check,
 729        .disable        = meson_venc_hdmi_encoder_disable,
 730        .enable         = meson_venc_hdmi_encoder_enable,
 731        .mode_set       = meson_venc_hdmi_encoder_mode_set,
 732};
 733
 734/* DW HDMI Regmap */
 735
 736static int meson_dw_hdmi_reg_read(void *context, unsigned int reg,
 737                                  unsigned int *result)
 738{
 739        struct meson_dw_hdmi *dw_hdmi = context;
 740
 741        *result = dw_hdmi->data->dwc_read(dw_hdmi, reg);
 742
 743        return 0;
 744
 745}
 746
 747static int meson_dw_hdmi_reg_write(void *context, unsigned int reg,
 748                                   unsigned int val)
 749{
 750        struct meson_dw_hdmi *dw_hdmi = context;
 751
 752        dw_hdmi->data->dwc_write(dw_hdmi, reg, val);
 753
 754        return 0;
 755}
 756
 757static const struct regmap_config meson_dw_hdmi_regmap_config = {
 758        .reg_bits = 32,
 759        .val_bits = 8,
 760        .reg_read = meson_dw_hdmi_reg_read,
 761        .reg_write = meson_dw_hdmi_reg_write,
 762        .max_register = 0x10000,
 763        .fast_io = true,
 764};
 765
 766static const struct meson_dw_hdmi_data meson_dw_hdmi_gx_data = {
 767        .top_read = dw_hdmi_top_read,
 768        .top_write = dw_hdmi_top_write,
 769        .dwc_read = dw_hdmi_dwc_read,
 770        .dwc_write = dw_hdmi_dwc_write,
 771};
 772
 773static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = {
 774        .top_read = dw_hdmi_g12a_top_read,
 775        .top_write = dw_hdmi_g12a_top_write,
 776        .dwc_read = dw_hdmi_g12a_dwc_read,
 777        .dwc_write = dw_hdmi_g12a_dwc_write,
 778};
 779
 780static bool meson_hdmi_connector_is_available(struct device *dev)
 781{
 782        struct device_node *ep, *remote;
 783
 784        /* HDMI Connector is on the second port, first endpoint */
 785        ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0);
 786        if (!ep)
 787                return false;
 788
 789        /* If the endpoint node exists, consider it enabled */
 790        remote = of_graph_get_remote_port(ep);
 791        if (remote) {
 792                of_node_put(ep);
 793                return true;
 794        }
 795
 796        of_node_put(ep);
 797        of_node_put(remote);
 798
 799        return false;
 800}
 801
 802static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 803                                void *data)
 804{
 805        struct platform_device *pdev = to_platform_device(dev);
 806        const struct meson_dw_hdmi_data *match;
 807        struct meson_dw_hdmi *meson_dw_hdmi;
 808        struct drm_device *drm = data;
 809        struct meson_drm *priv = drm->dev_private;
 810        struct dw_hdmi_plat_data *dw_plat_data;
 811        struct drm_encoder *encoder;
 812        struct resource *res;
 813        int irq;
 814        int ret;
 815
 816        DRM_DEBUG_DRIVER("\n");
 817
 818        if (!meson_hdmi_connector_is_available(dev)) {
 819                dev_info(drm->dev, "HDMI Output connector not available\n");
 820                return -ENODEV;
 821        }
 822
 823        match = of_device_get_match_data(&pdev->dev);
 824        if (!match) {
 825                dev_err(&pdev->dev, "failed to get match data\n");
 826                return -ENODEV;
 827        }
 828
 829        meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi),
 830                                     GFP_KERNEL);
 831        if (!meson_dw_hdmi)
 832                return -ENOMEM;
 833
 834        meson_dw_hdmi->priv = priv;
 835        meson_dw_hdmi->dev = dev;
 836        meson_dw_hdmi->data = match;
 837        dw_plat_data = &meson_dw_hdmi->dw_plat_data;
 838        encoder = &meson_dw_hdmi->encoder;
 839
 840        meson_dw_hdmi->hdmi_supply = devm_regulator_get_optional(dev, "hdmi");
 841        if (IS_ERR(meson_dw_hdmi->hdmi_supply)) {
 842                if (PTR_ERR(meson_dw_hdmi->hdmi_supply) == -EPROBE_DEFER)
 843                        return -EPROBE_DEFER;
 844                meson_dw_hdmi->hdmi_supply = NULL;
 845        } else {
 846                ret = regulator_enable(meson_dw_hdmi->hdmi_supply);
 847                if (ret)
 848                        return ret;
 849        }
 850
 851        meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev,
 852                                                "hdmitx_apb");
 853        if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) {
 854                dev_err(dev, "Failed to get hdmitx_apb reset\n");
 855                return PTR_ERR(meson_dw_hdmi->hdmitx_apb);
 856        }
 857
 858        meson_dw_hdmi->hdmitx_ctrl = devm_reset_control_get_exclusive(dev,
 859                                                "hdmitx");
 860        if (IS_ERR(meson_dw_hdmi->hdmitx_ctrl)) {
 861                dev_err(dev, "Failed to get hdmitx reset\n");
 862                return PTR_ERR(meson_dw_hdmi->hdmitx_ctrl);
 863        }
 864
 865        meson_dw_hdmi->hdmitx_phy = devm_reset_control_get_exclusive(dev,
 866                                                "hdmitx_phy");
 867        if (IS_ERR(meson_dw_hdmi->hdmitx_phy)) {
 868                dev_err(dev, "Failed to get hdmitx_phy reset\n");
 869                return PTR_ERR(meson_dw_hdmi->hdmitx_phy);
 870        }
 871
 872        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 873        meson_dw_hdmi->hdmitx = devm_ioremap_resource(dev, res);
 874        if (IS_ERR(meson_dw_hdmi->hdmitx))
 875                return PTR_ERR(meson_dw_hdmi->hdmitx);
 876
 877        meson_dw_hdmi->hdmi_pclk = devm_clk_get(dev, "isfr");
 878        if (IS_ERR(meson_dw_hdmi->hdmi_pclk)) {
 879                dev_err(dev, "Unable to get HDMI pclk\n");
 880                return PTR_ERR(meson_dw_hdmi->hdmi_pclk);
 881        }
 882        clk_prepare_enable(meson_dw_hdmi->hdmi_pclk);
 883
 884        meson_dw_hdmi->venci_clk = devm_clk_get(dev, "venci");
 885        if (IS_ERR(meson_dw_hdmi->venci_clk)) {
 886                dev_err(dev, "Unable to get venci clk\n");
 887                return PTR_ERR(meson_dw_hdmi->venci_clk);
 888        }
 889        clk_prepare_enable(meson_dw_hdmi->venci_clk);
 890
 891        dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi,
 892                                              &meson_dw_hdmi_regmap_config);
 893        if (IS_ERR(dw_plat_data->regm))
 894                return PTR_ERR(dw_plat_data->regm);
 895
 896        irq = platform_get_irq(pdev, 0);
 897        if (irq < 0) {
 898                dev_err(dev, "Failed to get hdmi top irq\n");
 899                return irq;
 900        }
 901
 902        ret = devm_request_threaded_irq(dev, irq, dw_hdmi_top_irq,
 903                                        dw_hdmi_top_thread_irq, IRQF_SHARED,
 904                                        "dw_hdmi_top_irq", meson_dw_hdmi);
 905        if (ret) {
 906                dev_err(dev, "Failed to request hdmi top irq\n");
 907                return ret;
 908        }
 909
 910        /* Encoder */
 911
 912        drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs);
 913
 914        ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs,
 915                               DRM_MODE_ENCODER_TMDS, "meson_hdmi");
 916        if (ret) {
 917                dev_err(priv->dev, "Failed to init HDMI encoder\n");
 918                return ret;
 919        }
 920
 921        encoder->possible_crtcs = BIT(0);
 922
 923        DRM_DEBUG_DRIVER("encoder initialized\n");
 924
 925        /* Enable clocks */
 926        regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
 927
 928        /* Bring HDMITX MEM output of power down */
 929        regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
 930
 931        /* Reset HDMITX APB & TX & PHY */
 932        reset_control_reset(meson_dw_hdmi->hdmitx_apb);
 933        reset_control_reset(meson_dw_hdmi->hdmitx_ctrl);
 934        reset_control_reset(meson_dw_hdmi->hdmitx_phy);
 935
 936        /* Enable APB3 fail on error */
 937        if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
 938                writel_bits_relaxed(BIT(15), BIT(15),
 939                                    meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG);
 940                writel_bits_relaxed(BIT(15), BIT(15),
 941                                    meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG);
 942        }
 943
 944        /* Bring out of reset */
 945        meson_dw_hdmi->data->top_write(meson_dw_hdmi,
 946                                       HDMITX_TOP_SW_RESET,  0);
 947
 948        msleep(20);
 949
 950        meson_dw_hdmi->data->top_write(meson_dw_hdmi,
 951                                       HDMITX_TOP_CLK_CNTL, 0xff);
 952
 953        /* Enable HDMI-TX Interrupt */
 954        meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
 955                                       HDMITX_TOP_INTR_CORE);
 956
 957        meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN,
 958                                       HDMITX_TOP_INTR_CORE);
 959
 960        /* Bridge / Connector */
 961
 962        dw_plat_data->mode_valid = dw_hdmi_mode_valid;
 963        dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops;
 964        dw_plat_data->phy_name = "meson_dw_hdmi_phy";
 965        dw_plat_data->phy_data = meson_dw_hdmi;
 966        dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
 967        dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
 968
 969        platform_set_drvdata(pdev, meson_dw_hdmi);
 970
 971        meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder,
 972                                           &meson_dw_hdmi->dw_plat_data);
 973        if (IS_ERR(meson_dw_hdmi->hdmi))
 974                return PTR_ERR(meson_dw_hdmi->hdmi);
 975
 976        DRM_DEBUG_DRIVER("HDMI controller initialized\n");
 977
 978        return 0;
 979}
 980
 981static void meson_dw_hdmi_unbind(struct device *dev, struct device *master,
 982                                   void *data)
 983{
 984        struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev);
 985
 986        dw_hdmi_unbind(meson_dw_hdmi->hdmi);
 987}
 988
 989static const struct component_ops meson_dw_hdmi_ops = {
 990        .bind   = meson_dw_hdmi_bind,
 991        .unbind = meson_dw_hdmi_unbind,
 992};
 993
 994static int meson_dw_hdmi_probe(struct platform_device *pdev)
 995{
 996        return component_add(&pdev->dev, &meson_dw_hdmi_ops);
 997}
 998
 999static int meson_dw_hdmi_remove(struct platform_device *pdev)
1000{
1001        component_del(&pdev->dev, &meson_dw_hdmi_ops);
1002
1003        return 0;
1004}
1005
1006static const struct of_device_id meson_dw_hdmi_of_table[] = {
1007        { .compatible = "amlogic,meson-gxbb-dw-hdmi",
1008          .data = &meson_dw_hdmi_gx_data },
1009        { .compatible = "amlogic,meson-gxl-dw-hdmi",
1010          .data = &meson_dw_hdmi_gx_data },
1011        { .compatible = "amlogic,meson-gxm-dw-hdmi",
1012          .data = &meson_dw_hdmi_gx_data },
1013        { .compatible = "amlogic,meson-g12a-dw-hdmi",
1014          .data = &meson_dw_hdmi_g12a_data },
1015        { }
1016};
1017MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table);
1018
1019static struct platform_driver meson_dw_hdmi_platform_driver = {
1020        .probe          = meson_dw_hdmi_probe,
1021        .remove         = meson_dw_hdmi_remove,
1022        .driver         = {
1023                .name           = DRIVER_NAME,
1024                .of_match_table = meson_dw_hdmi_of_table,
1025        },
1026};
1027module_platform_driver(meson_dw_hdmi_platform_driver);
1028
1029MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
1030MODULE_DESCRIPTION(DRIVER_DESC);
1031MODULE_LICENSE("GPL");
1032