Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright © 2006-2011 Intel Corporation
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice (including the next
0012  * paragraph) shall be included in all copies or substantial portions of the
0013  * Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0018  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0020  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0021  * DEALINGS IN THE SOFTWARE.
0022  *
0023  * Authors:
0024  *  jim liu <jim.liu@intel.com>
0025  */
0026 
0027 #include <linux/pm_runtime.h>
0028 
0029 #include <drm/drm.h>
0030 #include <drm/drm_crtc.h>
0031 #include <drm/drm_edid.h>
0032 #include <drm/drm_simple_kms_helper.h>
0033 
0034 #include "cdv_device.h"
0035 #include "psb_drv.h"
0036 #include "psb_intel_drv.h"
0037 #include "psb_intel_reg.h"
0038 
0039 /* hdmi control bits */
0040 #define HDMI_NULL_PACKETS_DURING_VSYNC  (1 << 9)
0041 #define HDMI_BORDER_ENABLE      (1 << 7)
0042 #define HDMI_AUDIO_ENABLE       (1 << 6)
0043 #define HDMI_VSYNC_ACTIVE_HIGH      (1 << 4)
0044 #define HDMI_HSYNC_ACTIVE_HIGH      (1 << 3)
0045 /* hdmi-b control bits */
0046 #define HDMIB_PIPE_B_SELECT     (1 << 30)
0047 
0048 
0049 struct mid_intel_hdmi_priv {
0050     u32 hdmi_reg;
0051     u32 save_HDMIB;
0052     bool has_hdmi_sink;
0053     bool has_hdmi_audio;
0054     /* Should set this when detect hotplug */
0055     bool hdmi_device_connected;
0056     struct drm_device *dev;
0057 };
0058 
0059 static void cdv_hdmi_mode_set(struct drm_encoder *encoder,
0060             struct drm_display_mode *mode,
0061             struct drm_display_mode *adjusted_mode)
0062 {
0063     struct drm_device *dev = encoder->dev;
0064     struct gma_encoder *gma_encoder = to_gma_encoder(encoder);
0065     struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv;
0066     u32 hdmib;
0067     struct drm_crtc *crtc = encoder->crtc;
0068     struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
0069 
0070     hdmib = (2 << 10);
0071 
0072     if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
0073         hdmib |= HDMI_VSYNC_ACTIVE_HIGH;
0074     if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
0075         hdmib |= HDMI_HSYNC_ACTIVE_HIGH;
0076 
0077     if (gma_crtc->pipe == 1)
0078         hdmib |= HDMIB_PIPE_B_SELECT;
0079 
0080     if (hdmi_priv->has_hdmi_audio) {
0081         hdmib |= HDMI_AUDIO_ENABLE;
0082         hdmib |= HDMI_NULL_PACKETS_DURING_VSYNC;
0083     }
0084 
0085     REG_WRITE(hdmi_priv->hdmi_reg, hdmib);
0086     REG_READ(hdmi_priv->hdmi_reg);
0087 }
0088 
0089 static void cdv_hdmi_dpms(struct drm_encoder *encoder, int mode)
0090 {
0091     struct drm_device *dev = encoder->dev;
0092     struct gma_encoder *gma_encoder = to_gma_encoder(encoder);
0093     struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv;
0094     u32 hdmib;
0095 
0096     hdmib = REG_READ(hdmi_priv->hdmi_reg);
0097 
0098     if (mode != DRM_MODE_DPMS_ON)
0099         REG_WRITE(hdmi_priv->hdmi_reg, hdmib & ~HDMIB_PORT_EN);
0100     else
0101         REG_WRITE(hdmi_priv->hdmi_reg, hdmib | HDMIB_PORT_EN);
0102     REG_READ(hdmi_priv->hdmi_reg);
0103 }
0104 
0105 static void cdv_hdmi_save(struct drm_connector *connector)
0106 {
0107     struct drm_device *dev = connector->dev;
0108     struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
0109     struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv;
0110 
0111     hdmi_priv->save_HDMIB = REG_READ(hdmi_priv->hdmi_reg);
0112 }
0113 
0114 static void cdv_hdmi_restore(struct drm_connector *connector)
0115 {
0116     struct drm_device *dev = connector->dev;
0117     struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
0118     struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv;
0119 
0120     REG_WRITE(hdmi_priv->hdmi_reg, hdmi_priv->save_HDMIB);
0121     REG_READ(hdmi_priv->hdmi_reg);
0122 }
0123 
0124 static enum drm_connector_status cdv_hdmi_detect(
0125                 struct drm_connector *connector, bool force)
0126 {
0127     struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
0128     struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv;
0129     struct edid *edid = NULL;
0130     enum drm_connector_status status = connector_status_disconnected;
0131 
0132     edid = drm_get_edid(connector, connector->ddc);
0133 
0134     hdmi_priv->has_hdmi_sink = false;
0135     hdmi_priv->has_hdmi_audio = false;
0136     if (edid) {
0137         if (edid->input & DRM_EDID_INPUT_DIGITAL) {
0138             status = connector_status_connected;
0139             hdmi_priv->has_hdmi_sink =
0140                         drm_detect_hdmi_monitor(edid);
0141             hdmi_priv->has_hdmi_audio =
0142                         drm_detect_monitor_audio(edid);
0143         }
0144         kfree(edid);
0145     }
0146     return status;
0147 }
0148 
0149 static int cdv_hdmi_set_property(struct drm_connector *connector,
0150                        struct drm_property *property,
0151                        uint64_t value)
0152 {
0153     struct drm_encoder *encoder = connector->encoder;
0154 
0155     if (!strcmp(property->name, "scaling mode") && encoder) {
0156         struct gma_crtc *crtc = to_gma_crtc(encoder->crtc);
0157         bool centre;
0158         uint64_t curValue;
0159 
0160         if (!crtc)
0161             return -1;
0162 
0163         switch (value) {
0164         case DRM_MODE_SCALE_FULLSCREEN:
0165             break;
0166         case DRM_MODE_SCALE_NO_SCALE:
0167             break;
0168         case DRM_MODE_SCALE_ASPECT:
0169             break;
0170         default:
0171             return -1;
0172         }
0173 
0174         if (drm_object_property_get_value(&connector->base,
0175                             property, &curValue))
0176             return -1;
0177 
0178         if (curValue == value)
0179             return 0;
0180 
0181         if (drm_object_property_set_value(&connector->base,
0182                             property, value))
0183             return -1;
0184 
0185         centre = (curValue == DRM_MODE_SCALE_NO_SCALE) ||
0186             (value == DRM_MODE_SCALE_NO_SCALE);
0187 
0188         if (crtc->saved_mode.hdisplay != 0 &&
0189             crtc->saved_mode.vdisplay != 0) {
0190             if (centre) {
0191                 if (!drm_crtc_helper_set_mode(encoder->crtc, &crtc->saved_mode,
0192                         encoder->crtc->x, encoder->crtc->y, encoder->crtc->primary->fb))
0193                     return -1;
0194             } else {
0195                 const struct drm_encoder_helper_funcs *helpers
0196                             = encoder->helper_private;
0197                 helpers->mode_set(encoder, &crtc->saved_mode,
0198                          &crtc->saved_adjusted_mode);
0199             }
0200         }
0201     }
0202     return 0;
0203 }
0204 
0205 /*
0206  * Return the list of HDMI DDC modes if available.
0207  */
0208 static int cdv_hdmi_get_modes(struct drm_connector *connector)
0209 {
0210     struct edid *edid = NULL;
0211     int ret = 0;
0212 
0213     edid = drm_get_edid(connector, connector->ddc);
0214     if (edid) {
0215         drm_connector_update_edid_property(connector, edid);
0216         ret = drm_add_edid_modes(connector, edid);
0217         kfree(edid);
0218     }
0219     return ret;
0220 }
0221 
0222 static enum drm_mode_status cdv_hdmi_mode_valid(struct drm_connector *connector,
0223                  struct drm_display_mode *mode)
0224 {
0225     if (mode->clock > 165000)
0226         return MODE_CLOCK_HIGH;
0227     if (mode->clock < 20000)
0228         return MODE_CLOCK_HIGH;
0229 
0230     /* just in case */
0231     if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
0232         return MODE_NO_DBLESCAN;
0233 
0234     /* just in case */
0235     if (mode->flags & DRM_MODE_FLAG_INTERLACE)
0236         return MODE_NO_INTERLACE;
0237 
0238     return MODE_OK;
0239 }
0240 
0241 static void cdv_hdmi_destroy(struct drm_connector *connector)
0242 {
0243     struct gma_connector *gma_connector = to_gma_connector(connector);
0244     struct gma_i2c_chan *ddc_bus = to_gma_i2c_chan(connector->ddc);
0245 
0246     gma_i2c_destroy(ddc_bus);
0247     drm_connector_cleanup(connector);
0248     kfree(gma_connector);
0249 }
0250 
0251 static const struct drm_encoder_helper_funcs cdv_hdmi_helper_funcs = {
0252     .dpms = cdv_hdmi_dpms,
0253     .prepare = gma_encoder_prepare,
0254     .mode_set = cdv_hdmi_mode_set,
0255     .commit = gma_encoder_commit,
0256 };
0257 
0258 static const struct drm_connector_helper_funcs
0259                     cdv_hdmi_connector_helper_funcs = {
0260     .get_modes = cdv_hdmi_get_modes,
0261     .mode_valid = cdv_hdmi_mode_valid,
0262     .best_encoder = gma_best_encoder,
0263 };
0264 
0265 static const struct drm_connector_funcs cdv_hdmi_connector_funcs = {
0266     .dpms = drm_helper_connector_dpms,
0267     .detect = cdv_hdmi_detect,
0268     .fill_modes = drm_helper_probe_single_connector_modes,
0269     .set_property = cdv_hdmi_set_property,
0270     .destroy = cdv_hdmi_destroy,
0271 };
0272 
0273 void cdv_hdmi_init(struct drm_device *dev,
0274             struct psb_intel_mode_device *mode_dev, int reg)
0275 {
0276     struct gma_encoder *gma_encoder;
0277     struct gma_connector *gma_connector;
0278     struct drm_connector *connector;
0279     struct mid_intel_hdmi_priv *hdmi_priv;
0280     struct gma_i2c_chan *ddc_bus;
0281     int ddc_reg;
0282     int ret;
0283 
0284     gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL);
0285     if (!gma_encoder)
0286         return;
0287 
0288     gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL);
0289     if (!gma_connector)
0290         goto err_free_encoder;
0291 
0292     hdmi_priv = kzalloc(sizeof(struct mid_intel_hdmi_priv), GFP_KERNEL);
0293     if (!hdmi_priv)
0294         goto err_free_connector;
0295 
0296     connector = &gma_connector->base;
0297     connector->polled = DRM_CONNECTOR_POLL_HPD;
0298     gma_connector->save = cdv_hdmi_save;
0299     gma_connector->restore = cdv_hdmi_restore;
0300 
0301     switch (reg) {
0302     case SDVOB:
0303         ddc_reg = GPIOE;
0304         gma_encoder->ddi_select = DDI0_SELECT;
0305         break;
0306     case SDVOC:
0307         ddc_reg = GPIOD;
0308         gma_encoder->ddi_select = DDI1_SELECT;
0309         break;
0310     default:
0311         DRM_ERROR("unknown reg 0x%x for HDMI\n", reg);
0312         goto err_free_hdmi_priv;
0313     }
0314 
0315     ddc_bus = gma_i2c_create(dev, ddc_reg,
0316                  (reg == SDVOB) ? "HDMIB" : "HDMIC");
0317     if (!ddc_bus) {
0318         dev_err(dev->dev, "No ddc adapter available!\n");
0319         goto err_free_hdmi_priv;
0320     }
0321 
0322     ret = drm_connector_init_with_ddc(dev, connector,
0323                       &cdv_hdmi_connector_funcs,
0324                       DRM_MODE_CONNECTOR_DVID,
0325                       &ddc_bus->base);
0326     if (ret)
0327         goto err_ddc_destroy;
0328 
0329     ret = drm_simple_encoder_init(dev, &gma_encoder->base,
0330                       DRM_MODE_ENCODER_TMDS);
0331     if (ret)
0332         goto err_connector_cleanup;
0333 
0334     gma_connector_attach_encoder(gma_connector, gma_encoder);
0335     gma_encoder->type = INTEL_OUTPUT_HDMI;
0336     hdmi_priv->hdmi_reg = reg;
0337     hdmi_priv->has_hdmi_sink = false;
0338     gma_encoder->dev_priv = hdmi_priv;
0339 
0340     drm_encoder_helper_add(&gma_encoder->base, &cdv_hdmi_helper_funcs);
0341     drm_connector_helper_add(connector,
0342                  &cdv_hdmi_connector_helper_funcs);
0343     connector->display_info.subpixel_order = SubPixelHorizontalRGB;
0344     connector->interlace_allowed = false;
0345     connector->doublescan_allowed = false;
0346 
0347     drm_object_attach_property(&connector->base,
0348                       dev->mode_config.scaling_mode_property,
0349                       DRM_MODE_SCALE_FULLSCREEN);
0350 
0351     hdmi_priv->dev = dev;
0352     return;
0353 
0354 err_connector_cleanup:
0355     drm_connector_cleanup(connector);
0356 err_ddc_destroy:
0357     gma_i2c_destroy(ddc_bus);
0358 err_free_hdmi_priv:
0359     kfree(hdmi_priv);
0360 err_free_connector:
0361     kfree(gma_connector);
0362 err_free_encoder:
0363     kfree(gma_encoder);
0364 }