linux/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
<<
>>
Prefs
   1/*
   2 * Copyright © 2006-2011 Intel Corporation
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice (including the next
  12 * paragraph) shall be included in all copies or substantial portions of the
  13 * Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21 * DEALINGS IN THE SOFTWARE.
  22 *
  23 * Authors:
  24 *      jim liu <jim.liu@intel.com>
  25 *
  26 * FIXME:
  27 *      We should probably make this generic and share it with Medfield
  28 */
  29
  30#include <drm/drmP.h>
  31#include <drm/drm.h>
  32#include <drm/drm_crtc.h>
  33#include <drm/drm_edid.h>
  34#include "psb_intel_drv.h"
  35#include "psb_drv.h"
  36#include "psb_intel_reg.h"
  37#include <linux/pm_runtime.h>
  38
  39/* hdmi control bits */
  40#define HDMI_NULL_PACKETS_DURING_VSYNC  (1 << 9)
  41#define HDMI_BORDER_ENABLE              (1 << 7)
  42#define HDMI_AUDIO_ENABLE               (1 << 6)
  43#define HDMI_VSYNC_ACTIVE_HIGH          (1 << 4)
  44#define HDMI_HSYNC_ACTIVE_HIGH          (1 << 3)
  45/* hdmi-b control bits */
  46#define HDMIB_PIPE_B_SELECT             (1 << 30)
  47
  48
  49struct mid_intel_hdmi_priv {
  50        u32 hdmi_reg;
  51        u32 save_HDMIB;
  52        bool has_hdmi_sink;
  53        bool has_hdmi_audio;
  54        /* Should set this when detect hotplug */
  55        bool hdmi_device_connected;
  56        struct mdfld_hdmi_i2c *i2c_bus;
  57        struct i2c_adapter *hdmi_i2c_adapter;   /* for control functions */
  58        struct drm_device *dev;
  59};
  60
  61static void cdv_hdmi_mode_set(struct drm_encoder *encoder,
  62                        struct drm_display_mode *mode,
  63                        struct drm_display_mode *adjusted_mode)
  64{
  65        struct drm_device *dev = encoder->dev;
  66        struct psb_intel_encoder *psb_intel_encoder = to_psb_intel_encoder(encoder);
  67        struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv;
  68        u32 hdmib;
  69        struct drm_crtc *crtc = encoder->crtc;
  70        struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);
  71
  72        hdmib = (2 << 10);
  73
  74        if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
  75                hdmib |= HDMI_VSYNC_ACTIVE_HIGH;
  76        if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
  77                hdmib |= HDMI_HSYNC_ACTIVE_HIGH;
  78
  79        if (intel_crtc->pipe == 1)
  80                hdmib |= HDMIB_PIPE_B_SELECT;
  81
  82        if (hdmi_priv->has_hdmi_audio) {
  83                hdmib |= HDMI_AUDIO_ENABLE;
  84                hdmib |= HDMI_NULL_PACKETS_DURING_VSYNC;
  85        }
  86
  87        REG_WRITE(hdmi_priv->hdmi_reg, hdmib);
  88        REG_READ(hdmi_priv->hdmi_reg);
  89}
  90
  91static bool cdv_hdmi_mode_fixup(struct drm_encoder *encoder,
  92                                  struct drm_display_mode *mode,
  93                                  struct drm_display_mode *adjusted_mode)
  94{
  95        return true;
  96}
  97
  98static void cdv_hdmi_dpms(struct drm_encoder *encoder, int mode)
  99{
 100        struct drm_device *dev = encoder->dev;
 101        struct psb_intel_encoder *psb_intel_encoder =
 102                                                to_psb_intel_encoder(encoder);
 103        struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv;
 104        u32 hdmib;
 105
 106        hdmib = REG_READ(hdmi_priv->hdmi_reg);
 107
 108        if (mode != DRM_MODE_DPMS_ON)
 109                REG_WRITE(hdmi_priv->hdmi_reg, hdmib & ~HDMIB_PORT_EN);
 110        else
 111                REG_WRITE(hdmi_priv->hdmi_reg, hdmib | HDMIB_PORT_EN);
 112        REG_READ(hdmi_priv->hdmi_reg);
 113}
 114
 115static void cdv_hdmi_save(struct drm_connector *connector)
 116{
 117        struct drm_device *dev = connector->dev;
 118        struct psb_intel_encoder *psb_intel_encoder =
 119                                        psb_intel_attached_encoder(connector);
 120        struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv;
 121
 122        hdmi_priv->save_HDMIB = REG_READ(hdmi_priv->hdmi_reg);
 123}
 124
 125static void cdv_hdmi_restore(struct drm_connector *connector)
 126{
 127        struct drm_device *dev = connector->dev;
 128        struct psb_intel_encoder *psb_intel_encoder =
 129                                        psb_intel_attached_encoder(connector);
 130        struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv;
 131
 132        REG_WRITE(hdmi_priv->hdmi_reg, hdmi_priv->save_HDMIB);
 133        REG_READ(hdmi_priv->hdmi_reg);
 134}
 135
 136static enum drm_connector_status cdv_hdmi_detect(
 137                                struct drm_connector *connector, bool force)
 138{
 139        struct psb_intel_encoder *psb_intel_encoder =
 140                                        psb_intel_attached_encoder(connector);
 141        struct psb_intel_connector *psb_intel_connector =
 142                                        to_psb_intel_connector(connector);
 143        struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv;
 144        struct edid *edid = NULL;
 145        enum drm_connector_status status = connector_status_disconnected;
 146
 147        edid = drm_get_edid(connector, &psb_intel_encoder->i2c_bus->adapter);
 148
 149        hdmi_priv->has_hdmi_sink = false;
 150        hdmi_priv->has_hdmi_audio = false;
 151        if (edid) {
 152                if (edid->input & DRM_EDID_INPUT_DIGITAL) {
 153                        status = connector_status_connected;
 154                        hdmi_priv->has_hdmi_sink =
 155                                                drm_detect_hdmi_monitor(edid);
 156                        hdmi_priv->has_hdmi_audio =
 157                                                drm_detect_monitor_audio(edid);
 158                }
 159
 160                psb_intel_connector->base.display_info.raw_edid = NULL;
 161                kfree(edid);
 162        }
 163        return status;
 164}
 165
 166static int cdv_hdmi_set_property(struct drm_connector *connector,
 167                                       struct drm_property *property,
 168                                       uint64_t value)
 169{
 170        struct drm_encoder *encoder = connector->encoder;
 171
 172        if (!strcmp(property->name, "scaling mode") && encoder) {
 173                struct psb_intel_crtc *crtc = to_psb_intel_crtc(encoder->crtc);
 174                bool centre;
 175                uint64_t curValue;
 176
 177                if (!crtc)
 178                        return -1;
 179
 180                switch (value) {
 181                case DRM_MODE_SCALE_FULLSCREEN:
 182                        break;
 183                case DRM_MODE_SCALE_NO_SCALE:
 184                        break;
 185                case DRM_MODE_SCALE_ASPECT:
 186                        break;
 187                default:
 188                        return -1;
 189                }
 190
 191                if (drm_connector_property_get_value(connector,
 192                                                        property, &curValue))
 193                        return -1;
 194
 195                if (curValue == value)
 196                        return 0;
 197
 198                if (drm_connector_property_set_value(connector,
 199                                                        property, value))
 200                        return -1;
 201
 202                centre = (curValue == DRM_MODE_SCALE_NO_SCALE) ||
 203                        (value == DRM_MODE_SCALE_NO_SCALE);
 204
 205                if (crtc->saved_mode.hdisplay != 0 &&
 206                    crtc->saved_mode.vdisplay != 0) {
 207                        if (centre) {
 208                                if (!drm_crtc_helper_set_mode(encoder->crtc, &crtc->saved_mode,
 209                                            encoder->crtc->x, encoder->crtc->y, encoder->crtc->fb))
 210                                        return -1;
 211                        } else {
 212                                struct drm_encoder_helper_funcs *helpers
 213                                                    = encoder->helper_private;
 214                                helpers->mode_set(encoder, &crtc->saved_mode,
 215                                             &crtc->saved_adjusted_mode);
 216                        }
 217                }
 218        }
 219        return 0;
 220}
 221
 222/*
 223 * Return the list of HDMI DDC modes if available.
 224 */
 225static int cdv_hdmi_get_modes(struct drm_connector *connector)
 226{
 227        struct psb_intel_encoder *psb_intel_encoder =
 228                                        psb_intel_attached_encoder(connector);
 229        struct edid *edid = NULL;
 230        int ret = 0;
 231
 232        edid = drm_get_edid(connector, &psb_intel_encoder->i2c_bus->adapter);
 233        if (edid) {
 234                drm_mode_connector_update_edid_property(connector, edid);
 235                ret = drm_add_edid_modes(connector, edid);
 236                kfree(edid);
 237        }
 238        return ret;
 239}
 240
 241static int cdv_hdmi_mode_valid(struct drm_connector *connector,
 242                                 struct drm_display_mode *mode)
 243{
 244        struct drm_psb_private *dev_priv = connector->dev->dev_private;
 245
 246        if (mode->clock > 165000)
 247                return MODE_CLOCK_HIGH;
 248        if (mode->clock < 20000)
 249                return MODE_CLOCK_HIGH;
 250
 251        /* just in case */
 252        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
 253                return MODE_NO_DBLESCAN;
 254
 255        /* just in case */
 256        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
 257                return MODE_NO_INTERLACE;
 258
 259        /* We assume worst case scenario of 32 bpp here, since we don't know */
 260        if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
 261            dev_priv->vram_stolen_size)
 262                return MODE_MEM;
 263
 264        return MODE_OK;
 265}
 266
 267static void cdv_hdmi_destroy(struct drm_connector *connector)
 268{
 269        struct psb_intel_encoder *psb_intel_encoder =
 270                                        psb_intel_attached_encoder(connector);
 271
 272        if (psb_intel_encoder->i2c_bus)
 273                psb_intel_i2c_destroy(psb_intel_encoder->i2c_bus);
 274        drm_sysfs_connector_remove(connector);
 275        drm_connector_cleanup(connector);
 276        kfree(connector);
 277}
 278
 279static const struct drm_encoder_helper_funcs cdv_hdmi_helper_funcs = {
 280        .dpms = cdv_hdmi_dpms,
 281        .mode_fixup = cdv_hdmi_mode_fixup,
 282        .prepare = psb_intel_encoder_prepare,
 283        .mode_set = cdv_hdmi_mode_set,
 284        .commit = psb_intel_encoder_commit,
 285};
 286
 287static const struct drm_connector_helper_funcs
 288                                        cdv_hdmi_connector_helper_funcs = {
 289        .get_modes = cdv_hdmi_get_modes,
 290        .mode_valid = cdv_hdmi_mode_valid,
 291        .best_encoder = psb_intel_best_encoder,
 292};
 293
 294static const struct drm_connector_funcs cdv_hdmi_connector_funcs = {
 295        .dpms = drm_helper_connector_dpms,
 296        .save = cdv_hdmi_save,
 297        .restore = cdv_hdmi_restore,
 298        .detect = cdv_hdmi_detect,
 299        .fill_modes = drm_helper_probe_single_connector_modes,
 300        .set_property = cdv_hdmi_set_property,
 301        .destroy = cdv_hdmi_destroy,
 302};
 303
 304void cdv_hdmi_init(struct drm_device *dev,
 305                        struct psb_intel_mode_device *mode_dev, int reg)
 306{
 307        struct psb_intel_encoder *psb_intel_encoder;
 308        struct psb_intel_connector *psb_intel_connector;
 309        struct drm_connector *connector;
 310        struct drm_encoder *encoder;
 311        struct mid_intel_hdmi_priv *hdmi_priv;
 312        int ddc_bus;
 313
 314        psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder),
 315                                    GFP_KERNEL);
 316
 317        if (!psb_intel_encoder)
 318                return;
 319
 320        psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector),
 321                                      GFP_KERNEL);
 322
 323        if (!psb_intel_connector)
 324                goto err_connector;
 325
 326        hdmi_priv = kzalloc(sizeof(struct mid_intel_hdmi_priv), GFP_KERNEL);
 327
 328        if (!hdmi_priv)
 329                goto err_priv;
 330
 331        connector = &psb_intel_connector->base;
 332        encoder = &psb_intel_encoder->base;
 333        drm_connector_init(dev, connector,
 334                           &cdv_hdmi_connector_funcs,
 335                           DRM_MODE_CONNECTOR_DVID);
 336
 337        drm_encoder_init(dev, encoder, &psb_intel_lvds_enc_funcs,
 338                         DRM_MODE_ENCODER_TMDS);
 339
 340        psb_intel_connector_attach_encoder(psb_intel_connector,
 341                                           psb_intel_encoder);
 342        psb_intel_encoder->type = INTEL_OUTPUT_HDMI;
 343        hdmi_priv->hdmi_reg = reg;
 344        hdmi_priv->has_hdmi_sink = false;
 345        psb_intel_encoder->dev_priv = hdmi_priv;
 346
 347        drm_encoder_helper_add(encoder, &cdv_hdmi_helper_funcs);
 348        drm_connector_helper_add(connector,
 349                                 &cdv_hdmi_connector_helper_funcs);
 350        connector->display_info.subpixel_order = SubPixelHorizontalRGB;
 351        connector->interlace_allowed = false;
 352        connector->doublescan_allowed = false;
 353
 354        drm_connector_attach_property(connector,
 355                                      dev->mode_config.scaling_mode_property,
 356                                      DRM_MODE_SCALE_FULLSCREEN);
 357
 358        switch (reg) {
 359        case SDVOB:
 360                ddc_bus = GPIOE;
 361                break;
 362        case SDVOC:
 363                ddc_bus = GPIOD;
 364                break;
 365        default:
 366                DRM_ERROR("unknown reg 0x%x for HDMI\n", reg);
 367                goto failed_ddc;
 368                break;
 369        }
 370
 371        psb_intel_encoder->i2c_bus = psb_intel_i2c_create(dev,
 372                                ddc_bus, (reg == SDVOB) ? "HDMIB" : "HDMIC");
 373
 374        if (!psb_intel_encoder->i2c_bus) {
 375                dev_err(dev->dev, "No ddc adapter available!\n");
 376                goto failed_ddc;
 377        }
 378
 379        hdmi_priv->hdmi_i2c_adapter =
 380                                &(psb_intel_encoder->i2c_bus->adapter);
 381        hdmi_priv->dev = dev;
 382        drm_sysfs_connector_add(connector);
 383        return;
 384
 385failed_ddc:
 386        drm_encoder_cleanup(encoder);
 387        drm_connector_cleanup(connector);
 388err_priv:
 389        kfree(psb_intel_connector);
 390err_connector:
 391        kfree(psb_intel_encoder);
 392}
 393