162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2008 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * Copyright 2008 Red Hat Inc. 462306a36Sopenharmony_ci * Copyright 2009 Jerome Glisse. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 762306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 862306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 962306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1062306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 1162306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1462306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1762306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1862306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1962306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 2062306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2162306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2262306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Authors: Dave Airlie 2562306a36Sopenharmony_ci * Alex Deucher 2662306a36Sopenharmony_ci * Jerome Glisse 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/firmware.h> 3062306a36Sopenharmony_ci#include <linux/module.h> 3162306a36Sopenharmony_ci#include <linux/pci.h> 3262306a36Sopenharmony_ci#include <linux/seq_file.h> 3362306a36Sopenharmony_ci#include <linux/slab.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <drm/drm_device.h> 3662306a36Sopenharmony_ci#include <drm/drm_file.h> 3762306a36Sopenharmony_ci#include <drm/drm_fourcc.h> 3862306a36Sopenharmony_ci#include <drm/drm_framebuffer.h> 3962306a36Sopenharmony_ci#include <drm/drm_vblank.h> 4062306a36Sopenharmony_ci#include <drm/radeon_drm.h> 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include "atom.h" 4362306a36Sopenharmony_ci#include "r100_reg_safe.h" 4462306a36Sopenharmony_ci#include "r100d.h" 4562306a36Sopenharmony_ci#include "radeon.h" 4662306a36Sopenharmony_ci#include "radeon_asic.h" 4762306a36Sopenharmony_ci#include "radeon_reg.h" 4862306a36Sopenharmony_ci#include "rn50_reg_safe.h" 4962306a36Sopenharmony_ci#include "rs100d.h" 5062306a36Sopenharmony_ci#include "rv200d.h" 5162306a36Sopenharmony_ci#include "rv250d.h" 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* Firmware Names */ 5462306a36Sopenharmony_ci#define FIRMWARE_R100 "radeon/R100_cp.bin" 5562306a36Sopenharmony_ci#define FIRMWARE_R200 "radeon/R200_cp.bin" 5662306a36Sopenharmony_ci#define FIRMWARE_R300 "radeon/R300_cp.bin" 5762306a36Sopenharmony_ci#define FIRMWARE_R420 "radeon/R420_cp.bin" 5862306a36Sopenharmony_ci#define FIRMWARE_RS690 "radeon/RS690_cp.bin" 5962306a36Sopenharmony_ci#define FIRMWARE_RS600 "radeon/RS600_cp.bin" 6062306a36Sopenharmony_ci#define FIRMWARE_R520 "radeon/R520_cp.bin" 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_R100); 6362306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_R200); 6462306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_R300); 6562306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_R420); 6662306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RS690); 6762306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RS600); 6862306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_R520); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#include "r100_track.h" 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* This files gather functions specifics to: 7362306a36Sopenharmony_ci * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 7462306a36Sopenharmony_ci * and others in some cases. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic bool r100_is_in_vblank(struct radeon_device *rdev, int crtc) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci if (crtc == 0) { 8062306a36Sopenharmony_ci if (RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR) 8162306a36Sopenharmony_ci return true; 8262306a36Sopenharmony_ci else 8362306a36Sopenharmony_ci return false; 8462306a36Sopenharmony_ci } else { 8562306a36Sopenharmony_ci if (RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR) 8662306a36Sopenharmony_ci return true; 8762306a36Sopenharmony_ci else 8862306a36Sopenharmony_ci return false; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic bool r100_is_counter_moving(struct radeon_device *rdev, int crtc) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci u32 vline1, vline2; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (crtc == 0) { 9762306a36Sopenharmony_ci vline1 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; 9862306a36Sopenharmony_ci vline2 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; 9962306a36Sopenharmony_ci } else { 10062306a36Sopenharmony_ci vline1 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; 10162306a36Sopenharmony_ci vline2 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci if (vline1 != vline2) 10462306a36Sopenharmony_ci return true; 10562306a36Sopenharmony_ci else 10662306a36Sopenharmony_ci return false; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/** 11062306a36Sopenharmony_ci * r100_wait_for_vblank - vblank wait asic callback. 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * @rdev: radeon_device pointer 11362306a36Sopenharmony_ci * @crtc: crtc to wait for vblank on 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * Wait for vblank on the requested crtc (r1xx-r4xx). 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_civoid r100_wait_for_vblank(struct radeon_device *rdev, int crtc) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci unsigned i = 0; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (crtc >= rdev->num_crtc) 12262306a36Sopenharmony_ci return; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (crtc == 0) { 12562306a36Sopenharmony_ci if (!(RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN)) 12662306a36Sopenharmony_ci return; 12762306a36Sopenharmony_ci } else { 12862306a36Sopenharmony_ci if (!(RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_EN)) 12962306a36Sopenharmony_ci return; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* depending on when we hit vblank, we may be close to active; if so, 13362306a36Sopenharmony_ci * wait for another frame. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci while (r100_is_in_vblank(rdev, crtc)) { 13662306a36Sopenharmony_ci if (i++ % 100 == 0) { 13762306a36Sopenharmony_ci if (!r100_is_counter_moving(rdev, crtc)) 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci while (!r100_is_in_vblank(rdev, crtc)) { 14362306a36Sopenharmony_ci if (i++ % 100 == 0) { 14462306a36Sopenharmony_ci if (!r100_is_counter_moving(rdev, crtc)) 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/** 15162306a36Sopenharmony_ci * r100_page_flip - pageflip callback. 15262306a36Sopenharmony_ci * 15362306a36Sopenharmony_ci * @rdev: radeon_device pointer 15462306a36Sopenharmony_ci * @crtc_id: crtc to cleanup pageflip on 15562306a36Sopenharmony_ci * @crtc_base: new address of the crtc (GPU MC address) 15662306a36Sopenharmony_ci * @async: asynchronous flip 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * Does the actual pageflip (r1xx-r4xx). 15962306a36Sopenharmony_ci * During vblank we take the crtc lock and wait for the update_pending 16062306a36Sopenharmony_ci * bit to go high, when it does, we release the lock, and allow the 16162306a36Sopenharmony_ci * double buffered update to take place. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_civoid r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base, bool async) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; 16662306a36Sopenharmony_ci uint32_t crtc_pitch, pitch_pixels; 16762306a36Sopenharmony_ci struct drm_framebuffer *fb = radeon_crtc->base.primary->fb; 16862306a36Sopenharmony_ci u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK; 16962306a36Sopenharmony_ci int i; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* Lock the graphics update lock */ 17262306a36Sopenharmony_ci /* update the scanout addresses */ 17362306a36Sopenharmony_ci WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* update pitch */ 17662306a36Sopenharmony_ci pitch_pixels = fb->pitches[0] / fb->format->cpp[0]; 17762306a36Sopenharmony_ci crtc_pitch = DIV_ROUND_UP(pitch_pixels * fb->format->cpp[0] * 8, 17862306a36Sopenharmony_ci fb->format->cpp[0] * 8 * 8); 17962306a36Sopenharmony_ci crtc_pitch |= crtc_pitch << 16; 18062306a36Sopenharmony_ci WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Wait for update_pending to go high. */ 18362306a36Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 18462306a36Sopenharmony_ci if (RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET) 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci udelay(1); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* Unlock the lock, so double-buffering can take place inside vblank */ 19162306a36Sopenharmony_ci tmp &= ~RADEON_CRTC_OFFSET__OFFSET_LOCK; 19262306a36Sopenharmony_ci WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/** 19762306a36Sopenharmony_ci * r100_page_flip_pending - check if page flip is still pending 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * @rdev: radeon_device pointer 20062306a36Sopenharmony_ci * @crtc_id: crtc to check 20162306a36Sopenharmony_ci * 20262306a36Sopenharmony_ci * Check if the last pagefilp is still pending (r1xx-r4xx). 20362306a36Sopenharmony_ci * Returns the current update pending status. 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_cibool r100_page_flip_pending(struct radeon_device *rdev, int crtc_id) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* Return current update_pending status: */ 21062306a36Sopenharmony_ci return !!(RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & 21162306a36Sopenharmony_ci RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/** 21562306a36Sopenharmony_ci * r100_pm_get_dynpm_state - look up dynpm power state callback. 21662306a36Sopenharmony_ci * 21762306a36Sopenharmony_ci * @rdev: radeon_device pointer 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci * Look up the optimal power state based on the 22062306a36Sopenharmony_ci * current state of the GPU (r1xx-r5xx). 22162306a36Sopenharmony_ci * Used for dynpm only. 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_civoid r100_pm_get_dynpm_state(struct radeon_device *rdev) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci int i; 22662306a36Sopenharmony_ci rdev->pm.dynpm_can_upclock = true; 22762306a36Sopenharmony_ci rdev->pm.dynpm_can_downclock = true; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci switch (rdev->pm.dynpm_planned_action) { 23062306a36Sopenharmony_ci case DYNPM_ACTION_MINIMUM: 23162306a36Sopenharmony_ci rdev->pm.requested_power_state_index = 0; 23262306a36Sopenharmony_ci rdev->pm.dynpm_can_downclock = false; 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci case DYNPM_ACTION_DOWNCLOCK: 23562306a36Sopenharmony_ci if (rdev->pm.current_power_state_index == 0) { 23662306a36Sopenharmony_ci rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; 23762306a36Sopenharmony_ci rdev->pm.dynpm_can_downclock = false; 23862306a36Sopenharmony_ci } else { 23962306a36Sopenharmony_ci if (rdev->pm.active_crtc_count > 1) { 24062306a36Sopenharmony_ci for (i = 0; i < rdev->pm.num_power_states; i++) { 24162306a36Sopenharmony_ci if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) 24262306a36Sopenharmony_ci continue; 24362306a36Sopenharmony_ci else if (i >= rdev->pm.current_power_state_index) { 24462306a36Sopenharmony_ci rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci } else { 24762306a36Sopenharmony_ci rdev->pm.requested_power_state_index = i; 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci } else 25262306a36Sopenharmony_ci rdev->pm.requested_power_state_index = 25362306a36Sopenharmony_ci rdev->pm.current_power_state_index - 1; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci /* don't use the power state if crtcs are active and no display flag is set */ 25662306a36Sopenharmony_ci if ((rdev->pm.active_crtc_count > 0) && 25762306a36Sopenharmony_ci (rdev->pm.power_state[rdev->pm.requested_power_state_index].clock_info[0].flags & 25862306a36Sopenharmony_ci RADEON_PM_MODE_NO_DISPLAY)) { 25962306a36Sopenharmony_ci rdev->pm.requested_power_state_index++; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci break; 26262306a36Sopenharmony_ci case DYNPM_ACTION_UPCLOCK: 26362306a36Sopenharmony_ci if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { 26462306a36Sopenharmony_ci rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; 26562306a36Sopenharmony_ci rdev->pm.dynpm_can_upclock = false; 26662306a36Sopenharmony_ci } else { 26762306a36Sopenharmony_ci if (rdev->pm.active_crtc_count > 1) { 26862306a36Sopenharmony_ci for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { 26962306a36Sopenharmony_ci if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) 27062306a36Sopenharmony_ci continue; 27162306a36Sopenharmony_ci else if (i <= rdev->pm.current_power_state_index) { 27262306a36Sopenharmony_ci rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; 27362306a36Sopenharmony_ci break; 27462306a36Sopenharmony_ci } else { 27562306a36Sopenharmony_ci rdev->pm.requested_power_state_index = i; 27662306a36Sopenharmony_ci break; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci } else 28062306a36Sopenharmony_ci rdev->pm.requested_power_state_index = 28162306a36Sopenharmony_ci rdev->pm.current_power_state_index + 1; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci break; 28462306a36Sopenharmony_ci case DYNPM_ACTION_DEFAULT: 28562306a36Sopenharmony_ci rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; 28662306a36Sopenharmony_ci rdev->pm.dynpm_can_upclock = false; 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci case DYNPM_ACTION_NONE: 28962306a36Sopenharmony_ci default: 29062306a36Sopenharmony_ci DRM_ERROR("Requested mode for not defined action\n"); 29162306a36Sopenharmony_ci return; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci /* only one clock mode per power state */ 29462306a36Sopenharmony_ci rdev->pm.requested_clock_mode_index = 0; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Requested: e: %d m: %d p: %d\n", 29762306a36Sopenharmony_ci rdev->pm.power_state[rdev->pm.requested_power_state_index]. 29862306a36Sopenharmony_ci clock_info[rdev->pm.requested_clock_mode_index].sclk, 29962306a36Sopenharmony_ci rdev->pm.power_state[rdev->pm.requested_power_state_index]. 30062306a36Sopenharmony_ci clock_info[rdev->pm.requested_clock_mode_index].mclk, 30162306a36Sopenharmony_ci rdev->pm.power_state[rdev->pm.requested_power_state_index]. 30262306a36Sopenharmony_ci pcie_lanes); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/** 30662306a36Sopenharmony_ci * r100_pm_init_profile - Initialize power profiles callback. 30762306a36Sopenharmony_ci * 30862306a36Sopenharmony_ci * @rdev: radeon_device pointer 30962306a36Sopenharmony_ci * 31062306a36Sopenharmony_ci * Initialize the power states used in profile mode 31162306a36Sopenharmony_ci * (r1xx-r3xx). 31262306a36Sopenharmony_ci * Used for profile mode only. 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_civoid r100_pm_init_profile(struct radeon_device *rdev) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci /* default */ 31762306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; 31862306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; 31962306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; 32062306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; 32162306a36Sopenharmony_ci /* low sh */ 32262306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0; 32362306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0; 32462306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; 32562306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; 32662306a36Sopenharmony_ci /* mid sh */ 32762306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 0; 32862306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 0; 32962306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; 33062306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; 33162306a36Sopenharmony_ci /* high sh */ 33262306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0; 33362306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; 33462306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; 33562306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; 33662306a36Sopenharmony_ci /* low mh */ 33762306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0; 33862306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; 33962306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; 34062306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; 34162306a36Sopenharmony_ci /* mid mh */ 34262306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 0; 34362306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; 34462306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; 34562306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; 34662306a36Sopenharmony_ci /* high mh */ 34762306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0; 34862306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; 34962306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; 35062306a36Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci/** 35462306a36Sopenharmony_ci * r100_pm_misc - set additional pm hw parameters callback. 35562306a36Sopenharmony_ci * 35662306a36Sopenharmony_ci * @rdev: radeon_device pointer 35762306a36Sopenharmony_ci * 35862306a36Sopenharmony_ci * Set non-clock parameters associated with a power state 35962306a36Sopenharmony_ci * (voltage, pcie lanes, etc.) (r1xx-r4xx). 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_civoid r100_pm_misc(struct radeon_device *rdev) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci int requested_index = rdev->pm.requested_power_state_index; 36462306a36Sopenharmony_ci struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; 36562306a36Sopenharmony_ci struct radeon_voltage *voltage = &ps->clock_info[0].voltage; 36662306a36Sopenharmony_ci u32 tmp, sclk_cntl, sclk_cntl2, sclk_more_cntl; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if ((voltage->type == VOLTAGE_GPIO) && (voltage->gpio.valid)) { 36962306a36Sopenharmony_ci if (ps->misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { 37062306a36Sopenharmony_ci tmp = RREG32(voltage->gpio.reg); 37162306a36Sopenharmony_ci if (voltage->active_high) 37262306a36Sopenharmony_ci tmp |= voltage->gpio.mask; 37362306a36Sopenharmony_ci else 37462306a36Sopenharmony_ci tmp &= ~(voltage->gpio.mask); 37562306a36Sopenharmony_ci WREG32(voltage->gpio.reg, tmp); 37662306a36Sopenharmony_ci if (voltage->delay) 37762306a36Sopenharmony_ci udelay(voltage->delay); 37862306a36Sopenharmony_ci } else { 37962306a36Sopenharmony_ci tmp = RREG32(voltage->gpio.reg); 38062306a36Sopenharmony_ci if (voltage->active_high) 38162306a36Sopenharmony_ci tmp &= ~voltage->gpio.mask; 38262306a36Sopenharmony_ci else 38362306a36Sopenharmony_ci tmp |= voltage->gpio.mask; 38462306a36Sopenharmony_ci WREG32(voltage->gpio.reg, tmp); 38562306a36Sopenharmony_ci if (voltage->delay) 38662306a36Sopenharmony_ci udelay(voltage->delay); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci sclk_cntl = RREG32_PLL(SCLK_CNTL); 39162306a36Sopenharmony_ci sclk_cntl2 = RREG32_PLL(SCLK_CNTL2); 39262306a36Sopenharmony_ci sclk_cntl2 &= ~REDUCED_SPEED_SCLK_SEL(3); 39362306a36Sopenharmony_ci sclk_more_cntl = RREG32_PLL(SCLK_MORE_CNTL); 39462306a36Sopenharmony_ci sclk_more_cntl &= ~VOLTAGE_DELAY_SEL(3); 39562306a36Sopenharmony_ci if (ps->misc & ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN) { 39662306a36Sopenharmony_ci sclk_more_cntl |= REDUCED_SPEED_SCLK_EN; 39762306a36Sopenharmony_ci if (ps->misc & ATOM_PM_MISCINFO_DYN_CLK_3D_IDLE) 39862306a36Sopenharmony_ci sclk_cntl2 |= REDUCED_SPEED_SCLK_MODE; 39962306a36Sopenharmony_ci else 40062306a36Sopenharmony_ci sclk_cntl2 &= ~REDUCED_SPEED_SCLK_MODE; 40162306a36Sopenharmony_ci if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2) 40262306a36Sopenharmony_ci sclk_cntl2 |= REDUCED_SPEED_SCLK_SEL(0); 40362306a36Sopenharmony_ci else if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4) 40462306a36Sopenharmony_ci sclk_cntl2 |= REDUCED_SPEED_SCLK_SEL(2); 40562306a36Sopenharmony_ci } else 40662306a36Sopenharmony_ci sclk_more_cntl &= ~REDUCED_SPEED_SCLK_EN; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (ps->misc & ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN) { 40962306a36Sopenharmony_ci sclk_more_cntl |= IO_CG_VOLTAGE_DROP; 41062306a36Sopenharmony_ci if (voltage->delay) { 41162306a36Sopenharmony_ci sclk_more_cntl |= VOLTAGE_DROP_SYNC; 41262306a36Sopenharmony_ci switch (voltage->delay) { 41362306a36Sopenharmony_ci case 33: 41462306a36Sopenharmony_ci sclk_more_cntl |= VOLTAGE_DELAY_SEL(0); 41562306a36Sopenharmony_ci break; 41662306a36Sopenharmony_ci case 66: 41762306a36Sopenharmony_ci sclk_more_cntl |= VOLTAGE_DELAY_SEL(1); 41862306a36Sopenharmony_ci break; 41962306a36Sopenharmony_ci case 99: 42062306a36Sopenharmony_ci sclk_more_cntl |= VOLTAGE_DELAY_SEL(2); 42162306a36Sopenharmony_ci break; 42262306a36Sopenharmony_ci case 132: 42362306a36Sopenharmony_ci sclk_more_cntl |= VOLTAGE_DELAY_SEL(3); 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci } else 42762306a36Sopenharmony_ci sclk_more_cntl &= ~VOLTAGE_DROP_SYNC; 42862306a36Sopenharmony_ci } else 42962306a36Sopenharmony_ci sclk_more_cntl &= ~IO_CG_VOLTAGE_DROP; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN) 43262306a36Sopenharmony_ci sclk_cntl &= ~FORCE_HDP; 43362306a36Sopenharmony_ci else 43462306a36Sopenharmony_ci sclk_cntl |= FORCE_HDP; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci WREG32_PLL(SCLK_CNTL, sclk_cntl); 43762306a36Sopenharmony_ci WREG32_PLL(SCLK_CNTL2, sclk_cntl2); 43862306a36Sopenharmony_ci WREG32_PLL(SCLK_MORE_CNTL, sclk_more_cntl); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* set pcie lanes */ 44162306a36Sopenharmony_ci if ((rdev->flags & RADEON_IS_PCIE) && 44262306a36Sopenharmony_ci !(rdev->flags & RADEON_IS_IGP) && 44362306a36Sopenharmony_ci rdev->asic->pm.set_pcie_lanes && 44462306a36Sopenharmony_ci (ps->pcie_lanes != 44562306a36Sopenharmony_ci rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) { 44662306a36Sopenharmony_ci radeon_set_pcie_lanes(rdev, 44762306a36Sopenharmony_ci ps->pcie_lanes); 44862306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Setting: p: %d\n", ps->pcie_lanes); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci/** 45362306a36Sopenharmony_ci * r100_pm_prepare - pre-power state change callback. 45462306a36Sopenharmony_ci * 45562306a36Sopenharmony_ci * @rdev: radeon_device pointer 45662306a36Sopenharmony_ci * 45762306a36Sopenharmony_ci * Prepare for a power state change (r1xx-r4xx). 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_civoid r100_pm_prepare(struct radeon_device *rdev) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci struct drm_device *ddev = rdev->ddev; 46262306a36Sopenharmony_ci struct drm_crtc *crtc; 46362306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc; 46462306a36Sopenharmony_ci u32 tmp; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* disable any active CRTCs */ 46762306a36Sopenharmony_ci list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { 46862306a36Sopenharmony_ci radeon_crtc = to_radeon_crtc(crtc); 46962306a36Sopenharmony_ci if (radeon_crtc->enabled) { 47062306a36Sopenharmony_ci if (radeon_crtc->crtc_id) { 47162306a36Sopenharmony_ci tmp = RREG32(RADEON_CRTC2_GEN_CNTL); 47262306a36Sopenharmony_ci tmp |= RADEON_CRTC2_DISP_REQ_EN_B; 47362306a36Sopenharmony_ci WREG32(RADEON_CRTC2_GEN_CNTL, tmp); 47462306a36Sopenharmony_ci } else { 47562306a36Sopenharmony_ci tmp = RREG32(RADEON_CRTC_GEN_CNTL); 47662306a36Sopenharmony_ci tmp |= RADEON_CRTC_DISP_REQ_EN_B; 47762306a36Sopenharmony_ci WREG32(RADEON_CRTC_GEN_CNTL, tmp); 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci/** 48462306a36Sopenharmony_ci * r100_pm_finish - post-power state change callback. 48562306a36Sopenharmony_ci * 48662306a36Sopenharmony_ci * @rdev: radeon_device pointer 48762306a36Sopenharmony_ci * 48862306a36Sopenharmony_ci * Clean up after a power state change (r1xx-r4xx). 48962306a36Sopenharmony_ci */ 49062306a36Sopenharmony_civoid r100_pm_finish(struct radeon_device *rdev) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct drm_device *ddev = rdev->ddev; 49362306a36Sopenharmony_ci struct drm_crtc *crtc; 49462306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc; 49562306a36Sopenharmony_ci u32 tmp; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* enable any active CRTCs */ 49862306a36Sopenharmony_ci list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { 49962306a36Sopenharmony_ci radeon_crtc = to_radeon_crtc(crtc); 50062306a36Sopenharmony_ci if (radeon_crtc->enabled) { 50162306a36Sopenharmony_ci if (radeon_crtc->crtc_id) { 50262306a36Sopenharmony_ci tmp = RREG32(RADEON_CRTC2_GEN_CNTL); 50362306a36Sopenharmony_ci tmp &= ~RADEON_CRTC2_DISP_REQ_EN_B; 50462306a36Sopenharmony_ci WREG32(RADEON_CRTC2_GEN_CNTL, tmp); 50562306a36Sopenharmony_ci } else { 50662306a36Sopenharmony_ci tmp = RREG32(RADEON_CRTC_GEN_CNTL); 50762306a36Sopenharmony_ci tmp &= ~RADEON_CRTC_DISP_REQ_EN_B; 50862306a36Sopenharmony_ci WREG32(RADEON_CRTC_GEN_CNTL, tmp); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci/** 51562306a36Sopenharmony_ci * r100_gui_idle - gui idle callback. 51662306a36Sopenharmony_ci * 51762306a36Sopenharmony_ci * @rdev: radeon_device pointer 51862306a36Sopenharmony_ci * 51962306a36Sopenharmony_ci * Check of the GUI (2D/3D engines) are idle (r1xx-r5xx). 52062306a36Sopenharmony_ci * Returns true if idle, false if not. 52162306a36Sopenharmony_ci */ 52262306a36Sopenharmony_cibool r100_gui_idle(struct radeon_device *rdev) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci if (RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE) 52562306a36Sopenharmony_ci return false; 52662306a36Sopenharmony_ci else 52762306a36Sopenharmony_ci return true; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci/* hpd for digital panel detect/disconnect */ 53162306a36Sopenharmony_ci/** 53262306a36Sopenharmony_ci * r100_hpd_sense - hpd sense callback. 53362306a36Sopenharmony_ci * 53462306a36Sopenharmony_ci * @rdev: radeon_device pointer 53562306a36Sopenharmony_ci * @hpd: hpd (hotplug detect) pin 53662306a36Sopenharmony_ci * 53762306a36Sopenharmony_ci * Checks if a digital monitor is connected (r1xx-r4xx). 53862306a36Sopenharmony_ci * Returns true if connected, false if not connected. 53962306a36Sopenharmony_ci */ 54062306a36Sopenharmony_cibool r100_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci bool connected = false; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci switch (hpd) { 54562306a36Sopenharmony_ci case RADEON_HPD_1: 54662306a36Sopenharmony_ci if (RREG32(RADEON_FP_GEN_CNTL) & RADEON_FP_DETECT_SENSE) 54762306a36Sopenharmony_ci connected = true; 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci case RADEON_HPD_2: 55062306a36Sopenharmony_ci if (RREG32(RADEON_FP2_GEN_CNTL) & RADEON_FP2_DETECT_SENSE) 55162306a36Sopenharmony_ci connected = true; 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci default: 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci return connected; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci/** 56062306a36Sopenharmony_ci * r100_hpd_set_polarity - hpd set polarity callback. 56162306a36Sopenharmony_ci * 56262306a36Sopenharmony_ci * @rdev: radeon_device pointer 56362306a36Sopenharmony_ci * @hpd: hpd (hotplug detect) pin 56462306a36Sopenharmony_ci * 56562306a36Sopenharmony_ci * Set the polarity of the hpd pin (r1xx-r4xx). 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_civoid r100_hpd_set_polarity(struct radeon_device *rdev, 56862306a36Sopenharmony_ci enum radeon_hpd_id hpd) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci u32 tmp; 57162306a36Sopenharmony_ci bool connected = r100_hpd_sense(rdev, hpd); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci switch (hpd) { 57462306a36Sopenharmony_ci case RADEON_HPD_1: 57562306a36Sopenharmony_ci tmp = RREG32(RADEON_FP_GEN_CNTL); 57662306a36Sopenharmony_ci if (connected) 57762306a36Sopenharmony_ci tmp &= ~RADEON_FP_DETECT_INT_POL; 57862306a36Sopenharmony_ci else 57962306a36Sopenharmony_ci tmp |= RADEON_FP_DETECT_INT_POL; 58062306a36Sopenharmony_ci WREG32(RADEON_FP_GEN_CNTL, tmp); 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci case RADEON_HPD_2: 58362306a36Sopenharmony_ci tmp = RREG32(RADEON_FP2_GEN_CNTL); 58462306a36Sopenharmony_ci if (connected) 58562306a36Sopenharmony_ci tmp &= ~RADEON_FP2_DETECT_INT_POL; 58662306a36Sopenharmony_ci else 58762306a36Sopenharmony_ci tmp |= RADEON_FP2_DETECT_INT_POL; 58862306a36Sopenharmony_ci WREG32(RADEON_FP2_GEN_CNTL, tmp); 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci default: 59162306a36Sopenharmony_ci break; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci/** 59662306a36Sopenharmony_ci * r100_hpd_init - hpd setup callback. 59762306a36Sopenharmony_ci * 59862306a36Sopenharmony_ci * @rdev: radeon_device pointer 59962306a36Sopenharmony_ci * 60062306a36Sopenharmony_ci * Setup the hpd pins used by the card (r1xx-r4xx). 60162306a36Sopenharmony_ci * Set the polarity, and enable the hpd interrupts. 60262306a36Sopenharmony_ci */ 60362306a36Sopenharmony_civoid r100_hpd_init(struct radeon_device *rdev) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci struct drm_device *dev = rdev->ddev; 60662306a36Sopenharmony_ci struct drm_connector *connector; 60762306a36Sopenharmony_ci unsigned enable = 0; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 61062306a36Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 61162306a36Sopenharmony_ci if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) 61262306a36Sopenharmony_ci enable |= 1 << radeon_connector->hpd.hpd; 61362306a36Sopenharmony_ci radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci radeon_irq_kms_enable_hpd(rdev, enable); 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci/** 61962306a36Sopenharmony_ci * r100_hpd_fini - hpd tear down callback. 62062306a36Sopenharmony_ci * 62162306a36Sopenharmony_ci * @rdev: radeon_device pointer 62262306a36Sopenharmony_ci * 62362306a36Sopenharmony_ci * Tear down the hpd pins used by the card (r1xx-r4xx). 62462306a36Sopenharmony_ci * Disable the hpd interrupts. 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_civoid r100_hpd_fini(struct radeon_device *rdev) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci struct drm_device *dev = rdev->ddev; 62962306a36Sopenharmony_ci struct drm_connector *connector; 63062306a36Sopenharmony_ci unsigned disable = 0; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 63362306a36Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 63462306a36Sopenharmony_ci if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) 63562306a36Sopenharmony_ci disable |= 1 << radeon_connector->hpd.hpd; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci radeon_irq_kms_disable_hpd(rdev, disable); 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci/* 64162306a36Sopenharmony_ci * PCI GART 64262306a36Sopenharmony_ci */ 64362306a36Sopenharmony_civoid r100_pci_gart_tlb_flush(struct radeon_device *rdev) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci /* TODO: can we do somethings here ? */ 64662306a36Sopenharmony_ci /* It seems hw only cache one entry so we should discard this 64762306a36Sopenharmony_ci * entry otherwise if first GPU GART read hit this entry it 64862306a36Sopenharmony_ci * could end up in wrong address. */ 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ciint r100_pci_gart_init(struct radeon_device *rdev) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci int r; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (rdev->gart.ptr) { 65662306a36Sopenharmony_ci WARN(1, "R100 PCI GART already initialized\n"); 65762306a36Sopenharmony_ci return 0; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci /* Initialize common gart structure */ 66062306a36Sopenharmony_ci r = radeon_gart_init(rdev); 66162306a36Sopenharmony_ci if (r) 66262306a36Sopenharmony_ci return r; 66362306a36Sopenharmony_ci rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; 66462306a36Sopenharmony_ci rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush; 66562306a36Sopenharmony_ci rdev->asic->gart.get_page_entry = &r100_pci_gart_get_page_entry; 66662306a36Sopenharmony_ci rdev->asic->gart.set_page = &r100_pci_gart_set_page; 66762306a36Sopenharmony_ci return radeon_gart_table_ram_alloc(rdev); 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ciint r100_pci_gart_enable(struct radeon_device *rdev) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci uint32_t tmp; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* discard memory request outside of configured range */ 67562306a36Sopenharmony_ci tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS; 67662306a36Sopenharmony_ci WREG32(RADEON_AIC_CNTL, tmp); 67762306a36Sopenharmony_ci /* set address range for PCI address translate */ 67862306a36Sopenharmony_ci WREG32(RADEON_AIC_LO_ADDR, rdev->mc.gtt_start); 67962306a36Sopenharmony_ci WREG32(RADEON_AIC_HI_ADDR, rdev->mc.gtt_end); 68062306a36Sopenharmony_ci /* set PCI GART page-table base address */ 68162306a36Sopenharmony_ci WREG32(RADEON_AIC_PT_BASE, rdev->gart.table_addr); 68262306a36Sopenharmony_ci tmp = RREG32(RADEON_AIC_CNTL) | RADEON_PCIGART_TRANSLATE_EN; 68362306a36Sopenharmony_ci WREG32(RADEON_AIC_CNTL, tmp); 68462306a36Sopenharmony_ci r100_pci_gart_tlb_flush(rdev); 68562306a36Sopenharmony_ci DRM_INFO("PCI GART of %uM enabled (table at 0x%016llX).\n", 68662306a36Sopenharmony_ci (unsigned)(rdev->mc.gtt_size >> 20), 68762306a36Sopenharmony_ci (unsigned long long)rdev->gart.table_addr); 68862306a36Sopenharmony_ci rdev->gart.ready = true; 68962306a36Sopenharmony_ci return 0; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_civoid r100_pci_gart_disable(struct radeon_device *rdev) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci uint32_t tmp; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* discard memory request outside of configured range */ 69762306a36Sopenharmony_ci tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS; 69862306a36Sopenharmony_ci WREG32(RADEON_AIC_CNTL, tmp & ~RADEON_PCIGART_TRANSLATE_EN); 69962306a36Sopenharmony_ci WREG32(RADEON_AIC_LO_ADDR, 0); 70062306a36Sopenharmony_ci WREG32(RADEON_AIC_HI_ADDR, 0); 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ciuint64_t r100_pci_gart_get_page_entry(uint64_t addr, uint32_t flags) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci return addr; 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_civoid r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i, 70962306a36Sopenharmony_ci uint64_t entry) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci u32 *gtt = rdev->gart.ptr; 71262306a36Sopenharmony_ci gtt[i] = cpu_to_le32(lower_32_bits(entry)); 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_civoid r100_pci_gart_fini(struct radeon_device *rdev) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci radeon_gart_fini(rdev); 71862306a36Sopenharmony_ci r100_pci_gart_disable(rdev); 71962306a36Sopenharmony_ci radeon_gart_table_ram_free(rdev); 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ciint r100_irq_set(struct radeon_device *rdev) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci uint32_t tmp = 0; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (!rdev->irq.installed) { 72762306a36Sopenharmony_ci WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); 72862306a36Sopenharmony_ci WREG32(R_000040_GEN_INT_CNTL, 0); 72962306a36Sopenharmony_ci return -EINVAL; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { 73262306a36Sopenharmony_ci tmp |= RADEON_SW_INT_ENABLE; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci if (rdev->irq.crtc_vblank_int[0] || 73562306a36Sopenharmony_ci atomic_read(&rdev->irq.pflip[0])) { 73662306a36Sopenharmony_ci tmp |= RADEON_CRTC_VBLANK_MASK; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci if (rdev->irq.crtc_vblank_int[1] || 73962306a36Sopenharmony_ci atomic_read(&rdev->irq.pflip[1])) { 74062306a36Sopenharmony_ci tmp |= RADEON_CRTC2_VBLANK_MASK; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci if (rdev->irq.hpd[0]) { 74362306a36Sopenharmony_ci tmp |= RADEON_FP_DETECT_MASK; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci if (rdev->irq.hpd[1]) { 74662306a36Sopenharmony_ci tmp |= RADEON_FP2_DETECT_MASK; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci WREG32(RADEON_GEN_INT_CNTL, tmp); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* read back to post the write */ 75162306a36Sopenharmony_ci RREG32(RADEON_GEN_INT_CNTL); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci return 0; 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_civoid r100_irq_disable(struct radeon_device *rdev) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci u32 tmp; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci WREG32(R_000040_GEN_INT_CNTL, 0); 76162306a36Sopenharmony_ci /* Wait and acknowledge irq */ 76262306a36Sopenharmony_ci mdelay(1); 76362306a36Sopenharmony_ci tmp = RREG32(R_000044_GEN_INT_STATUS); 76462306a36Sopenharmony_ci WREG32(R_000044_GEN_INT_STATUS, tmp); 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic uint32_t r100_irq_ack(struct radeon_device *rdev) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci uint32_t irqs = RREG32(RADEON_GEN_INT_STATUS); 77062306a36Sopenharmony_ci uint32_t irq_mask = RADEON_SW_INT_TEST | 77162306a36Sopenharmony_ci RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT | 77262306a36Sopenharmony_ci RADEON_FP_DETECT_STAT | RADEON_FP2_DETECT_STAT; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (irqs) { 77562306a36Sopenharmony_ci WREG32(RADEON_GEN_INT_STATUS, irqs); 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci return irqs & irq_mask; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ciint r100_irq_process(struct radeon_device *rdev) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci uint32_t status, msi_rearm; 78362306a36Sopenharmony_ci bool queue_hotplug = false; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci status = r100_irq_ack(rdev); 78662306a36Sopenharmony_ci if (!status) { 78762306a36Sopenharmony_ci return IRQ_NONE; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci if (rdev->shutdown) { 79062306a36Sopenharmony_ci return IRQ_NONE; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci while (status) { 79362306a36Sopenharmony_ci /* SW interrupt */ 79462306a36Sopenharmony_ci if (status & RADEON_SW_INT_TEST) { 79562306a36Sopenharmony_ci radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci /* Vertical blank interrupts */ 79862306a36Sopenharmony_ci if (status & RADEON_CRTC_VBLANK_STAT) { 79962306a36Sopenharmony_ci if (rdev->irq.crtc_vblank_int[0]) { 80062306a36Sopenharmony_ci drm_handle_vblank(rdev->ddev, 0); 80162306a36Sopenharmony_ci rdev->pm.vblank_sync = true; 80262306a36Sopenharmony_ci wake_up(&rdev->irq.vblank_queue); 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci if (atomic_read(&rdev->irq.pflip[0])) 80562306a36Sopenharmony_ci radeon_crtc_handle_vblank(rdev, 0); 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci if (status & RADEON_CRTC2_VBLANK_STAT) { 80862306a36Sopenharmony_ci if (rdev->irq.crtc_vblank_int[1]) { 80962306a36Sopenharmony_ci drm_handle_vblank(rdev->ddev, 1); 81062306a36Sopenharmony_ci rdev->pm.vblank_sync = true; 81162306a36Sopenharmony_ci wake_up(&rdev->irq.vblank_queue); 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci if (atomic_read(&rdev->irq.pflip[1])) 81462306a36Sopenharmony_ci radeon_crtc_handle_vblank(rdev, 1); 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci if (status & RADEON_FP_DETECT_STAT) { 81762306a36Sopenharmony_ci queue_hotplug = true; 81862306a36Sopenharmony_ci DRM_DEBUG("HPD1\n"); 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci if (status & RADEON_FP2_DETECT_STAT) { 82162306a36Sopenharmony_ci queue_hotplug = true; 82262306a36Sopenharmony_ci DRM_DEBUG("HPD2\n"); 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci status = r100_irq_ack(rdev); 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci if (queue_hotplug) 82762306a36Sopenharmony_ci schedule_delayed_work(&rdev->hotplug_work, 0); 82862306a36Sopenharmony_ci if (rdev->msi_enabled) { 82962306a36Sopenharmony_ci switch (rdev->family) { 83062306a36Sopenharmony_ci case CHIP_RS400: 83162306a36Sopenharmony_ci case CHIP_RS480: 83262306a36Sopenharmony_ci msi_rearm = RREG32(RADEON_AIC_CNTL) & ~RS400_MSI_REARM; 83362306a36Sopenharmony_ci WREG32(RADEON_AIC_CNTL, msi_rearm); 83462306a36Sopenharmony_ci WREG32(RADEON_AIC_CNTL, msi_rearm | RS400_MSI_REARM); 83562306a36Sopenharmony_ci break; 83662306a36Sopenharmony_ci default: 83762306a36Sopenharmony_ci WREG32(RADEON_MSI_REARM_EN, RV370_MSI_REARM_EN); 83862306a36Sopenharmony_ci break; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci return IRQ_HANDLED; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ciu32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc) 84562306a36Sopenharmony_ci{ 84662306a36Sopenharmony_ci if (crtc == 0) 84762306a36Sopenharmony_ci return RREG32(RADEON_CRTC_CRNT_FRAME); 84862306a36Sopenharmony_ci else 84962306a36Sopenharmony_ci return RREG32(RADEON_CRTC2_CRNT_FRAME); 85062306a36Sopenharmony_ci} 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci/** 85362306a36Sopenharmony_ci * r100_ring_hdp_flush - flush Host Data Path via the ring buffer 85462306a36Sopenharmony_ci * @rdev: radeon device structure 85562306a36Sopenharmony_ci * @ring: ring buffer struct for emitting packets 85662306a36Sopenharmony_ci */ 85762306a36Sopenharmony_cistatic void r100_ring_hdp_flush(struct radeon_device *rdev, struct radeon_ring *ring) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0)); 86062306a36Sopenharmony_ci radeon_ring_write(ring, rdev->config.r100.hdp_cntl | 86162306a36Sopenharmony_ci RADEON_HDP_READ_BUFFER_INVALIDATE); 86262306a36Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0)); 86362306a36Sopenharmony_ci radeon_ring_write(ring, rdev->config.r100.hdp_cntl); 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci/* Who ever call radeon_fence_emit should call ring_lock and ask 86762306a36Sopenharmony_ci * for enough space (today caller are ib schedule and buffer move) */ 86862306a36Sopenharmony_civoid r100_fence_ring_emit(struct radeon_device *rdev, 86962306a36Sopenharmony_ci struct radeon_fence *fence) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[fence->ring]; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci /* We have to make sure that caches are flushed before 87462306a36Sopenharmony_ci * CPU might read something from VRAM. */ 87562306a36Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0)); 87662306a36Sopenharmony_ci radeon_ring_write(ring, RADEON_RB3D_DC_FLUSH_ALL); 87762306a36Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); 87862306a36Sopenharmony_ci radeon_ring_write(ring, RADEON_RB3D_ZC_FLUSH_ALL); 87962306a36Sopenharmony_ci /* Wait until IDLE & CLEAN */ 88062306a36Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0)); 88162306a36Sopenharmony_ci radeon_ring_write(ring, RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_3D_IDLECLEAN); 88262306a36Sopenharmony_ci r100_ring_hdp_flush(rdev, ring); 88362306a36Sopenharmony_ci /* Emit fence sequence & fire IRQ */ 88462306a36Sopenharmony_ci radeon_ring_write(ring, PACKET0(rdev->fence_drv[fence->ring].scratch_reg, 0)); 88562306a36Sopenharmony_ci radeon_ring_write(ring, fence->seq); 88662306a36Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_GEN_INT_STATUS, 0)); 88762306a36Sopenharmony_ci radeon_ring_write(ring, RADEON_SW_INT_FIRE); 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cibool r100_semaphore_ring_emit(struct radeon_device *rdev, 89162306a36Sopenharmony_ci struct radeon_ring *ring, 89262306a36Sopenharmony_ci struct radeon_semaphore *semaphore, 89362306a36Sopenharmony_ci bool emit_wait) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci /* Unused on older asics, since we don't have semaphores or multiple rings */ 89662306a36Sopenharmony_ci BUG(); 89762306a36Sopenharmony_ci return false; 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_cistruct radeon_fence *r100_copy_blit(struct radeon_device *rdev, 90162306a36Sopenharmony_ci uint64_t src_offset, 90262306a36Sopenharmony_ci uint64_t dst_offset, 90362306a36Sopenharmony_ci unsigned num_gpu_pages, 90462306a36Sopenharmony_ci struct dma_resv *resv) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; 90762306a36Sopenharmony_ci struct radeon_fence *fence; 90862306a36Sopenharmony_ci uint32_t cur_pages; 90962306a36Sopenharmony_ci uint32_t stride_bytes = RADEON_GPU_PAGE_SIZE; 91062306a36Sopenharmony_ci uint32_t pitch; 91162306a36Sopenharmony_ci uint32_t stride_pixels; 91262306a36Sopenharmony_ci unsigned ndw; 91362306a36Sopenharmony_ci int num_loops; 91462306a36Sopenharmony_ci int r = 0; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* radeon limited to 16k stride */ 91762306a36Sopenharmony_ci stride_bytes &= 0x3fff; 91862306a36Sopenharmony_ci /* radeon pitch is /64 */ 91962306a36Sopenharmony_ci pitch = stride_bytes / 64; 92062306a36Sopenharmony_ci stride_pixels = stride_bytes / 4; 92162306a36Sopenharmony_ci num_loops = DIV_ROUND_UP(num_gpu_pages, 8191); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci /* Ask for enough room for blit + flush + fence */ 92462306a36Sopenharmony_ci ndw = 64 + (10 * num_loops); 92562306a36Sopenharmony_ci r = radeon_ring_lock(rdev, ring, ndw); 92662306a36Sopenharmony_ci if (r) { 92762306a36Sopenharmony_ci DRM_ERROR("radeon: moving bo (%d) asking for %u dw.\n", r, ndw); 92862306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci while (num_gpu_pages > 0) { 93162306a36Sopenharmony_ci cur_pages = num_gpu_pages; 93262306a36Sopenharmony_ci if (cur_pages > 8191) { 93362306a36Sopenharmony_ci cur_pages = 8191; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci num_gpu_pages -= cur_pages; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci /* pages are in Y direction - height 93862306a36Sopenharmony_ci page width in X direction - width */ 93962306a36Sopenharmony_ci radeon_ring_write(ring, PACKET3(PACKET3_BITBLT_MULTI, 8)); 94062306a36Sopenharmony_ci radeon_ring_write(ring, 94162306a36Sopenharmony_ci RADEON_GMC_SRC_PITCH_OFFSET_CNTL | 94262306a36Sopenharmony_ci RADEON_GMC_DST_PITCH_OFFSET_CNTL | 94362306a36Sopenharmony_ci RADEON_GMC_SRC_CLIPPING | 94462306a36Sopenharmony_ci RADEON_GMC_DST_CLIPPING | 94562306a36Sopenharmony_ci RADEON_GMC_BRUSH_NONE | 94662306a36Sopenharmony_ci (RADEON_COLOR_FORMAT_ARGB8888 << 8) | 94762306a36Sopenharmony_ci RADEON_GMC_SRC_DATATYPE_COLOR | 94862306a36Sopenharmony_ci RADEON_ROP3_S | 94962306a36Sopenharmony_ci RADEON_DP_SRC_SOURCE_MEMORY | 95062306a36Sopenharmony_ci RADEON_GMC_CLR_CMP_CNTL_DIS | 95162306a36Sopenharmony_ci RADEON_GMC_WR_MSK_DIS); 95262306a36Sopenharmony_ci radeon_ring_write(ring, (pitch << 22) | (src_offset >> 10)); 95362306a36Sopenharmony_ci radeon_ring_write(ring, (pitch << 22) | (dst_offset >> 10)); 95462306a36Sopenharmony_ci radeon_ring_write(ring, (0x1fff) | (0x1fff << 16)); 95562306a36Sopenharmony_ci radeon_ring_write(ring, 0); 95662306a36Sopenharmony_ci radeon_ring_write(ring, (0x1fff) | (0x1fff << 16)); 95762306a36Sopenharmony_ci radeon_ring_write(ring, num_gpu_pages); 95862306a36Sopenharmony_ci radeon_ring_write(ring, num_gpu_pages); 95962306a36Sopenharmony_ci radeon_ring_write(ring, cur_pages | (stride_pixels << 16)); 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0)); 96262306a36Sopenharmony_ci radeon_ring_write(ring, RADEON_RB2D_DC_FLUSH_ALL); 96362306a36Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0)); 96462306a36Sopenharmony_ci radeon_ring_write(ring, 96562306a36Sopenharmony_ci RADEON_WAIT_2D_IDLECLEAN | 96662306a36Sopenharmony_ci RADEON_WAIT_HOST_IDLECLEAN | 96762306a36Sopenharmony_ci RADEON_WAIT_DMA_GUI_IDLE); 96862306a36Sopenharmony_ci r = radeon_fence_emit(rdev, &fence, RADEON_RING_TYPE_GFX_INDEX); 96962306a36Sopenharmony_ci if (r) { 97062306a36Sopenharmony_ci radeon_ring_unlock_undo(rdev, ring); 97162306a36Sopenharmony_ci return ERR_PTR(r); 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci radeon_ring_unlock_commit(rdev, ring, false); 97462306a36Sopenharmony_ci return fence; 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_cistatic int r100_cp_wait_for_idle(struct radeon_device *rdev) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci unsigned i; 98062306a36Sopenharmony_ci u32 tmp; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 98362306a36Sopenharmony_ci tmp = RREG32(R_000E40_RBBM_STATUS); 98462306a36Sopenharmony_ci if (!G_000E40_CP_CMDSTRM_BUSY(tmp)) { 98562306a36Sopenharmony_ci return 0; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci udelay(1); 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci return -1; 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_civoid r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci int r; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci r = radeon_ring_lock(rdev, ring, 2); 99762306a36Sopenharmony_ci if (r) { 99862306a36Sopenharmony_ci return; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_ISYNC_CNTL, 0)); 100162306a36Sopenharmony_ci radeon_ring_write(ring, 100262306a36Sopenharmony_ci RADEON_ISYNC_ANY2D_IDLE3D | 100362306a36Sopenharmony_ci RADEON_ISYNC_ANY3D_IDLE2D | 100462306a36Sopenharmony_ci RADEON_ISYNC_WAIT_IDLEGUI | 100562306a36Sopenharmony_ci RADEON_ISYNC_CPSCRATCH_IDLEGUI); 100662306a36Sopenharmony_ci radeon_ring_unlock_commit(rdev, ring, false); 100762306a36Sopenharmony_ci} 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci/* Load the microcode for the CP */ 101162306a36Sopenharmony_cistatic int r100_cp_init_microcode(struct radeon_device *rdev) 101262306a36Sopenharmony_ci{ 101362306a36Sopenharmony_ci const char *fw_name = NULL; 101462306a36Sopenharmony_ci int err; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci DRM_DEBUG_KMS("\n"); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) || 101962306a36Sopenharmony_ci (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) || 102062306a36Sopenharmony_ci (rdev->family == CHIP_RS200)) { 102162306a36Sopenharmony_ci DRM_INFO("Loading R100 Microcode\n"); 102262306a36Sopenharmony_ci fw_name = FIRMWARE_R100; 102362306a36Sopenharmony_ci } else if ((rdev->family == CHIP_R200) || 102462306a36Sopenharmony_ci (rdev->family == CHIP_RV250) || 102562306a36Sopenharmony_ci (rdev->family == CHIP_RV280) || 102662306a36Sopenharmony_ci (rdev->family == CHIP_RS300)) { 102762306a36Sopenharmony_ci DRM_INFO("Loading R200 Microcode\n"); 102862306a36Sopenharmony_ci fw_name = FIRMWARE_R200; 102962306a36Sopenharmony_ci } else if ((rdev->family == CHIP_R300) || 103062306a36Sopenharmony_ci (rdev->family == CHIP_R350) || 103162306a36Sopenharmony_ci (rdev->family == CHIP_RV350) || 103262306a36Sopenharmony_ci (rdev->family == CHIP_RV380) || 103362306a36Sopenharmony_ci (rdev->family == CHIP_RS400) || 103462306a36Sopenharmony_ci (rdev->family == CHIP_RS480)) { 103562306a36Sopenharmony_ci DRM_INFO("Loading R300 Microcode\n"); 103662306a36Sopenharmony_ci fw_name = FIRMWARE_R300; 103762306a36Sopenharmony_ci } else if ((rdev->family == CHIP_R420) || 103862306a36Sopenharmony_ci (rdev->family == CHIP_R423) || 103962306a36Sopenharmony_ci (rdev->family == CHIP_RV410)) { 104062306a36Sopenharmony_ci DRM_INFO("Loading R400 Microcode\n"); 104162306a36Sopenharmony_ci fw_name = FIRMWARE_R420; 104262306a36Sopenharmony_ci } else if ((rdev->family == CHIP_RS690) || 104362306a36Sopenharmony_ci (rdev->family == CHIP_RS740)) { 104462306a36Sopenharmony_ci DRM_INFO("Loading RS690/RS740 Microcode\n"); 104562306a36Sopenharmony_ci fw_name = FIRMWARE_RS690; 104662306a36Sopenharmony_ci } else if (rdev->family == CHIP_RS600) { 104762306a36Sopenharmony_ci DRM_INFO("Loading RS600 Microcode\n"); 104862306a36Sopenharmony_ci fw_name = FIRMWARE_RS600; 104962306a36Sopenharmony_ci } else if ((rdev->family == CHIP_RV515) || 105062306a36Sopenharmony_ci (rdev->family == CHIP_R520) || 105162306a36Sopenharmony_ci (rdev->family == CHIP_RV530) || 105262306a36Sopenharmony_ci (rdev->family == CHIP_R580) || 105362306a36Sopenharmony_ci (rdev->family == CHIP_RV560) || 105462306a36Sopenharmony_ci (rdev->family == CHIP_RV570)) { 105562306a36Sopenharmony_ci DRM_INFO("Loading R500 Microcode\n"); 105662306a36Sopenharmony_ci fw_name = FIRMWARE_R520; 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); 106062306a36Sopenharmony_ci if (err) { 106162306a36Sopenharmony_ci pr_err("radeon_cp: Failed to load firmware \"%s\"\n", fw_name); 106262306a36Sopenharmony_ci } else if (rdev->me_fw->size % 8) { 106362306a36Sopenharmony_ci pr_err("radeon_cp: Bogus length %zu in firmware \"%s\"\n", 106462306a36Sopenharmony_ci rdev->me_fw->size, fw_name); 106562306a36Sopenharmony_ci err = -EINVAL; 106662306a36Sopenharmony_ci release_firmware(rdev->me_fw); 106762306a36Sopenharmony_ci rdev->me_fw = NULL; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci return err; 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ciu32 r100_gfx_get_rptr(struct radeon_device *rdev, 107362306a36Sopenharmony_ci struct radeon_ring *ring) 107462306a36Sopenharmony_ci{ 107562306a36Sopenharmony_ci u32 rptr; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci if (rdev->wb.enabled) 107862306a36Sopenharmony_ci rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]); 107962306a36Sopenharmony_ci else 108062306a36Sopenharmony_ci rptr = RREG32(RADEON_CP_RB_RPTR); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci return rptr; 108362306a36Sopenharmony_ci} 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ciu32 r100_gfx_get_wptr(struct radeon_device *rdev, 108662306a36Sopenharmony_ci struct radeon_ring *ring) 108762306a36Sopenharmony_ci{ 108862306a36Sopenharmony_ci return RREG32(RADEON_CP_RB_WPTR); 108962306a36Sopenharmony_ci} 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_civoid r100_gfx_set_wptr(struct radeon_device *rdev, 109262306a36Sopenharmony_ci struct radeon_ring *ring) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci WREG32(RADEON_CP_RB_WPTR, ring->wptr); 109562306a36Sopenharmony_ci (void)RREG32(RADEON_CP_RB_WPTR); 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_cistatic void r100_cp_load_microcode(struct radeon_device *rdev) 109962306a36Sopenharmony_ci{ 110062306a36Sopenharmony_ci const __be32 *fw_data; 110162306a36Sopenharmony_ci int i, size; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci if (r100_gui_wait_for_idle(rdev)) { 110462306a36Sopenharmony_ci pr_warn("Failed to wait GUI idle while programming pipes. Bad things might happen.\n"); 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci if (rdev->me_fw) { 110862306a36Sopenharmony_ci size = rdev->me_fw->size / 4; 110962306a36Sopenharmony_ci fw_data = (const __be32 *)&rdev->me_fw->data[0]; 111062306a36Sopenharmony_ci WREG32(RADEON_CP_ME_RAM_ADDR, 0); 111162306a36Sopenharmony_ci for (i = 0; i < size; i += 2) { 111262306a36Sopenharmony_ci WREG32(RADEON_CP_ME_RAM_DATAH, 111362306a36Sopenharmony_ci be32_to_cpup(&fw_data[i])); 111462306a36Sopenharmony_ci WREG32(RADEON_CP_ME_RAM_DATAL, 111562306a36Sopenharmony_ci be32_to_cpup(&fw_data[i + 1])); 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci} 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ciint r100_cp_init(struct radeon_device *rdev, unsigned ring_size) 112162306a36Sopenharmony_ci{ 112262306a36Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; 112362306a36Sopenharmony_ci unsigned rb_bufsz; 112462306a36Sopenharmony_ci unsigned rb_blksz; 112562306a36Sopenharmony_ci unsigned max_fetch; 112662306a36Sopenharmony_ci unsigned pre_write_timer; 112762306a36Sopenharmony_ci unsigned pre_write_limit; 112862306a36Sopenharmony_ci unsigned indirect2_start; 112962306a36Sopenharmony_ci unsigned indirect1_start; 113062306a36Sopenharmony_ci uint32_t tmp; 113162306a36Sopenharmony_ci int r; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci r100_debugfs_cp_init(rdev); 113462306a36Sopenharmony_ci if (!rdev->me_fw) { 113562306a36Sopenharmony_ci r = r100_cp_init_microcode(rdev); 113662306a36Sopenharmony_ci if (r) { 113762306a36Sopenharmony_ci DRM_ERROR("Failed to load firmware!\n"); 113862306a36Sopenharmony_ci return r; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci /* Align ring size */ 114362306a36Sopenharmony_ci rb_bufsz = order_base_2(ring_size / 8); 114462306a36Sopenharmony_ci ring_size = (1 << (rb_bufsz + 1)) * 4; 114562306a36Sopenharmony_ci r100_cp_load_microcode(rdev); 114662306a36Sopenharmony_ci r = radeon_ring_init(rdev, ring, ring_size, RADEON_WB_CP_RPTR_OFFSET, 114762306a36Sopenharmony_ci RADEON_CP_PACKET2); 114862306a36Sopenharmony_ci if (r) { 114962306a36Sopenharmony_ci return r; 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci /* Each time the cp read 1024 bytes (16 dword/quadword) update 115262306a36Sopenharmony_ci * the rptr copy in system ram */ 115362306a36Sopenharmony_ci rb_blksz = 9; 115462306a36Sopenharmony_ci /* cp will read 128bytes at a time (4 dwords) */ 115562306a36Sopenharmony_ci max_fetch = 1; 115662306a36Sopenharmony_ci ring->align_mask = 16 - 1; 115762306a36Sopenharmony_ci /* Write to CP_RB_WPTR will be delayed for pre_write_timer clocks */ 115862306a36Sopenharmony_ci pre_write_timer = 64; 115962306a36Sopenharmony_ci /* Force CP_RB_WPTR write if written more than one time before the 116062306a36Sopenharmony_ci * delay expire 116162306a36Sopenharmony_ci */ 116262306a36Sopenharmony_ci pre_write_limit = 0; 116362306a36Sopenharmony_ci /* Setup the cp cache like this (cache size is 96 dwords) : 116462306a36Sopenharmony_ci * RING 0 to 15 116562306a36Sopenharmony_ci * INDIRECT1 16 to 79 116662306a36Sopenharmony_ci * INDIRECT2 80 to 95 116762306a36Sopenharmony_ci * So ring cache size is 16dwords (> (2 * max_fetch = 2 * 4dwords)) 116862306a36Sopenharmony_ci * indirect1 cache size is 64dwords (> (2 * max_fetch = 2 * 4dwords)) 116962306a36Sopenharmony_ci * indirect2 cache size is 16dwords (> (2 * max_fetch = 2 * 4dwords)) 117062306a36Sopenharmony_ci * Idea being that most of the gpu cmd will be through indirect1 buffer 117162306a36Sopenharmony_ci * so it gets the bigger cache. 117262306a36Sopenharmony_ci */ 117362306a36Sopenharmony_ci indirect2_start = 80; 117462306a36Sopenharmony_ci indirect1_start = 16; 117562306a36Sopenharmony_ci /* cp setup */ 117662306a36Sopenharmony_ci WREG32(0x718, pre_write_timer | (pre_write_limit << 28)); 117762306a36Sopenharmony_ci tmp = (REG_SET(RADEON_RB_BUFSZ, rb_bufsz) | 117862306a36Sopenharmony_ci REG_SET(RADEON_RB_BLKSZ, rb_blksz) | 117962306a36Sopenharmony_ci REG_SET(RADEON_MAX_FETCH, max_fetch)); 118062306a36Sopenharmony_ci#ifdef __BIG_ENDIAN 118162306a36Sopenharmony_ci tmp |= RADEON_BUF_SWAP_32BIT; 118262306a36Sopenharmony_ci#endif 118362306a36Sopenharmony_ci WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_NO_UPDATE); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci /* Set ring address */ 118662306a36Sopenharmony_ci DRM_INFO("radeon: ring at 0x%016lX\n", (unsigned long)ring->gpu_addr); 118762306a36Sopenharmony_ci WREG32(RADEON_CP_RB_BASE, ring->gpu_addr); 118862306a36Sopenharmony_ci /* Force read & write ptr to 0 */ 118962306a36Sopenharmony_ci WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA | RADEON_RB_NO_UPDATE); 119062306a36Sopenharmony_ci WREG32(RADEON_CP_RB_RPTR_WR, 0); 119162306a36Sopenharmony_ci ring->wptr = 0; 119262306a36Sopenharmony_ci WREG32(RADEON_CP_RB_WPTR, ring->wptr); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci /* set the wb address whether it's enabled or not */ 119562306a36Sopenharmony_ci WREG32(R_00070C_CP_RB_RPTR_ADDR, 119662306a36Sopenharmony_ci S_00070C_RB_RPTR_ADDR((rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) >> 2)); 119762306a36Sopenharmony_ci WREG32(R_000774_SCRATCH_ADDR, rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci if (rdev->wb.enabled) 120062306a36Sopenharmony_ci WREG32(R_000770_SCRATCH_UMSK, 0xff); 120162306a36Sopenharmony_ci else { 120262306a36Sopenharmony_ci tmp |= RADEON_RB_NO_UPDATE; 120362306a36Sopenharmony_ci WREG32(R_000770_SCRATCH_UMSK, 0); 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci WREG32(RADEON_CP_RB_CNTL, tmp); 120762306a36Sopenharmony_ci udelay(10); 120862306a36Sopenharmony_ci /* Set cp mode to bus mastering & enable cp*/ 120962306a36Sopenharmony_ci WREG32(RADEON_CP_CSQ_MODE, 121062306a36Sopenharmony_ci REG_SET(RADEON_INDIRECT2_START, indirect2_start) | 121162306a36Sopenharmony_ci REG_SET(RADEON_INDIRECT1_START, indirect1_start)); 121262306a36Sopenharmony_ci WREG32(RADEON_CP_RB_WPTR_DELAY, 0); 121362306a36Sopenharmony_ci WREG32(RADEON_CP_CSQ_MODE, 0x00004D4D); 121462306a36Sopenharmony_ci WREG32(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci /* at this point everything should be setup correctly to enable master */ 121762306a36Sopenharmony_ci pci_set_master(rdev->pdev); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci radeon_ring_start(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); 122062306a36Sopenharmony_ci r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, ring); 122162306a36Sopenharmony_ci if (r) { 122262306a36Sopenharmony_ci DRM_ERROR("radeon: cp isn't working (%d).\n", r); 122362306a36Sopenharmony_ci return r; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci ring->ready = true; 122662306a36Sopenharmony_ci radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci if (!ring->rptr_save_reg /* not resuming from suspend */ 122962306a36Sopenharmony_ci && radeon_ring_supports_scratch_reg(rdev, ring)) { 123062306a36Sopenharmony_ci r = radeon_scratch_get(rdev, &ring->rptr_save_reg); 123162306a36Sopenharmony_ci if (r) { 123262306a36Sopenharmony_ci DRM_ERROR("failed to get scratch reg for rptr save (%d).\n", r); 123362306a36Sopenharmony_ci ring->rptr_save_reg = 0; 123462306a36Sopenharmony_ci } 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci return 0; 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_civoid r100_cp_fini(struct radeon_device *rdev) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci if (r100_cp_wait_for_idle(rdev)) { 124262306a36Sopenharmony_ci DRM_ERROR("Wait for CP idle timeout, shutting down CP.\n"); 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci /* Disable ring */ 124562306a36Sopenharmony_ci r100_cp_disable(rdev); 124662306a36Sopenharmony_ci radeon_scratch_free(rdev, rdev->ring[RADEON_RING_TYPE_GFX_INDEX].rptr_save_reg); 124762306a36Sopenharmony_ci radeon_ring_fini(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); 124862306a36Sopenharmony_ci DRM_INFO("radeon: cp finalized\n"); 124962306a36Sopenharmony_ci} 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_civoid r100_cp_disable(struct radeon_device *rdev) 125262306a36Sopenharmony_ci{ 125362306a36Sopenharmony_ci /* Disable ring */ 125462306a36Sopenharmony_ci radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); 125562306a36Sopenharmony_ci rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false; 125662306a36Sopenharmony_ci WREG32(RADEON_CP_CSQ_MODE, 0); 125762306a36Sopenharmony_ci WREG32(RADEON_CP_CSQ_CNTL, 0); 125862306a36Sopenharmony_ci WREG32(R_000770_SCRATCH_UMSK, 0); 125962306a36Sopenharmony_ci if (r100_gui_wait_for_idle(rdev)) { 126062306a36Sopenharmony_ci pr_warn("Failed to wait GUI idle while programming pipes. Bad things might happen.\n"); 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci} 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci/* 126562306a36Sopenharmony_ci * CS functions 126662306a36Sopenharmony_ci */ 126762306a36Sopenharmony_ciint r100_reloc_pitch_offset(struct radeon_cs_parser *p, 126862306a36Sopenharmony_ci struct radeon_cs_packet *pkt, 126962306a36Sopenharmony_ci unsigned idx, 127062306a36Sopenharmony_ci unsigned reg) 127162306a36Sopenharmony_ci{ 127262306a36Sopenharmony_ci int r; 127362306a36Sopenharmony_ci u32 tile_flags = 0; 127462306a36Sopenharmony_ci u32 tmp; 127562306a36Sopenharmony_ci struct radeon_bo_list *reloc; 127662306a36Sopenharmony_ci u32 value; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 127962306a36Sopenharmony_ci if (r) { 128062306a36Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 128162306a36Sopenharmony_ci idx, reg); 128262306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 128362306a36Sopenharmony_ci return r; 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci value = radeon_get_ib_value(p, idx); 128762306a36Sopenharmony_ci tmp = value & 0x003fffff; 128862306a36Sopenharmony_ci tmp += (((u32)reloc->gpu_offset) >> 10); 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { 129162306a36Sopenharmony_ci if (reloc->tiling_flags & RADEON_TILING_MACRO) 129262306a36Sopenharmony_ci tile_flags |= RADEON_DST_TILE_MACRO; 129362306a36Sopenharmony_ci if (reloc->tiling_flags & RADEON_TILING_MICRO) { 129462306a36Sopenharmony_ci if (reg == RADEON_SRC_PITCH_OFFSET) { 129562306a36Sopenharmony_ci DRM_ERROR("Cannot src blit from microtiled surface\n"); 129662306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 129762306a36Sopenharmony_ci return -EINVAL; 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci tile_flags |= RADEON_DST_TILE_MICRO; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci tmp |= tile_flags; 130362306a36Sopenharmony_ci p->ib.ptr[idx] = (value & 0x3fc00000) | tmp; 130462306a36Sopenharmony_ci } else 130562306a36Sopenharmony_ci p->ib.ptr[idx] = (value & 0xffc00000) | tmp; 130662306a36Sopenharmony_ci return 0; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ciint r100_packet3_load_vbpntr(struct radeon_cs_parser *p, 131062306a36Sopenharmony_ci struct radeon_cs_packet *pkt, 131162306a36Sopenharmony_ci int idx) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci unsigned c, i; 131462306a36Sopenharmony_ci struct radeon_bo_list *reloc; 131562306a36Sopenharmony_ci struct r100_cs_track *track; 131662306a36Sopenharmony_ci int r = 0; 131762306a36Sopenharmony_ci volatile uint32_t *ib; 131862306a36Sopenharmony_ci u32 idx_value; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci ib = p->ib.ptr; 132162306a36Sopenharmony_ci track = (struct r100_cs_track *)p->track; 132262306a36Sopenharmony_ci c = radeon_get_ib_value(p, idx++) & 0x1F; 132362306a36Sopenharmony_ci if (c > 16) { 132462306a36Sopenharmony_ci DRM_ERROR("Only 16 vertex buffers are allowed %d\n", 132562306a36Sopenharmony_ci pkt->opcode); 132662306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 132762306a36Sopenharmony_ci return -EINVAL; 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci track->num_arrays = c; 133062306a36Sopenharmony_ci for (i = 0; i < (c - 1); i+=2, idx+=3) { 133162306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 133262306a36Sopenharmony_ci if (r) { 133362306a36Sopenharmony_ci DRM_ERROR("No reloc for packet3 %d\n", 133462306a36Sopenharmony_ci pkt->opcode); 133562306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 133662306a36Sopenharmony_ci return r; 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci idx_value = radeon_get_ib_value(p, idx); 133962306a36Sopenharmony_ci ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->gpu_offset); 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci track->arrays[i + 0].esize = idx_value >> 8; 134262306a36Sopenharmony_ci track->arrays[i + 0].robj = reloc->robj; 134362306a36Sopenharmony_ci track->arrays[i + 0].esize &= 0x7F; 134462306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 134562306a36Sopenharmony_ci if (r) { 134662306a36Sopenharmony_ci DRM_ERROR("No reloc for packet3 %d\n", 134762306a36Sopenharmony_ci pkt->opcode); 134862306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 134962306a36Sopenharmony_ci return r; 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci ib[idx+2] = radeon_get_ib_value(p, idx + 2) + ((u32)reloc->gpu_offset); 135262306a36Sopenharmony_ci track->arrays[i + 1].robj = reloc->robj; 135362306a36Sopenharmony_ci track->arrays[i + 1].esize = idx_value >> 24; 135462306a36Sopenharmony_ci track->arrays[i + 1].esize &= 0x7F; 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci if (c & 1) { 135762306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 135862306a36Sopenharmony_ci if (r) { 135962306a36Sopenharmony_ci DRM_ERROR("No reloc for packet3 %d\n", 136062306a36Sopenharmony_ci pkt->opcode); 136162306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 136262306a36Sopenharmony_ci return r; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci idx_value = radeon_get_ib_value(p, idx); 136562306a36Sopenharmony_ci ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->gpu_offset); 136662306a36Sopenharmony_ci track->arrays[i + 0].robj = reloc->robj; 136762306a36Sopenharmony_ci track->arrays[i + 0].esize = idx_value >> 8; 136862306a36Sopenharmony_ci track->arrays[i + 0].esize &= 0x7F; 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci return r; 137162306a36Sopenharmony_ci} 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ciint r100_cs_parse_packet0(struct radeon_cs_parser *p, 137462306a36Sopenharmony_ci struct radeon_cs_packet *pkt, 137562306a36Sopenharmony_ci const unsigned *auth, unsigned n, 137662306a36Sopenharmony_ci radeon_packet0_check_t check) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci unsigned reg; 137962306a36Sopenharmony_ci unsigned i, j, m; 138062306a36Sopenharmony_ci unsigned idx; 138162306a36Sopenharmony_ci int r; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci idx = pkt->idx + 1; 138462306a36Sopenharmony_ci reg = pkt->reg; 138562306a36Sopenharmony_ci /* Check that register fall into register range 138662306a36Sopenharmony_ci * determined by the number of entry (n) in the 138762306a36Sopenharmony_ci * safe register bitmap. 138862306a36Sopenharmony_ci */ 138962306a36Sopenharmony_ci if (pkt->one_reg_wr) { 139062306a36Sopenharmony_ci if ((reg >> 7) > n) { 139162306a36Sopenharmony_ci return -EINVAL; 139262306a36Sopenharmony_ci } 139362306a36Sopenharmony_ci } else { 139462306a36Sopenharmony_ci if (((reg + (pkt->count << 2)) >> 7) > n) { 139562306a36Sopenharmony_ci return -EINVAL; 139662306a36Sopenharmony_ci } 139762306a36Sopenharmony_ci } 139862306a36Sopenharmony_ci for (i = 0; i <= pkt->count; i++, idx++) { 139962306a36Sopenharmony_ci j = (reg >> 7); 140062306a36Sopenharmony_ci m = 1 << ((reg >> 2) & 31); 140162306a36Sopenharmony_ci if (auth[j] & m) { 140262306a36Sopenharmony_ci r = check(p, pkt, idx, reg); 140362306a36Sopenharmony_ci if (r) { 140462306a36Sopenharmony_ci return r; 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci } 140762306a36Sopenharmony_ci if (pkt->one_reg_wr) { 140862306a36Sopenharmony_ci if (!(auth[j] & m)) { 140962306a36Sopenharmony_ci break; 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci } else { 141262306a36Sopenharmony_ci reg += 4; 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci return 0; 141662306a36Sopenharmony_ci} 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci/** 141962306a36Sopenharmony_ci * r100_cs_packet_parse_vline() - parse userspace VLINE packet 142062306a36Sopenharmony_ci * @p: parser structure holding parsing context. 142162306a36Sopenharmony_ci * 142262306a36Sopenharmony_ci * Userspace sends a special sequence for VLINE waits. 142362306a36Sopenharmony_ci * PACKET0 - VLINE_START_END + value 142462306a36Sopenharmony_ci * PACKET0 - WAIT_UNTIL +_value 142562306a36Sopenharmony_ci * RELOC (P3) - crtc_id in reloc. 142662306a36Sopenharmony_ci * 142762306a36Sopenharmony_ci * This function parses this and relocates the VLINE START END 142862306a36Sopenharmony_ci * and WAIT UNTIL packets to the correct crtc. 142962306a36Sopenharmony_ci * It also detects a switched off crtc and nulls out the 143062306a36Sopenharmony_ci * wait in that case. 143162306a36Sopenharmony_ci */ 143262306a36Sopenharmony_ciint r100_cs_packet_parse_vline(struct radeon_cs_parser *p) 143362306a36Sopenharmony_ci{ 143462306a36Sopenharmony_ci struct drm_crtc *crtc; 143562306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc; 143662306a36Sopenharmony_ci struct radeon_cs_packet p3reloc, waitreloc; 143762306a36Sopenharmony_ci int crtc_id; 143862306a36Sopenharmony_ci int r; 143962306a36Sopenharmony_ci uint32_t header, h_idx, reg; 144062306a36Sopenharmony_ci volatile uint32_t *ib; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci ib = p->ib.ptr; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci /* parse the wait until */ 144562306a36Sopenharmony_ci r = radeon_cs_packet_parse(p, &waitreloc, p->idx); 144662306a36Sopenharmony_ci if (r) 144762306a36Sopenharmony_ci return r; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci /* check its a wait until and only 1 count */ 145062306a36Sopenharmony_ci if (waitreloc.reg != RADEON_WAIT_UNTIL || 145162306a36Sopenharmony_ci waitreloc.count != 0) { 145262306a36Sopenharmony_ci DRM_ERROR("vline wait had illegal wait until segment\n"); 145362306a36Sopenharmony_ci return -EINVAL; 145462306a36Sopenharmony_ci } 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci if (radeon_get_ib_value(p, waitreloc.idx + 1) != RADEON_WAIT_CRTC_VLINE) { 145762306a36Sopenharmony_ci DRM_ERROR("vline wait had illegal wait until\n"); 145862306a36Sopenharmony_ci return -EINVAL; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci /* jump over the NOP */ 146262306a36Sopenharmony_ci r = radeon_cs_packet_parse(p, &p3reloc, p->idx + waitreloc.count + 2); 146362306a36Sopenharmony_ci if (r) 146462306a36Sopenharmony_ci return r; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci h_idx = p->idx - 2; 146762306a36Sopenharmony_ci p->idx += waitreloc.count + 2; 146862306a36Sopenharmony_ci p->idx += p3reloc.count + 2; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci header = radeon_get_ib_value(p, h_idx); 147162306a36Sopenharmony_ci crtc_id = radeon_get_ib_value(p, h_idx + 5); 147262306a36Sopenharmony_ci reg = R100_CP_PACKET0_GET_REG(header); 147362306a36Sopenharmony_ci crtc = drm_crtc_find(p->rdev->ddev, p->filp, crtc_id); 147462306a36Sopenharmony_ci if (!crtc) { 147562306a36Sopenharmony_ci DRM_ERROR("cannot find crtc %d\n", crtc_id); 147662306a36Sopenharmony_ci return -ENOENT; 147762306a36Sopenharmony_ci } 147862306a36Sopenharmony_ci radeon_crtc = to_radeon_crtc(crtc); 147962306a36Sopenharmony_ci crtc_id = radeon_crtc->crtc_id; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci if (!crtc->enabled) { 148262306a36Sopenharmony_ci /* if the CRTC isn't enabled - we need to nop out the wait until */ 148362306a36Sopenharmony_ci ib[h_idx + 2] = PACKET2(0); 148462306a36Sopenharmony_ci ib[h_idx + 3] = PACKET2(0); 148562306a36Sopenharmony_ci } else if (crtc_id == 1) { 148662306a36Sopenharmony_ci switch (reg) { 148762306a36Sopenharmony_ci case AVIVO_D1MODE_VLINE_START_END: 148862306a36Sopenharmony_ci header &= ~R300_CP_PACKET0_REG_MASK; 148962306a36Sopenharmony_ci header |= AVIVO_D2MODE_VLINE_START_END >> 2; 149062306a36Sopenharmony_ci break; 149162306a36Sopenharmony_ci case RADEON_CRTC_GUI_TRIG_VLINE: 149262306a36Sopenharmony_ci header &= ~R300_CP_PACKET0_REG_MASK; 149362306a36Sopenharmony_ci header |= RADEON_CRTC2_GUI_TRIG_VLINE >> 2; 149462306a36Sopenharmony_ci break; 149562306a36Sopenharmony_ci default: 149662306a36Sopenharmony_ci DRM_ERROR("unknown crtc reloc\n"); 149762306a36Sopenharmony_ci return -EINVAL; 149862306a36Sopenharmony_ci } 149962306a36Sopenharmony_ci ib[h_idx] = header; 150062306a36Sopenharmony_ci ib[h_idx + 3] |= RADEON_ENG_DISPLAY_SELECT_CRTC1; 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci return 0; 150462306a36Sopenharmony_ci} 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_cistatic int r100_get_vtx_size(uint32_t vtx_fmt) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci int vtx_size; 150962306a36Sopenharmony_ci vtx_size = 2; 151062306a36Sopenharmony_ci /* ordered according to bits in spec */ 151162306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_W0) 151262306a36Sopenharmony_ci vtx_size++; 151362306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_FPCOLOR) 151462306a36Sopenharmony_ci vtx_size += 3; 151562306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_FPALPHA) 151662306a36Sopenharmony_ci vtx_size++; 151762306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_PKCOLOR) 151862306a36Sopenharmony_ci vtx_size++; 151962306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_FPSPEC) 152062306a36Sopenharmony_ci vtx_size += 3; 152162306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_FPFOG) 152262306a36Sopenharmony_ci vtx_size++; 152362306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_PKSPEC) 152462306a36Sopenharmony_ci vtx_size++; 152562306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_ST0) 152662306a36Sopenharmony_ci vtx_size += 2; 152762306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_ST1) 152862306a36Sopenharmony_ci vtx_size += 2; 152962306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_Q1) 153062306a36Sopenharmony_ci vtx_size++; 153162306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_ST2) 153262306a36Sopenharmony_ci vtx_size += 2; 153362306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_Q2) 153462306a36Sopenharmony_ci vtx_size++; 153562306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_ST3) 153662306a36Sopenharmony_ci vtx_size += 2; 153762306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_Q3) 153862306a36Sopenharmony_ci vtx_size++; 153962306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_Q0) 154062306a36Sopenharmony_ci vtx_size++; 154162306a36Sopenharmony_ci /* blend weight */ 154262306a36Sopenharmony_ci if (vtx_fmt & (0x7 << 15)) 154362306a36Sopenharmony_ci vtx_size += (vtx_fmt >> 15) & 0x7; 154462306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_N0) 154562306a36Sopenharmony_ci vtx_size += 3; 154662306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_XY1) 154762306a36Sopenharmony_ci vtx_size += 2; 154862306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_Z1) 154962306a36Sopenharmony_ci vtx_size++; 155062306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_W1) 155162306a36Sopenharmony_ci vtx_size++; 155262306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_N1) 155362306a36Sopenharmony_ci vtx_size++; 155462306a36Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_Z) 155562306a36Sopenharmony_ci vtx_size++; 155662306a36Sopenharmony_ci return vtx_size; 155762306a36Sopenharmony_ci} 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_cistatic int r100_packet0_check(struct radeon_cs_parser *p, 156062306a36Sopenharmony_ci struct radeon_cs_packet *pkt, 156162306a36Sopenharmony_ci unsigned idx, unsigned reg) 156262306a36Sopenharmony_ci{ 156362306a36Sopenharmony_ci struct radeon_bo_list *reloc; 156462306a36Sopenharmony_ci struct r100_cs_track *track; 156562306a36Sopenharmony_ci volatile uint32_t *ib; 156662306a36Sopenharmony_ci uint32_t tmp; 156762306a36Sopenharmony_ci int r; 156862306a36Sopenharmony_ci int i, face; 156962306a36Sopenharmony_ci u32 tile_flags = 0; 157062306a36Sopenharmony_ci u32 idx_value; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci ib = p->ib.ptr; 157362306a36Sopenharmony_ci track = (struct r100_cs_track *)p->track; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci idx_value = radeon_get_ib_value(p, idx); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci switch (reg) { 157862306a36Sopenharmony_ci case RADEON_CRTC_GUI_TRIG_VLINE: 157962306a36Sopenharmony_ci r = r100_cs_packet_parse_vline(p); 158062306a36Sopenharmony_ci if (r) { 158162306a36Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 158262306a36Sopenharmony_ci idx, reg); 158362306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 158462306a36Sopenharmony_ci return r; 158562306a36Sopenharmony_ci } 158662306a36Sopenharmony_ci break; 158762306a36Sopenharmony_ci /* FIXME: only allow PACKET3 blit? easier to check for out of 158862306a36Sopenharmony_ci * range access */ 158962306a36Sopenharmony_ci case RADEON_DST_PITCH_OFFSET: 159062306a36Sopenharmony_ci case RADEON_SRC_PITCH_OFFSET: 159162306a36Sopenharmony_ci r = r100_reloc_pitch_offset(p, pkt, idx, reg); 159262306a36Sopenharmony_ci if (r) 159362306a36Sopenharmony_ci return r; 159462306a36Sopenharmony_ci break; 159562306a36Sopenharmony_ci case RADEON_RB3D_DEPTHOFFSET: 159662306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 159762306a36Sopenharmony_ci if (r) { 159862306a36Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 159962306a36Sopenharmony_ci idx, reg); 160062306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 160162306a36Sopenharmony_ci return r; 160262306a36Sopenharmony_ci } 160362306a36Sopenharmony_ci track->zb.robj = reloc->robj; 160462306a36Sopenharmony_ci track->zb.offset = idx_value; 160562306a36Sopenharmony_ci track->zb_dirty = true; 160662306a36Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 160762306a36Sopenharmony_ci break; 160862306a36Sopenharmony_ci case RADEON_RB3D_COLOROFFSET: 160962306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 161062306a36Sopenharmony_ci if (r) { 161162306a36Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 161262306a36Sopenharmony_ci idx, reg); 161362306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 161462306a36Sopenharmony_ci return r; 161562306a36Sopenharmony_ci } 161662306a36Sopenharmony_ci track->cb[0].robj = reloc->robj; 161762306a36Sopenharmony_ci track->cb[0].offset = idx_value; 161862306a36Sopenharmony_ci track->cb_dirty = true; 161962306a36Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 162062306a36Sopenharmony_ci break; 162162306a36Sopenharmony_ci case RADEON_PP_TXOFFSET_0: 162262306a36Sopenharmony_ci case RADEON_PP_TXOFFSET_1: 162362306a36Sopenharmony_ci case RADEON_PP_TXOFFSET_2: 162462306a36Sopenharmony_ci i = (reg - RADEON_PP_TXOFFSET_0) / 24; 162562306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 162662306a36Sopenharmony_ci if (r) { 162762306a36Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 162862306a36Sopenharmony_ci idx, reg); 162962306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 163062306a36Sopenharmony_ci return r; 163162306a36Sopenharmony_ci } 163262306a36Sopenharmony_ci if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { 163362306a36Sopenharmony_ci if (reloc->tiling_flags & RADEON_TILING_MACRO) 163462306a36Sopenharmony_ci tile_flags |= RADEON_TXO_MACRO_TILE; 163562306a36Sopenharmony_ci if (reloc->tiling_flags & RADEON_TILING_MICRO) 163662306a36Sopenharmony_ci tile_flags |= RADEON_TXO_MICRO_TILE_X2; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci tmp = idx_value & ~(0x7 << 2); 163962306a36Sopenharmony_ci tmp |= tile_flags; 164062306a36Sopenharmony_ci ib[idx] = tmp + ((u32)reloc->gpu_offset); 164162306a36Sopenharmony_ci } else 164262306a36Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 164362306a36Sopenharmony_ci track->textures[i].robj = reloc->robj; 164462306a36Sopenharmony_ci track->tex_dirty = true; 164562306a36Sopenharmony_ci break; 164662306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T0_0: 164762306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T0_1: 164862306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T0_2: 164962306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T0_3: 165062306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T0_4: 165162306a36Sopenharmony_ci i = (reg - RADEON_PP_CUBIC_OFFSET_T0_0) / 4; 165262306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 165362306a36Sopenharmony_ci if (r) { 165462306a36Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 165562306a36Sopenharmony_ci idx, reg); 165662306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 165762306a36Sopenharmony_ci return r; 165862306a36Sopenharmony_ci } 165962306a36Sopenharmony_ci track->textures[0].cube_info[i].offset = idx_value; 166062306a36Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 166162306a36Sopenharmony_ci track->textures[0].cube_info[i].robj = reloc->robj; 166262306a36Sopenharmony_ci track->tex_dirty = true; 166362306a36Sopenharmony_ci break; 166462306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T1_0: 166562306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T1_1: 166662306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T1_2: 166762306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T1_3: 166862306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T1_4: 166962306a36Sopenharmony_ci i = (reg - RADEON_PP_CUBIC_OFFSET_T1_0) / 4; 167062306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 167162306a36Sopenharmony_ci if (r) { 167262306a36Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 167362306a36Sopenharmony_ci idx, reg); 167462306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 167562306a36Sopenharmony_ci return r; 167662306a36Sopenharmony_ci } 167762306a36Sopenharmony_ci track->textures[1].cube_info[i].offset = idx_value; 167862306a36Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 167962306a36Sopenharmony_ci track->textures[1].cube_info[i].robj = reloc->robj; 168062306a36Sopenharmony_ci track->tex_dirty = true; 168162306a36Sopenharmony_ci break; 168262306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T2_0: 168362306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T2_1: 168462306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T2_2: 168562306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T2_3: 168662306a36Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T2_4: 168762306a36Sopenharmony_ci i = (reg - RADEON_PP_CUBIC_OFFSET_T2_0) / 4; 168862306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 168962306a36Sopenharmony_ci if (r) { 169062306a36Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 169162306a36Sopenharmony_ci idx, reg); 169262306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 169362306a36Sopenharmony_ci return r; 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci track->textures[2].cube_info[i].offset = idx_value; 169662306a36Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 169762306a36Sopenharmony_ci track->textures[2].cube_info[i].robj = reloc->robj; 169862306a36Sopenharmony_ci track->tex_dirty = true; 169962306a36Sopenharmony_ci break; 170062306a36Sopenharmony_ci case RADEON_RE_WIDTH_HEIGHT: 170162306a36Sopenharmony_ci track->maxy = ((idx_value >> 16) & 0x7FF); 170262306a36Sopenharmony_ci track->cb_dirty = true; 170362306a36Sopenharmony_ci track->zb_dirty = true; 170462306a36Sopenharmony_ci break; 170562306a36Sopenharmony_ci case RADEON_RB3D_COLORPITCH: 170662306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 170762306a36Sopenharmony_ci if (r) { 170862306a36Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 170962306a36Sopenharmony_ci idx, reg); 171062306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 171162306a36Sopenharmony_ci return r; 171262306a36Sopenharmony_ci } 171362306a36Sopenharmony_ci if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { 171462306a36Sopenharmony_ci if (reloc->tiling_flags & RADEON_TILING_MACRO) 171562306a36Sopenharmony_ci tile_flags |= RADEON_COLOR_TILE_ENABLE; 171662306a36Sopenharmony_ci if (reloc->tiling_flags & RADEON_TILING_MICRO) 171762306a36Sopenharmony_ci tile_flags |= RADEON_COLOR_MICROTILE_ENABLE; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci tmp = idx_value & ~(0x7 << 16); 172062306a36Sopenharmony_ci tmp |= tile_flags; 172162306a36Sopenharmony_ci ib[idx] = tmp; 172262306a36Sopenharmony_ci } else 172362306a36Sopenharmony_ci ib[idx] = idx_value; 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci track->cb[0].pitch = idx_value & RADEON_COLORPITCH_MASK; 172662306a36Sopenharmony_ci track->cb_dirty = true; 172762306a36Sopenharmony_ci break; 172862306a36Sopenharmony_ci case RADEON_RB3D_DEPTHPITCH: 172962306a36Sopenharmony_ci track->zb.pitch = idx_value & RADEON_DEPTHPITCH_MASK; 173062306a36Sopenharmony_ci track->zb_dirty = true; 173162306a36Sopenharmony_ci break; 173262306a36Sopenharmony_ci case RADEON_RB3D_CNTL: 173362306a36Sopenharmony_ci switch ((idx_value >> RADEON_RB3D_COLOR_FORMAT_SHIFT) & 0x1f) { 173462306a36Sopenharmony_ci case 7: 173562306a36Sopenharmony_ci case 8: 173662306a36Sopenharmony_ci case 9: 173762306a36Sopenharmony_ci case 11: 173862306a36Sopenharmony_ci case 12: 173962306a36Sopenharmony_ci track->cb[0].cpp = 1; 174062306a36Sopenharmony_ci break; 174162306a36Sopenharmony_ci case 3: 174262306a36Sopenharmony_ci case 4: 174362306a36Sopenharmony_ci case 15: 174462306a36Sopenharmony_ci track->cb[0].cpp = 2; 174562306a36Sopenharmony_ci break; 174662306a36Sopenharmony_ci case 6: 174762306a36Sopenharmony_ci track->cb[0].cpp = 4; 174862306a36Sopenharmony_ci break; 174962306a36Sopenharmony_ci default: 175062306a36Sopenharmony_ci DRM_ERROR("Invalid color buffer format (%d) !\n", 175162306a36Sopenharmony_ci ((idx_value >> RADEON_RB3D_COLOR_FORMAT_SHIFT) & 0x1f)); 175262306a36Sopenharmony_ci return -EINVAL; 175362306a36Sopenharmony_ci } 175462306a36Sopenharmony_ci track->z_enabled = !!(idx_value & RADEON_Z_ENABLE); 175562306a36Sopenharmony_ci track->cb_dirty = true; 175662306a36Sopenharmony_ci track->zb_dirty = true; 175762306a36Sopenharmony_ci break; 175862306a36Sopenharmony_ci case RADEON_RB3D_ZSTENCILCNTL: 175962306a36Sopenharmony_ci switch (idx_value & 0xf) { 176062306a36Sopenharmony_ci case 0: 176162306a36Sopenharmony_ci track->zb.cpp = 2; 176262306a36Sopenharmony_ci break; 176362306a36Sopenharmony_ci case 2: 176462306a36Sopenharmony_ci case 3: 176562306a36Sopenharmony_ci case 4: 176662306a36Sopenharmony_ci case 5: 176762306a36Sopenharmony_ci case 9: 176862306a36Sopenharmony_ci case 11: 176962306a36Sopenharmony_ci track->zb.cpp = 4; 177062306a36Sopenharmony_ci break; 177162306a36Sopenharmony_ci default: 177262306a36Sopenharmony_ci break; 177362306a36Sopenharmony_ci } 177462306a36Sopenharmony_ci track->zb_dirty = true; 177562306a36Sopenharmony_ci break; 177662306a36Sopenharmony_ci case RADEON_RB3D_ZPASS_ADDR: 177762306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 177862306a36Sopenharmony_ci if (r) { 177962306a36Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 178062306a36Sopenharmony_ci idx, reg); 178162306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 178262306a36Sopenharmony_ci return r; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 178562306a36Sopenharmony_ci break; 178662306a36Sopenharmony_ci case RADEON_PP_CNTL: 178762306a36Sopenharmony_ci { 178862306a36Sopenharmony_ci uint32_t temp = idx_value >> 4; 178962306a36Sopenharmony_ci for (i = 0; i < track->num_texture; i++) 179062306a36Sopenharmony_ci track->textures[i].enabled = !!(temp & (1 << i)); 179162306a36Sopenharmony_ci track->tex_dirty = true; 179262306a36Sopenharmony_ci } 179362306a36Sopenharmony_ci break; 179462306a36Sopenharmony_ci case RADEON_SE_VF_CNTL: 179562306a36Sopenharmony_ci track->vap_vf_cntl = idx_value; 179662306a36Sopenharmony_ci break; 179762306a36Sopenharmony_ci case RADEON_SE_VTX_FMT: 179862306a36Sopenharmony_ci track->vtx_size = r100_get_vtx_size(idx_value); 179962306a36Sopenharmony_ci break; 180062306a36Sopenharmony_ci case RADEON_PP_TEX_SIZE_0: 180162306a36Sopenharmony_ci case RADEON_PP_TEX_SIZE_1: 180262306a36Sopenharmony_ci case RADEON_PP_TEX_SIZE_2: 180362306a36Sopenharmony_ci i = (reg - RADEON_PP_TEX_SIZE_0) / 8; 180462306a36Sopenharmony_ci track->textures[i].width = (idx_value & RADEON_TEX_USIZE_MASK) + 1; 180562306a36Sopenharmony_ci track->textures[i].height = ((idx_value & RADEON_TEX_VSIZE_MASK) >> RADEON_TEX_VSIZE_SHIFT) + 1; 180662306a36Sopenharmony_ci track->tex_dirty = true; 180762306a36Sopenharmony_ci break; 180862306a36Sopenharmony_ci case RADEON_PP_TEX_PITCH_0: 180962306a36Sopenharmony_ci case RADEON_PP_TEX_PITCH_1: 181062306a36Sopenharmony_ci case RADEON_PP_TEX_PITCH_2: 181162306a36Sopenharmony_ci i = (reg - RADEON_PP_TEX_PITCH_0) / 8; 181262306a36Sopenharmony_ci track->textures[i].pitch = idx_value + 32; 181362306a36Sopenharmony_ci track->tex_dirty = true; 181462306a36Sopenharmony_ci break; 181562306a36Sopenharmony_ci case RADEON_PP_TXFILTER_0: 181662306a36Sopenharmony_ci case RADEON_PP_TXFILTER_1: 181762306a36Sopenharmony_ci case RADEON_PP_TXFILTER_2: 181862306a36Sopenharmony_ci i = (reg - RADEON_PP_TXFILTER_0) / 24; 181962306a36Sopenharmony_ci track->textures[i].num_levels = ((idx_value & RADEON_MAX_MIP_LEVEL_MASK) 182062306a36Sopenharmony_ci >> RADEON_MAX_MIP_LEVEL_SHIFT); 182162306a36Sopenharmony_ci tmp = (idx_value >> 23) & 0x7; 182262306a36Sopenharmony_ci if (tmp == 2 || tmp == 6) 182362306a36Sopenharmony_ci track->textures[i].roundup_w = false; 182462306a36Sopenharmony_ci tmp = (idx_value >> 27) & 0x7; 182562306a36Sopenharmony_ci if (tmp == 2 || tmp == 6) 182662306a36Sopenharmony_ci track->textures[i].roundup_h = false; 182762306a36Sopenharmony_ci track->tex_dirty = true; 182862306a36Sopenharmony_ci break; 182962306a36Sopenharmony_ci case RADEON_PP_TXFORMAT_0: 183062306a36Sopenharmony_ci case RADEON_PP_TXFORMAT_1: 183162306a36Sopenharmony_ci case RADEON_PP_TXFORMAT_2: 183262306a36Sopenharmony_ci i = (reg - RADEON_PP_TXFORMAT_0) / 24; 183362306a36Sopenharmony_ci if (idx_value & RADEON_TXFORMAT_NON_POWER2) { 183462306a36Sopenharmony_ci track->textures[i].use_pitch = true; 183562306a36Sopenharmony_ci } else { 183662306a36Sopenharmony_ci track->textures[i].use_pitch = false; 183762306a36Sopenharmony_ci track->textures[i].width = 1 << ((idx_value & RADEON_TXFORMAT_WIDTH_MASK) >> RADEON_TXFORMAT_WIDTH_SHIFT); 183862306a36Sopenharmony_ci track->textures[i].height = 1 << ((idx_value & RADEON_TXFORMAT_HEIGHT_MASK) >> RADEON_TXFORMAT_HEIGHT_SHIFT); 183962306a36Sopenharmony_ci } 184062306a36Sopenharmony_ci if (idx_value & RADEON_TXFORMAT_CUBIC_MAP_ENABLE) 184162306a36Sopenharmony_ci track->textures[i].tex_coord_type = 2; 184262306a36Sopenharmony_ci switch ((idx_value & RADEON_TXFORMAT_FORMAT_MASK)) { 184362306a36Sopenharmony_ci case RADEON_TXFORMAT_I8: 184462306a36Sopenharmony_ci case RADEON_TXFORMAT_RGB332: 184562306a36Sopenharmony_ci case RADEON_TXFORMAT_Y8: 184662306a36Sopenharmony_ci track->textures[i].cpp = 1; 184762306a36Sopenharmony_ci track->textures[i].compress_format = R100_TRACK_COMP_NONE; 184862306a36Sopenharmony_ci break; 184962306a36Sopenharmony_ci case RADEON_TXFORMAT_AI88: 185062306a36Sopenharmony_ci case RADEON_TXFORMAT_ARGB1555: 185162306a36Sopenharmony_ci case RADEON_TXFORMAT_RGB565: 185262306a36Sopenharmony_ci case RADEON_TXFORMAT_ARGB4444: 185362306a36Sopenharmony_ci case RADEON_TXFORMAT_VYUY422: 185462306a36Sopenharmony_ci case RADEON_TXFORMAT_YVYU422: 185562306a36Sopenharmony_ci case RADEON_TXFORMAT_SHADOW16: 185662306a36Sopenharmony_ci case RADEON_TXFORMAT_LDUDV655: 185762306a36Sopenharmony_ci case RADEON_TXFORMAT_DUDV88: 185862306a36Sopenharmony_ci track->textures[i].cpp = 2; 185962306a36Sopenharmony_ci track->textures[i].compress_format = R100_TRACK_COMP_NONE; 186062306a36Sopenharmony_ci break; 186162306a36Sopenharmony_ci case RADEON_TXFORMAT_ARGB8888: 186262306a36Sopenharmony_ci case RADEON_TXFORMAT_RGBA8888: 186362306a36Sopenharmony_ci case RADEON_TXFORMAT_SHADOW32: 186462306a36Sopenharmony_ci case RADEON_TXFORMAT_LDUDUV8888: 186562306a36Sopenharmony_ci track->textures[i].cpp = 4; 186662306a36Sopenharmony_ci track->textures[i].compress_format = R100_TRACK_COMP_NONE; 186762306a36Sopenharmony_ci break; 186862306a36Sopenharmony_ci case RADEON_TXFORMAT_DXT1: 186962306a36Sopenharmony_ci track->textures[i].cpp = 1; 187062306a36Sopenharmony_ci track->textures[i].compress_format = R100_TRACK_COMP_DXT1; 187162306a36Sopenharmony_ci break; 187262306a36Sopenharmony_ci case RADEON_TXFORMAT_DXT23: 187362306a36Sopenharmony_ci case RADEON_TXFORMAT_DXT45: 187462306a36Sopenharmony_ci track->textures[i].cpp = 1; 187562306a36Sopenharmony_ci track->textures[i].compress_format = R100_TRACK_COMP_DXT35; 187662306a36Sopenharmony_ci break; 187762306a36Sopenharmony_ci } 187862306a36Sopenharmony_ci track->textures[i].cube_info[4].width = 1 << ((idx_value >> 16) & 0xf); 187962306a36Sopenharmony_ci track->textures[i].cube_info[4].height = 1 << ((idx_value >> 20) & 0xf); 188062306a36Sopenharmony_ci track->tex_dirty = true; 188162306a36Sopenharmony_ci break; 188262306a36Sopenharmony_ci case RADEON_PP_CUBIC_FACES_0: 188362306a36Sopenharmony_ci case RADEON_PP_CUBIC_FACES_1: 188462306a36Sopenharmony_ci case RADEON_PP_CUBIC_FACES_2: 188562306a36Sopenharmony_ci tmp = idx_value; 188662306a36Sopenharmony_ci i = (reg - RADEON_PP_CUBIC_FACES_0) / 4; 188762306a36Sopenharmony_ci for (face = 0; face < 4; face++) { 188862306a36Sopenharmony_ci track->textures[i].cube_info[face].width = 1 << ((tmp >> (face * 8)) & 0xf); 188962306a36Sopenharmony_ci track->textures[i].cube_info[face].height = 1 << ((tmp >> ((face * 8) + 4)) & 0xf); 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci track->tex_dirty = true; 189262306a36Sopenharmony_ci break; 189362306a36Sopenharmony_ci default: 189462306a36Sopenharmony_ci pr_err("Forbidden register 0x%04X in cs at %d\n", reg, idx); 189562306a36Sopenharmony_ci return -EINVAL; 189662306a36Sopenharmony_ci } 189762306a36Sopenharmony_ci return 0; 189862306a36Sopenharmony_ci} 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ciint r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p, 190162306a36Sopenharmony_ci struct radeon_cs_packet *pkt, 190262306a36Sopenharmony_ci struct radeon_bo *robj) 190362306a36Sopenharmony_ci{ 190462306a36Sopenharmony_ci unsigned idx; 190562306a36Sopenharmony_ci u32 value; 190662306a36Sopenharmony_ci idx = pkt->idx + 1; 190762306a36Sopenharmony_ci value = radeon_get_ib_value(p, idx + 2); 190862306a36Sopenharmony_ci if ((value + 1) > radeon_bo_size(robj)) { 190962306a36Sopenharmony_ci DRM_ERROR("[drm] Buffer too small for PACKET3 INDX_BUFFER " 191062306a36Sopenharmony_ci "(need %u have %lu) !\n", 191162306a36Sopenharmony_ci value + 1, 191262306a36Sopenharmony_ci radeon_bo_size(robj)); 191362306a36Sopenharmony_ci return -EINVAL; 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci return 0; 191662306a36Sopenharmony_ci} 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_cistatic int r100_packet3_check(struct radeon_cs_parser *p, 191962306a36Sopenharmony_ci struct radeon_cs_packet *pkt) 192062306a36Sopenharmony_ci{ 192162306a36Sopenharmony_ci struct radeon_bo_list *reloc; 192262306a36Sopenharmony_ci struct r100_cs_track *track; 192362306a36Sopenharmony_ci unsigned idx; 192462306a36Sopenharmony_ci volatile uint32_t *ib; 192562306a36Sopenharmony_ci int r; 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci ib = p->ib.ptr; 192862306a36Sopenharmony_ci idx = pkt->idx + 1; 192962306a36Sopenharmony_ci track = (struct r100_cs_track *)p->track; 193062306a36Sopenharmony_ci switch (pkt->opcode) { 193162306a36Sopenharmony_ci case PACKET3_3D_LOAD_VBPNTR: 193262306a36Sopenharmony_ci r = r100_packet3_load_vbpntr(p, pkt, idx); 193362306a36Sopenharmony_ci if (r) 193462306a36Sopenharmony_ci return r; 193562306a36Sopenharmony_ci break; 193662306a36Sopenharmony_ci case PACKET3_INDX_BUFFER: 193762306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 193862306a36Sopenharmony_ci if (r) { 193962306a36Sopenharmony_ci DRM_ERROR("No reloc for packet3 %d\n", pkt->opcode); 194062306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 194162306a36Sopenharmony_ci return r; 194262306a36Sopenharmony_ci } 194362306a36Sopenharmony_ci ib[idx+1] = radeon_get_ib_value(p, idx+1) + ((u32)reloc->gpu_offset); 194462306a36Sopenharmony_ci r = r100_cs_track_check_pkt3_indx_buffer(p, pkt, reloc->robj); 194562306a36Sopenharmony_ci if (r) { 194662306a36Sopenharmony_ci return r; 194762306a36Sopenharmony_ci } 194862306a36Sopenharmony_ci break; 194962306a36Sopenharmony_ci case 0x23: 195062306a36Sopenharmony_ci /* 3D_RNDR_GEN_INDX_PRIM on r100/r200 */ 195162306a36Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 195262306a36Sopenharmony_ci if (r) { 195362306a36Sopenharmony_ci DRM_ERROR("No reloc for packet3 %d\n", pkt->opcode); 195462306a36Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 195562306a36Sopenharmony_ci return r; 195662306a36Sopenharmony_ci } 195762306a36Sopenharmony_ci ib[idx] = radeon_get_ib_value(p, idx) + ((u32)reloc->gpu_offset); 195862306a36Sopenharmony_ci track->num_arrays = 1; 195962306a36Sopenharmony_ci track->vtx_size = r100_get_vtx_size(radeon_get_ib_value(p, idx + 2)); 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci track->arrays[0].robj = reloc->robj; 196262306a36Sopenharmony_ci track->arrays[0].esize = track->vtx_size; 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci track->max_indx = radeon_get_ib_value(p, idx+1); 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx+3); 196762306a36Sopenharmony_ci track->immd_dwords = pkt->count - 1; 196862306a36Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 196962306a36Sopenharmony_ci if (r) 197062306a36Sopenharmony_ci return r; 197162306a36Sopenharmony_ci break; 197262306a36Sopenharmony_ci case PACKET3_3D_DRAW_IMMD: 197362306a36Sopenharmony_ci if (((radeon_get_ib_value(p, idx + 1) >> 4) & 0x3) != 3) { 197462306a36Sopenharmony_ci DRM_ERROR("PRIM_WALK must be 3 for IMMD draw\n"); 197562306a36Sopenharmony_ci return -EINVAL; 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci track->vtx_size = r100_get_vtx_size(radeon_get_ib_value(p, idx + 0)); 197862306a36Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx + 1); 197962306a36Sopenharmony_ci track->immd_dwords = pkt->count - 1; 198062306a36Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 198162306a36Sopenharmony_ci if (r) 198262306a36Sopenharmony_ci return r; 198362306a36Sopenharmony_ci break; 198462306a36Sopenharmony_ci /* triggers drawing using in-packet vertex data */ 198562306a36Sopenharmony_ci case PACKET3_3D_DRAW_IMMD_2: 198662306a36Sopenharmony_ci if (((radeon_get_ib_value(p, idx) >> 4) & 0x3) != 3) { 198762306a36Sopenharmony_ci DRM_ERROR("PRIM_WALK must be 3 for IMMD draw\n"); 198862306a36Sopenharmony_ci return -EINVAL; 198962306a36Sopenharmony_ci } 199062306a36Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx); 199162306a36Sopenharmony_ci track->immd_dwords = pkt->count; 199262306a36Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 199362306a36Sopenharmony_ci if (r) 199462306a36Sopenharmony_ci return r; 199562306a36Sopenharmony_ci break; 199662306a36Sopenharmony_ci /* triggers drawing using in-packet vertex data */ 199762306a36Sopenharmony_ci case PACKET3_3D_DRAW_VBUF_2: 199862306a36Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx); 199962306a36Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 200062306a36Sopenharmony_ci if (r) 200162306a36Sopenharmony_ci return r; 200262306a36Sopenharmony_ci break; 200362306a36Sopenharmony_ci /* triggers drawing of vertex buffers setup elsewhere */ 200462306a36Sopenharmony_ci case PACKET3_3D_DRAW_INDX_2: 200562306a36Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx); 200662306a36Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 200762306a36Sopenharmony_ci if (r) 200862306a36Sopenharmony_ci return r; 200962306a36Sopenharmony_ci break; 201062306a36Sopenharmony_ci /* triggers drawing using indices to vertex buffer */ 201162306a36Sopenharmony_ci case PACKET3_3D_DRAW_VBUF: 201262306a36Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx + 1); 201362306a36Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 201462306a36Sopenharmony_ci if (r) 201562306a36Sopenharmony_ci return r; 201662306a36Sopenharmony_ci break; 201762306a36Sopenharmony_ci /* triggers drawing of vertex buffers setup elsewhere */ 201862306a36Sopenharmony_ci case PACKET3_3D_DRAW_INDX: 201962306a36Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx + 1); 202062306a36Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 202162306a36Sopenharmony_ci if (r) 202262306a36Sopenharmony_ci return r; 202362306a36Sopenharmony_ci break; 202462306a36Sopenharmony_ci /* triggers drawing using indices to vertex buffer */ 202562306a36Sopenharmony_ci case PACKET3_3D_CLEAR_HIZ: 202662306a36Sopenharmony_ci case PACKET3_3D_CLEAR_ZMASK: 202762306a36Sopenharmony_ci if (p->rdev->hyperz_filp != p->filp) 202862306a36Sopenharmony_ci return -EINVAL; 202962306a36Sopenharmony_ci break; 203062306a36Sopenharmony_ci case PACKET3_NOP: 203162306a36Sopenharmony_ci break; 203262306a36Sopenharmony_ci default: 203362306a36Sopenharmony_ci DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode); 203462306a36Sopenharmony_ci return -EINVAL; 203562306a36Sopenharmony_ci } 203662306a36Sopenharmony_ci return 0; 203762306a36Sopenharmony_ci} 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ciint r100_cs_parse(struct radeon_cs_parser *p) 204062306a36Sopenharmony_ci{ 204162306a36Sopenharmony_ci struct radeon_cs_packet pkt; 204262306a36Sopenharmony_ci struct r100_cs_track *track; 204362306a36Sopenharmony_ci int r; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci track = kzalloc(sizeof(*track), GFP_KERNEL); 204662306a36Sopenharmony_ci if (!track) 204762306a36Sopenharmony_ci return -ENOMEM; 204862306a36Sopenharmony_ci r100_cs_track_clear(p->rdev, track); 204962306a36Sopenharmony_ci p->track = track; 205062306a36Sopenharmony_ci do { 205162306a36Sopenharmony_ci r = radeon_cs_packet_parse(p, &pkt, p->idx); 205262306a36Sopenharmony_ci if (r) { 205362306a36Sopenharmony_ci return r; 205462306a36Sopenharmony_ci } 205562306a36Sopenharmony_ci p->idx += pkt.count + 2; 205662306a36Sopenharmony_ci switch (pkt.type) { 205762306a36Sopenharmony_ci case RADEON_PACKET_TYPE0: 205862306a36Sopenharmony_ci if (p->rdev->family >= CHIP_R200) 205962306a36Sopenharmony_ci r = r100_cs_parse_packet0(p, &pkt, 206062306a36Sopenharmony_ci p->rdev->config.r100.reg_safe_bm, 206162306a36Sopenharmony_ci p->rdev->config.r100.reg_safe_bm_size, 206262306a36Sopenharmony_ci &r200_packet0_check); 206362306a36Sopenharmony_ci else 206462306a36Sopenharmony_ci r = r100_cs_parse_packet0(p, &pkt, 206562306a36Sopenharmony_ci p->rdev->config.r100.reg_safe_bm, 206662306a36Sopenharmony_ci p->rdev->config.r100.reg_safe_bm_size, 206762306a36Sopenharmony_ci &r100_packet0_check); 206862306a36Sopenharmony_ci break; 206962306a36Sopenharmony_ci case RADEON_PACKET_TYPE2: 207062306a36Sopenharmony_ci break; 207162306a36Sopenharmony_ci case RADEON_PACKET_TYPE3: 207262306a36Sopenharmony_ci r = r100_packet3_check(p, &pkt); 207362306a36Sopenharmony_ci break; 207462306a36Sopenharmony_ci default: 207562306a36Sopenharmony_ci DRM_ERROR("Unknown packet type %d !\n", 207662306a36Sopenharmony_ci pkt.type); 207762306a36Sopenharmony_ci return -EINVAL; 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci if (r) 208062306a36Sopenharmony_ci return r; 208162306a36Sopenharmony_ci } while (p->idx < p->chunk_ib->length_dw); 208262306a36Sopenharmony_ci return 0; 208362306a36Sopenharmony_ci} 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_cistatic void r100_cs_track_texture_print(struct r100_cs_track_texture *t) 208662306a36Sopenharmony_ci{ 208762306a36Sopenharmony_ci DRM_ERROR("pitch %d\n", t->pitch); 208862306a36Sopenharmony_ci DRM_ERROR("use_pitch %d\n", t->use_pitch); 208962306a36Sopenharmony_ci DRM_ERROR("width %d\n", t->width); 209062306a36Sopenharmony_ci DRM_ERROR("width_11 %d\n", t->width_11); 209162306a36Sopenharmony_ci DRM_ERROR("height %d\n", t->height); 209262306a36Sopenharmony_ci DRM_ERROR("height_11 %d\n", t->height_11); 209362306a36Sopenharmony_ci DRM_ERROR("num levels %d\n", t->num_levels); 209462306a36Sopenharmony_ci DRM_ERROR("depth %d\n", t->txdepth); 209562306a36Sopenharmony_ci DRM_ERROR("bpp %d\n", t->cpp); 209662306a36Sopenharmony_ci DRM_ERROR("coordinate type %d\n", t->tex_coord_type); 209762306a36Sopenharmony_ci DRM_ERROR("width round to power of 2 %d\n", t->roundup_w); 209862306a36Sopenharmony_ci DRM_ERROR("height round to power of 2 %d\n", t->roundup_h); 209962306a36Sopenharmony_ci DRM_ERROR("compress format %d\n", t->compress_format); 210062306a36Sopenharmony_ci} 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_cistatic int r100_track_compress_size(int compress_format, int w, int h) 210362306a36Sopenharmony_ci{ 210462306a36Sopenharmony_ci int block_width, block_height, block_bytes; 210562306a36Sopenharmony_ci int wblocks, hblocks; 210662306a36Sopenharmony_ci int min_wblocks; 210762306a36Sopenharmony_ci int sz; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci block_width = 4; 211062306a36Sopenharmony_ci block_height = 4; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci switch (compress_format) { 211362306a36Sopenharmony_ci case R100_TRACK_COMP_DXT1: 211462306a36Sopenharmony_ci block_bytes = 8; 211562306a36Sopenharmony_ci min_wblocks = 4; 211662306a36Sopenharmony_ci break; 211762306a36Sopenharmony_ci default: 211862306a36Sopenharmony_ci case R100_TRACK_COMP_DXT35: 211962306a36Sopenharmony_ci block_bytes = 16; 212062306a36Sopenharmony_ci min_wblocks = 2; 212162306a36Sopenharmony_ci break; 212262306a36Sopenharmony_ci } 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci hblocks = (h + block_height - 1) / block_height; 212562306a36Sopenharmony_ci wblocks = (w + block_width - 1) / block_width; 212662306a36Sopenharmony_ci if (wblocks < min_wblocks) 212762306a36Sopenharmony_ci wblocks = min_wblocks; 212862306a36Sopenharmony_ci sz = wblocks * hblocks * block_bytes; 212962306a36Sopenharmony_ci return sz; 213062306a36Sopenharmony_ci} 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_cistatic int r100_cs_track_cube(struct radeon_device *rdev, 213362306a36Sopenharmony_ci struct r100_cs_track *track, unsigned idx) 213462306a36Sopenharmony_ci{ 213562306a36Sopenharmony_ci unsigned face, w, h; 213662306a36Sopenharmony_ci struct radeon_bo *cube_robj; 213762306a36Sopenharmony_ci unsigned long size; 213862306a36Sopenharmony_ci unsigned compress_format = track->textures[idx].compress_format; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci for (face = 0; face < 5; face++) { 214162306a36Sopenharmony_ci cube_robj = track->textures[idx].cube_info[face].robj; 214262306a36Sopenharmony_ci w = track->textures[idx].cube_info[face].width; 214362306a36Sopenharmony_ci h = track->textures[idx].cube_info[face].height; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci if (compress_format) { 214662306a36Sopenharmony_ci size = r100_track_compress_size(compress_format, w, h); 214762306a36Sopenharmony_ci } else 214862306a36Sopenharmony_ci size = w * h; 214962306a36Sopenharmony_ci size *= track->textures[idx].cpp; 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci size += track->textures[idx].cube_info[face].offset; 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_ci if (size > radeon_bo_size(cube_robj)) { 215462306a36Sopenharmony_ci DRM_ERROR("Cube texture offset greater than object size %lu %lu\n", 215562306a36Sopenharmony_ci size, radeon_bo_size(cube_robj)); 215662306a36Sopenharmony_ci r100_cs_track_texture_print(&track->textures[idx]); 215762306a36Sopenharmony_ci return -1; 215862306a36Sopenharmony_ci } 215962306a36Sopenharmony_ci } 216062306a36Sopenharmony_ci return 0; 216162306a36Sopenharmony_ci} 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_cistatic int r100_cs_track_texture_check(struct radeon_device *rdev, 216462306a36Sopenharmony_ci struct r100_cs_track *track) 216562306a36Sopenharmony_ci{ 216662306a36Sopenharmony_ci struct radeon_bo *robj; 216762306a36Sopenharmony_ci unsigned long size; 216862306a36Sopenharmony_ci unsigned u, i, w, h, d; 216962306a36Sopenharmony_ci int ret; 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci for (u = 0; u < track->num_texture; u++) { 217262306a36Sopenharmony_ci if (!track->textures[u].enabled) 217362306a36Sopenharmony_ci continue; 217462306a36Sopenharmony_ci if (track->textures[u].lookup_disable) 217562306a36Sopenharmony_ci continue; 217662306a36Sopenharmony_ci robj = track->textures[u].robj; 217762306a36Sopenharmony_ci if (robj == NULL) { 217862306a36Sopenharmony_ci DRM_ERROR("No texture bound to unit %u\n", u); 217962306a36Sopenharmony_ci return -EINVAL; 218062306a36Sopenharmony_ci } 218162306a36Sopenharmony_ci size = 0; 218262306a36Sopenharmony_ci for (i = 0; i <= track->textures[u].num_levels; i++) { 218362306a36Sopenharmony_ci if (track->textures[u].use_pitch) { 218462306a36Sopenharmony_ci if (rdev->family < CHIP_R300) 218562306a36Sopenharmony_ci w = (track->textures[u].pitch / track->textures[u].cpp) / (1 << i); 218662306a36Sopenharmony_ci else 218762306a36Sopenharmony_ci w = track->textures[u].pitch / (1 << i); 218862306a36Sopenharmony_ci } else { 218962306a36Sopenharmony_ci w = track->textures[u].width; 219062306a36Sopenharmony_ci if (rdev->family >= CHIP_RV515) 219162306a36Sopenharmony_ci w |= track->textures[u].width_11; 219262306a36Sopenharmony_ci w = w / (1 << i); 219362306a36Sopenharmony_ci if (track->textures[u].roundup_w) 219462306a36Sopenharmony_ci w = roundup_pow_of_two(w); 219562306a36Sopenharmony_ci } 219662306a36Sopenharmony_ci h = track->textures[u].height; 219762306a36Sopenharmony_ci if (rdev->family >= CHIP_RV515) 219862306a36Sopenharmony_ci h |= track->textures[u].height_11; 219962306a36Sopenharmony_ci h = h / (1 << i); 220062306a36Sopenharmony_ci if (track->textures[u].roundup_h) 220162306a36Sopenharmony_ci h = roundup_pow_of_two(h); 220262306a36Sopenharmony_ci if (track->textures[u].tex_coord_type == 1) { 220362306a36Sopenharmony_ci d = (1 << track->textures[u].txdepth) / (1 << i); 220462306a36Sopenharmony_ci if (!d) 220562306a36Sopenharmony_ci d = 1; 220662306a36Sopenharmony_ci } else { 220762306a36Sopenharmony_ci d = 1; 220862306a36Sopenharmony_ci } 220962306a36Sopenharmony_ci if (track->textures[u].compress_format) { 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci size += r100_track_compress_size(track->textures[u].compress_format, w, h) * d; 221262306a36Sopenharmony_ci /* compressed textures are block based */ 221362306a36Sopenharmony_ci } else 221462306a36Sopenharmony_ci size += w * h * d; 221562306a36Sopenharmony_ci } 221662306a36Sopenharmony_ci size *= track->textures[u].cpp; 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci switch (track->textures[u].tex_coord_type) { 221962306a36Sopenharmony_ci case 0: 222062306a36Sopenharmony_ci case 1: 222162306a36Sopenharmony_ci break; 222262306a36Sopenharmony_ci case 2: 222362306a36Sopenharmony_ci if (track->separate_cube) { 222462306a36Sopenharmony_ci ret = r100_cs_track_cube(rdev, track, u); 222562306a36Sopenharmony_ci if (ret) 222662306a36Sopenharmony_ci return ret; 222762306a36Sopenharmony_ci } else 222862306a36Sopenharmony_ci size *= 6; 222962306a36Sopenharmony_ci break; 223062306a36Sopenharmony_ci default: 223162306a36Sopenharmony_ci DRM_ERROR("Invalid texture coordinate type %u for unit " 223262306a36Sopenharmony_ci "%u\n", track->textures[u].tex_coord_type, u); 223362306a36Sopenharmony_ci return -EINVAL; 223462306a36Sopenharmony_ci } 223562306a36Sopenharmony_ci if (size > radeon_bo_size(robj)) { 223662306a36Sopenharmony_ci DRM_ERROR("Texture of unit %u needs %lu bytes but is " 223762306a36Sopenharmony_ci "%lu\n", u, size, radeon_bo_size(robj)); 223862306a36Sopenharmony_ci r100_cs_track_texture_print(&track->textures[u]); 223962306a36Sopenharmony_ci return -EINVAL; 224062306a36Sopenharmony_ci } 224162306a36Sopenharmony_ci } 224262306a36Sopenharmony_ci return 0; 224362306a36Sopenharmony_ci} 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ciint r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track) 224662306a36Sopenharmony_ci{ 224762306a36Sopenharmony_ci unsigned i; 224862306a36Sopenharmony_ci unsigned long size; 224962306a36Sopenharmony_ci unsigned prim_walk; 225062306a36Sopenharmony_ci unsigned nverts; 225162306a36Sopenharmony_ci unsigned num_cb = track->cb_dirty ? track->num_cb : 0; 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci if (num_cb && !track->zb_cb_clear && !track->color_channel_mask && 225462306a36Sopenharmony_ci !track->blend_read_enable) 225562306a36Sopenharmony_ci num_cb = 0; 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci for (i = 0; i < num_cb; i++) { 225862306a36Sopenharmony_ci if (track->cb[i].robj == NULL) { 225962306a36Sopenharmony_ci DRM_ERROR("[drm] No buffer for color buffer %d !\n", i); 226062306a36Sopenharmony_ci return -EINVAL; 226162306a36Sopenharmony_ci } 226262306a36Sopenharmony_ci size = track->cb[i].pitch * track->cb[i].cpp * track->maxy; 226362306a36Sopenharmony_ci size += track->cb[i].offset; 226462306a36Sopenharmony_ci if (size > radeon_bo_size(track->cb[i].robj)) { 226562306a36Sopenharmony_ci DRM_ERROR("[drm] Buffer too small for color buffer %d " 226662306a36Sopenharmony_ci "(need %lu have %lu) !\n", i, size, 226762306a36Sopenharmony_ci radeon_bo_size(track->cb[i].robj)); 226862306a36Sopenharmony_ci DRM_ERROR("[drm] color buffer %d (%u %u %u %u)\n", 226962306a36Sopenharmony_ci i, track->cb[i].pitch, track->cb[i].cpp, 227062306a36Sopenharmony_ci track->cb[i].offset, track->maxy); 227162306a36Sopenharmony_ci return -EINVAL; 227262306a36Sopenharmony_ci } 227362306a36Sopenharmony_ci } 227462306a36Sopenharmony_ci track->cb_dirty = false; 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci if (track->zb_dirty && track->z_enabled) { 227762306a36Sopenharmony_ci if (track->zb.robj == NULL) { 227862306a36Sopenharmony_ci DRM_ERROR("[drm] No buffer for z buffer !\n"); 227962306a36Sopenharmony_ci return -EINVAL; 228062306a36Sopenharmony_ci } 228162306a36Sopenharmony_ci size = track->zb.pitch * track->zb.cpp * track->maxy; 228262306a36Sopenharmony_ci size += track->zb.offset; 228362306a36Sopenharmony_ci if (size > radeon_bo_size(track->zb.robj)) { 228462306a36Sopenharmony_ci DRM_ERROR("[drm] Buffer too small for z buffer " 228562306a36Sopenharmony_ci "(need %lu have %lu) !\n", size, 228662306a36Sopenharmony_ci radeon_bo_size(track->zb.robj)); 228762306a36Sopenharmony_ci DRM_ERROR("[drm] zbuffer (%u %u %u %u)\n", 228862306a36Sopenharmony_ci track->zb.pitch, track->zb.cpp, 228962306a36Sopenharmony_ci track->zb.offset, track->maxy); 229062306a36Sopenharmony_ci return -EINVAL; 229162306a36Sopenharmony_ci } 229262306a36Sopenharmony_ci } 229362306a36Sopenharmony_ci track->zb_dirty = false; 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci if (track->aa_dirty && track->aaresolve) { 229662306a36Sopenharmony_ci if (track->aa.robj == NULL) { 229762306a36Sopenharmony_ci DRM_ERROR("[drm] No buffer for AA resolve buffer %d !\n", i); 229862306a36Sopenharmony_ci return -EINVAL; 229962306a36Sopenharmony_ci } 230062306a36Sopenharmony_ci /* I believe the format comes from colorbuffer0. */ 230162306a36Sopenharmony_ci size = track->aa.pitch * track->cb[0].cpp * track->maxy; 230262306a36Sopenharmony_ci size += track->aa.offset; 230362306a36Sopenharmony_ci if (size > radeon_bo_size(track->aa.robj)) { 230462306a36Sopenharmony_ci DRM_ERROR("[drm] Buffer too small for AA resolve buffer %d " 230562306a36Sopenharmony_ci "(need %lu have %lu) !\n", i, size, 230662306a36Sopenharmony_ci radeon_bo_size(track->aa.robj)); 230762306a36Sopenharmony_ci DRM_ERROR("[drm] AA resolve buffer %d (%u %u %u %u)\n", 230862306a36Sopenharmony_ci i, track->aa.pitch, track->cb[0].cpp, 230962306a36Sopenharmony_ci track->aa.offset, track->maxy); 231062306a36Sopenharmony_ci return -EINVAL; 231162306a36Sopenharmony_ci } 231262306a36Sopenharmony_ci } 231362306a36Sopenharmony_ci track->aa_dirty = false; 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci prim_walk = (track->vap_vf_cntl >> 4) & 0x3; 231662306a36Sopenharmony_ci if (track->vap_vf_cntl & (1 << 14)) { 231762306a36Sopenharmony_ci nverts = track->vap_alt_nverts; 231862306a36Sopenharmony_ci } else { 231962306a36Sopenharmony_ci nverts = (track->vap_vf_cntl >> 16) & 0xFFFF; 232062306a36Sopenharmony_ci } 232162306a36Sopenharmony_ci switch (prim_walk) { 232262306a36Sopenharmony_ci case 1: 232362306a36Sopenharmony_ci for (i = 0; i < track->num_arrays; i++) { 232462306a36Sopenharmony_ci size = track->arrays[i].esize * track->max_indx * 4UL; 232562306a36Sopenharmony_ci if (track->arrays[i].robj == NULL) { 232662306a36Sopenharmony_ci DRM_ERROR("(PW %u) Vertex array %u no buffer " 232762306a36Sopenharmony_ci "bound\n", prim_walk, i); 232862306a36Sopenharmony_ci return -EINVAL; 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_ci if (size > radeon_bo_size(track->arrays[i].robj)) { 233162306a36Sopenharmony_ci dev_err(rdev->dev, "(PW %u) Vertex array %u " 233262306a36Sopenharmony_ci "need %lu dwords have %lu dwords\n", 233362306a36Sopenharmony_ci prim_walk, i, size >> 2, 233462306a36Sopenharmony_ci radeon_bo_size(track->arrays[i].robj) 233562306a36Sopenharmony_ci >> 2); 233662306a36Sopenharmony_ci DRM_ERROR("Max indices %u\n", track->max_indx); 233762306a36Sopenharmony_ci return -EINVAL; 233862306a36Sopenharmony_ci } 233962306a36Sopenharmony_ci } 234062306a36Sopenharmony_ci break; 234162306a36Sopenharmony_ci case 2: 234262306a36Sopenharmony_ci for (i = 0; i < track->num_arrays; i++) { 234362306a36Sopenharmony_ci size = track->arrays[i].esize * (nverts - 1) * 4UL; 234462306a36Sopenharmony_ci if (track->arrays[i].robj == NULL) { 234562306a36Sopenharmony_ci DRM_ERROR("(PW %u) Vertex array %u no buffer " 234662306a36Sopenharmony_ci "bound\n", prim_walk, i); 234762306a36Sopenharmony_ci return -EINVAL; 234862306a36Sopenharmony_ci } 234962306a36Sopenharmony_ci if (size > radeon_bo_size(track->arrays[i].robj)) { 235062306a36Sopenharmony_ci dev_err(rdev->dev, "(PW %u) Vertex array %u " 235162306a36Sopenharmony_ci "need %lu dwords have %lu dwords\n", 235262306a36Sopenharmony_ci prim_walk, i, size >> 2, 235362306a36Sopenharmony_ci radeon_bo_size(track->arrays[i].robj) 235462306a36Sopenharmony_ci >> 2); 235562306a36Sopenharmony_ci return -EINVAL; 235662306a36Sopenharmony_ci } 235762306a36Sopenharmony_ci } 235862306a36Sopenharmony_ci break; 235962306a36Sopenharmony_ci case 3: 236062306a36Sopenharmony_ci size = track->vtx_size * nverts; 236162306a36Sopenharmony_ci if (size != track->immd_dwords) { 236262306a36Sopenharmony_ci DRM_ERROR("IMMD draw %u dwors but needs %lu dwords\n", 236362306a36Sopenharmony_ci track->immd_dwords, size); 236462306a36Sopenharmony_ci DRM_ERROR("VAP_VF_CNTL.NUM_VERTICES %u, VTX_SIZE %u\n", 236562306a36Sopenharmony_ci nverts, track->vtx_size); 236662306a36Sopenharmony_ci return -EINVAL; 236762306a36Sopenharmony_ci } 236862306a36Sopenharmony_ci break; 236962306a36Sopenharmony_ci default: 237062306a36Sopenharmony_ci DRM_ERROR("[drm] Invalid primitive walk %d for VAP_VF_CNTL\n", 237162306a36Sopenharmony_ci prim_walk); 237262306a36Sopenharmony_ci return -EINVAL; 237362306a36Sopenharmony_ci } 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci if (track->tex_dirty) { 237662306a36Sopenharmony_ci track->tex_dirty = false; 237762306a36Sopenharmony_ci return r100_cs_track_texture_check(rdev, track); 237862306a36Sopenharmony_ci } 237962306a36Sopenharmony_ci return 0; 238062306a36Sopenharmony_ci} 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_civoid r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track) 238362306a36Sopenharmony_ci{ 238462306a36Sopenharmony_ci unsigned i, face; 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci track->cb_dirty = true; 238762306a36Sopenharmony_ci track->zb_dirty = true; 238862306a36Sopenharmony_ci track->tex_dirty = true; 238962306a36Sopenharmony_ci track->aa_dirty = true; 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci if (rdev->family < CHIP_R300) { 239262306a36Sopenharmony_ci track->num_cb = 1; 239362306a36Sopenharmony_ci if (rdev->family <= CHIP_RS200) 239462306a36Sopenharmony_ci track->num_texture = 3; 239562306a36Sopenharmony_ci else 239662306a36Sopenharmony_ci track->num_texture = 6; 239762306a36Sopenharmony_ci track->maxy = 2048; 239862306a36Sopenharmony_ci track->separate_cube = true; 239962306a36Sopenharmony_ci } else { 240062306a36Sopenharmony_ci track->num_cb = 4; 240162306a36Sopenharmony_ci track->num_texture = 16; 240262306a36Sopenharmony_ci track->maxy = 4096; 240362306a36Sopenharmony_ci track->separate_cube = false; 240462306a36Sopenharmony_ci track->aaresolve = false; 240562306a36Sopenharmony_ci track->aa.robj = NULL; 240662306a36Sopenharmony_ci } 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci for (i = 0; i < track->num_cb; i++) { 240962306a36Sopenharmony_ci track->cb[i].robj = NULL; 241062306a36Sopenharmony_ci track->cb[i].pitch = 8192; 241162306a36Sopenharmony_ci track->cb[i].cpp = 16; 241262306a36Sopenharmony_ci track->cb[i].offset = 0; 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci track->z_enabled = true; 241562306a36Sopenharmony_ci track->zb.robj = NULL; 241662306a36Sopenharmony_ci track->zb.pitch = 8192; 241762306a36Sopenharmony_ci track->zb.cpp = 4; 241862306a36Sopenharmony_ci track->zb.offset = 0; 241962306a36Sopenharmony_ci track->vtx_size = 0x7F; 242062306a36Sopenharmony_ci track->immd_dwords = 0xFFFFFFFFUL; 242162306a36Sopenharmony_ci track->num_arrays = 11; 242262306a36Sopenharmony_ci track->max_indx = 0x00FFFFFFUL; 242362306a36Sopenharmony_ci for (i = 0; i < track->num_arrays; i++) { 242462306a36Sopenharmony_ci track->arrays[i].robj = NULL; 242562306a36Sopenharmony_ci track->arrays[i].esize = 0x7F; 242662306a36Sopenharmony_ci } 242762306a36Sopenharmony_ci for (i = 0; i < track->num_texture; i++) { 242862306a36Sopenharmony_ci track->textures[i].compress_format = R100_TRACK_COMP_NONE; 242962306a36Sopenharmony_ci track->textures[i].pitch = 16536; 243062306a36Sopenharmony_ci track->textures[i].width = 16536; 243162306a36Sopenharmony_ci track->textures[i].height = 16536; 243262306a36Sopenharmony_ci track->textures[i].width_11 = 1 << 11; 243362306a36Sopenharmony_ci track->textures[i].height_11 = 1 << 11; 243462306a36Sopenharmony_ci track->textures[i].num_levels = 12; 243562306a36Sopenharmony_ci if (rdev->family <= CHIP_RS200) { 243662306a36Sopenharmony_ci track->textures[i].tex_coord_type = 0; 243762306a36Sopenharmony_ci track->textures[i].txdepth = 0; 243862306a36Sopenharmony_ci } else { 243962306a36Sopenharmony_ci track->textures[i].txdepth = 16; 244062306a36Sopenharmony_ci track->textures[i].tex_coord_type = 1; 244162306a36Sopenharmony_ci } 244262306a36Sopenharmony_ci track->textures[i].cpp = 64; 244362306a36Sopenharmony_ci track->textures[i].robj = NULL; 244462306a36Sopenharmony_ci /* CS IB emission code makes sure texture unit are disabled */ 244562306a36Sopenharmony_ci track->textures[i].enabled = false; 244662306a36Sopenharmony_ci track->textures[i].lookup_disable = false; 244762306a36Sopenharmony_ci track->textures[i].roundup_w = true; 244862306a36Sopenharmony_ci track->textures[i].roundup_h = true; 244962306a36Sopenharmony_ci if (track->separate_cube) 245062306a36Sopenharmony_ci for (face = 0; face < 5; face++) { 245162306a36Sopenharmony_ci track->textures[i].cube_info[face].robj = NULL; 245262306a36Sopenharmony_ci track->textures[i].cube_info[face].width = 16536; 245362306a36Sopenharmony_ci track->textures[i].cube_info[face].height = 16536; 245462306a36Sopenharmony_ci track->textures[i].cube_info[face].offset = 0; 245562306a36Sopenharmony_ci } 245662306a36Sopenharmony_ci } 245762306a36Sopenharmony_ci} 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_ci/* 246062306a36Sopenharmony_ci * Global GPU functions 246162306a36Sopenharmony_ci */ 246262306a36Sopenharmony_cistatic void r100_errata(struct radeon_device *rdev) 246362306a36Sopenharmony_ci{ 246462306a36Sopenharmony_ci rdev->pll_errata = 0; 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci if (rdev->family == CHIP_RV200 || rdev->family == CHIP_RS200) { 246762306a36Sopenharmony_ci rdev->pll_errata |= CHIP_ERRATA_PLL_DUMMYREADS; 246862306a36Sopenharmony_ci } 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci if (rdev->family == CHIP_RV100 || 247162306a36Sopenharmony_ci rdev->family == CHIP_RS100 || 247262306a36Sopenharmony_ci rdev->family == CHIP_RS200) { 247362306a36Sopenharmony_ci rdev->pll_errata |= CHIP_ERRATA_PLL_DELAY; 247462306a36Sopenharmony_ci } 247562306a36Sopenharmony_ci} 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_cistatic int r100_rbbm_fifo_wait_for_entry(struct radeon_device *rdev, unsigned n) 247862306a36Sopenharmony_ci{ 247962306a36Sopenharmony_ci unsigned i; 248062306a36Sopenharmony_ci uint32_t tmp; 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 248362306a36Sopenharmony_ci tmp = RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK; 248462306a36Sopenharmony_ci if (tmp >= n) { 248562306a36Sopenharmony_ci return 0; 248662306a36Sopenharmony_ci } 248762306a36Sopenharmony_ci udelay(1); 248862306a36Sopenharmony_ci } 248962306a36Sopenharmony_ci return -1; 249062306a36Sopenharmony_ci} 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ciint r100_gui_wait_for_idle(struct radeon_device *rdev) 249362306a36Sopenharmony_ci{ 249462306a36Sopenharmony_ci unsigned i; 249562306a36Sopenharmony_ci uint32_t tmp; 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci if (r100_rbbm_fifo_wait_for_entry(rdev, 64)) { 249862306a36Sopenharmony_ci pr_warn("radeon: wait for empty RBBM fifo failed! Bad things might happen.\n"); 249962306a36Sopenharmony_ci } 250062306a36Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 250162306a36Sopenharmony_ci tmp = RREG32(RADEON_RBBM_STATUS); 250262306a36Sopenharmony_ci if (!(tmp & RADEON_RBBM_ACTIVE)) { 250362306a36Sopenharmony_ci return 0; 250462306a36Sopenharmony_ci } 250562306a36Sopenharmony_ci udelay(1); 250662306a36Sopenharmony_ci } 250762306a36Sopenharmony_ci return -1; 250862306a36Sopenharmony_ci} 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ciint r100_mc_wait_for_idle(struct radeon_device *rdev) 251162306a36Sopenharmony_ci{ 251262306a36Sopenharmony_ci unsigned i; 251362306a36Sopenharmony_ci uint32_t tmp; 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 251662306a36Sopenharmony_ci /* read MC_STATUS */ 251762306a36Sopenharmony_ci tmp = RREG32(RADEON_MC_STATUS); 251862306a36Sopenharmony_ci if (tmp & RADEON_MC_IDLE) { 251962306a36Sopenharmony_ci return 0; 252062306a36Sopenharmony_ci } 252162306a36Sopenharmony_ci udelay(1); 252262306a36Sopenharmony_ci } 252362306a36Sopenharmony_ci return -1; 252462306a36Sopenharmony_ci} 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_cibool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) 252762306a36Sopenharmony_ci{ 252862306a36Sopenharmony_ci u32 rbbm_status; 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci rbbm_status = RREG32(R_000E40_RBBM_STATUS); 253162306a36Sopenharmony_ci if (!G_000E40_GUI_ACTIVE(rbbm_status)) { 253262306a36Sopenharmony_ci radeon_ring_lockup_update(rdev, ring); 253362306a36Sopenharmony_ci return false; 253462306a36Sopenharmony_ci } 253562306a36Sopenharmony_ci return radeon_ring_test_lockup(rdev, ring); 253662306a36Sopenharmony_ci} 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci/* required on r1xx, r2xx, r300, r(v)350, r420/r481, rs400/rs480 */ 253962306a36Sopenharmony_civoid r100_enable_bm(struct radeon_device *rdev) 254062306a36Sopenharmony_ci{ 254162306a36Sopenharmony_ci uint32_t tmp; 254262306a36Sopenharmony_ci /* Enable bus mastering */ 254362306a36Sopenharmony_ci tmp = RREG32(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; 254462306a36Sopenharmony_ci WREG32(RADEON_BUS_CNTL, tmp); 254562306a36Sopenharmony_ci} 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_civoid r100_bm_disable(struct radeon_device *rdev) 254862306a36Sopenharmony_ci{ 254962306a36Sopenharmony_ci u32 tmp; 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci /* disable bus mastering */ 255262306a36Sopenharmony_ci tmp = RREG32(R_000030_BUS_CNTL); 255362306a36Sopenharmony_ci WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000044); 255462306a36Sopenharmony_ci mdelay(1); 255562306a36Sopenharmony_ci WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000042); 255662306a36Sopenharmony_ci mdelay(1); 255762306a36Sopenharmony_ci WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040); 255862306a36Sopenharmony_ci tmp = RREG32(RADEON_BUS_CNTL); 255962306a36Sopenharmony_ci mdelay(1); 256062306a36Sopenharmony_ci pci_clear_master(rdev->pdev); 256162306a36Sopenharmony_ci mdelay(1); 256262306a36Sopenharmony_ci} 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ciint r100_asic_reset(struct radeon_device *rdev, bool hard) 256562306a36Sopenharmony_ci{ 256662306a36Sopenharmony_ci struct r100_mc_save save; 256762306a36Sopenharmony_ci u32 status, tmp; 256862306a36Sopenharmony_ci int ret = 0; 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci status = RREG32(R_000E40_RBBM_STATUS); 257162306a36Sopenharmony_ci if (!G_000E40_GUI_ACTIVE(status)) { 257262306a36Sopenharmony_ci return 0; 257362306a36Sopenharmony_ci } 257462306a36Sopenharmony_ci r100_mc_stop(rdev, &save); 257562306a36Sopenharmony_ci status = RREG32(R_000E40_RBBM_STATUS); 257662306a36Sopenharmony_ci dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); 257762306a36Sopenharmony_ci /* stop CP */ 257862306a36Sopenharmony_ci WREG32(RADEON_CP_CSQ_CNTL, 0); 257962306a36Sopenharmony_ci tmp = RREG32(RADEON_CP_RB_CNTL); 258062306a36Sopenharmony_ci WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA); 258162306a36Sopenharmony_ci WREG32(RADEON_CP_RB_RPTR_WR, 0); 258262306a36Sopenharmony_ci WREG32(RADEON_CP_RB_WPTR, 0); 258362306a36Sopenharmony_ci WREG32(RADEON_CP_RB_CNTL, tmp); 258462306a36Sopenharmony_ci /* save PCI state */ 258562306a36Sopenharmony_ci pci_save_state(rdev->pdev); 258662306a36Sopenharmony_ci /* disable bus mastering */ 258762306a36Sopenharmony_ci r100_bm_disable(rdev); 258862306a36Sopenharmony_ci WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_SE(1) | 258962306a36Sopenharmony_ci S_0000F0_SOFT_RESET_RE(1) | 259062306a36Sopenharmony_ci S_0000F0_SOFT_RESET_PP(1) | 259162306a36Sopenharmony_ci S_0000F0_SOFT_RESET_RB(1)); 259262306a36Sopenharmony_ci RREG32(R_0000F0_RBBM_SOFT_RESET); 259362306a36Sopenharmony_ci mdelay(500); 259462306a36Sopenharmony_ci WREG32(R_0000F0_RBBM_SOFT_RESET, 0); 259562306a36Sopenharmony_ci mdelay(1); 259662306a36Sopenharmony_ci status = RREG32(R_000E40_RBBM_STATUS); 259762306a36Sopenharmony_ci dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); 259862306a36Sopenharmony_ci /* reset CP */ 259962306a36Sopenharmony_ci WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1)); 260062306a36Sopenharmony_ci RREG32(R_0000F0_RBBM_SOFT_RESET); 260162306a36Sopenharmony_ci mdelay(500); 260262306a36Sopenharmony_ci WREG32(R_0000F0_RBBM_SOFT_RESET, 0); 260362306a36Sopenharmony_ci mdelay(1); 260462306a36Sopenharmony_ci status = RREG32(R_000E40_RBBM_STATUS); 260562306a36Sopenharmony_ci dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); 260662306a36Sopenharmony_ci /* restore PCI & busmastering */ 260762306a36Sopenharmony_ci pci_restore_state(rdev->pdev); 260862306a36Sopenharmony_ci r100_enable_bm(rdev); 260962306a36Sopenharmony_ci /* Check if GPU is idle */ 261062306a36Sopenharmony_ci if (G_000E40_SE_BUSY(status) || G_000E40_RE_BUSY(status) || 261162306a36Sopenharmony_ci G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) { 261262306a36Sopenharmony_ci dev_err(rdev->dev, "failed to reset GPU\n"); 261362306a36Sopenharmony_ci ret = -1; 261462306a36Sopenharmony_ci } else 261562306a36Sopenharmony_ci dev_info(rdev->dev, "GPU reset succeed\n"); 261662306a36Sopenharmony_ci r100_mc_resume(rdev, &save); 261762306a36Sopenharmony_ci return ret; 261862306a36Sopenharmony_ci} 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_civoid r100_set_common_regs(struct radeon_device *rdev) 262162306a36Sopenharmony_ci{ 262262306a36Sopenharmony_ci bool force_dac2 = false; 262362306a36Sopenharmony_ci u32 tmp; 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_ci /* set these so they don't interfere with anything */ 262662306a36Sopenharmony_ci WREG32(RADEON_OV0_SCALE_CNTL, 0); 262762306a36Sopenharmony_ci WREG32(RADEON_SUBPIC_CNTL, 0); 262862306a36Sopenharmony_ci WREG32(RADEON_VIPH_CONTROL, 0); 262962306a36Sopenharmony_ci WREG32(RADEON_I2C_CNTL_1, 0); 263062306a36Sopenharmony_ci WREG32(RADEON_DVI_I2C_CNTL_1, 0); 263162306a36Sopenharmony_ci WREG32(RADEON_CAP0_TRIG_CNTL, 0); 263262306a36Sopenharmony_ci WREG32(RADEON_CAP1_TRIG_CNTL, 0); 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci /* always set up dac2 on rn50 and some rv100 as lots 263562306a36Sopenharmony_ci * of servers seem to wire it up to a VGA port but 263662306a36Sopenharmony_ci * don't report it in the bios connector 263762306a36Sopenharmony_ci * table. 263862306a36Sopenharmony_ci */ 263962306a36Sopenharmony_ci switch (rdev->pdev->device) { 264062306a36Sopenharmony_ci /* RN50 */ 264162306a36Sopenharmony_ci case 0x515e: 264262306a36Sopenharmony_ci case 0x5969: 264362306a36Sopenharmony_ci force_dac2 = true; 264462306a36Sopenharmony_ci break; 264562306a36Sopenharmony_ci /* RV100*/ 264662306a36Sopenharmony_ci case 0x5159: 264762306a36Sopenharmony_ci case 0x515a: 264862306a36Sopenharmony_ci /* DELL triple head servers */ 264962306a36Sopenharmony_ci if ((rdev->pdev->subsystem_vendor == 0x1028 /* DELL */) && 265062306a36Sopenharmony_ci ((rdev->pdev->subsystem_device == 0x016c) || 265162306a36Sopenharmony_ci (rdev->pdev->subsystem_device == 0x016d) || 265262306a36Sopenharmony_ci (rdev->pdev->subsystem_device == 0x016e) || 265362306a36Sopenharmony_ci (rdev->pdev->subsystem_device == 0x016f) || 265462306a36Sopenharmony_ci (rdev->pdev->subsystem_device == 0x0170) || 265562306a36Sopenharmony_ci (rdev->pdev->subsystem_device == 0x017d) || 265662306a36Sopenharmony_ci (rdev->pdev->subsystem_device == 0x017e) || 265762306a36Sopenharmony_ci (rdev->pdev->subsystem_device == 0x0183) || 265862306a36Sopenharmony_ci (rdev->pdev->subsystem_device == 0x018a) || 265962306a36Sopenharmony_ci (rdev->pdev->subsystem_device == 0x019a))) 266062306a36Sopenharmony_ci force_dac2 = true; 266162306a36Sopenharmony_ci break; 266262306a36Sopenharmony_ci } 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_ci if (force_dac2) { 266562306a36Sopenharmony_ci u32 disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); 266662306a36Sopenharmony_ci u32 tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); 266762306a36Sopenharmony_ci u32 dac2_cntl = RREG32(RADEON_DAC_CNTL2); 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci /* For CRT on DAC2, don't turn it on if BIOS didn't 267062306a36Sopenharmony_ci enable it, even it's detected. 267162306a36Sopenharmony_ci */ 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci /* force it to crtc0 */ 267462306a36Sopenharmony_ci dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; 267562306a36Sopenharmony_ci dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; 267662306a36Sopenharmony_ci disp_hw_debug |= RADEON_CRT2_DISP1_SEL; 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_ci /* set up the TV DAC */ 267962306a36Sopenharmony_ci tv_dac_cntl &= ~(RADEON_TV_DAC_PEDESTAL | 268062306a36Sopenharmony_ci RADEON_TV_DAC_STD_MASK | 268162306a36Sopenharmony_ci RADEON_TV_DAC_RDACPD | 268262306a36Sopenharmony_ci RADEON_TV_DAC_GDACPD | 268362306a36Sopenharmony_ci RADEON_TV_DAC_BDACPD | 268462306a36Sopenharmony_ci RADEON_TV_DAC_BGADJ_MASK | 268562306a36Sopenharmony_ci RADEON_TV_DAC_DACADJ_MASK); 268662306a36Sopenharmony_ci tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | 268762306a36Sopenharmony_ci RADEON_TV_DAC_NHOLD | 268862306a36Sopenharmony_ci RADEON_TV_DAC_STD_PS2 | 268962306a36Sopenharmony_ci (0x58 << 16)); 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_ci WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); 269262306a36Sopenharmony_ci WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); 269362306a36Sopenharmony_ci WREG32(RADEON_DAC_CNTL2, dac2_cntl); 269462306a36Sopenharmony_ci } 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ci /* switch PM block to ACPI mode */ 269762306a36Sopenharmony_ci tmp = RREG32_PLL(RADEON_PLL_PWRMGT_CNTL); 269862306a36Sopenharmony_ci tmp &= ~RADEON_PM_MODE_SEL; 269962306a36Sopenharmony_ci WREG32_PLL(RADEON_PLL_PWRMGT_CNTL, tmp); 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci} 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ci/* 270462306a36Sopenharmony_ci * VRAM info 270562306a36Sopenharmony_ci */ 270662306a36Sopenharmony_cistatic void r100_vram_get_type(struct radeon_device *rdev) 270762306a36Sopenharmony_ci{ 270862306a36Sopenharmony_ci uint32_t tmp; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci rdev->mc.vram_is_ddr = false; 271162306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_IGP) 271262306a36Sopenharmony_ci rdev->mc.vram_is_ddr = true; 271362306a36Sopenharmony_ci else if (RREG32(RADEON_MEM_SDRAM_MODE_REG) & RADEON_MEM_CFG_TYPE_DDR) 271462306a36Sopenharmony_ci rdev->mc.vram_is_ddr = true; 271562306a36Sopenharmony_ci if ((rdev->family == CHIP_RV100) || 271662306a36Sopenharmony_ci (rdev->family == CHIP_RS100) || 271762306a36Sopenharmony_ci (rdev->family == CHIP_RS200)) { 271862306a36Sopenharmony_ci tmp = RREG32(RADEON_MEM_CNTL); 271962306a36Sopenharmony_ci if (tmp & RV100_HALF_MODE) { 272062306a36Sopenharmony_ci rdev->mc.vram_width = 32; 272162306a36Sopenharmony_ci } else { 272262306a36Sopenharmony_ci rdev->mc.vram_width = 64; 272362306a36Sopenharmony_ci } 272462306a36Sopenharmony_ci if (rdev->flags & RADEON_SINGLE_CRTC) { 272562306a36Sopenharmony_ci rdev->mc.vram_width /= 4; 272662306a36Sopenharmony_ci rdev->mc.vram_is_ddr = true; 272762306a36Sopenharmony_ci } 272862306a36Sopenharmony_ci } else if (rdev->family <= CHIP_RV280) { 272962306a36Sopenharmony_ci tmp = RREG32(RADEON_MEM_CNTL); 273062306a36Sopenharmony_ci if (tmp & RADEON_MEM_NUM_CHANNELS_MASK) { 273162306a36Sopenharmony_ci rdev->mc.vram_width = 128; 273262306a36Sopenharmony_ci } else { 273362306a36Sopenharmony_ci rdev->mc.vram_width = 64; 273462306a36Sopenharmony_ci } 273562306a36Sopenharmony_ci } else { 273662306a36Sopenharmony_ci /* newer IGPs */ 273762306a36Sopenharmony_ci rdev->mc.vram_width = 128; 273862306a36Sopenharmony_ci } 273962306a36Sopenharmony_ci} 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_cistatic u32 r100_get_accessible_vram(struct radeon_device *rdev) 274262306a36Sopenharmony_ci{ 274362306a36Sopenharmony_ci u32 aper_size; 274462306a36Sopenharmony_ci u8 byte; 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_ci aper_size = RREG32(RADEON_CONFIG_APER_SIZE); 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci /* Set HDP_APER_CNTL only on cards that are known not to be broken, 274962306a36Sopenharmony_ci * that is has the 2nd generation multifunction PCI interface 275062306a36Sopenharmony_ci */ 275162306a36Sopenharmony_ci if (rdev->family == CHIP_RV280 || 275262306a36Sopenharmony_ci rdev->family >= CHIP_RV350) { 275362306a36Sopenharmony_ci WREG32_P(RADEON_HOST_PATH_CNTL, RADEON_HDP_APER_CNTL, 275462306a36Sopenharmony_ci ~RADEON_HDP_APER_CNTL); 275562306a36Sopenharmony_ci DRM_INFO("Generation 2 PCI interface, using max accessible memory\n"); 275662306a36Sopenharmony_ci return aper_size * 2; 275762306a36Sopenharmony_ci } 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci /* Older cards have all sorts of funny issues to deal with. First 276062306a36Sopenharmony_ci * check if it's a multifunction card by reading the PCI config 276162306a36Sopenharmony_ci * header type... Limit those to one aperture size 276262306a36Sopenharmony_ci */ 276362306a36Sopenharmony_ci pci_read_config_byte(rdev->pdev, 0xe, &byte); 276462306a36Sopenharmony_ci if (byte & 0x80) { 276562306a36Sopenharmony_ci DRM_INFO("Generation 1 PCI interface in multifunction mode\n"); 276662306a36Sopenharmony_ci DRM_INFO("Limiting VRAM to one aperture\n"); 276762306a36Sopenharmony_ci return aper_size; 276862306a36Sopenharmony_ci } 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci /* Single function older card. We read HDP_APER_CNTL to see how the BIOS 277162306a36Sopenharmony_ci * have set it up. We don't write this as it's broken on some ASICs but 277262306a36Sopenharmony_ci * we expect the BIOS to have done the right thing (might be too optimistic...) 277362306a36Sopenharmony_ci */ 277462306a36Sopenharmony_ci if (RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL) 277562306a36Sopenharmony_ci return aper_size * 2; 277662306a36Sopenharmony_ci return aper_size; 277762306a36Sopenharmony_ci} 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_civoid r100_vram_init_sizes(struct radeon_device *rdev) 278062306a36Sopenharmony_ci{ 278162306a36Sopenharmony_ci u64 config_aper_size; 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci /* work out accessible VRAM */ 278462306a36Sopenharmony_ci rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0); 278562306a36Sopenharmony_ci rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0); 278662306a36Sopenharmony_ci rdev->mc.visible_vram_size = r100_get_accessible_vram(rdev); 278762306a36Sopenharmony_ci /* FIXME we don't use the second aperture yet when we could use it */ 278862306a36Sopenharmony_ci if (rdev->mc.visible_vram_size > rdev->mc.aper_size) 278962306a36Sopenharmony_ci rdev->mc.visible_vram_size = rdev->mc.aper_size; 279062306a36Sopenharmony_ci config_aper_size = RREG32(RADEON_CONFIG_APER_SIZE); 279162306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_IGP) { 279262306a36Sopenharmony_ci uint32_t tom; 279362306a36Sopenharmony_ci /* read NB_TOM to get the amount of ram stolen for the GPU */ 279462306a36Sopenharmony_ci tom = RREG32(RADEON_NB_TOM); 279562306a36Sopenharmony_ci rdev->mc.real_vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16); 279662306a36Sopenharmony_ci WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size); 279762306a36Sopenharmony_ci rdev->mc.mc_vram_size = rdev->mc.real_vram_size; 279862306a36Sopenharmony_ci } else { 279962306a36Sopenharmony_ci rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE); 280062306a36Sopenharmony_ci /* Some production boards of m6 will report 0 280162306a36Sopenharmony_ci * if it's 8 MB 280262306a36Sopenharmony_ci */ 280362306a36Sopenharmony_ci if (rdev->mc.real_vram_size == 0) { 280462306a36Sopenharmony_ci rdev->mc.real_vram_size = 8192 * 1024; 280562306a36Sopenharmony_ci WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size); 280662306a36Sopenharmony_ci } 280762306a36Sopenharmony_ci /* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM - 280862306a36Sopenharmony_ci * Novell bug 204882 + along with lots of ubuntu ones 280962306a36Sopenharmony_ci */ 281062306a36Sopenharmony_ci if (rdev->mc.aper_size > config_aper_size) 281162306a36Sopenharmony_ci config_aper_size = rdev->mc.aper_size; 281262306a36Sopenharmony_ci 281362306a36Sopenharmony_ci if (config_aper_size > rdev->mc.real_vram_size) 281462306a36Sopenharmony_ci rdev->mc.mc_vram_size = config_aper_size; 281562306a36Sopenharmony_ci else 281662306a36Sopenharmony_ci rdev->mc.mc_vram_size = rdev->mc.real_vram_size; 281762306a36Sopenharmony_ci } 281862306a36Sopenharmony_ci} 281962306a36Sopenharmony_ci 282062306a36Sopenharmony_civoid r100_vga_set_state(struct radeon_device *rdev, bool state) 282162306a36Sopenharmony_ci{ 282262306a36Sopenharmony_ci uint32_t temp; 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci temp = RREG32(RADEON_CONFIG_CNTL); 282562306a36Sopenharmony_ci if (!state) { 282662306a36Sopenharmony_ci temp &= ~RADEON_CFG_VGA_RAM_EN; 282762306a36Sopenharmony_ci temp |= RADEON_CFG_VGA_IO_DIS; 282862306a36Sopenharmony_ci } else { 282962306a36Sopenharmony_ci temp &= ~RADEON_CFG_VGA_IO_DIS; 283062306a36Sopenharmony_ci } 283162306a36Sopenharmony_ci WREG32(RADEON_CONFIG_CNTL, temp); 283262306a36Sopenharmony_ci} 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_cistatic void r100_mc_init(struct radeon_device *rdev) 283562306a36Sopenharmony_ci{ 283662306a36Sopenharmony_ci u64 base; 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci r100_vram_get_type(rdev); 283962306a36Sopenharmony_ci r100_vram_init_sizes(rdev); 284062306a36Sopenharmony_ci base = rdev->mc.aper_base; 284162306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_IGP) 284262306a36Sopenharmony_ci base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16; 284362306a36Sopenharmony_ci radeon_vram_location(rdev, &rdev->mc, base); 284462306a36Sopenharmony_ci rdev->mc.gtt_base_align = 0; 284562306a36Sopenharmony_ci if (!(rdev->flags & RADEON_IS_AGP)) 284662306a36Sopenharmony_ci radeon_gtt_location(rdev, &rdev->mc); 284762306a36Sopenharmony_ci radeon_update_bandwidth_info(rdev); 284862306a36Sopenharmony_ci} 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_ci/* 285262306a36Sopenharmony_ci * Indirect registers accessor 285362306a36Sopenharmony_ci */ 285462306a36Sopenharmony_civoid r100_pll_errata_after_index(struct radeon_device *rdev) 285562306a36Sopenharmony_ci{ 285662306a36Sopenharmony_ci if (rdev->pll_errata & CHIP_ERRATA_PLL_DUMMYREADS) { 285762306a36Sopenharmony_ci (void)RREG32(RADEON_CLOCK_CNTL_DATA); 285862306a36Sopenharmony_ci (void)RREG32(RADEON_CRTC_GEN_CNTL); 285962306a36Sopenharmony_ci } 286062306a36Sopenharmony_ci} 286162306a36Sopenharmony_ci 286262306a36Sopenharmony_cistatic void r100_pll_errata_after_data(struct radeon_device *rdev) 286362306a36Sopenharmony_ci{ 286462306a36Sopenharmony_ci /* This workarounds is necessary on RV100, RS100 and RS200 chips 286562306a36Sopenharmony_ci * or the chip could hang on a subsequent access 286662306a36Sopenharmony_ci */ 286762306a36Sopenharmony_ci if (rdev->pll_errata & CHIP_ERRATA_PLL_DELAY) { 286862306a36Sopenharmony_ci mdelay(5); 286962306a36Sopenharmony_ci } 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci /* This function is required to workaround a hardware bug in some (all?) 287262306a36Sopenharmony_ci * revisions of the R300. This workaround should be called after every 287362306a36Sopenharmony_ci * CLOCK_CNTL_INDEX register access. If not, register reads afterward 287462306a36Sopenharmony_ci * may not be correct. 287562306a36Sopenharmony_ci */ 287662306a36Sopenharmony_ci if (rdev->pll_errata & CHIP_ERRATA_R300_CG) { 287762306a36Sopenharmony_ci uint32_t save, tmp; 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_ci save = RREG32(RADEON_CLOCK_CNTL_INDEX); 288062306a36Sopenharmony_ci tmp = save & ~(0x3f | RADEON_PLL_WR_EN); 288162306a36Sopenharmony_ci WREG32(RADEON_CLOCK_CNTL_INDEX, tmp); 288262306a36Sopenharmony_ci tmp = RREG32(RADEON_CLOCK_CNTL_DATA); 288362306a36Sopenharmony_ci WREG32(RADEON_CLOCK_CNTL_INDEX, save); 288462306a36Sopenharmony_ci } 288562306a36Sopenharmony_ci} 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ciuint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg) 288862306a36Sopenharmony_ci{ 288962306a36Sopenharmony_ci unsigned long flags; 289062306a36Sopenharmony_ci uint32_t data; 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci spin_lock_irqsave(&rdev->pll_idx_lock, flags); 289362306a36Sopenharmony_ci WREG8(RADEON_CLOCK_CNTL_INDEX, reg & 0x3f); 289462306a36Sopenharmony_ci r100_pll_errata_after_index(rdev); 289562306a36Sopenharmony_ci data = RREG32(RADEON_CLOCK_CNTL_DATA); 289662306a36Sopenharmony_ci r100_pll_errata_after_data(rdev); 289762306a36Sopenharmony_ci spin_unlock_irqrestore(&rdev->pll_idx_lock, flags); 289862306a36Sopenharmony_ci return data; 289962306a36Sopenharmony_ci} 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_civoid r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) 290262306a36Sopenharmony_ci{ 290362306a36Sopenharmony_ci unsigned long flags; 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci spin_lock_irqsave(&rdev->pll_idx_lock, flags); 290662306a36Sopenharmony_ci WREG8(RADEON_CLOCK_CNTL_INDEX, ((reg & 0x3f) | RADEON_PLL_WR_EN)); 290762306a36Sopenharmony_ci r100_pll_errata_after_index(rdev); 290862306a36Sopenharmony_ci WREG32(RADEON_CLOCK_CNTL_DATA, v); 290962306a36Sopenharmony_ci r100_pll_errata_after_data(rdev); 291062306a36Sopenharmony_ci spin_unlock_irqrestore(&rdev->pll_idx_lock, flags); 291162306a36Sopenharmony_ci} 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_cistatic void r100_set_safe_registers(struct radeon_device *rdev) 291462306a36Sopenharmony_ci{ 291562306a36Sopenharmony_ci if (ASIC_IS_RN50(rdev)) { 291662306a36Sopenharmony_ci rdev->config.r100.reg_safe_bm = rn50_reg_safe_bm; 291762306a36Sopenharmony_ci rdev->config.r100.reg_safe_bm_size = ARRAY_SIZE(rn50_reg_safe_bm); 291862306a36Sopenharmony_ci } else if (rdev->family < CHIP_R200) { 291962306a36Sopenharmony_ci rdev->config.r100.reg_safe_bm = r100_reg_safe_bm; 292062306a36Sopenharmony_ci rdev->config.r100.reg_safe_bm_size = ARRAY_SIZE(r100_reg_safe_bm); 292162306a36Sopenharmony_ci } else { 292262306a36Sopenharmony_ci r200_set_safe_registers(rdev); 292362306a36Sopenharmony_ci } 292462306a36Sopenharmony_ci} 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci/* 292762306a36Sopenharmony_ci * Debugfs info 292862306a36Sopenharmony_ci */ 292962306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 293062306a36Sopenharmony_cistatic int r100_debugfs_rbbm_info_show(struct seq_file *m, void *unused) 293162306a36Sopenharmony_ci{ 293262306a36Sopenharmony_ci struct radeon_device *rdev = m->private; 293362306a36Sopenharmony_ci uint32_t reg, value; 293462306a36Sopenharmony_ci unsigned i; 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci seq_printf(m, "RBBM_STATUS 0x%08x\n", RREG32(RADEON_RBBM_STATUS)); 293762306a36Sopenharmony_ci seq_printf(m, "RBBM_CMDFIFO_STAT 0x%08x\n", RREG32(0xE7C)); 293862306a36Sopenharmony_ci seq_printf(m, "CP_STAT 0x%08x\n", RREG32(RADEON_CP_STAT)); 293962306a36Sopenharmony_ci for (i = 0; i < 64; i++) { 294062306a36Sopenharmony_ci WREG32(RADEON_RBBM_CMDFIFO_ADDR, i | 0x100); 294162306a36Sopenharmony_ci reg = (RREG32(RADEON_RBBM_CMDFIFO_DATA) - 1) >> 2; 294262306a36Sopenharmony_ci WREG32(RADEON_RBBM_CMDFIFO_ADDR, i); 294362306a36Sopenharmony_ci value = RREG32(RADEON_RBBM_CMDFIFO_DATA); 294462306a36Sopenharmony_ci seq_printf(m, "[0x%03X] 0x%04X=0x%08X\n", i, reg, value); 294562306a36Sopenharmony_ci } 294662306a36Sopenharmony_ci return 0; 294762306a36Sopenharmony_ci} 294862306a36Sopenharmony_ci 294962306a36Sopenharmony_cistatic int r100_debugfs_cp_ring_info_show(struct seq_file *m, void *unused) 295062306a36Sopenharmony_ci{ 295162306a36Sopenharmony_ci struct radeon_device *rdev = m->private; 295262306a36Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; 295362306a36Sopenharmony_ci uint32_t rdp, wdp; 295462306a36Sopenharmony_ci unsigned count, i, j; 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci radeon_ring_free_size(rdev, ring); 295762306a36Sopenharmony_ci rdp = RREG32(RADEON_CP_RB_RPTR); 295862306a36Sopenharmony_ci wdp = RREG32(RADEON_CP_RB_WPTR); 295962306a36Sopenharmony_ci count = (rdp + ring->ring_size - wdp) & ring->ptr_mask; 296062306a36Sopenharmony_ci seq_printf(m, "CP_STAT 0x%08x\n", RREG32(RADEON_CP_STAT)); 296162306a36Sopenharmony_ci seq_printf(m, "CP_RB_WPTR 0x%08x\n", wdp); 296262306a36Sopenharmony_ci seq_printf(m, "CP_RB_RPTR 0x%08x\n", rdp); 296362306a36Sopenharmony_ci seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw); 296462306a36Sopenharmony_ci seq_printf(m, "%u dwords in ring\n", count); 296562306a36Sopenharmony_ci if (ring->ready) { 296662306a36Sopenharmony_ci for (j = 0; j <= count; j++) { 296762306a36Sopenharmony_ci i = (rdp + j) & ring->ptr_mask; 296862306a36Sopenharmony_ci seq_printf(m, "r[%04d]=0x%08x\n", i, ring->ring[i]); 296962306a36Sopenharmony_ci } 297062306a36Sopenharmony_ci } 297162306a36Sopenharmony_ci return 0; 297262306a36Sopenharmony_ci} 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci 297562306a36Sopenharmony_cistatic int r100_debugfs_cp_csq_fifo_show(struct seq_file *m, void *unused) 297662306a36Sopenharmony_ci{ 297762306a36Sopenharmony_ci struct radeon_device *rdev = m->private; 297862306a36Sopenharmony_ci uint32_t csq_stat, csq2_stat, tmp; 297962306a36Sopenharmony_ci unsigned r_rptr, r_wptr, ib1_rptr, ib1_wptr, ib2_rptr, ib2_wptr; 298062306a36Sopenharmony_ci unsigned i; 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci seq_printf(m, "CP_STAT 0x%08x\n", RREG32(RADEON_CP_STAT)); 298362306a36Sopenharmony_ci seq_printf(m, "CP_CSQ_MODE 0x%08x\n", RREG32(RADEON_CP_CSQ_MODE)); 298462306a36Sopenharmony_ci csq_stat = RREG32(RADEON_CP_CSQ_STAT); 298562306a36Sopenharmony_ci csq2_stat = RREG32(RADEON_CP_CSQ2_STAT); 298662306a36Sopenharmony_ci r_rptr = (csq_stat >> 0) & 0x3ff; 298762306a36Sopenharmony_ci r_wptr = (csq_stat >> 10) & 0x3ff; 298862306a36Sopenharmony_ci ib1_rptr = (csq_stat >> 20) & 0x3ff; 298962306a36Sopenharmony_ci ib1_wptr = (csq2_stat >> 0) & 0x3ff; 299062306a36Sopenharmony_ci ib2_rptr = (csq2_stat >> 10) & 0x3ff; 299162306a36Sopenharmony_ci ib2_wptr = (csq2_stat >> 20) & 0x3ff; 299262306a36Sopenharmony_ci seq_printf(m, "CP_CSQ_STAT 0x%08x\n", csq_stat); 299362306a36Sopenharmony_ci seq_printf(m, "CP_CSQ2_STAT 0x%08x\n", csq2_stat); 299462306a36Sopenharmony_ci seq_printf(m, "Ring rptr %u\n", r_rptr); 299562306a36Sopenharmony_ci seq_printf(m, "Ring wptr %u\n", r_wptr); 299662306a36Sopenharmony_ci seq_printf(m, "Indirect1 rptr %u\n", ib1_rptr); 299762306a36Sopenharmony_ci seq_printf(m, "Indirect1 wptr %u\n", ib1_wptr); 299862306a36Sopenharmony_ci seq_printf(m, "Indirect2 rptr %u\n", ib2_rptr); 299962306a36Sopenharmony_ci seq_printf(m, "Indirect2 wptr %u\n", ib2_wptr); 300062306a36Sopenharmony_ci /* FIXME: 0, 128, 640 depends on fifo setup see cp_init_kms 300162306a36Sopenharmony_ci * 128 = indirect1_start * 8 & 640 = indirect2_start * 8 */ 300262306a36Sopenharmony_ci seq_printf(m, "Ring fifo:\n"); 300362306a36Sopenharmony_ci for (i = 0; i < 256; i++) { 300462306a36Sopenharmony_ci WREG32(RADEON_CP_CSQ_ADDR, i << 2); 300562306a36Sopenharmony_ci tmp = RREG32(RADEON_CP_CSQ_DATA); 300662306a36Sopenharmony_ci seq_printf(m, "rfifo[%04d]=0x%08X\n", i, tmp); 300762306a36Sopenharmony_ci } 300862306a36Sopenharmony_ci seq_printf(m, "Indirect1 fifo:\n"); 300962306a36Sopenharmony_ci for (i = 256; i <= 512; i++) { 301062306a36Sopenharmony_ci WREG32(RADEON_CP_CSQ_ADDR, i << 2); 301162306a36Sopenharmony_ci tmp = RREG32(RADEON_CP_CSQ_DATA); 301262306a36Sopenharmony_ci seq_printf(m, "ib1fifo[%04d]=0x%08X\n", i, tmp); 301362306a36Sopenharmony_ci } 301462306a36Sopenharmony_ci seq_printf(m, "Indirect2 fifo:\n"); 301562306a36Sopenharmony_ci for (i = 640; i < ib1_wptr; i++) { 301662306a36Sopenharmony_ci WREG32(RADEON_CP_CSQ_ADDR, i << 2); 301762306a36Sopenharmony_ci tmp = RREG32(RADEON_CP_CSQ_DATA); 301862306a36Sopenharmony_ci seq_printf(m, "ib2fifo[%04d]=0x%08X\n", i, tmp); 301962306a36Sopenharmony_ci } 302062306a36Sopenharmony_ci return 0; 302162306a36Sopenharmony_ci} 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_cistatic int r100_debugfs_mc_info_show(struct seq_file *m, void *unused) 302462306a36Sopenharmony_ci{ 302562306a36Sopenharmony_ci struct radeon_device *rdev = m->private; 302662306a36Sopenharmony_ci uint32_t tmp; 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_ci tmp = RREG32(RADEON_CONFIG_MEMSIZE); 302962306a36Sopenharmony_ci seq_printf(m, "CONFIG_MEMSIZE 0x%08x\n", tmp); 303062306a36Sopenharmony_ci tmp = RREG32(RADEON_MC_FB_LOCATION); 303162306a36Sopenharmony_ci seq_printf(m, "MC_FB_LOCATION 0x%08x\n", tmp); 303262306a36Sopenharmony_ci tmp = RREG32(RADEON_BUS_CNTL); 303362306a36Sopenharmony_ci seq_printf(m, "BUS_CNTL 0x%08x\n", tmp); 303462306a36Sopenharmony_ci tmp = RREG32(RADEON_MC_AGP_LOCATION); 303562306a36Sopenharmony_ci seq_printf(m, "MC_AGP_LOCATION 0x%08x\n", tmp); 303662306a36Sopenharmony_ci tmp = RREG32(RADEON_AGP_BASE); 303762306a36Sopenharmony_ci seq_printf(m, "AGP_BASE 0x%08x\n", tmp); 303862306a36Sopenharmony_ci tmp = RREG32(RADEON_HOST_PATH_CNTL); 303962306a36Sopenharmony_ci seq_printf(m, "HOST_PATH_CNTL 0x%08x\n", tmp); 304062306a36Sopenharmony_ci tmp = RREG32(0x01D0); 304162306a36Sopenharmony_ci seq_printf(m, "AIC_CTRL 0x%08x\n", tmp); 304262306a36Sopenharmony_ci tmp = RREG32(RADEON_AIC_LO_ADDR); 304362306a36Sopenharmony_ci seq_printf(m, "AIC_LO_ADDR 0x%08x\n", tmp); 304462306a36Sopenharmony_ci tmp = RREG32(RADEON_AIC_HI_ADDR); 304562306a36Sopenharmony_ci seq_printf(m, "AIC_HI_ADDR 0x%08x\n", tmp); 304662306a36Sopenharmony_ci tmp = RREG32(0x01E4); 304762306a36Sopenharmony_ci seq_printf(m, "AIC_TLB_ADDR 0x%08x\n", tmp); 304862306a36Sopenharmony_ci return 0; 304962306a36Sopenharmony_ci} 305062306a36Sopenharmony_ci 305162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(r100_debugfs_rbbm_info); 305262306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(r100_debugfs_cp_ring_info); 305362306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(r100_debugfs_cp_csq_fifo); 305462306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(r100_debugfs_mc_info); 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_ci#endif 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_civoid r100_debugfs_rbbm_init(struct radeon_device *rdev) 305962306a36Sopenharmony_ci{ 306062306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 306162306a36Sopenharmony_ci struct dentry *root = rdev->ddev->primary->debugfs_root; 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci debugfs_create_file("r100_rbbm_info", 0444, root, rdev, 306462306a36Sopenharmony_ci &r100_debugfs_rbbm_info_fops); 306562306a36Sopenharmony_ci#endif 306662306a36Sopenharmony_ci} 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_civoid r100_debugfs_cp_init(struct radeon_device *rdev) 306962306a36Sopenharmony_ci{ 307062306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 307162306a36Sopenharmony_ci struct dentry *root = rdev->ddev->primary->debugfs_root; 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci debugfs_create_file("r100_cp_ring_info", 0444, root, rdev, 307462306a36Sopenharmony_ci &r100_debugfs_cp_ring_info_fops); 307562306a36Sopenharmony_ci debugfs_create_file("r100_cp_csq_fifo", 0444, root, rdev, 307662306a36Sopenharmony_ci &r100_debugfs_cp_csq_fifo_fops); 307762306a36Sopenharmony_ci#endif 307862306a36Sopenharmony_ci} 307962306a36Sopenharmony_ci 308062306a36Sopenharmony_civoid r100_debugfs_mc_info_init(struct radeon_device *rdev) 308162306a36Sopenharmony_ci{ 308262306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 308362306a36Sopenharmony_ci struct dentry *root = rdev->ddev->primary->debugfs_root; 308462306a36Sopenharmony_ci 308562306a36Sopenharmony_ci debugfs_create_file("r100_mc_info", 0444, root, rdev, 308662306a36Sopenharmony_ci &r100_debugfs_mc_info_fops); 308762306a36Sopenharmony_ci#endif 308862306a36Sopenharmony_ci} 308962306a36Sopenharmony_ci 309062306a36Sopenharmony_ciint r100_set_surface_reg(struct radeon_device *rdev, int reg, 309162306a36Sopenharmony_ci uint32_t tiling_flags, uint32_t pitch, 309262306a36Sopenharmony_ci uint32_t offset, uint32_t obj_size) 309362306a36Sopenharmony_ci{ 309462306a36Sopenharmony_ci int surf_index = reg * 16; 309562306a36Sopenharmony_ci int flags = 0; 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_ci if (rdev->family <= CHIP_RS200) { 309862306a36Sopenharmony_ci if ((tiling_flags & (RADEON_TILING_MACRO|RADEON_TILING_MICRO)) 309962306a36Sopenharmony_ci == (RADEON_TILING_MACRO|RADEON_TILING_MICRO)) 310062306a36Sopenharmony_ci flags |= RADEON_SURF_TILE_COLOR_BOTH; 310162306a36Sopenharmony_ci if (tiling_flags & RADEON_TILING_MACRO) 310262306a36Sopenharmony_ci flags |= RADEON_SURF_TILE_COLOR_MACRO; 310362306a36Sopenharmony_ci /* setting pitch to 0 disables tiling */ 310462306a36Sopenharmony_ci if ((tiling_flags & (RADEON_TILING_MACRO|RADEON_TILING_MICRO)) 310562306a36Sopenharmony_ci == 0) 310662306a36Sopenharmony_ci pitch = 0; 310762306a36Sopenharmony_ci } else if (rdev->family <= CHIP_RV280) { 310862306a36Sopenharmony_ci if (tiling_flags & (RADEON_TILING_MACRO)) 310962306a36Sopenharmony_ci flags |= R200_SURF_TILE_COLOR_MACRO; 311062306a36Sopenharmony_ci if (tiling_flags & RADEON_TILING_MICRO) 311162306a36Sopenharmony_ci flags |= R200_SURF_TILE_COLOR_MICRO; 311262306a36Sopenharmony_ci } else { 311362306a36Sopenharmony_ci if (tiling_flags & RADEON_TILING_MACRO) 311462306a36Sopenharmony_ci flags |= R300_SURF_TILE_MACRO; 311562306a36Sopenharmony_ci if (tiling_flags & RADEON_TILING_MICRO) 311662306a36Sopenharmony_ci flags |= R300_SURF_TILE_MICRO; 311762306a36Sopenharmony_ci } 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci if (tiling_flags & RADEON_TILING_SWAP_16BIT) 312062306a36Sopenharmony_ci flags |= RADEON_SURF_AP0_SWP_16BPP | RADEON_SURF_AP1_SWP_16BPP; 312162306a36Sopenharmony_ci if (tiling_flags & RADEON_TILING_SWAP_32BIT) 312262306a36Sopenharmony_ci flags |= RADEON_SURF_AP0_SWP_32BPP | RADEON_SURF_AP1_SWP_32BPP; 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ci /* r100/r200 divide by 16 */ 312562306a36Sopenharmony_ci if (rdev->family < CHIP_R300) 312662306a36Sopenharmony_ci flags |= pitch / 16; 312762306a36Sopenharmony_ci else 312862306a36Sopenharmony_ci flags |= pitch / 8; 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci 313162306a36Sopenharmony_ci DRM_DEBUG_KMS("writing surface %d %d %x %x\n", reg, flags, offset, offset+obj_size-1); 313262306a36Sopenharmony_ci WREG32(RADEON_SURFACE0_INFO + surf_index, flags); 313362306a36Sopenharmony_ci WREG32(RADEON_SURFACE0_LOWER_BOUND + surf_index, offset); 313462306a36Sopenharmony_ci WREG32(RADEON_SURFACE0_UPPER_BOUND + surf_index, offset + obj_size - 1); 313562306a36Sopenharmony_ci return 0; 313662306a36Sopenharmony_ci} 313762306a36Sopenharmony_ci 313862306a36Sopenharmony_civoid r100_clear_surface_reg(struct radeon_device *rdev, int reg) 313962306a36Sopenharmony_ci{ 314062306a36Sopenharmony_ci int surf_index = reg * 16; 314162306a36Sopenharmony_ci WREG32(RADEON_SURFACE0_INFO + surf_index, 0); 314262306a36Sopenharmony_ci} 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_civoid r100_bandwidth_update(struct radeon_device *rdev) 314562306a36Sopenharmony_ci{ 314662306a36Sopenharmony_ci fixed20_12 trcd_ff, trp_ff, tras_ff, trbs_ff, tcas_ff; 314762306a36Sopenharmony_ci fixed20_12 sclk_ff, mclk_ff, sclk_eff_ff, sclk_delay_ff; 314862306a36Sopenharmony_ci fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff; 314962306a36Sopenharmony_ci fixed20_12 crit_point_ff = {0}; 315062306a36Sopenharmony_ci uint32_t temp, data, mem_trcd, mem_trp, mem_tras; 315162306a36Sopenharmony_ci fixed20_12 memtcas_ff[8] = { 315262306a36Sopenharmony_ci dfixed_init(1), 315362306a36Sopenharmony_ci dfixed_init(2), 315462306a36Sopenharmony_ci dfixed_init(3), 315562306a36Sopenharmony_ci dfixed_init(0), 315662306a36Sopenharmony_ci dfixed_init_half(1), 315762306a36Sopenharmony_ci dfixed_init_half(2), 315862306a36Sopenharmony_ci dfixed_init(0), 315962306a36Sopenharmony_ci }; 316062306a36Sopenharmony_ci fixed20_12 memtcas_rs480_ff[8] = { 316162306a36Sopenharmony_ci dfixed_init(0), 316262306a36Sopenharmony_ci dfixed_init(1), 316362306a36Sopenharmony_ci dfixed_init(2), 316462306a36Sopenharmony_ci dfixed_init(3), 316562306a36Sopenharmony_ci dfixed_init(0), 316662306a36Sopenharmony_ci dfixed_init_half(1), 316762306a36Sopenharmony_ci dfixed_init_half(2), 316862306a36Sopenharmony_ci dfixed_init_half(3), 316962306a36Sopenharmony_ci }; 317062306a36Sopenharmony_ci fixed20_12 memtcas2_ff[8] = { 317162306a36Sopenharmony_ci dfixed_init(0), 317262306a36Sopenharmony_ci dfixed_init(1), 317362306a36Sopenharmony_ci dfixed_init(2), 317462306a36Sopenharmony_ci dfixed_init(3), 317562306a36Sopenharmony_ci dfixed_init(4), 317662306a36Sopenharmony_ci dfixed_init(5), 317762306a36Sopenharmony_ci dfixed_init(6), 317862306a36Sopenharmony_ci dfixed_init(7), 317962306a36Sopenharmony_ci }; 318062306a36Sopenharmony_ci fixed20_12 memtrbs[8] = { 318162306a36Sopenharmony_ci dfixed_init(1), 318262306a36Sopenharmony_ci dfixed_init_half(1), 318362306a36Sopenharmony_ci dfixed_init(2), 318462306a36Sopenharmony_ci dfixed_init_half(2), 318562306a36Sopenharmony_ci dfixed_init(3), 318662306a36Sopenharmony_ci dfixed_init_half(3), 318762306a36Sopenharmony_ci dfixed_init(4), 318862306a36Sopenharmony_ci dfixed_init_half(4) 318962306a36Sopenharmony_ci }; 319062306a36Sopenharmony_ci fixed20_12 memtrbs_r4xx[8] = { 319162306a36Sopenharmony_ci dfixed_init(4), 319262306a36Sopenharmony_ci dfixed_init(5), 319362306a36Sopenharmony_ci dfixed_init(6), 319462306a36Sopenharmony_ci dfixed_init(7), 319562306a36Sopenharmony_ci dfixed_init(8), 319662306a36Sopenharmony_ci dfixed_init(9), 319762306a36Sopenharmony_ci dfixed_init(10), 319862306a36Sopenharmony_ci dfixed_init(11) 319962306a36Sopenharmony_ci }; 320062306a36Sopenharmony_ci fixed20_12 min_mem_eff; 320162306a36Sopenharmony_ci fixed20_12 mc_latency_sclk, mc_latency_mclk, k1; 320262306a36Sopenharmony_ci fixed20_12 cur_latency_mclk, cur_latency_sclk; 320362306a36Sopenharmony_ci fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate = {0}, 320462306a36Sopenharmony_ci disp_drain_rate2, read_return_rate; 320562306a36Sopenharmony_ci fixed20_12 time_disp1_drop_priority; 320662306a36Sopenharmony_ci int c; 320762306a36Sopenharmony_ci int cur_size = 16; /* in octawords */ 320862306a36Sopenharmony_ci int critical_point = 0, critical_point2; 320962306a36Sopenharmony_ci/* uint32_t read_return_rate, time_disp1_drop_priority; */ 321062306a36Sopenharmony_ci int stop_req, max_stop_req; 321162306a36Sopenharmony_ci struct drm_display_mode *mode1 = NULL; 321262306a36Sopenharmony_ci struct drm_display_mode *mode2 = NULL; 321362306a36Sopenharmony_ci uint32_t pixel_bytes1 = 0; 321462306a36Sopenharmony_ci uint32_t pixel_bytes2 = 0; 321562306a36Sopenharmony_ci 321662306a36Sopenharmony_ci /* Guess line buffer size to be 8192 pixels */ 321762306a36Sopenharmony_ci u32 lb_size = 8192; 321862306a36Sopenharmony_ci 321962306a36Sopenharmony_ci if (!rdev->mode_info.mode_config_initialized) 322062306a36Sopenharmony_ci return; 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci radeon_update_display_priority(rdev); 322362306a36Sopenharmony_ci 322462306a36Sopenharmony_ci if (rdev->mode_info.crtcs[0]->base.enabled) { 322562306a36Sopenharmony_ci const struct drm_framebuffer *fb = 322662306a36Sopenharmony_ci rdev->mode_info.crtcs[0]->base.primary->fb; 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci mode1 = &rdev->mode_info.crtcs[0]->base.mode; 322962306a36Sopenharmony_ci pixel_bytes1 = fb->format->cpp[0]; 323062306a36Sopenharmony_ci } 323162306a36Sopenharmony_ci if (!(rdev->flags & RADEON_SINGLE_CRTC)) { 323262306a36Sopenharmony_ci if (rdev->mode_info.crtcs[1]->base.enabled) { 323362306a36Sopenharmony_ci const struct drm_framebuffer *fb = 323462306a36Sopenharmony_ci rdev->mode_info.crtcs[1]->base.primary->fb; 323562306a36Sopenharmony_ci 323662306a36Sopenharmony_ci mode2 = &rdev->mode_info.crtcs[1]->base.mode; 323762306a36Sopenharmony_ci pixel_bytes2 = fb->format->cpp[0]; 323862306a36Sopenharmony_ci } 323962306a36Sopenharmony_ci } 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ci min_mem_eff.full = dfixed_const_8(0); 324262306a36Sopenharmony_ci /* get modes */ 324362306a36Sopenharmony_ci if ((rdev->disp_priority == 2) && ASIC_IS_R300(rdev)) { 324462306a36Sopenharmony_ci uint32_t mc_init_misc_lat_timer = RREG32(R300_MC_INIT_MISC_LAT_TIMER); 324562306a36Sopenharmony_ci mc_init_misc_lat_timer &= ~(R300_MC_DISP1R_INIT_LAT_MASK << R300_MC_DISP1R_INIT_LAT_SHIFT); 324662306a36Sopenharmony_ci mc_init_misc_lat_timer &= ~(R300_MC_DISP0R_INIT_LAT_MASK << R300_MC_DISP0R_INIT_LAT_SHIFT); 324762306a36Sopenharmony_ci /* check crtc enables */ 324862306a36Sopenharmony_ci if (mode2) 324962306a36Sopenharmony_ci mc_init_misc_lat_timer |= (1 << R300_MC_DISP1R_INIT_LAT_SHIFT); 325062306a36Sopenharmony_ci if (mode1) 325162306a36Sopenharmony_ci mc_init_misc_lat_timer |= (1 << R300_MC_DISP0R_INIT_LAT_SHIFT); 325262306a36Sopenharmony_ci WREG32(R300_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer); 325362306a36Sopenharmony_ci } 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci /* 325662306a36Sopenharmony_ci * determine is there is enough bw for current mode 325762306a36Sopenharmony_ci */ 325862306a36Sopenharmony_ci sclk_ff = rdev->pm.sclk; 325962306a36Sopenharmony_ci mclk_ff = rdev->pm.mclk; 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1); 326262306a36Sopenharmony_ci temp_ff.full = dfixed_const(temp); 326362306a36Sopenharmony_ci mem_bw.full = dfixed_mul(mclk_ff, temp_ff); 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_ci pix_clk.full = 0; 326662306a36Sopenharmony_ci pix_clk2.full = 0; 326762306a36Sopenharmony_ci peak_disp_bw.full = 0; 326862306a36Sopenharmony_ci if (mode1) { 326962306a36Sopenharmony_ci temp_ff.full = dfixed_const(1000); 327062306a36Sopenharmony_ci pix_clk.full = dfixed_const(mode1->clock); /* convert to fixed point */ 327162306a36Sopenharmony_ci pix_clk.full = dfixed_div(pix_clk, temp_ff); 327262306a36Sopenharmony_ci temp_ff.full = dfixed_const(pixel_bytes1); 327362306a36Sopenharmony_ci peak_disp_bw.full += dfixed_mul(pix_clk, temp_ff); 327462306a36Sopenharmony_ci } 327562306a36Sopenharmony_ci if (mode2) { 327662306a36Sopenharmony_ci temp_ff.full = dfixed_const(1000); 327762306a36Sopenharmony_ci pix_clk2.full = dfixed_const(mode2->clock); /* convert to fixed point */ 327862306a36Sopenharmony_ci pix_clk2.full = dfixed_div(pix_clk2, temp_ff); 327962306a36Sopenharmony_ci temp_ff.full = dfixed_const(pixel_bytes2); 328062306a36Sopenharmony_ci peak_disp_bw.full += dfixed_mul(pix_clk2, temp_ff); 328162306a36Sopenharmony_ci } 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_ci mem_bw.full = dfixed_mul(mem_bw, min_mem_eff); 328462306a36Sopenharmony_ci if (peak_disp_bw.full >= mem_bw.full) { 328562306a36Sopenharmony_ci DRM_ERROR("You may not have enough display bandwidth for current mode\n" 328662306a36Sopenharmony_ci "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); 328762306a36Sopenharmony_ci } 328862306a36Sopenharmony_ci 328962306a36Sopenharmony_ci /* Get values from the EXT_MEM_CNTL register...converting its contents. */ 329062306a36Sopenharmony_ci temp = RREG32(RADEON_MEM_TIMING_CNTL); 329162306a36Sopenharmony_ci if ((rdev->family == CHIP_RV100) || (rdev->flags & RADEON_IS_IGP)) { /* RV100, M6, IGPs */ 329262306a36Sopenharmony_ci mem_trcd = ((temp >> 2) & 0x3) + 1; 329362306a36Sopenharmony_ci mem_trp = ((temp & 0x3)) + 1; 329462306a36Sopenharmony_ci mem_tras = ((temp & 0x70) >> 4) + 1; 329562306a36Sopenharmony_ci } else if (rdev->family == CHIP_R300 || 329662306a36Sopenharmony_ci rdev->family == CHIP_R350) { /* r300, r350 */ 329762306a36Sopenharmony_ci mem_trcd = (temp & 0x7) + 1; 329862306a36Sopenharmony_ci mem_trp = ((temp >> 8) & 0x7) + 1; 329962306a36Sopenharmony_ci mem_tras = ((temp >> 11) & 0xf) + 4; 330062306a36Sopenharmony_ci } else if (rdev->family == CHIP_RV350 || 330162306a36Sopenharmony_ci rdev->family == CHIP_RV380) { 330262306a36Sopenharmony_ci /* rv3x0 */ 330362306a36Sopenharmony_ci mem_trcd = (temp & 0x7) + 3; 330462306a36Sopenharmony_ci mem_trp = ((temp >> 8) & 0x7) + 3; 330562306a36Sopenharmony_ci mem_tras = ((temp >> 11) & 0xf) + 6; 330662306a36Sopenharmony_ci } else if (rdev->family == CHIP_R420 || 330762306a36Sopenharmony_ci rdev->family == CHIP_R423 || 330862306a36Sopenharmony_ci rdev->family == CHIP_RV410) { 330962306a36Sopenharmony_ci /* r4xx */ 331062306a36Sopenharmony_ci mem_trcd = (temp & 0xf) + 3; 331162306a36Sopenharmony_ci if (mem_trcd > 15) 331262306a36Sopenharmony_ci mem_trcd = 15; 331362306a36Sopenharmony_ci mem_trp = ((temp >> 8) & 0xf) + 3; 331462306a36Sopenharmony_ci if (mem_trp > 15) 331562306a36Sopenharmony_ci mem_trp = 15; 331662306a36Sopenharmony_ci mem_tras = ((temp >> 12) & 0x1f) + 6; 331762306a36Sopenharmony_ci if (mem_tras > 31) 331862306a36Sopenharmony_ci mem_tras = 31; 331962306a36Sopenharmony_ci } else { /* RV200, R200 */ 332062306a36Sopenharmony_ci mem_trcd = (temp & 0x7) + 1; 332162306a36Sopenharmony_ci mem_trp = ((temp >> 8) & 0x7) + 1; 332262306a36Sopenharmony_ci mem_tras = ((temp >> 12) & 0xf) + 4; 332362306a36Sopenharmony_ci } 332462306a36Sopenharmony_ci /* convert to FF */ 332562306a36Sopenharmony_ci trcd_ff.full = dfixed_const(mem_trcd); 332662306a36Sopenharmony_ci trp_ff.full = dfixed_const(mem_trp); 332762306a36Sopenharmony_ci tras_ff.full = dfixed_const(mem_tras); 332862306a36Sopenharmony_ci 332962306a36Sopenharmony_ci /* Get values from the MEM_SDRAM_MODE_REG register...converting its */ 333062306a36Sopenharmony_ci temp = RREG32(RADEON_MEM_SDRAM_MODE_REG); 333162306a36Sopenharmony_ci data = (temp & (7 << 20)) >> 20; 333262306a36Sopenharmony_ci if ((rdev->family == CHIP_RV100) || rdev->flags & RADEON_IS_IGP) { 333362306a36Sopenharmony_ci if (rdev->family == CHIP_RS480) /* don't think rs400 */ 333462306a36Sopenharmony_ci tcas_ff = memtcas_rs480_ff[data]; 333562306a36Sopenharmony_ci else 333662306a36Sopenharmony_ci tcas_ff = memtcas_ff[data]; 333762306a36Sopenharmony_ci } else 333862306a36Sopenharmony_ci tcas_ff = memtcas2_ff[data]; 333962306a36Sopenharmony_ci 334062306a36Sopenharmony_ci if (rdev->family == CHIP_RS400 || 334162306a36Sopenharmony_ci rdev->family == CHIP_RS480) { 334262306a36Sopenharmony_ci /* extra cas latency stored in bits 23-25 0-4 clocks */ 334362306a36Sopenharmony_ci data = (temp >> 23) & 0x7; 334462306a36Sopenharmony_ci if (data < 5) 334562306a36Sopenharmony_ci tcas_ff.full += dfixed_const(data); 334662306a36Sopenharmony_ci } 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci if (ASIC_IS_R300(rdev) && !(rdev->flags & RADEON_IS_IGP)) { 334962306a36Sopenharmony_ci /* on the R300, Tcas is included in Trbs. 335062306a36Sopenharmony_ci */ 335162306a36Sopenharmony_ci temp = RREG32(RADEON_MEM_CNTL); 335262306a36Sopenharmony_ci data = (R300_MEM_NUM_CHANNELS_MASK & temp); 335362306a36Sopenharmony_ci if (data == 1) { 335462306a36Sopenharmony_ci if (R300_MEM_USE_CD_CH_ONLY & temp) { 335562306a36Sopenharmony_ci temp = RREG32(R300_MC_IND_INDEX); 335662306a36Sopenharmony_ci temp &= ~R300_MC_IND_ADDR_MASK; 335762306a36Sopenharmony_ci temp |= R300_MC_READ_CNTL_CD_mcind; 335862306a36Sopenharmony_ci WREG32(R300_MC_IND_INDEX, temp); 335962306a36Sopenharmony_ci temp = RREG32(R300_MC_IND_DATA); 336062306a36Sopenharmony_ci data = (R300_MEM_RBS_POSITION_C_MASK & temp); 336162306a36Sopenharmony_ci } else { 336262306a36Sopenharmony_ci temp = RREG32(R300_MC_READ_CNTL_AB); 336362306a36Sopenharmony_ci data = (R300_MEM_RBS_POSITION_A_MASK & temp); 336462306a36Sopenharmony_ci } 336562306a36Sopenharmony_ci } else { 336662306a36Sopenharmony_ci temp = RREG32(R300_MC_READ_CNTL_AB); 336762306a36Sopenharmony_ci data = (R300_MEM_RBS_POSITION_A_MASK & temp); 336862306a36Sopenharmony_ci } 336962306a36Sopenharmony_ci if (rdev->family == CHIP_RV410 || 337062306a36Sopenharmony_ci rdev->family == CHIP_R420 || 337162306a36Sopenharmony_ci rdev->family == CHIP_R423) 337262306a36Sopenharmony_ci trbs_ff = memtrbs_r4xx[data]; 337362306a36Sopenharmony_ci else 337462306a36Sopenharmony_ci trbs_ff = memtrbs[data]; 337562306a36Sopenharmony_ci tcas_ff.full += trbs_ff.full; 337662306a36Sopenharmony_ci } 337762306a36Sopenharmony_ci 337862306a36Sopenharmony_ci sclk_eff_ff.full = sclk_ff.full; 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_AGP) { 338162306a36Sopenharmony_ci fixed20_12 agpmode_ff; 338262306a36Sopenharmony_ci agpmode_ff.full = dfixed_const(radeon_agpmode); 338362306a36Sopenharmony_ci temp_ff.full = dfixed_const_666(16); 338462306a36Sopenharmony_ci sclk_eff_ff.full -= dfixed_mul(agpmode_ff, temp_ff); 338562306a36Sopenharmony_ci } 338662306a36Sopenharmony_ci /* TODO PCIE lanes may affect this - agpmode == 16?? */ 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 338962306a36Sopenharmony_ci sclk_delay_ff.full = dfixed_const(250); 339062306a36Sopenharmony_ci } else { 339162306a36Sopenharmony_ci if ((rdev->family == CHIP_RV100) || 339262306a36Sopenharmony_ci rdev->flags & RADEON_IS_IGP) { 339362306a36Sopenharmony_ci if (rdev->mc.vram_is_ddr) 339462306a36Sopenharmony_ci sclk_delay_ff.full = dfixed_const(41); 339562306a36Sopenharmony_ci else 339662306a36Sopenharmony_ci sclk_delay_ff.full = dfixed_const(33); 339762306a36Sopenharmony_ci } else { 339862306a36Sopenharmony_ci if (rdev->mc.vram_width == 128) 339962306a36Sopenharmony_ci sclk_delay_ff.full = dfixed_const(57); 340062306a36Sopenharmony_ci else 340162306a36Sopenharmony_ci sclk_delay_ff.full = dfixed_const(41); 340262306a36Sopenharmony_ci } 340362306a36Sopenharmony_ci } 340462306a36Sopenharmony_ci 340562306a36Sopenharmony_ci mc_latency_sclk.full = dfixed_div(sclk_delay_ff, sclk_eff_ff); 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci if (rdev->mc.vram_is_ddr) { 340862306a36Sopenharmony_ci if (rdev->mc.vram_width == 32) { 340962306a36Sopenharmony_ci k1.full = dfixed_const(40); 341062306a36Sopenharmony_ci c = 3; 341162306a36Sopenharmony_ci } else { 341262306a36Sopenharmony_ci k1.full = dfixed_const(20); 341362306a36Sopenharmony_ci c = 1; 341462306a36Sopenharmony_ci } 341562306a36Sopenharmony_ci } else { 341662306a36Sopenharmony_ci k1.full = dfixed_const(40); 341762306a36Sopenharmony_ci c = 3; 341862306a36Sopenharmony_ci } 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci temp_ff.full = dfixed_const(2); 342162306a36Sopenharmony_ci mc_latency_mclk.full = dfixed_mul(trcd_ff, temp_ff); 342262306a36Sopenharmony_ci temp_ff.full = dfixed_const(c); 342362306a36Sopenharmony_ci mc_latency_mclk.full += dfixed_mul(tcas_ff, temp_ff); 342462306a36Sopenharmony_ci temp_ff.full = dfixed_const(4); 342562306a36Sopenharmony_ci mc_latency_mclk.full += dfixed_mul(tras_ff, temp_ff); 342662306a36Sopenharmony_ci mc_latency_mclk.full += dfixed_mul(trp_ff, temp_ff); 342762306a36Sopenharmony_ci mc_latency_mclk.full += k1.full; 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ci mc_latency_mclk.full = dfixed_div(mc_latency_mclk, mclk_ff); 343062306a36Sopenharmony_ci mc_latency_mclk.full += dfixed_div(temp_ff, sclk_eff_ff); 343162306a36Sopenharmony_ci 343262306a36Sopenharmony_ci /* 343362306a36Sopenharmony_ci HW cursor time assuming worst case of full size colour cursor. 343462306a36Sopenharmony_ci */ 343562306a36Sopenharmony_ci temp_ff.full = dfixed_const((2 * (cur_size - (rdev->mc.vram_is_ddr + 1)))); 343662306a36Sopenharmony_ci temp_ff.full += trcd_ff.full; 343762306a36Sopenharmony_ci if (temp_ff.full < tras_ff.full) 343862306a36Sopenharmony_ci temp_ff.full = tras_ff.full; 343962306a36Sopenharmony_ci cur_latency_mclk.full = dfixed_div(temp_ff, mclk_ff); 344062306a36Sopenharmony_ci 344162306a36Sopenharmony_ci temp_ff.full = dfixed_const(cur_size); 344262306a36Sopenharmony_ci cur_latency_sclk.full = dfixed_div(temp_ff, sclk_eff_ff); 344362306a36Sopenharmony_ci /* 344462306a36Sopenharmony_ci Find the total latency for the display data. 344562306a36Sopenharmony_ci */ 344662306a36Sopenharmony_ci disp_latency_overhead.full = dfixed_const(8); 344762306a36Sopenharmony_ci disp_latency_overhead.full = dfixed_div(disp_latency_overhead, sclk_ff); 344862306a36Sopenharmony_ci mc_latency_mclk.full += disp_latency_overhead.full + cur_latency_mclk.full; 344962306a36Sopenharmony_ci mc_latency_sclk.full += disp_latency_overhead.full + cur_latency_sclk.full; 345062306a36Sopenharmony_ci 345162306a36Sopenharmony_ci if (mc_latency_mclk.full > mc_latency_sclk.full) 345262306a36Sopenharmony_ci disp_latency.full = mc_latency_mclk.full; 345362306a36Sopenharmony_ci else 345462306a36Sopenharmony_ci disp_latency.full = mc_latency_sclk.full; 345562306a36Sopenharmony_ci 345662306a36Sopenharmony_ci /* setup Max GRPH_STOP_REQ default value */ 345762306a36Sopenharmony_ci if (ASIC_IS_RV100(rdev)) 345862306a36Sopenharmony_ci max_stop_req = 0x5c; 345962306a36Sopenharmony_ci else 346062306a36Sopenharmony_ci max_stop_req = 0x7c; 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ci if (mode1) { 346362306a36Sopenharmony_ci /* CRTC1 346462306a36Sopenharmony_ci Set GRPH_BUFFER_CNTL register using h/w defined optimal values. 346562306a36Sopenharmony_ci GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ] 346662306a36Sopenharmony_ci */ 346762306a36Sopenharmony_ci stop_req = mode1->hdisplay * pixel_bytes1 / 16; 346862306a36Sopenharmony_ci 346962306a36Sopenharmony_ci if (stop_req > max_stop_req) 347062306a36Sopenharmony_ci stop_req = max_stop_req; 347162306a36Sopenharmony_ci 347262306a36Sopenharmony_ci /* 347362306a36Sopenharmony_ci Find the drain rate of the display buffer. 347462306a36Sopenharmony_ci */ 347562306a36Sopenharmony_ci temp_ff.full = dfixed_const((16/pixel_bytes1)); 347662306a36Sopenharmony_ci disp_drain_rate.full = dfixed_div(pix_clk, temp_ff); 347762306a36Sopenharmony_ci 347862306a36Sopenharmony_ci /* 347962306a36Sopenharmony_ci Find the critical point of the display buffer. 348062306a36Sopenharmony_ci */ 348162306a36Sopenharmony_ci crit_point_ff.full = dfixed_mul(disp_drain_rate, disp_latency); 348262306a36Sopenharmony_ci crit_point_ff.full += dfixed_const_half(0); 348362306a36Sopenharmony_ci 348462306a36Sopenharmony_ci critical_point = dfixed_trunc(crit_point_ff); 348562306a36Sopenharmony_ci 348662306a36Sopenharmony_ci if (rdev->disp_priority == 2) { 348762306a36Sopenharmony_ci critical_point = 0; 348862306a36Sopenharmony_ci } 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_ci /* 349162306a36Sopenharmony_ci The critical point should never be above max_stop_req-4. Setting 349262306a36Sopenharmony_ci GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time. 349362306a36Sopenharmony_ci */ 349462306a36Sopenharmony_ci if (max_stop_req - critical_point < 4) 349562306a36Sopenharmony_ci critical_point = 0; 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_ci if (critical_point == 0 && mode2 && rdev->family == CHIP_R300) { 349862306a36Sopenharmony_ci /* some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/ 349962306a36Sopenharmony_ci critical_point = 0x10; 350062306a36Sopenharmony_ci } 350162306a36Sopenharmony_ci 350262306a36Sopenharmony_ci temp = RREG32(RADEON_GRPH_BUFFER_CNTL); 350362306a36Sopenharmony_ci temp &= ~(RADEON_GRPH_STOP_REQ_MASK); 350462306a36Sopenharmony_ci temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); 350562306a36Sopenharmony_ci temp &= ~(RADEON_GRPH_START_REQ_MASK); 350662306a36Sopenharmony_ci if ((rdev->family == CHIP_R350) && 350762306a36Sopenharmony_ci (stop_req > 0x15)) { 350862306a36Sopenharmony_ci stop_req -= 0x10; 350962306a36Sopenharmony_ci } 351062306a36Sopenharmony_ci temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); 351162306a36Sopenharmony_ci temp |= RADEON_GRPH_BUFFER_SIZE; 351262306a36Sopenharmony_ci temp &= ~(RADEON_GRPH_CRITICAL_CNTL | 351362306a36Sopenharmony_ci RADEON_GRPH_CRITICAL_AT_SOF | 351462306a36Sopenharmony_ci RADEON_GRPH_STOP_CNTL); 351562306a36Sopenharmony_ci /* 351662306a36Sopenharmony_ci Write the result into the register. 351762306a36Sopenharmony_ci */ 351862306a36Sopenharmony_ci WREG32(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) | 351962306a36Sopenharmony_ci (critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT))); 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci#if 0 352262306a36Sopenharmony_ci if ((rdev->family == CHIP_RS400) || 352362306a36Sopenharmony_ci (rdev->family == CHIP_RS480)) { 352462306a36Sopenharmony_ci /* attempt to program RS400 disp regs correctly ??? */ 352562306a36Sopenharmony_ci temp = RREG32(RS400_DISP1_REG_CNTL); 352662306a36Sopenharmony_ci temp &= ~(RS400_DISP1_START_REQ_LEVEL_MASK | 352762306a36Sopenharmony_ci RS400_DISP1_STOP_REQ_LEVEL_MASK); 352862306a36Sopenharmony_ci WREG32(RS400_DISP1_REQ_CNTL1, (temp | 352962306a36Sopenharmony_ci (critical_point << RS400_DISP1_START_REQ_LEVEL_SHIFT) | 353062306a36Sopenharmony_ci (critical_point << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); 353162306a36Sopenharmony_ci temp = RREG32(RS400_DMIF_MEM_CNTL1); 353262306a36Sopenharmony_ci temp &= ~(RS400_DISP1_CRITICAL_POINT_START_MASK | 353362306a36Sopenharmony_ci RS400_DISP1_CRITICAL_POINT_STOP_MASK); 353462306a36Sopenharmony_ci WREG32(RS400_DMIF_MEM_CNTL1, (temp | 353562306a36Sopenharmony_ci (critical_point << RS400_DISP1_CRITICAL_POINT_START_SHIFT) | 353662306a36Sopenharmony_ci (critical_point << RS400_DISP1_CRITICAL_POINT_STOP_SHIFT))); 353762306a36Sopenharmony_ci } 353862306a36Sopenharmony_ci#endif 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci DRM_DEBUG_KMS("GRPH_BUFFER_CNTL from to %x\n", 354162306a36Sopenharmony_ci /* (unsigned int)info->SavedReg->grph_buffer_cntl, */ 354262306a36Sopenharmony_ci (unsigned int)RREG32(RADEON_GRPH_BUFFER_CNTL)); 354362306a36Sopenharmony_ci } 354462306a36Sopenharmony_ci 354562306a36Sopenharmony_ci if (mode2) { 354662306a36Sopenharmony_ci u32 grph2_cntl; 354762306a36Sopenharmony_ci stop_req = mode2->hdisplay * pixel_bytes2 / 16; 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_ci if (stop_req > max_stop_req) 355062306a36Sopenharmony_ci stop_req = max_stop_req; 355162306a36Sopenharmony_ci 355262306a36Sopenharmony_ci /* 355362306a36Sopenharmony_ci Find the drain rate of the display buffer. 355462306a36Sopenharmony_ci */ 355562306a36Sopenharmony_ci temp_ff.full = dfixed_const((16/pixel_bytes2)); 355662306a36Sopenharmony_ci disp_drain_rate2.full = dfixed_div(pix_clk2, temp_ff); 355762306a36Sopenharmony_ci 355862306a36Sopenharmony_ci grph2_cntl = RREG32(RADEON_GRPH2_BUFFER_CNTL); 355962306a36Sopenharmony_ci grph2_cntl &= ~(RADEON_GRPH_STOP_REQ_MASK); 356062306a36Sopenharmony_ci grph2_cntl |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); 356162306a36Sopenharmony_ci grph2_cntl &= ~(RADEON_GRPH_START_REQ_MASK); 356262306a36Sopenharmony_ci if ((rdev->family == CHIP_R350) && 356362306a36Sopenharmony_ci (stop_req > 0x15)) { 356462306a36Sopenharmony_ci stop_req -= 0x10; 356562306a36Sopenharmony_ci } 356662306a36Sopenharmony_ci grph2_cntl |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); 356762306a36Sopenharmony_ci grph2_cntl |= RADEON_GRPH_BUFFER_SIZE; 356862306a36Sopenharmony_ci grph2_cntl &= ~(RADEON_GRPH_CRITICAL_CNTL | 356962306a36Sopenharmony_ci RADEON_GRPH_CRITICAL_AT_SOF | 357062306a36Sopenharmony_ci RADEON_GRPH_STOP_CNTL); 357162306a36Sopenharmony_ci 357262306a36Sopenharmony_ci if ((rdev->family == CHIP_RS100) || 357362306a36Sopenharmony_ci (rdev->family == CHIP_RS200)) 357462306a36Sopenharmony_ci critical_point2 = 0; 357562306a36Sopenharmony_ci else { 357662306a36Sopenharmony_ci temp = (rdev->mc.vram_width * rdev->mc.vram_is_ddr + 1)/128; 357762306a36Sopenharmony_ci temp_ff.full = dfixed_const(temp); 357862306a36Sopenharmony_ci temp_ff.full = dfixed_mul(mclk_ff, temp_ff); 357962306a36Sopenharmony_ci if (sclk_ff.full < temp_ff.full) 358062306a36Sopenharmony_ci temp_ff.full = sclk_ff.full; 358162306a36Sopenharmony_ci 358262306a36Sopenharmony_ci read_return_rate.full = temp_ff.full; 358362306a36Sopenharmony_ci 358462306a36Sopenharmony_ci if (mode1) { 358562306a36Sopenharmony_ci temp_ff.full = read_return_rate.full - disp_drain_rate.full; 358662306a36Sopenharmony_ci time_disp1_drop_priority.full = dfixed_div(crit_point_ff, temp_ff); 358762306a36Sopenharmony_ci } else { 358862306a36Sopenharmony_ci time_disp1_drop_priority.full = 0; 358962306a36Sopenharmony_ci } 359062306a36Sopenharmony_ci crit_point_ff.full = disp_latency.full + time_disp1_drop_priority.full + disp_latency.full; 359162306a36Sopenharmony_ci crit_point_ff.full = dfixed_mul(crit_point_ff, disp_drain_rate2); 359262306a36Sopenharmony_ci crit_point_ff.full += dfixed_const_half(0); 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_ci critical_point2 = dfixed_trunc(crit_point_ff); 359562306a36Sopenharmony_ci 359662306a36Sopenharmony_ci if (rdev->disp_priority == 2) { 359762306a36Sopenharmony_ci critical_point2 = 0; 359862306a36Sopenharmony_ci } 359962306a36Sopenharmony_ci 360062306a36Sopenharmony_ci if (max_stop_req - critical_point2 < 4) 360162306a36Sopenharmony_ci critical_point2 = 0; 360262306a36Sopenharmony_ci 360362306a36Sopenharmony_ci } 360462306a36Sopenharmony_ci 360562306a36Sopenharmony_ci if (critical_point2 == 0 && rdev->family == CHIP_R300) { 360662306a36Sopenharmony_ci /* some R300 cards have problem with this set to 0 */ 360762306a36Sopenharmony_ci critical_point2 = 0x10; 360862306a36Sopenharmony_ci } 360962306a36Sopenharmony_ci 361062306a36Sopenharmony_ci WREG32(RADEON_GRPH2_BUFFER_CNTL, ((grph2_cntl & ~RADEON_GRPH_CRITICAL_POINT_MASK) | 361162306a36Sopenharmony_ci (critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT))); 361262306a36Sopenharmony_ci 361362306a36Sopenharmony_ci if ((rdev->family == CHIP_RS400) || 361462306a36Sopenharmony_ci (rdev->family == CHIP_RS480)) { 361562306a36Sopenharmony_ci#if 0 361662306a36Sopenharmony_ci /* attempt to program RS400 disp2 regs correctly ??? */ 361762306a36Sopenharmony_ci temp = RREG32(RS400_DISP2_REQ_CNTL1); 361862306a36Sopenharmony_ci temp &= ~(RS400_DISP2_START_REQ_LEVEL_MASK | 361962306a36Sopenharmony_ci RS400_DISP2_STOP_REQ_LEVEL_MASK); 362062306a36Sopenharmony_ci WREG32(RS400_DISP2_REQ_CNTL1, (temp | 362162306a36Sopenharmony_ci (critical_point2 << RS400_DISP1_START_REQ_LEVEL_SHIFT) | 362262306a36Sopenharmony_ci (critical_point2 << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); 362362306a36Sopenharmony_ci temp = RREG32(RS400_DISP2_REQ_CNTL2); 362462306a36Sopenharmony_ci temp &= ~(RS400_DISP2_CRITICAL_POINT_START_MASK | 362562306a36Sopenharmony_ci RS400_DISP2_CRITICAL_POINT_STOP_MASK); 362662306a36Sopenharmony_ci WREG32(RS400_DISP2_REQ_CNTL2, (temp | 362762306a36Sopenharmony_ci (critical_point2 << RS400_DISP2_CRITICAL_POINT_START_SHIFT) | 362862306a36Sopenharmony_ci (critical_point2 << RS400_DISP2_CRITICAL_POINT_STOP_SHIFT))); 362962306a36Sopenharmony_ci#endif 363062306a36Sopenharmony_ci WREG32(RS400_DISP2_REQ_CNTL1, 0x105DC1CC); 363162306a36Sopenharmony_ci WREG32(RS400_DISP2_REQ_CNTL2, 0x2749D000); 363262306a36Sopenharmony_ci WREG32(RS400_DMIF_MEM_CNTL1, 0x29CA71DC); 363362306a36Sopenharmony_ci WREG32(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC); 363462306a36Sopenharmony_ci } 363562306a36Sopenharmony_ci 363662306a36Sopenharmony_ci DRM_DEBUG_KMS("GRPH2_BUFFER_CNTL from to %x\n", 363762306a36Sopenharmony_ci (unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL)); 363862306a36Sopenharmony_ci } 363962306a36Sopenharmony_ci 364062306a36Sopenharmony_ci /* Save number of lines the linebuffer leads before the scanout */ 364162306a36Sopenharmony_ci if (mode1) 364262306a36Sopenharmony_ci rdev->mode_info.crtcs[0]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode1->crtc_hdisplay); 364362306a36Sopenharmony_ci 364462306a36Sopenharmony_ci if (mode2) 364562306a36Sopenharmony_ci rdev->mode_info.crtcs[1]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode2->crtc_hdisplay); 364662306a36Sopenharmony_ci} 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ciint r100_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) 364962306a36Sopenharmony_ci{ 365062306a36Sopenharmony_ci uint32_t scratch; 365162306a36Sopenharmony_ci uint32_t tmp = 0; 365262306a36Sopenharmony_ci unsigned i; 365362306a36Sopenharmony_ci int r; 365462306a36Sopenharmony_ci 365562306a36Sopenharmony_ci r = radeon_scratch_get(rdev, &scratch); 365662306a36Sopenharmony_ci if (r) { 365762306a36Sopenharmony_ci DRM_ERROR("radeon: cp failed to get scratch reg (%d).\n", r); 365862306a36Sopenharmony_ci return r; 365962306a36Sopenharmony_ci } 366062306a36Sopenharmony_ci WREG32(scratch, 0xCAFEDEAD); 366162306a36Sopenharmony_ci r = radeon_ring_lock(rdev, ring, 2); 366262306a36Sopenharmony_ci if (r) { 366362306a36Sopenharmony_ci DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); 366462306a36Sopenharmony_ci radeon_scratch_free(rdev, scratch); 366562306a36Sopenharmony_ci return r; 366662306a36Sopenharmony_ci } 366762306a36Sopenharmony_ci radeon_ring_write(ring, PACKET0(scratch, 0)); 366862306a36Sopenharmony_ci radeon_ring_write(ring, 0xDEADBEEF); 366962306a36Sopenharmony_ci radeon_ring_unlock_commit(rdev, ring, false); 367062306a36Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 367162306a36Sopenharmony_ci tmp = RREG32(scratch); 367262306a36Sopenharmony_ci if (tmp == 0xDEADBEEF) { 367362306a36Sopenharmony_ci break; 367462306a36Sopenharmony_ci } 367562306a36Sopenharmony_ci udelay(1); 367662306a36Sopenharmony_ci } 367762306a36Sopenharmony_ci if (i < rdev->usec_timeout) { 367862306a36Sopenharmony_ci DRM_INFO("ring test succeeded in %d usecs\n", i); 367962306a36Sopenharmony_ci } else { 368062306a36Sopenharmony_ci DRM_ERROR("radeon: ring test failed (scratch(0x%04X)=0x%08X)\n", 368162306a36Sopenharmony_ci scratch, tmp); 368262306a36Sopenharmony_ci r = -EINVAL; 368362306a36Sopenharmony_ci } 368462306a36Sopenharmony_ci radeon_scratch_free(rdev, scratch); 368562306a36Sopenharmony_ci return r; 368662306a36Sopenharmony_ci} 368762306a36Sopenharmony_ci 368862306a36Sopenharmony_civoid r100_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) 368962306a36Sopenharmony_ci{ 369062306a36Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; 369162306a36Sopenharmony_ci 369262306a36Sopenharmony_ci if (ring->rptr_save_reg) { 369362306a36Sopenharmony_ci u32 next_rptr = ring->wptr + 2 + 3; 369462306a36Sopenharmony_ci radeon_ring_write(ring, PACKET0(ring->rptr_save_reg, 0)); 369562306a36Sopenharmony_ci radeon_ring_write(ring, next_rptr); 369662306a36Sopenharmony_ci } 369762306a36Sopenharmony_ci 369862306a36Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_CP_IB_BASE, 1)); 369962306a36Sopenharmony_ci radeon_ring_write(ring, ib->gpu_addr); 370062306a36Sopenharmony_ci radeon_ring_write(ring, ib->length_dw); 370162306a36Sopenharmony_ci} 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_ciint r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) 370462306a36Sopenharmony_ci{ 370562306a36Sopenharmony_ci struct radeon_ib ib; 370662306a36Sopenharmony_ci uint32_t scratch; 370762306a36Sopenharmony_ci uint32_t tmp = 0; 370862306a36Sopenharmony_ci unsigned i; 370962306a36Sopenharmony_ci int r; 371062306a36Sopenharmony_ci 371162306a36Sopenharmony_ci r = radeon_scratch_get(rdev, &scratch); 371262306a36Sopenharmony_ci if (r) { 371362306a36Sopenharmony_ci DRM_ERROR("radeon: failed to get scratch reg (%d).\n", r); 371462306a36Sopenharmony_ci return r; 371562306a36Sopenharmony_ci } 371662306a36Sopenharmony_ci WREG32(scratch, 0xCAFEDEAD); 371762306a36Sopenharmony_ci r = radeon_ib_get(rdev, RADEON_RING_TYPE_GFX_INDEX, &ib, NULL, 256); 371862306a36Sopenharmony_ci if (r) { 371962306a36Sopenharmony_ci DRM_ERROR("radeon: failed to get ib (%d).\n", r); 372062306a36Sopenharmony_ci goto free_scratch; 372162306a36Sopenharmony_ci } 372262306a36Sopenharmony_ci ib.ptr[0] = PACKET0(scratch, 0); 372362306a36Sopenharmony_ci ib.ptr[1] = 0xDEADBEEF; 372462306a36Sopenharmony_ci ib.ptr[2] = PACKET2(0); 372562306a36Sopenharmony_ci ib.ptr[3] = PACKET2(0); 372662306a36Sopenharmony_ci ib.ptr[4] = PACKET2(0); 372762306a36Sopenharmony_ci ib.ptr[5] = PACKET2(0); 372862306a36Sopenharmony_ci ib.ptr[6] = PACKET2(0); 372962306a36Sopenharmony_ci ib.ptr[7] = PACKET2(0); 373062306a36Sopenharmony_ci ib.length_dw = 8; 373162306a36Sopenharmony_ci r = radeon_ib_schedule(rdev, &ib, NULL, false); 373262306a36Sopenharmony_ci if (r) { 373362306a36Sopenharmony_ci DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); 373462306a36Sopenharmony_ci goto free_ib; 373562306a36Sopenharmony_ci } 373662306a36Sopenharmony_ci r = radeon_fence_wait_timeout(ib.fence, false, usecs_to_jiffies( 373762306a36Sopenharmony_ci RADEON_USEC_IB_TEST_TIMEOUT)); 373862306a36Sopenharmony_ci if (r < 0) { 373962306a36Sopenharmony_ci DRM_ERROR("radeon: fence wait failed (%d).\n", r); 374062306a36Sopenharmony_ci goto free_ib; 374162306a36Sopenharmony_ci } else if (r == 0) { 374262306a36Sopenharmony_ci DRM_ERROR("radeon: fence wait timed out.\n"); 374362306a36Sopenharmony_ci r = -ETIMEDOUT; 374462306a36Sopenharmony_ci goto free_ib; 374562306a36Sopenharmony_ci } 374662306a36Sopenharmony_ci r = 0; 374762306a36Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 374862306a36Sopenharmony_ci tmp = RREG32(scratch); 374962306a36Sopenharmony_ci if (tmp == 0xDEADBEEF) { 375062306a36Sopenharmony_ci break; 375162306a36Sopenharmony_ci } 375262306a36Sopenharmony_ci udelay(1); 375362306a36Sopenharmony_ci } 375462306a36Sopenharmony_ci if (i < rdev->usec_timeout) { 375562306a36Sopenharmony_ci DRM_INFO("ib test succeeded in %u usecs\n", i); 375662306a36Sopenharmony_ci } else { 375762306a36Sopenharmony_ci DRM_ERROR("radeon: ib test failed (scratch(0x%04X)=0x%08X)\n", 375862306a36Sopenharmony_ci scratch, tmp); 375962306a36Sopenharmony_ci r = -EINVAL; 376062306a36Sopenharmony_ci } 376162306a36Sopenharmony_cifree_ib: 376262306a36Sopenharmony_ci radeon_ib_free(rdev, &ib); 376362306a36Sopenharmony_cifree_scratch: 376462306a36Sopenharmony_ci radeon_scratch_free(rdev, scratch); 376562306a36Sopenharmony_ci return r; 376662306a36Sopenharmony_ci} 376762306a36Sopenharmony_ci 376862306a36Sopenharmony_civoid r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save) 376962306a36Sopenharmony_ci{ 377062306a36Sopenharmony_ci /* Shutdown CP we shouldn't need to do that but better be safe than 377162306a36Sopenharmony_ci * sorry 377262306a36Sopenharmony_ci */ 377362306a36Sopenharmony_ci rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false; 377462306a36Sopenharmony_ci WREG32(R_000740_CP_CSQ_CNTL, 0); 377562306a36Sopenharmony_ci 377662306a36Sopenharmony_ci /* Save few CRTC registers */ 377762306a36Sopenharmony_ci save->GENMO_WT = RREG8(R_0003C2_GENMO_WT); 377862306a36Sopenharmony_ci save->CRTC_EXT_CNTL = RREG32(R_000054_CRTC_EXT_CNTL); 377962306a36Sopenharmony_ci save->CRTC_GEN_CNTL = RREG32(R_000050_CRTC_GEN_CNTL); 378062306a36Sopenharmony_ci save->CUR_OFFSET = RREG32(R_000260_CUR_OFFSET); 378162306a36Sopenharmony_ci if (!(rdev->flags & RADEON_SINGLE_CRTC)) { 378262306a36Sopenharmony_ci save->CRTC2_GEN_CNTL = RREG32(R_0003F8_CRTC2_GEN_CNTL); 378362306a36Sopenharmony_ci save->CUR2_OFFSET = RREG32(R_000360_CUR2_OFFSET); 378462306a36Sopenharmony_ci } 378562306a36Sopenharmony_ci 378662306a36Sopenharmony_ci /* Disable VGA aperture access */ 378762306a36Sopenharmony_ci WREG8(R_0003C2_GENMO_WT, C_0003C2_VGA_RAM_EN & save->GENMO_WT); 378862306a36Sopenharmony_ci /* Disable cursor, overlay, crtc */ 378962306a36Sopenharmony_ci WREG32(R_000260_CUR_OFFSET, save->CUR_OFFSET | S_000260_CUR_LOCK(1)); 379062306a36Sopenharmony_ci WREG32(R_000054_CRTC_EXT_CNTL, save->CRTC_EXT_CNTL | 379162306a36Sopenharmony_ci S_000054_CRTC_DISPLAY_DIS(1)); 379262306a36Sopenharmony_ci WREG32(R_000050_CRTC_GEN_CNTL, 379362306a36Sopenharmony_ci (C_000050_CRTC_CUR_EN & save->CRTC_GEN_CNTL) | 379462306a36Sopenharmony_ci S_000050_CRTC_DISP_REQ_EN_B(1)); 379562306a36Sopenharmony_ci WREG32(R_000420_OV0_SCALE_CNTL, 379662306a36Sopenharmony_ci C_000420_OV0_OVERLAY_EN & RREG32(R_000420_OV0_SCALE_CNTL)); 379762306a36Sopenharmony_ci WREG32(R_000260_CUR_OFFSET, C_000260_CUR_LOCK & save->CUR_OFFSET); 379862306a36Sopenharmony_ci if (!(rdev->flags & RADEON_SINGLE_CRTC)) { 379962306a36Sopenharmony_ci WREG32(R_000360_CUR2_OFFSET, save->CUR2_OFFSET | 380062306a36Sopenharmony_ci S_000360_CUR2_LOCK(1)); 380162306a36Sopenharmony_ci WREG32(R_0003F8_CRTC2_GEN_CNTL, 380262306a36Sopenharmony_ci (C_0003F8_CRTC2_CUR_EN & save->CRTC2_GEN_CNTL) | 380362306a36Sopenharmony_ci S_0003F8_CRTC2_DISPLAY_DIS(1) | 380462306a36Sopenharmony_ci S_0003F8_CRTC2_DISP_REQ_EN_B(1)); 380562306a36Sopenharmony_ci WREG32(R_000360_CUR2_OFFSET, 380662306a36Sopenharmony_ci C_000360_CUR2_LOCK & save->CUR2_OFFSET); 380762306a36Sopenharmony_ci } 380862306a36Sopenharmony_ci} 380962306a36Sopenharmony_ci 381062306a36Sopenharmony_civoid r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save) 381162306a36Sopenharmony_ci{ 381262306a36Sopenharmony_ci /* Update base address for crtc */ 381362306a36Sopenharmony_ci WREG32(R_00023C_DISPLAY_BASE_ADDR, rdev->mc.vram_start); 381462306a36Sopenharmony_ci if (!(rdev->flags & RADEON_SINGLE_CRTC)) { 381562306a36Sopenharmony_ci WREG32(R_00033C_CRTC2_DISPLAY_BASE_ADDR, rdev->mc.vram_start); 381662306a36Sopenharmony_ci } 381762306a36Sopenharmony_ci /* Restore CRTC registers */ 381862306a36Sopenharmony_ci WREG8(R_0003C2_GENMO_WT, save->GENMO_WT); 381962306a36Sopenharmony_ci WREG32(R_000054_CRTC_EXT_CNTL, save->CRTC_EXT_CNTL); 382062306a36Sopenharmony_ci WREG32(R_000050_CRTC_GEN_CNTL, save->CRTC_GEN_CNTL); 382162306a36Sopenharmony_ci if (!(rdev->flags & RADEON_SINGLE_CRTC)) { 382262306a36Sopenharmony_ci WREG32(R_0003F8_CRTC2_GEN_CNTL, save->CRTC2_GEN_CNTL); 382362306a36Sopenharmony_ci } 382462306a36Sopenharmony_ci} 382562306a36Sopenharmony_ci 382662306a36Sopenharmony_civoid r100_vga_render_disable(struct radeon_device *rdev) 382762306a36Sopenharmony_ci{ 382862306a36Sopenharmony_ci u32 tmp; 382962306a36Sopenharmony_ci 383062306a36Sopenharmony_ci tmp = RREG8(R_0003C2_GENMO_WT); 383162306a36Sopenharmony_ci WREG8(R_0003C2_GENMO_WT, C_0003C2_VGA_RAM_EN & tmp); 383262306a36Sopenharmony_ci} 383362306a36Sopenharmony_ci 383462306a36Sopenharmony_cistatic void r100_mc_program(struct radeon_device *rdev) 383562306a36Sopenharmony_ci{ 383662306a36Sopenharmony_ci struct r100_mc_save save; 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_ci /* Stops all mc clients */ 383962306a36Sopenharmony_ci r100_mc_stop(rdev, &save); 384062306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_AGP) { 384162306a36Sopenharmony_ci WREG32(R_00014C_MC_AGP_LOCATION, 384262306a36Sopenharmony_ci S_00014C_MC_AGP_START(rdev->mc.gtt_start >> 16) | 384362306a36Sopenharmony_ci S_00014C_MC_AGP_TOP(rdev->mc.gtt_end >> 16)); 384462306a36Sopenharmony_ci WREG32(R_000170_AGP_BASE, lower_32_bits(rdev->mc.agp_base)); 384562306a36Sopenharmony_ci if (rdev->family > CHIP_RV200) 384662306a36Sopenharmony_ci WREG32(R_00015C_AGP_BASE_2, 384762306a36Sopenharmony_ci upper_32_bits(rdev->mc.agp_base) & 0xff); 384862306a36Sopenharmony_ci } else { 384962306a36Sopenharmony_ci WREG32(R_00014C_MC_AGP_LOCATION, 0x0FFFFFFF); 385062306a36Sopenharmony_ci WREG32(R_000170_AGP_BASE, 0); 385162306a36Sopenharmony_ci if (rdev->family > CHIP_RV200) 385262306a36Sopenharmony_ci WREG32(R_00015C_AGP_BASE_2, 0); 385362306a36Sopenharmony_ci } 385462306a36Sopenharmony_ci /* Wait for mc idle */ 385562306a36Sopenharmony_ci if (r100_mc_wait_for_idle(rdev)) 385662306a36Sopenharmony_ci dev_warn(rdev->dev, "Wait for MC idle timeout.\n"); 385762306a36Sopenharmony_ci /* Program MC, should be a 32bits limited address space */ 385862306a36Sopenharmony_ci WREG32(R_000148_MC_FB_LOCATION, 385962306a36Sopenharmony_ci S_000148_MC_FB_START(rdev->mc.vram_start >> 16) | 386062306a36Sopenharmony_ci S_000148_MC_FB_TOP(rdev->mc.vram_end >> 16)); 386162306a36Sopenharmony_ci r100_mc_resume(rdev, &save); 386262306a36Sopenharmony_ci} 386362306a36Sopenharmony_ci 386462306a36Sopenharmony_cistatic void r100_clock_startup(struct radeon_device *rdev) 386562306a36Sopenharmony_ci{ 386662306a36Sopenharmony_ci u32 tmp; 386762306a36Sopenharmony_ci 386862306a36Sopenharmony_ci if (radeon_dynclks != -1 && radeon_dynclks) 386962306a36Sopenharmony_ci radeon_legacy_set_clock_gating(rdev, 1); 387062306a36Sopenharmony_ci /* We need to force on some of the block */ 387162306a36Sopenharmony_ci tmp = RREG32_PLL(R_00000D_SCLK_CNTL); 387262306a36Sopenharmony_ci tmp |= S_00000D_FORCE_CP(1) | S_00000D_FORCE_VIP(1); 387362306a36Sopenharmony_ci if ((rdev->family == CHIP_RV250) || (rdev->family == CHIP_RV280)) 387462306a36Sopenharmony_ci tmp |= S_00000D_FORCE_DISP1(1) | S_00000D_FORCE_DISP2(1); 387562306a36Sopenharmony_ci WREG32_PLL(R_00000D_SCLK_CNTL, tmp); 387662306a36Sopenharmony_ci} 387762306a36Sopenharmony_ci 387862306a36Sopenharmony_cistatic int r100_startup(struct radeon_device *rdev) 387962306a36Sopenharmony_ci{ 388062306a36Sopenharmony_ci int r; 388162306a36Sopenharmony_ci 388262306a36Sopenharmony_ci /* set common regs */ 388362306a36Sopenharmony_ci r100_set_common_regs(rdev); 388462306a36Sopenharmony_ci /* program mc */ 388562306a36Sopenharmony_ci r100_mc_program(rdev); 388662306a36Sopenharmony_ci /* Resume clock */ 388762306a36Sopenharmony_ci r100_clock_startup(rdev); 388862306a36Sopenharmony_ci /* Initialize GART (initialize after TTM so we can allocate 388962306a36Sopenharmony_ci * memory through TTM but finalize after TTM) */ 389062306a36Sopenharmony_ci r100_enable_bm(rdev); 389162306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_PCI) { 389262306a36Sopenharmony_ci r = r100_pci_gart_enable(rdev); 389362306a36Sopenharmony_ci if (r) 389462306a36Sopenharmony_ci return r; 389562306a36Sopenharmony_ci } 389662306a36Sopenharmony_ci 389762306a36Sopenharmony_ci /* allocate wb buffer */ 389862306a36Sopenharmony_ci r = radeon_wb_init(rdev); 389962306a36Sopenharmony_ci if (r) 390062306a36Sopenharmony_ci return r; 390162306a36Sopenharmony_ci 390262306a36Sopenharmony_ci r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX); 390362306a36Sopenharmony_ci if (r) { 390462306a36Sopenharmony_ci dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r); 390562306a36Sopenharmony_ci return r; 390662306a36Sopenharmony_ci } 390762306a36Sopenharmony_ci 390862306a36Sopenharmony_ci /* Enable IRQ */ 390962306a36Sopenharmony_ci if (!rdev->irq.installed) { 391062306a36Sopenharmony_ci r = radeon_irq_kms_init(rdev); 391162306a36Sopenharmony_ci if (r) 391262306a36Sopenharmony_ci return r; 391362306a36Sopenharmony_ci } 391462306a36Sopenharmony_ci 391562306a36Sopenharmony_ci r100_irq_set(rdev); 391662306a36Sopenharmony_ci rdev->config.r100.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); 391762306a36Sopenharmony_ci /* 1M ring buffer */ 391862306a36Sopenharmony_ci r = r100_cp_init(rdev, 1024 * 1024); 391962306a36Sopenharmony_ci if (r) { 392062306a36Sopenharmony_ci dev_err(rdev->dev, "failed initializing CP (%d).\n", r); 392162306a36Sopenharmony_ci return r; 392262306a36Sopenharmony_ci } 392362306a36Sopenharmony_ci 392462306a36Sopenharmony_ci r = radeon_ib_pool_init(rdev); 392562306a36Sopenharmony_ci if (r) { 392662306a36Sopenharmony_ci dev_err(rdev->dev, "IB initialization failed (%d).\n", r); 392762306a36Sopenharmony_ci return r; 392862306a36Sopenharmony_ci } 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_ci return 0; 393162306a36Sopenharmony_ci} 393262306a36Sopenharmony_ci 393362306a36Sopenharmony_ciint r100_resume(struct radeon_device *rdev) 393462306a36Sopenharmony_ci{ 393562306a36Sopenharmony_ci int r; 393662306a36Sopenharmony_ci 393762306a36Sopenharmony_ci /* Make sur GART are not working */ 393862306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_PCI) 393962306a36Sopenharmony_ci r100_pci_gart_disable(rdev); 394062306a36Sopenharmony_ci /* Resume clock before doing reset */ 394162306a36Sopenharmony_ci r100_clock_startup(rdev); 394262306a36Sopenharmony_ci /* Reset gpu before posting otherwise ATOM will enter infinite loop */ 394362306a36Sopenharmony_ci if (radeon_asic_reset(rdev)) { 394462306a36Sopenharmony_ci dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", 394562306a36Sopenharmony_ci RREG32(R_000E40_RBBM_STATUS), 394662306a36Sopenharmony_ci RREG32(R_0007C0_CP_STAT)); 394762306a36Sopenharmony_ci } 394862306a36Sopenharmony_ci /* post */ 394962306a36Sopenharmony_ci radeon_combios_asic_init(rdev->ddev); 395062306a36Sopenharmony_ci /* Resume clock after posting */ 395162306a36Sopenharmony_ci r100_clock_startup(rdev); 395262306a36Sopenharmony_ci /* Initialize surface registers */ 395362306a36Sopenharmony_ci radeon_surface_init(rdev); 395462306a36Sopenharmony_ci 395562306a36Sopenharmony_ci rdev->accel_working = true; 395662306a36Sopenharmony_ci r = r100_startup(rdev); 395762306a36Sopenharmony_ci if (r) { 395862306a36Sopenharmony_ci rdev->accel_working = false; 395962306a36Sopenharmony_ci } 396062306a36Sopenharmony_ci return r; 396162306a36Sopenharmony_ci} 396262306a36Sopenharmony_ci 396362306a36Sopenharmony_ciint r100_suspend(struct radeon_device *rdev) 396462306a36Sopenharmony_ci{ 396562306a36Sopenharmony_ci radeon_pm_suspend(rdev); 396662306a36Sopenharmony_ci r100_cp_disable(rdev); 396762306a36Sopenharmony_ci radeon_wb_disable(rdev); 396862306a36Sopenharmony_ci r100_irq_disable(rdev); 396962306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_PCI) 397062306a36Sopenharmony_ci r100_pci_gart_disable(rdev); 397162306a36Sopenharmony_ci return 0; 397262306a36Sopenharmony_ci} 397362306a36Sopenharmony_ci 397462306a36Sopenharmony_civoid r100_fini(struct radeon_device *rdev) 397562306a36Sopenharmony_ci{ 397662306a36Sopenharmony_ci radeon_pm_fini(rdev); 397762306a36Sopenharmony_ci r100_cp_fini(rdev); 397862306a36Sopenharmony_ci radeon_wb_fini(rdev); 397962306a36Sopenharmony_ci radeon_ib_pool_fini(rdev); 398062306a36Sopenharmony_ci radeon_gem_fini(rdev); 398162306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_PCI) 398262306a36Sopenharmony_ci r100_pci_gart_fini(rdev); 398362306a36Sopenharmony_ci radeon_agp_fini(rdev); 398462306a36Sopenharmony_ci radeon_irq_kms_fini(rdev); 398562306a36Sopenharmony_ci radeon_fence_driver_fini(rdev); 398662306a36Sopenharmony_ci radeon_bo_fini(rdev); 398762306a36Sopenharmony_ci radeon_atombios_fini(rdev); 398862306a36Sopenharmony_ci kfree(rdev->bios); 398962306a36Sopenharmony_ci rdev->bios = NULL; 399062306a36Sopenharmony_ci} 399162306a36Sopenharmony_ci 399262306a36Sopenharmony_ci/* 399362306a36Sopenharmony_ci * Due to how kexec works, it can leave the hw fully initialised when it 399462306a36Sopenharmony_ci * boots the new kernel. However doing our init sequence with the CP and 399562306a36Sopenharmony_ci * WB stuff setup causes GPU hangs on the RN50 at least. So at startup 399662306a36Sopenharmony_ci * do some quick sanity checks and restore sane values to avoid this 399762306a36Sopenharmony_ci * problem. 399862306a36Sopenharmony_ci */ 399962306a36Sopenharmony_civoid r100_restore_sanity(struct radeon_device *rdev) 400062306a36Sopenharmony_ci{ 400162306a36Sopenharmony_ci u32 tmp; 400262306a36Sopenharmony_ci 400362306a36Sopenharmony_ci tmp = RREG32(RADEON_CP_CSQ_CNTL); 400462306a36Sopenharmony_ci if (tmp) { 400562306a36Sopenharmony_ci WREG32(RADEON_CP_CSQ_CNTL, 0); 400662306a36Sopenharmony_ci } 400762306a36Sopenharmony_ci tmp = RREG32(RADEON_CP_RB_CNTL); 400862306a36Sopenharmony_ci if (tmp) { 400962306a36Sopenharmony_ci WREG32(RADEON_CP_RB_CNTL, 0); 401062306a36Sopenharmony_ci } 401162306a36Sopenharmony_ci tmp = RREG32(RADEON_SCRATCH_UMSK); 401262306a36Sopenharmony_ci if (tmp) { 401362306a36Sopenharmony_ci WREG32(RADEON_SCRATCH_UMSK, 0); 401462306a36Sopenharmony_ci } 401562306a36Sopenharmony_ci} 401662306a36Sopenharmony_ci 401762306a36Sopenharmony_ciint r100_init(struct radeon_device *rdev) 401862306a36Sopenharmony_ci{ 401962306a36Sopenharmony_ci int r; 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_ci /* Register debugfs file specific to this group of asics */ 402262306a36Sopenharmony_ci r100_debugfs_mc_info_init(rdev); 402362306a36Sopenharmony_ci /* Disable VGA */ 402462306a36Sopenharmony_ci r100_vga_render_disable(rdev); 402562306a36Sopenharmony_ci /* Initialize scratch registers */ 402662306a36Sopenharmony_ci radeon_scratch_init(rdev); 402762306a36Sopenharmony_ci /* Initialize surface registers */ 402862306a36Sopenharmony_ci radeon_surface_init(rdev); 402962306a36Sopenharmony_ci /* sanity check some register to avoid hangs like after kexec */ 403062306a36Sopenharmony_ci r100_restore_sanity(rdev); 403162306a36Sopenharmony_ci /* TODO: disable VGA need to use VGA request */ 403262306a36Sopenharmony_ci /* BIOS*/ 403362306a36Sopenharmony_ci if (!radeon_get_bios(rdev)) { 403462306a36Sopenharmony_ci if (ASIC_IS_AVIVO(rdev)) 403562306a36Sopenharmony_ci return -EINVAL; 403662306a36Sopenharmony_ci } 403762306a36Sopenharmony_ci if (rdev->is_atom_bios) { 403862306a36Sopenharmony_ci dev_err(rdev->dev, "Expecting combios for RS400/RS480 GPU\n"); 403962306a36Sopenharmony_ci return -EINVAL; 404062306a36Sopenharmony_ci } else { 404162306a36Sopenharmony_ci r = radeon_combios_init(rdev); 404262306a36Sopenharmony_ci if (r) 404362306a36Sopenharmony_ci return r; 404462306a36Sopenharmony_ci } 404562306a36Sopenharmony_ci /* Reset gpu before posting otherwise ATOM will enter infinite loop */ 404662306a36Sopenharmony_ci if (radeon_asic_reset(rdev)) { 404762306a36Sopenharmony_ci dev_warn(rdev->dev, 404862306a36Sopenharmony_ci "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", 404962306a36Sopenharmony_ci RREG32(R_000E40_RBBM_STATUS), 405062306a36Sopenharmony_ci RREG32(R_0007C0_CP_STAT)); 405162306a36Sopenharmony_ci } 405262306a36Sopenharmony_ci /* check if cards are posted or not */ 405362306a36Sopenharmony_ci if (radeon_boot_test_post_card(rdev) == false) 405462306a36Sopenharmony_ci return -EINVAL; 405562306a36Sopenharmony_ci /* Set asic errata */ 405662306a36Sopenharmony_ci r100_errata(rdev); 405762306a36Sopenharmony_ci /* Initialize clocks */ 405862306a36Sopenharmony_ci radeon_get_clock_info(rdev->ddev); 405962306a36Sopenharmony_ci /* initialize AGP */ 406062306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_AGP) { 406162306a36Sopenharmony_ci r = radeon_agp_init(rdev); 406262306a36Sopenharmony_ci if (r) { 406362306a36Sopenharmony_ci radeon_agp_disable(rdev); 406462306a36Sopenharmony_ci } 406562306a36Sopenharmony_ci } 406662306a36Sopenharmony_ci /* initialize VRAM */ 406762306a36Sopenharmony_ci r100_mc_init(rdev); 406862306a36Sopenharmony_ci /* Fence driver */ 406962306a36Sopenharmony_ci radeon_fence_driver_init(rdev); 407062306a36Sopenharmony_ci /* Memory manager */ 407162306a36Sopenharmony_ci r = radeon_bo_init(rdev); 407262306a36Sopenharmony_ci if (r) 407362306a36Sopenharmony_ci return r; 407462306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_PCI) { 407562306a36Sopenharmony_ci r = r100_pci_gart_init(rdev); 407662306a36Sopenharmony_ci if (r) 407762306a36Sopenharmony_ci return r; 407862306a36Sopenharmony_ci } 407962306a36Sopenharmony_ci r100_set_safe_registers(rdev); 408062306a36Sopenharmony_ci 408162306a36Sopenharmony_ci /* Initialize power management */ 408262306a36Sopenharmony_ci radeon_pm_init(rdev); 408362306a36Sopenharmony_ci 408462306a36Sopenharmony_ci rdev->accel_working = true; 408562306a36Sopenharmony_ci r = r100_startup(rdev); 408662306a36Sopenharmony_ci if (r) { 408762306a36Sopenharmony_ci /* Somethings want wront with the accel init stop accel */ 408862306a36Sopenharmony_ci dev_err(rdev->dev, "Disabling GPU acceleration\n"); 408962306a36Sopenharmony_ci r100_cp_fini(rdev); 409062306a36Sopenharmony_ci radeon_wb_fini(rdev); 409162306a36Sopenharmony_ci radeon_ib_pool_fini(rdev); 409262306a36Sopenharmony_ci radeon_irq_kms_fini(rdev); 409362306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_PCI) 409462306a36Sopenharmony_ci r100_pci_gart_fini(rdev); 409562306a36Sopenharmony_ci rdev->accel_working = false; 409662306a36Sopenharmony_ci } 409762306a36Sopenharmony_ci return 0; 409862306a36Sopenharmony_ci} 409962306a36Sopenharmony_ci 410062306a36Sopenharmony_ciuint32_t r100_mm_rreg_slow(struct radeon_device *rdev, uint32_t reg) 410162306a36Sopenharmony_ci{ 410262306a36Sopenharmony_ci unsigned long flags; 410362306a36Sopenharmony_ci uint32_t ret; 410462306a36Sopenharmony_ci 410562306a36Sopenharmony_ci spin_lock_irqsave(&rdev->mmio_idx_lock, flags); 410662306a36Sopenharmony_ci writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); 410762306a36Sopenharmony_ci ret = readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); 410862306a36Sopenharmony_ci spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); 410962306a36Sopenharmony_ci return ret; 411062306a36Sopenharmony_ci} 411162306a36Sopenharmony_ci 411262306a36Sopenharmony_civoid r100_mm_wreg_slow(struct radeon_device *rdev, uint32_t reg, uint32_t v) 411362306a36Sopenharmony_ci{ 411462306a36Sopenharmony_ci unsigned long flags; 411562306a36Sopenharmony_ci 411662306a36Sopenharmony_ci spin_lock_irqsave(&rdev->mmio_idx_lock, flags); 411762306a36Sopenharmony_ci writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); 411862306a36Sopenharmony_ci writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); 411962306a36Sopenharmony_ci spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); 412062306a36Sopenharmony_ci} 412162306a36Sopenharmony_ci 412262306a36Sopenharmony_ciu32 r100_io_rreg(struct radeon_device *rdev, u32 reg) 412362306a36Sopenharmony_ci{ 412462306a36Sopenharmony_ci if (reg < rdev->rio_mem_size) 412562306a36Sopenharmony_ci return ioread32(rdev->rio_mem + reg); 412662306a36Sopenharmony_ci else { 412762306a36Sopenharmony_ci iowrite32(reg, rdev->rio_mem + RADEON_MM_INDEX); 412862306a36Sopenharmony_ci return ioread32(rdev->rio_mem + RADEON_MM_DATA); 412962306a36Sopenharmony_ci } 413062306a36Sopenharmony_ci} 413162306a36Sopenharmony_ci 413262306a36Sopenharmony_civoid r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v) 413362306a36Sopenharmony_ci{ 413462306a36Sopenharmony_ci if (reg < rdev->rio_mem_size) 413562306a36Sopenharmony_ci iowrite32(v, rdev->rio_mem + reg); 413662306a36Sopenharmony_ci else { 413762306a36Sopenharmony_ci iowrite32(reg, rdev->rio_mem + RADEON_MM_INDEX); 413862306a36Sopenharmony_ci iowrite32(v, rdev->rio_mem + RADEON_MM_DATA); 413962306a36Sopenharmony_ci } 414062306a36Sopenharmony_ci} 4141