root/drivers/gpu/drm/gma500/cdv_intel_hdmi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cdv_hdmi_mode_set
  2. cdv_hdmi_dpms
  3. cdv_hdmi_save
  4. cdv_hdmi_restore
  5. cdv_hdmi_detect
  6. cdv_hdmi_set_property
  7. cdv_hdmi_get_modes
  8. cdv_hdmi_mode_valid
  9. cdv_hdmi_destroy
  10. cdv_hdmi_init

   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 <linux/pm_runtime.h>
  31 
  32 #include <drm/drm.h>
  33 #include <drm/drm_crtc.h>
  34 #include <drm/drm_edid.h>
  35 
  36 #include "cdv_device.h"
  37 #include "psb_drv.h"
  38 #include "psb_intel_drv.h"
  39 #include "psb_intel_reg.h"
  40 
  41 /* hdmi control bits */
  42 #define HDMI_NULL_PACKETS_DURING_VSYNC  (1 << 9)
  43 #define HDMI_BORDER_ENABLE              (1 << 7)
  44 #define HDMI_AUDIO_ENABLE               (1 << 6)
  45 #define HDMI_VSYNC_ACTIVE_HIGH          (1 << 4)
  46 #define HDMI_HSYNC_ACTIVE_HIGH          (1 << 3)
  47 /* hdmi-b control bits */
  48 #define HDMIB_PIPE_B_SELECT             (1 << 30)
  49 
  50 
  51 struct mid_intel_hdmi_priv {
  52         u32 hdmi_reg;
  53         u32 save_HDMIB;
  54         bool has_hdmi_sink;
  55         bool has_hdmi_audio;
  56         /* Should set this when detect hotplug */
  57         bool hdmi_device_connected;
  58         struct mdfld_hdmi_i2c *i2c_bus;
  59         struct i2c_adapter *hdmi_i2c_adapter;   /* for control functions */
  60         struct drm_device *dev;
  61 };
  62 
  63 static void cdv_hdmi_mode_set(struct drm_encoder *encoder,
  64                         struct drm_display_mode *mode,
  65                         struct drm_display_mode *adjusted_mode)
  66 {
  67         struct drm_device *dev = encoder->dev;
  68         struct gma_encoder *gma_encoder = to_gma_encoder(encoder);
  69         struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv;
  70         u32 hdmib;
  71         struct drm_crtc *crtc = encoder->crtc;
  72         struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
  73 
  74         hdmib = (2 << 10);
  75 
  76         if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
  77                 hdmib |= HDMI_VSYNC_ACTIVE_HIGH;
  78         if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
  79                 hdmib |= HDMI_HSYNC_ACTIVE_HIGH;
  80 
  81         if (gma_crtc->pipe == 1)
  82                 hdmib |= HDMIB_PIPE_B_SELECT;
  83 
  84         if (hdmi_priv->has_hdmi_audio) {
  85                 hdmib |= HDMI_AUDIO_ENABLE;
  86                 hdmib |= HDMI_NULL_PACKETS_DURING_VSYNC;
  87         }
  88 
  89         REG_WRITE(hdmi_priv->hdmi_reg, hdmib);
  90         REG_READ(hdmi_priv->hdmi_reg);
  91 }
  92 
  93 static void cdv_hdmi_dpms(struct drm_encoder *encoder, int mode)
  94 {
  95         struct drm_device *dev = encoder->dev;
  96         struct gma_encoder *gma_encoder = to_gma_encoder(encoder);
  97         struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv;
  98         u32 hdmib;
  99 
 100         hdmib = REG_READ(hdmi_priv->hdmi_reg);
 101 
 102         if (mode != DRM_MODE_DPMS_ON)
 103                 REG_WRITE(hdmi_priv->hdmi_reg, hdmib & ~HDMIB_PORT_EN);
 104         else
 105                 REG_WRITE(hdmi_priv->hdmi_reg, hdmib | HDMIB_PORT_EN);
 106         REG_READ(hdmi_priv->hdmi_reg);
 107 }
 108 
 109 static void cdv_hdmi_save(struct drm_connector *connector)
 110 {
 111         struct drm_device *dev = connector->dev;
 112         struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
 113         struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv;
 114 
 115         hdmi_priv->save_HDMIB = REG_READ(hdmi_priv->hdmi_reg);
 116 }
 117 
 118 static void cdv_hdmi_restore(struct drm_connector *connector)
 119 {
 120         struct drm_device *dev = connector->dev;
 121         struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
 122         struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv;
 123 
 124         REG_WRITE(hdmi_priv->hdmi_reg, hdmi_priv->save_HDMIB);
 125         REG_READ(hdmi_priv->hdmi_reg);
 126 }
 127 
 128 static enum drm_connector_status cdv_hdmi_detect(
 129                                 struct drm_connector *connector, bool force)
 130 {
 131         struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
 132         struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv;
 133         struct edid *edid = NULL;
 134         enum drm_connector_status status = connector_status_disconnected;
 135 
 136         edid = drm_get_edid(connector, &gma_encoder->i2c_bus->adapter);
 137 
 138         hdmi_priv->has_hdmi_sink = false;
 139         hdmi_priv->has_hdmi_audio = false;
 140         if (edid) {
 141                 if (edid->input & DRM_EDID_INPUT_DIGITAL) {
 142                         status = connector_status_connected;
 143                         hdmi_priv->has_hdmi_sink =
 144                                                 drm_detect_hdmi_monitor(edid);
 145                         hdmi_priv->has_hdmi_audio =
 146                                                 drm_detect_monitor_audio(edid);
 147                 }
 148                 kfree(edid);
 149         }
 150         return status;
 151 }
 152 
 153 static int cdv_hdmi_set_property(struct drm_connector *connector,
 154                                        struct drm_property *property,
 155                                        uint64_t value)
 156 {
 157         struct drm_encoder *encoder = connector->encoder;
 158 
 159         if (!strcmp(property->name, "scaling mode") && encoder) {
 160                 struct gma_crtc *crtc = to_gma_crtc(encoder->crtc);
 161                 bool centre;
 162                 uint64_t curValue;
 163 
 164                 if (!crtc)
 165                         return -1;
 166 
 167                 switch (value) {
 168                 case DRM_MODE_SCALE_FULLSCREEN:
 169                         break;
 170                 case DRM_MODE_SCALE_NO_SCALE:
 171                         break;
 172                 case DRM_MODE_SCALE_ASPECT:
 173                         break;
 174                 default:
 175                         return -1;
 176                 }
 177 
 178                 if (drm_object_property_get_value(&connector->base,
 179                                                         property, &curValue))
 180                         return -1;
 181 
 182                 if (curValue == value)
 183                         return 0;
 184 
 185                 if (drm_object_property_set_value(&connector->base,
 186                                                         property, value))
 187                         return -1;
 188 
 189                 centre = (curValue == DRM_MODE_SCALE_NO_SCALE) ||
 190                         (value == DRM_MODE_SCALE_NO_SCALE);
 191 
 192                 if (crtc->saved_mode.hdisplay != 0 &&
 193                     crtc->saved_mode.vdisplay != 0) {
 194                         if (centre) {
 195                                 if (!drm_crtc_helper_set_mode(encoder->crtc, &crtc->saved_mode,
 196                                             encoder->crtc->x, encoder->crtc->y, encoder->crtc->primary->fb))
 197                                         return -1;
 198                         } else {
 199                                 const struct drm_encoder_helper_funcs *helpers
 200                                                     = encoder->helper_private;
 201                                 helpers->mode_set(encoder, &crtc->saved_mode,
 202                                              &crtc->saved_adjusted_mode);
 203                         }
 204                 }
 205         }
 206         return 0;
 207 }
 208 
 209 /*
 210  * Return the list of HDMI DDC modes if available.
 211  */
 212 static int cdv_hdmi_get_modes(struct drm_connector *connector)
 213 {
 214         struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
 215         struct edid *edid = NULL;
 216         int ret = 0;
 217 
 218         edid = drm_get_edid(connector, &gma_encoder->i2c_bus->adapter);
 219         if (edid) {
 220                 drm_connector_update_edid_property(connector, edid);
 221                 ret = drm_add_edid_modes(connector, edid);
 222                 kfree(edid);
 223         }
 224         return ret;
 225 }
 226 
 227 static enum drm_mode_status cdv_hdmi_mode_valid(struct drm_connector *connector,
 228                                  struct drm_display_mode *mode)
 229 {
 230         if (mode->clock > 165000)
 231                 return MODE_CLOCK_HIGH;
 232         if (mode->clock < 20000)
 233                 return MODE_CLOCK_HIGH;
 234 
 235         /* just in case */
 236         if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
 237                 return MODE_NO_DBLESCAN;
 238 
 239         /* just in case */
 240         if (mode->flags & DRM_MODE_FLAG_INTERLACE)
 241                 return MODE_NO_INTERLACE;
 242 
 243         return MODE_OK;
 244 }
 245 
 246 static void cdv_hdmi_destroy(struct drm_connector *connector)
 247 {
 248         struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
 249 
 250         psb_intel_i2c_destroy(gma_encoder->i2c_bus);
 251         drm_connector_unregister(connector);
 252         drm_connector_cleanup(connector);
 253         kfree(connector);
 254 }
 255 
 256 static const struct drm_encoder_helper_funcs cdv_hdmi_helper_funcs = {
 257         .dpms = cdv_hdmi_dpms,
 258         .prepare = gma_encoder_prepare,
 259         .mode_set = cdv_hdmi_mode_set,
 260         .commit = gma_encoder_commit,
 261 };
 262 
 263 static const struct drm_connector_helper_funcs
 264                                         cdv_hdmi_connector_helper_funcs = {
 265         .get_modes = cdv_hdmi_get_modes,
 266         .mode_valid = cdv_hdmi_mode_valid,
 267         .best_encoder = gma_best_encoder,
 268 };
 269 
 270 static const struct drm_connector_funcs cdv_hdmi_connector_funcs = {
 271         .dpms = drm_helper_connector_dpms,
 272         .detect = cdv_hdmi_detect,
 273         .fill_modes = drm_helper_probe_single_connector_modes,
 274         .set_property = cdv_hdmi_set_property,
 275         .destroy = cdv_hdmi_destroy,
 276 };
 277 
 278 void cdv_hdmi_init(struct drm_device *dev,
 279                         struct psb_intel_mode_device *mode_dev, int reg)
 280 {
 281         struct gma_encoder *gma_encoder;
 282         struct gma_connector *gma_connector;
 283         struct drm_connector *connector;
 284         struct drm_encoder *encoder;
 285         struct mid_intel_hdmi_priv *hdmi_priv;
 286         int ddc_bus;
 287 
 288         gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL);
 289 
 290         if (!gma_encoder)
 291                 return;
 292 
 293         gma_connector = kzalloc(sizeof(struct gma_connector),
 294                                       GFP_KERNEL);
 295 
 296         if (!gma_connector)
 297                 goto err_connector;
 298 
 299         hdmi_priv = kzalloc(sizeof(struct mid_intel_hdmi_priv), GFP_KERNEL);
 300 
 301         if (!hdmi_priv)
 302                 goto err_priv;
 303 
 304         connector = &gma_connector->base;
 305         connector->polled = DRM_CONNECTOR_POLL_HPD;
 306         gma_connector->save = cdv_hdmi_save;
 307         gma_connector->restore = cdv_hdmi_restore;
 308 
 309         encoder = &gma_encoder->base;
 310         drm_connector_init(dev, connector,
 311                            &cdv_hdmi_connector_funcs,
 312                            DRM_MODE_CONNECTOR_DVID);
 313 
 314         drm_encoder_init(dev, encoder, &psb_intel_lvds_enc_funcs,
 315                          DRM_MODE_ENCODER_TMDS, NULL);
 316 
 317         gma_connector_attach_encoder(gma_connector, gma_encoder);
 318         gma_encoder->type = INTEL_OUTPUT_HDMI;
 319         hdmi_priv->hdmi_reg = reg;
 320         hdmi_priv->has_hdmi_sink = false;
 321         gma_encoder->dev_priv = hdmi_priv;
 322 
 323         drm_encoder_helper_add(encoder, &cdv_hdmi_helper_funcs);
 324         drm_connector_helper_add(connector,
 325                                  &cdv_hdmi_connector_helper_funcs);
 326         connector->display_info.subpixel_order = SubPixelHorizontalRGB;
 327         connector->interlace_allowed = false;
 328         connector->doublescan_allowed = false;
 329 
 330         drm_object_attach_property(&connector->base,
 331                                       dev->mode_config.scaling_mode_property,
 332                                       DRM_MODE_SCALE_FULLSCREEN);
 333 
 334         switch (reg) {
 335         case SDVOB:
 336                 ddc_bus = GPIOE;
 337                 gma_encoder->ddi_select = DDI0_SELECT;
 338                 break;
 339         case SDVOC:
 340                 ddc_bus = GPIOD;
 341                 gma_encoder->ddi_select = DDI1_SELECT;
 342                 break;
 343         default:
 344                 DRM_ERROR("unknown reg 0x%x for HDMI\n", reg);
 345                 goto failed_ddc;
 346                 break;
 347         }
 348 
 349         gma_encoder->i2c_bus = psb_intel_i2c_create(dev,
 350                                 ddc_bus, (reg == SDVOB) ? "HDMIB" : "HDMIC");
 351 
 352         if (!gma_encoder->i2c_bus) {
 353                 dev_err(dev->dev, "No ddc adapter available!\n");
 354                 goto failed_ddc;
 355         }
 356 
 357         hdmi_priv->hdmi_i2c_adapter = &(gma_encoder->i2c_bus->adapter);
 358         hdmi_priv->dev = dev;
 359         drm_connector_register(connector);
 360         return;
 361 
 362 failed_ddc:
 363         drm_encoder_cleanup(encoder);
 364         drm_connector_cleanup(connector);
 365 err_priv:
 366         kfree(gma_connector);
 367 err_connector:
 368         kfree(gma_encoder);
 369 }

/* [<][>][^][v][top][bottom][index][help] */