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