18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2008 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * Copyright 2008 Red Hat Inc. 48c2ecf20Sopenharmony_ci * Copyright 2009 Jerome Glisse. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 88c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 98c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 108c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 118c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 148c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 178c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 188c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 198c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 208c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 218c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 228c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Authors: Dave Airlie 258c2ecf20Sopenharmony_ci * Alex Deucher 268c2ecf20Sopenharmony_ci * Jerome Glisse 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <linux/firmware.h> 308c2ecf20Sopenharmony_ci#include <linux/module.h> 318c2ecf20Sopenharmony_ci#include <linux/pci.h> 328c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 338c2ecf20Sopenharmony_ci#include <linux/slab.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <drm/drm_debugfs.h> 368c2ecf20Sopenharmony_ci#include <drm/drm_device.h> 378c2ecf20Sopenharmony_ci#include <drm/drm_file.h> 388c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 398c2ecf20Sopenharmony_ci#include <drm/drm_vblank.h> 408c2ecf20Sopenharmony_ci#include <drm/radeon_drm.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include "atom.h" 438c2ecf20Sopenharmony_ci#include "r100_reg_safe.h" 448c2ecf20Sopenharmony_ci#include "r100d.h" 458c2ecf20Sopenharmony_ci#include "radeon.h" 468c2ecf20Sopenharmony_ci#include "radeon_asic.h" 478c2ecf20Sopenharmony_ci#include "radeon_reg.h" 488c2ecf20Sopenharmony_ci#include "rn50_reg_safe.h" 498c2ecf20Sopenharmony_ci#include "rs100d.h" 508c2ecf20Sopenharmony_ci#include "rv200d.h" 518c2ecf20Sopenharmony_ci#include "rv250d.h" 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* Firmware Names */ 548c2ecf20Sopenharmony_ci#define FIRMWARE_R100 "radeon/R100_cp.bin" 558c2ecf20Sopenharmony_ci#define FIRMWARE_R200 "radeon/R200_cp.bin" 568c2ecf20Sopenharmony_ci#define FIRMWARE_R300 "radeon/R300_cp.bin" 578c2ecf20Sopenharmony_ci#define FIRMWARE_R420 "radeon/R420_cp.bin" 588c2ecf20Sopenharmony_ci#define FIRMWARE_RS690 "radeon/RS690_cp.bin" 598c2ecf20Sopenharmony_ci#define FIRMWARE_RS600 "radeon/RS600_cp.bin" 608c2ecf20Sopenharmony_ci#define FIRMWARE_R520 "radeon/R520_cp.bin" 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_R100); 638c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_R200); 648c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_R300); 658c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_R420); 668c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RS690); 678c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RS600); 688c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_R520); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#include "r100_track.h" 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* This files gather functions specifics to: 738c2ecf20Sopenharmony_ci * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 748c2ecf20Sopenharmony_ci * and others in some cases. 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic bool r100_is_in_vblank(struct radeon_device *rdev, int crtc) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci if (crtc == 0) { 808c2ecf20Sopenharmony_ci if (RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR) 818c2ecf20Sopenharmony_ci return true; 828c2ecf20Sopenharmony_ci else 838c2ecf20Sopenharmony_ci return false; 848c2ecf20Sopenharmony_ci } else { 858c2ecf20Sopenharmony_ci if (RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR) 868c2ecf20Sopenharmony_ci return true; 878c2ecf20Sopenharmony_ci else 888c2ecf20Sopenharmony_ci return false; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic bool r100_is_counter_moving(struct radeon_device *rdev, int crtc) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci u32 vline1, vline2; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (crtc == 0) { 978c2ecf20Sopenharmony_ci vline1 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; 988c2ecf20Sopenharmony_ci vline2 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; 998c2ecf20Sopenharmony_ci } else { 1008c2ecf20Sopenharmony_ci vline1 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; 1018c2ecf20Sopenharmony_ci vline2 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci if (vline1 != vline2) 1048c2ecf20Sopenharmony_ci return true; 1058c2ecf20Sopenharmony_ci else 1068c2ecf20Sopenharmony_ci return false; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/** 1108c2ecf20Sopenharmony_ci * r100_wait_for_vblank - vblank wait asic callback. 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 1138c2ecf20Sopenharmony_ci * @crtc: crtc to wait for vblank on 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * Wait for vblank on the requested crtc (r1xx-r4xx). 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_civoid r100_wait_for_vblank(struct radeon_device *rdev, int crtc) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci unsigned i = 0; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (crtc >= rdev->num_crtc) 1228c2ecf20Sopenharmony_ci return; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (crtc == 0) { 1258c2ecf20Sopenharmony_ci if (!(RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN)) 1268c2ecf20Sopenharmony_ci return; 1278c2ecf20Sopenharmony_ci } else { 1288c2ecf20Sopenharmony_ci if (!(RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_EN)) 1298c2ecf20Sopenharmony_ci return; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* depending on when we hit vblank, we may be close to active; if so, 1338c2ecf20Sopenharmony_ci * wait for another frame. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci while (r100_is_in_vblank(rdev, crtc)) { 1368c2ecf20Sopenharmony_ci if (i++ % 100 == 0) { 1378c2ecf20Sopenharmony_ci if (!r100_is_counter_moving(rdev, crtc)) 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci while (!r100_is_in_vblank(rdev, crtc)) { 1438c2ecf20Sopenharmony_ci if (i++ % 100 == 0) { 1448c2ecf20Sopenharmony_ci if (!r100_is_counter_moving(rdev, crtc)) 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/** 1518c2ecf20Sopenharmony_ci * r100_page_flip - pageflip callback. 1528c2ecf20Sopenharmony_ci * 1538c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 1548c2ecf20Sopenharmony_ci * @crtc_id: crtc to cleanup pageflip on 1558c2ecf20Sopenharmony_ci * @crtc_base: new address of the crtc (GPU MC address) 1568c2ecf20Sopenharmony_ci * 1578c2ecf20Sopenharmony_ci * Does the actual pageflip (r1xx-r4xx). 1588c2ecf20Sopenharmony_ci * During vblank we take the crtc lock and wait for the update_pending 1598c2ecf20Sopenharmony_ci * bit to go high, when it does, we release the lock, and allow the 1608c2ecf20Sopenharmony_ci * double buffered update to take place. 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_civoid r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base, bool async) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; 1658c2ecf20Sopenharmony_ci u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK; 1668c2ecf20Sopenharmony_ci int i; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Lock the graphics update lock */ 1698c2ecf20Sopenharmony_ci /* update the scanout addresses */ 1708c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* Wait for update_pending to go high. */ 1738c2ecf20Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 1748c2ecf20Sopenharmony_ci if (RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET) 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci udelay(1); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* Unlock the lock, so double-buffering can take place inside vblank */ 1818c2ecf20Sopenharmony_ci tmp &= ~RADEON_CRTC_OFFSET__OFFSET_LOCK; 1828c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/** 1878c2ecf20Sopenharmony_ci * r100_page_flip_pending - check if page flip is still pending 1888c2ecf20Sopenharmony_ci * 1898c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 1908c2ecf20Sopenharmony_ci * @crtc_id: crtc to check 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * Check if the last pagefilp is still pending (r1xx-r4xx). 1938c2ecf20Sopenharmony_ci * Returns the current update pending status. 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_cibool r100_page_flip_pending(struct radeon_device *rdev, int crtc_id) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Return current update_pending status: */ 2008c2ecf20Sopenharmony_ci return !!(RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & 2018c2ecf20Sopenharmony_ci RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/** 2058c2ecf20Sopenharmony_ci * r100_pm_get_dynpm_state - look up dynpm power state callback. 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 2088c2ecf20Sopenharmony_ci * 2098c2ecf20Sopenharmony_ci * Look up the optimal power state based on the 2108c2ecf20Sopenharmony_ci * current state of the GPU (r1xx-r5xx). 2118c2ecf20Sopenharmony_ci * Used for dynpm only. 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_civoid r100_pm_get_dynpm_state(struct radeon_device *rdev) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci int i; 2168c2ecf20Sopenharmony_ci rdev->pm.dynpm_can_upclock = true; 2178c2ecf20Sopenharmony_ci rdev->pm.dynpm_can_downclock = true; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci switch (rdev->pm.dynpm_planned_action) { 2208c2ecf20Sopenharmony_ci case DYNPM_ACTION_MINIMUM: 2218c2ecf20Sopenharmony_ci rdev->pm.requested_power_state_index = 0; 2228c2ecf20Sopenharmony_ci rdev->pm.dynpm_can_downclock = false; 2238c2ecf20Sopenharmony_ci break; 2248c2ecf20Sopenharmony_ci case DYNPM_ACTION_DOWNCLOCK: 2258c2ecf20Sopenharmony_ci if (rdev->pm.current_power_state_index == 0) { 2268c2ecf20Sopenharmony_ci rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; 2278c2ecf20Sopenharmony_ci rdev->pm.dynpm_can_downclock = false; 2288c2ecf20Sopenharmony_ci } else { 2298c2ecf20Sopenharmony_ci if (rdev->pm.active_crtc_count > 1) { 2308c2ecf20Sopenharmony_ci for (i = 0; i < rdev->pm.num_power_states; i++) { 2318c2ecf20Sopenharmony_ci if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) 2328c2ecf20Sopenharmony_ci continue; 2338c2ecf20Sopenharmony_ci else if (i >= rdev->pm.current_power_state_index) { 2348c2ecf20Sopenharmony_ci rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci } else { 2378c2ecf20Sopenharmony_ci rdev->pm.requested_power_state_index = i; 2388c2ecf20Sopenharmony_ci break; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci } else 2428c2ecf20Sopenharmony_ci rdev->pm.requested_power_state_index = 2438c2ecf20Sopenharmony_ci rdev->pm.current_power_state_index - 1; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci /* don't use the power state if crtcs are active and no display flag is set */ 2468c2ecf20Sopenharmony_ci if ((rdev->pm.active_crtc_count > 0) && 2478c2ecf20Sopenharmony_ci (rdev->pm.power_state[rdev->pm.requested_power_state_index].clock_info[0].flags & 2488c2ecf20Sopenharmony_ci RADEON_PM_MODE_NO_DISPLAY)) { 2498c2ecf20Sopenharmony_ci rdev->pm.requested_power_state_index++; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci case DYNPM_ACTION_UPCLOCK: 2538c2ecf20Sopenharmony_ci if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { 2548c2ecf20Sopenharmony_ci rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; 2558c2ecf20Sopenharmony_ci rdev->pm.dynpm_can_upclock = false; 2568c2ecf20Sopenharmony_ci } else { 2578c2ecf20Sopenharmony_ci if (rdev->pm.active_crtc_count > 1) { 2588c2ecf20Sopenharmony_ci for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { 2598c2ecf20Sopenharmony_ci if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) 2608c2ecf20Sopenharmony_ci continue; 2618c2ecf20Sopenharmony_ci else if (i <= rdev->pm.current_power_state_index) { 2628c2ecf20Sopenharmony_ci rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci } else { 2658c2ecf20Sopenharmony_ci rdev->pm.requested_power_state_index = i; 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci } else 2708c2ecf20Sopenharmony_ci rdev->pm.requested_power_state_index = 2718c2ecf20Sopenharmony_ci rdev->pm.current_power_state_index + 1; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci case DYNPM_ACTION_DEFAULT: 2758c2ecf20Sopenharmony_ci rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; 2768c2ecf20Sopenharmony_ci rdev->pm.dynpm_can_upclock = false; 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci case DYNPM_ACTION_NONE: 2798c2ecf20Sopenharmony_ci default: 2808c2ecf20Sopenharmony_ci DRM_ERROR("Requested mode for not defined action\n"); 2818c2ecf20Sopenharmony_ci return; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci /* only one clock mode per power state */ 2848c2ecf20Sopenharmony_ci rdev->pm.requested_clock_mode_index = 0; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Requested: e: %d m: %d p: %d\n", 2878c2ecf20Sopenharmony_ci rdev->pm.power_state[rdev->pm.requested_power_state_index]. 2888c2ecf20Sopenharmony_ci clock_info[rdev->pm.requested_clock_mode_index].sclk, 2898c2ecf20Sopenharmony_ci rdev->pm.power_state[rdev->pm.requested_power_state_index]. 2908c2ecf20Sopenharmony_ci clock_info[rdev->pm.requested_clock_mode_index].mclk, 2918c2ecf20Sopenharmony_ci rdev->pm.power_state[rdev->pm.requested_power_state_index]. 2928c2ecf20Sopenharmony_ci pcie_lanes); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/** 2968c2ecf20Sopenharmony_ci * r100_pm_init_profile - Initialize power profiles callback. 2978c2ecf20Sopenharmony_ci * 2988c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 2998c2ecf20Sopenharmony_ci * 3008c2ecf20Sopenharmony_ci * Initialize the power states used in profile mode 3018c2ecf20Sopenharmony_ci * (r1xx-r3xx). 3028c2ecf20Sopenharmony_ci * Used for profile mode only. 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_civoid r100_pm_init_profile(struct radeon_device *rdev) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci /* default */ 3078c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; 3088c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; 3098c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; 3108c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; 3118c2ecf20Sopenharmony_ci /* low sh */ 3128c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0; 3138c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0; 3148c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; 3158c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; 3168c2ecf20Sopenharmony_ci /* mid sh */ 3178c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 0; 3188c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 0; 3198c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; 3208c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; 3218c2ecf20Sopenharmony_ci /* high sh */ 3228c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0; 3238c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; 3248c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; 3258c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; 3268c2ecf20Sopenharmony_ci /* low mh */ 3278c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0; 3288c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; 3298c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; 3308c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; 3318c2ecf20Sopenharmony_ci /* mid mh */ 3328c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 0; 3338c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; 3348c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; 3358c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; 3368c2ecf20Sopenharmony_ci /* high mh */ 3378c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0; 3388c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; 3398c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; 3408c2ecf20Sopenharmony_ci rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci/** 3448c2ecf20Sopenharmony_ci * r100_pm_misc - set additional pm hw parameters callback. 3458c2ecf20Sopenharmony_ci * 3468c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 3478c2ecf20Sopenharmony_ci * 3488c2ecf20Sopenharmony_ci * Set non-clock parameters associated with a power state 3498c2ecf20Sopenharmony_ci * (voltage, pcie lanes, etc.) (r1xx-r4xx). 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_civoid r100_pm_misc(struct radeon_device *rdev) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci int requested_index = rdev->pm.requested_power_state_index; 3548c2ecf20Sopenharmony_ci struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; 3558c2ecf20Sopenharmony_ci struct radeon_voltage *voltage = &ps->clock_info[0].voltage; 3568c2ecf20Sopenharmony_ci u32 tmp, sclk_cntl, sclk_cntl2, sclk_more_cntl; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if ((voltage->type == VOLTAGE_GPIO) && (voltage->gpio.valid)) { 3598c2ecf20Sopenharmony_ci if (ps->misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { 3608c2ecf20Sopenharmony_ci tmp = RREG32(voltage->gpio.reg); 3618c2ecf20Sopenharmony_ci if (voltage->active_high) 3628c2ecf20Sopenharmony_ci tmp |= voltage->gpio.mask; 3638c2ecf20Sopenharmony_ci else 3648c2ecf20Sopenharmony_ci tmp &= ~(voltage->gpio.mask); 3658c2ecf20Sopenharmony_ci WREG32(voltage->gpio.reg, tmp); 3668c2ecf20Sopenharmony_ci if (voltage->delay) 3678c2ecf20Sopenharmony_ci udelay(voltage->delay); 3688c2ecf20Sopenharmony_ci } else { 3698c2ecf20Sopenharmony_ci tmp = RREG32(voltage->gpio.reg); 3708c2ecf20Sopenharmony_ci if (voltage->active_high) 3718c2ecf20Sopenharmony_ci tmp &= ~voltage->gpio.mask; 3728c2ecf20Sopenharmony_ci else 3738c2ecf20Sopenharmony_ci tmp |= voltage->gpio.mask; 3748c2ecf20Sopenharmony_ci WREG32(voltage->gpio.reg, tmp); 3758c2ecf20Sopenharmony_ci if (voltage->delay) 3768c2ecf20Sopenharmony_ci udelay(voltage->delay); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci sclk_cntl = RREG32_PLL(SCLK_CNTL); 3818c2ecf20Sopenharmony_ci sclk_cntl2 = RREG32_PLL(SCLK_CNTL2); 3828c2ecf20Sopenharmony_ci sclk_cntl2 &= ~REDUCED_SPEED_SCLK_SEL(3); 3838c2ecf20Sopenharmony_ci sclk_more_cntl = RREG32_PLL(SCLK_MORE_CNTL); 3848c2ecf20Sopenharmony_ci sclk_more_cntl &= ~VOLTAGE_DELAY_SEL(3); 3858c2ecf20Sopenharmony_ci if (ps->misc & ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN) { 3868c2ecf20Sopenharmony_ci sclk_more_cntl |= REDUCED_SPEED_SCLK_EN; 3878c2ecf20Sopenharmony_ci if (ps->misc & ATOM_PM_MISCINFO_DYN_CLK_3D_IDLE) 3888c2ecf20Sopenharmony_ci sclk_cntl2 |= REDUCED_SPEED_SCLK_MODE; 3898c2ecf20Sopenharmony_ci else 3908c2ecf20Sopenharmony_ci sclk_cntl2 &= ~REDUCED_SPEED_SCLK_MODE; 3918c2ecf20Sopenharmony_ci if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2) 3928c2ecf20Sopenharmony_ci sclk_cntl2 |= REDUCED_SPEED_SCLK_SEL(0); 3938c2ecf20Sopenharmony_ci else if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4) 3948c2ecf20Sopenharmony_ci sclk_cntl2 |= REDUCED_SPEED_SCLK_SEL(2); 3958c2ecf20Sopenharmony_ci } else 3968c2ecf20Sopenharmony_ci sclk_more_cntl &= ~REDUCED_SPEED_SCLK_EN; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (ps->misc & ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN) { 3998c2ecf20Sopenharmony_ci sclk_more_cntl |= IO_CG_VOLTAGE_DROP; 4008c2ecf20Sopenharmony_ci if (voltage->delay) { 4018c2ecf20Sopenharmony_ci sclk_more_cntl |= VOLTAGE_DROP_SYNC; 4028c2ecf20Sopenharmony_ci switch (voltage->delay) { 4038c2ecf20Sopenharmony_ci case 33: 4048c2ecf20Sopenharmony_ci sclk_more_cntl |= VOLTAGE_DELAY_SEL(0); 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci case 66: 4078c2ecf20Sopenharmony_ci sclk_more_cntl |= VOLTAGE_DELAY_SEL(1); 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci case 99: 4108c2ecf20Sopenharmony_ci sclk_more_cntl |= VOLTAGE_DELAY_SEL(2); 4118c2ecf20Sopenharmony_ci break; 4128c2ecf20Sopenharmony_ci case 132: 4138c2ecf20Sopenharmony_ci sclk_more_cntl |= VOLTAGE_DELAY_SEL(3); 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci } else 4178c2ecf20Sopenharmony_ci sclk_more_cntl &= ~VOLTAGE_DROP_SYNC; 4188c2ecf20Sopenharmony_ci } else 4198c2ecf20Sopenharmony_ci sclk_more_cntl &= ~IO_CG_VOLTAGE_DROP; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN) 4228c2ecf20Sopenharmony_ci sclk_cntl &= ~FORCE_HDP; 4238c2ecf20Sopenharmony_ci else 4248c2ecf20Sopenharmony_ci sclk_cntl |= FORCE_HDP; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci WREG32_PLL(SCLK_CNTL, sclk_cntl); 4278c2ecf20Sopenharmony_ci WREG32_PLL(SCLK_CNTL2, sclk_cntl2); 4288c2ecf20Sopenharmony_ci WREG32_PLL(SCLK_MORE_CNTL, sclk_more_cntl); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* set pcie lanes */ 4318c2ecf20Sopenharmony_ci if ((rdev->flags & RADEON_IS_PCIE) && 4328c2ecf20Sopenharmony_ci !(rdev->flags & RADEON_IS_IGP) && 4338c2ecf20Sopenharmony_ci rdev->asic->pm.set_pcie_lanes && 4348c2ecf20Sopenharmony_ci (ps->pcie_lanes != 4358c2ecf20Sopenharmony_ci rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) { 4368c2ecf20Sopenharmony_ci radeon_set_pcie_lanes(rdev, 4378c2ecf20Sopenharmony_ci ps->pcie_lanes); 4388c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Setting: p: %d\n", ps->pcie_lanes); 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci/** 4438c2ecf20Sopenharmony_ci * r100_pm_prepare - pre-power state change callback. 4448c2ecf20Sopenharmony_ci * 4458c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 4468c2ecf20Sopenharmony_ci * 4478c2ecf20Sopenharmony_ci * Prepare for a power state change (r1xx-r4xx). 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_civoid r100_pm_prepare(struct radeon_device *rdev) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct drm_device *ddev = rdev->ddev; 4528c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 4538c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc; 4548c2ecf20Sopenharmony_ci u32 tmp; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* disable any active CRTCs */ 4578c2ecf20Sopenharmony_ci list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { 4588c2ecf20Sopenharmony_ci radeon_crtc = to_radeon_crtc(crtc); 4598c2ecf20Sopenharmony_ci if (radeon_crtc->enabled) { 4608c2ecf20Sopenharmony_ci if (radeon_crtc->crtc_id) { 4618c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_CRTC2_GEN_CNTL); 4628c2ecf20Sopenharmony_ci tmp |= RADEON_CRTC2_DISP_REQ_EN_B; 4638c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_GEN_CNTL, tmp); 4648c2ecf20Sopenharmony_ci } else { 4658c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_CRTC_GEN_CNTL); 4668c2ecf20Sopenharmony_ci tmp |= RADEON_CRTC_DISP_REQ_EN_B; 4678c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC_GEN_CNTL, tmp); 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci/** 4748c2ecf20Sopenharmony_ci * r100_pm_finish - post-power state change callback. 4758c2ecf20Sopenharmony_ci * 4768c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 4778c2ecf20Sopenharmony_ci * 4788c2ecf20Sopenharmony_ci * Clean up after a power state change (r1xx-r4xx). 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_civoid r100_pm_finish(struct radeon_device *rdev) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct drm_device *ddev = rdev->ddev; 4838c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 4848c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc; 4858c2ecf20Sopenharmony_ci u32 tmp; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* enable any active CRTCs */ 4888c2ecf20Sopenharmony_ci list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { 4898c2ecf20Sopenharmony_ci radeon_crtc = to_radeon_crtc(crtc); 4908c2ecf20Sopenharmony_ci if (radeon_crtc->enabled) { 4918c2ecf20Sopenharmony_ci if (radeon_crtc->crtc_id) { 4928c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_CRTC2_GEN_CNTL); 4938c2ecf20Sopenharmony_ci tmp &= ~RADEON_CRTC2_DISP_REQ_EN_B; 4948c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC2_GEN_CNTL, tmp); 4958c2ecf20Sopenharmony_ci } else { 4968c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_CRTC_GEN_CNTL); 4978c2ecf20Sopenharmony_ci tmp &= ~RADEON_CRTC_DISP_REQ_EN_B; 4988c2ecf20Sopenharmony_ci WREG32(RADEON_CRTC_GEN_CNTL, tmp); 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci/** 5058c2ecf20Sopenharmony_ci * r100_gui_idle - gui idle callback. 5068c2ecf20Sopenharmony_ci * 5078c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 5088c2ecf20Sopenharmony_ci * 5098c2ecf20Sopenharmony_ci * Check of the GUI (2D/3D engines) are idle (r1xx-r5xx). 5108c2ecf20Sopenharmony_ci * Returns true if idle, false if not. 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_cibool r100_gui_idle(struct radeon_device *rdev) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci if (RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE) 5158c2ecf20Sopenharmony_ci return false; 5168c2ecf20Sopenharmony_ci else 5178c2ecf20Sopenharmony_ci return true; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci/* hpd for digital panel detect/disconnect */ 5218c2ecf20Sopenharmony_ci/** 5228c2ecf20Sopenharmony_ci * r100_hpd_sense - hpd sense callback. 5238c2ecf20Sopenharmony_ci * 5248c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 5258c2ecf20Sopenharmony_ci * @hpd: hpd (hotplug detect) pin 5268c2ecf20Sopenharmony_ci * 5278c2ecf20Sopenharmony_ci * Checks if a digital monitor is connected (r1xx-r4xx). 5288c2ecf20Sopenharmony_ci * Returns true if connected, false if not connected. 5298c2ecf20Sopenharmony_ci */ 5308c2ecf20Sopenharmony_cibool r100_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci bool connected = false; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci switch (hpd) { 5358c2ecf20Sopenharmony_ci case RADEON_HPD_1: 5368c2ecf20Sopenharmony_ci if (RREG32(RADEON_FP_GEN_CNTL) & RADEON_FP_DETECT_SENSE) 5378c2ecf20Sopenharmony_ci connected = true; 5388c2ecf20Sopenharmony_ci break; 5398c2ecf20Sopenharmony_ci case RADEON_HPD_2: 5408c2ecf20Sopenharmony_ci if (RREG32(RADEON_FP2_GEN_CNTL) & RADEON_FP2_DETECT_SENSE) 5418c2ecf20Sopenharmony_ci connected = true; 5428c2ecf20Sopenharmony_ci break; 5438c2ecf20Sopenharmony_ci default: 5448c2ecf20Sopenharmony_ci break; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci return connected; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci/** 5508c2ecf20Sopenharmony_ci * r100_hpd_set_polarity - hpd set polarity callback. 5518c2ecf20Sopenharmony_ci * 5528c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 5538c2ecf20Sopenharmony_ci * @hpd: hpd (hotplug detect) pin 5548c2ecf20Sopenharmony_ci * 5558c2ecf20Sopenharmony_ci * Set the polarity of the hpd pin (r1xx-r4xx). 5568c2ecf20Sopenharmony_ci */ 5578c2ecf20Sopenharmony_civoid r100_hpd_set_polarity(struct radeon_device *rdev, 5588c2ecf20Sopenharmony_ci enum radeon_hpd_id hpd) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci u32 tmp; 5618c2ecf20Sopenharmony_ci bool connected = r100_hpd_sense(rdev, hpd); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci switch (hpd) { 5648c2ecf20Sopenharmony_ci case RADEON_HPD_1: 5658c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_FP_GEN_CNTL); 5668c2ecf20Sopenharmony_ci if (connected) 5678c2ecf20Sopenharmony_ci tmp &= ~RADEON_FP_DETECT_INT_POL; 5688c2ecf20Sopenharmony_ci else 5698c2ecf20Sopenharmony_ci tmp |= RADEON_FP_DETECT_INT_POL; 5708c2ecf20Sopenharmony_ci WREG32(RADEON_FP_GEN_CNTL, tmp); 5718c2ecf20Sopenharmony_ci break; 5728c2ecf20Sopenharmony_ci case RADEON_HPD_2: 5738c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_FP2_GEN_CNTL); 5748c2ecf20Sopenharmony_ci if (connected) 5758c2ecf20Sopenharmony_ci tmp &= ~RADEON_FP2_DETECT_INT_POL; 5768c2ecf20Sopenharmony_ci else 5778c2ecf20Sopenharmony_ci tmp |= RADEON_FP2_DETECT_INT_POL; 5788c2ecf20Sopenharmony_ci WREG32(RADEON_FP2_GEN_CNTL, tmp); 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci default: 5818c2ecf20Sopenharmony_ci break; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci/** 5868c2ecf20Sopenharmony_ci * r100_hpd_init - hpd setup callback. 5878c2ecf20Sopenharmony_ci * 5888c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 5898c2ecf20Sopenharmony_ci * 5908c2ecf20Sopenharmony_ci * Setup the hpd pins used by the card (r1xx-r4xx). 5918c2ecf20Sopenharmony_ci * Set the polarity, and enable the hpd interrupts. 5928c2ecf20Sopenharmony_ci */ 5938c2ecf20Sopenharmony_civoid r100_hpd_init(struct radeon_device *rdev) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci struct drm_device *dev = rdev->ddev; 5968c2ecf20Sopenharmony_ci struct drm_connector *connector; 5978c2ecf20Sopenharmony_ci unsigned enable = 0; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 6008c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 6018c2ecf20Sopenharmony_ci if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) 6028c2ecf20Sopenharmony_ci enable |= 1 << radeon_connector->hpd.hpd; 6038c2ecf20Sopenharmony_ci radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci radeon_irq_kms_enable_hpd(rdev, enable); 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci/** 6098c2ecf20Sopenharmony_ci * r100_hpd_fini - hpd tear down callback. 6108c2ecf20Sopenharmony_ci * 6118c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 6128c2ecf20Sopenharmony_ci * 6138c2ecf20Sopenharmony_ci * Tear down the hpd pins used by the card (r1xx-r4xx). 6148c2ecf20Sopenharmony_ci * Disable the hpd interrupts. 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_civoid r100_hpd_fini(struct radeon_device *rdev) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct drm_device *dev = rdev->ddev; 6198c2ecf20Sopenharmony_ci struct drm_connector *connector; 6208c2ecf20Sopenharmony_ci unsigned disable = 0; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 6238c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 6248c2ecf20Sopenharmony_ci if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) 6258c2ecf20Sopenharmony_ci disable |= 1 << radeon_connector->hpd.hpd; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci radeon_irq_kms_disable_hpd(rdev, disable); 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci/* 6318c2ecf20Sopenharmony_ci * PCI GART 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_civoid r100_pci_gart_tlb_flush(struct radeon_device *rdev) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci /* TODO: can we do somethings here ? */ 6368c2ecf20Sopenharmony_ci /* It seems hw only cache one entry so we should discard this 6378c2ecf20Sopenharmony_ci * entry otherwise if first GPU GART read hit this entry it 6388c2ecf20Sopenharmony_ci * could end up in wrong address. */ 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ciint r100_pci_gart_init(struct radeon_device *rdev) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci int r; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (rdev->gart.ptr) { 6468c2ecf20Sopenharmony_ci WARN(1, "R100 PCI GART already initialized\n"); 6478c2ecf20Sopenharmony_ci return 0; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci /* Initialize common gart structure */ 6508c2ecf20Sopenharmony_ci r = radeon_gart_init(rdev); 6518c2ecf20Sopenharmony_ci if (r) 6528c2ecf20Sopenharmony_ci return r; 6538c2ecf20Sopenharmony_ci rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; 6548c2ecf20Sopenharmony_ci rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush; 6558c2ecf20Sopenharmony_ci rdev->asic->gart.get_page_entry = &r100_pci_gart_get_page_entry; 6568c2ecf20Sopenharmony_ci rdev->asic->gart.set_page = &r100_pci_gart_set_page; 6578c2ecf20Sopenharmony_ci return radeon_gart_table_ram_alloc(rdev); 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ciint r100_pci_gart_enable(struct radeon_device *rdev) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci uint32_t tmp; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* discard memory request outside of configured range */ 6658c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS; 6668c2ecf20Sopenharmony_ci WREG32(RADEON_AIC_CNTL, tmp); 6678c2ecf20Sopenharmony_ci /* set address range for PCI address translate */ 6688c2ecf20Sopenharmony_ci WREG32(RADEON_AIC_LO_ADDR, rdev->mc.gtt_start); 6698c2ecf20Sopenharmony_ci WREG32(RADEON_AIC_HI_ADDR, rdev->mc.gtt_end); 6708c2ecf20Sopenharmony_ci /* set PCI GART page-table base address */ 6718c2ecf20Sopenharmony_ci WREG32(RADEON_AIC_PT_BASE, rdev->gart.table_addr); 6728c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_AIC_CNTL) | RADEON_PCIGART_TRANSLATE_EN; 6738c2ecf20Sopenharmony_ci WREG32(RADEON_AIC_CNTL, tmp); 6748c2ecf20Sopenharmony_ci r100_pci_gart_tlb_flush(rdev); 6758c2ecf20Sopenharmony_ci DRM_INFO("PCI GART of %uM enabled (table at 0x%016llX).\n", 6768c2ecf20Sopenharmony_ci (unsigned)(rdev->mc.gtt_size >> 20), 6778c2ecf20Sopenharmony_ci (unsigned long long)rdev->gart.table_addr); 6788c2ecf20Sopenharmony_ci rdev->gart.ready = true; 6798c2ecf20Sopenharmony_ci return 0; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_civoid r100_pci_gart_disable(struct radeon_device *rdev) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci uint32_t tmp; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* discard memory request outside of configured range */ 6878c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS; 6888c2ecf20Sopenharmony_ci WREG32(RADEON_AIC_CNTL, tmp & ~RADEON_PCIGART_TRANSLATE_EN); 6898c2ecf20Sopenharmony_ci WREG32(RADEON_AIC_LO_ADDR, 0); 6908c2ecf20Sopenharmony_ci WREG32(RADEON_AIC_HI_ADDR, 0); 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ciuint64_t r100_pci_gart_get_page_entry(uint64_t addr, uint32_t flags) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci return addr; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_civoid r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i, 6998c2ecf20Sopenharmony_ci uint64_t entry) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci u32 *gtt = rdev->gart.ptr; 7028c2ecf20Sopenharmony_ci gtt[i] = cpu_to_le32(lower_32_bits(entry)); 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_civoid r100_pci_gart_fini(struct radeon_device *rdev) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci radeon_gart_fini(rdev); 7088c2ecf20Sopenharmony_ci r100_pci_gart_disable(rdev); 7098c2ecf20Sopenharmony_ci radeon_gart_table_ram_free(rdev); 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ciint r100_irq_set(struct radeon_device *rdev) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci uint32_t tmp = 0; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (!rdev->irq.installed) { 7178c2ecf20Sopenharmony_ci WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); 7188c2ecf20Sopenharmony_ci WREG32(R_000040_GEN_INT_CNTL, 0); 7198c2ecf20Sopenharmony_ci return -EINVAL; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { 7228c2ecf20Sopenharmony_ci tmp |= RADEON_SW_INT_ENABLE; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci if (rdev->irq.crtc_vblank_int[0] || 7258c2ecf20Sopenharmony_ci atomic_read(&rdev->irq.pflip[0])) { 7268c2ecf20Sopenharmony_ci tmp |= RADEON_CRTC_VBLANK_MASK; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci if (rdev->irq.crtc_vblank_int[1] || 7298c2ecf20Sopenharmony_ci atomic_read(&rdev->irq.pflip[1])) { 7308c2ecf20Sopenharmony_ci tmp |= RADEON_CRTC2_VBLANK_MASK; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci if (rdev->irq.hpd[0]) { 7338c2ecf20Sopenharmony_ci tmp |= RADEON_FP_DETECT_MASK; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci if (rdev->irq.hpd[1]) { 7368c2ecf20Sopenharmony_ci tmp |= RADEON_FP2_DETECT_MASK; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci WREG32(RADEON_GEN_INT_CNTL, tmp); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci /* read back to post the write */ 7418c2ecf20Sopenharmony_ci RREG32(RADEON_GEN_INT_CNTL); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci return 0; 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_civoid r100_irq_disable(struct radeon_device *rdev) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci u32 tmp; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci WREG32(R_000040_GEN_INT_CNTL, 0); 7518c2ecf20Sopenharmony_ci /* Wait and acknowledge irq */ 7528c2ecf20Sopenharmony_ci mdelay(1); 7538c2ecf20Sopenharmony_ci tmp = RREG32(R_000044_GEN_INT_STATUS); 7548c2ecf20Sopenharmony_ci WREG32(R_000044_GEN_INT_STATUS, tmp); 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic uint32_t r100_irq_ack(struct radeon_device *rdev) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci uint32_t irqs = RREG32(RADEON_GEN_INT_STATUS); 7608c2ecf20Sopenharmony_ci uint32_t irq_mask = RADEON_SW_INT_TEST | 7618c2ecf20Sopenharmony_ci RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT | 7628c2ecf20Sopenharmony_ci RADEON_FP_DETECT_STAT | RADEON_FP2_DETECT_STAT; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (irqs) { 7658c2ecf20Sopenharmony_ci WREG32(RADEON_GEN_INT_STATUS, irqs); 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci return irqs & irq_mask; 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ciint r100_irq_process(struct radeon_device *rdev) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci uint32_t status, msi_rearm; 7738c2ecf20Sopenharmony_ci bool queue_hotplug = false; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci status = r100_irq_ack(rdev); 7768c2ecf20Sopenharmony_ci if (!status) { 7778c2ecf20Sopenharmony_ci return IRQ_NONE; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci if (rdev->shutdown) { 7808c2ecf20Sopenharmony_ci return IRQ_NONE; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci while (status) { 7838c2ecf20Sopenharmony_ci /* SW interrupt */ 7848c2ecf20Sopenharmony_ci if (status & RADEON_SW_INT_TEST) { 7858c2ecf20Sopenharmony_ci radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci /* Vertical blank interrupts */ 7888c2ecf20Sopenharmony_ci if (status & RADEON_CRTC_VBLANK_STAT) { 7898c2ecf20Sopenharmony_ci if (rdev->irq.crtc_vblank_int[0]) { 7908c2ecf20Sopenharmony_ci drm_handle_vblank(rdev->ddev, 0); 7918c2ecf20Sopenharmony_ci rdev->pm.vblank_sync = true; 7928c2ecf20Sopenharmony_ci wake_up(&rdev->irq.vblank_queue); 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci if (atomic_read(&rdev->irq.pflip[0])) 7958c2ecf20Sopenharmony_ci radeon_crtc_handle_vblank(rdev, 0); 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci if (status & RADEON_CRTC2_VBLANK_STAT) { 7988c2ecf20Sopenharmony_ci if (rdev->irq.crtc_vblank_int[1]) { 7998c2ecf20Sopenharmony_ci drm_handle_vblank(rdev->ddev, 1); 8008c2ecf20Sopenharmony_ci rdev->pm.vblank_sync = true; 8018c2ecf20Sopenharmony_ci wake_up(&rdev->irq.vblank_queue); 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci if (atomic_read(&rdev->irq.pflip[1])) 8048c2ecf20Sopenharmony_ci radeon_crtc_handle_vblank(rdev, 1); 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci if (status & RADEON_FP_DETECT_STAT) { 8078c2ecf20Sopenharmony_ci queue_hotplug = true; 8088c2ecf20Sopenharmony_ci DRM_DEBUG("HPD1\n"); 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci if (status & RADEON_FP2_DETECT_STAT) { 8118c2ecf20Sopenharmony_ci queue_hotplug = true; 8128c2ecf20Sopenharmony_ci DRM_DEBUG("HPD2\n"); 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci status = r100_irq_ack(rdev); 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci if (queue_hotplug) 8178c2ecf20Sopenharmony_ci schedule_delayed_work(&rdev->hotplug_work, 0); 8188c2ecf20Sopenharmony_ci if (rdev->msi_enabled) { 8198c2ecf20Sopenharmony_ci switch (rdev->family) { 8208c2ecf20Sopenharmony_ci case CHIP_RS400: 8218c2ecf20Sopenharmony_ci case CHIP_RS480: 8228c2ecf20Sopenharmony_ci msi_rearm = RREG32(RADEON_AIC_CNTL) & ~RS400_MSI_REARM; 8238c2ecf20Sopenharmony_ci WREG32(RADEON_AIC_CNTL, msi_rearm); 8248c2ecf20Sopenharmony_ci WREG32(RADEON_AIC_CNTL, msi_rearm | RS400_MSI_REARM); 8258c2ecf20Sopenharmony_ci break; 8268c2ecf20Sopenharmony_ci default: 8278c2ecf20Sopenharmony_ci WREG32(RADEON_MSI_REARM_EN, RV370_MSI_REARM_EN); 8288c2ecf20Sopenharmony_ci break; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci return IRQ_HANDLED; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ciu32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci if (crtc == 0) 8378c2ecf20Sopenharmony_ci return RREG32(RADEON_CRTC_CRNT_FRAME); 8388c2ecf20Sopenharmony_ci else 8398c2ecf20Sopenharmony_ci return RREG32(RADEON_CRTC2_CRNT_FRAME); 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci/** 8438c2ecf20Sopenharmony_ci * r100_ring_hdp_flush - flush Host Data Path via the ring buffer 8448c2ecf20Sopenharmony_ci * rdev: radeon device structure 8458c2ecf20Sopenharmony_ci * ring: ring buffer struct for emitting packets 8468c2ecf20Sopenharmony_ci */ 8478c2ecf20Sopenharmony_cistatic void r100_ring_hdp_flush(struct radeon_device *rdev, struct radeon_ring *ring) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0)); 8508c2ecf20Sopenharmony_ci radeon_ring_write(ring, rdev->config.r100.hdp_cntl | 8518c2ecf20Sopenharmony_ci RADEON_HDP_READ_BUFFER_INVALIDATE); 8528c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0)); 8538c2ecf20Sopenharmony_ci radeon_ring_write(ring, rdev->config.r100.hdp_cntl); 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci/* Who ever call radeon_fence_emit should call ring_lock and ask 8578c2ecf20Sopenharmony_ci * for enough space (today caller are ib schedule and buffer move) */ 8588c2ecf20Sopenharmony_civoid r100_fence_ring_emit(struct radeon_device *rdev, 8598c2ecf20Sopenharmony_ci struct radeon_fence *fence) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[fence->ring]; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* We have to make sure that caches are flushed before 8648c2ecf20Sopenharmony_ci * CPU might read something from VRAM. */ 8658c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0)); 8668c2ecf20Sopenharmony_ci radeon_ring_write(ring, RADEON_RB3D_DC_FLUSH_ALL); 8678c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); 8688c2ecf20Sopenharmony_ci radeon_ring_write(ring, RADEON_RB3D_ZC_FLUSH_ALL); 8698c2ecf20Sopenharmony_ci /* Wait until IDLE & CLEAN */ 8708c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0)); 8718c2ecf20Sopenharmony_ci radeon_ring_write(ring, RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_3D_IDLECLEAN); 8728c2ecf20Sopenharmony_ci r100_ring_hdp_flush(rdev, ring); 8738c2ecf20Sopenharmony_ci /* Emit fence sequence & fire IRQ */ 8748c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET0(rdev->fence_drv[fence->ring].scratch_reg, 0)); 8758c2ecf20Sopenharmony_ci radeon_ring_write(ring, fence->seq); 8768c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_GEN_INT_STATUS, 0)); 8778c2ecf20Sopenharmony_ci radeon_ring_write(ring, RADEON_SW_INT_FIRE); 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cibool r100_semaphore_ring_emit(struct radeon_device *rdev, 8818c2ecf20Sopenharmony_ci struct radeon_ring *ring, 8828c2ecf20Sopenharmony_ci struct radeon_semaphore *semaphore, 8838c2ecf20Sopenharmony_ci bool emit_wait) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci /* Unused on older asics, since we don't have semaphores or multiple rings */ 8868c2ecf20Sopenharmony_ci BUG(); 8878c2ecf20Sopenharmony_ci return false; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistruct radeon_fence *r100_copy_blit(struct radeon_device *rdev, 8918c2ecf20Sopenharmony_ci uint64_t src_offset, 8928c2ecf20Sopenharmony_ci uint64_t dst_offset, 8938c2ecf20Sopenharmony_ci unsigned num_gpu_pages, 8948c2ecf20Sopenharmony_ci struct dma_resv *resv) 8958c2ecf20Sopenharmony_ci{ 8968c2ecf20Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; 8978c2ecf20Sopenharmony_ci struct radeon_fence *fence; 8988c2ecf20Sopenharmony_ci uint32_t cur_pages; 8998c2ecf20Sopenharmony_ci uint32_t stride_bytes = RADEON_GPU_PAGE_SIZE; 9008c2ecf20Sopenharmony_ci uint32_t pitch; 9018c2ecf20Sopenharmony_ci uint32_t stride_pixels; 9028c2ecf20Sopenharmony_ci unsigned ndw; 9038c2ecf20Sopenharmony_ci int num_loops; 9048c2ecf20Sopenharmony_ci int r = 0; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci /* radeon limited to 16k stride */ 9078c2ecf20Sopenharmony_ci stride_bytes &= 0x3fff; 9088c2ecf20Sopenharmony_ci /* radeon pitch is /64 */ 9098c2ecf20Sopenharmony_ci pitch = stride_bytes / 64; 9108c2ecf20Sopenharmony_ci stride_pixels = stride_bytes / 4; 9118c2ecf20Sopenharmony_ci num_loops = DIV_ROUND_UP(num_gpu_pages, 8191); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* Ask for enough room for blit + flush + fence */ 9148c2ecf20Sopenharmony_ci ndw = 64 + (10 * num_loops); 9158c2ecf20Sopenharmony_ci r = radeon_ring_lock(rdev, ring, ndw); 9168c2ecf20Sopenharmony_ci if (r) { 9178c2ecf20Sopenharmony_ci DRM_ERROR("radeon: moving bo (%d) asking for %u dw.\n", r, ndw); 9188c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci while (num_gpu_pages > 0) { 9218c2ecf20Sopenharmony_ci cur_pages = num_gpu_pages; 9228c2ecf20Sopenharmony_ci if (cur_pages > 8191) { 9238c2ecf20Sopenharmony_ci cur_pages = 8191; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci num_gpu_pages -= cur_pages; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci /* pages are in Y direction - height 9288c2ecf20Sopenharmony_ci page width in X direction - width */ 9298c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET3(PACKET3_BITBLT_MULTI, 8)); 9308c2ecf20Sopenharmony_ci radeon_ring_write(ring, 9318c2ecf20Sopenharmony_ci RADEON_GMC_SRC_PITCH_OFFSET_CNTL | 9328c2ecf20Sopenharmony_ci RADEON_GMC_DST_PITCH_OFFSET_CNTL | 9338c2ecf20Sopenharmony_ci RADEON_GMC_SRC_CLIPPING | 9348c2ecf20Sopenharmony_ci RADEON_GMC_DST_CLIPPING | 9358c2ecf20Sopenharmony_ci RADEON_GMC_BRUSH_NONE | 9368c2ecf20Sopenharmony_ci (RADEON_COLOR_FORMAT_ARGB8888 << 8) | 9378c2ecf20Sopenharmony_ci RADEON_GMC_SRC_DATATYPE_COLOR | 9388c2ecf20Sopenharmony_ci RADEON_ROP3_S | 9398c2ecf20Sopenharmony_ci RADEON_DP_SRC_SOURCE_MEMORY | 9408c2ecf20Sopenharmony_ci RADEON_GMC_CLR_CMP_CNTL_DIS | 9418c2ecf20Sopenharmony_ci RADEON_GMC_WR_MSK_DIS); 9428c2ecf20Sopenharmony_ci radeon_ring_write(ring, (pitch << 22) | (src_offset >> 10)); 9438c2ecf20Sopenharmony_ci radeon_ring_write(ring, (pitch << 22) | (dst_offset >> 10)); 9448c2ecf20Sopenharmony_ci radeon_ring_write(ring, (0x1fff) | (0x1fff << 16)); 9458c2ecf20Sopenharmony_ci radeon_ring_write(ring, 0); 9468c2ecf20Sopenharmony_ci radeon_ring_write(ring, (0x1fff) | (0x1fff << 16)); 9478c2ecf20Sopenharmony_ci radeon_ring_write(ring, num_gpu_pages); 9488c2ecf20Sopenharmony_ci radeon_ring_write(ring, num_gpu_pages); 9498c2ecf20Sopenharmony_ci radeon_ring_write(ring, cur_pages | (stride_pixels << 16)); 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0)); 9528c2ecf20Sopenharmony_ci radeon_ring_write(ring, RADEON_RB2D_DC_FLUSH_ALL); 9538c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0)); 9548c2ecf20Sopenharmony_ci radeon_ring_write(ring, 9558c2ecf20Sopenharmony_ci RADEON_WAIT_2D_IDLECLEAN | 9568c2ecf20Sopenharmony_ci RADEON_WAIT_HOST_IDLECLEAN | 9578c2ecf20Sopenharmony_ci RADEON_WAIT_DMA_GUI_IDLE); 9588c2ecf20Sopenharmony_ci r = radeon_fence_emit(rdev, &fence, RADEON_RING_TYPE_GFX_INDEX); 9598c2ecf20Sopenharmony_ci if (r) { 9608c2ecf20Sopenharmony_ci radeon_ring_unlock_undo(rdev, ring); 9618c2ecf20Sopenharmony_ci return ERR_PTR(r); 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci radeon_ring_unlock_commit(rdev, ring, false); 9648c2ecf20Sopenharmony_ci return fence; 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cistatic int r100_cp_wait_for_idle(struct radeon_device *rdev) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci unsigned i; 9708c2ecf20Sopenharmony_ci u32 tmp; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 9738c2ecf20Sopenharmony_ci tmp = RREG32(R_000E40_RBBM_STATUS); 9748c2ecf20Sopenharmony_ci if (!G_000E40_CP_CMDSTRM_BUSY(tmp)) { 9758c2ecf20Sopenharmony_ci return 0; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci udelay(1); 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci return -1; 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_civoid r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring) 9838c2ecf20Sopenharmony_ci{ 9848c2ecf20Sopenharmony_ci int r; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci r = radeon_ring_lock(rdev, ring, 2); 9878c2ecf20Sopenharmony_ci if (r) { 9888c2ecf20Sopenharmony_ci return; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_ISYNC_CNTL, 0)); 9918c2ecf20Sopenharmony_ci radeon_ring_write(ring, 9928c2ecf20Sopenharmony_ci RADEON_ISYNC_ANY2D_IDLE3D | 9938c2ecf20Sopenharmony_ci RADEON_ISYNC_ANY3D_IDLE2D | 9948c2ecf20Sopenharmony_ci RADEON_ISYNC_WAIT_IDLEGUI | 9958c2ecf20Sopenharmony_ci RADEON_ISYNC_CPSCRATCH_IDLEGUI); 9968c2ecf20Sopenharmony_ci radeon_ring_unlock_commit(rdev, ring, false); 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci/* Load the microcode for the CP */ 10018c2ecf20Sopenharmony_cistatic int r100_cp_init_microcode(struct radeon_device *rdev) 10028c2ecf20Sopenharmony_ci{ 10038c2ecf20Sopenharmony_ci const char *fw_name = NULL; 10048c2ecf20Sopenharmony_ci int err; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) || 10098c2ecf20Sopenharmony_ci (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) || 10108c2ecf20Sopenharmony_ci (rdev->family == CHIP_RS200)) { 10118c2ecf20Sopenharmony_ci DRM_INFO("Loading R100 Microcode\n"); 10128c2ecf20Sopenharmony_ci fw_name = FIRMWARE_R100; 10138c2ecf20Sopenharmony_ci } else if ((rdev->family == CHIP_R200) || 10148c2ecf20Sopenharmony_ci (rdev->family == CHIP_RV250) || 10158c2ecf20Sopenharmony_ci (rdev->family == CHIP_RV280) || 10168c2ecf20Sopenharmony_ci (rdev->family == CHIP_RS300)) { 10178c2ecf20Sopenharmony_ci DRM_INFO("Loading R200 Microcode\n"); 10188c2ecf20Sopenharmony_ci fw_name = FIRMWARE_R200; 10198c2ecf20Sopenharmony_ci } else if ((rdev->family == CHIP_R300) || 10208c2ecf20Sopenharmony_ci (rdev->family == CHIP_R350) || 10218c2ecf20Sopenharmony_ci (rdev->family == CHIP_RV350) || 10228c2ecf20Sopenharmony_ci (rdev->family == CHIP_RV380) || 10238c2ecf20Sopenharmony_ci (rdev->family == CHIP_RS400) || 10248c2ecf20Sopenharmony_ci (rdev->family == CHIP_RS480)) { 10258c2ecf20Sopenharmony_ci DRM_INFO("Loading R300 Microcode\n"); 10268c2ecf20Sopenharmony_ci fw_name = FIRMWARE_R300; 10278c2ecf20Sopenharmony_ci } else if ((rdev->family == CHIP_R420) || 10288c2ecf20Sopenharmony_ci (rdev->family == CHIP_R423) || 10298c2ecf20Sopenharmony_ci (rdev->family == CHIP_RV410)) { 10308c2ecf20Sopenharmony_ci DRM_INFO("Loading R400 Microcode\n"); 10318c2ecf20Sopenharmony_ci fw_name = FIRMWARE_R420; 10328c2ecf20Sopenharmony_ci } else if ((rdev->family == CHIP_RS690) || 10338c2ecf20Sopenharmony_ci (rdev->family == CHIP_RS740)) { 10348c2ecf20Sopenharmony_ci DRM_INFO("Loading RS690/RS740 Microcode\n"); 10358c2ecf20Sopenharmony_ci fw_name = FIRMWARE_RS690; 10368c2ecf20Sopenharmony_ci } else if (rdev->family == CHIP_RS600) { 10378c2ecf20Sopenharmony_ci DRM_INFO("Loading RS600 Microcode\n"); 10388c2ecf20Sopenharmony_ci fw_name = FIRMWARE_RS600; 10398c2ecf20Sopenharmony_ci } else if ((rdev->family == CHIP_RV515) || 10408c2ecf20Sopenharmony_ci (rdev->family == CHIP_R520) || 10418c2ecf20Sopenharmony_ci (rdev->family == CHIP_RV530) || 10428c2ecf20Sopenharmony_ci (rdev->family == CHIP_R580) || 10438c2ecf20Sopenharmony_ci (rdev->family == CHIP_RV560) || 10448c2ecf20Sopenharmony_ci (rdev->family == CHIP_RV570)) { 10458c2ecf20Sopenharmony_ci DRM_INFO("Loading R500 Microcode\n"); 10468c2ecf20Sopenharmony_ci fw_name = FIRMWARE_R520; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); 10508c2ecf20Sopenharmony_ci if (err) { 10518c2ecf20Sopenharmony_ci pr_err("radeon_cp: Failed to load firmware \"%s\"\n", fw_name); 10528c2ecf20Sopenharmony_ci } else if (rdev->me_fw->size % 8) { 10538c2ecf20Sopenharmony_ci pr_err("radeon_cp: Bogus length %zu in firmware \"%s\"\n", 10548c2ecf20Sopenharmony_ci rdev->me_fw->size, fw_name); 10558c2ecf20Sopenharmony_ci err = -EINVAL; 10568c2ecf20Sopenharmony_ci release_firmware(rdev->me_fw); 10578c2ecf20Sopenharmony_ci rdev->me_fw = NULL; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci return err; 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ciu32 r100_gfx_get_rptr(struct radeon_device *rdev, 10638c2ecf20Sopenharmony_ci struct radeon_ring *ring) 10648c2ecf20Sopenharmony_ci{ 10658c2ecf20Sopenharmony_ci u32 rptr; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (rdev->wb.enabled) 10688c2ecf20Sopenharmony_ci rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]); 10698c2ecf20Sopenharmony_ci else 10708c2ecf20Sopenharmony_ci rptr = RREG32(RADEON_CP_RB_RPTR); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci return rptr; 10738c2ecf20Sopenharmony_ci} 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ciu32 r100_gfx_get_wptr(struct radeon_device *rdev, 10768c2ecf20Sopenharmony_ci struct radeon_ring *ring) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci return RREG32(RADEON_CP_RB_WPTR); 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_civoid r100_gfx_set_wptr(struct radeon_device *rdev, 10828c2ecf20Sopenharmony_ci struct radeon_ring *ring) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci WREG32(RADEON_CP_RB_WPTR, ring->wptr); 10858c2ecf20Sopenharmony_ci (void)RREG32(RADEON_CP_RB_WPTR); 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_cistatic void r100_cp_load_microcode(struct radeon_device *rdev) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci const __be32 *fw_data; 10918c2ecf20Sopenharmony_ci int i, size; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (r100_gui_wait_for_idle(rdev)) { 10948c2ecf20Sopenharmony_ci pr_warn("Failed to wait GUI idle while programming pipes. Bad things might happen.\n"); 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (rdev->me_fw) { 10988c2ecf20Sopenharmony_ci size = rdev->me_fw->size / 4; 10998c2ecf20Sopenharmony_ci fw_data = (const __be32 *)&rdev->me_fw->data[0]; 11008c2ecf20Sopenharmony_ci WREG32(RADEON_CP_ME_RAM_ADDR, 0); 11018c2ecf20Sopenharmony_ci for (i = 0; i < size; i += 2) { 11028c2ecf20Sopenharmony_ci WREG32(RADEON_CP_ME_RAM_DATAH, 11038c2ecf20Sopenharmony_ci be32_to_cpup(&fw_data[i])); 11048c2ecf20Sopenharmony_ci WREG32(RADEON_CP_ME_RAM_DATAL, 11058c2ecf20Sopenharmony_ci be32_to_cpup(&fw_data[i + 1])); 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ciint r100_cp_init(struct radeon_device *rdev, unsigned ring_size) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; 11138c2ecf20Sopenharmony_ci unsigned rb_bufsz; 11148c2ecf20Sopenharmony_ci unsigned rb_blksz; 11158c2ecf20Sopenharmony_ci unsigned max_fetch; 11168c2ecf20Sopenharmony_ci unsigned pre_write_timer; 11178c2ecf20Sopenharmony_ci unsigned pre_write_limit; 11188c2ecf20Sopenharmony_ci unsigned indirect2_start; 11198c2ecf20Sopenharmony_ci unsigned indirect1_start; 11208c2ecf20Sopenharmony_ci uint32_t tmp; 11218c2ecf20Sopenharmony_ci int r; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci if (r100_debugfs_cp_init(rdev)) { 11248c2ecf20Sopenharmony_ci DRM_ERROR("Failed to register debugfs file for CP !\n"); 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci if (!rdev->me_fw) { 11278c2ecf20Sopenharmony_ci r = r100_cp_init_microcode(rdev); 11288c2ecf20Sopenharmony_ci if (r) { 11298c2ecf20Sopenharmony_ci DRM_ERROR("Failed to load firmware!\n"); 11308c2ecf20Sopenharmony_ci return r; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci /* Align ring size */ 11358c2ecf20Sopenharmony_ci rb_bufsz = order_base_2(ring_size / 8); 11368c2ecf20Sopenharmony_ci ring_size = (1 << (rb_bufsz + 1)) * 4; 11378c2ecf20Sopenharmony_ci r100_cp_load_microcode(rdev); 11388c2ecf20Sopenharmony_ci r = radeon_ring_init(rdev, ring, ring_size, RADEON_WB_CP_RPTR_OFFSET, 11398c2ecf20Sopenharmony_ci RADEON_CP_PACKET2); 11408c2ecf20Sopenharmony_ci if (r) { 11418c2ecf20Sopenharmony_ci return r; 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci /* Each time the cp read 1024 bytes (16 dword/quadword) update 11448c2ecf20Sopenharmony_ci * the rptr copy in system ram */ 11458c2ecf20Sopenharmony_ci rb_blksz = 9; 11468c2ecf20Sopenharmony_ci /* cp will read 128bytes at a time (4 dwords) */ 11478c2ecf20Sopenharmony_ci max_fetch = 1; 11488c2ecf20Sopenharmony_ci ring->align_mask = 16 - 1; 11498c2ecf20Sopenharmony_ci /* Write to CP_RB_WPTR will be delayed for pre_write_timer clocks */ 11508c2ecf20Sopenharmony_ci pre_write_timer = 64; 11518c2ecf20Sopenharmony_ci /* Force CP_RB_WPTR write if written more than one time before the 11528c2ecf20Sopenharmony_ci * delay expire 11538c2ecf20Sopenharmony_ci */ 11548c2ecf20Sopenharmony_ci pre_write_limit = 0; 11558c2ecf20Sopenharmony_ci /* Setup the cp cache like this (cache size is 96 dwords) : 11568c2ecf20Sopenharmony_ci * RING 0 to 15 11578c2ecf20Sopenharmony_ci * INDIRECT1 16 to 79 11588c2ecf20Sopenharmony_ci * INDIRECT2 80 to 95 11598c2ecf20Sopenharmony_ci * So ring cache size is 16dwords (> (2 * max_fetch = 2 * 4dwords)) 11608c2ecf20Sopenharmony_ci * indirect1 cache size is 64dwords (> (2 * max_fetch = 2 * 4dwords)) 11618c2ecf20Sopenharmony_ci * indirect2 cache size is 16dwords (> (2 * max_fetch = 2 * 4dwords)) 11628c2ecf20Sopenharmony_ci * Idea being that most of the gpu cmd will be through indirect1 buffer 11638c2ecf20Sopenharmony_ci * so it gets the bigger cache. 11648c2ecf20Sopenharmony_ci */ 11658c2ecf20Sopenharmony_ci indirect2_start = 80; 11668c2ecf20Sopenharmony_ci indirect1_start = 16; 11678c2ecf20Sopenharmony_ci /* cp setup */ 11688c2ecf20Sopenharmony_ci WREG32(0x718, pre_write_timer | (pre_write_limit << 28)); 11698c2ecf20Sopenharmony_ci tmp = (REG_SET(RADEON_RB_BUFSZ, rb_bufsz) | 11708c2ecf20Sopenharmony_ci REG_SET(RADEON_RB_BLKSZ, rb_blksz) | 11718c2ecf20Sopenharmony_ci REG_SET(RADEON_MAX_FETCH, max_fetch)); 11728c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 11738c2ecf20Sopenharmony_ci tmp |= RADEON_BUF_SWAP_32BIT; 11748c2ecf20Sopenharmony_ci#endif 11758c2ecf20Sopenharmony_ci WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_NO_UPDATE); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci /* Set ring address */ 11788c2ecf20Sopenharmony_ci DRM_INFO("radeon: ring at 0x%016lX\n", (unsigned long)ring->gpu_addr); 11798c2ecf20Sopenharmony_ci WREG32(RADEON_CP_RB_BASE, ring->gpu_addr); 11808c2ecf20Sopenharmony_ci /* Force read & write ptr to 0 */ 11818c2ecf20Sopenharmony_ci WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA | RADEON_RB_NO_UPDATE); 11828c2ecf20Sopenharmony_ci WREG32(RADEON_CP_RB_RPTR_WR, 0); 11838c2ecf20Sopenharmony_ci ring->wptr = 0; 11848c2ecf20Sopenharmony_ci WREG32(RADEON_CP_RB_WPTR, ring->wptr); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci /* set the wb address whether it's enabled or not */ 11878c2ecf20Sopenharmony_ci WREG32(R_00070C_CP_RB_RPTR_ADDR, 11888c2ecf20Sopenharmony_ci S_00070C_RB_RPTR_ADDR((rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) >> 2)); 11898c2ecf20Sopenharmony_ci WREG32(R_000774_SCRATCH_ADDR, rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci if (rdev->wb.enabled) 11928c2ecf20Sopenharmony_ci WREG32(R_000770_SCRATCH_UMSK, 0xff); 11938c2ecf20Sopenharmony_ci else { 11948c2ecf20Sopenharmony_ci tmp |= RADEON_RB_NO_UPDATE; 11958c2ecf20Sopenharmony_ci WREG32(R_000770_SCRATCH_UMSK, 0); 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci WREG32(RADEON_CP_RB_CNTL, tmp); 11998c2ecf20Sopenharmony_ci udelay(10); 12008c2ecf20Sopenharmony_ci /* Set cp mode to bus mastering & enable cp*/ 12018c2ecf20Sopenharmony_ci WREG32(RADEON_CP_CSQ_MODE, 12028c2ecf20Sopenharmony_ci REG_SET(RADEON_INDIRECT2_START, indirect2_start) | 12038c2ecf20Sopenharmony_ci REG_SET(RADEON_INDIRECT1_START, indirect1_start)); 12048c2ecf20Sopenharmony_ci WREG32(RADEON_CP_RB_WPTR_DELAY, 0); 12058c2ecf20Sopenharmony_ci WREG32(RADEON_CP_CSQ_MODE, 0x00004D4D); 12068c2ecf20Sopenharmony_ci WREG32(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci /* at this point everything should be setup correctly to enable master */ 12098c2ecf20Sopenharmony_ci pci_set_master(rdev->pdev); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci radeon_ring_start(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); 12128c2ecf20Sopenharmony_ci r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, ring); 12138c2ecf20Sopenharmony_ci if (r) { 12148c2ecf20Sopenharmony_ci DRM_ERROR("radeon: cp isn't working (%d).\n", r); 12158c2ecf20Sopenharmony_ci return r; 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci ring->ready = true; 12188c2ecf20Sopenharmony_ci radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci if (!ring->rptr_save_reg /* not resuming from suspend */ 12218c2ecf20Sopenharmony_ci && radeon_ring_supports_scratch_reg(rdev, ring)) { 12228c2ecf20Sopenharmony_ci r = radeon_scratch_get(rdev, &ring->rptr_save_reg); 12238c2ecf20Sopenharmony_ci if (r) { 12248c2ecf20Sopenharmony_ci DRM_ERROR("failed to get scratch reg for rptr save (%d).\n", r); 12258c2ecf20Sopenharmony_ci ring->rptr_save_reg = 0; 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci return 0; 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_civoid r100_cp_fini(struct radeon_device *rdev) 12328c2ecf20Sopenharmony_ci{ 12338c2ecf20Sopenharmony_ci if (r100_cp_wait_for_idle(rdev)) { 12348c2ecf20Sopenharmony_ci DRM_ERROR("Wait for CP idle timeout, shutting down CP.\n"); 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci /* Disable ring */ 12378c2ecf20Sopenharmony_ci r100_cp_disable(rdev); 12388c2ecf20Sopenharmony_ci radeon_scratch_free(rdev, rdev->ring[RADEON_RING_TYPE_GFX_INDEX].rptr_save_reg); 12398c2ecf20Sopenharmony_ci radeon_ring_fini(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); 12408c2ecf20Sopenharmony_ci DRM_INFO("radeon: cp finalized\n"); 12418c2ecf20Sopenharmony_ci} 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_civoid r100_cp_disable(struct radeon_device *rdev) 12448c2ecf20Sopenharmony_ci{ 12458c2ecf20Sopenharmony_ci /* Disable ring */ 12468c2ecf20Sopenharmony_ci radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); 12478c2ecf20Sopenharmony_ci rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false; 12488c2ecf20Sopenharmony_ci WREG32(RADEON_CP_CSQ_MODE, 0); 12498c2ecf20Sopenharmony_ci WREG32(RADEON_CP_CSQ_CNTL, 0); 12508c2ecf20Sopenharmony_ci WREG32(R_000770_SCRATCH_UMSK, 0); 12518c2ecf20Sopenharmony_ci if (r100_gui_wait_for_idle(rdev)) { 12528c2ecf20Sopenharmony_ci pr_warn("Failed to wait GUI idle while programming pipes. Bad things might happen.\n"); 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci/* 12578c2ecf20Sopenharmony_ci * CS functions 12588c2ecf20Sopenharmony_ci */ 12598c2ecf20Sopenharmony_ciint r100_reloc_pitch_offset(struct radeon_cs_parser *p, 12608c2ecf20Sopenharmony_ci struct radeon_cs_packet *pkt, 12618c2ecf20Sopenharmony_ci unsigned idx, 12628c2ecf20Sopenharmony_ci unsigned reg) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci int r; 12658c2ecf20Sopenharmony_ci u32 tile_flags = 0; 12668c2ecf20Sopenharmony_ci u32 tmp; 12678c2ecf20Sopenharmony_ci struct radeon_bo_list *reloc; 12688c2ecf20Sopenharmony_ci u32 value; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 12718c2ecf20Sopenharmony_ci if (r) { 12728c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 12738c2ecf20Sopenharmony_ci idx, reg); 12748c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 12758c2ecf20Sopenharmony_ci return r; 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci value = radeon_get_ib_value(p, idx); 12798c2ecf20Sopenharmony_ci tmp = value & 0x003fffff; 12808c2ecf20Sopenharmony_ci tmp += (((u32)reloc->gpu_offset) >> 10); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { 12838c2ecf20Sopenharmony_ci if (reloc->tiling_flags & RADEON_TILING_MACRO) 12848c2ecf20Sopenharmony_ci tile_flags |= RADEON_DST_TILE_MACRO; 12858c2ecf20Sopenharmony_ci if (reloc->tiling_flags & RADEON_TILING_MICRO) { 12868c2ecf20Sopenharmony_ci if (reg == RADEON_SRC_PITCH_OFFSET) { 12878c2ecf20Sopenharmony_ci DRM_ERROR("Cannot src blit from microtiled surface\n"); 12888c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 12898c2ecf20Sopenharmony_ci return -EINVAL; 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci tile_flags |= RADEON_DST_TILE_MICRO; 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci tmp |= tile_flags; 12958c2ecf20Sopenharmony_ci p->ib.ptr[idx] = (value & 0x3fc00000) | tmp; 12968c2ecf20Sopenharmony_ci } else 12978c2ecf20Sopenharmony_ci p->ib.ptr[idx] = (value & 0xffc00000) | tmp; 12988c2ecf20Sopenharmony_ci return 0; 12998c2ecf20Sopenharmony_ci} 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ciint r100_packet3_load_vbpntr(struct radeon_cs_parser *p, 13028c2ecf20Sopenharmony_ci struct radeon_cs_packet *pkt, 13038c2ecf20Sopenharmony_ci int idx) 13048c2ecf20Sopenharmony_ci{ 13058c2ecf20Sopenharmony_ci unsigned c, i; 13068c2ecf20Sopenharmony_ci struct radeon_bo_list *reloc; 13078c2ecf20Sopenharmony_ci struct r100_cs_track *track; 13088c2ecf20Sopenharmony_ci int r = 0; 13098c2ecf20Sopenharmony_ci volatile uint32_t *ib; 13108c2ecf20Sopenharmony_ci u32 idx_value; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci ib = p->ib.ptr; 13138c2ecf20Sopenharmony_ci track = (struct r100_cs_track *)p->track; 13148c2ecf20Sopenharmony_ci c = radeon_get_ib_value(p, idx++) & 0x1F; 13158c2ecf20Sopenharmony_ci if (c > 16) { 13168c2ecf20Sopenharmony_ci DRM_ERROR("Only 16 vertex buffers are allowed %d\n", 13178c2ecf20Sopenharmony_ci pkt->opcode); 13188c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 13198c2ecf20Sopenharmony_ci return -EINVAL; 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci track->num_arrays = c; 13228c2ecf20Sopenharmony_ci for (i = 0; i < (c - 1); i+=2, idx+=3) { 13238c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 13248c2ecf20Sopenharmony_ci if (r) { 13258c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for packet3 %d\n", 13268c2ecf20Sopenharmony_ci pkt->opcode); 13278c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 13288c2ecf20Sopenharmony_ci return r; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci idx_value = radeon_get_ib_value(p, idx); 13318c2ecf20Sopenharmony_ci ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->gpu_offset); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci track->arrays[i + 0].esize = idx_value >> 8; 13348c2ecf20Sopenharmony_ci track->arrays[i + 0].robj = reloc->robj; 13358c2ecf20Sopenharmony_ci track->arrays[i + 0].esize &= 0x7F; 13368c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 13378c2ecf20Sopenharmony_ci if (r) { 13388c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for packet3 %d\n", 13398c2ecf20Sopenharmony_ci pkt->opcode); 13408c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 13418c2ecf20Sopenharmony_ci return r; 13428c2ecf20Sopenharmony_ci } 13438c2ecf20Sopenharmony_ci ib[idx+2] = radeon_get_ib_value(p, idx + 2) + ((u32)reloc->gpu_offset); 13448c2ecf20Sopenharmony_ci track->arrays[i + 1].robj = reloc->robj; 13458c2ecf20Sopenharmony_ci track->arrays[i + 1].esize = idx_value >> 24; 13468c2ecf20Sopenharmony_ci track->arrays[i + 1].esize &= 0x7F; 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci if (c & 1) { 13498c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 13508c2ecf20Sopenharmony_ci if (r) { 13518c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for packet3 %d\n", 13528c2ecf20Sopenharmony_ci pkt->opcode); 13538c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 13548c2ecf20Sopenharmony_ci return r; 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci idx_value = radeon_get_ib_value(p, idx); 13578c2ecf20Sopenharmony_ci ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->gpu_offset); 13588c2ecf20Sopenharmony_ci track->arrays[i + 0].robj = reloc->robj; 13598c2ecf20Sopenharmony_ci track->arrays[i + 0].esize = idx_value >> 8; 13608c2ecf20Sopenharmony_ci track->arrays[i + 0].esize &= 0x7F; 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci return r; 13638c2ecf20Sopenharmony_ci} 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ciint r100_cs_parse_packet0(struct radeon_cs_parser *p, 13668c2ecf20Sopenharmony_ci struct radeon_cs_packet *pkt, 13678c2ecf20Sopenharmony_ci const unsigned *auth, unsigned n, 13688c2ecf20Sopenharmony_ci radeon_packet0_check_t check) 13698c2ecf20Sopenharmony_ci{ 13708c2ecf20Sopenharmony_ci unsigned reg; 13718c2ecf20Sopenharmony_ci unsigned i, j, m; 13728c2ecf20Sopenharmony_ci unsigned idx; 13738c2ecf20Sopenharmony_ci int r; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci idx = pkt->idx + 1; 13768c2ecf20Sopenharmony_ci reg = pkt->reg; 13778c2ecf20Sopenharmony_ci /* Check that register fall into register range 13788c2ecf20Sopenharmony_ci * determined by the number of entry (n) in the 13798c2ecf20Sopenharmony_ci * safe register bitmap. 13808c2ecf20Sopenharmony_ci */ 13818c2ecf20Sopenharmony_ci if (pkt->one_reg_wr) { 13828c2ecf20Sopenharmony_ci if ((reg >> 7) > n) { 13838c2ecf20Sopenharmony_ci return -EINVAL; 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci } else { 13868c2ecf20Sopenharmony_ci if (((reg + (pkt->count << 2)) >> 7) > n) { 13878c2ecf20Sopenharmony_ci return -EINVAL; 13888c2ecf20Sopenharmony_ci } 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci for (i = 0; i <= pkt->count; i++, idx++) { 13918c2ecf20Sopenharmony_ci j = (reg >> 7); 13928c2ecf20Sopenharmony_ci m = 1 << ((reg >> 2) & 31); 13938c2ecf20Sopenharmony_ci if (auth[j] & m) { 13948c2ecf20Sopenharmony_ci r = check(p, pkt, idx, reg); 13958c2ecf20Sopenharmony_ci if (r) { 13968c2ecf20Sopenharmony_ci return r; 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci if (pkt->one_reg_wr) { 14008c2ecf20Sopenharmony_ci if (!(auth[j] & m)) { 14018c2ecf20Sopenharmony_ci break; 14028c2ecf20Sopenharmony_ci } 14038c2ecf20Sopenharmony_ci } else { 14048c2ecf20Sopenharmony_ci reg += 4; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci return 0; 14088c2ecf20Sopenharmony_ci} 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci/** 14118c2ecf20Sopenharmony_ci * r100_cs_packet_next_vline() - parse userspace VLINE packet 14128c2ecf20Sopenharmony_ci * @parser: parser structure holding parsing context. 14138c2ecf20Sopenharmony_ci * 14148c2ecf20Sopenharmony_ci * Userspace sends a special sequence for VLINE waits. 14158c2ecf20Sopenharmony_ci * PACKET0 - VLINE_START_END + value 14168c2ecf20Sopenharmony_ci * PACKET0 - WAIT_UNTIL +_value 14178c2ecf20Sopenharmony_ci * RELOC (P3) - crtc_id in reloc. 14188c2ecf20Sopenharmony_ci * 14198c2ecf20Sopenharmony_ci * This function parses this and relocates the VLINE START END 14208c2ecf20Sopenharmony_ci * and WAIT UNTIL packets to the correct crtc. 14218c2ecf20Sopenharmony_ci * It also detects a switched off crtc and nulls out the 14228c2ecf20Sopenharmony_ci * wait in that case. 14238c2ecf20Sopenharmony_ci */ 14248c2ecf20Sopenharmony_ciint r100_cs_packet_parse_vline(struct radeon_cs_parser *p) 14258c2ecf20Sopenharmony_ci{ 14268c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 14278c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc; 14288c2ecf20Sopenharmony_ci struct radeon_cs_packet p3reloc, waitreloc; 14298c2ecf20Sopenharmony_ci int crtc_id; 14308c2ecf20Sopenharmony_ci int r; 14318c2ecf20Sopenharmony_ci uint32_t header, h_idx, reg; 14328c2ecf20Sopenharmony_ci volatile uint32_t *ib; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci ib = p->ib.ptr; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci /* parse the wait until */ 14378c2ecf20Sopenharmony_ci r = radeon_cs_packet_parse(p, &waitreloc, p->idx); 14388c2ecf20Sopenharmony_ci if (r) 14398c2ecf20Sopenharmony_ci return r; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci /* check its a wait until and only 1 count */ 14428c2ecf20Sopenharmony_ci if (waitreloc.reg != RADEON_WAIT_UNTIL || 14438c2ecf20Sopenharmony_ci waitreloc.count != 0) { 14448c2ecf20Sopenharmony_ci DRM_ERROR("vline wait had illegal wait until segment\n"); 14458c2ecf20Sopenharmony_ci return -EINVAL; 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci if (radeon_get_ib_value(p, waitreloc.idx + 1) != RADEON_WAIT_CRTC_VLINE) { 14498c2ecf20Sopenharmony_ci DRM_ERROR("vline wait had illegal wait until\n"); 14508c2ecf20Sopenharmony_ci return -EINVAL; 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci /* jump over the NOP */ 14548c2ecf20Sopenharmony_ci r = radeon_cs_packet_parse(p, &p3reloc, p->idx + waitreloc.count + 2); 14558c2ecf20Sopenharmony_ci if (r) 14568c2ecf20Sopenharmony_ci return r; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci h_idx = p->idx - 2; 14598c2ecf20Sopenharmony_ci p->idx += waitreloc.count + 2; 14608c2ecf20Sopenharmony_ci p->idx += p3reloc.count + 2; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci header = radeon_get_ib_value(p, h_idx); 14638c2ecf20Sopenharmony_ci crtc_id = radeon_get_ib_value(p, h_idx + 5); 14648c2ecf20Sopenharmony_ci reg = R100_CP_PACKET0_GET_REG(header); 14658c2ecf20Sopenharmony_ci crtc = drm_crtc_find(p->rdev->ddev, p->filp, crtc_id); 14668c2ecf20Sopenharmony_ci if (!crtc) { 14678c2ecf20Sopenharmony_ci DRM_ERROR("cannot find crtc %d\n", crtc_id); 14688c2ecf20Sopenharmony_ci return -ENOENT; 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci radeon_crtc = to_radeon_crtc(crtc); 14718c2ecf20Sopenharmony_ci crtc_id = radeon_crtc->crtc_id; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci if (!crtc->enabled) { 14748c2ecf20Sopenharmony_ci /* if the CRTC isn't enabled - we need to nop out the wait until */ 14758c2ecf20Sopenharmony_ci ib[h_idx + 2] = PACKET2(0); 14768c2ecf20Sopenharmony_ci ib[h_idx + 3] = PACKET2(0); 14778c2ecf20Sopenharmony_ci } else if (crtc_id == 1) { 14788c2ecf20Sopenharmony_ci switch (reg) { 14798c2ecf20Sopenharmony_ci case AVIVO_D1MODE_VLINE_START_END: 14808c2ecf20Sopenharmony_ci header &= ~R300_CP_PACKET0_REG_MASK; 14818c2ecf20Sopenharmony_ci header |= AVIVO_D2MODE_VLINE_START_END >> 2; 14828c2ecf20Sopenharmony_ci break; 14838c2ecf20Sopenharmony_ci case RADEON_CRTC_GUI_TRIG_VLINE: 14848c2ecf20Sopenharmony_ci header &= ~R300_CP_PACKET0_REG_MASK; 14858c2ecf20Sopenharmony_ci header |= RADEON_CRTC2_GUI_TRIG_VLINE >> 2; 14868c2ecf20Sopenharmony_ci break; 14878c2ecf20Sopenharmony_ci default: 14888c2ecf20Sopenharmony_ci DRM_ERROR("unknown crtc reloc\n"); 14898c2ecf20Sopenharmony_ci return -EINVAL; 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci ib[h_idx] = header; 14928c2ecf20Sopenharmony_ci ib[h_idx + 3] |= RADEON_ENG_DISPLAY_SELECT_CRTC1; 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci return 0; 14968c2ecf20Sopenharmony_ci} 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_cistatic int r100_get_vtx_size(uint32_t vtx_fmt) 14998c2ecf20Sopenharmony_ci{ 15008c2ecf20Sopenharmony_ci int vtx_size; 15018c2ecf20Sopenharmony_ci vtx_size = 2; 15028c2ecf20Sopenharmony_ci /* ordered according to bits in spec */ 15038c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_W0) 15048c2ecf20Sopenharmony_ci vtx_size++; 15058c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_FPCOLOR) 15068c2ecf20Sopenharmony_ci vtx_size += 3; 15078c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_FPALPHA) 15088c2ecf20Sopenharmony_ci vtx_size++; 15098c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_PKCOLOR) 15108c2ecf20Sopenharmony_ci vtx_size++; 15118c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_FPSPEC) 15128c2ecf20Sopenharmony_ci vtx_size += 3; 15138c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_FPFOG) 15148c2ecf20Sopenharmony_ci vtx_size++; 15158c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_PKSPEC) 15168c2ecf20Sopenharmony_ci vtx_size++; 15178c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_ST0) 15188c2ecf20Sopenharmony_ci vtx_size += 2; 15198c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_ST1) 15208c2ecf20Sopenharmony_ci vtx_size += 2; 15218c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_Q1) 15228c2ecf20Sopenharmony_ci vtx_size++; 15238c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_ST2) 15248c2ecf20Sopenharmony_ci vtx_size += 2; 15258c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_Q2) 15268c2ecf20Sopenharmony_ci vtx_size++; 15278c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_ST3) 15288c2ecf20Sopenharmony_ci vtx_size += 2; 15298c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_Q3) 15308c2ecf20Sopenharmony_ci vtx_size++; 15318c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_Q0) 15328c2ecf20Sopenharmony_ci vtx_size++; 15338c2ecf20Sopenharmony_ci /* blend weight */ 15348c2ecf20Sopenharmony_ci if (vtx_fmt & (0x7 << 15)) 15358c2ecf20Sopenharmony_ci vtx_size += (vtx_fmt >> 15) & 0x7; 15368c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_N0) 15378c2ecf20Sopenharmony_ci vtx_size += 3; 15388c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_XY1) 15398c2ecf20Sopenharmony_ci vtx_size += 2; 15408c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_Z1) 15418c2ecf20Sopenharmony_ci vtx_size++; 15428c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_W1) 15438c2ecf20Sopenharmony_ci vtx_size++; 15448c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_N1) 15458c2ecf20Sopenharmony_ci vtx_size++; 15468c2ecf20Sopenharmony_ci if (vtx_fmt & RADEON_SE_VTX_FMT_Z) 15478c2ecf20Sopenharmony_ci vtx_size++; 15488c2ecf20Sopenharmony_ci return vtx_size; 15498c2ecf20Sopenharmony_ci} 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_cistatic int r100_packet0_check(struct radeon_cs_parser *p, 15528c2ecf20Sopenharmony_ci struct radeon_cs_packet *pkt, 15538c2ecf20Sopenharmony_ci unsigned idx, unsigned reg) 15548c2ecf20Sopenharmony_ci{ 15558c2ecf20Sopenharmony_ci struct radeon_bo_list *reloc; 15568c2ecf20Sopenharmony_ci struct r100_cs_track *track; 15578c2ecf20Sopenharmony_ci volatile uint32_t *ib; 15588c2ecf20Sopenharmony_ci uint32_t tmp; 15598c2ecf20Sopenharmony_ci int r; 15608c2ecf20Sopenharmony_ci int i, face; 15618c2ecf20Sopenharmony_ci u32 tile_flags = 0; 15628c2ecf20Sopenharmony_ci u32 idx_value; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci ib = p->ib.ptr; 15658c2ecf20Sopenharmony_ci track = (struct r100_cs_track *)p->track; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci idx_value = radeon_get_ib_value(p, idx); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci switch (reg) { 15708c2ecf20Sopenharmony_ci case RADEON_CRTC_GUI_TRIG_VLINE: 15718c2ecf20Sopenharmony_ci r = r100_cs_packet_parse_vline(p); 15728c2ecf20Sopenharmony_ci if (r) { 15738c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 15748c2ecf20Sopenharmony_ci idx, reg); 15758c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 15768c2ecf20Sopenharmony_ci return r; 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci break; 15798c2ecf20Sopenharmony_ci /* FIXME: only allow PACKET3 blit? easier to check for out of 15808c2ecf20Sopenharmony_ci * range access */ 15818c2ecf20Sopenharmony_ci case RADEON_DST_PITCH_OFFSET: 15828c2ecf20Sopenharmony_ci case RADEON_SRC_PITCH_OFFSET: 15838c2ecf20Sopenharmony_ci r = r100_reloc_pitch_offset(p, pkt, idx, reg); 15848c2ecf20Sopenharmony_ci if (r) 15858c2ecf20Sopenharmony_ci return r; 15868c2ecf20Sopenharmony_ci break; 15878c2ecf20Sopenharmony_ci case RADEON_RB3D_DEPTHOFFSET: 15888c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 15898c2ecf20Sopenharmony_ci if (r) { 15908c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 15918c2ecf20Sopenharmony_ci idx, reg); 15928c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 15938c2ecf20Sopenharmony_ci return r; 15948c2ecf20Sopenharmony_ci } 15958c2ecf20Sopenharmony_ci track->zb.robj = reloc->robj; 15968c2ecf20Sopenharmony_ci track->zb.offset = idx_value; 15978c2ecf20Sopenharmony_ci track->zb_dirty = true; 15988c2ecf20Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 15998c2ecf20Sopenharmony_ci break; 16008c2ecf20Sopenharmony_ci case RADEON_RB3D_COLOROFFSET: 16018c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 16028c2ecf20Sopenharmony_ci if (r) { 16038c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 16048c2ecf20Sopenharmony_ci idx, reg); 16058c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 16068c2ecf20Sopenharmony_ci return r; 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci track->cb[0].robj = reloc->robj; 16098c2ecf20Sopenharmony_ci track->cb[0].offset = idx_value; 16108c2ecf20Sopenharmony_ci track->cb_dirty = true; 16118c2ecf20Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 16128c2ecf20Sopenharmony_ci break; 16138c2ecf20Sopenharmony_ci case RADEON_PP_TXOFFSET_0: 16148c2ecf20Sopenharmony_ci case RADEON_PP_TXOFFSET_1: 16158c2ecf20Sopenharmony_ci case RADEON_PP_TXOFFSET_2: 16168c2ecf20Sopenharmony_ci i = (reg - RADEON_PP_TXOFFSET_0) / 24; 16178c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 16188c2ecf20Sopenharmony_ci if (r) { 16198c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 16208c2ecf20Sopenharmony_ci idx, reg); 16218c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 16228c2ecf20Sopenharmony_ci return r; 16238c2ecf20Sopenharmony_ci } 16248c2ecf20Sopenharmony_ci if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { 16258c2ecf20Sopenharmony_ci if (reloc->tiling_flags & RADEON_TILING_MACRO) 16268c2ecf20Sopenharmony_ci tile_flags |= RADEON_TXO_MACRO_TILE; 16278c2ecf20Sopenharmony_ci if (reloc->tiling_flags & RADEON_TILING_MICRO) 16288c2ecf20Sopenharmony_ci tile_flags |= RADEON_TXO_MICRO_TILE_X2; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci tmp = idx_value & ~(0x7 << 2); 16318c2ecf20Sopenharmony_ci tmp |= tile_flags; 16328c2ecf20Sopenharmony_ci ib[idx] = tmp + ((u32)reloc->gpu_offset); 16338c2ecf20Sopenharmony_ci } else 16348c2ecf20Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 16358c2ecf20Sopenharmony_ci track->textures[i].robj = reloc->robj; 16368c2ecf20Sopenharmony_ci track->tex_dirty = true; 16378c2ecf20Sopenharmony_ci break; 16388c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T0_0: 16398c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T0_1: 16408c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T0_2: 16418c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T0_3: 16428c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T0_4: 16438c2ecf20Sopenharmony_ci i = (reg - RADEON_PP_CUBIC_OFFSET_T0_0) / 4; 16448c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 16458c2ecf20Sopenharmony_ci if (r) { 16468c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 16478c2ecf20Sopenharmony_ci idx, reg); 16488c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 16498c2ecf20Sopenharmony_ci return r; 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci track->textures[0].cube_info[i].offset = idx_value; 16528c2ecf20Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 16538c2ecf20Sopenharmony_ci track->textures[0].cube_info[i].robj = reloc->robj; 16548c2ecf20Sopenharmony_ci track->tex_dirty = true; 16558c2ecf20Sopenharmony_ci break; 16568c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T1_0: 16578c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T1_1: 16588c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T1_2: 16598c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T1_3: 16608c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T1_4: 16618c2ecf20Sopenharmony_ci i = (reg - RADEON_PP_CUBIC_OFFSET_T1_0) / 4; 16628c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 16638c2ecf20Sopenharmony_ci if (r) { 16648c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 16658c2ecf20Sopenharmony_ci idx, reg); 16668c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 16678c2ecf20Sopenharmony_ci return r; 16688c2ecf20Sopenharmony_ci } 16698c2ecf20Sopenharmony_ci track->textures[1].cube_info[i].offset = idx_value; 16708c2ecf20Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 16718c2ecf20Sopenharmony_ci track->textures[1].cube_info[i].robj = reloc->robj; 16728c2ecf20Sopenharmony_ci track->tex_dirty = true; 16738c2ecf20Sopenharmony_ci break; 16748c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T2_0: 16758c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T2_1: 16768c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T2_2: 16778c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T2_3: 16788c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_OFFSET_T2_4: 16798c2ecf20Sopenharmony_ci i = (reg - RADEON_PP_CUBIC_OFFSET_T2_0) / 4; 16808c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 16818c2ecf20Sopenharmony_ci if (r) { 16828c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 16838c2ecf20Sopenharmony_ci idx, reg); 16848c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 16858c2ecf20Sopenharmony_ci return r; 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_ci track->textures[2].cube_info[i].offset = idx_value; 16888c2ecf20Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 16898c2ecf20Sopenharmony_ci track->textures[2].cube_info[i].robj = reloc->robj; 16908c2ecf20Sopenharmony_ci track->tex_dirty = true; 16918c2ecf20Sopenharmony_ci break; 16928c2ecf20Sopenharmony_ci case RADEON_RE_WIDTH_HEIGHT: 16938c2ecf20Sopenharmony_ci track->maxy = ((idx_value >> 16) & 0x7FF); 16948c2ecf20Sopenharmony_ci track->cb_dirty = true; 16958c2ecf20Sopenharmony_ci track->zb_dirty = true; 16968c2ecf20Sopenharmony_ci break; 16978c2ecf20Sopenharmony_ci case RADEON_RB3D_COLORPITCH: 16988c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 16998c2ecf20Sopenharmony_ci if (r) { 17008c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 17018c2ecf20Sopenharmony_ci idx, reg); 17028c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 17038c2ecf20Sopenharmony_ci return r; 17048c2ecf20Sopenharmony_ci } 17058c2ecf20Sopenharmony_ci if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { 17068c2ecf20Sopenharmony_ci if (reloc->tiling_flags & RADEON_TILING_MACRO) 17078c2ecf20Sopenharmony_ci tile_flags |= RADEON_COLOR_TILE_ENABLE; 17088c2ecf20Sopenharmony_ci if (reloc->tiling_flags & RADEON_TILING_MICRO) 17098c2ecf20Sopenharmony_ci tile_flags |= RADEON_COLOR_MICROTILE_ENABLE; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci tmp = idx_value & ~(0x7 << 16); 17128c2ecf20Sopenharmony_ci tmp |= tile_flags; 17138c2ecf20Sopenharmony_ci ib[idx] = tmp; 17148c2ecf20Sopenharmony_ci } else 17158c2ecf20Sopenharmony_ci ib[idx] = idx_value; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci track->cb[0].pitch = idx_value & RADEON_COLORPITCH_MASK; 17188c2ecf20Sopenharmony_ci track->cb_dirty = true; 17198c2ecf20Sopenharmony_ci break; 17208c2ecf20Sopenharmony_ci case RADEON_RB3D_DEPTHPITCH: 17218c2ecf20Sopenharmony_ci track->zb.pitch = idx_value & RADEON_DEPTHPITCH_MASK; 17228c2ecf20Sopenharmony_ci track->zb_dirty = true; 17238c2ecf20Sopenharmony_ci break; 17248c2ecf20Sopenharmony_ci case RADEON_RB3D_CNTL: 17258c2ecf20Sopenharmony_ci switch ((idx_value >> RADEON_RB3D_COLOR_FORMAT_SHIFT) & 0x1f) { 17268c2ecf20Sopenharmony_ci case 7: 17278c2ecf20Sopenharmony_ci case 8: 17288c2ecf20Sopenharmony_ci case 9: 17298c2ecf20Sopenharmony_ci case 11: 17308c2ecf20Sopenharmony_ci case 12: 17318c2ecf20Sopenharmony_ci track->cb[0].cpp = 1; 17328c2ecf20Sopenharmony_ci break; 17338c2ecf20Sopenharmony_ci case 3: 17348c2ecf20Sopenharmony_ci case 4: 17358c2ecf20Sopenharmony_ci case 15: 17368c2ecf20Sopenharmony_ci track->cb[0].cpp = 2; 17378c2ecf20Sopenharmony_ci break; 17388c2ecf20Sopenharmony_ci case 6: 17398c2ecf20Sopenharmony_ci track->cb[0].cpp = 4; 17408c2ecf20Sopenharmony_ci break; 17418c2ecf20Sopenharmony_ci default: 17428c2ecf20Sopenharmony_ci DRM_ERROR("Invalid color buffer format (%d) !\n", 17438c2ecf20Sopenharmony_ci ((idx_value >> RADEON_RB3D_COLOR_FORMAT_SHIFT) & 0x1f)); 17448c2ecf20Sopenharmony_ci return -EINVAL; 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci track->z_enabled = !!(idx_value & RADEON_Z_ENABLE); 17478c2ecf20Sopenharmony_ci track->cb_dirty = true; 17488c2ecf20Sopenharmony_ci track->zb_dirty = true; 17498c2ecf20Sopenharmony_ci break; 17508c2ecf20Sopenharmony_ci case RADEON_RB3D_ZSTENCILCNTL: 17518c2ecf20Sopenharmony_ci switch (idx_value & 0xf) { 17528c2ecf20Sopenharmony_ci case 0: 17538c2ecf20Sopenharmony_ci track->zb.cpp = 2; 17548c2ecf20Sopenharmony_ci break; 17558c2ecf20Sopenharmony_ci case 2: 17568c2ecf20Sopenharmony_ci case 3: 17578c2ecf20Sopenharmony_ci case 4: 17588c2ecf20Sopenharmony_ci case 5: 17598c2ecf20Sopenharmony_ci case 9: 17608c2ecf20Sopenharmony_ci case 11: 17618c2ecf20Sopenharmony_ci track->zb.cpp = 4; 17628c2ecf20Sopenharmony_ci break; 17638c2ecf20Sopenharmony_ci default: 17648c2ecf20Sopenharmony_ci break; 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci track->zb_dirty = true; 17678c2ecf20Sopenharmony_ci break; 17688c2ecf20Sopenharmony_ci case RADEON_RB3D_ZPASS_ADDR: 17698c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 17708c2ecf20Sopenharmony_ci if (r) { 17718c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 17728c2ecf20Sopenharmony_ci idx, reg); 17738c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 17748c2ecf20Sopenharmony_ci return r; 17758c2ecf20Sopenharmony_ci } 17768c2ecf20Sopenharmony_ci ib[idx] = idx_value + ((u32)reloc->gpu_offset); 17778c2ecf20Sopenharmony_ci break; 17788c2ecf20Sopenharmony_ci case RADEON_PP_CNTL: 17798c2ecf20Sopenharmony_ci { 17808c2ecf20Sopenharmony_ci uint32_t temp = idx_value >> 4; 17818c2ecf20Sopenharmony_ci for (i = 0; i < track->num_texture; i++) 17828c2ecf20Sopenharmony_ci track->textures[i].enabled = !!(temp & (1 << i)); 17838c2ecf20Sopenharmony_ci track->tex_dirty = true; 17848c2ecf20Sopenharmony_ci } 17858c2ecf20Sopenharmony_ci break; 17868c2ecf20Sopenharmony_ci case RADEON_SE_VF_CNTL: 17878c2ecf20Sopenharmony_ci track->vap_vf_cntl = idx_value; 17888c2ecf20Sopenharmony_ci break; 17898c2ecf20Sopenharmony_ci case RADEON_SE_VTX_FMT: 17908c2ecf20Sopenharmony_ci track->vtx_size = r100_get_vtx_size(idx_value); 17918c2ecf20Sopenharmony_ci break; 17928c2ecf20Sopenharmony_ci case RADEON_PP_TEX_SIZE_0: 17938c2ecf20Sopenharmony_ci case RADEON_PP_TEX_SIZE_1: 17948c2ecf20Sopenharmony_ci case RADEON_PP_TEX_SIZE_2: 17958c2ecf20Sopenharmony_ci i = (reg - RADEON_PP_TEX_SIZE_0) / 8; 17968c2ecf20Sopenharmony_ci track->textures[i].width = (idx_value & RADEON_TEX_USIZE_MASK) + 1; 17978c2ecf20Sopenharmony_ci track->textures[i].height = ((idx_value & RADEON_TEX_VSIZE_MASK) >> RADEON_TEX_VSIZE_SHIFT) + 1; 17988c2ecf20Sopenharmony_ci track->tex_dirty = true; 17998c2ecf20Sopenharmony_ci break; 18008c2ecf20Sopenharmony_ci case RADEON_PP_TEX_PITCH_0: 18018c2ecf20Sopenharmony_ci case RADEON_PP_TEX_PITCH_1: 18028c2ecf20Sopenharmony_ci case RADEON_PP_TEX_PITCH_2: 18038c2ecf20Sopenharmony_ci i = (reg - RADEON_PP_TEX_PITCH_0) / 8; 18048c2ecf20Sopenharmony_ci track->textures[i].pitch = idx_value + 32; 18058c2ecf20Sopenharmony_ci track->tex_dirty = true; 18068c2ecf20Sopenharmony_ci break; 18078c2ecf20Sopenharmony_ci case RADEON_PP_TXFILTER_0: 18088c2ecf20Sopenharmony_ci case RADEON_PP_TXFILTER_1: 18098c2ecf20Sopenharmony_ci case RADEON_PP_TXFILTER_2: 18108c2ecf20Sopenharmony_ci i = (reg - RADEON_PP_TXFILTER_0) / 24; 18118c2ecf20Sopenharmony_ci track->textures[i].num_levels = ((idx_value & RADEON_MAX_MIP_LEVEL_MASK) 18128c2ecf20Sopenharmony_ci >> RADEON_MAX_MIP_LEVEL_SHIFT); 18138c2ecf20Sopenharmony_ci tmp = (idx_value >> 23) & 0x7; 18148c2ecf20Sopenharmony_ci if (tmp == 2 || tmp == 6) 18158c2ecf20Sopenharmony_ci track->textures[i].roundup_w = false; 18168c2ecf20Sopenharmony_ci tmp = (idx_value >> 27) & 0x7; 18178c2ecf20Sopenharmony_ci if (tmp == 2 || tmp == 6) 18188c2ecf20Sopenharmony_ci track->textures[i].roundup_h = false; 18198c2ecf20Sopenharmony_ci track->tex_dirty = true; 18208c2ecf20Sopenharmony_ci break; 18218c2ecf20Sopenharmony_ci case RADEON_PP_TXFORMAT_0: 18228c2ecf20Sopenharmony_ci case RADEON_PP_TXFORMAT_1: 18238c2ecf20Sopenharmony_ci case RADEON_PP_TXFORMAT_2: 18248c2ecf20Sopenharmony_ci i = (reg - RADEON_PP_TXFORMAT_0) / 24; 18258c2ecf20Sopenharmony_ci if (idx_value & RADEON_TXFORMAT_NON_POWER2) { 18268c2ecf20Sopenharmony_ci track->textures[i].use_pitch = true; 18278c2ecf20Sopenharmony_ci } else { 18288c2ecf20Sopenharmony_ci track->textures[i].use_pitch = false; 18298c2ecf20Sopenharmony_ci track->textures[i].width = 1 << ((idx_value & RADEON_TXFORMAT_WIDTH_MASK) >> RADEON_TXFORMAT_WIDTH_SHIFT); 18308c2ecf20Sopenharmony_ci track->textures[i].height = 1 << ((idx_value & RADEON_TXFORMAT_HEIGHT_MASK) >> RADEON_TXFORMAT_HEIGHT_SHIFT); 18318c2ecf20Sopenharmony_ci } 18328c2ecf20Sopenharmony_ci if (idx_value & RADEON_TXFORMAT_CUBIC_MAP_ENABLE) 18338c2ecf20Sopenharmony_ci track->textures[i].tex_coord_type = 2; 18348c2ecf20Sopenharmony_ci switch ((idx_value & RADEON_TXFORMAT_FORMAT_MASK)) { 18358c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_I8: 18368c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_RGB332: 18378c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_Y8: 18388c2ecf20Sopenharmony_ci track->textures[i].cpp = 1; 18398c2ecf20Sopenharmony_ci track->textures[i].compress_format = R100_TRACK_COMP_NONE; 18408c2ecf20Sopenharmony_ci break; 18418c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_AI88: 18428c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_ARGB1555: 18438c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_RGB565: 18448c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_ARGB4444: 18458c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_VYUY422: 18468c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_YVYU422: 18478c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_SHADOW16: 18488c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_LDUDV655: 18498c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_DUDV88: 18508c2ecf20Sopenharmony_ci track->textures[i].cpp = 2; 18518c2ecf20Sopenharmony_ci track->textures[i].compress_format = R100_TRACK_COMP_NONE; 18528c2ecf20Sopenharmony_ci break; 18538c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_ARGB8888: 18548c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_RGBA8888: 18558c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_SHADOW32: 18568c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_LDUDUV8888: 18578c2ecf20Sopenharmony_ci track->textures[i].cpp = 4; 18588c2ecf20Sopenharmony_ci track->textures[i].compress_format = R100_TRACK_COMP_NONE; 18598c2ecf20Sopenharmony_ci break; 18608c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_DXT1: 18618c2ecf20Sopenharmony_ci track->textures[i].cpp = 1; 18628c2ecf20Sopenharmony_ci track->textures[i].compress_format = R100_TRACK_COMP_DXT1; 18638c2ecf20Sopenharmony_ci break; 18648c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_DXT23: 18658c2ecf20Sopenharmony_ci case RADEON_TXFORMAT_DXT45: 18668c2ecf20Sopenharmony_ci track->textures[i].cpp = 1; 18678c2ecf20Sopenharmony_ci track->textures[i].compress_format = R100_TRACK_COMP_DXT35; 18688c2ecf20Sopenharmony_ci break; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci track->textures[i].cube_info[4].width = 1 << ((idx_value >> 16) & 0xf); 18718c2ecf20Sopenharmony_ci track->textures[i].cube_info[4].height = 1 << ((idx_value >> 20) & 0xf); 18728c2ecf20Sopenharmony_ci track->tex_dirty = true; 18738c2ecf20Sopenharmony_ci break; 18748c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_FACES_0: 18758c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_FACES_1: 18768c2ecf20Sopenharmony_ci case RADEON_PP_CUBIC_FACES_2: 18778c2ecf20Sopenharmony_ci tmp = idx_value; 18788c2ecf20Sopenharmony_ci i = (reg - RADEON_PP_CUBIC_FACES_0) / 4; 18798c2ecf20Sopenharmony_ci for (face = 0; face < 4; face++) { 18808c2ecf20Sopenharmony_ci track->textures[i].cube_info[face].width = 1 << ((tmp >> (face * 8)) & 0xf); 18818c2ecf20Sopenharmony_ci track->textures[i].cube_info[face].height = 1 << ((tmp >> ((face * 8) + 4)) & 0xf); 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci track->tex_dirty = true; 18848c2ecf20Sopenharmony_ci break; 18858c2ecf20Sopenharmony_ci default: 18868c2ecf20Sopenharmony_ci pr_err("Forbidden register 0x%04X in cs at %d\n", reg, idx); 18878c2ecf20Sopenharmony_ci return -EINVAL; 18888c2ecf20Sopenharmony_ci } 18898c2ecf20Sopenharmony_ci return 0; 18908c2ecf20Sopenharmony_ci} 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ciint r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p, 18938c2ecf20Sopenharmony_ci struct radeon_cs_packet *pkt, 18948c2ecf20Sopenharmony_ci struct radeon_bo *robj) 18958c2ecf20Sopenharmony_ci{ 18968c2ecf20Sopenharmony_ci unsigned idx; 18978c2ecf20Sopenharmony_ci u32 value; 18988c2ecf20Sopenharmony_ci idx = pkt->idx + 1; 18998c2ecf20Sopenharmony_ci value = radeon_get_ib_value(p, idx + 2); 19008c2ecf20Sopenharmony_ci if ((value + 1) > radeon_bo_size(robj)) { 19018c2ecf20Sopenharmony_ci DRM_ERROR("[drm] Buffer too small for PACKET3 INDX_BUFFER " 19028c2ecf20Sopenharmony_ci "(need %u have %lu) !\n", 19038c2ecf20Sopenharmony_ci value + 1, 19048c2ecf20Sopenharmony_ci radeon_bo_size(robj)); 19058c2ecf20Sopenharmony_ci return -EINVAL; 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci return 0; 19088c2ecf20Sopenharmony_ci} 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_cistatic int r100_packet3_check(struct radeon_cs_parser *p, 19118c2ecf20Sopenharmony_ci struct radeon_cs_packet *pkt) 19128c2ecf20Sopenharmony_ci{ 19138c2ecf20Sopenharmony_ci struct radeon_bo_list *reloc; 19148c2ecf20Sopenharmony_ci struct r100_cs_track *track; 19158c2ecf20Sopenharmony_ci unsigned idx; 19168c2ecf20Sopenharmony_ci volatile uint32_t *ib; 19178c2ecf20Sopenharmony_ci int r; 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci ib = p->ib.ptr; 19208c2ecf20Sopenharmony_ci idx = pkt->idx + 1; 19218c2ecf20Sopenharmony_ci track = (struct r100_cs_track *)p->track; 19228c2ecf20Sopenharmony_ci switch (pkt->opcode) { 19238c2ecf20Sopenharmony_ci case PACKET3_3D_LOAD_VBPNTR: 19248c2ecf20Sopenharmony_ci r = r100_packet3_load_vbpntr(p, pkt, idx); 19258c2ecf20Sopenharmony_ci if (r) 19268c2ecf20Sopenharmony_ci return r; 19278c2ecf20Sopenharmony_ci break; 19288c2ecf20Sopenharmony_ci case PACKET3_INDX_BUFFER: 19298c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 19308c2ecf20Sopenharmony_ci if (r) { 19318c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for packet3 %d\n", pkt->opcode); 19328c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 19338c2ecf20Sopenharmony_ci return r; 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci ib[idx+1] = radeon_get_ib_value(p, idx+1) + ((u32)reloc->gpu_offset); 19368c2ecf20Sopenharmony_ci r = r100_cs_track_check_pkt3_indx_buffer(p, pkt, reloc->robj); 19378c2ecf20Sopenharmony_ci if (r) { 19388c2ecf20Sopenharmony_ci return r; 19398c2ecf20Sopenharmony_ci } 19408c2ecf20Sopenharmony_ci break; 19418c2ecf20Sopenharmony_ci case 0x23: 19428c2ecf20Sopenharmony_ci /* 3D_RNDR_GEN_INDX_PRIM on r100/r200 */ 19438c2ecf20Sopenharmony_ci r = radeon_cs_packet_next_reloc(p, &reloc, 0); 19448c2ecf20Sopenharmony_ci if (r) { 19458c2ecf20Sopenharmony_ci DRM_ERROR("No reloc for packet3 %d\n", pkt->opcode); 19468c2ecf20Sopenharmony_ci radeon_cs_dump_packet(p, pkt); 19478c2ecf20Sopenharmony_ci return r; 19488c2ecf20Sopenharmony_ci } 19498c2ecf20Sopenharmony_ci ib[idx] = radeon_get_ib_value(p, idx) + ((u32)reloc->gpu_offset); 19508c2ecf20Sopenharmony_ci track->num_arrays = 1; 19518c2ecf20Sopenharmony_ci track->vtx_size = r100_get_vtx_size(radeon_get_ib_value(p, idx + 2)); 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci track->arrays[0].robj = reloc->robj; 19548c2ecf20Sopenharmony_ci track->arrays[0].esize = track->vtx_size; 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci track->max_indx = radeon_get_ib_value(p, idx+1); 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx+3); 19598c2ecf20Sopenharmony_ci track->immd_dwords = pkt->count - 1; 19608c2ecf20Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 19618c2ecf20Sopenharmony_ci if (r) 19628c2ecf20Sopenharmony_ci return r; 19638c2ecf20Sopenharmony_ci break; 19648c2ecf20Sopenharmony_ci case PACKET3_3D_DRAW_IMMD: 19658c2ecf20Sopenharmony_ci if (((radeon_get_ib_value(p, idx + 1) >> 4) & 0x3) != 3) { 19668c2ecf20Sopenharmony_ci DRM_ERROR("PRIM_WALK must be 3 for IMMD draw\n"); 19678c2ecf20Sopenharmony_ci return -EINVAL; 19688c2ecf20Sopenharmony_ci } 19698c2ecf20Sopenharmony_ci track->vtx_size = r100_get_vtx_size(radeon_get_ib_value(p, idx + 0)); 19708c2ecf20Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx + 1); 19718c2ecf20Sopenharmony_ci track->immd_dwords = pkt->count - 1; 19728c2ecf20Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 19738c2ecf20Sopenharmony_ci if (r) 19748c2ecf20Sopenharmony_ci return r; 19758c2ecf20Sopenharmony_ci break; 19768c2ecf20Sopenharmony_ci /* triggers drawing using in-packet vertex data */ 19778c2ecf20Sopenharmony_ci case PACKET3_3D_DRAW_IMMD_2: 19788c2ecf20Sopenharmony_ci if (((radeon_get_ib_value(p, idx) >> 4) & 0x3) != 3) { 19798c2ecf20Sopenharmony_ci DRM_ERROR("PRIM_WALK must be 3 for IMMD draw\n"); 19808c2ecf20Sopenharmony_ci return -EINVAL; 19818c2ecf20Sopenharmony_ci } 19828c2ecf20Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx); 19838c2ecf20Sopenharmony_ci track->immd_dwords = pkt->count; 19848c2ecf20Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 19858c2ecf20Sopenharmony_ci if (r) 19868c2ecf20Sopenharmony_ci return r; 19878c2ecf20Sopenharmony_ci break; 19888c2ecf20Sopenharmony_ci /* triggers drawing using in-packet vertex data */ 19898c2ecf20Sopenharmony_ci case PACKET3_3D_DRAW_VBUF_2: 19908c2ecf20Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx); 19918c2ecf20Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 19928c2ecf20Sopenharmony_ci if (r) 19938c2ecf20Sopenharmony_ci return r; 19948c2ecf20Sopenharmony_ci break; 19958c2ecf20Sopenharmony_ci /* triggers drawing of vertex buffers setup elsewhere */ 19968c2ecf20Sopenharmony_ci case PACKET3_3D_DRAW_INDX_2: 19978c2ecf20Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx); 19988c2ecf20Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 19998c2ecf20Sopenharmony_ci if (r) 20008c2ecf20Sopenharmony_ci return r; 20018c2ecf20Sopenharmony_ci break; 20028c2ecf20Sopenharmony_ci /* triggers drawing using indices to vertex buffer */ 20038c2ecf20Sopenharmony_ci case PACKET3_3D_DRAW_VBUF: 20048c2ecf20Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx + 1); 20058c2ecf20Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 20068c2ecf20Sopenharmony_ci if (r) 20078c2ecf20Sopenharmony_ci return r; 20088c2ecf20Sopenharmony_ci break; 20098c2ecf20Sopenharmony_ci /* triggers drawing of vertex buffers setup elsewhere */ 20108c2ecf20Sopenharmony_ci case PACKET3_3D_DRAW_INDX: 20118c2ecf20Sopenharmony_ci track->vap_vf_cntl = radeon_get_ib_value(p, idx + 1); 20128c2ecf20Sopenharmony_ci r = r100_cs_track_check(p->rdev, track); 20138c2ecf20Sopenharmony_ci if (r) 20148c2ecf20Sopenharmony_ci return r; 20158c2ecf20Sopenharmony_ci break; 20168c2ecf20Sopenharmony_ci /* triggers drawing using indices to vertex buffer */ 20178c2ecf20Sopenharmony_ci case PACKET3_3D_CLEAR_HIZ: 20188c2ecf20Sopenharmony_ci case PACKET3_3D_CLEAR_ZMASK: 20198c2ecf20Sopenharmony_ci if (p->rdev->hyperz_filp != p->filp) 20208c2ecf20Sopenharmony_ci return -EINVAL; 20218c2ecf20Sopenharmony_ci break; 20228c2ecf20Sopenharmony_ci case PACKET3_NOP: 20238c2ecf20Sopenharmony_ci break; 20248c2ecf20Sopenharmony_ci default: 20258c2ecf20Sopenharmony_ci DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode); 20268c2ecf20Sopenharmony_ci return -EINVAL; 20278c2ecf20Sopenharmony_ci } 20288c2ecf20Sopenharmony_ci return 0; 20298c2ecf20Sopenharmony_ci} 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ciint r100_cs_parse(struct radeon_cs_parser *p) 20328c2ecf20Sopenharmony_ci{ 20338c2ecf20Sopenharmony_ci struct radeon_cs_packet pkt; 20348c2ecf20Sopenharmony_ci struct r100_cs_track *track; 20358c2ecf20Sopenharmony_ci int r; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci track = kzalloc(sizeof(*track), GFP_KERNEL); 20388c2ecf20Sopenharmony_ci if (!track) 20398c2ecf20Sopenharmony_ci return -ENOMEM; 20408c2ecf20Sopenharmony_ci r100_cs_track_clear(p->rdev, track); 20418c2ecf20Sopenharmony_ci p->track = track; 20428c2ecf20Sopenharmony_ci do { 20438c2ecf20Sopenharmony_ci r = radeon_cs_packet_parse(p, &pkt, p->idx); 20448c2ecf20Sopenharmony_ci if (r) { 20458c2ecf20Sopenharmony_ci return r; 20468c2ecf20Sopenharmony_ci } 20478c2ecf20Sopenharmony_ci p->idx += pkt.count + 2; 20488c2ecf20Sopenharmony_ci switch (pkt.type) { 20498c2ecf20Sopenharmony_ci case RADEON_PACKET_TYPE0: 20508c2ecf20Sopenharmony_ci if (p->rdev->family >= CHIP_R200) 20518c2ecf20Sopenharmony_ci r = r100_cs_parse_packet0(p, &pkt, 20528c2ecf20Sopenharmony_ci p->rdev->config.r100.reg_safe_bm, 20538c2ecf20Sopenharmony_ci p->rdev->config.r100.reg_safe_bm_size, 20548c2ecf20Sopenharmony_ci &r200_packet0_check); 20558c2ecf20Sopenharmony_ci else 20568c2ecf20Sopenharmony_ci r = r100_cs_parse_packet0(p, &pkt, 20578c2ecf20Sopenharmony_ci p->rdev->config.r100.reg_safe_bm, 20588c2ecf20Sopenharmony_ci p->rdev->config.r100.reg_safe_bm_size, 20598c2ecf20Sopenharmony_ci &r100_packet0_check); 20608c2ecf20Sopenharmony_ci break; 20618c2ecf20Sopenharmony_ci case RADEON_PACKET_TYPE2: 20628c2ecf20Sopenharmony_ci break; 20638c2ecf20Sopenharmony_ci case RADEON_PACKET_TYPE3: 20648c2ecf20Sopenharmony_ci r = r100_packet3_check(p, &pkt); 20658c2ecf20Sopenharmony_ci break; 20668c2ecf20Sopenharmony_ci default: 20678c2ecf20Sopenharmony_ci DRM_ERROR("Unknown packet type %d !\n", 20688c2ecf20Sopenharmony_ci pkt.type); 20698c2ecf20Sopenharmony_ci return -EINVAL; 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci if (r) 20728c2ecf20Sopenharmony_ci return r; 20738c2ecf20Sopenharmony_ci } while (p->idx < p->chunk_ib->length_dw); 20748c2ecf20Sopenharmony_ci return 0; 20758c2ecf20Sopenharmony_ci} 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_cistatic void r100_cs_track_texture_print(struct r100_cs_track_texture *t) 20788c2ecf20Sopenharmony_ci{ 20798c2ecf20Sopenharmony_ci DRM_ERROR("pitch %d\n", t->pitch); 20808c2ecf20Sopenharmony_ci DRM_ERROR("use_pitch %d\n", t->use_pitch); 20818c2ecf20Sopenharmony_ci DRM_ERROR("width %d\n", t->width); 20828c2ecf20Sopenharmony_ci DRM_ERROR("width_11 %d\n", t->width_11); 20838c2ecf20Sopenharmony_ci DRM_ERROR("height %d\n", t->height); 20848c2ecf20Sopenharmony_ci DRM_ERROR("height_11 %d\n", t->height_11); 20858c2ecf20Sopenharmony_ci DRM_ERROR("num levels %d\n", t->num_levels); 20868c2ecf20Sopenharmony_ci DRM_ERROR("depth %d\n", t->txdepth); 20878c2ecf20Sopenharmony_ci DRM_ERROR("bpp %d\n", t->cpp); 20888c2ecf20Sopenharmony_ci DRM_ERROR("coordinate type %d\n", t->tex_coord_type); 20898c2ecf20Sopenharmony_ci DRM_ERROR("width round to power of 2 %d\n", t->roundup_w); 20908c2ecf20Sopenharmony_ci DRM_ERROR("height round to power of 2 %d\n", t->roundup_h); 20918c2ecf20Sopenharmony_ci DRM_ERROR("compress format %d\n", t->compress_format); 20928c2ecf20Sopenharmony_ci} 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_cistatic int r100_track_compress_size(int compress_format, int w, int h) 20958c2ecf20Sopenharmony_ci{ 20968c2ecf20Sopenharmony_ci int block_width, block_height, block_bytes; 20978c2ecf20Sopenharmony_ci int wblocks, hblocks; 20988c2ecf20Sopenharmony_ci int min_wblocks; 20998c2ecf20Sopenharmony_ci int sz; 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci block_width = 4; 21028c2ecf20Sopenharmony_ci block_height = 4; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci switch (compress_format) { 21058c2ecf20Sopenharmony_ci case R100_TRACK_COMP_DXT1: 21068c2ecf20Sopenharmony_ci block_bytes = 8; 21078c2ecf20Sopenharmony_ci min_wblocks = 4; 21088c2ecf20Sopenharmony_ci break; 21098c2ecf20Sopenharmony_ci default: 21108c2ecf20Sopenharmony_ci case R100_TRACK_COMP_DXT35: 21118c2ecf20Sopenharmony_ci block_bytes = 16; 21128c2ecf20Sopenharmony_ci min_wblocks = 2; 21138c2ecf20Sopenharmony_ci break; 21148c2ecf20Sopenharmony_ci } 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci hblocks = (h + block_height - 1) / block_height; 21178c2ecf20Sopenharmony_ci wblocks = (w + block_width - 1) / block_width; 21188c2ecf20Sopenharmony_ci if (wblocks < min_wblocks) 21198c2ecf20Sopenharmony_ci wblocks = min_wblocks; 21208c2ecf20Sopenharmony_ci sz = wblocks * hblocks * block_bytes; 21218c2ecf20Sopenharmony_ci return sz; 21228c2ecf20Sopenharmony_ci} 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_cistatic int r100_cs_track_cube(struct radeon_device *rdev, 21258c2ecf20Sopenharmony_ci struct r100_cs_track *track, unsigned idx) 21268c2ecf20Sopenharmony_ci{ 21278c2ecf20Sopenharmony_ci unsigned face, w, h; 21288c2ecf20Sopenharmony_ci struct radeon_bo *cube_robj; 21298c2ecf20Sopenharmony_ci unsigned long size; 21308c2ecf20Sopenharmony_ci unsigned compress_format = track->textures[idx].compress_format; 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci for (face = 0; face < 5; face++) { 21338c2ecf20Sopenharmony_ci cube_robj = track->textures[idx].cube_info[face].robj; 21348c2ecf20Sopenharmony_ci w = track->textures[idx].cube_info[face].width; 21358c2ecf20Sopenharmony_ci h = track->textures[idx].cube_info[face].height; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci if (compress_format) { 21388c2ecf20Sopenharmony_ci size = r100_track_compress_size(compress_format, w, h); 21398c2ecf20Sopenharmony_ci } else 21408c2ecf20Sopenharmony_ci size = w * h; 21418c2ecf20Sopenharmony_ci size *= track->textures[idx].cpp; 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci size += track->textures[idx].cube_info[face].offset; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci if (size > radeon_bo_size(cube_robj)) { 21468c2ecf20Sopenharmony_ci DRM_ERROR("Cube texture offset greater than object size %lu %lu\n", 21478c2ecf20Sopenharmony_ci size, radeon_bo_size(cube_robj)); 21488c2ecf20Sopenharmony_ci r100_cs_track_texture_print(&track->textures[idx]); 21498c2ecf20Sopenharmony_ci return -1; 21508c2ecf20Sopenharmony_ci } 21518c2ecf20Sopenharmony_ci } 21528c2ecf20Sopenharmony_ci return 0; 21538c2ecf20Sopenharmony_ci} 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_cistatic int r100_cs_track_texture_check(struct radeon_device *rdev, 21568c2ecf20Sopenharmony_ci struct r100_cs_track *track) 21578c2ecf20Sopenharmony_ci{ 21588c2ecf20Sopenharmony_ci struct radeon_bo *robj; 21598c2ecf20Sopenharmony_ci unsigned long size; 21608c2ecf20Sopenharmony_ci unsigned u, i, w, h, d; 21618c2ecf20Sopenharmony_ci int ret; 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci for (u = 0; u < track->num_texture; u++) { 21648c2ecf20Sopenharmony_ci if (!track->textures[u].enabled) 21658c2ecf20Sopenharmony_ci continue; 21668c2ecf20Sopenharmony_ci if (track->textures[u].lookup_disable) 21678c2ecf20Sopenharmony_ci continue; 21688c2ecf20Sopenharmony_ci robj = track->textures[u].robj; 21698c2ecf20Sopenharmony_ci if (robj == NULL) { 21708c2ecf20Sopenharmony_ci DRM_ERROR("No texture bound to unit %u\n", u); 21718c2ecf20Sopenharmony_ci return -EINVAL; 21728c2ecf20Sopenharmony_ci } 21738c2ecf20Sopenharmony_ci size = 0; 21748c2ecf20Sopenharmony_ci for (i = 0; i <= track->textures[u].num_levels; i++) { 21758c2ecf20Sopenharmony_ci if (track->textures[u].use_pitch) { 21768c2ecf20Sopenharmony_ci if (rdev->family < CHIP_R300) 21778c2ecf20Sopenharmony_ci w = (track->textures[u].pitch / track->textures[u].cpp) / (1 << i); 21788c2ecf20Sopenharmony_ci else 21798c2ecf20Sopenharmony_ci w = track->textures[u].pitch / (1 << i); 21808c2ecf20Sopenharmony_ci } else { 21818c2ecf20Sopenharmony_ci w = track->textures[u].width; 21828c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_RV515) 21838c2ecf20Sopenharmony_ci w |= track->textures[u].width_11; 21848c2ecf20Sopenharmony_ci w = w / (1 << i); 21858c2ecf20Sopenharmony_ci if (track->textures[u].roundup_w) 21868c2ecf20Sopenharmony_ci w = roundup_pow_of_two(w); 21878c2ecf20Sopenharmony_ci } 21888c2ecf20Sopenharmony_ci h = track->textures[u].height; 21898c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_RV515) 21908c2ecf20Sopenharmony_ci h |= track->textures[u].height_11; 21918c2ecf20Sopenharmony_ci h = h / (1 << i); 21928c2ecf20Sopenharmony_ci if (track->textures[u].roundup_h) 21938c2ecf20Sopenharmony_ci h = roundup_pow_of_two(h); 21948c2ecf20Sopenharmony_ci if (track->textures[u].tex_coord_type == 1) { 21958c2ecf20Sopenharmony_ci d = (1 << track->textures[u].txdepth) / (1 << i); 21968c2ecf20Sopenharmony_ci if (!d) 21978c2ecf20Sopenharmony_ci d = 1; 21988c2ecf20Sopenharmony_ci } else { 21998c2ecf20Sopenharmony_ci d = 1; 22008c2ecf20Sopenharmony_ci } 22018c2ecf20Sopenharmony_ci if (track->textures[u].compress_format) { 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci size += r100_track_compress_size(track->textures[u].compress_format, w, h) * d; 22048c2ecf20Sopenharmony_ci /* compressed textures are block based */ 22058c2ecf20Sopenharmony_ci } else 22068c2ecf20Sopenharmony_ci size += w * h * d; 22078c2ecf20Sopenharmony_ci } 22088c2ecf20Sopenharmony_ci size *= track->textures[u].cpp; 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci switch (track->textures[u].tex_coord_type) { 22118c2ecf20Sopenharmony_ci case 0: 22128c2ecf20Sopenharmony_ci case 1: 22138c2ecf20Sopenharmony_ci break; 22148c2ecf20Sopenharmony_ci case 2: 22158c2ecf20Sopenharmony_ci if (track->separate_cube) { 22168c2ecf20Sopenharmony_ci ret = r100_cs_track_cube(rdev, track, u); 22178c2ecf20Sopenharmony_ci if (ret) 22188c2ecf20Sopenharmony_ci return ret; 22198c2ecf20Sopenharmony_ci } else 22208c2ecf20Sopenharmony_ci size *= 6; 22218c2ecf20Sopenharmony_ci break; 22228c2ecf20Sopenharmony_ci default: 22238c2ecf20Sopenharmony_ci DRM_ERROR("Invalid texture coordinate type %u for unit " 22248c2ecf20Sopenharmony_ci "%u\n", track->textures[u].tex_coord_type, u); 22258c2ecf20Sopenharmony_ci return -EINVAL; 22268c2ecf20Sopenharmony_ci } 22278c2ecf20Sopenharmony_ci if (size > radeon_bo_size(robj)) { 22288c2ecf20Sopenharmony_ci DRM_ERROR("Texture of unit %u needs %lu bytes but is " 22298c2ecf20Sopenharmony_ci "%lu\n", u, size, radeon_bo_size(robj)); 22308c2ecf20Sopenharmony_ci r100_cs_track_texture_print(&track->textures[u]); 22318c2ecf20Sopenharmony_ci return -EINVAL; 22328c2ecf20Sopenharmony_ci } 22338c2ecf20Sopenharmony_ci } 22348c2ecf20Sopenharmony_ci return 0; 22358c2ecf20Sopenharmony_ci} 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ciint r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track) 22388c2ecf20Sopenharmony_ci{ 22398c2ecf20Sopenharmony_ci unsigned i; 22408c2ecf20Sopenharmony_ci unsigned long size; 22418c2ecf20Sopenharmony_ci unsigned prim_walk; 22428c2ecf20Sopenharmony_ci unsigned nverts; 22438c2ecf20Sopenharmony_ci unsigned num_cb = track->cb_dirty ? track->num_cb : 0; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci if (num_cb && !track->zb_cb_clear && !track->color_channel_mask && 22468c2ecf20Sopenharmony_ci !track->blend_read_enable) 22478c2ecf20Sopenharmony_ci num_cb = 0; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci for (i = 0; i < num_cb; i++) { 22508c2ecf20Sopenharmony_ci if (track->cb[i].robj == NULL) { 22518c2ecf20Sopenharmony_ci DRM_ERROR("[drm] No buffer for color buffer %d !\n", i); 22528c2ecf20Sopenharmony_ci return -EINVAL; 22538c2ecf20Sopenharmony_ci } 22548c2ecf20Sopenharmony_ci size = track->cb[i].pitch * track->cb[i].cpp * track->maxy; 22558c2ecf20Sopenharmony_ci size += track->cb[i].offset; 22568c2ecf20Sopenharmony_ci if (size > radeon_bo_size(track->cb[i].robj)) { 22578c2ecf20Sopenharmony_ci DRM_ERROR("[drm] Buffer too small for color buffer %d " 22588c2ecf20Sopenharmony_ci "(need %lu have %lu) !\n", i, size, 22598c2ecf20Sopenharmony_ci radeon_bo_size(track->cb[i].robj)); 22608c2ecf20Sopenharmony_ci DRM_ERROR("[drm] color buffer %d (%u %u %u %u)\n", 22618c2ecf20Sopenharmony_ci i, track->cb[i].pitch, track->cb[i].cpp, 22628c2ecf20Sopenharmony_ci track->cb[i].offset, track->maxy); 22638c2ecf20Sopenharmony_ci return -EINVAL; 22648c2ecf20Sopenharmony_ci } 22658c2ecf20Sopenharmony_ci } 22668c2ecf20Sopenharmony_ci track->cb_dirty = false; 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci if (track->zb_dirty && track->z_enabled) { 22698c2ecf20Sopenharmony_ci if (track->zb.robj == NULL) { 22708c2ecf20Sopenharmony_ci DRM_ERROR("[drm] No buffer for z buffer !\n"); 22718c2ecf20Sopenharmony_ci return -EINVAL; 22728c2ecf20Sopenharmony_ci } 22738c2ecf20Sopenharmony_ci size = track->zb.pitch * track->zb.cpp * track->maxy; 22748c2ecf20Sopenharmony_ci size += track->zb.offset; 22758c2ecf20Sopenharmony_ci if (size > radeon_bo_size(track->zb.robj)) { 22768c2ecf20Sopenharmony_ci DRM_ERROR("[drm] Buffer too small for z buffer " 22778c2ecf20Sopenharmony_ci "(need %lu have %lu) !\n", size, 22788c2ecf20Sopenharmony_ci radeon_bo_size(track->zb.robj)); 22798c2ecf20Sopenharmony_ci DRM_ERROR("[drm] zbuffer (%u %u %u %u)\n", 22808c2ecf20Sopenharmony_ci track->zb.pitch, track->zb.cpp, 22818c2ecf20Sopenharmony_ci track->zb.offset, track->maxy); 22828c2ecf20Sopenharmony_ci return -EINVAL; 22838c2ecf20Sopenharmony_ci } 22848c2ecf20Sopenharmony_ci } 22858c2ecf20Sopenharmony_ci track->zb_dirty = false; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci if (track->aa_dirty && track->aaresolve) { 22888c2ecf20Sopenharmony_ci if (track->aa.robj == NULL) { 22898c2ecf20Sopenharmony_ci DRM_ERROR("[drm] No buffer for AA resolve buffer %d !\n", i); 22908c2ecf20Sopenharmony_ci return -EINVAL; 22918c2ecf20Sopenharmony_ci } 22928c2ecf20Sopenharmony_ci /* I believe the format comes from colorbuffer0. */ 22938c2ecf20Sopenharmony_ci size = track->aa.pitch * track->cb[0].cpp * track->maxy; 22948c2ecf20Sopenharmony_ci size += track->aa.offset; 22958c2ecf20Sopenharmony_ci if (size > radeon_bo_size(track->aa.robj)) { 22968c2ecf20Sopenharmony_ci DRM_ERROR("[drm] Buffer too small for AA resolve buffer %d " 22978c2ecf20Sopenharmony_ci "(need %lu have %lu) !\n", i, size, 22988c2ecf20Sopenharmony_ci radeon_bo_size(track->aa.robj)); 22998c2ecf20Sopenharmony_ci DRM_ERROR("[drm] AA resolve buffer %d (%u %u %u %u)\n", 23008c2ecf20Sopenharmony_ci i, track->aa.pitch, track->cb[0].cpp, 23018c2ecf20Sopenharmony_ci track->aa.offset, track->maxy); 23028c2ecf20Sopenharmony_ci return -EINVAL; 23038c2ecf20Sopenharmony_ci } 23048c2ecf20Sopenharmony_ci } 23058c2ecf20Sopenharmony_ci track->aa_dirty = false; 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci prim_walk = (track->vap_vf_cntl >> 4) & 0x3; 23088c2ecf20Sopenharmony_ci if (track->vap_vf_cntl & (1 << 14)) { 23098c2ecf20Sopenharmony_ci nverts = track->vap_alt_nverts; 23108c2ecf20Sopenharmony_ci } else { 23118c2ecf20Sopenharmony_ci nverts = (track->vap_vf_cntl >> 16) & 0xFFFF; 23128c2ecf20Sopenharmony_ci } 23138c2ecf20Sopenharmony_ci switch (prim_walk) { 23148c2ecf20Sopenharmony_ci case 1: 23158c2ecf20Sopenharmony_ci for (i = 0; i < track->num_arrays; i++) { 23168c2ecf20Sopenharmony_ci size = track->arrays[i].esize * track->max_indx * 4UL; 23178c2ecf20Sopenharmony_ci if (track->arrays[i].robj == NULL) { 23188c2ecf20Sopenharmony_ci DRM_ERROR("(PW %u) Vertex array %u no buffer " 23198c2ecf20Sopenharmony_ci "bound\n", prim_walk, i); 23208c2ecf20Sopenharmony_ci return -EINVAL; 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci if (size > radeon_bo_size(track->arrays[i].robj)) { 23238c2ecf20Sopenharmony_ci dev_err(rdev->dev, "(PW %u) Vertex array %u " 23248c2ecf20Sopenharmony_ci "need %lu dwords have %lu dwords\n", 23258c2ecf20Sopenharmony_ci prim_walk, i, size >> 2, 23268c2ecf20Sopenharmony_ci radeon_bo_size(track->arrays[i].robj) 23278c2ecf20Sopenharmony_ci >> 2); 23288c2ecf20Sopenharmony_ci DRM_ERROR("Max indices %u\n", track->max_indx); 23298c2ecf20Sopenharmony_ci return -EINVAL; 23308c2ecf20Sopenharmony_ci } 23318c2ecf20Sopenharmony_ci } 23328c2ecf20Sopenharmony_ci break; 23338c2ecf20Sopenharmony_ci case 2: 23348c2ecf20Sopenharmony_ci for (i = 0; i < track->num_arrays; i++) { 23358c2ecf20Sopenharmony_ci size = track->arrays[i].esize * (nverts - 1) * 4UL; 23368c2ecf20Sopenharmony_ci if (track->arrays[i].robj == NULL) { 23378c2ecf20Sopenharmony_ci DRM_ERROR("(PW %u) Vertex array %u no buffer " 23388c2ecf20Sopenharmony_ci "bound\n", prim_walk, i); 23398c2ecf20Sopenharmony_ci return -EINVAL; 23408c2ecf20Sopenharmony_ci } 23418c2ecf20Sopenharmony_ci if (size > radeon_bo_size(track->arrays[i].robj)) { 23428c2ecf20Sopenharmony_ci dev_err(rdev->dev, "(PW %u) Vertex array %u " 23438c2ecf20Sopenharmony_ci "need %lu dwords have %lu dwords\n", 23448c2ecf20Sopenharmony_ci prim_walk, i, size >> 2, 23458c2ecf20Sopenharmony_ci radeon_bo_size(track->arrays[i].robj) 23468c2ecf20Sopenharmony_ci >> 2); 23478c2ecf20Sopenharmony_ci return -EINVAL; 23488c2ecf20Sopenharmony_ci } 23498c2ecf20Sopenharmony_ci } 23508c2ecf20Sopenharmony_ci break; 23518c2ecf20Sopenharmony_ci case 3: 23528c2ecf20Sopenharmony_ci size = track->vtx_size * nverts; 23538c2ecf20Sopenharmony_ci if (size != track->immd_dwords) { 23548c2ecf20Sopenharmony_ci DRM_ERROR("IMMD draw %u dwors but needs %lu dwords\n", 23558c2ecf20Sopenharmony_ci track->immd_dwords, size); 23568c2ecf20Sopenharmony_ci DRM_ERROR("VAP_VF_CNTL.NUM_VERTICES %u, VTX_SIZE %u\n", 23578c2ecf20Sopenharmony_ci nverts, track->vtx_size); 23588c2ecf20Sopenharmony_ci return -EINVAL; 23598c2ecf20Sopenharmony_ci } 23608c2ecf20Sopenharmony_ci break; 23618c2ecf20Sopenharmony_ci default: 23628c2ecf20Sopenharmony_ci DRM_ERROR("[drm] Invalid primitive walk %d for VAP_VF_CNTL\n", 23638c2ecf20Sopenharmony_ci prim_walk); 23648c2ecf20Sopenharmony_ci return -EINVAL; 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci if (track->tex_dirty) { 23688c2ecf20Sopenharmony_ci track->tex_dirty = false; 23698c2ecf20Sopenharmony_ci return r100_cs_track_texture_check(rdev, track); 23708c2ecf20Sopenharmony_ci } 23718c2ecf20Sopenharmony_ci return 0; 23728c2ecf20Sopenharmony_ci} 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_civoid r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track) 23758c2ecf20Sopenharmony_ci{ 23768c2ecf20Sopenharmony_ci unsigned i, face; 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci track->cb_dirty = true; 23798c2ecf20Sopenharmony_ci track->zb_dirty = true; 23808c2ecf20Sopenharmony_ci track->tex_dirty = true; 23818c2ecf20Sopenharmony_ci track->aa_dirty = true; 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci if (rdev->family < CHIP_R300) { 23848c2ecf20Sopenharmony_ci track->num_cb = 1; 23858c2ecf20Sopenharmony_ci if (rdev->family <= CHIP_RS200) 23868c2ecf20Sopenharmony_ci track->num_texture = 3; 23878c2ecf20Sopenharmony_ci else 23888c2ecf20Sopenharmony_ci track->num_texture = 6; 23898c2ecf20Sopenharmony_ci track->maxy = 2048; 23908c2ecf20Sopenharmony_ci track->separate_cube = true; 23918c2ecf20Sopenharmony_ci } else { 23928c2ecf20Sopenharmony_ci track->num_cb = 4; 23938c2ecf20Sopenharmony_ci track->num_texture = 16; 23948c2ecf20Sopenharmony_ci track->maxy = 4096; 23958c2ecf20Sopenharmony_ci track->separate_cube = false; 23968c2ecf20Sopenharmony_ci track->aaresolve = false; 23978c2ecf20Sopenharmony_ci track->aa.robj = NULL; 23988c2ecf20Sopenharmony_ci } 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci for (i = 0; i < track->num_cb; i++) { 24018c2ecf20Sopenharmony_ci track->cb[i].robj = NULL; 24028c2ecf20Sopenharmony_ci track->cb[i].pitch = 8192; 24038c2ecf20Sopenharmony_ci track->cb[i].cpp = 16; 24048c2ecf20Sopenharmony_ci track->cb[i].offset = 0; 24058c2ecf20Sopenharmony_ci } 24068c2ecf20Sopenharmony_ci track->z_enabled = true; 24078c2ecf20Sopenharmony_ci track->zb.robj = NULL; 24088c2ecf20Sopenharmony_ci track->zb.pitch = 8192; 24098c2ecf20Sopenharmony_ci track->zb.cpp = 4; 24108c2ecf20Sopenharmony_ci track->zb.offset = 0; 24118c2ecf20Sopenharmony_ci track->vtx_size = 0x7F; 24128c2ecf20Sopenharmony_ci track->immd_dwords = 0xFFFFFFFFUL; 24138c2ecf20Sopenharmony_ci track->num_arrays = 11; 24148c2ecf20Sopenharmony_ci track->max_indx = 0x00FFFFFFUL; 24158c2ecf20Sopenharmony_ci for (i = 0; i < track->num_arrays; i++) { 24168c2ecf20Sopenharmony_ci track->arrays[i].robj = NULL; 24178c2ecf20Sopenharmony_ci track->arrays[i].esize = 0x7F; 24188c2ecf20Sopenharmony_ci } 24198c2ecf20Sopenharmony_ci for (i = 0; i < track->num_texture; i++) { 24208c2ecf20Sopenharmony_ci track->textures[i].compress_format = R100_TRACK_COMP_NONE; 24218c2ecf20Sopenharmony_ci track->textures[i].pitch = 16536; 24228c2ecf20Sopenharmony_ci track->textures[i].width = 16536; 24238c2ecf20Sopenharmony_ci track->textures[i].height = 16536; 24248c2ecf20Sopenharmony_ci track->textures[i].width_11 = 1 << 11; 24258c2ecf20Sopenharmony_ci track->textures[i].height_11 = 1 << 11; 24268c2ecf20Sopenharmony_ci track->textures[i].num_levels = 12; 24278c2ecf20Sopenharmony_ci if (rdev->family <= CHIP_RS200) { 24288c2ecf20Sopenharmony_ci track->textures[i].tex_coord_type = 0; 24298c2ecf20Sopenharmony_ci track->textures[i].txdepth = 0; 24308c2ecf20Sopenharmony_ci } else { 24318c2ecf20Sopenharmony_ci track->textures[i].txdepth = 16; 24328c2ecf20Sopenharmony_ci track->textures[i].tex_coord_type = 1; 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci track->textures[i].cpp = 64; 24358c2ecf20Sopenharmony_ci track->textures[i].robj = NULL; 24368c2ecf20Sopenharmony_ci /* CS IB emission code makes sure texture unit are disabled */ 24378c2ecf20Sopenharmony_ci track->textures[i].enabled = false; 24388c2ecf20Sopenharmony_ci track->textures[i].lookup_disable = false; 24398c2ecf20Sopenharmony_ci track->textures[i].roundup_w = true; 24408c2ecf20Sopenharmony_ci track->textures[i].roundup_h = true; 24418c2ecf20Sopenharmony_ci if (track->separate_cube) 24428c2ecf20Sopenharmony_ci for (face = 0; face < 5; face++) { 24438c2ecf20Sopenharmony_ci track->textures[i].cube_info[face].robj = NULL; 24448c2ecf20Sopenharmony_ci track->textures[i].cube_info[face].width = 16536; 24458c2ecf20Sopenharmony_ci track->textures[i].cube_info[face].height = 16536; 24468c2ecf20Sopenharmony_ci track->textures[i].cube_info[face].offset = 0; 24478c2ecf20Sopenharmony_ci } 24488c2ecf20Sopenharmony_ci } 24498c2ecf20Sopenharmony_ci} 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci/* 24528c2ecf20Sopenharmony_ci * Global GPU functions 24538c2ecf20Sopenharmony_ci */ 24548c2ecf20Sopenharmony_cistatic void r100_errata(struct radeon_device *rdev) 24558c2ecf20Sopenharmony_ci{ 24568c2ecf20Sopenharmony_ci rdev->pll_errata = 0; 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci if (rdev->family == CHIP_RV200 || rdev->family == CHIP_RS200) { 24598c2ecf20Sopenharmony_ci rdev->pll_errata |= CHIP_ERRATA_PLL_DUMMYREADS; 24608c2ecf20Sopenharmony_ci } 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci if (rdev->family == CHIP_RV100 || 24638c2ecf20Sopenharmony_ci rdev->family == CHIP_RS100 || 24648c2ecf20Sopenharmony_ci rdev->family == CHIP_RS200) { 24658c2ecf20Sopenharmony_ci rdev->pll_errata |= CHIP_ERRATA_PLL_DELAY; 24668c2ecf20Sopenharmony_ci } 24678c2ecf20Sopenharmony_ci} 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_cistatic int r100_rbbm_fifo_wait_for_entry(struct radeon_device *rdev, unsigned n) 24708c2ecf20Sopenharmony_ci{ 24718c2ecf20Sopenharmony_ci unsigned i; 24728c2ecf20Sopenharmony_ci uint32_t tmp; 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 24758c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK; 24768c2ecf20Sopenharmony_ci if (tmp >= n) { 24778c2ecf20Sopenharmony_ci return 0; 24788c2ecf20Sopenharmony_ci } 24798c2ecf20Sopenharmony_ci udelay(1); 24808c2ecf20Sopenharmony_ci } 24818c2ecf20Sopenharmony_ci return -1; 24828c2ecf20Sopenharmony_ci} 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ciint r100_gui_wait_for_idle(struct radeon_device *rdev) 24858c2ecf20Sopenharmony_ci{ 24868c2ecf20Sopenharmony_ci unsigned i; 24878c2ecf20Sopenharmony_ci uint32_t tmp; 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci if (r100_rbbm_fifo_wait_for_entry(rdev, 64)) { 24908c2ecf20Sopenharmony_ci pr_warn("radeon: wait for empty RBBM fifo failed! Bad things might happen.\n"); 24918c2ecf20Sopenharmony_ci } 24928c2ecf20Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 24938c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_RBBM_STATUS); 24948c2ecf20Sopenharmony_ci if (!(tmp & RADEON_RBBM_ACTIVE)) { 24958c2ecf20Sopenharmony_ci return 0; 24968c2ecf20Sopenharmony_ci } 24978c2ecf20Sopenharmony_ci udelay(1); 24988c2ecf20Sopenharmony_ci } 24998c2ecf20Sopenharmony_ci return -1; 25008c2ecf20Sopenharmony_ci} 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_ciint r100_mc_wait_for_idle(struct radeon_device *rdev) 25038c2ecf20Sopenharmony_ci{ 25048c2ecf20Sopenharmony_ci unsigned i; 25058c2ecf20Sopenharmony_ci uint32_t tmp; 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 25088c2ecf20Sopenharmony_ci /* read MC_STATUS */ 25098c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_MC_STATUS); 25108c2ecf20Sopenharmony_ci if (tmp & RADEON_MC_IDLE) { 25118c2ecf20Sopenharmony_ci return 0; 25128c2ecf20Sopenharmony_ci } 25138c2ecf20Sopenharmony_ci udelay(1); 25148c2ecf20Sopenharmony_ci } 25158c2ecf20Sopenharmony_ci return -1; 25168c2ecf20Sopenharmony_ci} 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_cibool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) 25198c2ecf20Sopenharmony_ci{ 25208c2ecf20Sopenharmony_ci u32 rbbm_status; 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci rbbm_status = RREG32(R_000E40_RBBM_STATUS); 25238c2ecf20Sopenharmony_ci if (!G_000E40_GUI_ACTIVE(rbbm_status)) { 25248c2ecf20Sopenharmony_ci radeon_ring_lockup_update(rdev, ring); 25258c2ecf20Sopenharmony_ci return false; 25268c2ecf20Sopenharmony_ci } 25278c2ecf20Sopenharmony_ci return radeon_ring_test_lockup(rdev, ring); 25288c2ecf20Sopenharmony_ci} 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci/* required on r1xx, r2xx, r300, r(v)350, r420/r481, rs400/rs480 */ 25318c2ecf20Sopenharmony_civoid r100_enable_bm(struct radeon_device *rdev) 25328c2ecf20Sopenharmony_ci{ 25338c2ecf20Sopenharmony_ci uint32_t tmp; 25348c2ecf20Sopenharmony_ci /* Enable bus mastering */ 25358c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; 25368c2ecf20Sopenharmony_ci WREG32(RADEON_BUS_CNTL, tmp); 25378c2ecf20Sopenharmony_ci} 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_civoid r100_bm_disable(struct radeon_device *rdev) 25408c2ecf20Sopenharmony_ci{ 25418c2ecf20Sopenharmony_ci u32 tmp; 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci /* disable bus mastering */ 25448c2ecf20Sopenharmony_ci tmp = RREG32(R_000030_BUS_CNTL); 25458c2ecf20Sopenharmony_ci WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000044); 25468c2ecf20Sopenharmony_ci mdelay(1); 25478c2ecf20Sopenharmony_ci WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000042); 25488c2ecf20Sopenharmony_ci mdelay(1); 25498c2ecf20Sopenharmony_ci WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040); 25508c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_BUS_CNTL); 25518c2ecf20Sopenharmony_ci mdelay(1); 25528c2ecf20Sopenharmony_ci pci_clear_master(rdev->pdev); 25538c2ecf20Sopenharmony_ci mdelay(1); 25548c2ecf20Sopenharmony_ci} 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ciint r100_asic_reset(struct radeon_device *rdev, bool hard) 25578c2ecf20Sopenharmony_ci{ 25588c2ecf20Sopenharmony_ci struct r100_mc_save save; 25598c2ecf20Sopenharmony_ci u32 status, tmp; 25608c2ecf20Sopenharmony_ci int ret = 0; 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci status = RREG32(R_000E40_RBBM_STATUS); 25638c2ecf20Sopenharmony_ci if (!G_000E40_GUI_ACTIVE(status)) { 25648c2ecf20Sopenharmony_ci return 0; 25658c2ecf20Sopenharmony_ci } 25668c2ecf20Sopenharmony_ci r100_mc_stop(rdev, &save); 25678c2ecf20Sopenharmony_ci status = RREG32(R_000E40_RBBM_STATUS); 25688c2ecf20Sopenharmony_ci dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); 25698c2ecf20Sopenharmony_ci /* stop CP */ 25708c2ecf20Sopenharmony_ci WREG32(RADEON_CP_CSQ_CNTL, 0); 25718c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_CP_RB_CNTL); 25728c2ecf20Sopenharmony_ci WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA); 25738c2ecf20Sopenharmony_ci WREG32(RADEON_CP_RB_RPTR_WR, 0); 25748c2ecf20Sopenharmony_ci WREG32(RADEON_CP_RB_WPTR, 0); 25758c2ecf20Sopenharmony_ci WREG32(RADEON_CP_RB_CNTL, tmp); 25768c2ecf20Sopenharmony_ci /* save PCI state */ 25778c2ecf20Sopenharmony_ci pci_save_state(rdev->pdev); 25788c2ecf20Sopenharmony_ci /* disable bus mastering */ 25798c2ecf20Sopenharmony_ci r100_bm_disable(rdev); 25808c2ecf20Sopenharmony_ci WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_SE(1) | 25818c2ecf20Sopenharmony_ci S_0000F0_SOFT_RESET_RE(1) | 25828c2ecf20Sopenharmony_ci S_0000F0_SOFT_RESET_PP(1) | 25838c2ecf20Sopenharmony_ci S_0000F0_SOFT_RESET_RB(1)); 25848c2ecf20Sopenharmony_ci RREG32(R_0000F0_RBBM_SOFT_RESET); 25858c2ecf20Sopenharmony_ci mdelay(500); 25868c2ecf20Sopenharmony_ci WREG32(R_0000F0_RBBM_SOFT_RESET, 0); 25878c2ecf20Sopenharmony_ci mdelay(1); 25888c2ecf20Sopenharmony_ci status = RREG32(R_000E40_RBBM_STATUS); 25898c2ecf20Sopenharmony_ci dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); 25908c2ecf20Sopenharmony_ci /* reset CP */ 25918c2ecf20Sopenharmony_ci WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1)); 25928c2ecf20Sopenharmony_ci RREG32(R_0000F0_RBBM_SOFT_RESET); 25938c2ecf20Sopenharmony_ci mdelay(500); 25948c2ecf20Sopenharmony_ci WREG32(R_0000F0_RBBM_SOFT_RESET, 0); 25958c2ecf20Sopenharmony_ci mdelay(1); 25968c2ecf20Sopenharmony_ci status = RREG32(R_000E40_RBBM_STATUS); 25978c2ecf20Sopenharmony_ci dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); 25988c2ecf20Sopenharmony_ci /* restore PCI & busmastering */ 25998c2ecf20Sopenharmony_ci pci_restore_state(rdev->pdev); 26008c2ecf20Sopenharmony_ci r100_enable_bm(rdev); 26018c2ecf20Sopenharmony_ci /* Check if GPU is idle */ 26028c2ecf20Sopenharmony_ci if (G_000E40_SE_BUSY(status) || G_000E40_RE_BUSY(status) || 26038c2ecf20Sopenharmony_ci G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) { 26048c2ecf20Sopenharmony_ci dev_err(rdev->dev, "failed to reset GPU\n"); 26058c2ecf20Sopenharmony_ci ret = -1; 26068c2ecf20Sopenharmony_ci } else 26078c2ecf20Sopenharmony_ci dev_info(rdev->dev, "GPU reset succeed\n"); 26088c2ecf20Sopenharmony_ci r100_mc_resume(rdev, &save); 26098c2ecf20Sopenharmony_ci return ret; 26108c2ecf20Sopenharmony_ci} 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_civoid r100_set_common_regs(struct radeon_device *rdev) 26138c2ecf20Sopenharmony_ci{ 26148c2ecf20Sopenharmony_ci struct drm_device *dev = rdev->ddev; 26158c2ecf20Sopenharmony_ci bool force_dac2 = false; 26168c2ecf20Sopenharmony_ci u32 tmp; 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci /* set these so they don't interfere with anything */ 26198c2ecf20Sopenharmony_ci WREG32(RADEON_OV0_SCALE_CNTL, 0); 26208c2ecf20Sopenharmony_ci WREG32(RADEON_SUBPIC_CNTL, 0); 26218c2ecf20Sopenharmony_ci WREG32(RADEON_VIPH_CONTROL, 0); 26228c2ecf20Sopenharmony_ci WREG32(RADEON_I2C_CNTL_1, 0); 26238c2ecf20Sopenharmony_ci WREG32(RADEON_DVI_I2C_CNTL_1, 0); 26248c2ecf20Sopenharmony_ci WREG32(RADEON_CAP0_TRIG_CNTL, 0); 26258c2ecf20Sopenharmony_ci WREG32(RADEON_CAP1_TRIG_CNTL, 0); 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci /* always set up dac2 on rn50 and some rv100 as lots 26288c2ecf20Sopenharmony_ci * of servers seem to wire it up to a VGA port but 26298c2ecf20Sopenharmony_ci * don't report it in the bios connector 26308c2ecf20Sopenharmony_ci * table. 26318c2ecf20Sopenharmony_ci */ 26328c2ecf20Sopenharmony_ci switch (dev->pdev->device) { 26338c2ecf20Sopenharmony_ci /* RN50 */ 26348c2ecf20Sopenharmony_ci case 0x515e: 26358c2ecf20Sopenharmony_ci case 0x5969: 26368c2ecf20Sopenharmony_ci force_dac2 = true; 26378c2ecf20Sopenharmony_ci break; 26388c2ecf20Sopenharmony_ci /* RV100*/ 26398c2ecf20Sopenharmony_ci case 0x5159: 26408c2ecf20Sopenharmony_ci case 0x515a: 26418c2ecf20Sopenharmony_ci /* DELL triple head servers */ 26428c2ecf20Sopenharmony_ci if ((dev->pdev->subsystem_vendor == 0x1028 /* DELL */) && 26438c2ecf20Sopenharmony_ci ((dev->pdev->subsystem_device == 0x016c) || 26448c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x016d) || 26458c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x016e) || 26468c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x016f) || 26478c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x0170) || 26488c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x017d) || 26498c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x017e) || 26508c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x0183) || 26518c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x018a) || 26528c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x019a))) 26538c2ecf20Sopenharmony_ci force_dac2 = true; 26548c2ecf20Sopenharmony_ci break; 26558c2ecf20Sopenharmony_ci } 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci if (force_dac2) { 26588c2ecf20Sopenharmony_ci u32 disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); 26598c2ecf20Sopenharmony_ci u32 tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); 26608c2ecf20Sopenharmony_ci u32 dac2_cntl = RREG32(RADEON_DAC_CNTL2); 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci /* For CRT on DAC2, don't turn it on if BIOS didn't 26638c2ecf20Sopenharmony_ci enable it, even it's detected. 26648c2ecf20Sopenharmony_ci */ 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci /* force it to crtc0 */ 26678c2ecf20Sopenharmony_ci dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; 26688c2ecf20Sopenharmony_ci dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; 26698c2ecf20Sopenharmony_ci disp_hw_debug |= RADEON_CRT2_DISP1_SEL; 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci /* set up the TV DAC */ 26728c2ecf20Sopenharmony_ci tv_dac_cntl &= ~(RADEON_TV_DAC_PEDESTAL | 26738c2ecf20Sopenharmony_ci RADEON_TV_DAC_STD_MASK | 26748c2ecf20Sopenharmony_ci RADEON_TV_DAC_RDACPD | 26758c2ecf20Sopenharmony_ci RADEON_TV_DAC_GDACPD | 26768c2ecf20Sopenharmony_ci RADEON_TV_DAC_BDACPD | 26778c2ecf20Sopenharmony_ci RADEON_TV_DAC_BGADJ_MASK | 26788c2ecf20Sopenharmony_ci RADEON_TV_DAC_DACADJ_MASK); 26798c2ecf20Sopenharmony_ci tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | 26808c2ecf20Sopenharmony_ci RADEON_TV_DAC_NHOLD | 26818c2ecf20Sopenharmony_ci RADEON_TV_DAC_STD_PS2 | 26828c2ecf20Sopenharmony_ci (0x58 << 16)); 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); 26858c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); 26868c2ecf20Sopenharmony_ci WREG32(RADEON_DAC_CNTL2, dac2_cntl); 26878c2ecf20Sopenharmony_ci } 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci /* switch PM block to ACPI mode */ 26908c2ecf20Sopenharmony_ci tmp = RREG32_PLL(RADEON_PLL_PWRMGT_CNTL); 26918c2ecf20Sopenharmony_ci tmp &= ~RADEON_PM_MODE_SEL; 26928c2ecf20Sopenharmony_ci WREG32_PLL(RADEON_PLL_PWRMGT_CNTL, tmp); 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci} 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_ci/* 26978c2ecf20Sopenharmony_ci * VRAM info 26988c2ecf20Sopenharmony_ci */ 26998c2ecf20Sopenharmony_cistatic void r100_vram_get_type(struct radeon_device *rdev) 27008c2ecf20Sopenharmony_ci{ 27018c2ecf20Sopenharmony_ci uint32_t tmp; 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci rdev->mc.vram_is_ddr = false; 27048c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_IGP) 27058c2ecf20Sopenharmony_ci rdev->mc.vram_is_ddr = true; 27068c2ecf20Sopenharmony_ci else if (RREG32(RADEON_MEM_SDRAM_MODE_REG) & RADEON_MEM_CFG_TYPE_DDR) 27078c2ecf20Sopenharmony_ci rdev->mc.vram_is_ddr = true; 27088c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_RV100) || 27098c2ecf20Sopenharmony_ci (rdev->family == CHIP_RS100) || 27108c2ecf20Sopenharmony_ci (rdev->family == CHIP_RS200)) { 27118c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_MEM_CNTL); 27128c2ecf20Sopenharmony_ci if (tmp & RV100_HALF_MODE) { 27138c2ecf20Sopenharmony_ci rdev->mc.vram_width = 32; 27148c2ecf20Sopenharmony_ci } else { 27158c2ecf20Sopenharmony_ci rdev->mc.vram_width = 64; 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_SINGLE_CRTC) { 27188c2ecf20Sopenharmony_ci rdev->mc.vram_width /= 4; 27198c2ecf20Sopenharmony_ci rdev->mc.vram_is_ddr = true; 27208c2ecf20Sopenharmony_ci } 27218c2ecf20Sopenharmony_ci } else if (rdev->family <= CHIP_RV280) { 27228c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_MEM_CNTL); 27238c2ecf20Sopenharmony_ci if (tmp & RADEON_MEM_NUM_CHANNELS_MASK) { 27248c2ecf20Sopenharmony_ci rdev->mc.vram_width = 128; 27258c2ecf20Sopenharmony_ci } else { 27268c2ecf20Sopenharmony_ci rdev->mc.vram_width = 64; 27278c2ecf20Sopenharmony_ci } 27288c2ecf20Sopenharmony_ci } else { 27298c2ecf20Sopenharmony_ci /* newer IGPs */ 27308c2ecf20Sopenharmony_ci rdev->mc.vram_width = 128; 27318c2ecf20Sopenharmony_ci } 27328c2ecf20Sopenharmony_ci} 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_cistatic u32 r100_get_accessible_vram(struct radeon_device *rdev) 27358c2ecf20Sopenharmony_ci{ 27368c2ecf20Sopenharmony_ci u32 aper_size; 27378c2ecf20Sopenharmony_ci u8 byte; 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci aper_size = RREG32(RADEON_CONFIG_APER_SIZE); 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci /* Set HDP_APER_CNTL only on cards that are known not to be broken, 27428c2ecf20Sopenharmony_ci * that is has the 2nd generation multifunction PCI interface 27438c2ecf20Sopenharmony_ci */ 27448c2ecf20Sopenharmony_ci if (rdev->family == CHIP_RV280 || 27458c2ecf20Sopenharmony_ci rdev->family >= CHIP_RV350) { 27468c2ecf20Sopenharmony_ci WREG32_P(RADEON_HOST_PATH_CNTL, RADEON_HDP_APER_CNTL, 27478c2ecf20Sopenharmony_ci ~RADEON_HDP_APER_CNTL); 27488c2ecf20Sopenharmony_ci DRM_INFO("Generation 2 PCI interface, using max accessible memory\n"); 27498c2ecf20Sopenharmony_ci return aper_size * 2; 27508c2ecf20Sopenharmony_ci } 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci /* Older cards have all sorts of funny issues to deal with. First 27538c2ecf20Sopenharmony_ci * check if it's a multifunction card by reading the PCI config 27548c2ecf20Sopenharmony_ci * header type... Limit those to one aperture size 27558c2ecf20Sopenharmony_ci */ 27568c2ecf20Sopenharmony_ci pci_read_config_byte(rdev->pdev, 0xe, &byte); 27578c2ecf20Sopenharmony_ci if (byte & 0x80) { 27588c2ecf20Sopenharmony_ci DRM_INFO("Generation 1 PCI interface in multifunction mode\n"); 27598c2ecf20Sopenharmony_ci DRM_INFO("Limiting VRAM to one aperture\n"); 27608c2ecf20Sopenharmony_ci return aper_size; 27618c2ecf20Sopenharmony_ci } 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci /* Single function older card. We read HDP_APER_CNTL to see how the BIOS 27648c2ecf20Sopenharmony_ci * have set it up. We don't write this as it's broken on some ASICs but 27658c2ecf20Sopenharmony_ci * we expect the BIOS to have done the right thing (might be too optimistic...) 27668c2ecf20Sopenharmony_ci */ 27678c2ecf20Sopenharmony_ci if (RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL) 27688c2ecf20Sopenharmony_ci return aper_size * 2; 27698c2ecf20Sopenharmony_ci return aper_size; 27708c2ecf20Sopenharmony_ci} 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_civoid r100_vram_init_sizes(struct radeon_device *rdev) 27738c2ecf20Sopenharmony_ci{ 27748c2ecf20Sopenharmony_ci u64 config_aper_size; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci /* work out accessible VRAM */ 27778c2ecf20Sopenharmony_ci rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0); 27788c2ecf20Sopenharmony_ci rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0); 27798c2ecf20Sopenharmony_ci rdev->mc.visible_vram_size = r100_get_accessible_vram(rdev); 27808c2ecf20Sopenharmony_ci /* FIXME we don't use the second aperture yet when we could use it */ 27818c2ecf20Sopenharmony_ci if (rdev->mc.visible_vram_size > rdev->mc.aper_size) 27828c2ecf20Sopenharmony_ci rdev->mc.visible_vram_size = rdev->mc.aper_size; 27838c2ecf20Sopenharmony_ci config_aper_size = RREG32(RADEON_CONFIG_APER_SIZE); 27848c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_IGP) { 27858c2ecf20Sopenharmony_ci uint32_t tom; 27868c2ecf20Sopenharmony_ci /* read NB_TOM to get the amount of ram stolen for the GPU */ 27878c2ecf20Sopenharmony_ci tom = RREG32(RADEON_NB_TOM); 27888c2ecf20Sopenharmony_ci rdev->mc.real_vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16); 27898c2ecf20Sopenharmony_ci WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size); 27908c2ecf20Sopenharmony_ci rdev->mc.mc_vram_size = rdev->mc.real_vram_size; 27918c2ecf20Sopenharmony_ci } else { 27928c2ecf20Sopenharmony_ci rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE); 27938c2ecf20Sopenharmony_ci /* Some production boards of m6 will report 0 27948c2ecf20Sopenharmony_ci * if it's 8 MB 27958c2ecf20Sopenharmony_ci */ 27968c2ecf20Sopenharmony_ci if (rdev->mc.real_vram_size == 0) { 27978c2ecf20Sopenharmony_ci rdev->mc.real_vram_size = 8192 * 1024; 27988c2ecf20Sopenharmony_ci WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size); 27998c2ecf20Sopenharmony_ci } 28008c2ecf20Sopenharmony_ci /* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM - 28018c2ecf20Sopenharmony_ci * Novell bug 204882 + along with lots of ubuntu ones 28028c2ecf20Sopenharmony_ci */ 28038c2ecf20Sopenharmony_ci if (rdev->mc.aper_size > config_aper_size) 28048c2ecf20Sopenharmony_ci config_aper_size = rdev->mc.aper_size; 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci if (config_aper_size > rdev->mc.real_vram_size) 28078c2ecf20Sopenharmony_ci rdev->mc.mc_vram_size = config_aper_size; 28088c2ecf20Sopenharmony_ci else 28098c2ecf20Sopenharmony_ci rdev->mc.mc_vram_size = rdev->mc.real_vram_size; 28108c2ecf20Sopenharmony_ci } 28118c2ecf20Sopenharmony_ci} 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_civoid r100_vga_set_state(struct radeon_device *rdev, bool state) 28148c2ecf20Sopenharmony_ci{ 28158c2ecf20Sopenharmony_ci uint32_t temp; 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci temp = RREG32(RADEON_CONFIG_CNTL); 28188c2ecf20Sopenharmony_ci if (!state) { 28198c2ecf20Sopenharmony_ci temp &= ~RADEON_CFG_VGA_RAM_EN; 28208c2ecf20Sopenharmony_ci temp |= RADEON_CFG_VGA_IO_DIS; 28218c2ecf20Sopenharmony_ci } else { 28228c2ecf20Sopenharmony_ci temp &= ~RADEON_CFG_VGA_IO_DIS; 28238c2ecf20Sopenharmony_ci } 28248c2ecf20Sopenharmony_ci WREG32(RADEON_CONFIG_CNTL, temp); 28258c2ecf20Sopenharmony_ci} 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_cistatic void r100_mc_init(struct radeon_device *rdev) 28288c2ecf20Sopenharmony_ci{ 28298c2ecf20Sopenharmony_ci u64 base; 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci r100_vram_get_type(rdev); 28328c2ecf20Sopenharmony_ci r100_vram_init_sizes(rdev); 28338c2ecf20Sopenharmony_ci base = rdev->mc.aper_base; 28348c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_IGP) 28358c2ecf20Sopenharmony_ci base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16; 28368c2ecf20Sopenharmony_ci radeon_vram_location(rdev, &rdev->mc, base); 28378c2ecf20Sopenharmony_ci rdev->mc.gtt_base_align = 0; 28388c2ecf20Sopenharmony_ci if (!(rdev->flags & RADEON_IS_AGP)) 28398c2ecf20Sopenharmony_ci radeon_gtt_location(rdev, &rdev->mc); 28408c2ecf20Sopenharmony_ci radeon_update_bandwidth_info(rdev); 28418c2ecf20Sopenharmony_ci} 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci/* 28458c2ecf20Sopenharmony_ci * Indirect registers accessor 28468c2ecf20Sopenharmony_ci */ 28478c2ecf20Sopenharmony_civoid r100_pll_errata_after_index(struct radeon_device *rdev) 28488c2ecf20Sopenharmony_ci{ 28498c2ecf20Sopenharmony_ci if (rdev->pll_errata & CHIP_ERRATA_PLL_DUMMYREADS) { 28508c2ecf20Sopenharmony_ci (void)RREG32(RADEON_CLOCK_CNTL_DATA); 28518c2ecf20Sopenharmony_ci (void)RREG32(RADEON_CRTC_GEN_CNTL); 28528c2ecf20Sopenharmony_ci } 28538c2ecf20Sopenharmony_ci} 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_cistatic void r100_pll_errata_after_data(struct radeon_device *rdev) 28568c2ecf20Sopenharmony_ci{ 28578c2ecf20Sopenharmony_ci /* This workarounds is necessary on RV100, RS100 and RS200 chips 28588c2ecf20Sopenharmony_ci * or the chip could hang on a subsequent access 28598c2ecf20Sopenharmony_ci */ 28608c2ecf20Sopenharmony_ci if (rdev->pll_errata & CHIP_ERRATA_PLL_DELAY) { 28618c2ecf20Sopenharmony_ci mdelay(5); 28628c2ecf20Sopenharmony_ci } 28638c2ecf20Sopenharmony_ci 28648c2ecf20Sopenharmony_ci /* This function is required to workaround a hardware bug in some (all?) 28658c2ecf20Sopenharmony_ci * revisions of the R300. This workaround should be called after every 28668c2ecf20Sopenharmony_ci * CLOCK_CNTL_INDEX register access. If not, register reads afterward 28678c2ecf20Sopenharmony_ci * may not be correct. 28688c2ecf20Sopenharmony_ci */ 28698c2ecf20Sopenharmony_ci if (rdev->pll_errata & CHIP_ERRATA_R300_CG) { 28708c2ecf20Sopenharmony_ci uint32_t save, tmp; 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci save = RREG32(RADEON_CLOCK_CNTL_INDEX); 28738c2ecf20Sopenharmony_ci tmp = save & ~(0x3f | RADEON_PLL_WR_EN); 28748c2ecf20Sopenharmony_ci WREG32(RADEON_CLOCK_CNTL_INDEX, tmp); 28758c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_CLOCK_CNTL_DATA); 28768c2ecf20Sopenharmony_ci WREG32(RADEON_CLOCK_CNTL_INDEX, save); 28778c2ecf20Sopenharmony_ci } 28788c2ecf20Sopenharmony_ci} 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ciuint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg) 28818c2ecf20Sopenharmony_ci{ 28828c2ecf20Sopenharmony_ci unsigned long flags; 28838c2ecf20Sopenharmony_ci uint32_t data; 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci spin_lock_irqsave(&rdev->pll_idx_lock, flags); 28868c2ecf20Sopenharmony_ci WREG8(RADEON_CLOCK_CNTL_INDEX, reg & 0x3f); 28878c2ecf20Sopenharmony_ci r100_pll_errata_after_index(rdev); 28888c2ecf20Sopenharmony_ci data = RREG32(RADEON_CLOCK_CNTL_DATA); 28898c2ecf20Sopenharmony_ci r100_pll_errata_after_data(rdev); 28908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rdev->pll_idx_lock, flags); 28918c2ecf20Sopenharmony_ci return data; 28928c2ecf20Sopenharmony_ci} 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_civoid r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) 28958c2ecf20Sopenharmony_ci{ 28968c2ecf20Sopenharmony_ci unsigned long flags; 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci spin_lock_irqsave(&rdev->pll_idx_lock, flags); 28998c2ecf20Sopenharmony_ci WREG8(RADEON_CLOCK_CNTL_INDEX, ((reg & 0x3f) | RADEON_PLL_WR_EN)); 29008c2ecf20Sopenharmony_ci r100_pll_errata_after_index(rdev); 29018c2ecf20Sopenharmony_ci WREG32(RADEON_CLOCK_CNTL_DATA, v); 29028c2ecf20Sopenharmony_ci r100_pll_errata_after_data(rdev); 29038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rdev->pll_idx_lock, flags); 29048c2ecf20Sopenharmony_ci} 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_cistatic void r100_set_safe_registers(struct radeon_device *rdev) 29078c2ecf20Sopenharmony_ci{ 29088c2ecf20Sopenharmony_ci if (ASIC_IS_RN50(rdev)) { 29098c2ecf20Sopenharmony_ci rdev->config.r100.reg_safe_bm = rn50_reg_safe_bm; 29108c2ecf20Sopenharmony_ci rdev->config.r100.reg_safe_bm_size = ARRAY_SIZE(rn50_reg_safe_bm); 29118c2ecf20Sopenharmony_ci } else if (rdev->family < CHIP_R200) { 29128c2ecf20Sopenharmony_ci rdev->config.r100.reg_safe_bm = r100_reg_safe_bm; 29138c2ecf20Sopenharmony_ci rdev->config.r100.reg_safe_bm_size = ARRAY_SIZE(r100_reg_safe_bm); 29148c2ecf20Sopenharmony_ci } else { 29158c2ecf20Sopenharmony_ci r200_set_safe_registers(rdev); 29168c2ecf20Sopenharmony_ci } 29178c2ecf20Sopenharmony_ci} 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci/* 29208c2ecf20Sopenharmony_ci * Debugfs info 29218c2ecf20Sopenharmony_ci */ 29228c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 29238c2ecf20Sopenharmony_cistatic int r100_debugfs_rbbm_info(struct seq_file *m, void *data) 29248c2ecf20Sopenharmony_ci{ 29258c2ecf20Sopenharmony_ci struct drm_info_node *node = (struct drm_info_node *) m->private; 29268c2ecf20Sopenharmony_ci struct drm_device *dev = node->minor->dev; 29278c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 29288c2ecf20Sopenharmony_ci uint32_t reg, value; 29298c2ecf20Sopenharmony_ci unsigned i; 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci seq_printf(m, "RBBM_STATUS 0x%08x\n", RREG32(RADEON_RBBM_STATUS)); 29328c2ecf20Sopenharmony_ci seq_printf(m, "RBBM_CMDFIFO_STAT 0x%08x\n", RREG32(0xE7C)); 29338c2ecf20Sopenharmony_ci seq_printf(m, "CP_STAT 0x%08x\n", RREG32(RADEON_CP_STAT)); 29348c2ecf20Sopenharmony_ci for (i = 0; i < 64; i++) { 29358c2ecf20Sopenharmony_ci WREG32(RADEON_RBBM_CMDFIFO_ADDR, i | 0x100); 29368c2ecf20Sopenharmony_ci reg = (RREG32(RADEON_RBBM_CMDFIFO_DATA) - 1) >> 2; 29378c2ecf20Sopenharmony_ci WREG32(RADEON_RBBM_CMDFIFO_ADDR, i); 29388c2ecf20Sopenharmony_ci value = RREG32(RADEON_RBBM_CMDFIFO_DATA); 29398c2ecf20Sopenharmony_ci seq_printf(m, "[0x%03X] 0x%04X=0x%08X\n", i, reg, value); 29408c2ecf20Sopenharmony_ci } 29418c2ecf20Sopenharmony_ci return 0; 29428c2ecf20Sopenharmony_ci} 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_cistatic int r100_debugfs_cp_ring_info(struct seq_file *m, void *data) 29458c2ecf20Sopenharmony_ci{ 29468c2ecf20Sopenharmony_ci struct drm_info_node *node = (struct drm_info_node *) m->private; 29478c2ecf20Sopenharmony_ci struct drm_device *dev = node->minor->dev; 29488c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 29498c2ecf20Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; 29508c2ecf20Sopenharmony_ci uint32_t rdp, wdp; 29518c2ecf20Sopenharmony_ci unsigned count, i, j; 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci radeon_ring_free_size(rdev, ring); 29548c2ecf20Sopenharmony_ci rdp = RREG32(RADEON_CP_RB_RPTR); 29558c2ecf20Sopenharmony_ci wdp = RREG32(RADEON_CP_RB_WPTR); 29568c2ecf20Sopenharmony_ci count = (rdp + ring->ring_size - wdp) & ring->ptr_mask; 29578c2ecf20Sopenharmony_ci seq_printf(m, "CP_STAT 0x%08x\n", RREG32(RADEON_CP_STAT)); 29588c2ecf20Sopenharmony_ci seq_printf(m, "CP_RB_WPTR 0x%08x\n", wdp); 29598c2ecf20Sopenharmony_ci seq_printf(m, "CP_RB_RPTR 0x%08x\n", rdp); 29608c2ecf20Sopenharmony_ci seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw); 29618c2ecf20Sopenharmony_ci seq_printf(m, "%u dwords in ring\n", count); 29628c2ecf20Sopenharmony_ci if (ring->ready) { 29638c2ecf20Sopenharmony_ci for (j = 0; j <= count; j++) { 29648c2ecf20Sopenharmony_ci i = (rdp + j) & ring->ptr_mask; 29658c2ecf20Sopenharmony_ci seq_printf(m, "r[%04d]=0x%08x\n", i, ring->ring[i]); 29668c2ecf20Sopenharmony_ci } 29678c2ecf20Sopenharmony_ci } 29688c2ecf20Sopenharmony_ci return 0; 29698c2ecf20Sopenharmony_ci} 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_cistatic int r100_debugfs_cp_csq_fifo(struct seq_file *m, void *data) 29738c2ecf20Sopenharmony_ci{ 29748c2ecf20Sopenharmony_ci struct drm_info_node *node = (struct drm_info_node *) m->private; 29758c2ecf20Sopenharmony_ci struct drm_device *dev = node->minor->dev; 29768c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 29778c2ecf20Sopenharmony_ci uint32_t csq_stat, csq2_stat, tmp; 29788c2ecf20Sopenharmony_ci unsigned r_rptr, r_wptr, ib1_rptr, ib1_wptr, ib2_rptr, ib2_wptr; 29798c2ecf20Sopenharmony_ci unsigned i; 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci seq_printf(m, "CP_STAT 0x%08x\n", RREG32(RADEON_CP_STAT)); 29828c2ecf20Sopenharmony_ci seq_printf(m, "CP_CSQ_MODE 0x%08x\n", RREG32(RADEON_CP_CSQ_MODE)); 29838c2ecf20Sopenharmony_ci csq_stat = RREG32(RADEON_CP_CSQ_STAT); 29848c2ecf20Sopenharmony_ci csq2_stat = RREG32(RADEON_CP_CSQ2_STAT); 29858c2ecf20Sopenharmony_ci r_rptr = (csq_stat >> 0) & 0x3ff; 29868c2ecf20Sopenharmony_ci r_wptr = (csq_stat >> 10) & 0x3ff; 29878c2ecf20Sopenharmony_ci ib1_rptr = (csq_stat >> 20) & 0x3ff; 29888c2ecf20Sopenharmony_ci ib1_wptr = (csq2_stat >> 0) & 0x3ff; 29898c2ecf20Sopenharmony_ci ib2_rptr = (csq2_stat >> 10) & 0x3ff; 29908c2ecf20Sopenharmony_ci ib2_wptr = (csq2_stat >> 20) & 0x3ff; 29918c2ecf20Sopenharmony_ci seq_printf(m, "CP_CSQ_STAT 0x%08x\n", csq_stat); 29928c2ecf20Sopenharmony_ci seq_printf(m, "CP_CSQ2_STAT 0x%08x\n", csq2_stat); 29938c2ecf20Sopenharmony_ci seq_printf(m, "Ring rptr %u\n", r_rptr); 29948c2ecf20Sopenharmony_ci seq_printf(m, "Ring wptr %u\n", r_wptr); 29958c2ecf20Sopenharmony_ci seq_printf(m, "Indirect1 rptr %u\n", ib1_rptr); 29968c2ecf20Sopenharmony_ci seq_printf(m, "Indirect1 wptr %u\n", ib1_wptr); 29978c2ecf20Sopenharmony_ci seq_printf(m, "Indirect2 rptr %u\n", ib2_rptr); 29988c2ecf20Sopenharmony_ci seq_printf(m, "Indirect2 wptr %u\n", ib2_wptr); 29998c2ecf20Sopenharmony_ci /* FIXME: 0, 128, 640 depends on fifo setup see cp_init_kms 30008c2ecf20Sopenharmony_ci * 128 = indirect1_start * 8 & 640 = indirect2_start * 8 */ 30018c2ecf20Sopenharmony_ci seq_printf(m, "Ring fifo:\n"); 30028c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) { 30038c2ecf20Sopenharmony_ci WREG32(RADEON_CP_CSQ_ADDR, i << 2); 30048c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_CP_CSQ_DATA); 30058c2ecf20Sopenharmony_ci seq_printf(m, "rfifo[%04d]=0x%08X\n", i, tmp); 30068c2ecf20Sopenharmony_ci } 30078c2ecf20Sopenharmony_ci seq_printf(m, "Indirect1 fifo:\n"); 30088c2ecf20Sopenharmony_ci for (i = 256; i <= 512; i++) { 30098c2ecf20Sopenharmony_ci WREG32(RADEON_CP_CSQ_ADDR, i << 2); 30108c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_CP_CSQ_DATA); 30118c2ecf20Sopenharmony_ci seq_printf(m, "ib1fifo[%04d]=0x%08X\n", i, tmp); 30128c2ecf20Sopenharmony_ci } 30138c2ecf20Sopenharmony_ci seq_printf(m, "Indirect2 fifo:\n"); 30148c2ecf20Sopenharmony_ci for (i = 640; i < ib1_wptr; i++) { 30158c2ecf20Sopenharmony_ci WREG32(RADEON_CP_CSQ_ADDR, i << 2); 30168c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_CP_CSQ_DATA); 30178c2ecf20Sopenharmony_ci seq_printf(m, "ib2fifo[%04d]=0x%08X\n", i, tmp); 30188c2ecf20Sopenharmony_ci } 30198c2ecf20Sopenharmony_ci return 0; 30208c2ecf20Sopenharmony_ci} 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_cistatic int r100_debugfs_mc_info(struct seq_file *m, void *data) 30238c2ecf20Sopenharmony_ci{ 30248c2ecf20Sopenharmony_ci struct drm_info_node *node = (struct drm_info_node *) m->private; 30258c2ecf20Sopenharmony_ci struct drm_device *dev = node->minor->dev; 30268c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 30278c2ecf20Sopenharmony_ci uint32_t tmp; 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_CONFIG_MEMSIZE); 30308c2ecf20Sopenharmony_ci seq_printf(m, "CONFIG_MEMSIZE 0x%08x\n", tmp); 30318c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_MC_FB_LOCATION); 30328c2ecf20Sopenharmony_ci seq_printf(m, "MC_FB_LOCATION 0x%08x\n", tmp); 30338c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_BUS_CNTL); 30348c2ecf20Sopenharmony_ci seq_printf(m, "BUS_CNTL 0x%08x\n", tmp); 30358c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_MC_AGP_LOCATION); 30368c2ecf20Sopenharmony_ci seq_printf(m, "MC_AGP_LOCATION 0x%08x\n", tmp); 30378c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_AGP_BASE); 30388c2ecf20Sopenharmony_ci seq_printf(m, "AGP_BASE 0x%08x\n", tmp); 30398c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_HOST_PATH_CNTL); 30408c2ecf20Sopenharmony_ci seq_printf(m, "HOST_PATH_CNTL 0x%08x\n", tmp); 30418c2ecf20Sopenharmony_ci tmp = RREG32(0x01D0); 30428c2ecf20Sopenharmony_ci seq_printf(m, "AIC_CTRL 0x%08x\n", tmp); 30438c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_AIC_LO_ADDR); 30448c2ecf20Sopenharmony_ci seq_printf(m, "AIC_LO_ADDR 0x%08x\n", tmp); 30458c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_AIC_HI_ADDR); 30468c2ecf20Sopenharmony_ci seq_printf(m, "AIC_HI_ADDR 0x%08x\n", tmp); 30478c2ecf20Sopenharmony_ci tmp = RREG32(0x01E4); 30488c2ecf20Sopenharmony_ci seq_printf(m, "AIC_TLB_ADDR 0x%08x\n", tmp); 30498c2ecf20Sopenharmony_ci return 0; 30508c2ecf20Sopenharmony_ci} 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_cistatic struct drm_info_list r100_debugfs_rbbm_list[] = { 30538c2ecf20Sopenharmony_ci {"r100_rbbm_info", r100_debugfs_rbbm_info, 0, NULL}, 30548c2ecf20Sopenharmony_ci}; 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_cistatic struct drm_info_list r100_debugfs_cp_list[] = { 30578c2ecf20Sopenharmony_ci {"r100_cp_ring_info", r100_debugfs_cp_ring_info, 0, NULL}, 30588c2ecf20Sopenharmony_ci {"r100_cp_csq_fifo", r100_debugfs_cp_csq_fifo, 0, NULL}, 30598c2ecf20Sopenharmony_ci}; 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_cistatic struct drm_info_list r100_debugfs_mc_info_list[] = { 30628c2ecf20Sopenharmony_ci {"r100_mc_info", r100_debugfs_mc_info, 0, NULL}, 30638c2ecf20Sopenharmony_ci}; 30648c2ecf20Sopenharmony_ci#endif 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_ciint r100_debugfs_rbbm_init(struct radeon_device *rdev) 30678c2ecf20Sopenharmony_ci{ 30688c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 30698c2ecf20Sopenharmony_ci return radeon_debugfs_add_files(rdev, r100_debugfs_rbbm_list, 1); 30708c2ecf20Sopenharmony_ci#else 30718c2ecf20Sopenharmony_ci return 0; 30728c2ecf20Sopenharmony_ci#endif 30738c2ecf20Sopenharmony_ci} 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ciint r100_debugfs_cp_init(struct radeon_device *rdev) 30768c2ecf20Sopenharmony_ci{ 30778c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 30788c2ecf20Sopenharmony_ci return radeon_debugfs_add_files(rdev, r100_debugfs_cp_list, 2); 30798c2ecf20Sopenharmony_ci#else 30808c2ecf20Sopenharmony_ci return 0; 30818c2ecf20Sopenharmony_ci#endif 30828c2ecf20Sopenharmony_ci} 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ciint r100_debugfs_mc_info_init(struct radeon_device *rdev) 30858c2ecf20Sopenharmony_ci{ 30868c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 30878c2ecf20Sopenharmony_ci return radeon_debugfs_add_files(rdev, r100_debugfs_mc_info_list, 1); 30888c2ecf20Sopenharmony_ci#else 30898c2ecf20Sopenharmony_ci return 0; 30908c2ecf20Sopenharmony_ci#endif 30918c2ecf20Sopenharmony_ci} 30928c2ecf20Sopenharmony_ci 30938c2ecf20Sopenharmony_ciint r100_set_surface_reg(struct radeon_device *rdev, int reg, 30948c2ecf20Sopenharmony_ci uint32_t tiling_flags, uint32_t pitch, 30958c2ecf20Sopenharmony_ci uint32_t offset, uint32_t obj_size) 30968c2ecf20Sopenharmony_ci{ 30978c2ecf20Sopenharmony_ci int surf_index = reg * 16; 30988c2ecf20Sopenharmony_ci int flags = 0; 30998c2ecf20Sopenharmony_ci 31008c2ecf20Sopenharmony_ci if (rdev->family <= CHIP_RS200) { 31018c2ecf20Sopenharmony_ci if ((tiling_flags & (RADEON_TILING_MACRO|RADEON_TILING_MICRO)) 31028c2ecf20Sopenharmony_ci == (RADEON_TILING_MACRO|RADEON_TILING_MICRO)) 31038c2ecf20Sopenharmony_ci flags |= RADEON_SURF_TILE_COLOR_BOTH; 31048c2ecf20Sopenharmony_ci if (tiling_flags & RADEON_TILING_MACRO) 31058c2ecf20Sopenharmony_ci flags |= RADEON_SURF_TILE_COLOR_MACRO; 31068c2ecf20Sopenharmony_ci /* setting pitch to 0 disables tiling */ 31078c2ecf20Sopenharmony_ci if ((tiling_flags & (RADEON_TILING_MACRO|RADEON_TILING_MICRO)) 31088c2ecf20Sopenharmony_ci == 0) 31098c2ecf20Sopenharmony_ci pitch = 0; 31108c2ecf20Sopenharmony_ci } else if (rdev->family <= CHIP_RV280) { 31118c2ecf20Sopenharmony_ci if (tiling_flags & (RADEON_TILING_MACRO)) 31128c2ecf20Sopenharmony_ci flags |= R200_SURF_TILE_COLOR_MACRO; 31138c2ecf20Sopenharmony_ci if (tiling_flags & RADEON_TILING_MICRO) 31148c2ecf20Sopenharmony_ci flags |= R200_SURF_TILE_COLOR_MICRO; 31158c2ecf20Sopenharmony_ci } else { 31168c2ecf20Sopenharmony_ci if (tiling_flags & RADEON_TILING_MACRO) 31178c2ecf20Sopenharmony_ci flags |= R300_SURF_TILE_MACRO; 31188c2ecf20Sopenharmony_ci if (tiling_flags & RADEON_TILING_MICRO) 31198c2ecf20Sopenharmony_ci flags |= R300_SURF_TILE_MICRO; 31208c2ecf20Sopenharmony_ci } 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_ci if (tiling_flags & RADEON_TILING_SWAP_16BIT) 31238c2ecf20Sopenharmony_ci flags |= RADEON_SURF_AP0_SWP_16BPP | RADEON_SURF_AP1_SWP_16BPP; 31248c2ecf20Sopenharmony_ci if (tiling_flags & RADEON_TILING_SWAP_32BIT) 31258c2ecf20Sopenharmony_ci flags |= RADEON_SURF_AP0_SWP_32BPP | RADEON_SURF_AP1_SWP_32BPP; 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci /* r100/r200 divide by 16 */ 31288c2ecf20Sopenharmony_ci if (rdev->family < CHIP_R300) 31298c2ecf20Sopenharmony_ci flags |= pitch / 16; 31308c2ecf20Sopenharmony_ci else 31318c2ecf20Sopenharmony_ci flags |= pitch / 8; 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("writing surface %d %d %x %x\n", reg, flags, offset, offset+obj_size-1); 31358c2ecf20Sopenharmony_ci WREG32(RADEON_SURFACE0_INFO + surf_index, flags); 31368c2ecf20Sopenharmony_ci WREG32(RADEON_SURFACE0_LOWER_BOUND + surf_index, offset); 31378c2ecf20Sopenharmony_ci WREG32(RADEON_SURFACE0_UPPER_BOUND + surf_index, offset + obj_size - 1); 31388c2ecf20Sopenharmony_ci return 0; 31398c2ecf20Sopenharmony_ci} 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_civoid r100_clear_surface_reg(struct radeon_device *rdev, int reg) 31428c2ecf20Sopenharmony_ci{ 31438c2ecf20Sopenharmony_ci int surf_index = reg * 16; 31448c2ecf20Sopenharmony_ci WREG32(RADEON_SURFACE0_INFO + surf_index, 0); 31458c2ecf20Sopenharmony_ci} 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_civoid r100_bandwidth_update(struct radeon_device *rdev) 31488c2ecf20Sopenharmony_ci{ 31498c2ecf20Sopenharmony_ci fixed20_12 trcd_ff, trp_ff, tras_ff, trbs_ff, tcas_ff; 31508c2ecf20Sopenharmony_ci fixed20_12 sclk_ff, mclk_ff, sclk_eff_ff, sclk_delay_ff; 31518c2ecf20Sopenharmony_ci fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff; 31528c2ecf20Sopenharmony_ci fixed20_12 crit_point_ff = {0}; 31538c2ecf20Sopenharmony_ci uint32_t temp, data, mem_trcd, mem_trp, mem_tras; 31548c2ecf20Sopenharmony_ci fixed20_12 memtcas_ff[8] = { 31558c2ecf20Sopenharmony_ci dfixed_init(1), 31568c2ecf20Sopenharmony_ci dfixed_init(2), 31578c2ecf20Sopenharmony_ci dfixed_init(3), 31588c2ecf20Sopenharmony_ci dfixed_init(0), 31598c2ecf20Sopenharmony_ci dfixed_init_half(1), 31608c2ecf20Sopenharmony_ci dfixed_init_half(2), 31618c2ecf20Sopenharmony_ci dfixed_init(0), 31628c2ecf20Sopenharmony_ci }; 31638c2ecf20Sopenharmony_ci fixed20_12 memtcas_rs480_ff[8] = { 31648c2ecf20Sopenharmony_ci dfixed_init(0), 31658c2ecf20Sopenharmony_ci dfixed_init(1), 31668c2ecf20Sopenharmony_ci dfixed_init(2), 31678c2ecf20Sopenharmony_ci dfixed_init(3), 31688c2ecf20Sopenharmony_ci dfixed_init(0), 31698c2ecf20Sopenharmony_ci dfixed_init_half(1), 31708c2ecf20Sopenharmony_ci dfixed_init_half(2), 31718c2ecf20Sopenharmony_ci dfixed_init_half(3), 31728c2ecf20Sopenharmony_ci }; 31738c2ecf20Sopenharmony_ci fixed20_12 memtcas2_ff[8] = { 31748c2ecf20Sopenharmony_ci dfixed_init(0), 31758c2ecf20Sopenharmony_ci dfixed_init(1), 31768c2ecf20Sopenharmony_ci dfixed_init(2), 31778c2ecf20Sopenharmony_ci dfixed_init(3), 31788c2ecf20Sopenharmony_ci dfixed_init(4), 31798c2ecf20Sopenharmony_ci dfixed_init(5), 31808c2ecf20Sopenharmony_ci dfixed_init(6), 31818c2ecf20Sopenharmony_ci dfixed_init(7), 31828c2ecf20Sopenharmony_ci }; 31838c2ecf20Sopenharmony_ci fixed20_12 memtrbs[8] = { 31848c2ecf20Sopenharmony_ci dfixed_init(1), 31858c2ecf20Sopenharmony_ci dfixed_init_half(1), 31868c2ecf20Sopenharmony_ci dfixed_init(2), 31878c2ecf20Sopenharmony_ci dfixed_init_half(2), 31888c2ecf20Sopenharmony_ci dfixed_init(3), 31898c2ecf20Sopenharmony_ci dfixed_init_half(3), 31908c2ecf20Sopenharmony_ci dfixed_init(4), 31918c2ecf20Sopenharmony_ci dfixed_init_half(4) 31928c2ecf20Sopenharmony_ci }; 31938c2ecf20Sopenharmony_ci fixed20_12 memtrbs_r4xx[8] = { 31948c2ecf20Sopenharmony_ci dfixed_init(4), 31958c2ecf20Sopenharmony_ci dfixed_init(5), 31968c2ecf20Sopenharmony_ci dfixed_init(6), 31978c2ecf20Sopenharmony_ci dfixed_init(7), 31988c2ecf20Sopenharmony_ci dfixed_init(8), 31998c2ecf20Sopenharmony_ci dfixed_init(9), 32008c2ecf20Sopenharmony_ci dfixed_init(10), 32018c2ecf20Sopenharmony_ci dfixed_init(11) 32028c2ecf20Sopenharmony_ci }; 32038c2ecf20Sopenharmony_ci fixed20_12 min_mem_eff; 32048c2ecf20Sopenharmony_ci fixed20_12 mc_latency_sclk, mc_latency_mclk, k1; 32058c2ecf20Sopenharmony_ci fixed20_12 cur_latency_mclk, cur_latency_sclk; 32068c2ecf20Sopenharmony_ci fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate = {0}, 32078c2ecf20Sopenharmony_ci disp_drain_rate2, read_return_rate; 32088c2ecf20Sopenharmony_ci fixed20_12 time_disp1_drop_priority; 32098c2ecf20Sopenharmony_ci int c; 32108c2ecf20Sopenharmony_ci int cur_size = 16; /* in octawords */ 32118c2ecf20Sopenharmony_ci int critical_point = 0, critical_point2; 32128c2ecf20Sopenharmony_ci/* uint32_t read_return_rate, time_disp1_drop_priority; */ 32138c2ecf20Sopenharmony_ci int stop_req, max_stop_req; 32148c2ecf20Sopenharmony_ci struct drm_display_mode *mode1 = NULL; 32158c2ecf20Sopenharmony_ci struct drm_display_mode *mode2 = NULL; 32168c2ecf20Sopenharmony_ci uint32_t pixel_bytes1 = 0; 32178c2ecf20Sopenharmony_ci uint32_t pixel_bytes2 = 0; 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ci /* Guess line buffer size to be 8192 pixels */ 32208c2ecf20Sopenharmony_ci u32 lb_size = 8192; 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci if (!rdev->mode_info.mode_config_initialized) 32238c2ecf20Sopenharmony_ci return; 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ci radeon_update_display_priority(rdev); 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci if (rdev->mode_info.crtcs[0]->base.enabled) { 32288c2ecf20Sopenharmony_ci const struct drm_framebuffer *fb = 32298c2ecf20Sopenharmony_ci rdev->mode_info.crtcs[0]->base.primary->fb; 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci mode1 = &rdev->mode_info.crtcs[0]->base.mode; 32328c2ecf20Sopenharmony_ci pixel_bytes1 = fb->format->cpp[0]; 32338c2ecf20Sopenharmony_ci } 32348c2ecf20Sopenharmony_ci if (!(rdev->flags & RADEON_SINGLE_CRTC)) { 32358c2ecf20Sopenharmony_ci if (rdev->mode_info.crtcs[1]->base.enabled) { 32368c2ecf20Sopenharmony_ci const struct drm_framebuffer *fb = 32378c2ecf20Sopenharmony_ci rdev->mode_info.crtcs[1]->base.primary->fb; 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci mode2 = &rdev->mode_info.crtcs[1]->base.mode; 32408c2ecf20Sopenharmony_ci pixel_bytes2 = fb->format->cpp[0]; 32418c2ecf20Sopenharmony_ci } 32428c2ecf20Sopenharmony_ci } 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_ci min_mem_eff.full = dfixed_const_8(0); 32458c2ecf20Sopenharmony_ci /* get modes */ 32468c2ecf20Sopenharmony_ci if ((rdev->disp_priority == 2) && ASIC_IS_R300(rdev)) { 32478c2ecf20Sopenharmony_ci uint32_t mc_init_misc_lat_timer = RREG32(R300_MC_INIT_MISC_LAT_TIMER); 32488c2ecf20Sopenharmony_ci mc_init_misc_lat_timer &= ~(R300_MC_DISP1R_INIT_LAT_MASK << R300_MC_DISP1R_INIT_LAT_SHIFT); 32498c2ecf20Sopenharmony_ci mc_init_misc_lat_timer &= ~(R300_MC_DISP0R_INIT_LAT_MASK << R300_MC_DISP0R_INIT_LAT_SHIFT); 32508c2ecf20Sopenharmony_ci /* check crtc enables */ 32518c2ecf20Sopenharmony_ci if (mode2) 32528c2ecf20Sopenharmony_ci mc_init_misc_lat_timer |= (1 << R300_MC_DISP1R_INIT_LAT_SHIFT); 32538c2ecf20Sopenharmony_ci if (mode1) 32548c2ecf20Sopenharmony_ci mc_init_misc_lat_timer |= (1 << R300_MC_DISP0R_INIT_LAT_SHIFT); 32558c2ecf20Sopenharmony_ci WREG32(R300_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer); 32568c2ecf20Sopenharmony_ci } 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci /* 32598c2ecf20Sopenharmony_ci * determine is there is enough bw for current mode 32608c2ecf20Sopenharmony_ci */ 32618c2ecf20Sopenharmony_ci sclk_ff = rdev->pm.sclk; 32628c2ecf20Sopenharmony_ci mclk_ff = rdev->pm.mclk; 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1); 32658c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const(temp); 32668c2ecf20Sopenharmony_ci mem_bw.full = dfixed_mul(mclk_ff, temp_ff); 32678c2ecf20Sopenharmony_ci 32688c2ecf20Sopenharmony_ci pix_clk.full = 0; 32698c2ecf20Sopenharmony_ci pix_clk2.full = 0; 32708c2ecf20Sopenharmony_ci peak_disp_bw.full = 0; 32718c2ecf20Sopenharmony_ci if (mode1) { 32728c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const(1000); 32738c2ecf20Sopenharmony_ci pix_clk.full = dfixed_const(mode1->clock); /* convert to fixed point */ 32748c2ecf20Sopenharmony_ci pix_clk.full = dfixed_div(pix_clk, temp_ff); 32758c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const(pixel_bytes1); 32768c2ecf20Sopenharmony_ci peak_disp_bw.full += dfixed_mul(pix_clk, temp_ff); 32778c2ecf20Sopenharmony_ci } 32788c2ecf20Sopenharmony_ci if (mode2) { 32798c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const(1000); 32808c2ecf20Sopenharmony_ci pix_clk2.full = dfixed_const(mode2->clock); /* convert to fixed point */ 32818c2ecf20Sopenharmony_ci pix_clk2.full = dfixed_div(pix_clk2, temp_ff); 32828c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const(pixel_bytes2); 32838c2ecf20Sopenharmony_ci peak_disp_bw.full += dfixed_mul(pix_clk2, temp_ff); 32848c2ecf20Sopenharmony_ci } 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci mem_bw.full = dfixed_mul(mem_bw, min_mem_eff); 32878c2ecf20Sopenharmony_ci if (peak_disp_bw.full >= mem_bw.full) { 32888c2ecf20Sopenharmony_ci DRM_ERROR("You may not have enough display bandwidth for current mode\n" 32898c2ecf20Sopenharmony_ci "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); 32908c2ecf20Sopenharmony_ci } 32918c2ecf20Sopenharmony_ci 32928c2ecf20Sopenharmony_ci /* Get values from the EXT_MEM_CNTL register...converting its contents. */ 32938c2ecf20Sopenharmony_ci temp = RREG32(RADEON_MEM_TIMING_CNTL); 32948c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_RV100) || (rdev->flags & RADEON_IS_IGP)) { /* RV100, M6, IGPs */ 32958c2ecf20Sopenharmony_ci mem_trcd = ((temp >> 2) & 0x3) + 1; 32968c2ecf20Sopenharmony_ci mem_trp = ((temp & 0x3)) + 1; 32978c2ecf20Sopenharmony_ci mem_tras = ((temp & 0x70) >> 4) + 1; 32988c2ecf20Sopenharmony_ci } else if (rdev->family == CHIP_R300 || 32998c2ecf20Sopenharmony_ci rdev->family == CHIP_R350) { /* r300, r350 */ 33008c2ecf20Sopenharmony_ci mem_trcd = (temp & 0x7) + 1; 33018c2ecf20Sopenharmony_ci mem_trp = ((temp >> 8) & 0x7) + 1; 33028c2ecf20Sopenharmony_ci mem_tras = ((temp >> 11) & 0xf) + 4; 33038c2ecf20Sopenharmony_ci } else if (rdev->family == CHIP_RV350 || 33048c2ecf20Sopenharmony_ci rdev->family == CHIP_RV380) { 33058c2ecf20Sopenharmony_ci /* rv3x0 */ 33068c2ecf20Sopenharmony_ci mem_trcd = (temp & 0x7) + 3; 33078c2ecf20Sopenharmony_ci mem_trp = ((temp >> 8) & 0x7) + 3; 33088c2ecf20Sopenharmony_ci mem_tras = ((temp >> 11) & 0xf) + 6; 33098c2ecf20Sopenharmony_ci } else if (rdev->family == CHIP_R420 || 33108c2ecf20Sopenharmony_ci rdev->family == CHIP_R423 || 33118c2ecf20Sopenharmony_ci rdev->family == CHIP_RV410) { 33128c2ecf20Sopenharmony_ci /* r4xx */ 33138c2ecf20Sopenharmony_ci mem_trcd = (temp & 0xf) + 3; 33148c2ecf20Sopenharmony_ci if (mem_trcd > 15) 33158c2ecf20Sopenharmony_ci mem_trcd = 15; 33168c2ecf20Sopenharmony_ci mem_trp = ((temp >> 8) & 0xf) + 3; 33178c2ecf20Sopenharmony_ci if (mem_trp > 15) 33188c2ecf20Sopenharmony_ci mem_trp = 15; 33198c2ecf20Sopenharmony_ci mem_tras = ((temp >> 12) & 0x1f) + 6; 33208c2ecf20Sopenharmony_ci if (mem_tras > 31) 33218c2ecf20Sopenharmony_ci mem_tras = 31; 33228c2ecf20Sopenharmony_ci } else { /* RV200, R200 */ 33238c2ecf20Sopenharmony_ci mem_trcd = (temp & 0x7) + 1; 33248c2ecf20Sopenharmony_ci mem_trp = ((temp >> 8) & 0x7) + 1; 33258c2ecf20Sopenharmony_ci mem_tras = ((temp >> 12) & 0xf) + 4; 33268c2ecf20Sopenharmony_ci } 33278c2ecf20Sopenharmony_ci /* convert to FF */ 33288c2ecf20Sopenharmony_ci trcd_ff.full = dfixed_const(mem_trcd); 33298c2ecf20Sopenharmony_ci trp_ff.full = dfixed_const(mem_trp); 33308c2ecf20Sopenharmony_ci tras_ff.full = dfixed_const(mem_tras); 33318c2ecf20Sopenharmony_ci 33328c2ecf20Sopenharmony_ci /* Get values from the MEM_SDRAM_MODE_REG register...converting its */ 33338c2ecf20Sopenharmony_ci temp = RREG32(RADEON_MEM_SDRAM_MODE_REG); 33348c2ecf20Sopenharmony_ci data = (temp & (7 << 20)) >> 20; 33358c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_RV100) || rdev->flags & RADEON_IS_IGP) { 33368c2ecf20Sopenharmony_ci if (rdev->family == CHIP_RS480) /* don't think rs400 */ 33378c2ecf20Sopenharmony_ci tcas_ff = memtcas_rs480_ff[data]; 33388c2ecf20Sopenharmony_ci else 33398c2ecf20Sopenharmony_ci tcas_ff = memtcas_ff[data]; 33408c2ecf20Sopenharmony_ci } else 33418c2ecf20Sopenharmony_ci tcas_ff = memtcas2_ff[data]; 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci if (rdev->family == CHIP_RS400 || 33448c2ecf20Sopenharmony_ci rdev->family == CHIP_RS480) { 33458c2ecf20Sopenharmony_ci /* extra cas latency stored in bits 23-25 0-4 clocks */ 33468c2ecf20Sopenharmony_ci data = (temp >> 23) & 0x7; 33478c2ecf20Sopenharmony_ci if (data < 5) 33488c2ecf20Sopenharmony_ci tcas_ff.full += dfixed_const(data); 33498c2ecf20Sopenharmony_ci } 33508c2ecf20Sopenharmony_ci 33518c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev) && !(rdev->flags & RADEON_IS_IGP)) { 33528c2ecf20Sopenharmony_ci /* on the R300, Tcas is included in Trbs. 33538c2ecf20Sopenharmony_ci */ 33548c2ecf20Sopenharmony_ci temp = RREG32(RADEON_MEM_CNTL); 33558c2ecf20Sopenharmony_ci data = (R300_MEM_NUM_CHANNELS_MASK & temp); 33568c2ecf20Sopenharmony_ci if (data == 1) { 33578c2ecf20Sopenharmony_ci if (R300_MEM_USE_CD_CH_ONLY & temp) { 33588c2ecf20Sopenharmony_ci temp = RREG32(R300_MC_IND_INDEX); 33598c2ecf20Sopenharmony_ci temp &= ~R300_MC_IND_ADDR_MASK; 33608c2ecf20Sopenharmony_ci temp |= R300_MC_READ_CNTL_CD_mcind; 33618c2ecf20Sopenharmony_ci WREG32(R300_MC_IND_INDEX, temp); 33628c2ecf20Sopenharmony_ci temp = RREG32(R300_MC_IND_DATA); 33638c2ecf20Sopenharmony_ci data = (R300_MEM_RBS_POSITION_C_MASK & temp); 33648c2ecf20Sopenharmony_ci } else { 33658c2ecf20Sopenharmony_ci temp = RREG32(R300_MC_READ_CNTL_AB); 33668c2ecf20Sopenharmony_ci data = (R300_MEM_RBS_POSITION_A_MASK & temp); 33678c2ecf20Sopenharmony_ci } 33688c2ecf20Sopenharmony_ci } else { 33698c2ecf20Sopenharmony_ci temp = RREG32(R300_MC_READ_CNTL_AB); 33708c2ecf20Sopenharmony_ci data = (R300_MEM_RBS_POSITION_A_MASK & temp); 33718c2ecf20Sopenharmony_ci } 33728c2ecf20Sopenharmony_ci if (rdev->family == CHIP_RV410 || 33738c2ecf20Sopenharmony_ci rdev->family == CHIP_R420 || 33748c2ecf20Sopenharmony_ci rdev->family == CHIP_R423) 33758c2ecf20Sopenharmony_ci trbs_ff = memtrbs_r4xx[data]; 33768c2ecf20Sopenharmony_ci else 33778c2ecf20Sopenharmony_ci trbs_ff = memtrbs[data]; 33788c2ecf20Sopenharmony_ci tcas_ff.full += trbs_ff.full; 33798c2ecf20Sopenharmony_ci } 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci sclk_eff_ff.full = sclk_ff.full; 33828c2ecf20Sopenharmony_ci 33838c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_AGP) { 33848c2ecf20Sopenharmony_ci fixed20_12 agpmode_ff; 33858c2ecf20Sopenharmony_ci agpmode_ff.full = dfixed_const(radeon_agpmode); 33868c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const_666(16); 33878c2ecf20Sopenharmony_ci sclk_eff_ff.full -= dfixed_mul(agpmode_ff, temp_ff); 33888c2ecf20Sopenharmony_ci } 33898c2ecf20Sopenharmony_ci /* TODO PCIE lanes may affect this - agpmode == 16?? */ 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_ci if (ASIC_IS_R300(rdev)) { 33928c2ecf20Sopenharmony_ci sclk_delay_ff.full = dfixed_const(250); 33938c2ecf20Sopenharmony_ci } else { 33948c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_RV100) || 33958c2ecf20Sopenharmony_ci rdev->flags & RADEON_IS_IGP) { 33968c2ecf20Sopenharmony_ci if (rdev->mc.vram_is_ddr) 33978c2ecf20Sopenharmony_ci sclk_delay_ff.full = dfixed_const(41); 33988c2ecf20Sopenharmony_ci else 33998c2ecf20Sopenharmony_ci sclk_delay_ff.full = dfixed_const(33); 34008c2ecf20Sopenharmony_ci } else { 34018c2ecf20Sopenharmony_ci if (rdev->mc.vram_width == 128) 34028c2ecf20Sopenharmony_ci sclk_delay_ff.full = dfixed_const(57); 34038c2ecf20Sopenharmony_ci else 34048c2ecf20Sopenharmony_ci sclk_delay_ff.full = dfixed_const(41); 34058c2ecf20Sopenharmony_ci } 34068c2ecf20Sopenharmony_ci } 34078c2ecf20Sopenharmony_ci 34088c2ecf20Sopenharmony_ci mc_latency_sclk.full = dfixed_div(sclk_delay_ff, sclk_eff_ff); 34098c2ecf20Sopenharmony_ci 34108c2ecf20Sopenharmony_ci if (rdev->mc.vram_is_ddr) { 34118c2ecf20Sopenharmony_ci if (rdev->mc.vram_width == 32) { 34128c2ecf20Sopenharmony_ci k1.full = dfixed_const(40); 34138c2ecf20Sopenharmony_ci c = 3; 34148c2ecf20Sopenharmony_ci } else { 34158c2ecf20Sopenharmony_ci k1.full = dfixed_const(20); 34168c2ecf20Sopenharmony_ci c = 1; 34178c2ecf20Sopenharmony_ci } 34188c2ecf20Sopenharmony_ci } else { 34198c2ecf20Sopenharmony_ci k1.full = dfixed_const(40); 34208c2ecf20Sopenharmony_ci c = 3; 34218c2ecf20Sopenharmony_ci } 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const(2); 34248c2ecf20Sopenharmony_ci mc_latency_mclk.full = dfixed_mul(trcd_ff, temp_ff); 34258c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const(c); 34268c2ecf20Sopenharmony_ci mc_latency_mclk.full += dfixed_mul(tcas_ff, temp_ff); 34278c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const(4); 34288c2ecf20Sopenharmony_ci mc_latency_mclk.full += dfixed_mul(tras_ff, temp_ff); 34298c2ecf20Sopenharmony_ci mc_latency_mclk.full += dfixed_mul(trp_ff, temp_ff); 34308c2ecf20Sopenharmony_ci mc_latency_mclk.full += k1.full; 34318c2ecf20Sopenharmony_ci 34328c2ecf20Sopenharmony_ci mc_latency_mclk.full = dfixed_div(mc_latency_mclk, mclk_ff); 34338c2ecf20Sopenharmony_ci mc_latency_mclk.full += dfixed_div(temp_ff, sclk_eff_ff); 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_ci /* 34368c2ecf20Sopenharmony_ci HW cursor time assuming worst case of full size colour cursor. 34378c2ecf20Sopenharmony_ci */ 34388c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const((2 * (cur_size - (rdev->mc.vram_is_ddr + 1)))); 34398c2ecf20Sopenharmony_ci temp_ff.full += trcd_ff.full; 34408c2ecf20Sopenharmony_ci if (temp_ff.full < tras_ff.full) 34418c2ecf20Sopenharmony_ci temp_ff.full = tras_ff.full; 34428c2ecf20Sopenharmony_ci cur_latency_mclk.full = dfixed_div(temp_ff, mclk_ff); 34438c2ecf20Sopenharmony_ci 34448c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const(cur_size); 34458c2ecf20Sopenharmony_ci cur_latency_sclk.full = dfixed_div(temp_ff, sclk_eff_ff); 34468c2ecf20Sopenharmony_ci /* 34478c2ecf20Sopenharmony_ci Find the total latency for the display data. 34488c2ecf20Sopenharmony_ci */ 34498c2ecf20Sopenharmony_ci disp_latency_overhead.full = dfixed_const(8); 34508c2ecf20Sopenharmony_ci disp_latency_overhead.full = dfixed_div(disp_latency_overhead, sclk_ff); 34518c2ecf20Sopenharmony_ci mc_latency_mclk.full += disp_latency_overhead.full + cur_latency_mclk.full; 34528c2ecf20Sopenharmony_ci mc_latency_sclk.full += disp_latency_overhead.full + cur_latency_sclk.full; 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci if (mc_latency_mclk.full > mc_latency_sclk.full) 34558c2ecf20Sopenharmony_ci disp_latency.full = mc_latency_mclk.full; 34568c2ecf20Sopenharmony_ci else 34578c2ecf20Sopenharmony_ci disp_latency.full = mc_latency_sclk.full; 34588c2ecf20Sopenharmony_ci 34598c2ecf20Sopenharmony_ci /* setup Max GRPH_STOP_REQ default value */ 34608c2ecf20Sopenharmony_ci if (ASIC_IS_RV100(rdev)) 34618c2ecf20Sopenharmony_ci max_stop_req = 0x5c; 34628c2ecf20Sopenharmony_ci else 34638c2ecf20Sopenharmony_ci max_stop_req = 0x7c; 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci if (mode1) { 34668c2ecf20Sopenharmony_ci /* CRTC1 34678c2ecf20Sopenharmony_ci Set GRPH_BUFFER_CNTL register using h/w defined optimal values. 34688c2ecf20Sopenharmony_ci GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ] 34698c2ecf20Sopenharmony_ci */ 34708c2ecf20Sopenharmony_ci stop_req = mode1->hdisplay * pixel_bytes1 / 16; 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_ci if (stop_req > max_stop_req) 34738c2ecf20Sopenharmony_ci stop_req = max_stop_req; 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_ci /* 34768c2ecf20Sopenharmony_ci Find the drain rate of the display buffer. 34778c2ecf20Sopenharmony_ci */ 34788c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const((16/pixel_bytes1)); 34798c2ecf20Sopenharmony_ci disp_drain_rate.full = dfixed_div(pix_clk, temp_ff); 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci /* 34828c2ecf20Sopenharmony_ci Find the critical point of the display buffer. 34838c2ecf20Sopenharmony_ci */ 34848c2ecf20Sopenharmony_ci crit_point_ff.full = dfixed_mul(disp_drain_rate, disp_latency); 34858c2ecf20Sopenharmony_ci crit_point_ff.full += dfixed_const_half(0); 34868c2ecf20Sopenharmony_ci 34878c2ecf20Sopenharmony_ci critical_point = dfixed_trunc(crit_point_ff); 34888c2ecf20Sopenharmony_ci 34898c2ecf20Sopenharmony_ci if (rdev->disp_priority == 2) { 34908c2ecf20Sopenharmony_ci critical_point = 0; 34918c2ecf20Sopenharmony_ci } 34928c2ecf20Sopenharmony_ci 34938c2ecf20Sopenharmony_ci /* 34948c2ecf20Sopenharmony_ci The critical point should never be above max_stop_req-4. Setting 34958c2ecf20Sopenharmony_ci GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time. 34968c2ecf20Sopenharmony_ci */ 34978c2ecf20Sopenharmony_ci if (max_stop_req - critical_point < 4) 34988c2ecf20Sopenharmony_ci critical_point = 0; 34998c2ecf20Sopenharmony_ci 35008c2ecf20Sopenharmony_ci if (critical_point == 0 && mode2 && rdev->family == CHIP_R300) { 35018c2ecf20Sopenharmony_ci /* some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/ 35028c2ecf20Sopenharmony_ci critical_point = 0x10; 35038c2ecf20Sopenharmony_ci } 35048c2ecf20Sopenharmony_ci 35058c2ecf20Sopenharmony_ci temp = RREG32(RADEON_GRPH_BUFFER_CNTL); 35068c2ecf20Sopenharmony_ci temp &= ~(RADEON_GRPH_STOP_REQ_MASK); 35078c2ecf20Sopenharmony_ci temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); 35088c2ecf20Sopenharmony_ci temp &= ~(RADEON_GRPH_START_REQ_MASK); 35098c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_R350) && 35108c2ecf20Sopenharmony_ci (stop_req > 0x15)) { 35118c2ecf20Sopenharmony_ci stop_req -= 0x10; 35128c2ecf20Sopenharmony_ci } 35138c2ecf20Sopenharmony_ci temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); 35148c2ecf20Sopenharmony_ci temp |= RADEON_GRPH_BUFFER_SIZE; 35158c2ecf20Sopenharmony_ci temp &= ~(RADEON_GRPH_CRITICAL_CNTL | 35168c2ecf20Sopenharmony_ci RADEON_GRPH_CRITICAL_AT_SOF | 35178c2ecf20Sopenharmony_ci RADEON_GRPH_STOP_CNTL); 35188c2ecf20Sopenharmony_ci /* 35198c2ecf20Sopenharmony_ci Write the result into the register. 35208c2ecf20Sopenharmony_ci */ 35218c2ecf20Sopenharmony_ci WREG32(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) | 35228c2ecf20Sopenharmony_ci (critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT))); 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci#if 0 35258c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_RS400) || 35268c2ecf20Sopenharmony_ci (rdev->family == CHIP_RS480)) { 35278c2ecf20Sopenharmony_ci /* attempt to program RS400 disp regs correctly ??? */ 35288c2ecf20Sopenharmony_ci temp = RREG32(RS400_DISP1_REG_CNTL); 35298c2ecf20Sopenharmony_ci temp &= ~(RS400_DISP1_START_REQ_LEVEL_MASK | 35308c2ecf20Sopenharmony_ci RS400_DISP1_STOP_REQ_LEVEL_MASK); 35318c2ecf20Sopenharmony_ci WREG32(RS400_DISP1_REQ_CNTL1, (temp | 35328c2ecf20Sopenharmony_ci (critical_point << RS400_DISP1_START_REQ_LEVEL_SHIFT) | 35338c2ecf20Sopenharmony_ci (critical_point << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); 35348c2ecf20Sopenharmony_ci temp = RREG32(RS400_DMIF_MEM_CNTL1); 35358c2ecf20Sopenharmony_ci temp &= ~(RS400_DISP1_CRITICAL_POINT_START_MASK | 35368c2ecf20Sopenharmony_ci RS400_DISP1_CRITICAL_POINT_STOP_MASK); 35378c2ecf20Sopenharmony_ci WREG32(RS400_DMIF_MEM_CNTL1, (temp | 35388c2ecf20Sopenharmony_ci (critical_point << RS400_DISP1_CRITICAL_POINT_START_SHIFT) | 35398c2ecf20Sopenharmony_ci (critical_point << RS400_DISP1_CRITICAL_POINT_STOP_SHIFT))); 35408c2ecf20Sopenharmony_ci } 35418c2ecf20Sopenharmony_ci#endif 35428c2ecf20Sopenharmony_ci 35438c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("GRPH_BUFFER_CNTL from to %x\n", 35448c2ecf20Sopenharmony_ci /* (unsigned int)info->SavedReg->grph_buffer_cntl, */ 35458c2ecf20Sopenharmony_ci (unsigned int)RREG32(RADEON_GRPH_BUFFER_CNTL)); 35468c2ecf20Sopenharmony_ci } 35478c2ecf20Sopenharmony_ci 35488c2ecf20Sopenharmony_ci if (mode2) { 35498c2ecf20Sopenharmony_ci u32 grph2_cntl; 35508c2ecf20Sopenharmony_ci stop_req = mode2->hdisplay * pixel_bytes2 / 16; 35518c2ecf20Sopenharmony_ci 35528c2ecf20Sopenharmony_ci if (stop_req > max_stop_req) 35538c2ecf20Sopenharmony_ci stop_req = max_stop_req; 35548c2ecf20Sopenharmony_ci 35558c2ecf20Sopenharmony_ci /* 35568c2ecf20Sopenharmony_ci Find the drain rate of the display buffer. 35578c2ecf20Sopenharmony_ci */ 35588c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const((16/pixel_bytes2)); 35598c2ecf20Sopenharmony_ci disp_drain_rate2.full = dfixed_div(pix_clk2, temp_ff); 35608c2ecf20Sopenharmony_ci 35618c2ecf20Sopenharmony_ci grph2_cntl = RREG32(RADEON_GRPH2_BUFFER_CNTL); 35628c2ecf20Sopenharmony_ci grph2_cntl &= ~(RADEON_GRPH_STOP_REQ_MASK); 35638c2ecf20Sopenharmony_ci grph2_cntl |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); 35648c2ecf20Sopenharmony_ci grph2_cntl &= ~(RADEON_GRPH_START_REQ_MASK); 35658c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_R350) && 35668c2ecf20Sopenharmony_ci (stop_req > 0x15)) { 35678c2ecf20Sopenharmony_ci stop_req -= 0x10; 35688c2ecf20Sopenharmony_ci } 35698c2ecf20Sopenharmony_ci grph2_cntl |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); 35708c2ecf20Sopenharmony_ci grph2_cntl |= RADEON_GRPH_BUFFER_SIZE; 35718c2ecf20Sopenharmony_ci grph2_cntl &= ~(RADEON_GRPH_CRITICAL_CNTL | 35728c2ecf20Sopenharmony_ci RADEON_GRPH_CRITICAL_AT_SOF | 35738c2ecf20Sopenharmony_ci RADEON_GRPH_STOP_CNTL); 35748c2ecf20Sopenharmony_ci 35758c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_RS100) || 35768c2ecf20Sopenharmony_ci (rdev->family == CHIP_RS200)) 35778c2ecf20Sopenharmony_ci critical_point2 = 0; 35788c2ecf20Sopenharmony_ci else { 35798c2ecf20Sopenharmony_ci temp = (rdev->mc.vram_width * rdev->mc.vram_is_ddr + 1)/128; 35808c2ecf20Sopenharmony_ci temp_ff.full = dfixed_const(temp); 35818c2ecf20Sopenharmony_ci temp_ff.full = dfixed_mul(mclk_ff, temp_ff); 35828c2ecf20Sopenharmony_ci if (sclk_ff.full < temp_ff.full) 35838c2ecf20Sopenharmony_ci temp_ff.full = sclk_ff.full; 35848c2ecf20Sopenharmony_ci 35858c2ecf20Sopenharmony_ci read_return_rate.full = temp_ff.full; 35868c2ecf20Sopenharmony_ci 35878c2ecf20Sopenharmony_ci if (mode1) { 35888c2ecf20Sopenharmony_ci temp_ff.full = read_return_rate.full - disp_drain_rate.full; 35898c2ecf20Sopenharmony_ci time_disp1_drop_priority.full = dfixed_div(crit_point_ff, temp_ff); 35908c2ecf20Sopenharmony_ci } else { 35918c2ecf20Sopenharmony_ci time_disp1_drop_priority.full = 0; 35928c2ecf20Sopenharmony_ci } 35938c2ecf20Sopenharmony_ci crit_point_ff.full = disp_latency.full + time_disp1_drop_priority.full + disp_latency.full; 35948c2ecf20Sopenharmony_ci crit_point_ff.full = dfixed_mul(crit_point_ff, disp_drain_rate2); 35958c2ecf20Sopenharmony_ci crit_point_ff.full += dfixed_const_half(0); 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci critical_point2 = dfixed_trunc(crit_point_ff); 35988c2ecf20Sopenharmony_ci 35998c2ecf20Sopenharmony_ci if (rdev->disp_priority == 2) { 36008c2ecf20Sopenharmony_ci critical_point2 = 0; 36018c2ecf20Sopenharmony_ci } 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_ci if (max_stop_req - critical_point2 < 4) 36048c2ecf20Sopenharmony_ci critical_point2 = 0; 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ci } 36078c2ecf20Sopenharmony_ci 36088c2ecf20Sopenharmony_ci if (critical_point2 == 0 && rdev->family == CHIP_R300) { 36098c2ecf20Sopenharmony_ci /* some R300 cards have problem with this set to 0 */ 36108c2ecf20Sopenharmony_ci critical_point2 = 0x10; 36118c2ecf20Sopenharmony_ci } 36128c2ecf20Sopenharmony_ci 36138c2ecf20Sopenharmony_ci WREG32(RADEON_GRPH2_BUFFER_CNTL, ((grph2_cntl & ~RADEON_GRPH_CRITICAL_POINT_MASK) | 36148c2ecf20Sopenharmony_ci (critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT))); 36158c2ecf20Sopenharmony_ci 36168c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_RS400) || 36178c2ecf20Sopenharmony_ci (rdev->family == CHIP_RS480)) { 36188c2ecf20Sopenharmony_ci#if 0 36198c2ecf20Sopenharmony_ci /* attempt to program RS400 disp2 regs correctly ??? */ 36208c2ecf20Sopenharmony_ci temp = RREG32(RS400_DISP2_REQ_CNTL1); 36218c2ecf20Sopenharmony_ci temp &= ~(RS400_DISP2_START_REQ_LEVEL_MASK | 36228c2ecf20Sopenharmony_ci RS400_DISP2_STOP_REQ_LEVEL_MASK); 36238c2ecf20Sopenharmony_ci WREG32(RS400_DISP2_REQ_CNTL1, (temp | 36248c2ecf20Sopenharmony_ci (critical_point2 << RS400_DISP1_START_REQ_LEVEL_SHIFT) | 36258c2ecf20Sopenharmony_ci (critical_point2 << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); 36268c2ecf20Sopenharmony_ci temp = RREG32(RS400_DISP2_REQ_CNTL2); 36278c2ecf20Sopenharmony_ci temp &= ~(RS400_DISP2_CRITICAL_POINT_START_MASK | 36288c2ecf20Sopenharmony_ci RS400_DISP2_CRITICAL_POINT_STOP_MASK); 36298c2ecf20Sopenharmony_ci WREG32(RS400_DISP2_REQ_CNTL2, (temp | 36308c2ecf20Sopenharmony_ci (critical_point2 << RS400_DISP2_CRITICAL_POINT_START_SHIFT) | 36318c2ecf20Sopenharmony_ci (critical_point2 << RS400_DISP2_CRITICAL_POINT_STOP_SHIFT))); 36328c2ecf20Sopenharmony_ci#endif 36338c2ecf20Sopenharmony_ci WREG32(RS400_DISP2_REQ_CNTL1, 0x105DC1CC); 36348c2ecf20Sopenharmony_ci WREG32(RS400_DISP2_REQ_CNTL2, 0x2749D000); 36358c2ecf20Sopenharmony_ci WREG32(RS400_DMIF_MEM_CNTL1, 0x29CA71DC); 36368c2ecf20Sopenharmony_ci WREG32(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC); 36378c2ecf20Sopenharmony_ci } 36388c2ecf20Sopenharmony_ci 36398c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("GRPH2_BUFFER_CNTL from to %x\n", 36408c2ecf20Sopenharmony_ci (unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL)); 36418c2ecf20Sopenharmony_ci } 36428c2ecf20Sopenharmony_ci 36438c2ecf20Sopenharmony_ci /* Save number of lines the linebuffer leads before the scanout */ 36448c2ecf20Sopenharmony_ci if (mode1) 36458c2ecf20Sopenharmony_ci rdev->mode_info.crtcs[0]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode1->crtc_hdisplay); 36468c2ecf20Sopenharmony_ci 36478c2ecf20Sopenharmony_ci if (mode2) 36488c2ecf20Sopenharmony_ci rdev->mode_info.crtcs[1]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode2->crtc_hdisplay); 36498c2ecf20Sopenharmony_ci} 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ciint r100_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) 36528c2ecf20Sopenharmony_ci{ 36538c2ecf20Sopenharmony_ci uint32_t scratch; 36548c2ecf20Sopenharmony_ci uint32_t tmp = 0; 36558c2ecf20Sopenharmony_ci unsigned i; 36568c2ecf20Sopenharmony_ci int r; 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_ci r = radeon_scratch_get(rdev, &scratch); 36598c2ecf20Sopenharmony_ci if (r) { 36608c2ecf20Sopenharmony_ci DRM_ERROR("radeon: cp failed to get scratch reg (%d).\n", r); 36618c2ecf20Sopenharmony_ci return r; 36628c2ecf20Sopenharmony_ci } 36638c2ecf20Sopenharmony_ci WREG32(scratch, 0xCAFEDEAD); 36648c2ecf20Sopenharmony_ci r = radeon_ring_lock(rdev, ring, 2); 36658c2ecf20Sopenharmony_ci if (r) { 36668c2ecf20Sopenharmony_ci DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); 36678c2ecf20Sopenharmony_ci radeon_scratch_free(rdev, scratch); 36688c2ecf20Sopenharmony_ci return r; 36698c2ecf20Sopenharmony_ci } 36708c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET0(scratch, 0)); 36718c2ecf20Sopenharmony_ci radeon_ring_write(ring, 0xDEADBEEF); 36728c2ecf20Sopenharmony_ci radeon_ring_unlock_commit(rdev, ring, false); 36738c2ecf20Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 36748c2ecf20Sopenharmony_ci tmp = RREG32(scratch); 36758c2ecf20Sopenharmony_ci if (tmp == 0xDEADBEEF) { 36768c2ecf20Sopenharmony_ci break; 36778c2ecf20Sopenharmony_ci } 36788c2ecf20Sopenharmony_ci udelay(1); 36798c2ecf20Sopenharmony_ci } 36808c2ecf20Sopenharmony_ci if (i < rdev->usec_timeout) { 36818c2ecf20Sopenharmony_ci DRM_INFO("ring test succeeded in %d usecs\n", i); 36828c2ecf20Sopenharmony_ci } else { 36838c2ecf20Sopenharmony_ci DRM_ERROR("radeon: ring test failed (scratch(0x%04X)=0x%08X)\n", 36848c2ecf20Sopenharmony_ci scratch, tmp); 36858c2ecf20Sopenharmony_ci r = -EINVAL; 36868c2ecf20Sopenharmony_ci } 36878c2ecf20Sopenharmony_ci radeon_scratch_free(rdev, scratch); 36888c2ecf20Sopenharmony_ci return r; 36898c2ecf20Sopenharmony_ci} 36908c2ecf20Sopenharmony_ci 36918c2ecf20Sopenharmony_civoid r100_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) 36928c2ecf20Sopenharmony_ci{ 36938c2ecf20Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci if (ring->rptr_save_reg) { 36968c2ecf20Sopenharmony_ci u32 next_rptr = ring->wptr + 2 + 3; 36978c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET0(ring->rptr_save_reg, 0)); 36988c2ecf20Sopenharmony_ci radeon_ring_write(ring, next_rptr); 36998c2ecf20Sopenharmony_ci } 37008c2ecf20Sopenharmony_ci 37018c2ecf20Sopenharmony_ci radeon_ring_write(ring, PACKET0(RADEON_CP_IB_BASE, 1)); 37028c2ecf20Sopenharmony_ci radeon_ring_write(ring, ib->gpu_addr); 37038c2ecf20Sopenharmony_ci radeon_ring_write(ring, ib->length_dw); 37048c2ecf20Sopenharmony_ci} 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_ciint r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) 37078c2ecf20Sopenharmony_ci{ 37088c2ecf20Sopenharmony_ci struct radeon_ib ib; 37098c2ecf20Sopenharmony_ci uint32_t scratch; 37108c2ecf20Sopenharmony_ci uint32_t tmp = 0; 37118c2ecf20Sopenharmony_ci unsigned i; 37128c2ecf20Sopenharmony_ci int r; 37138c2ecf20Sopenharmony_ci 37148c2ecf20Sopenharmony_ci r = radeon_scratch_get(rdev, &scratch); 37158c2ecf20Sopenharmony_ci if (r) { 37168c2ecf20Sopenharmony_ci DRM_ERROR("radeon: failed to get scratch reg (%d).\n", r); 37178c2ecf20Sopenharmony_ci return r; 37188c2ecf20Sopenharmony_ci } 37198c2ecf20Sopenharmony_ci WREG32(scratch, 0xCAFEDEAD); 37208c2ecf20Sopenharmony_ci r = radeon_ib_get(rdev, RADEON_RING_TYPE_GFX_INDEX, &ib, NULL, 256); 37218c2ecf20Sopenharmony_ci if (r) { 37228c2ecf20Sopenharmony_ci DRM_ERROR("radeon: failed to get ib (%d).\n", r); 37238c2ecf20Sopenharmony_ci goto free_scratch; 37248c2ecf20Sopenharmony_ci } 37258c2ecf20Sopenharmony_ci ib.ptr[0] = PACKET0(scratch, 0); 37268c2ecf20Sopenharmony_ci ib.ptr[1] = 0xDEADBEEF; 37278c2ecf20Sopenharmony_ci ib.ptr[2] = PACKET2(0); 37288c2ecf20Sopenharmony_ci ib.ptr[3] = PACKET2(0); 37298c2ecf20Sopenharmony_ci ib.ptr[4] = PACKET2(0); 37308c2ecf20Sopenharmony_ci ib.ptr[5] = PACKET2(0); 37318c2ecf20Sopenharmony_ci ib.ptr[6] = PACKET2(0); 37328c2ecf20Sopenharmony_ci ib.ptr[7] = PACKET2(0); 37338c2ecf20Sopenharmony_ci ib.length_dw = 8; 37348c2ecf20Sopenharmony_ci r = radeon_ib_schedule(rdev, &ib, NULL, false); 37358c2ecf20Sopenharmony_ci if (r) { 37368c2ecf20Sopenharmony_ci DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); 37378c2ecf20Sopenharmony_ci goto free_ib; 37388c2ecf20Sopenharmony_ci } 37398c2ecf20Sopenharmony_ci r = radeon_fence_wait_timeout(ib.fence, false, usecs_to_jiffies( 37408c2ecf20Sopenharmony_ci RADEON_USEC_IB_TEST_TIMEOUT)); 37418c2ecf20Sopenharmony_ci if (r < 0) { 37428c2ecf20Sopenharmony_ci DRM_ERROR("radeon: fence wait failed (%d).\n", r); 37438c2ecf20Sopenharmony_ci goto free_ib; 37448c2ecf20Sopenharmony_ci } else if (r == 0) { 37458c2ecf20Sopenharmony_ci DRM_ERROR("radeon: fence wait timed out.\n"); 37468c2ecf20Sopenharmony_ci r = -ETIMEDOUT; 37478c2ecf20Sopenharmony_ci goto free_ib; 37488c2ecf20Sopenharmony_ci } 37498c2ecf20Sopenharmony_ci r = 0; 37508c2ecf20Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 37518c2ecf20Sopenharmony_ci tmp = RREG32(scratch); 37528c2ecf20Sopenharmony_ci if (tmp == 0xDEADBEEF) { 37538c2ecf20Sopenharmony_ci break; 37548c2ecf20Sopenharmony_ci } 37558c2ecf20Sopenharmony_ci udelay(1); 37568c2ecf20Sopenharmony_ci } 37578c2ecf20Sopenharmony_ci if (i < rdev->usec_timeout) { 37588c2ecf20Sopenharmony_ci DRM_INFO("ib test succeeded in %u usecs\n", i); 37598c2ecf20Sopenharmony_ci } else { 37608c2ecf20Sopenharmony_ci DRM_ERROR("radeon: ib test failed (scratch(0x%04X)=0x%08X)\n", 37618c2ecf20Sopenharmony_ci scratch, tmp); 37628c2ecf20Sopenharmony_ci r = -EINVAL; 37638c2ecf20Sopenharmony_ci } 37648c2ecf20Sopenharmony_cifree_ib: 37658c2ecf20Sopenharmony_ci radeon_ib_free(rdev, &ib); 37668c2ecf20Sopenharmony_cifree_scratch: 37678c2ecf20Sopenharmony_ci radeon_scratch_free(rdev, scratch); 37688c2ecf20Sopenharmony_ci return r; 37698c2ecf20Sopenharmony_ci} 37708c2ecf20Sopenharmony_ci 37718c2ecf20Sopenharmony_civoid r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save) 37728c2ecf20Sopenharmony_ci{ 37738c2ecf20Sopenharmony_ci /* Shutdown CP we shouldn't need to do that but better be safe than 37748c2ecf20Sopenharmony_ci * sorry 37758c2ecf20Sopenharmony_ci */ 37768c2ecf20Sopenharmony_ci rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false; 37778c2ecf20Sopenharmony_ci WREG32(R_000740_CP_CSQ_CNTL, 0); 37788c2ecf20Sopenharmony_ci 37798c2ecf20Sopenharmony_ci /* Save few CRTC registers */ 37808c2ecf20Sopenharmony_ci save->GENMO_WT = RREG8(R_0003C2_GENMO_WT); 37818c2ecf20Sopenharmony_ci save->CRTC_EXT_CNTL = RREG32(R_000054_CRTC_EXT_CNTL); 37828c2ecf20Sopenharmony_ci save->CRTC_GEN_CNTL = RREG32(R_000050_CRTC_GEN_CNTL); 37838c2ecf20Sopenharmony_ci save->CUR_OFFSET = RREG32(R_000260_CUR_OFFSET); 37848c2ecf20Sopenharmony_ci if (!(rdev->flags & RADEON_SINGLE_CRTC)) { 37858c2ecf20Sopenharmony_ci save->CRTC2_GEN_CNTL = RREG32(R_0003F8_CRTC2_GEN_CNTL); 37868c2ecf20Sopenharmony_ci save->CUR2_OFFSET = RREG32(R_000360_CUR2_OFFSET); 37878c2ecf20Sopenharmony_ci } 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_ci /* Disable VGA aperture access */ 37908c2ecf20Sopenharmony_ci WREG8(R_0003C2_GENMO_WT, C_0003C2_VGA_RAM_EN & save->GENMO_WT); 37918c2ecf20Sopenharmony_ci /* Disable cursor, overlay, crtc */ 37928c2ecf20Sopenharmony_ci WREG32(R_000260_CUR_OFFSET, save->CUR_OFFSET | S_000260_CUR_LOCK(1)); 37938c2ecf20Sopenharmony_ci WREG32(R_000054_CRTC_EXT_CNTL, save->CRTC_EXT_CNTL | 37948c2ecf20Sopenharmony_ci S_000054_CRTC_DISPLAY_DIS(1)); 37958c2ecf20Sopenharmony_ci WREG32(R_000050_CRTC_GEN_CNTL, 37968c2ecf20Sopenharmony_ci (C_000050_CRTC_CUR_EN & save->CRTC_GEN_CNTL) | 37978c2ecf20Sopenharmony_ci S_000050_CRTC_DISP_REQ_EN_B(1)); 37988c2ecf20Sopenharmony_ci WREG32(R_000420_OV0_SCALE_CNTL, 37998c2ecf20Sopenharmony_ci C_000420_OV0_OVERLAY_EN & RREG32(R_000420_OV0_SCALE_CNTL)); 38008c2ecf20Sopenharmony_ci WREG32(R_000260_CUR_OFFSET, C_000260_CUR_LOCK & save->CUR_OFFSET); 38018c2ecf20Sopenharmony_ci if (!(rdev->flags & RADEON_SINGLE_CRTC)) { 38028c2ecf20Sopenharmony_ci WREG32(R_000360_CUR2_OFFSET, save->CUR2_OFFSET | 38038c2ecf20Sopenharmony_ci S_000360_CUR2_LOCK(1)); 38048c2ecf20Sopenharmony_ci WREG32(R_0003F8_CRTC2_GEN_CNTL, 38058c2ecf20Sopenharmony_ci (C_0003F8_CRTC2_CUR_EN & save->CRTC2_GEN_CNTL) | 38068c2ecf20Sopenharmony_ci S_0003F8_CRTC2_DISPLAY_DIS(1) | 38078c2ecf20Sopenharmony_ci S_0003F8_CRTC2_DISP_REQ_EN_B(1)); 38088c2ecf20Sopenharmony_ci WREG32(R_000360_CUR2_OFFSET, 38098c2ecf20Sopenharmony_ci C_000360_CUR2_LOCK & save->CUR2_OFFSET); 38108c2ecf20Sopenharmony_ci } 38118c2ecf20Sopenharmony_ci} 38128c2ecf20Sopenharmony_ci 38138c2ecf20Sopenharmony_civoid r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save) 38148c2ecf20Sopenharmony_ci{ 38158c2ecf20Sopenharmony_ci /* Update base address for crtc */ 38168c2ecf20Sopenharmony_ci WREG32(R_00023C_DISPLAY_BASE_ADDR, rdev->mc.vram_start); 38178c2ecf20Sopenharmony_ci if (!(rdev->flags & RADEON_SINGLE_CRTC)) { 38188c2ecf20Sopenharmony_ci WREG32(R_00033C_CRTC2_DISPLAY_BASE_ADDR, rdev->mc.vram_start); 38198c2ecf20Sopenharmony_ci } 38208c2ecf20Sopenharmony_ci /* Restore CRTC registers */ 38218c2ecf20Sopenharmony_ci WREG8(R_0003C2_GENMO_WT, save->GENMO_WT); 38228c2ecf20Sopenharmony_ci WREG32(R_000054_CRTC_EXT_CNTL, save->CRTC_EXT_CNTL); 38238c2ecf20Sopenharmony_ci WREG32(R_000050_CRTC_GEN_CNTL, save->CRTC_GEN_CNTL); 38248c2ecf20Sopenharmony_ci if (!(rdev->flags & RADEON_SINGLE_CRTC)) { 38258c2ecf20Sopenharmony_ci WREG32(R_0003F8_CRTC2_GEN_CNTL, save->CRTC2_GEN_CNTL); 38268c2ecf20Sopenharmony_ci } 38278c2ecf20Sopenharmony_ci} 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_civoid r100_vga_render_disable(struct radeon_device *rdev) 38308c2ecf20Sopenharmony_ci{ 38318c2ecf20Sopenharmony_ci u32 tmp; 38328c2ecf20Sopenharmony_ci 38338c2ecf20Sopenharmony_ci tmp = RREG8(R_0003C2_GENMO_WT); 38348c2ecf20Sopenharmony_ci WREG8(R_0003C2_GENMO_WT, C_0003C2_VGA_RAM_EN & tmp); 38358c2ecf20Sopenharmony_ci} 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_cistatic void r100_debugfs(struct radeon_device *rdev) 38388c2ecf20Sopenharmony_ci{ 38398c2ecf20Sopenharmony_ci int r; 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci r = r100_debugfs_mc_info_init(rdev); 38428c2ecf20Sopenharmony_ci if (r) 38438c2ecf20Sopenharmony_ci dev_warn(rdev->dev, "Failed to create r100_mc debugfs file.\n"); 38448c2ecf20Sopenharmony_ci} 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_cistatic void r100_mc_program(struct radeon_device *rdev) 38478c2ecf20Sopenharmony_ci{ 38488c2ecf20Sopenharmony_ci struct r100_mc_save save; 38498c2ecf20Sopenharmony_ci 38508c2ecf20Sopenharmony_ci /* Stops all mc clients */ 38518c2ecf20Sopenharmony_ci r100_mc_stop(rdev, &save); 38528c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_AGP) { 38538c2ecf20Sopenharmony_ci WREG32(R_00014C_MC_AGP_LOCATION, 38548c2ecf20Sopenharmony_ci S_00014C_MC_AGP_START(rdev->mc.gtt_start >> 16) | 38558c2ecf20Sopenharmony_ci S_00014C_MC_AGP_TOP(rdev->mc.gtt_end >> 16)); 38568c2ecf20Sopenharmony_ci WREG32(R_000170_AGP_BASE, lower_32_bits(rdev->mc.agp_base)); 38578c2ecf20Sopenharmony_ci if (rdev->family > CHIP_RV200) 38588c2ecf20Sopenharmony_ci WREG32(R_00015C_AGP_BASE_2, 38598c2ecf20Sopenharmony_ci upper_32_bits(rdev->mc.agp_base) & 0xff); 38608c2ecf20Sopenharmony_ci } else { 38618c2ecf20Sopenharmony_ci WREG32(R_00014C_MC_AGP_LOCATION, 0x0FFFFFFF); 38628c2ecf20Sopenharmony_ci WREG32(R_000170_AGP_BASE, 0); 38638c2ecf20Sopenharmony_ci if (rdev->family > CHIP_RV200) 38648c2ecf20Sopenharmony_ci WREG32(R_00015C_AGP_BASE_2, 0); 38658c2ecf20Sopenharmony_ci } 38668c2ecf20Sopenharmony_ci /* Wait for mc idle */ 38678c2ecf20Sopenharmony_ci if (r100_mc_wait_for_idle(rdev)) 38688c2ecf20Sopenharmony_ci dev_warn(rdev->dev, "Wait for MC idle timeout.\n"); 38698c2ecf20Sopenharmony_ci /* Program MC, should be a 32bits limited address space */ 38708c2ecf20Sopenharmony_ci WREG32(R_000148_MC_FB_LOCATION, 38718c2ecf20Sopenharmony_ci S_000148_MC_FB_START(rdev->mc.vram_start >> 16) | 38728c2ecf20Sopenharmony_ci S_000148_MC_FB_TOP(rdev->mc.vram_end >> 16)); 38738c2ecf20Sopenharmony_ci r100_mc_resume(rdev, &save); 38748c2ecf20Sopenharmony_ci} 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_cistatic void r100_clock_startup(struct radeon_device *rdev) 38778c2ecf20Sopenharmony_ci{ 38788c2ecf20Sopenharmony_ci u32 tmp; 38798c2ecf20Sopenharmony_ci 38808c2ecf20Sopenharmony_ci if (radeon_dynclks != -1 && radeon_dynclks) 38818c2ecf20Sopenharmony_ci radeon_legacy_set_clock_gating(rdev, 1); 38828c2ecf20Sopenharmony_ci /* We need to force on some of the block */ 38838c2ecf20Sopenharmony_ci tmp = RREG32_PLL(R_00000D_SCLK_CNTL); 38848c2ecf20Sopenharmony_ci tmp |= S_00000D_FORCE_CP(1) | S_00000D_FORCE_VIP(1); 38858c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_RV250) || (rdev->family == CHIP_RV280)) 38868c2ecf20Sopenharmony_ci tmp |= S_00000D_FORCE_DISP1(1) | S_00000D_FORCE_DISP2(1); 38878c2ecf20Sopenharmony_ci WREG32_PLL(R_00000D_SCLK_CNTL, tmp); 38888c2ecf20Sopenharmony_ci} 38898c2ecf20Sopenharmony_ci 38908c2ecf20Sopenharmony_cistatic int r100_startup(struct radeon_device *rdev) 38918c2ecf20Sopenharmony_ci{ 38928c2ecf20Sopenharmony_ci int r; 38938c2ecf20Sopenharmony_ci 38948c2ecf20Sopenharmony_ci /* set common regs */ 38958c2ecf20Sopenharmony_ci r100_set_common_regs(rdev); 38968c2ecf20Sopenharmony_ci /* program mc */ 38978c2ecf20Sopenharmony_ci r100_mc_program(rdev); 38988c2ecf20Sopenharmony_ci /* Resume clock */ 38998c2ecf20Sopenharmony_ci r100_clock_startup(rdev); 39008c2ecf20Sopenharmony_ci /* Initialize GART (initialize after TTM so we can allocate 39018c2ecf20Sopenharmony_ci * memory through TTM but finalize after TTM) */ 39028c2ecf20Sopenharmony_ci r100_enable_bm(rdev); 39038c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_PCI) { 39048c2ecf20Sopenharmony_ci r = r100_pci_gart_enable(rdev); 39058c2ecf20Sopenharmony_ci if (r) 39068c2ecf20Sopenharmony_ci return r; 39078c2ecf20Sopenharmony_ci } 39088c2ecf20Sopenharmony_ci 39098c2ecf20Sopenharmony_ci /* allocate wb buffer */ 39108c2ecf20Sopenharmony_ci r = radeon_wb_init(rdev); 39118c2ecf20Sopenharmony_ci if (r) 39128c2ecf20Sopenharmony_ci return r; 39138c2ecf20Sopenharmony_ci 39148c2ecf20Sopenharmony_ci r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX); 39158c2ecf20Sopenharmony_ci if (r) { 39168c2ecf20Sopenharmony_ci dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r); 39178c2ecf20Sopenharmony_ci return r; 39188c2ecf20Sopenharmony_ci } 39198c2ecf20Sopenharmony_ci 39208c2ecf20Sopenharmony_ci /* Enable IRQ */ 39218c2ecf20Sopenharmony_ci if (!rdev->irq.installed) { 39228c2ecf20Sopenharmony_ci r = radeon_irq_kms_init(rdev); 39238c2ecf20Sopenharmony_ci if (r) 39248c2ecf20Sopenharmony_ci return r; 39258c2ecf20Sopenharmony_ci } 39268c2ecf20Sopenharmony_ci 39278c2ecf20Sopenharmony_ci r100_irq_set(rdev); 39288c2ecf20Sopenharmony_ci rdev->config.r100.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); 39298c2ecf20Sopenharmony_ci /* 1M ring buffer */ 39308c2ecf20Sopenharmony_ci r = r100_cp_init(rdev, 1024 * 1024); 39318c2ecf20Sopenharmony_ci if (r) { 39328c2ecf20Sopenharmony_ci dev_err(rdev->dev, "failed initializing CP (%d).\n", r); 39338c2ecf20Sopenharmony_ci return r; 39348c2ecf20Sopenharmony_ci } 39358c2ecf20Sopenharmony_ci 39368c2ecf20Sopenharmony_ci r = radeon_ib_pool_init(rdev); 39378c2ecf20Sopenharmony_ci if (r) { 39388c2ecf20Sopenharmony_ci dev_err(rdev->dev, "IB initialization failed (%d).\n", r); 39398c2ecf20Sopenharmony_ci return r; 39408c2ecf20Sopenharmony_ci } 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci return 0; 39438c2ecf20Sopenharmony_ci} 39448c2ecf20Sopenharmony_ci 39458c2ecf20Sopenharmony_ciint r100_resume(struct radeon_device *rdev) 39468c2ecf20Sopenharmony_ci{ 39478c2ecf20Sopenharmony_ci int r; 39488c2ecf20Sopenharmony_ci 39498c2ecf20Sopenharmony_ci /* Make sur GART are not working */ 39508c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_PCI) 39518c2ecf20Sopenharmony_ci r100_pci_gart_disable(rdev); 39528c2ecf20Sopenharmony_ci /* Resume clock before doing reset */ 39538c2ecf20Sopenharmony_ci r100_clock_startup(rdev); 39548c2ecf20Sopenharmony_ci /* Reset gpu before posting otherwise ATOM will enter infinite loop */ 39558c2ecf20Sopenharmony_ci if (radeon_asic_reset(rdev)) { 39568c2ecf20Sopenharmony_ci dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", 39578c2ecf20Sopenharmony_ci RREG32(R_000E40_RBBM_STATUS), 39588c2ecf20Sopenharmony_ci RREG32(R_0007C0_CP_STAT)); 39598c2ecf20Sopenharmony_ci } 39608c2ecf20Sopenharmony_ci /* post */ 39618c2ecf20Sopenharmony_ci radeon_combios_asic_init(rdev->ddev); 39628c2ecf20Sopenharmony_ci /* Resume clock after posting */ 39638c2ecf20Sopenharmony_ci r100_clock_startup(rdev); 39648c2ecf20Sopenharmony_ci /* Initialize surface registers */ 39658c2ecf20Sopenharmony_ci radeon_surface_init(rdev); 39668c2ecf20Sopenharmony_ci 39678c2ecf20Sopenharmony_ci rdev->accel_working = true; 39688c2ecf20Sopenharmony_ci r = r100_startup(rdev); 39698c2ecf20Sopenharmony_ci if (r) { 39708c2ecf20Sopenharmony_ci rdev->accel_working = false; 39718c2ecf20Sopenharmony_ci } 39728c2ecf20Sopenharmony_ci return r; 39738c2ecf20Sopenharmony_ci} 39748c2ecf20Sopenharmony_ci 39758c2ecf20Sopenharmony_ciint r100_suspend(struct radeon_device *rdev) 39768c2ecf20Sopenharmony_ci{ 39778c2ecf20Sopenharmony_ci radeon_pm_suspend(rdev); 39788c2ecf20Sopenharmony_ci r100_cp_disable(rdev); 39798c2ecf20Sopenharmony_ci radeon_wb_disable(rdev); 39808c2ecf20Sopenharmony_ci r100_irq_disable(rdev); 39818c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_PCI) 39828c2ecf20Sopenharmony_ci r100_pci_gart_disable(rdev); 39838c2ecf20Sopenharmony_ci return 0; 39848c2ecf20Sopenharmony_ci} 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_civoid r100_fini(struct radeon_device *rdev) 39878c2ecf20Sopenharmony_ci{ 39888c2ecf20Sopenharmony_ci radeon_pm_fini(rdev); 39898c2ecf20Sopenharmony_ci r100_cp_fini(rdev); 39908c2ecf20Sopenharmony_ci radeon_wb_fini(rdev); 39918c2ecf20Sopenharmony_ci radeon_ib_pool_fini(rdev); 39928c2ecf20Sopenharmony_ci radeon_gem_fini(rdev); 39938c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_PCI) 39948c2ecf20Sopenharmony_ci r100_pci_gart_fini(rdev); 39958c2ecf20Sopenharmony_ci radeon_agp_fini(rdev); 39968c2ecf20Sopenharmony_ci radeon_irq_kms_fini(rdev); 39978c2ecf20Sopenharmony_ci radeon_fence_driver_fini(rdev); 39988c2ecf20Sopenharmony_ci radeon_bo_fini(rdev); 39998c2ecf20Sopenharmony_ci radeon_atombios_fini(rdev); 40008c2ecf20Sopenharmony_ci kfree(rdev->bios); 40018c2ecf20Sopenharmony_ci rdev->bios = NULL; 40028c2ecf20Sopenharmony_ci} 40038c2ecf20Sopenharmony_ci 40048c2ecf20Sopenharmony_ci/* 40058c2ecf20Sopenharmony_ci * Due to how kexec works, it can leave the hw fully initialised when it 40068c2ecf20Sopenharmony_ci * boots the new kernel. However doing our init sequence with the CP and 40078c2ecf20Sopenharmony_ci * WB stuff setup causes GPU hangs on the RN50 at least. So at startup 40088c2ecf20Sopenharmony_ci * do some quick sanity checks and restore sane values to avoid this 40098c2ecf20Sopenharmony_ci * problem. 40108c2ecf20Sopenharmony_ci */ 40118c2ecf20Sopenharmony_civoid r100_restore_sanity(struct radeon_device *rdev) 40128c2ecf20Sopenharmony_ci{ 40138c2ecf20Sopenharmony_ci u32 tmp; 40148c2ecf20Sopenharmony_ci 40158c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_CP_CSQ_CNTL); 40168c2ecf20Sopenharmony_ci if (tmp) { 40178c2ecf20Sopenharmony_ci WREG32(RADEON_CP_CSQ_CNTL, 0); 40188c2ecf20Sopenharmony_ci } 40198c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_CP_RB_CNTL); 40208c2ecf20Sopenharmony_ci if (tmp) { 40218c2ecf20Sopenharmony_ci WREG32(RADEON_CP_RB_CNTL, 0); 40228c2ecf20Sopenharmony_ci } 40238c2ecf20Sopenharmony_ci tmp = RREG32(RADEON_SCRATCH_UMSK); 40248c2ecf20Sopenharmony_ci if (tmp) { 40258c2ecf20Sopenharmony_ci WREG32(RADEON_SCRATCH_UMSK, 0); 40268c2ecf20Sopenharmony_ci } 40278c2ecf20Sopenharmony_ci} 40288c2ecf20Sopenharmony_ci 40298c2ecf20Sopenharmony_ciint r100_init(struct radeon_device *rdev) 40308c2ecf20Sopenharmony_ci{ 40318c2ecf20Sopenharmony_ci int r; 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci /* Register debugfs file specific to this group of asics */ 40348c2ecf20Sopenharmony_ci r100_debugfs(rdev); 40358c2ecf20Sopenharmony_ci /* Disable VGA */ 40368c2ecf20Sopenharmony_ci r100_vga_render_disable(rdev); 40378c2ecf20Sopenharmony_ci /* Initialize scratch registers */ 40388c2ecf20Sopenharmony_ci radeon_scratch_init(rdev); 40398c2ecf20Sopenharmony_ci /* Initialize surface registers */ 40408c2ecf20Sopenharmony_ci radeon_surface_init(rdev); 40418c2ecf20Sopenharmony_ci /* sanity check some register to avoid hangs like after kexec */ 40428c2ecf20Sopenharmony_ci r100_restore_sanity(rdev); 40438c2ecf20Sopenharmony_ci /* TODO: disable VGA need to use VGA request */ 40448c2ecf20Sopenharmony_ci /* BIOS*/ 40458c2ecf20Sopenharmony_ci if (!radeon_get_bios(rdev)) { 40468c2ecf20Sopenharmony_ci if (ASIC_IS_AVIVO(rdev)) 40478c2ecf20Sopenharmony_ci return -EINVAL; 40488c2ecf20Sopenharmony_ci } 40498c2ecf20Sopenharmony_ci if (rdev->is_atom_bios) { 40508c2ecf20Sopenharmony_ci dev_err(rdev->dev, "Expecting combios for RS400/RS480 GPU\n"); 40518c2ecf20Sopenharmony_ci return -EINVAL; 40528c2ecf20Sopenharmony_ci } else { 40538c2ecf20Sopenharmony_ci r = radeon_combios_init(rdev); 40548c2ecf20Sopenharmony_ci if (r) 40558c2ecf20Sopenharmony_ci return r; 40568c2ecf20Sopenharmony_ci } 40578c2ecf20Sopenharmony_ci /* Reset gpu before posting otherwise ATOM will enter infinite loop */ 40588c2ecf20Sopenharmony_ci if (radeon_asic_reset(rdev)) { 40598c2ecf20Sopenharmony_ci dev_warn(rdev->dev, 40608c2ecf20Sopenharmony_ci "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", 40618c2ecf20Sopenharmony_ci RREG32(R_000E40_RBBM_STATUS), 40628c2ecf20Sopenharmony_ci RREG32(R_0007C0_CP_STAT)); 40638c2ecf20Sopenharmony_ci } 40648c2ecf20Sopenharmony_ci /* check if cards are posted or not */ 40658c2ecf20Sopenharmony_ci if (radeon_boot_test_post_card(rdev) == false) 40668c2ecf20Sopenharmony_ci return -EINVAL; 40678c2ecf20Sopenharmony_ci /* Set asic errata */ 40688c2ecf20Sopenharmony_ci r100_errata(rdev); 40698c2ecf20Sopenharmony_ci /* Initialize clocks */ 40708c2ecf20Sopenharmony_ci radeon_get_clock_info(rdev->ddev); 40718c2ecf20Sopenharmony_ci /* initialize AGP */ 40728c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_AGP) { 40738c2ecf20Sopenharmony_ci r = radeon_agp_init(rdev); 40748c2ecf20Sopenharmony_ci if (r) { 40758c2ecf20Sopenharmony_ci radeon_agp_disable(rdev); 40768c2ecf20Sopenharmony_ci } 40778c2ecf20Sopenharmony_ci } 40788c2ecf20Sopenharmony_ci /* initialize VRAM */ 40798c2ecf20Sopenharmony_ci r100_mc_init(rdev); 40808c2ecf20Sopenharmony_ci /* Fence driver */ 40818c2ecf20Sopenharmony_ci r = radeon_fence_driver_init(rdev); 40828c2ecf20Sopenharmony_ci if (r) 40838c2ecf20Sopenharmony_ci return r; 40848c2ecf20Sopenharmony_ci /* Memory manager */ 40858c2ecf20Sopenharmony_ci r = radeon_bo_init(rdev); 40868c2ecf20Sopenharmony_ci if (r) 40878c2ecf20Sopenharmony_ci return r; 40888c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_PCI) { 40898c2ecf20Sopenharmony_ci r = r100_pci_gart_init(rdev); 40908c2ecf20Sopenharmony_ci if (r) 40918c2ecf20Sopenharmony_ci return r; 40928c2ecf20Sopenharmony_ci } 40938c2ecf20Sopenharmony_ci r100_set_safe_registers(rdev); 40948c2ecf20Sopenharmony_ci 40958c2ecf20Sopenharmony_ci /* Initialize power management */ 40968c2ecf20Sopenharmony_ci radeon_pm_init(rdev); 40978c2ecf20Sopenharmony_ci 40988c2ecf20Sopenharmony_ci rdev->accel_working = true; 40998c2ecf20Sopenharmony_ci r = r100_startup(rdev); 41008c2ecf20Sopenharmony_ci if (r) { 41018c2ecf20Sopenharmony_ci /* Somethings want wront with the accel init stop accel */ 41028c2ecf20Sopenharmony_ci dev_err(rdev->dev, "Disabling GPU acceleration\n"); 41038c2ecf20Sopenharmony_ci r100_cp_fini(rdev); 41048c2ecf20Sopenharmony_ci radeon_wb_fini(rdev); 41058c2ecf20Sopenharmony_ci radeon_ib_pool_fini(rdev); 41068c2ecf20Sopenharmony_ci radeon_irq_kms_fini(rdev); 41078c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_PCI) 41088c2ecf20Sopenharmony_ci r100_pci_gart_fini(rdev); 41098c2ecf20Sopenharmony_ci rdev->accel_working = false; 41108c2ecf20Sopenharmony_ci } 41118c2ecf20Sopenharmony_ci return 0; 41128c2ecf20Sopenharmony_ci} 41138c2ecf20Sopenharmony_ci 41148c2ecf20Sopenharmony_ciuint32_t r100_mm_rreg_slow(struct radeon_device *rdev, uint32_t reg) 41158c2ecf20Sopenharmony_ci{ 41168c2ecf20Sopenharmony_ci unsigned long flags; 41178c2ecf20Sopenharmony_ci uint32_t ret; 41188c2ecf20Sopenharmony_ci 41198c2ecf20Sopenharmony_ci spin_lock_irqsave(&rdev->mmio_idx_lock, flags); 41208c2ecf20Sopenharmony_ci writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); 41218c2ecf20Sopenharmony_ci ret = readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); 41228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); 41238c2ecf20Sopenharmony_ci return ret; 41248c2ecf20Sopenharmony_ci} 41258c2ecf20Sopenharmony_ci 41268c2ecf20Sopenharmony_civoid r100_mm_wreg_slow(struct radeon_device *rdev, uint32_t reg, uint32_t v) 41278c2ecf20Sopenharmony_ci{ 41288c2ecf20Sopenharmony_ci unsigned long flags; 41298c2ecf20Sopenharmony_ci 41308c2ecf20Sopenharmony_ci spin_lock_irqsave(&rdev->mmio_idx_lock, flags); 41318c2ecf20Sopenharmony_ci writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); 41328c2ecf20Sopenharmony_ci writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); 41338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); 41348c2ecf20Sopenharmony_ci} 41358c2ecf20Sopenharmony_ci 41368c2ecf20Sopenharmony_ciu32 r100_io_rreg(struct radeon_device *rdev, u32 reg) 41378c2ecf20Sopenharmony_ci{ 41388c2ecf20Sopenharmony_ci if (reg < rdev->rio_mem_size) 41398c2ecf20Sopenharmony_ci return ioread32(rdev->rio_mem + reg); 41408c2ecf20Sopenharmony_ci else { 41418c2ecf20Sopenharmony_ci iowrite32(reg, rdev->rio_mem + RADEON_MM_INDEX); 41428c2ecf20Sopenharmony_ci return ioread32(rdev->rio_mem + RADEON_MM_DATA); 41438c2ecf20Sopenharmony_ci } 41448c2ecf20Sopenharmony_ci} 41458c2ecf20Sopenharmony_ci 41468c2ecf20Sopenharmony_civoid r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v) 41478c2ecf20Sopenharmony_ci{ 41488c2ecf20Sopenharmony_ci if (reg < rdev->rio_mem_size) 41498c2ecf20Sopenharmony_ci iowrite32(v, rdev->rio_mem + reg); 41508c2ecf20Sopenharmony_ci else { 41518c2ecf20Sopenharmony_ci iowrite32(reg, rdev->rio_mem + RADEON_MM_INDEX); 41528c2ecf20Sopenharmony_ci iowrite32(v, rdev->rio_mem + RADEON_MM_DATA); 41538c2ecf20Sopenharmony_ci } 41548c2ecf20Sopenharmony_ci} 4155