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 <linux/slab.h>

David Howells
committed
#include <drm/drmP.h>
#include <drm/radeon_drm.h>
#include "radeon_reg.h"
#include "radeon.h"
#include "radeon_asic.h"
#include "rs100d.h"
#include "rv200d.h"
#include "rv250d.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);
/* 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)
{
int i;
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;
break;
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++;
}
break;
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;
rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index;
rdev->pm.dynpm_can_upclock = false;
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).
*/
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
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).
*/
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
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;
unsigned enable = 0;
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;
unsigned disable = 0;
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)
{
int r;
if (rdev->gart.ptr) {
WARN(1, "R100 PCI GART already initialized\n");
return 0;
}
/* 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;
radeon_gart_restore(rdev);
/* 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)
{
u32 *gtt = rdev->gart.ptr;
if (i < 0 || i > rdev->gart.num_gpu_pages) {
return -EINVAL;
}
gtt[i] = cpu_to_le32(lower_32_bits(addr));
return 0;
}
void r100_pci_gart_fini(struct radeon_device *rdev)
radeon_gart_fini(rdev);
r100_pci_gart_disable(rdev);
radeon_gart_table_ram_free(rdev);
int r100_irq_set(struct radeon_device *rdev)
{
uint32_t tmp = 0;
if (!rdev->irq.installed) {
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)
{
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);
}
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,
bool emit_wait)
{
/* 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,
unsigned num_gpu_pages,
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
uint32_t cur_pages;
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;
}
num_gpu_pages -= cur_pages;
/* 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);
return r;
}
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)
{
int r;
r = radeon_ring_lock(rdev, ring, 2);
if (r) {
return;
}
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)
DRM_DEBUG_KMS("\n");
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");