cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cdv_intel_crt.c (8020B)


      1/*
      2 * Copyright © 2006-2007 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 *	Eric Anholt <eric@anholt.net>
     25 */
     26
     27#include <linux/delay.h>
     28#include <linux/i2c.h>
     29#include <linux/pm_runtime.h>
     30
     31#include <drm/drm_simple_kms_helper.h>
     32
     33#include "cdv_device.h"
     34#include "intel_bios.h"
     35#include "power.h"
     36#include "psb_drv.h"
     37#include "psb_intel_drv.h"
     38#include "psb_intel_reg.h"
     39
     40
     41static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode)
     42{
     43	struct drm_device *dev = encoder->dev;
     44	u32 temp, reg;
     45	reg = ADPA;
     46
     47	temp = REG_READ(reg);
     48	temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
     49	temp &= ~ADPA_DAC_ENABLE;
     50
     51	switch (mode) {
     52	case DRM_MODE_DPMS_ON:
     53		temp |= ADPA_DAC_ENABLE;
     54		break;
     55	case DRM_MODE_DPMS_STANDBY:
     56		temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
     57		break;
     58	case DRM_MODE_DPMS_SUSPEND:
     59		temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
     60		break;
     61	case DRM_MODE_DPMS_OFF:
     62		temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
     63		break;
     64	}
     65
     66	REG_WRITE(reg, temp);
     67}
     68
     69static enum drm_mode_status cdv_intel_crt_mode_valid(struct drm_connector *connector,
     70				struct drm_display_mode *mode)
     71{
     72	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
     73		return MODE_NO_DBLESCAN;
     74
     75	/* The lowest clock for CDV is 20000KHz */
     76	if (mode->clock < 20000)
     77		return MODE_CLOCK_LOW;
     78
     79	/* The max clock for CDV is 355 instead of 400 */
     80	if (mode->clock > 355000)
     81		return MODE_CLOCK_HIGH;
     82
     83	return MODE_OK;
     84}
     85
     86static void cdv_intel_crt_mode_set(struct drm_encoder *encoder,
     87			       struct drm_display_mode *mode,
     88			       struct drm_display_mode *adjusted_mode)
     89{
     90
     91	struct drm_device *dev = encoder->dev;
     92	struct drm_crtc *crtc = encoder->crtc;
     93	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
     94	int dpll_md_reg;
     95	u32 adpa, dpll_md;
     96	u32 adpa_reg;
     97
     98	if (gma_crtc->pipe == 0)
     99		dpll_md_reg = DPLL_A_MD;
    100	else
    101		dpll_md_reg = DPLL_B_MD;
    102
    103	adpa_reg = ADPA;
    104
    105	/*
    106	 * Disable separate mode multiplier used when cloning SDVO to CRT
    107	 * XXX this needs to be adjusted when we really are cloning
    108	 */
    109	{
    110		dpll_md = REG_READ(dpll_md_reg);
    111		REG_WRITE(dpll_md_reg,
    112			   dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
    113	}
    114
    115	adpa = 0;
    116	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
    117		adpa |= ADPA_HSYNC_ACTIVE_HIGH;
    118	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
    119		adpa |= ADPA_VSYNC_ACTIVE_HIGH;
    120
    121	if (gma_crtc->pipe == 0)
    122		adpa |= ADPA_PIPE_A_SELECT;
    123	else
    124		adpa |= ADPA_PIPE_B_SELECT;
    125
    126	REG_WRITE(adpa_reg, adpa);
    127}
    128
    129
    130/*
    131 * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
    132 *
    133 * \return true if CRT is connected.
    134 * \return false if CRT is disconnected.
    135 */
    136static bool cdv_intel_crt_detect_hotplug(struct drm_connector *connector,
    137								bool force)
    138{
    139	struct drm_device *dev = connector->dev;
    140	u32 hotplug_en;
    141	int i, tries = 0, ret = false;
    142	u32 orig;
    143
    144	/*
    145	 * On a CDV thep, CRT detect sequence need to be done twice
    146	 * to get a reliable result.
    147	 */
    148	tries = 2;
    149
    150	orig = hotplug_en = REG_READ(PORT_HOTPLUG_EN);
    151	hotplug_en &= ~(CRT_HOTPLUG_DETECT_MASK);
    152	hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
    153
    154	hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
    155	hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
    156
    157	for (i = 0; i < tries ; i++) {
    158		unsigned long timeout;
    159		/* turn on the FORCE_DETECT */
    160		REG_WRITE(PORT_HOTPLUG_EN, hotplug_en);
    161		timeout = jiffies + msecs_to_jiffies(1000);
    162		/* wait for FORCE_DETECT to go off */
    163		do {
    164			if (!(REG_READ(PORT_HOTPLUG_EN) &
    165					CRT_HOTPLUG_FORCE_DETECT))
    166				break;
    167			msleep(1);
    168		} while (time_after(timeout, jiffies));
    169	}
    170
    171	if ((REG_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) !=
    172	    CRT_HOTPLUG_MONITOR_NONE)
    173		ret = true;
    174
    175	 /* clear the interrupt we just generated, if any */
    176	REG_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS);
    177
    178	/* and put the bits back */
    179	REG_WRITE(PORT_HOTPLUG_EN, orig);
    180	return ret;
    181}
    182
    183static enum drm_connector_status cdv_intel_crt_detect(
    184				struct drm_connector *connector, bool force)
    185{
    186	if (cdv_intel_crt_detect_hotplug(connector, force))
    187		return connector_status_connected;
    188	else
    189		return connector_status_disconnected;
    190}
    191
    192static void cdv_intel_crt_destroy(struct drm_connector *connector)
    193{
    194	struct gma_connector *gma_connector = to_gma_connector(connector);
    195	struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
    196
    197	psb_intel_i2c_destroy(gma_encoder->ddc_bus);
    198	drm_connector_cleanup(connector);
    199	kfree(gma_connector);
    200}
    201
    202static int cdv_intel_crt_get_modes(struct drm_connector *connector)
    203{
    204	struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
    205	return psb_intel_ddc_get_modes(connector,
    206				       &gma_encoder->ddc_bus->adapter);
    207}
    208
    209static int cdv_intel_crt_set_property(struct drm_connector *connector,
    210				  struct drm_property *property,
    211				  uint64_t value)
    212{
    213	return 0;
    214}
    215
    216/*
    217 * Routines for controlling stuff on the analog port
    218 */
    219
    220static const struct drm_encoder_helper_funcs cdv_intel_crt_helper_funcs = {
    221	.dpms = cdv_intel_crt_dpms,
    222	.prepare = gma_encoder_prepare,
    223	.commit = gma_encoder_commit,
    224	.mode_set = cdv_intel_crt_mode_set,
    225};
    226
    227static const struct drm_connector_funcs cdv_intel_crt_connector_funcs = {
    228	.dpms = drm_helper_connector_dpms,
    229	.detect = cdv_intel_crt_detect,
    230	.fill_modes = drm_helper_probe_single_connector_modes,
    231	.destroy = cdv_intel_crt_destroy,
    232	.set_property = cdv_intel_crt_set_property,
    233};
    234
    235static const struct drm_connector_helper_funcs
    236				cdv_intel_crt_connector_helper_funcs = {
    237	.mode_valid = cdv_intel_crt_mode_valid,
    238	.get_modes = cdv_intel_crt_get_modes,
    239	.best_encoder = gma_best_encoder,
    240};
    241
    242void cdv_intel_crt_init(struct drm_device *dev,
    243			struct psb_intel_mode_device *mode_dev)
    244{
    245
    246	struct gma_connector *gma_connector;
    247	struct gma_encoder *gma_encoder;
    248	struct drm_connector *connector;
    249	struct drm_encoder *encoder;
    250
    251	gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL);
    252	if (!gma_encoder)
    253		return;
    254
    255	gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL);
    256	if (!gma_connector)
    257		goto failed_connector;
    258
    259	connector = &gma_connector->base;
    260	connector->polled = DRM_CONNECTOR_POLL_HPD;
    261	drm_connector_init(dev, connector,
    262		&cdv_intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
    263
    264	encoder = &gma_encoder->base;
    265	drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_DAC);
    266
    267	gma_connector_attach_encoder(gma_connector, gma_encoder);
    268
    269	/* Set up the DDC bus. */
    270	gma_encoder->ddc_bus = psb_intel_i2c_create(dev, GPIOA, "CRTDDC_A");
    271	if (!gma_encoder->ddc_bus) {
    272		dev_printk(KERN_ERR, dev->dev, "DDC bus registration failed.\n");
    273		goto failed_ddc;
    274	}
    275
    276	gma_encoder->type = INTEL_OUTPUT_ANALOG;
    277	connector->interlace_allowed = 0;
    278	connector->doublescan_allowed = 0;
    279
    280	drm_encoder_helper_add(encoder, &cdv_intel_crt_helper_funcs);
    281	drm_connector_helper_add(connector,
    282					&cdv_intel_crt_connector_helper_funcs);
    283
    284	return;
    285failed_ddc:
    286	drm_encoder_cleanup(&gma_encoder->base);
    287	drm_connector_cleanup(&gma_connector->base);
    288	kfree(gma_connector);
    289failed_connector:
    290	kfree(gma_encoder);
    291	return;
    292}