Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright © 2006-2007 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  *  Eric Anholt <eric@anholt.net>
0025  */
0026 
0027 #include <linux/delay.h>
0028 #include <linux/i2c.h>
0029 #include <linux/pm_runtime.h>
0030 
0031 #include <drm/drm_simple_kms_helper.h>
0032 
0033 #include "cdv_device.h"
0034 #include "intel_bios.h"
0035 #include "power.h"
0036 #include "psb_drv.h"
0037 #include "psb_intel_drv.h"
0038 #include "psb_intel_reg.h"
0039 
0040 
0041 static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode)
0042 {
0043     struct drm_device *dev = encoder->dev;
0044     u32 temp, reg;
0045     reg = ADPA;
0046 
0047     temp = REG_READ(reg);
0048     temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
0049     temp &= ~ADPA_DAC_ENABLE;
0050 
0051     switch (mode) {
0052     case DRM_MODE_DPMS_ON:
0053         temp |= ADPA_DAC_ENABLE;
0054         break;
0055     case DRM_MODE_DPMS_STANDBY:
0056         temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
0057         break;
0058     case DRM_MODE_DPMS_SUSPEND:
0059         temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
0060         break;
0061     case DRM_MODE_DPMS_OFF:
0062         temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
0063         break;
0064     }
0065 
0066     REG_WRITE(reg, temp);
0067 }
0068 
0069 static enum drm_mode_status cdv_intel_crt_mode_valid(struct drm_connector *connector,
0070                 struct drm_display_mode *mode)
0071 {
0072     if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
0073         return MODE_NO_DBLESCAN;
0074 
0075     /* The lowest clock for CDV is 20000KHz */
0076     if (mode->clock < 20000)
0077         return MODE_CLOCK_LOW;
0078 
0079     /* The max clock for CDV is 355 instead of 400 */
0080     if (mode->clock > 355000)
0081         return MODE_CLOCK_HIGH;
0082 
0083     return MODE_OK;
0084 }
0085 
0086 static void cdv_intel_crt_mode_set(struct drm_encoder *encoder,
0087                    struct drm_display_mode *mode,
0088                    struct drm_display_mode *adjusted_mode)
0089 {
0090 
0091     struct drm_device *dev = encoder->dev;
0092     struct drm_crtc *crtc = encoder->crtc;
0093     struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
0094     int dpll_md_reg;
0095     u32 adpa, dpll_md;
0096     u32 adpa_reg;
0097 
0098     if (gma_crtc->pipe == 0)
0099         dpll_md_reg = DPLL_A_MD;
0100     else
0101         dpll_md_reg = DPLL_B_MD;
0102 
0103     adpa_reg = ADPA;
0104 
0105     /*
0106      * Disable separate mode multiplier used when cloning SDVO to CRT
0107      * XXX this needs to be adjusted when we really are cloning
0108      */
0109     {
0110         dpll_md = REG_READ(dpll_md_reg);
0111         REG_WRITE(dpll_md_reg,
0112                dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
0113     }
0114 
0115     adpa = 0;
0116     if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
0117         adpa |= ADPA_HSYNC_ACTIVE_HIGH;
0118     if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
0119         adpa |= ADPA_VSYNC_ACTIVE_HIGH;
0120 
0121     if (gma_crtc->pipe == 0)
0122         adpa |= ADPA_PIPE_A_SELECT;
0123     else
0124         adpa |= ADPA_PIPE_B_SELECT;
0125 
0126     REG_WRITE(adpa_reg, adpa);
0127 }
0128 
0129 
0130 /*
0131  * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
0132  *
0133  * \return true if CRT is connected.
0134  * \return false if CRT is disconnected.
0135  */
0136 static bool cdv_intel_crt_detect_hotplug(struct drm_connector *connector,
0137                                 bool force)
0138 {
0139     struct drm_device *dev = connector->dev;
0140     u32 hotplug_en;
0141     int i, tries = 0, ret = false;
0142     u32 orig;
0143 
0144     /*
0145      * On a CDV thep, CRT detect sequence need to be done twice
0146      * to get a reliable result.
0147      */
0148     tries = 2;
0149 
0150     orig = hotplug_en = REG_READ(PORT_HOTPLUG_EN);
0151     hotplug_en &= ~(CRT_HOTPLUG_DETECT_MASK);
0152     hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
0153 
0154     hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
0155     hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
0156 
0157     for (i = 0; i < tries ; i++) {
0158         unsigned long timeout;
0159         /* turn on the FORCE_DETECT */
0160         REG_WRITE(PORT_HOTPLUG_EN, hotplug_en);
0161         timeout = jiffies + msecs_to_jiffies(1000);
0162         /* wait for FORCE_DETECT to go off */
0163         do {
0164             if (!(REG_READ(PORT_HOTPLUG_EN) &
0165                     CRT_HOTPLUG_FORCE_DETECT))
0166                 break;
0167             msleep(1);
0168         } while (time_after(timeout, jiffies));
0169     }
0170 
0171     if ((REG_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) !=
0172         CRT_HOTPLUG_MONITOR_NONE)
0173         ret = true;
0174 
0175      /* clear the interrupt we just generated, if any */
0176     REG_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS);
0177 
0178     /* and put the bits back */
0179     REG_WRITE(PORT_HOTPLUG_EN, orig);
0180     return ret;
0181 }
0182 
0183 static enum drm_connector_status cdv_intel_crt_detect(
0184                 struct drm_connector *connector, bool force)
0185 {
0186     if (cdv_intel_crt_detect_hotplug(connector, force))
0187         return connector_status_connected;
0188     else
0189         return connector_status_disconnected;
0190 }
0191 
0192 static void cdv_intel_crt_destroy(struct drm_connector *connector)
0193 {
0194     struct gma_connector *gma_connector = to_gma_connector(connector);
0195     struct gma_i2c_chan *ddc_bus = to_gma_i2c_chan(connector->ddc);
0196 
0197     gma_i2c_destroy(ddc_bus);
0198     drm_connector_cleanup(connector);
0199     kfree(gma_connector);
0200 }
0201 
0202 static int cdv_intel_crt_get_modes(struct drm_connector *connector)
0203 {
0204     return psb_intel_ddc_get_modes(connector, connector->ddc);
0205 }
0206 
0207 static int cdv_intel_crt_set_property(struct drm_connector *connector,
0208                   struct drm_property *property,
0209                   uint64_t value)
0210 {
0211     return 0;
0212 }
0213 
0214 /*
0215  * Routines for controlling stuff on the analog port
0216  */
0217 
0218 static const struct drm_encoder_helper_funcs cdv_intel_crt_helper_funcs = {
0219     .dpms = cdv_intel_crt_dpms,
0220     .prepare = gma_encoder_prepare,
0221     .commit = gma_encoder_commit,
0222     .mode_set = cdv_intel_crt_mode_set,
0223 };
0224 
0225 static const struct drm_connector_funcs cdv_intel_crt_connector_funcs = {
0226     .dpms = drm_helper_connector_dpms,
0227     .detect = cdv_intel_crt_detect,
0228     .fill_modes = drm_helper_probe_single_connector_modes,
0229     .destroy = cdv_intel_crt_destroy,
0230     .set_property = cdv_intel_crt_set_property,
0231 };
0232 
0233 static const struct drm_connector_helper_funcs
0234                 cdv_intel_crt_connector_helper_funcs = {
0235     .mode_valid = cdv_intel_crt_mode_valid,
0236     .get_modes = cdv_intel_crt_get_modes,
0237     .best_encoder = gma_best_encoder,
0238 };
0239 
0240 void cdv_intel_crt_init(struct drm_device *dev,
0241             struct psb_intel_mode_device *mode_dev)
0242 {
0243 
0244     struct gma_connector *gma_connector;
0245     struct gma_encoder *gma_encoder;
0246     struct gma_i2c_chan *ddc_bus;
0247     struct drm_connector *connector;
0248     struct drm_encoder *encoder;
0249     int ret;
0250 
0251     gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL);
0252     if (!gma_encoder)
0253         return;
0254 
0255     gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL);
0256     if (!gma_connector)
0257         goto err_free_encoder;
0258 
0259     /* Set up the DDC bus. */
0260     ddc_bus = gma_i2c_create(dev, GPIOA, "CRTDDC_A");
0261     if (!ddc_bus) {
0262         dev_printk(KERN_ERR, dev->dev, "DDC bus registration failed.\n");
0263         goto err_free_connector;
0264     }
0265 
0266     connector = &gma_connector->base;
0267     connector->polled = DRM_CONNECTOR_POLL_HPD;
0268     ret = drm_connector_init_with_ddc(dev, connector,
0269                       &cdv_intel_crt_connector_funcs,
0270                       DRM_MODE_CONNECTOR_VGA,
0271                       &ddc_bus->base);
0272     if (ret)
0273         goto err_ddc_destroy;
0274 
0275     encoder = &gma_encoder->base;
0276     ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_DAC);
0277     if (ret)
0278         goto err_connector_cleanup;
0279 
0280     gma_connector_attach_encoder(gma_connector, gma_encoder);
0281 
0282     gma_encoder->type = INTEL_OUTPUT_ANALOG;
0283     connector->interlace_allowed = 0;
0284     connector->doublescan_allowed = 0;
0285 
0286     drm_encoder_helper_add(encoder, &cdv_intel_crt_helper_funcs);
0287     drm_connector_helper_add(connector,
0288                     &cdv_intel_crt_connector_helper_funcs);
0289 
0290     return;
0291 
0292 err_connector_cleanup:
0293     drm_connector_cleanup(&gma_connector->base);
0294 err_ddc_destroy:
0295     gma_i2c_destroy(ddc_bus);
0296 err_free_connector:
0297     kfree(gma_connector);
0298 err_free_encoder:
0299     kfree(gma_encoder);
0300     return;
0301 }