summaryrefslogtreecommitdiff
AgeCommit message (Expand)Author
2005-06-27Check for 2.6.12 suspend/resume changes (pm_message_t)Alan Hourihane
2005-06-27Check dev_privAlan Hourihane
2005-06-27Save state of registers for suspend/resume.Alan Hourihane
2005-06-26removed dev->sysdev_registeredJon Smirl
2005-06-24Ref count the sysdev class to support multiple DRM cardsJon Smirl
2005-06-24Make sysdev class only register when fbdev detectedJon Smirl
2005-06-24More err path clean up for drm_pm Add mandatory sysdev shutdown functionJon Smirl
2005-06-24Fix the sysdev approach for power management.Alan Hourihane
2005-06-24Fix suspend problem when i915 private hasn't been initialized yet.Alan Hourihane
2005-06-23Fix drm_memory_debug.c to compile, doesn't seem to be working Clean upJon Smirl
2005-06-22Get the power management hooks into the right place so that everything getsJon Smirl
2005-06-21Change initialization of savage register access to _DRM_READ_ONLY. Flags ofJon Smirl
2005-06-20Change initialization of radeon register access to _DRM_READ_ONLY. Flags ofJon Smirl
2005-06-19Remove I2C support from radeon driver. Same support is available fromJon Smirl
2005-06-17fix up drm_alloc_agp to take a dev arg and not pass crappy agpgart aroundDave Airlie
2005-06-17Fix 810/830 buildJon Smirl
2005-06-16Force AGP always for Intel chipsets.Alan Hourihane
2005-06-15Re-sync (and correct!) shared/mga_drm.h with shared-core/mga_drm.h.Ian Romanick
2005-06-14Adds support for PCI cards to MGA DRMIan Romanick
2005-06-11fix up drm.h for C++ include as this can be included in user programsDave Airlie
2005-06-10add dragonfly #define from Xorg CVSDave Airlie
2005-06-09Synchronize with the shared-core version.Ian Romanick
2005-06-09Completely re-initialize DMA settingsIan Romanick
2005-06-09drm_mem_init should be done at core load, not driver initJon Smirl
2005-06-06fix some issues with radeon interrupt handlingDave Airlie
2005-06-06Fix copyrightsAlan Hourihane
2005-06-06Add a few more bits of Tonnerre's NetBSD port (Still need to deal with theEric Anholt
2005-06-04misc cleanup patch from Adrian BunkDave Airlie
2005-06-04Remove warnings about code mixed with declerations..Dave Airlie
2005-06-03Minor clean-ups. The drm_mga_fullscreen_t stuff has been dead for a looongIan Romanick
2005-06-03Move the deallocation of dev_private. Since dev_private is allocated whenIan Romanick
2005-05-28Bugzilla #3217: Create a new __drm_pci_free which is used internally inEric Anholt
2005-05-28Bugzilla #3217: The size field in the new dma handle structure wasEric Anholt
2005-05-28Actually check for drm_fb_loaded before trying to initialize the sysdevAlan Hourihane
2005-05-28Re-implement the power management.Alan Hourihane
2005-05-27Modify drm_driver::device_is_agp to return a tri-state value to indicateIan Romanick
2005-05-27add radeon registers from VHA code these are the "unknown" registersDave Airlie
2005-05-23VIA:Thomas Hellstrom
2005-05-22Refactor the routines for "calculating" the size of the WARP microcode. TheIan Romanick
2005-05-21Forgot to bump the patchlevel and driver date on last commit.Ian Romanick
2005-05-21Change the MGA initialization and cleanup a bit. The dev_private structureIan Romanick
2005-05-20Refactor common, boilerplate ioctl code from drm_addbufs_* functions intoIan Romanick
2005-05-18Add i945G pci ids to drmDave Airlie
2005-05-17Savage doesn't require AGP any more. Enable build even without CONFIG_AGP.Felix Kuehling
2005-05-16Added device_is_agp callback to drm_driver. This function is called by theIan Romanick
2005-05-15wrap config.h include with defined for KERNELDave Airlie
2005-05-08VIA: Fix for oops when AGP ring-buffer initialization is called and thereThomas Hellstrom
2005-04-26Convert NOMAN to the new preferred spelling NO_MAN to quiet warnings.Eric Anholt
2005-04-26Clean up some const qualifier cast warnings.Eric Anholt
2005-04-26Convert BSD code to mostly use bus_dma, the dma abstraction for dealingEric Anholt
' href='#n362'>362 363 364 365
/*
 * Copyright 2007-8 Advanced Micro Devices, Inc.
 * Copyright 2008 Red Hat Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors: Dave Airlie
 *          Alex Deucher
 */
#include "drmP.h"
#include "radeon_drm.h"
#include "radeon_drv.h"

#include "atom.h"
#include "atom-bits.h"


union atom_supported_devices {
  struct _ATOM_SUPPORTED_DEVICES_INFO info;
  struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2;
  struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1;
};

static inline struct radeon_i2c_bus_rec radeon_lookup_gpio_for_ddc(struct drm_device *dev, uint8_t id)
{
	struct drm_radeon_private *dev_priv = dev->dev_private;
	struct atom_context *ctx = dev_priv->mode_info.atom_context;
	ATOM_GPIO_I2C_ASSIGMENT gpio;
	struct radeon_i2c_bus_rec i2c;
	int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
	struct _ATOM_GPIO_I2C_INFO *i2c_info;
	uint16_t data_offset;

	memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec));
	i2c.valid = false;

	atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset);

	i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);

	gpio = i2c_info->asGPIO_Info[id];

	i2c.mask_clk_reg = le16_to_cpu(gpio.usClkMaskRegisterIndex) * 4;
	i2c.mask_data_reg = le16_to_cpu(gpio.usDataMaskRegisterIndex) * 4;
	i2c.put_clk_reg = le16_to_cpu(gpio.usClkEnRegisterIndex) * 4;
	i2c.put_data_reg = le16_to_cpu(gpio.usDataEnRegisterIndex) * 4;
	i2c.get_clk_reg = le16_to_cpu(gpio.usClkY_RegisterIndex) * 4;
	i2c.get_data_reg = le16_to_cpu(gpio.usDataY_RegisterIndex) * 4;
	i2c.a_clk_reg = le16_to_cpu(gpio.usClkA_RegisterIndex) * 4;
	i2c.a_data_reg = le16_to_cpu(gpio.usDataA_RegisterIndex) * 4;
	i2c.mask_clk_mask = (1 << gpio.ucClkMaskShift);
	i2c.mask_data_mask = (1 << gpio.ucDataMaskShift);
	i2c.put_clk_mask = (1 << gpio.ucClkEnShift);
	i2c.put_data_mask = (1 << gpio.ucDataEnShift);
	i2c.get_clk_mask = (1 << gpio.ucClkY_Shift);
	i2c.get_data_mask = (1 <<  gpio.ucDataY_Shift);
	i2c.a_clk_mask = (1 << gpio.ucClkA_Shift);
	i2c.a_data_mask = (1 <<  gpio.ucDataA_Shift);
	i2c.valid = true;

	return i2c;
}

static void radeon_atom_apply_quirks(struct drm_device *dev, int index)
{
	struct drm_radeon_private *dev_priv = dev->dev_private;
	struct radeon_mode_info *mode_info = &dev_priv->mode_info;

	if ((dev->pdev->device == 0x791e) &&
	    (dev->pdev->subsystem_vendor == 0x1043) &&
	    (dev->pdev->subsystem_device == 0x826d)) {
		if ((mode_info->bios_connector[index].connector_type == CONNECTOR_HDMI_TYPE_A) &&
		    (mode_info->bios_connector[index].tmds_type == TMDS_LVTMA)) {
			mode_info->bios_connector[index].connector_type = CONNECTOR_DVI_D;
		}
	}

	if ((dev->pdev->device == 0x5653) &&
	    (dev->pdev->subsystem_vendor == 0x1462) &&
	    (dev->pdev->subsystem_device == 0x0291)) {
		if (mode_info->bios_connector[index].connector_type == CONNECTOR_LVDS) {
			mode_info->bios_connector[index].ddc_i2c.valid = false;
		}
	}
}

bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device *dev)
{
	struct drm_radeon_private *dev_priv = dev->dev_private;
	struct radeon_mode_info *mode_info = &dev_priv->mode_info;
	struct atom_context *ctx = mode_info->atom_context;
	int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo);
	uint16_t size, data_offset;
	uint8_t frev, crev;
	uint16_t device_support;

	union atom_supported_devices *supported_devices;
	int i,j;
	atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset);

	supported_devices = (union atom_supported_devices *)(ctx->bios + data_offset);

	device_support = le16_to_cpu(supported_devices->info.usDeviceSupport);

	for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {

		ATOM_CONNECTOR_INFO_I2C ci = supported_devices->info.asConnInfo[i];

		if (!(device_support & (1 << i))) {
			mode_info->bios_connector[i].valid = false;
			continue;
		}

		if (i == ATOM_DEVICE_CV_INDEX) {
			DRM_DEBUG("Skipping Component Video\n");
			mode_info->bios_connector[i].valid = false;
			continue;
		}

		if (i == ATOM_DEVICE_TV1_INDEX) {
			DRM_DEBUG("Skipping TV Out\n");
			mode_info->bios_connector[i].valid = false;
			continue;
		}

		mode_info->bios_connector[i].valid = true;
		mode_info->bios_connector[i].output_id = ci.sucI2cId.sbfAccess.bfI2C_LineMux;
		mode_info->bios_connector[i].devices = 1 << i;
		mode_info->bios_connector[i].connector_type = ci.sucConnectorInfo.sbfAccess.bfConnectorType;

		if (mode_info->bios_connector[i].connector_type == CONNECTOR_NONE) {
			mode_info->bios_connector[i].valid = false;
			continue;
		}

		mode_info->bios_connector[i].dac_type = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC;

		if ((i == ATOM_DEVICE_TV1_INDEX) ||
		    (i == ATOM_DEVICE_TV2_INDEX) ||
		    (i == ATOM_DEVICE_TV1_INDEX))
			mode_info->bios_connector[i].ddc_i2c.valid = false;
		else if ((dev_priv->chip_family == CHIP_RS600) ||
			 (dev_priv->chip_family == CHIP_RS690) ||
			 (dev_priv->chip_family == CHIP_RS740)) {
			if ((i == ATOM_DEVICE_DFP2_INDEX) || (i == ATOM_DEVICE_DFP3_INDEX))
				mode_info->bios_connector[i].ddc_i2c =
					radeon_lookup_gpio_for_ddc(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux + 1);
			else
				mode_info->bios_connector[i].ddc_i2c =
					radeon_lookup_gpio_for_ddc(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux);
		} else
			mode_info->bios_connector[i].ddc_i2c =
				radeon_lookup_gpio_for_ddc(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux);

		if (i == ATOM_DEVICE_DFP1_INDEX)
			mode_info->bios_connector[i].tmds_type = TMDS_INT;
		else if (i == ATOM_DEVICE_DFP2_INDEX) {
			if ((dev_priv->chip_family == CHIP_RS600) ||
			    (dev_priv->chip_family == CHIP_RS690) ||
			    (dev_priv->chip_family == CHIP_RS740))
				mode_info->bios_connector[i].tmds_type = TMDS_DDIA;
			else
				mode_info->bios_connector[i].tmds_type = TMDS_EXT;
		} else if (i == ATOM_DEVICE_DFP3_INDEX)
			mode_info->bios_connector[i].tmds_type = TMDS_LVTMA;
		else
			mode_info->bios_connector[i].tmds_type = TMDS_NONE;

		/* Always set the connector type to VGA for CRT1/CRT2. if they are
		 * shared with a DVI port, we'll pick up the DVI connector below when we
		 * merge the outputs
		 */
		if ((i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX) &&
		    (mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_I ||
		     mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_D ||
		     mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_A)) {
			mode_info->bios_connector[i].connector_type = CONNECTOR_VGA;
		}

		if (crev > 1) {
			ATOM_CONNECTOR_INC_SRC_BITMAP isb = supported_devices->info_2.asIntSrcInfo[i];

			switch(isb.ucIntSrcBitmap) {
			case 0x4:
				mode_info->bios_connector[i].hpd_mask = 0x1;
				break;
			case 0xa:
				mode_info->bios_connector[i].hpd_mask = 0x100;
				break;
			default:
				mode_info->bios_connector[i].hpd_mask = 0;
				break;
			}
		} else {
			mode_info->bios_connector[i].hpd_mask = 0;
		}

		radeon_atom_apply_quirks(dev, i);
	}

	/* CRTs/DFPs may share a port */
	for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
		if (!mode_info->bios_connector[i].valid)
			continue;

		for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
			if (mode_info->bios_connector[j].valid && (i != j)) {
				if (mode_info->bios_connector[i].output_id ==
				    mode_info->bios_connector[j].output_id) {
					if (((i == ATOM_DEVICE_DFP1_INDEX) ||
					     (i == ATOM_DEVICE_DFP2_INDEX) ||
					     (i == ATOM_DEVICE_DFP3_INDEX)) &&
					    ((j == ATOM_DEVICE_CRT1_INDEX) ||
					     (j == ATOM_DEVICE_CRT2_INDEX))) {
						mode_info->bios_connector[i].dac_type = mode_info->bios_connector[j].dac_type;
						mode_info->bios_connector[i].devices |= mode_info->bios_connector[j].devices;
						mode_info->bios_connector[i].hpd_mask = mode_info->bios_connector[j].hpd_mask;
						mode_info->bios_connector[j].valid = false;
					} else if (((j == ATOM_DEVICE_DFP1_INDEX) ||
						    (j == ATOM_DEVICE_DFP2_INDEX) ||
						    (j == ATOM_DEVICE_DFP3_INDEX)) &&
						   ((i == ATOM_DEVICE_CRT1_INDEX) ||
						    (i == ATOM_DEVICE_CRT2_INDEX))) {
						mode_info->bios_connector[j].dac_type = mode_info->bios_connector[i].dac_type;
						mode_info->bios_connector[j].devices |= mode_info->bios_connector[i].devices;
						mode_info->bios_connector[j].hpd_mask = mode_info->bios_connector[i].hpd_mask;
						mode_info->bios_connector[i].valid = false;
					}
				}
			}
		}
	}


	DRM_DEBUG("BIOS Connector table\n");
	for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
		if (!mode_info->bios_connector[i].valid)
			continue;

		DRM_DEBUG("Port %d: ddc_type 0x%x, dac_type %d, tmds_type %d, connector type %d, hpd_mask %d\n",
			  i, mode_info->bios_connector[i].ddc_i2c.mask_clk_reg,
			  mode_info->bios_connector[i].dac_type,
			  mode_info->bios_connector[i].tmds_type,
			  mode_info->bios_connector[i].connector_type,
			  mode_info->bios_connector[i].hpd_mask);
	}
	return true;
}

union firmware_info {
	ATOM_FIRMWARE_INFO info;
	ATOM_FIRMWARE_INFO_V1_2 info_12;
	ATOM_FIRMWARE_INFO_V1_3 info_13;
	ATOM_FIRMWARE_INFO_V1_4 info_14;
};

bool radeon_atom_get_clock_info(struct drm_device *dev)
{
	struct drm_radeon_private *dev_priv = dev->dev_private;
	struct radeon_mode_info *mode_info = &dev_priv->mode_info;
	int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
	union firmware_info *firmware_info;
	uint8_t frev, crev;
	struct radeon_pll *pll = &mode_info->pll;
	uint16_t data_offset;

	atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset);

	firmware_info = (union firmware_info *)(mode_info->atom_context->bios + data_offset);

	pll->reference_freq = le16_to_cpu(firmware_info->info.usReferenceClock);
	pll->reference_div = 0;

	pll->pll_out_min = le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output);
	pll->pll_out_max = le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);

	if (pll->pll_out_min == 0) {
		if (radeon_is_avivo(dev_priv))
			pll->pll_out_min = 64800;
		else
			pll->pll_out_min = 20000;
	}

	pll->pll_in_min = le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input);
	pll->pll_in_max = le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input);

	pll->xclk = le16_to_cpu(firmware_info->info.usMaxPixelClock);

	return true;
}

union lvds_info {
	struct _ATOM_LVDS_INFO info;
	struct _ATOM_LVDS_INFO_V12 info_12;
};

void radeon_get_lvds_info(struct radeon_encoder *encoder)
{
	struct drm_device *dev = encoder->base.dev;
	struct drm_radeon_private *dev_priv = dev->dev_private;
	struct radeon_mode_info *mode_info = &dev_priv->mode_info;
	int index = GetIndexIntoMasterTable(DATA, LVDS_Info);
	uint16_t data_offset;
	union lvds_info *lvds_info;
	uint8_t frev, crev;

	atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset);

	lvds_info = (union lvds_info *)(mode_info->atom_context->bios + data_offset);

	encoder->dotclock = le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10;
	encoder->panel_xres = le16_to_cpu(lvds_info->info.sLCDTiming.usHActive);
	encoder->panel_yres = le16_to_cpu(lvds_info->info.sLCDTiming.usVActive);
	encoder->hblank = le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time);
	encoder->hoverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset);
	encoder->hsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth);

	encoder->vblank = le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time);
	encoder->hoverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset);
	encoder->hsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth);
	encoder->panel_pwr_delay = le16_to_cpu(lvds_info->info.usOffDelayInMs);
}

void radeon_atom_dyn_clk_setup(struct drm_device *dev, int enable)
{
	struct drm_radeon_private *dev_priv = dev->dev_private;
	struct radeon_mode_info *mode_info = &dev_priv->mode_info;
	struct atom_context *ctx = mode_info->atom_context;
	DYNAMIC_CLOCK_GATING_PS_ALLOCATION args;
	int index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating);

	args.ucEnable = enable;

	atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args);
}

void radeon_atom_static_pwrmgt_setup(struct drm_device *dev, int enable)
{
	struct drm_radeon_private *dev_priv = dev->dev_private;
	struct radeon_mode_info *mode_info = &dev_priv->mode_info;
	struct atom_context *ctx = mode_info->atom_context;
	ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION args;
	int index = GetIndexIntoMasterTable(COMMAND, EnableASIC_StaticPwrMgt);

	args.ucEnable = enable;

	atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args);
}