Skip to content
Snippets Groups Projects
r100.c 116 KiB
Newer Older
/*
 * Copyright 2008 Advanced Micro Devices, Inc.
 * Copyright 2008 Red Hat Inc.
 * Copyright 2009 Jerome Glisse.
 *
 * 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
 *          Jerome Glisse
 */
#include <linux/seq_file.h>
#include <drm/drmP.h>
#include <drm/radeon_drm.h>
#include "radeon_reg.h"
#include "radeon.h"
#include "r100d.h"
#include "rs100d.h"
#include "rv200d.h"
#include "rv250d.h"
#include "atom.h"
#include <linux/firmware.h>
#include <linux/module.h>
#include "r100_reg_safe.h"
#include "rn50_reg_safe.h"

/* Firmware Names */
#define FIRMWARE_R100		"radeon/R100_cp.bin"
#define FIRMWARE_R200		"radeon/R200_cp.bin"
#define FIRMWARE_R300		"radeon/R300_cp.bin"
#define FIRMWARE_R420		"radeon/R420_cp.bin"
#define FIRMWARE_RS690		"radeon/RS690_cp.bin"
#define FIRMWARE_RS600		"radeon/RS600_cp.bin"
#define FIRMWARE_R520		"radeon/R520_cp.bin"

MODULE_FIRMWARE(FIRMWARE_R100);
MODULE_FIRMWARE(FIRMWARE_R200);
MODULE_FIRMWARE(FIRMWARE_R300);
MODULE_FIRMWARE(FIRMWARE_R420);
MODULE_FIRMWARE(FIRMWARE_RS690);
MODULE_FIRMWARE(FIRMWARE_RS600);
MODULE_FIRMWARE(FIRMWARE_R520);
#include "r100_track.h"

/* This files gather functions specifics to:
 * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280
 * and others in some cases.
 */

static bool r100_is_in_vblank(struct radeon_device *rdev, int crtc)
{
	if (crtc == 0) {
		if (RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR)
			return true;
		else
			return false;
	} else {
		if (RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR)
			return true;
		else
			return false;
	}
}

static bool r100_is_counter_moving(struct radeon_device *rdev, int crtc)
{
	u32 vline1, vline2;

	if (crtc == 0) {
		vline1 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
		vline2 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
	} else {
		vline1 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
		vline2 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
	}
	if (vline1 != vline2)
		return true;
	else
		return false;
}

/**
 * r100_wait_for_vblank - vblank wait asic callback.
 *
 * @rdev: radeon_device pointer
 * @crtc: crtc to wait for vblank on
 *
 * Wait for vblank on the requested crtc (r1xx-r4xx).
 */
void r100_wait_for_vblank(struct radeon_device *rdev, int crtc)
{
	if (crtc >= rdev->num_crtc)
		return;

	if (crtc == 0) {
		if (!(RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN))
			return;
		if (!(RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_EN))
			return;
	}

	/* depending on when we hit vblank, we may be close to active; if so,
	 * wait for another frame.
	 */
	while (r100_is_in_vblank(rdev, crtc)) {
		if (i++ % 100 == 0) {
			if (!r100_is_counter_moving(rdev, crtc))
				break;
		}
	}

	while (!r100_is_in_vblank(rdev, crtc)) {
		if (i++ % 100 == 0) {
			if (!r100_is_counter_moving(rdev, crtc))
				break;
/**
 * r100_pre_page_flip - pre-pageflip callback.
 *
 * @rdev: radeon_device pointer
 * @crtc: crtc to prepare for pageflip on
 *
 * Pre-pageflip callback (r1xx-r4xx).
 * Enables the pageflip irq (vblank irq).
void r100_pre_page_flip(struct radeon_device *rdev, int crtc)
{
	/* enable the pflip int */
	radeon_irq_kms_pflip_irq_get(rdev, crtc);
}

/**
 * r100_post_page_flip - pos-pageflip callback.
 *
 * @rdev: radeon_device pointer
 * @crtc: crtc to cleanup pageflip on
 *
 * Post-pageflip callback (r1xx-r4xx).
 * Disables the pageflip irq (vblank irq).
 */
void r100_post_page_flip(struct radeon_device *rdev, int crtc)
{
	/* disable the pflip int */
	radeon_irq_kms_pflip_irq_put(rdev, crtc);
}

/**
 * r100_page_flip - pageflip callback.
 *
 * @rdev: radeon_device pointer
 * @crtc_id: crtc to cleanup pageflip on
 * @crtc_base: new address of the crtc (GPU MC address)
 *
 * Does the actual pageflip (r1xx-r4xx).
 * During vblank we take the crtc lock and wait for the update_pending
 * bit to go high, when it does, we release the lock, and allow the
 * double buffered update to take place.
 * Returns the current update pending status.
 */
u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
{
	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
	u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK;

	/* Lock the graphics update lock */
	/* update the scanout addresses */
	WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp);

	/* Wait for update_pending to go high. */
	for (i = 0; i < rdev->usec_timeout; i++) {
		if (RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET)
			break;
		udelay(1);
	}
	DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n");

	/* Unlock the lock, so double-buffering can take place inside vblank */
	tmp &= ~RADEON_CRTC_OFFSET__OFFSET_LOCK;
	WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp);

	/* Return current update_pending status: */
	return RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET;
}

/**
 * r100_pm_get_dynpm_state - look up dynpm power state callback.
 *
 * @rdev: radeon_device pointer
 *
 * Look up the optimal power state based on the
 * current state of the GPU (r1xx-r5xx).
 * Used for dynpm only.
 */
void r100_pm_get_dynpm_state(struct radeon_device *rdev)
	rdev->pm.dynpm_can_upclock = true;
	rdev->pm.dynpm_can_downclock = true;
	switch (rdev->pm.dynpm_planned_action) {
	case DYNPM_ACTION_MINIMUM:
		rdev->pm.requested_power_state_index = 0;
		rdev->pm.dynpm_can_downclock = false;
	case DYNPM_ACTION_DOWNCLOCK:
		if (rdev->pm.current_power_state_index == 0) {
			rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
			rdev->pm.dynpm_can_downclock = false;
		} else {
			if (rdev->pm.active_crtc_count > 1) {
				for (i = 0; i < rdev->pm.num_power_states; i++) {
					if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
						continue;
					else if (i >= rdev->pm.current_power_state_index) {
						rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
						break;
					} else {
						rdev->pm.requested_power_state_index = i;
						break;
					}
				}
			} else
				rdev->pm.requested_power_state_index =
					rdev->pm.current_power_state_index - 1;
		}
		/* don't use the power state if crtcs are active and no display flag is set */
		if ((rdev->pm.active_crtc_count > 0) &&
		    (rdev->pm.power_state[rdev->pm.requested_power_state_index].clock_info[0].flags &
		     RADEON_PM_MODE_NO_DISPLAY)) {
			rdev->pm.requested_power_state_index++;
		}
	case DYNPM_ACTION_UPCLOCK:
		if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) {
			rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
			rdev->pm.dynpm_can_upclock = false;
		} else {
			if (rdev->pm.active_crtc_count > 1) {
				for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) {
					if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
						continue;
					else if (i <= rdev->pm.current_power_state_index) {
						rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
						break;
					} else {
						rdev->pm.requested_power_state_index = i;
						break;
					}
				}
			} else
				rdev->pm.requested_power_state_index =
					rdev->pm.current_power_state_index + 1;
		}
		break;
	case DYNPM_ACTION_DEFAULT:
		rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index;
		rdev->pm.dynpm_can_upclock = false;
	case DYNPM_ACTION_NONE:
	default:
		DRM_ERROR("Requested mode for not defined action\n");
		return;
	}
	/* only one clock mode per power state */
	rdev->pm.requested_clock_mode_index = 0;

	DRM_DEBUG_DRIVER("Requested: e: %d m: %d p: %d\n",
		  rdev->pm.power_state[rdev->pm.requested_power_state_index].
		  clock_info[rdev->pm.requested_clock_mode_index].sclk,
		  rdev->pm.power_state[rdev->pm.requested_power_state_index].
		  clock_info[rdev->pm.requested_clock_mode_index].mclk,
		  rdev->pm.power_state[rdev->pm.requested_power_state_index].
		  pcie_lanes);
/**
 * r100_pm_init_profile - Initialize power profiles callback.
 *
 * @rdev: radeon_device pointer
 *
 * Initialize the power states used in profile mode
 * (r1xx-r3xx).
 * Used for profile mode only.
 */
void r100_pm_init_profile(struct radeon_device *rdev)
{
	/* default */
	rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
	rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
	rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0;
	rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0;
	/* low sh */
	rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0;
	rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0;
	rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
	rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0;
	/* mid sh */
	rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 0;
	rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 0;
	rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0;
	rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0;
	/* high sh */
	rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0;
	rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
	rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0;
	rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0;
	/* low mh */
	rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0;
	rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
	rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
	rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0;
	/* mid mh */
	rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 0;
	rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
	rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0;
	rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0;
	/* high mh */
	rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0;
	rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
	rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0;
	rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0;
/**
 * r100_pm_misc - set additional pm hw parameters callback.
 *
 * @rdev: radeon_device pointer
 *
 * Set non-clock parameters associated with a power state
 * (voltage, pcie lanes, etc.) (r1xx-r4xx).
 */
void r100_pm_misc(struct radeon_device *rdev)
{
	int requested_index = rdev->pm.requested_power_state_index;
	struct radeon_power_state *ps = &rdev->pm.power_state[requested_index];
	struct radeon_voltage *voltage = &ps->clock_info[0].voltage;
	u32 tmp, sclk_cntl, sclk_cntl2, sclk_more_cntl;

	if ((voltage->type == VOLTAGE_GPIO) && (voltage->gpio.valid)) {
		if (ps->misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) {
			tmp = RREG32(voltage->gpio.reg);
			if (voltage->active_high)
				tmp |= voltage->gpio.mask;
			else
				tmp &= ~(voltage->gpio.mask);
			WREG32(voltage->gpio.reg, tmp);
			if (voltage->delay)
				udelay(voltage->delay);
		} else {
			tmp = RREG32(voltage->gpio.reg);
			if (voltage->active_high)
				tmp &= ~voltage->gpio.mask;
			else
				tmp |= voltage->gpio.mask;
			WREG32(voltage->gpio.reg, tmp);
			if (voltage->delay)
				udelay(voltage->delay);
		}
	}

	sclk_cntl = RREG32_PLL(SCLK_CNTL);
	sclk_cntl2 = RREG32_PLL(SCLK_CNTL2);
	sclk_cntl2 &= ~REDUCED_SPEED_SCLK_SEL(3);
	sclk_more_cntl = RREG32_PLL(SCLK_MORE_CNTL);
	sclk_more_cntl &= ~VOLTAGE_DELAY_SEL(3);
	if (ps->misc & ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN) {
		sclk_more_cntl |= REDUCED_SPEED_SCLK_EN;
		if (ps->misc & ATOM_PM_MISCINFO_DYN_CLK_3D_IDLE)
			sclk_cntl2 |= REDUCED_SPEED_SCLK_MODE;
		else
			sclk_cntl2 &= ~REDUCED_SPEED_SCLK_MODE;
		if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2)
			sclk_cntl2 |= REDUCED_SPEED_SCLK_SEL(0);
		else if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4)
			sclk_cntl2 |= REDUCED_SPEED_SCLK_SEL(2);
	} else
		sclk_more_cntl &= ~REDUCED_SPEED_SCLK_EN;

	if (ps->misc & ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN) {
		sclk_more_cntl |= IO_CG_VOLTAGE_DROP;
		if (voltage->delay) {
			sclk_more_cntl |= VOLTAGE_DROP_SYNC;
			switch (voltage->delay) {
			case 33:
				sclk_more_cntl |= VOLTAGE_DELAY_SEL(0);
				break;
			case 66:
				sclk_more_cntl |= VOLTAGE_DELAY_SEL(1);
				break;
			case 99:
				sclk_more_cntl |= VOLTAGE_DELAY_SEL(2);
				break;
			case 132:
				sclk_more_cntl |= VOLTAGE_DELAY_SEL(3);
				break;
			}
		} else
			sclk_more_cntl &= ~VOLTAGE_DROP_SYNC;
	} else
		sclk_more_cntl &= ~IO_CG_VOLTAGE_DROP;

	if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN)
		sclk_cntl &= ~FORCE_HDP;
	else
		sclk_cntl |= FORCE_HDP;

	WREG32_PLL(SCLK_CNTL, sclk_cntl);
	WREG32_PLL(SCLK_CNTL2, sclk_cntl2);
	WREG32_PLL(SCLK_MORE_CNTL, sclk_more_cntl);

	/* set pcie lanes */
	if ((rdev->flags & RADEON_IS_PCIE) &&
	    !(rdev->flags & RADEON_IS_IGP) &&
	    rdev->asic->pm.set_pcie_lanes &&
	    (ps->pcie_lanes !=
	     rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) {
		radeon_set_pcie_lanes(rdev,
				      ps->pcie_lanes);
		DRM_DEBUG_DRIVER("Setting: p: %d\n", ps->pcie_lanes);
/**
 * r100_pm_prepare - pre-power state change callback.
 *
 * @rdev: radeon_device pointer
 *
 * Prepare for a power state change (r1xx-r4xx).
 */
void r100_pm_prepare(struct radeon_device *rdev)
{
	struct drm_device *ddev = rdev->ddev;
	struct drm_crtc *crtc;
	struct radeon_crtc *radeon_crtc;
	u32 tmp;

	/* disable any active CRTCs */
	list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) {
		radeon_crtc = to_radeon_crtc(crtc);
		if (radeon_crtc->enabled) {
			if (radeon_crtc->crtc_id) {
				tmp = RREG32(RADEON_CRTC2_GEN_CNTL);
				tmp |= RADEON_CRTC2_DISP_REQ_EN_B;
				WREG32(RADEON_CRTC2_GEN_CNTL, tmp);
			} else {
				tmp = RREG32(RADEON_CRTC_GEN_CNTL);
				tmp |= RADEON_CRTC_DISP_REQ_EN_B;
				WREG32(RADEON_CRTC_GEN_CNTL, tmp);
			}
		}
	}
}

/**
 * r100_pm_finish - post-power state change callback.
 *
 * @rdev: radeon_device pointer
 *
 * Clean up after a power state change (r1xx-r4xx).
 */
void r100_pm_finish(struct radeon_device *rdev)
{
	struct drm_device *ddev = rdev->ddev;
	struct drm_crtc *crtc;
	struct radeon_crtc *radeon_crtc;
	u32 tmp;

	/* enable any active CRTCs */
	list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) {
		radeon_crtc = to_radeon_crtc(crtc);
		if (radeon_crtc->enabled) {
			if (radeon_crtc->crtc_id) {
				tmp = RREG32(RADEON_CRTC2_GEN_CNTL);
				tmp &= ~RADEON_CRTC2_DISP_REQ_EN_B;
				WREG32(RADEON_CRTC2_GEN_CNTL, tmp);
			} else {
				tmp = RREG32(RADEON_CRTC_GEN_CNTL);
				tmp &= ~RADEON_CRTC_DISP_REQ_EN_B;
				WREG32(RADEON_CRTC_GEN_CNTL, tmp);
			}
		}
	}
}

/**
 * r100_gui_idle - gui idle callback.
 *
 * @rdev: radeon_device pointer
 *
 * Check of the GUI (2D/3D engines) are idle (r1xx-r5xx).
 * Returns true if idle, false if not.
 */
bool r100_gui_idle(struct radeon_device *rdev)
{
	if (RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE)
		return false;
	else
		return true;
}

/* hpd for digital panel detect/disconnect */
/**
 * r100_hpd_sense - hpd sense callback.
 *
 * @rdev: radeon_device pointer
 * @hpd: hpd (hotplug detect) pin
 *
 * Checks if a digital monitor is connected (r1xx-r4xx).
 * Returns true if connected, false if not connected.
 */
bool r100_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
{
	bool connected = false;

	switch (hpd) {
	case RADEON_HPD_1:
		if (RREG32(RADEON_FP_GEN_CNTL) & RADEON_FP_DETECT_SENSE)
			connected = true;
		break;
	case RADEON_HPD_2:
		if (RREG32(RADEON_FP2_GEN_CNTL) & RADEON_FP2_DETECT_SENSE)
			connected = true;
		break;
	default:
		break;
	}
	return connected;
}

/**
 * r100_hpd_set_polarity - hpd set polarity callback.
 *
 * @rdev: radeon_device pointer
 * @hpd: hpd (hotplug detect) pin
 *
 * Set the polarity of the hpd pin (r1xx-r4xx).
 */
void r100_hpd_set_polarity(struct radeon_device *rdev,
			   enum radeon_hpd_id hpd)
{
	u32 tmp;
	bool connected = r100_hpd_sense(rdev, hpd);

	switch (hpd) {
	case RADEON_HPD_1:
		tmp = RREG32(RADEON_FP_GEN_CNTL);
		if (connected)
			tmp &= ~RADEON_FP_DETECT_INT_POL;
		else
			tmp |= RADEON_FP_DETECT_INT_POL;
		WREG32(RADEON_FP_GEN_CNTL, tmp);
		break;
	case RADEON_HPD_2:
		tmp = RREG32(RADEON_FP2_GEN_CNTL);
		if (connected)
			tmp &= ~RADEON_FP2_DETECT_INT_POL;
		else
			tmp |= RADEON_FP2_DETECT_INT_POL;
		WREG32(RADEON_FP2_GEN_CNTL, tmp);
		break;
	default:
		break;
	}
}

/**
 * r100_hpd_init - hpd setup callback.
 *
 * @rdev: radeon_device pointer
 *
 * Setup the hpd pins used by the card (r1xx-r4xx).
 * Set the polarity, and enable the hpd interrupts.
 */
void r100_hpd_init(struct radeon_device *rdev)
{
	struct drm_device *dev = rdev->ddev;
	struct drm_connector *connector;

	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
		enable |= 1 << radeon_connector->hpd.hpd;
		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
	radeon_irq_kms_enable_hpd(rdev, enable);
/**
 * r100_hpd_fini - hpd tear down callback.
 *
 * @rdev: radeon_device pointer
 *
 * Tear down the hpd pins used by the card (r1xx-r4xx).
 * Disable the hpd interrupts.
 */
void r100_hpd_fini(struct radeon_device *rdev)
{
	struct drm_device *dev = rdev->ddev;
	struct drm_connector *connector;

	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
		disable |= 1 << radeon_connector->hpd.hpd;
	radeon_irq_kms_disable_hpd(rdev, disable);
/*
 * PCI GART
 */
void r100_pci_gart_tlb_flush(struct radeon_device *rdev)
{
	/* TODO: can we do somethings here ? */
	/* It seems hw only cache one entry so we should discard this
	 * entry otherwise if first GPU GART read hit this entry it
	 * could end up in wrong address. */
}

int r100_pci_gart_init(struct radeon_device *rdev)
		WARN(1, "R100 PCI GART already initialized\n");
	/* Initialize common gart structure */
	r = radeon_gart_init(rdev);
	rdev->gart.table_size = rdev->gart.num_gpu_pages * 4;
	rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush;
	rdev->asic->gart.set_page = &r100_pci_gart_set_page;
	return radeon_gart_table_ram_alloc(rdev);
}

int r100_pci_gart_enable(struct radeon_device *rdev)
{
	uint32_t tmp;

	/* discard memory request outside of configured range */
	tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS;
	WREG32(RADEON_AIC_CNTL, tmp);
	/* set address range for PCI address translate */
	WREG32(RADEON_AIC_LO_ADDR, rdev->mc.gtt_start);
	WREG32(RADEON_AIC_HI_ADDR, rdev->mc.gtt_end);
	/* set PCI GART page-table base address */
	WREG32(RADEON_AIC_PT_BASE, rdev->gart.table_addr);
	tmp = RREG32(RADEON_AIC_CNTL) | RADEON_PCIGART_TRANSLATE_EN;
	WREG32(RADEON_AIC_CNTL, tmp);
	r100_pci_gart_tlb_flush(rdev);
	DRM_INFO("PCI GART of %uM enabled (table at 0x%016llX).\n",
		 (unsigned)(rdev->mc.gtt_size >> 20),
		 (unsigned long long)rdev->gart.table_addr);
	rdev->gart.ready = true;
	return 0;
}

void r100_pci_gart_disable(struct radeon_device *rdev)
{
	uint32_t tmp;

	/* discard memory request outside of configured range */
	tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS;
	WREG32(RADEON_AIC_CNTL, tmp & ~RADEON_PCIGART_TRANSLATE_EN);
	WREG32(RADEON_AIC_LO_ADDR, 0);
	WREG32(RADEON_AIC_HI_ADDR, 0);
}

int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
{
	if (i < 0 || i > rdev->gart.num_gpu_pages) {
		return -EINVAL;
	}
	gtt[i] = cpu_to_le32(lower_32_bits(addr));
void r100_pci_gart_fini(struct radeon_device *rdev)
	r100_pci_gart_disable(rdev);
	radeon_gart_table_ram_free(rdev);
int r100_irq_set(struct radeon_device *rdev)
{
	uint32_t tmp = 0;

		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
		WREG32(R_000040_GEN_INT_CNTL, 0);
		return -EINVAL;
	}
	if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
		tmp |= RADEON_SW_INT_ENABLE;
	}
	if (rdev->irq.crtc_vblank_int[0] ||
	    atomic_read(&rdev->irq.pflip[0])) {
		tmp |= RADEON_CRTC_VBLANK_MASK;
	}
	if (rdev->irq.crtc_vblank_int[1] ||
	    atomic_read(&rdev->irq.pflip[1])) {
		tmp |= RADEON_CRTC2_VBLANK_MASK;
	}
	if (rdev->irq.hpd[0]) {
		tmp |= RADEON_FP_DETECT_MASK;
	}
	if (rdev->irq.hpd[1]) {
		tmp |= RADEON_FP2_DETECT_MASK;
	}
	WREG32(RADEON_GEN_INT_CNTL, tmp);
	return 0;
}

void r100_irq_disable(struct radeon_device *rdev)
{
	u32 tmp;

	WREG32(R_000040_GEN_INT_CNTL, 0);
	/* Wait and acknowledge irq */
	mdelay(1);
	tmp = RREG32(R_000044_GEN_INT_STATUS);
	WREG32(R_000044_GEN_INT_STATUS, tmp);
}

static uint32_t r100_irq_ack(struct radeon_device *rdev)
{
	uint32_t irqs = RREG32(RADEON_GEN_INT_STATUS);
	uint32_t irq_mask = RADEON_SW_INT_TEST |
		RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT |
		RADEON_FP_DETECT_STAT | RADEON_FP2_DETECT_STAT;

	if (irqs) {
		WREG32(RADEON_GEN_INT_STATUS, irqs);
	}
	return irqs & irq_mask;
}

int r100_irq_process(struct radeon_device *rdev)
{
	uint32_t status, msi_rearm;
	bool queue_hotplug = false;

	status = r100_irq_ack(rdev);
	if (!status) {
		return IRQ_NONE;
	}
	if (rdev->shutdown) {
		return IRQ_NONE;
	}
	while (status) {
		/* SW interrupt */
		if (status & RADEON_SW_INT_TEST) {
			radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
		}
		/* Vertical blank interrupts */
		if (status & RADEON_CRTC_VBLANK_STAT) {
			if (rdev->irq.crtc_vblank_int[0]) {
				drm_handle_vblank(rdev->ddev, 0);
				rdev->pm.vblank_sync = true;
				wake_up(&rdev->irq.vblank_queue);
			}
			if (atomic_read(&rdev->irq.pflip[0]))
				radeon_crtc_handle_flip(rdev, 0);
		}
		if (status & RADEON_CRTC2_VBLANK_STAT) {
			if (rdev->irq.crtc_vblank_int[1]) {
				drm_handle_vblank(rdev->ddev, 1);
				rdev->pm.vblank_sync = true;
				wake_up(&rdev->irq.vblank_queue);
			}
			if (atomic_read(&rdev->irq.pflip[1]))
				radeon_crtc_handle_flip(rdev, 1);
		if (status & RADEON_FP_DETECT_STAT) {
			queue_hotplug = true;
			DRM_DEBUG("HPD1\n");
		}
		if (status & RADEON_FP2_DETECT_STAT) {
			queue_hotplug = true;
			DRM_DEBUG("HPD2\n");
		status = r100_irq_ack(rdev);
	}
	if (queue_hotplug)
		schedule_work(&rdev->hotplug_work);
	if (rdev->msi_enabled) {
		switch (rdev->family) {
		case CHIP_RS400:
		case CHIP_RS480:
			msi_rearm = RREG32(RADEON_AIC_CNTL) & ~RS400_MSI_REARM;
			WREG32(RADEON_AIC_CNTL, msi_rearm);
			WREG32(RADEON_AIC_CNTL, msi_rearm | RS400_MSI_REARM);
			break;
		default:
			WREG32(RADEON_MSI_REARM_EN, RV370_MSI_REARM_EN);
	return IRQ_HANDLED;
}

u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc)
{
	if (crtc == 0)
		return RREG32(RADEON_CRTC_CRNT_FRAME);
	else
		return RREG32(RADEON_CRTC2_CRNT_FRAME);
}

/* Who ever call radeon_fence_emit should call ring_lock and ask
 * for enough space (today caller are ib schedule and buffer move) */
void r100_fence_ring_emit(struct radeon_device *rdev,
			  struct radeon_fence *fence)
{
	struct radeon_ring *ring = &rdev->ring[fence->ring];
	/* We have to make sure that caches are flushed before
	 * CPU might read something from VRAM. */
	radeon_ring_write(ring, PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0));
	radeon_ring_write(ring, RADEON_RB3D_DC_FLUSH_ALL);
	radeon_ring_write(ring, PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0));
	radeon_ring_write(ring, RADEON_RB3D_ZC_FLUSH_ALL);
	/* Wait until IDLE & CLEAN */
	radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0));
	radeon_ring_write(ring, RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_3D_IDLECLEAN);
	radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0));
	radeon_ring_write(ring, rdev->config.r100.hdp_cntl |
				RADEON_HDP_READ_BUFFER_INVALIDATE);
	radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0));
	radeon_ring_write(ring, rdev->config.r100.hdp_cntl);
	/* Emit fence sequence & fire IRQ */
	radeon_ring_write(ring, PACKET0(rdev->fence_drv[fence->ring].scratch_reg, 0));
	radeon_ring_write(ring, fence->seq);
	radeon_ring_write(ring, PACKET0(RADEON_GEN_INT_STATUS, 0));
	radeon_ring_write(ring, RADEON_SW_INT_FIRE);
void r100_semaphore_ring_emit(struct radeon_device *rdev,
			      struct radeon_ring *ring,
			      struct radeon_semaphore *semaphore,
{
	/* Unused on older asics, since we don't have semaphores or multiple rings */
	BUG();
}

int r100_copy_blit(struct radeon_device *rdev,
		   uint64_t src_offset,
		   uint64_t dst_offset,
		   struct radeon_fence **fence)
	struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
	uint32_t stride_bytes = RADEON_GPU_PAGE_SIZE;
	uint32_t pitch;
	uint32_t stride_pixels;
	unsigned ndw;
	int num_loops;
	int r = 0;

	/* radeon limited to 16k stride */
	stride_bytes &= 0x3fff;
	/* radeon pitch is /64 */
	pitch = stride_bytes / 64;
	stride_pixels = stride_bytes / 4;
	num_loops = DIV_ROUND_UP(num_gpu_pages, 8191);

	/* Ask for enough room for blit + flush + fence */
	ndw = 64 + (10 * num_loops);
	r = radeon_ring_lock(rdev, ring, ndw);
	if (r) {
		DRM_ERROR("radeon: moving bo (%d) asking for %u dw.\n", r, ndw);
		return -EINVAL;
	}
	while (num_gpu_pages > 0) {
		cur_pages = num_gpu_pages;
		if (cur_pages > 8191) {
			cur_pages = 8191;
		}

		/* pages are in Y direction - height
		   page width in X direction - width */
		radeon_ring_write(ring, PACKET3(PACKET3_BITBLT_MULTI, 8));
		radeon_ring_write(ring,
				  RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
				  RADEON_GMC_DST_PITCH_OFFSET_CNTL |
				  RADEON_GMC_SRC_CLIPPING |
				  RADEON_GMC_DST_CLIPPING |
				  RADEON_GMC_BRUSH_NONE |
				  (RADEON_COLOR_FORMAT_ARGB8888 << 8) |
				  RADEON_GMC_SRC_DATATYPE_COLOR |
				  RADEON_ROP3_S |
				  RADEON_DP_SRC_SOURCE_MEMORY |
				  RADEON_GMC_CLR_CMP_CNTL_DIS |
				  RADEON_GMC_WR_MSK_DIS);
		radeon_ring_write(ring, (pitch << 22) | (src_offset >> 10));
		radeon_ring_write(ring, (pitch << 22) | (dst_offset >> 10));
		radeon_ring_write(ring, (0x1fff) | (0x1fff << 16));
		radeon_ring_write(ring, 0);
		radeon_ring_write(ring, (0x1fff) | (0x1fff << 16));
		radeon_ring_write(ring, num_gpu_pages);
		radeon_ring_write(ring, num_gpu_pages);
		radeon_ring_write(ring, cur_pages | (stride_pixels << 16));
	}
	radeon_ring_write(ring, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0));
	radeon_ring_write(ring, RADEON_RB2D_DC_FLUSH_ALL);
	radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0));
	radeon_ring_write(ring,
			  RADEON_WAIT_2D_IDLECLEAN |
			  RADEON_WAIT_HOST_IDLECLEAN |
			  RADEON_WAIT_DMA_GUI_IDLE);
	if (fence) {
		r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX);
	radeon_ring_unlock_commit(rdev, ring);
static int r100_cp_wait_for_idle(struct radeon_device *rdev)
{
	unsigned i;
	u32 tmp;

	for (i = 0; i < rdev->usec_timeout; i++) {
		tmp = RREG32(R_000E40_RBBM_STATUS);
		if (!G_000E40_CP_CMDSTRM_BUSY(tmp)) {
			return 0;
		}
		udelay(1);
	}
	return -1;
}

void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring)
	r = radeon_ring_lock(rdev, ring, 2);
	radeon_ring_write(ring, PACKET0(RADEON_ISYNC_CNTL, 0));
	radeon_ring_write(ring,
			  RADEON_ISYNC_ANY2D_IDLE3D |
			  RADEON_ISYNC_ANY3D_IDLE2D |
			  RADEON_ISYNC_WAIT_IDLEGUI |
			  RADEON_ISYNC_CPSCRATCH_IDLEGUI);
	radeon_ring_unlock_commit(rdev, ring);

/* Load the microcode for the CP */
static int r100_cp_init_microcode(struct radeon_device *rdev)
	const char *fw_name = NULL;
	int err;

	if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) ||
	    (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) ||
	    (rdev->family == CHIP_RS200)) {
		DRM_INFO("Loading R100 Microcode\n");
		fw_name = FIRMWARE_R100;