int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
{ /* start off with something large */ unsigned fb_div = 0, vclk_div = 0, dclk_div = 0; int r;
/* bypass vclk and dclk with bclk */
WREG32_P(CG_UPLL_FUNC_CNTL_2,
VCLK_SRC_SEL(1) | DCLK_SRC_SEL(1),
~(VCLK_SRC_SEL_MASK | DCLK_SRC_SEL_MASK));
/* put PLL in bypass mode */
WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~UPLL_BYPASS_EN_MASK);
if (!vclk || !dclk) { /* keep the Bypass mode, put PLL to sleep */
WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK); return0;
}
r = radeon_uvd_calc_upll_dividers(rdev, vclk, dclk, 125000, 250000, 16384, 0x03FFFFFF, 0, 128, 5,
&fb_div, &vclk_div, &dclk_div); if (r) return r;
/* set VCO_MODE to 1 */
WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_VCO_MODE_MASK, ~UPLL_VCO_MODE_MASK);
/* toggle UPLL_SLEEP to 1 then back to 0 */
WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK);
WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_SLEEP_MASK);
void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)
{ int readrq;
u16 v;
readrq = pcie_get_readrq(rdev->pdev);
v = ffs(readrq) - 8; /* if bios or OS sets MAX_READ_REQUEST_SIZE to an invalid value, fix it *toavoidhangsorperfomanceissues
*/ if ((v == 0) || (v == 6) || (v == 7))
pcie_set_readrq(rdev->pdev, 512);
}
/* LVDS/eDP FMT is set up by atom */ if (radeon_encoder->devices & ATOM_DEVICE_LCD_SUPPORT) return;
/* not needed for analog */ if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1) ||
(radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2)) return;
if (pos1 != pos2)
return true;
else
return false;
}
/**
* dce4_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 (evergreen+).
*/
void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc)
{
unsigned i = 0;
if (crtc >= rdev->num_crtc)
return;
if (!(RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[crtc]) & EVERGREEN_CRTC_MASTER_EN))
return;
/* depending on when we hit vblank, we may be close to active; if so,
* wait for another frame.
*/
while (dce4_is_in_vblank(rdev, crtc)) {
if (i++ % 100 == 0) {
if (!dce4_is_counter_moving(rdev, crtc))
break;
}
}
while (!dce4_is_in_vblank(rdev, crtc)) {
if (i++ % 100 == 0) {
if (!dce4_is_counter_moving(rdev, crtc))
break;
}
}
}
/**
* evergreen_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)
* @async: asynchronous flip
*
* Triggers the actual pageflip by updating the primary
* surface baseaddress (evergreen+).
*/
void evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base,
bool async)
{
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
struct drm_framebuffer *fb = radeon_crtc->base.primary->fb;
/* flip at hsync for async, default is vsync */
WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset,
async ? EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN : 0);
/* update pitch */
WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset,
fb->pitches[0] / fb->format->cpp[0]);
/* update the scanout addresses */
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
upper_32_bits(crtc_base));
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
(u32)crtc_base);
/* post the write */
RREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset);
}
/**
* evergreen_page_flip_pending - check if page flip is still pending
*
* @rdev: radeon_device pointer
* @crtc_id: crtc to check
*
* Returns the current update pending status.
*/
bool evergreen_page_flip_pending(struct radeon_device *rdev, int crtc_id)
{
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
int sumo_get_temp(struct radeon_device *rdev)
{
u32 temp = RREG32(CG_THERMAL_STATUS) & 0xff;
int actual_temp = temp - 49;
return actual_temp * 1000;
}
/**
* sumo_pm_init_profile - Initialize power profiles callback.
*
* @rdev: radeon_device pointer
*
* Initialize the power states used in profile mode
* (sumo, trinity, SI).
* Used for profile mode only.
*/
void sumo_pm_init_profile(struct radeon_device *rdev)
{
int idx;
/**
* btc_pm_init_profile - Initialize power profiles callback.
*
* @rdev: radeon_device pointer
*
* Initialize the power states used in profile mode
* (BTC, cayman).
* Used for profile mode only.
*/
void btc_pm_init_profile(struct radeon_device *rdev)
{
int idx;
/* 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 = 2;
/* starting with BTC, there is one state that is used for both
* MH and SH. Difference is that we always use the high clock index for
* mclk.
*/
if (rdev->flags & RADEON_IS_MOBILITY)
idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0);
else
idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
/* low sh */
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = idx;
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = idx;
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 = idx;
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = idx;
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 = 1;
/* high sh */
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = idx;
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = idx;
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 = 2;
/* low mh */
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = idx;
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = idx;
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 = idx;
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = idx;
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 = 1;
/* high mh */
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = idx;
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = idx;
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 = 2;
}
/**
* evergreen_pm_misc - set additional pm hw parameters callback.
*
* @rdev: radeon_device pointer
*
* Set non-clock parameters associated with a power state
* (voltage, etc.) (evergreen+).
*/
void evergreen_pm_misc(struct radeon_device *rdev)
{
int req_ps_idx = rdev->pm.requested_power_state_index;
int req_cm_idx = rdev->pm.requested_clock_mode_index;
struct radeon_power_state *ps = &rdev->pm.power_state[req_ps_idx];
struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage;
if (voltage->type == VOLTAGE_SW) {
/* 0xff0x are flags rather then an actual voltage */
if ((voltage->voltage & 0xff00) == 0xff00)
return;
if (voltage->voltage && (voltage->voltage != rdev->pm.current_vddc)) {
radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC);
rdev->pm.current_vddc = voltage->voltage;
DRM_DEBUG("Setting: vddc: %d\n", voltage->voltage);
}
/* starting with BTC, there is one state that is used for both
* MH and SH. Difference is that we always use the high clock index for
* mclk and vddci.
*/
if ((rdev->pm.pm_method == PM_METHOD_PROFILE) &&
(rdev->family >= CHIP_BARTS) &&
rdev->pm.active_crtc_count &&
((rdev->pm.profile_index == PM_PROFILE_MID_MH_IDX) ||
(rdev->pm.profile_index == PM_PROFILE_LOW_MH_IDX)))
voltage = &rdev->pm.power_state[req_ps_idx].
clock_info[rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx].voltage;
/* 0xff0x are flags rather then an actual voltage */
if ((voltage->vddci & 0xff00) == 0xff00)
return;
if (voltage->vddci && (voltage->vddci != rdev->pm.current_vddci)) {
radeon_atom_set_voltage(rdev, voltage->vddci, SET_VOLTAGE_TYPE_ASIC_VDDCI);
rdev->pm.current_vddci = voltage->vddci;
DRM_DEBUG("Setting: vddci: %d\n", voltage->vddci);
}
}
}
/**
* evergreen_pm_prepare - pre-power state change callback.
*
* @rdev: radeon_device pointer
*
* Prepare for a power state change (evergreen+).
*/
void evergreen_pm_prepare(struct radeon_device *rdev)
{
struct drm_device *ddev = rdev_to_drm(rdev);
struct drm_crtc *crtc;
struct radeon_crtc *radeon_crtc;
u32 tmp;
if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
/* don't try to enable hpd on eDP or LVDS avoid breaking the
* aux dp channel on imac and help (but not completely fix)
* https://bugzilla.redhat.com/show_bug.cgi?id=726143
* also avoid interrupt storms during dpms.
*/
continue;
}
static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev,
struct radeon_crtc *radeon_crtc,
struct drm_display_mode *mode,
struct drm_display_mode *other_mode)
{
u32 tmp, buffer_alloc, i;
u32 pipe_offset = radeon_crtc->crtc_id * 0x20;
/*
* Line Buffer Setup
* There are 3 line buffers, each one shared by 2 display controllers.
* DC_LB_MEMORY_SPLIT controls how that line buffer is shared between
* the display controllers. The paritioning is done via one of four
* preset allocations specified in bits 2:0:
* first display controller
* 0 - first half of lb (3840 * 2)
* 1 - first 3/4 of lb (5760 * 2)
* 2 - whole lb (7680 * 2), other crtc must be disabled
* 3 - first 1/4 of lb (1920 * 2)
* second display controller
* 4 - second half of lb (3840 * 2)
* 5 - second 3/4 of lb (5760 * 2)
* 6 - whole lb (7680 * 2), other crtc must be disabled
* 7 - last 1/4 of lb (1920 * 2)
*/
/* this can get tricky if we have two large displays on a paired group
* of crtcs. Ideally for multiple large displays we'd assign them to
* non-linked crtcs for maximum line buffer allocation.
*/
if (radeon_crtc->base.enabled && mode) {
if (other_mode) {
tmp = 0; /* 1/2 */
buffer_alloc = 1;
} else {
tmp = 2; /* whole */
buffer_alloc = 2;
}
} else {
tmp = 0;
buffer_alloc = 0;
}
/* second controller of the pair uses second half of the lb */
if (radeon_crtc->crtc_id % 2)
tmp += 4;
WREG32(DC_LB_MEMORY_SPLIT + radeon_crtc->crtc_offset, tmp);
if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) {
WREG32(PIPE0_DMIF_BUFFER_CONTROL + pipe_offset,
DMIF_BUFFERS_ALLOCATED(buffer_alloc));
for (i = 0; i < rdev->usec_timeout; i++) {
if (RREG32(PIPE0_DMIF_BUFFER_CONTROL + pipe_offset) &
DMIF_BUFFERS_ALLOCATED_COMPLETED)
break;
udelay(1);
}
}
if (radeon_crtc->base.enabled && mode) {
switch (tmp) {
case 0:
case 4:
default:
if (ASIC_IS_DCE5(rdev))
return 4096 * 2;
else
return 3840 * 2;
case 1:
case 5:
if (ASIC_IS_DCE5(rdev))
return 6144 * 2;
else
return 5760 * 2;
case 2:
case 6:
if (ASIC_IS_DCE5(rdev))
return 8192 * 2;
else
return 7680 * 2;
case 3:
case 7:
if (ASIC_IS_DCE5(rdev))
return 2048 * 2;
else
return 1920 * 2;
}
}
/* controller not enabled, so no lb used */
return 0;
}
switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
case 0:
default:
return 1;
case 1:
return 2;
case 2:
return 4;
case 3:
return 8;
}
}
struct evergreen_wm_params {
u32 dram_channels; /* number of dram channels */
u32 yclk; /* bandwidth per dram data pin in kHz */
u32 sclk; /* engine clock in kHz */
u32 disp_clk; /* display clock in kHz */
u32 src_width; /* viewport width */
u32 active_time; /* active display time in ns */
u32 blank_time; /* blank time in ns */
bool interlaced; /* mode is interlaced */
fixed20_12 vsc; /* vertical scale ratio */
u32 num_heads; /* number of active crtcs */
u32 bytes_per_pixel; /* bytes per pixel display + overlay */
u32 lb_size; /* line buffer allocated to pipe */
u32 vtaps; /* vertical scaler taps */
};
static u32 evergreen_dram_bandwidth(struct evergreen_wm_params *wm)
{
/* Calculate DRAM Bandwidth and the part allocated to display. */
fixed20_12 dram_efficiency; /* 0.7 */
fixed20_12 yclk, dram_channels, bandwidth;
fixed20_12 a;
static u32 evergreen_dram_bandwidth_for_display(struct evergreen_wm_params *wm)
{
/* Calculate DRAM Bandwidth and the part allocated to display. */
fixed20_12 disp_dram_allocation; /* 0.3 to 0.7 */
fixed20_12 yclk, dram_channels, bandwidth;
fixed20_12 a;
static u32 evergreen_available_bandwidth(struct evergreen_wm_params *wm)
{
/* Calculate the Available bandwidth. Display can use this temporarily but not in average. */
u32 dram_bandwidth = evergreen_dram_bandwidth(wm);
u32 data_return_bandwidth = evergreen_data_return_bandwidth(wm);
u32 dmif_req_bandwidth = evergreen_dmif_request_bandwidth(wm);
/* set for high clocks */
latency_watermark_a = min(evergreen_latency_watermark(&wm_high), (u32)65535);
/* set for low clocks */
latency_watermark_b = min(evergreen_latency_watermark(&wm_low), (u32)65535);
/* possibly force display priority to high */
/* should really do this at mode validation time... */
if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm_high) ||
!evergreen_average_bandwidth_vs_available_bandwidth(&wm_high) ||
!evergreen_check_latency_hiding(&wm_high) ||
(rdev->disp_priority == 2)) {
DRM_DEBUG_KMS("force priority a to high\n");
priority_a_cnt |= PRIORITY_ALWAYS_ON;
}
if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm_low) ||
!evergreen_average_bandwidth_vs_available_bandwidth(&wm_low) ||
!evergreen_check_latency_hiding(&wm_low) ||
(rdev->disp_priority == 2)) {
DRM_DEBUG_KMS("force priority b to high\n");
priority_b_cnt |= PRIORITY_ALWAYS_ON;
}
/* write the priority marks */
WREG32(PRIORITY_A_CNT + radeon_crtc->crtc_offset, priority_a_cnt);
WREG32(PRIORITY_B_CNT + radeon_crtc->crtc_offset, priority_b_cnt);
/* save values for DPM */
radeon_crtc->line_time = line_time;
radeon_crtc->wm_high = latency_watermark_a;
radeon_crtc->wm_low = latency_watermark_b;
}
/**
* evergreen_bandwidth_update - update display watermarks callback.
*
* @rdev: radeon_device pointer
*
* Update the display watermarks based on the requested mode(s)
* (evergreen+).
*/
void evergreen_bandwidth_update(struct radeon_device *rdev)
{
struct drm_display_mode *mode0 = NULL;
struct drm_display_mode *mode1 = NULL;
u32 num_heads = 0, lb_size;
int i;
if (!rdev->mode_info.mode_config_initialized)
return;
radeon_update_display_priority(rdev);
for (i = 0; i < rdev->num_crtc; i++) {
if (rdev->mode_info.crtcs[i]->base.enabled)
num_heads++;
}
for (i = 0; i < rdev->num_crtc; i += 2) {
mode0 = &rdev->mode_info.crtcs[i]->base.mode;
mode1 = &rdev->mode_info.crtcs[i+1]->base.mode;
lb_size = evergreen_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i], mode0, mode1);
evergreen_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads);
lb_size = evergreen_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i+1], mode1, mode0);
evergreen_program_watermarks(rdev, rdev->mode_info.crtcs[i+1], lb_size, num_heads);
}
}
/**
* evergreen_mc_wait_for_idle - wait for MC idle callback.
*
* @rdev: radeon_device pointer
*
* Wait for the MC (memory controller) to be idle.
* (evergreen+).
* Returns 0 if the MC is idle, -1 if not.
*/
int evergreen_mc_wait_for_idle(struct radeon_device *rdev)
{
unsigned i;
u32 tmp;
for (i = 0; i < rdev->usec_timeout; i++) {
/* read MC_STATUS */
tmp = RREG32(SRBM_STATUS) & 0x1F00;
if (!tmp)
return 0;
udelay(1);
}
return -1;
}
/*
* Assumption is that EVERGREEN_CRTC_MASTER_EN enable for requested crtc
* We go from crtc to connector and it is not relible since it
* should be an opposite direction .If crtc is enable then
* find the dig_fe which selects this crtc and insure that it enable.
* if such dig_fe is found then find dig_be which selects found dig_be and
* insure that it enable and in DP_SST mode.
* if UNIPHY_PLL_CONTROL1.enable then we should disconnect timing
* from dp symbols clocks .
*/
static bool evergreen_is_dp_sst_stream_enabled(struct radeon_device *rdev,
unsigned crtc_id, unsigned *ret_dig_fe)
{
unsigned i;
unsigned dig_fe;
unsigned dig_be;
unsigned dig_en_be;
unsigned uniphy_pll;
unsigned digs_fe_selected;
unsigned dig_be_mode;
unsigned dig_fe_mask;
bool is_enabled = false;
bool found_crtc = false;
/* loop through all running dig_fe to find selected crtc */
for (i = 0; i < ARRAY_SIZE(ni_dig_offsets); i++) {
dig_fe = RREG32(NI_DIG_FE_CNTL + ni_dig_offsets[i]);
if (dig_fe & NI_DIG_FE_CNTL_SYMCLK_FE_ON &&
crtc_id == NI_DIG_FE_CNTL_SOURCE_SELECT(dig_fe)) {
/* found running pipe */
found_crtc = true;
dig_fe_mask = 1 << i;
dig_fe = i;
break;
}
}
if (found_crtc) {
/* loop through all running dig_be to find selected dig_fe */
for (i = 0; i < ARRAY_SIZE(ni_dig_offsets); i++) {
dig_be = RREG32(NI_DIG_BE_CNTL + ni_dig_offsets[i]);
/* if dig_fe_selected by dig_be? */
digs_fe_selected = NI_DIG_BE_CNTL_FE_SOURCE_SELECT(dig_be);
dig_be_mode = NI_DIG_FE_CNTL_MODE(dig_be);
if (dig_fe_mask & digs_fe_selected &&
/* if dig_be in sst mode? */
dig_be_mode == NI_DIG_BE_DPSST) {
dig_en_be = RREG32(NI_DIG_BE_EN_CNTL +
ni_dig_offsets[i]);
uniphy_pll = RREG32(NI_DCIO_UNIPHY0_PLL_CONTROL1 +
ni_tx_offsets[i]);
/* dig_be enable and tx is running */
if (dig_en_be & NI_DIG_BE_EN_CNTL_ENABLE &&
dig_en_be & NI_DIG_BE_EN_CNTL_SYMBCLK_ON &&
uniphy_pll & NI_DCIO_UNIPHY0_PLL_CONTROL1_ENABLE) {
is_enabled = true;
*ret_dig_fe = dig_fe;
break;
}
}
}
}
void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
{
u32 crtc_enabled, tmp, frame_count, blackout;
int i, j;
unsigned dig_fe;
if (!ASIC_IS_NODCE(rdev)) {
save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
/* disable VGA render */
WREG32(VGA_RENDER_CONTROL, 0);
}
/* blank the display controllers */
for (i = 0; i < rdev->num_crtc; i++) {
crtc_enabled = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]) & EVERGREEN_CRTC_MASTER_EN;
if (crtc_enabled) {
save->crtc_enabled[i] = true;
if (ASIC_IS_DCE6(rdev)) {
tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]);
if (!(tmp & EVERGREEN_CRTC_BLANK_DATA_EN)) {
radeon_wait_for_vblank(rdev, i);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
tmp |= EVERGREEN_CRTC_BLANK_DATA_EN;
WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
}
} else {
tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
if (!(tmp & EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE)) {
radeon_wait_for_vblank(rdev, i);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE;
WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
}
}
/* wait for the next frame */
frame_count = radeon_get_vblank_counter(rdev, i);
for (j = 0; j < rdev->usec_timeout; j++) {
if (radeon_get_vblank_counter(rdev, i) != frame_count)
break;
udelay(1);
}
/*we should disable dig if it drives dp sst*/
/*but we are in radeon_device_init and the topology is unknown*/
/*and it is available after radeon_modeset_init*/
/*the following method radeon_atom_encoder_dpms_dig*/
/*does the job if we initialize it properly*/
/*for now we do it this manually*/
/**/
if (ASIC_IS_DCE5(rdev) &&
evergreen_is_dp_sst_stream_enabled(rdev, i, &dig_fe))
evergreen_blank_dp_output(rdev, dig_fe);
/*we could remove 6 lines below*/
/* XXX this is a hack to avoid strange behavior with EFI on certain systems */
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
tmp &= ~EVERGREEN_CRTC_MASTER_EN;
WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
save->crtc_enabled[i] = false;
/* ***** */
} else {
save->crtc_enabled[i] = false;
}
}
radeon_mc_wait_for_idle(rdev);
blackout = RREG32(MC_SHARED_BLACKOUT_CNTL);
if ((blackout & BLACKOUT_MODE_MASK) != 1) {
/* Block CPU access */
WREG32(BIF_FB_EN, 0);
/* blackout the MC */
blackout &= ~BLACKOUT_MODE_MASK;
WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1);
}
/* wait for the MC to settle */
udelay(100);
/* lock double buffered regs */
for (i = 0; i < rdev->num_crtc; i++) {
if (save->crtc_enabled[i]) {
tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]);
if (!(tmp & EVERGREEN_GRPH_UPDATE_LOCK)) {
tmp |= EVERGREEN_GRPH_UPDATE_LOCK;
WREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i], tmp);
}
tmp = RREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i]);
if (!(tmp & 1)) {
tmp |= 1;
WREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp);
}
}
}
}
void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save)
{
u32 tmp, frame_count;
int i, j;
/* update crtc base addresses */
for (i = 0; i < rdev->num_crtc; i++) {
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i],
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i],
(u32)rdev->mc.vram_start);
}
if (!ASIC_IS_NODCE(rdev)) {
WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start);
}
/* unlock regs and wait for update */
for (i = 0; i < rdev->num_crtc; i++) {
if (save->crtc_enabled[i]) {
tmp = RREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i]);
if ((tmp & 0x7) != 0) {
tmp &= ~0x7;
WREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i], tmp);
}
tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]);
if (tmp & EVERGREEN_GRPH_UPDATE_LOCK) {
tmp &= ~EVERGREEN_GRPH_UPDATE_LOCK;
WREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i], tmp);
}
tmp = RREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i]);
if (tmp & 1) {
tmp &= ~1;
WREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp);
}
for (j = 0; j < rdev->usec_timeout; j++) {
tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]);
if ((tmp & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING) == 0)
break;
udelay(1);
}
}
}
/* unblackout the MC */
tmp = RREG32(MC_SHARED_BLACKOUT_CNTL);
tmp &= ~BLACKOUT_MODE_MASK;
WREG32(MC_SHARED_BLACKOUT_CNTL, tmp);
/* allow CPU access */
WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
for (i = 0; i < rdev->num_crtc; i++) {
if (save->crtc_enabled[i]) {
if (ASIC_IS_DCE6(rdev)) {
tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]);
tmp &= ~EVERGREEN_CRTC_BLANK_DATA_EN;
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
} else {
tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
tmp &= ~EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE;
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
}
/* wait for the next frame */
frame_count = radeon_get_vblank_counter(rdev, i);
for (j = 0; j < rdev->usec_timeout; j++) {
if (radeon_get_vblank_counter(rdev, i) != frame_count)
break;
udelay(1);
}
}
}
if (!ASIC_IS_NODCE(rdev)) {
/* Unlock vga access */
WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);
mdelay(1);
WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
}
}
void evergreen_mc_program(struct radeon_device *rdev)
{
struct evergreen_mc_save save;
u32 tmp;
int i, j;
static int evergreen_cp_resume(struct radeon_device *rdev)
{
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
u32 tmp;
u32 rb_bufsz;
int r;
/* Reset cp; if cp is reset, then PA, SH, VGT also need to be reset */
WREG32(GRBM_SOFT_RESET, (SOFT_RESET_CP |
SOFT_RESET_PA |
SOFT_RESET_SH |
SOFT_RESET_VGT |
SOFT_RESET_SPI |
SOFT_RESET_SX));
RREG32(GRBM_SOFT_RESET);
mdelay(15);
WREG32(GRBM_SOFT_RESET, 0);
RREG32(GRBM_SOFT_RESET);
WREG32(GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i));
WREG32(RLC_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i));
rb_disable_bitmap = (RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000) >> 16;
tmp <<= 4;
tmp |= rb_disable_bitmap;
}
}
/* enabled rb are just the one not disabled :) */
disabled_rb_mask = tmp;
tmp = 0;
for (i = 0; i < rdev->config.evergreen.max_backends; i++)
tmp |= (1 << i);
/* if all the backends are disabled, fix it up here */
if ((disabled_rb_mask & tmp) == tmp) {
for (i = 0; i < rdev->config.evergreen.max_backends; i++)
disabled_rb_mask &= ~(1 << i);
}
for (i = 0; i < rdev->config.evergreen.num_ses; i++) {
u32 simd_disable_bitmap;
switch (rdev->family) {
case CHIP_CEDAR:
case CHIP_PALM:
case CHIP_SUMO:
case CHIP_SUMO2:
case CHIP_CAICOS:
/* no vertex cache */
sq_config &= ~VC_ENABLE;
break;
default:
break;
}
/* set the shader const cache sizes to 0 */
for (i = SQ_ALU_CONST_BUFFER_SIZE_PS_0; i < 0x28200; i += 4)
WREG32(i, 0);
for (i = SQ_ALU_CONST_BUFFER_SIZE_HS_0; i < 0x29000; i += 4)
WREG32(i, 0);
/* set mclk/sclk to bypass */
rv770_set_clk_bypass_mode(rdev);
/* disable BM */
pci_clear_master(rdev->pdev);
/* disable mem access */
evergreen_mc_stop(rdev, &save);
if (evergreen_mc_wait_for_idle(rdev)) {
dev_warn(rdev->dev, "Wait for MC idle timed out !\n");
}
/* reset */
radeon_pci_config_reset(rdev);
/* wait for asic to come out of reset */
for (i = 0; i < rdev->usec_timeout; i++) {
if (RREG32(CONFIG_MEMSIZE) != 0xffffffff)
break;
udelay(1);
}
}
int evergreen_asic_reset(struct radeon_device *rdev, bool hard)
{
u32 reset_mask;
if (hard) {
evergreen_gpu_pci_config_reset(rdev);
return 0;
}
if (!reset_mask)
r600_set_bios_scratch_engine_hung(rdev, false);
return 0;
}
/**
* evergreen_gfx_is_lockup - Check if the GFX engine is locked up
*
* @rdev: radeon_device pointer
* @ring: radeon_ring structure holding ring information
*
* Check if the GFX engine is locked up.
* Returns true if the engine appears to be locked up, false if not.
*/
bool evergreen_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
{
u32 reset_mask = evergreen_gpu_check_soft_reset(rdev);
void sumo_rlc_fini(struct radeon_device *rdev)
{
int r;
/* save restore block */
if (rdev->rlc.save_restore_obj) {
r = radeon_bo_reserve(rdev->rlc.save_restore_obj, false);
if (unlikely(r != 0))
dev_warn(rdev->dev, "(%d) reserve RLC sr bo failed\n", r);
radeon_bo_unpin(rdev->rlc.save_restore_obj);
radeon_bo_unreserve(rdev->rlc.save_restore_obj);
/* clear state block */
if (rdev->rlc.clear_state_obj) {
r = radeon_bo_reserve(rdev->rlc.clear_state_obj, false);
if (unlikely(r != 0))
dev_warn(rdev->dev, "(%d) reserve RLC c bo failed\n", r);
radeon_bo_unpin(rdev->rlc.clear_state_obj);
radeon_bo_unreserve(rdev->rlc.clear_state_obj);
fw_data = (const __be32 *)rdev->rlc_fw->data;
if (rdev->family >= CHIP_ARUBA) {
for (i = 0; i < ARUBA_RLC_UCODE_SIZE; i++) {
WREG32(RLC_UCODE_ADDR, i);
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
}
} else if (rdev->family >= CHIP_CAYMAN) {
for (i = 0; i < CAYMAN_RLC_UCODE_SIZE; i++) {
WREG32(RLC_UCODE_ADDR, i);
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
}
} else {
for (i = 0; i < EVERGREEN_RLC_UCODE_SIZE; i++) {
WREG32(RLC_UCODE_ADDR, i);
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
}
}
WREG32(RLC_UCODE_ADDR, 0);
evergreen_rlc_start(rdev);
return 0;
}
/* Interrupts */
u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc)
{
if (crtc >= rdev->num_crtc)
return 0;
else
return RREG32(CRTC_STATUS_FRAME_COUNT + crtc_offsets[crtc]);
}
void evergreen_disable_interrupt_state(struct radeon_device *rdev)
{
int i;
u32 tmp;
if (rdev->family >= CHIP_CAYMAN) {
cayman_cp_int_cntl_setup(rdev, 0,
CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
cayman_cp_int_cntl_setup(rdev, 1, 0);
cayman_cp_int_cntl_setup(rdev, 2, 0);
tmp = RREG32(CAYMAN_DMA1_CNTL) & ~TRAP_ENABLE;
WREG32(CAYMAN_DMA1_CNTL, tmp);
} else
WREG32(CP_INT_CNTL, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
tmp = RREG32(DMA_CNTL) & ~TRAP_ENABLE;
WREG32(DMA_CNTL, tmp);
WREG32(GRBM_INT_CNTL, 0);
WREG32(SRBM_INT_CNTL, 0);
for (i = 0; i < rdev->num_crtc; i++)
WREG32(INT_MASK + crtc_offsets[i], 0);
for (i = 0; i < rdev->num_crtc; i++)
WREG32(GRPH_INT_CONTROL + crtc_offsets[i], 0);
/* only one DAC on DCE5 */
if (!ASIC_IS_DCE5(rdev))
WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
WREG32(DACB_AUTODETECT_INT_CONTROL, 0);
for (i = 0; i < 6; i++)
WREG32_AND(DC_HPDx_INT_CONTROL(i), DC_HPDx_INT_POLARITY);
}
/* Note that the order we write back regs here is important */
int evergreen_irq_set(struct radeon_device *rdev)
{
int i;
u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE;
u32 cp_int_cntl1 = 0, cp_int_cntl2 = 0;
u32 grbm_int_cntl = 0;
u32 dma_cntl, dma_cntl1 = 0;
u32 thermal_int = 0;
if (!rdev->irq.installed) {
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
return -EINVAL;
}
/* don't enable anything if the ih is disabled */
if (!rdev->ih.enabled) {
r600_disable_interrupts(rdev);
/* force the active interrupt state to all disabled */
evergreen_disable_interrupt_state(rdev);
return 0;
}
if (rdev->family >= CHIP_CAYMAN)
WREG32(CAYMAN_DMA1_CNTL, dma_cntl1);
WREG32(GRBM_INT_CNTL, grbm_int_cntl);
for (i = 0; i < rdev->num_crtc; i++) {
radeon_irq_kms_set_irq_n_enabled(
rdev, INT_MASK + crtc_offsets[i],
VBLANK_INT_MASK,
rdev->irq.crtc_vblank_int[i] ||
atomic_read(&rdev->irq.pflip[i]), "vblank", i);
}
for (i = 0; i < rdev->num_crtc; i++)
WREG32(GRPH_INT_CONTROL + crtc_offsets[i], GRPH_PFLIP_INT_MASK);
for (i = 0; i < 6; i++) {
radeon_irq_kms_set_irq_n_enabled(
rdev, DC_HPDx_INT_CONTROL(i),
DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN,
rdev->irq.hpd[i], "HPD", i);
}
if (rdev->family == CHIP_ARUBA)
WREG32(TN_CG_THERMAL_INT_CTRL, thermal_int);
else
WREG32(CG_THERMAL_INT, thermal_int);
for (i = 0; i < 6; i++) {
radeon_irq_kms_set_irq_n_enabled(
rdev, AFMT_AUDIO_PACKET_CONTROL + crtc_offsets[i],
AFMT_AZ_FORMAT_WTRIG_MASK,
rdev->irq.afmt[i], "HDMI", i);
}
/* posting read */
RREG32(SRBM_STATUS);
return 0;
}
/* Note that the order we write back regs here is important */
static void evergreen_irq_ack(struct radeon_device *rdev)
{
int i, j;
u32 *grph_int = rdev->irq.stat_regs.evergreen.grph_int;
u32 *disp_int = rdev->irq.stat_regs.evergreen.disp_int;
u32 *afmt_status = rdev->irq.stat_regs.evergreen.afmt_status;
for (i = 0; i < 6; i++) {
disp_int[i] = RREG32(evergreen_disp_int_status[i]);
afmt_status[i] = RREG32(AFMT_STATUS + crtc_offsets[i]);
if (i < rdev->num_crtc)
grph_int[i] = RREG32(GRPH_INT_STATUS + crtc_offsets[i]);
}
/* We write back each interrupt register in pairs of two */
for (i = 0; i < rdev->num_crtc; i += 2) {
for (j = i; j < (i + 2); j++) {
if (grph_int[j] & GRPH_PFLIP_INT_OCCURRED)
WREG32(GRPH_INT_STATUS + crtc_offsets[j],
GRPH_PFLIP_INT_CLEAR);
}
for (j = i; j < (i + 2); j++) {
if (disp_int[j] & LB_D1_VBLANK_INTERRUPT)
WREG32(VBLANK_STATUS + crtc_offsets[j],
VBLANK_ACK);
if (disp_int[j] & LB_D1_VLINE_INTERRUPT)
WREG32(VLINE_STATUS + crtc_offsets[j],
VLINE_ACK);
}
}
for (i = 0; i < 6; i++) {
if (disp_int[i] & DC_HPD1_INTERRUPT)
WREG32_OR(DC_HPDx_INT_CONTROL(i), DC_HPDx_INT_ACK);
}
for (i = 0; i < 6; i++) {
if (disp_int[i] & DC_HPD1_RX_INTERRUPT)
WREG32_OR(DC_HPDx_INT_CONTROL(i), DC_HPDx_RX_INT_ACK);
}
for (i = 0; i < 6; i++) {
if (afmt_status[i] & AFMT_AZ_FORMAT_WTRIG)
WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + crtc_offsets[i],
AFMT_AZ_FORMAT_WTRIG_ACK);
}
}
if (!(afmt_status[afmt_idx] & AFMT_AZ_FORMAT_WTRIG))
DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
afmt_status[afmt_idx] &= ~AFMT_AZ_FORMAT_WTRIG;
queue_hdmi = true;
DRM_DEBUG("IH: HDMI%d\n", afmt_idx + 1);
break;
case 96:
DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR));
WREG32(SRBM_INT_ACK, 0x1);
break;
case 124: /* UVD */
DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
break;
case 146:
case 147:
addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR);
status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS);
/* reset addr and status */
WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1);
if (addr == 0x0 && status == 0x0)
break;
dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data);
dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n",
addr);
dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
status);
cayman_vm_decode_fault(rdev, status, addr);
break;
case 176: /* CP_INT in ring buffer */
case 177: /* CP_INT in IB1 */
case 178: /* CP_INT in IB2 */
DRM_DEBUG("IH: CP int: 0x%08x\n", src_data);
radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
break;
case 181: /* CP EOP event */
DRM_DEBUG("IH: CP EOP\n");
if (rdev->family >= CHIP_CAYMAN) {
switch (src_data) {
case 0:
radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
break;
case 1:
radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP1_INDEX);
break;
case 2:
radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP2_INDEX);
break;
}
} else
radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
break;
case 224: /* DMA trap event */
DRM_DEBUG("IH: DMA trap\n");
radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
break;
case 230: /* thermal low to high */
DRM_DEBUG("IH: thermal low to high\n");
rdev->pm.dpm.thermal.high_to_low = false;
queue_thermal = true;
break;
case 231: /* thermal high to low */
DRM_DEBUG("IH: thermal high to low\n");
rdev->pm.dpm.thermal.high_to_low = true;
queue_thermal = true;
break;
case 233: /* GUI IDLE */
DRM_DEBUG("IH: GUI idle\n");
break;
case 244: /* DMA trap event */
if (rdev->family >= CHIP_CAYMAN) {
DRM_DEBUG("IH: DMA1 trap\n");
radeon_fence_process(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
}
break;
default:
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
break;
}
/* wptr/rptr are in bytes! */
rptr += 16;
rptr &= rdev->ih.ptr_mask;
WREG32(IH_RB_RPTR, rptr);
}
if (queue_dp)
schedule_work(&rdev->dp_work);
if (queue_hotplug)
schedule_delayed_work(&rdev->hotplug_work, 0);
if (queue_hdmi)
schedule_work(&rdev->audio_work);
if (queue_thermal && rdev->pm.dpm_enabled)
schedule_work(&rdev->pm.dpm.thermal.work);
rdev->ih.rptr = rptr;
atomic_set(&rdev->ih.lock, 0);
/* make sure wptr hasn't changed while processing */
wptr = evergreen_get_ih_wptr(rdev);
if (wptr != rptr)
goto restart_ih;
return IRQ_HANDLED;
}
static void evergreen_uvd_init(struct radeon_device *rdev)
{
int r;
if (!rdev->has_uvd)
return;
r = radeon_uvd_init(rdev);
if (r) {
dev_err(rdev->dev, "failed UVD (%d) init.\n", r);
/*
* At this point rdev->uvd.vcpu_bo is NULL which trickles down
* to early fails uvd_v2_2_resume() and thus nothing happens
* there. So it is pointless to try to go through that code
* hence why we disable uvd here.
*/
rdev->has_uvd = false;
return;
}
rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL;
r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096);
}
static void evergreen_uvd_start(struct radeon_device *rdev)
{
int r;
if (!rdev->has_uvd)
return;
r = uvd_v2_2_resume(rdev);
if (r) {
dev_err(rdev->dev, "failed UVD resume (%d).\n", r);
goto error;
}
r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r);
goto error;
}
return;
/* scratch needs to be initialized before MC */
r = r600_vram_scratch_init(rdev);
if (r)
return r;
evergreen_mc_program(rdev);
if (ASIC_IS_DCE5(rdev) && !rdev->pm.dpm_enabled) {
r = ni_mc_load_microcode(rdev);
if (r) {
DRM_ERROR("Failed to load MC firmware!\n");
return r;
}
}
if (rdev->flags & RADEON_IS_AGP) {
evergreen_agp_enable(rdev);
} else {
r = evergreen_pcie_gart_enable(rdev);
if (r)
return r;
}
evergreen_gpu_init(rdev);
/* allocate rlc buffers */
if (rdev->flags & RADEON_IS_IGP) {
rdev->rlc.reg_list = sumo_rlc_save_restore_register_list;
rdev->rlc.reg_list_size =
(u32)ARRAY_SIZE(sumo_rlc_save_restore_register_list);
rdev->rlc.cs_data = evergreen_cs_data;
r = sumo_rlc_init(rdev);
if (r) {
DRM_ERROR("Failed to init rlc BOs!\n");
return r;
}
}
/* allocate wb buffer */
r = radeon_wb_init(rdev);
if (r)
return r;
r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
return r;
}
r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
return r;
}
evergreen_uvd_start(rdev);
/* Enable IRQ */
if (!rdev->irq.installed) {
r = radeon_irq_kms_init(rdev);
if (r)
return r;
}
r = r600_irq_init(rdev);
if (r) {
DRM_ERROR("radeon: IH init failed (%d).\n", r);
radeon_irq_kms_fini(rdev);
return r;
}
evergreen_irq_set(rdev);
ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
RADEON_CP_PACKET2);
if (r)
return r;
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
DMA_PACKET(DMA_PACKET_NOP, 0, 0));
if (r)
return r;
r = evergreen_cp_load_microcode(rdev);
if (r)
return r;
r = evergreen_cp_resume(rdev);
if (r)
return r;
r = r600_dma_resume(rdev);
if (r)
return r;
evergreen_uvd_resume(rdev);
r = radeon_ib_pool_init(rdev);
if (r) {
dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
return r;
}
r = radeon_audio_init(rdev);
if (r) {
DRM_ERROR("radeon: audio init failed\n");
return r;
}
return 0;
}
int evergreen_resume(struct radeon_device *rdev)
{
int r;
/* reset the asic, the gfx blocks are often in a bad state
* after the driver is unloaded or after a resume
*/
if (radeon_asic_reset(rdev))
dev_warn(rdev->dev, "GPU reset failed !\n");
/* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
* posting will perform necessary task to bring back GPU into good
* shape.
*/
/* post card */
atom_asic_init(rdev->mode_info.atom_context);
/* init golden registers */
evergreen_init_golden_registers(rdev);
if (rdev->pm.pm_method == PM_METHOD_DPM)
radeon_pm_resume(rdev);
rdev->accel_working = true;
r = evergreen_startup(rdev);
if (r) {
DRM_ERROR("evergreen startup failed on resume\n");
rdev->accel_working = false;
return r;
}
return r;
}
int evergreen_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
radeon_audio_fini(rdev);
if (rdev->has_uvd) {
radeon_uvd_suspend(rdev);
uvd_v1_0_fini(rdev);
}
r700_cp_stop(rdev);
r600_dma_stop(rdev);
evergreen_irq_suspend(rdev);
radeon_wb_disable(rdev);
evergreen_pcie_gart_disable(rdev);
return 0;
}
/* Plan is to move initialization in that function and use
* helper function so that radeon_device_init pretty much
* do nothing more than calling asic specific function. This
* should also allow to remove a bunch of callback function
* like vram_info.
*/
int evergreen_init(struct radeon_device *rdev)
{
int r;
/* Read BIOS */
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
return -EINVAL;
}
/* Must be an ATOMBIOS */
if (!rdev->is_atom_bios) {
dev_err(rdev->dev, "Expecting atombios for evergreen GPU\n");
return -EINVAL;
}
r = radeon_atombios_init(rdev);
if (r)
return r;
/* reset the asic, the gfx blocks are often in a bad state
* after the driver is unloaded or after a resume
*/
if (radeon_asic_reset(rdev))
dev_warn(rdev->dev, "GPU reset failed !\n");
/* Post card if necessary */
if (!radeon_card_posted(rdev)) {
if (!rdev->bios) {
dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
return -EINVAL;
}
DRM_INFO("GPU not posted. posting now...\n");
atom_asic_init(rdev->mode_info.atom_context);
}
/* init golden registers */
evergreen_init_golden_registers(rdev);
/* Initialize scratch registers */
r600_scratch_init(rdev);
/* Initialize surface registers */
radeon_surface_init(rdev);
/* Initialize clocks */
radeon_get_clock_info(rdev_to_drm(rdev));
/* Fence driver */
radeon_fence_driver_init(rdev);
/* initialize AGP */
if (rdev->flags & RADEON_IS_AGP) {
r = radeon_agp_init(rdev);
if (r)
radeon_agp_disable(rdev);
}
/* initialize memory controller */
r = evergreen_mc_init(rdev);
if (r)
return r;
/* Memory manager */
r = radeon_bo_init(rdev);
if (r)
return r;
if (ASIC_IS_DCE5(rdev)) {
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
r = ni_init_microcode(rdev);
if (r) {
DRM_ERROR("Failed to load firmware!\n");
return r;
}
}
} else {
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
r = r600_init_microcode(rdev);
if (r) {
DRM_ERROR("Failed to load firmware!\n");
return r;
}
}
}
/* Initialize power management */
radeon_pm_init(rdev);
rdev->accel_working = true;
r = evergreen_startup(rdev);
if (r) {
dev_err(rdev->dev, "disabling GPU acceleration\n");
r700_cp_fini(rdev);
r600_dma_fini(rdev);
r600_irq_fini(rdev);
if (rdev->flags & RADEON_IS_IGP)
sumo_rlc_fini(rdev);
radeon_wb_fini(rdev);
radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
evergreen_pcie_gart_fini(rdev);
rdev->accel_working = false;
}
/* Don't start up if the MC ucode is missing on BTC parts.
* The default clocks and voltages before the MC ucode
* is loaded are not suffient for advanced operations.
*/
if (ASIC_IS_DCE5(rdev)) {
if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) {
DRM_ERROR("radeon: MC ucode required for NI+.\n");
return -EINVAL;
}
}
} else {
link_width_cntl = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL);
/* XXX: only disable it if gen1 bridge vendor == 0x111d or 0x1106 */
if (1)
link_width_cntl |= LC_UPCONFIGURE_DIS;
else
link_width_cntl &= ~LC_UPCONFIGURE_DIS;
WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
}
}
void evergreen_program_aspm(struct radeon_device *rdev)
{
u32 data, orig;
u32 pcie_lc_cntl, pcie_lc_cntl_old;
bool disable_l0s, disable_l1 = false, disable_plloff_in_l1 = false;
/* fusion_platform = true
* if the system is a fusion system
* (APU or DGPU in a fusion system).
* todo: check if the system is a fusion platform.
*/
bool fusion_platform = false;
if (radeon_aspm == 0)
return;
if (!(rdev->flags & RADEON_IS_PCIE))
return;
switch (rdev->family) {
case CHIP_CYPRESS:
case CHIP_HEMLOCK:
case CHIP_JUNIPER:
case CHIP_REDWOOD:
case CHIP_CEDAR:
case CHIP_SUMO:
case CHIP_SUMO2:
case CHIP_PALM:
case CHIP_ARUBA:
disable_l0s = true;
break;
default:
disable_l0s = false;
break;
}
if (rdev->flags & RADEON_IS_IGP)
fusion_platform = true; /* XXX also dGPUs in a fusion system */
data = orig = RREG32_PIF_PHY0(PB0_PIF_PAIRING);
if (fusion_platform)
data &= ~MULTI_PIF;
else
data |= MULTI_PIF;
if (data != orig)
WREG32_PIF_PHY0(PB0_PIF_PAIRING, data);
data = orig = RREG32_PIF_PHY1(PB1_PIF_PAIRING);
if (fusion_platform)
data &= ~MULTI_PIF;
else
data |= MULTI_PIF;
if (data != orig)
WREG32_PIF_PHY1(PB1_PIF_PAIRING, data);
if (!disable_l1) {
if (rdev->family >= CHIP_BARTS)
pcie_lc_cntl |= LC_L1_INACTIVITY(7);
else
pcie_lc_cntl |= LC_L1_INACTIVITY(8);
if (!disable_plloff_in_l1) {
data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0);
data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK);
data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7);
if (data != orig)
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0, data);
data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1);
data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK);
data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7);
if (data != orig)
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1, data);
data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0);
data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK);
data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7);
if (data != orig)
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0, data);
data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1);
data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK);
data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7);
if (data != orig)
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1, data);
if (rdev->family >= CHIP_BARTS) {
data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0);
data &= ~PLL_RAMP_UP_TIME_0_MASK;
data |= PLL_RAMP_UP_TIME_0(4);
if (data != orig)
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0, data);
data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1);
data &= ~PLL_RAMP_UP_TIME_1_MASK;
data |= PLL_RAMP_UP_TIME_1(4);
if (data != orig)
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1, data);
data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0);
data &= ~PLL_RAMP_UP_TIME_0_MASK;
data |= PLL_RAMP_UP_TIME_0(4);
if (data != orig)
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0, data);
data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1);
data &= ~PLL_RAMP_UP_TIME_1_MASK;
data |= PLL_RAMP_UP_TIME_1(4);
if (data != orig)
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1, data);
}
data = orig = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL);
data &= ~LC_DYN_LANES_PWR_STATE_MASK;
data |= LC_DYN_LANES_PWR_STATE(3);
if (data != orig)
WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, data);
if (rdev->family >= CHIP_BARTS) {
data = orig = RREG32_PIF_PHY0(PB0_PIF_CNTL);
data &= ~LS2_EXIT_TIME_MASK;
data |= LS2_EXIT_TIME(1);
if (data != orig)
WREG32_PIF_PHY0(PB0_PIF_CNTL, data);
data = orig = RREG32_PIF_PHY1(PB1_PIF_CNTL);
data &= ~LS2_EXIT_TIME_MASK;
data |= LS2_EXIT_TIME(1);
if (data != orig)
WREG32_PIF_PHY1(PB1_PIF_CNTL, data);
}
}
}
/* evergreen parts only */
if (rdev->family < CHIP_BARTS)
pcie_lc_cntl |= LC_PMI_TO_L1_DIS;
if (pcie_lc_cntl != pcie_lc_cntl_old)
WREG32_PCIE_PORT(PCIE_LC_CNTL, pcie_lc_cntl);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.