18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2014 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <drm/drm_vblank.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "amdgpu.h" 278c2ecf20Sopenharmony_ci#include "amdgpu_pm.h" 288c2ecf20Sopenharmony_ci#include "amdgpu_i2c.h" 298c2ecf20Sopenharmony_ci#include "atom.h" 308c2ecf20Sopenharmony_ci#include "amdgpu_pll.h" 318c2ecf20Sopenharmony_ci#include "amdgpu_connectors.h" 328c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_SI 338c2ecf20Sopenharmony_ci#include "dce_v6_0.h" 348c2ecf20Sopenharmony_ci#endif 358c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_CIK 368c2ecf20Sopenharmony_ci#include "dce_v8_0.h" 378c2ecf20Sopenharmony_ci#endif 388c2ecf20Sopenharmony_ci#include "dce_v10_0.h" 398c2ecf20Sopenharmony_ci#include "dce_v11_0.h" 408c2ecf20Sopenharmony_ci#include "dce_virtual.h" 418c2ecf20Sopenharmony_ci#include "ivsrcid/ivsrcid_vislands30.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define DCE_VIRTUAL_VBLANK_PERIOD 16666666 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic void dce_virtual_set_display_funcs(struct amdgpu_device *adev); 478c2ecf20Sopenharmony_cistatic void dce_virtual_set_irq_funcs(struct amdgpu_device *adev); 488c2ecf20Sopenharmony_cistatic int dce_virtual_connector_encoder_init(struct amdgpu_device *adev, 498c2ecf20Sopenharmony_ci int index); 508c2ecf20Sopenharmony_cistatic int dce_virtual_pageflip(struct amdgpu_device *adev, 518c2ecf20Sopenharmony_ci unsigned crtc_id); 528c2ecf20Sopenharmony_cistatic enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vblank_timer); 538c2ecf20Sopenharmony_cistatic void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev, 548c2ecf20Sopenharmony_ci int crtc, 558c2ecf20Sopenharmony_ci enum amdgpu_interrupt_state state); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic u32 dce_virtual_vblank_get_counter(struct amdgpu_device *adev, int crtc) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void dce_virtual_page_flip(struct amdgpu_device *adev, 638c2ecf20Sopenharmony_ci int crtc_id, u64 crtc_base, bool async) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci return; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int dce_virtual_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, 698c2ecf20Sopenharmony_ci u32 *vbl, u32 *position) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci *vbl = 0; 728c2ecf20Sopenharmony_ci *position = 0; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return -EINVAL; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic bool dce_virtual_hpd_sense(struct amdgpu_device *adev, 788c2ecf20Sopenharmony_ci enum amdgpu_hpd_id hpd) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci return true; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic void dce_virtual_hpd_set_polarity(struct amdgpu_device *adev, 848c2ecf20Sopenharmony_ci enum amdgpu_hpd_id hpd) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci return; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic u32 dce_virtual_hpd_get_gpio_reg(struct amdgpu_device *adev) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/** 958c2ecf20Sopenharmony_ci * dce_virtual_bandwidth_update - program display watermarks 968c2ecf20Sopenharmony_ci * 978c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * Calculate and program the display watermarks and line 1008c2ecf20Sopenharmony_ci * buffer allocation (CIK). 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_cistatic void dce_virtual_bandwidth_update(struct amdgpu_device *adev) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci return; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int dce_virtual_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, 1088c2ecf20Sopenharmony_ci u16 *green, u16 *blue, uint32_t size, 1098c2ecf20Sopenharmony_ci struct drm_modeset_acquire_ctx *ctx) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void dce_virtual_crtc_destroy(struct drm_crtc *crtc) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci drm_crtc_cleanup(crtc); 1198c2ecf20Sopenharmony_ci kfree(amdgpu_crtc); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic const struct drm_crtc_funcs dce_virtual_crtc_funcs = { 1238c2ecf20Sopenharmony_ci .cursor_set2 = NULL, 1248c2ecf20Sopenharmony_ci .cursor_move = NULL, 1258c2ecf20Sopenharmony_ci .gamma_set = dce_virtual_crtc_gamma_set, 1268c2ecf20Sopenharmony_ci .set_config = amdgpu_display_crtc_set_config, 1278c2ecf20Sopenharmony_ci .destroy = dce_virtual_crtc_destroy, 1288c2ecf20Sopenharmony_ci .page_flip_target = amdgpu_display_crtc_page_flip_target, 1298c2ecf20Sopenharmony_ci .get_vblank_counter = amdgpu_get_vblank_counter_kms, 1308c2ecf20Sopenharmony_ci .enable_vblank = amdgpu_enable_vblank_kms, 1318c2ecf20Sopenharmony_ci .disable_vblank = amdgpu_disable_vblank_kms, 1328c2ecf20Sopenharmony_ci .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, 1338c2ecf20Sopenharmony_ci}; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic void dce_virtual_crtc_dpms(struct drm_crtc *crtc, int mode) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 1388c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 1398c2ecf20Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 1408c2ecf20Sopenharmony_ci unsigned type; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 1438c2ecf20Sopenharmony_ci return; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci switch (mode) { 1468c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_ON: 1478c2ecf20Sopenharmony_ci amdgpu_crtc->enabled = true; 1488c2ecf20Sopenharmony_ci /* Make sure VBLANK interrupts are still enabled */ 1498c2ecf20Sopenharmony_ci type = amdgpu_display_crtc_idx_to_irq_type(adev, 1508c2ecf20Sopenharmony_ci amdgpu_crtc->crtc_id); 1518c2ecf20Sopenharmony_ci amdgpu_irq_update(adev, &adev->crtc_irq, type); 1528c2ecf20Sopenharmony_ci drm_crtc_vblank_on(crtc); 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 1558c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 1568c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_OFF: 1578c2ecf20Sopenharmony_ci drm_crtc_vblank_off(crtc); 1588c2ecf20Sopenharmony_ci amdgpu_crtc->enabled = false; 1598c2ecf20Sopenharmony_ci break; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic void dce_virtual_crtc_prepare(struct drm_crtc *crtc) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void dce_virtual_crtc_commit(struct drm_crtc *crtc) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic void dce_virtual_crtc_disable(struct drm_crtc *crtc) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 1778c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (dev->num_crtcs) 1808c2ecf20Sopenharmony_ci drm_crtc_vblank_off(crtc); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci amdgpu_crtc->enabled = false; 1838c2ecf20Sopenharmony_ci amdgpu_crtc->pll_id = ATOM_PPLL_INVALID; 1848c2ecf20Sopenharmony_ci amdgpu_crtc->encoder = NULL; 1858c2ecf20Sopenharmony_ci amdgpu_crtc->connector = NULL; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int dce_virtual_crtc_mode_set(struct drm_crtc *crtc, 1898c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 1908c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode, 1918c2ecf20Sopenharmony_ci int x, int y, struct drm_framebuffer *old_fb) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* update the hw version fpr dpm */ 1968c2ecf20Sopenharmony_ci amdgpu_crtc->hw_mode = *adjusted_mode; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic bool dce_virtual_crtc_mode_fixup(struct drm_crtc *crtc, 2028c2ecf20Sopenharmony_ci const struct drm_display_mode *mode, 2038c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci return true; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int dce_virtual_crtc_set_base(struct drm_crtc *crtc, int x, int y, 2108c2ecf20Sopenharmony_ci struct drm_framebuffer *old_fb) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int dce_virtual_crtc_set_base_atomic(struct drm_crtc *crtc, 2168c2ecf20Sopenharmony_ci struct drm_framebuffer *fb, 2178c2ecf20Sopenharmony_ci int x, int y, enum mode_set_atomic state) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic const struct drm_crtc_helper_funcs dce_virtual_crtc_helper_funcs = { 2238c2ecf20Sopenharmony_ci .dpms = dce_virtual_crtc_dpms, 2248c2ecf20Sopenharmony_ci .mode_fixup = dce_virtual_crtc_mode_fixup, 2258c2ecf20Sopenharmony_ci .mode_set = dce_virtual_crtc_mode_set, 2268c2ecf20Sopenharmony_ci .mode_set_base = dce_virtual_crtc_set_base, 2278c2ecf20Sopenharmony_ci .mode_set_base_atomic = dce_virtual_crtc_set_base_atomic, 2288c2ecf20Sopenharmony_ci .prepare = dce_virtual_crtc_prepare, 2298c2ecf20Sopenharmony_ci .commit = dce_virtual_crtc_commit, 2308c2ecf20Sopenharmony_ci .disable = dce_virtual_crtc_disable, 2318c2ecf20Sopenharmony_ci .get_scanout_position = amdgpu_crtc_get_scanout_position, 2328c2ecf20Sopenharmony_ci}; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic int dce_virtual_crtc_init(struct amdgpu_device *adev, int index) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci amdgpu_crtc = kzalloc(sizeof(struct amdgpu_crtc) + 2398c2ecf20Sopenharmony_ci (AMDGPUFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); 2408c2ecf20Sopenharmony_ci if (amdgpu_crtc == NULL) 2418c2ecf20Sopenharmony_ci return -ENOMEM; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci drm_crtc_init(adev_to_drm(adev), &amdgpu_crtc->base, &dce_virtual_crtc_funcs); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci drm_mode_crtc_set_gamma_size(&amdgpu_crtc->base, 256); 2468c2ecf20Sopenharmony_ci amdgpu_crtc->crtc_id = index; 2478c2ecf20Sopenharmony_ci adev->mode_info.crtcs[index] = amdgpu_crtc; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci amdgpu_crtc->pll_id = ATOM_PPLL_INVALID; 2508c2ecf20Sopenharmony_ci amdgpu_crtc->encoder = NULL; 2518c2ecf20Sopenharmony_ci amdgpu_crtc->connector = NULL; 2528c2ecf20Sopenharmony_ci amdgpu_crtc->vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE; 2538c2ecf20Sopenharmony_ci drm_crtc_helper_add(&amdgpu_crtc->base, &dce_virtual_crtc_helper_funcs); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci hrtimer_init(&amdgpu_crtc->vblank_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 2568c2ecf20Sopenharmony_ci hrtimer_set_expires(&amdgpu_crtc->vblank_timer, DCE_VIRTUAL_VBLANK_PERIOD); 2578c2ecf20Sopenharmony_ci amdgpu_crtc->vblank_timer.function = dce_virtual_vblank_timer_handle; 2588c2ecf20Sopenharmony_ci hrtimer_start(&amdgpu_crtc->vblank_timer, 2598c2ecf20Sopenharmony_ci DCE_VIRTUAL_VBLANK_PERIOD, HRTIMER_MODE_REL); 2608c2ecf20Sopenharmony_ci return 0; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic int dce_virtual_early_init(void *handle) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct amdgpu_device *adev = (struct amdgpu_device *)handle; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci dce_virtual_set_display_funcs(adev); 2688c2ecf20Sopenharmony_ci dce_virtual_set_irq_funcs(adev); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci adev->mode_info.num_hpd = 1; 2718c2ecf20Sopenharmony_ci adev->mode_info.num_dig = 1; 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic struct drm_encoder * 2768c2ecf20Sopenharmony_cidce_virtual_encoder(struct drm_connector *connector) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct drm_encoder *encoder; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci drm_connector_for_each_possible_encoder(connector, encoder) { 2818c2ecf20Sopenharmony_ci if (encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL) 2828c2ecf20Sopenharmony_ci return encoder; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* pick the first one */ 2868c2ecf20Sopenharmony_ci drm_connector_for_each_possible_encoder(connector, encoder) 2878c2ecf20Sopenharmony_ci return encoder; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return NULL; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic int dce_virtual_get_modes(struct drm_connector *connector) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct drm_device *dev = connector->dev; 2958c2ecf20Sopenharmony_ci struct drm_display_mode *mode = NULL; 2968c2ecf20Sopenharmony_ci unsigned i; 2978c2ecf20Sopenharmony_ci static const struct mode_size { 2988c2ecf20Sopenharmony_ci int w; 2998c2ecf20Sopenharmony_ci int h; 3008c2ecf20Sopenharmony_ci } common_modes[21] = { 3018c2ecf20Sopenharmony_ci { 640, 480}, 3028c2ecf20Sopenharmony_ci { 720, 480}, 3038c2ecf20Sopenharmony_ci { 800, 600}, 3048c2ecf20Sopenharmony_ci { 848, 480}, 3058c2ecf20Sopenharmony_ci {1024, 768}, 3068c2ecf20Sopenharmony_ci {1152, 768}, 3078c2ecf20Sopenharmony_ci {1280, 720}, 3088c2ecf20Sopenharmony_ci {1280, 800}, 3098c2ecf20Sopenharmony_ci {1280, 854}, 3108c2ecf20Sopenharmony_ci {1280, 960}, 3118c2ecf20Sopenharmony_ci {1280, 1024}, 3128c2ecf20Sopenharmony_ci {1440, 900}, 3138c2ecf20Sopenharmony_ci {1400, 1050}, 3148c2ecf20Sopenharmony_ci {1680, 1050}, 3158c2ecf20Sopenharmony_ci {1600, 1200}, 3168c2ecf20Sopenharmony_ci {1920, 1080}, 3178c2ecf20Sopenharmony_ci {1920, 1200}, 3188c2ecf20Sopenharmony_ci {4096, 3112}, 3198c2ecf20Sopenharmony_ci {3656, 2664}, 3208c2ecf20Sopenharmony_ci {3840, 2160}, 3218c2ecf20Sopenharmony_ci {4096, 2160}, 3228c2ecf20Sopenharmony_ci }; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci for (i = 0; i < 21; i++) { 3258c2ecf20Sopenharmony_ci mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false); 3268c2ecf20Sopenharmony_ci drm_mode_probed_add(connector, mode); 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return 0; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic enum drm_mode_status dce_virtual_mode_valid(struct drm_connector *connector, 3338c2ecf20Sopenharmony_ci struct drm_display_mode *mode) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci return MODE_OK; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int 3398c2ecf20Sopenharmony_cidce_virtual_dpms(struct drm_connector *connector, int mode) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int 3458c2ecf20Sopenharmony_cidce_virtual_set_property(struct drm_connector *connector, 3468c2ecf20Sopenharmony_ci struct drm_property *property, 3478c2ecf20Sopenharmony_ci uint64_t val) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci return 0; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic void dce_virtual_destroy(struct drm_connector *connector) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci drm_connector_unregister(connector); 3558c2ecf20Sopenharmony_ci drm_connector_cleanup(connector); 3568c2ecf20Sopenharmony_ci kfree(connector); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic void dce_virtual_force(struct drm_connector *connector) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci return; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs dce_virtual_connector_helper_funcs = { 3658c2ecf20Sopenharmony_ci .get_modes = dce_virtual_get_modes, 3668c2ecf20Sopenharmony_ci .mode_valid = dce_virtual_mode_valid, 3678c2ecf20Sopenharmony_ci .best_encoder = dce_virtual_encoder, 3688c2ecf20Sopenharmony_ci}; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs dce_virtual_connector_funcs = { 3718c2ecf20Sopenharmony_ci .dpms = dce_virtual_dpms, 3728c2ecf20Sopenharmony_ci .fill_modes = drm_helper_probe_single_connector_modes, 3738c2ecf20Sopenharmony_ci .set_property = dce_virtual_set_property, 3748c2ecf20Sopenharmony_ci .destroy = dce_virtual_destroy, 3758c2ecf20Sopenharmony_ci .force = dce_virtual_force, 3768c2ecf20Sopenharmony_ci}; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic int dce_virtual_sw_init(void *handle) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci int r, i; 3818c2ecf20Sopenharmony_ci struct amdgpu_device *adev = (struct amdgpu_device *)handle; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_SMU_DISP_TIMER2_TRIGGER, &adev->crtc_irq); 3848c2ecf20Sopenharmony_ci if (r) 3858c2ecf20Sopenharmony_ci return r; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci adev_to_drm(adev)->max_vblank_count = 0; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci adev_to_drm(adev)->mode_config.funcs = &amdgpu_mode_funcs; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci adev_to_drm(adev)->mode_config.max_width = 16384; 3928c2ecf20Sopenharmony_ci adev_to_drm(adev)->mode_config.max_height = 16384; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci adev_to_drm(adev)->mode_config.preferred_depth = 24; 3958c2ecf20Sopenharmony_ci adev_to_drm(adev)->mode_config.prefer_shadow = 1; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci r = amdgpu_display_modeset_create_props(adev); 4008c2ecf20Sopenharmony_ci if (r) 4018c2ecf20Sopenharmony_ci return r; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci adev_to_drm(adev)->mode_config.max_width = 16384; 4048c2ecf20Sopenharmony_ci adev_to_drm(adev)->mode_config.max_height = 16384; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* allocate crtcs, encoders, connectors */ 4078c2ecf20Sopenharmony_ci for (i = 0; i < adev->mode_info.num_crtc; i++) { 4088c2ecf20Sopenharmony_ci r = dce_virtual_crtc_init(adev, i); 4098c2ecf20Sopenharmony_ci if (r) 4108c2ecf20Sopenharmony_ci return r; 4118c2ecf20Sopenharmony_ci r = dce_virtual_connector_encoder_init(adev, i); 4128c2ecf20Sopenharmony_ci if (r) 4138c2ecf20Sopenharmony_ci return r; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci drm_kms_helper_poll_init(adev_to_drm(adev)); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci adev->mode_info.mode_config_initialized = true; 4198c2ecf20Sopenharmony_ci return 0; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic int dce_virtual_sw_fini(void *handle) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct amdgpu_device *adev = (struct amdgpu_device *)handle; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci kfree(adev->mode_info.bios_hardcoded_edid); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci drm_kms_helper_poll_fini(adev_to_drm(adev)); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci drm_mode_config_cleanup(adev_to_drm(adev)); 4318c2ecf20Sopenharmony_ci /* clear crtcs pointer to avoid dce irq finish routine access freed data */ 4328c2ecf20Sopenharmony_ci memset(adev->mode_info.crtcs, 0, sizeof(adev->mode_info.crtcs[0]) * AMDGPU_MAX_CRTCS); 4338c2ecf20Sopenharmony_ci adev->mode_info.mode_config_initialized = false; 4348c2ecf20Sopenharmony_ci return 0; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic int dce_virtual_hw_init(void *handle) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct amdgpu_device *adev = (struct amdgpu_device *)handle; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci switch (adev->asic_type) { 4428c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_SI 4438c2ecf20Sopenharmony_ci case CHIP_TAHITI: 4448c2ecf20Sopenharmony_ci case CHIP_PITCAIRN: 4458c2ecf20Sopenharmony_ci case CHIP_VERDE: 4468c2ecf20Sopenharmony_ci case CHIP_OLAND: 4478c2ecf20Sopenharmony_ci dce_v6_0_disable_dce(adev); 4488c2ecf20Sopenharmony_ci break; 4498c2ecf20Sopenharmony_ci#endif 4508c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_CIK 4518c2ecf20Sopenharmony_ci case CHIP_BONAIRE: 4528c2ecf20Sopenharmony_ci case CHIP_HAWAII: 4538c2ecf20Sopenharmony_ci case CHIP_KAVERI: 4548c2ecf20Sopenharmony_ci case CHIP_KABINI: 4558c2ecf20Sopenharmony_ci case CHIP_MULLINS: 4568c2ecf20Sopenharmony_ci dce_v8_0_disable_dce(adev); 4578c2ecf20Sopenharmony_ci break; 4588c2ecf20Sopenharmony_ci#endif 4598c2ecf20Sopenharmony_ci case CHIP_FIJI: 4608c2ecf20Sopenharmony_ci case CHIP_TONGA: 4618c2ecf20Sopenharmony_ci dce_v10_0_disable_dce(adev); 4628c2ecf20Sopenharmony_ci break; 4638c2ecf20Sopenharmony_ci case CHIP_CARRIZO: 4648c2ecf20Sopenharmony_ci case CHIP_STONEY: 4658c2ecf20Sopenharmony_ci case CHIP_POLARIS10: 4668c2ecf20Sopenharmony_ci case CHIP_POLARIS11: 4678c2ecf20Sopenharmony_ci case CHIP_VEGAM: 4688c2ecf20Sopenharmony_ci dce_v11_0_disable_dce(adev); 4698c2ecf20Sopenharmony_ci break; 4708c2ecf20Sopenharmony_ci case CHIP_TOPAZ: 4718c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_SI 4728c2ecf20Sopenharmony_ci case CHIP_HAINAN: 4738c2ecf20Sopenharmony_ci#endif 4748c2ecf20Sopenharmony_ci /* no DCE */ 4758c2ecf20Sopenharmony_ci break; 4768c2ecf20Sopenharmony_ci default: 4778c2ecf20Sopenharmony_ci break; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic int dce_virtual_hw_fini(void *handle) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct amdgpu_device *adev = (struct amdgpu_device *)handle; 4858c2ecf20Sopenharmony_ci int i = 0; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci for (i = 0; i<adev->mode_info.num_crtc; i++) 4888c2ecf20Sopenharmony_ci if (adev->mode_info.crtcs[i]) 4898c2ecf20Sopenharmony_ci hrtimer_cancel(&adev->mode_info.crtcs[i]->vblank_timer); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int dce_virtual_suspend(void *handle) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci return dce_virtual_hw_fini(handle); 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic int dce_virtual_resume(void *handle) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci return dce_virtual_hw_init(handle); 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic bool dce_virtual_is_idle(void *handle) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci return true; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic int dce_virtual_wait_for_idle(void *handle) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci return 0; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic int dce_virtual_soft_reset(void *handle) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci return 0; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic int dce_virtual_set_clockgating_state(void *handle, 5208c2ecf20Sopenharmony_ci enum amd_clockgating_state state) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci return 0; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic int dce_virtual_set_powergating_state(void *handle, 5268c2ecf20Sopenharmony_ci enum amd_powergating_state state) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci return 0; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic const struct amd_ip_funcs dce_virtual_ip_funcs = { 5328c2ecf20Sopenharmony_ci .name = "dce_virtual", 5338c2ecf20Sopenharmony_ci .early_init = dce_virtual_early_init, 5348c2ecf20Sopenharmony_ci .late_init = NULL, 5358c2ecf20Sopenharmony_ci .sw_init = dce_virtual_sw_init, 5368c2ecf20Sopenharmony_ci .sw_fini = dce_virtual_sw_fini, 5378c2ecf20Sopenharmony_ci .hw_init = dce_virtual_hw_init, 5388c2ecf20Sopenharmony_ci .hw_fini = dce_virtual_hw_fini, 5398c2ecf20Sopenharmony_ci .suspend = dce_virtual_suspend, 5408c2ecf20Sopenharmony_ci .resume = dce_virtual_resume, 5418c2ecf20Sopenharmony_ci .is_idle = dce_virtual_is_idle, 5428c2ecf20Sopenharmony_ci .wait_for_idle = dce_virtual_wait_for_idle, 5438c2ecf20Sopenharmony_ci .soft_reset = dce_virtual_soft_reset, 5448c2ecf20Sopenharmony_ci .set_clockgating_state = dce_virtual_set_clockgating_state, 5458c2ecf20Sopenharmony_ci .set_powergating_state = dce_virtual_set_powergating_state, 5468c2ecf20Sopenharmony_ci}; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci/* these are handled by the primary encoders */ 5498c2ecf20Sopenharmony_cistatic void dce_virtual_encoder_prepare(struct drm_encoder *encoder) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci return; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic void dce_virtual_encoder_commit(struct drm_encoder *encoder) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci return; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic void 5608c2ecf20Sopenharmony_cidce_virtual_encoder_mode_set(struct drm_encoder *encoder, 5618c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 5628c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci return; 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic void dce_virtual_encoder_disable(struct drm_encoder *encoder) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci return; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic void 5738c2ecf20Sopenharmony_cidce_virtual_encoder_dpms(struct drm_encoder *encoder, int mode) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci return; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic bool dce_virtual_encoder_mode_fixup(struct drm_encoder *encoder, 5798c2ecf20Sopenharmony_ci const struct drm_display_mode *mode, 5808c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci return true; 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs dce_virtual_encoder_helper_funcs = { 5868c2ecf20Sopenharmony_ci .dpms = dce_virtual_encoder_dpms, 5878c2ecf20Sopenharmony_ci .mode_fixup = dce_virtual_encoder_mode_fixup, 5888c2ecf20Sopenharmony_ci .prepare = dce_virtual_encoder_prepare, 5898c2ecf20Sopenharmony_ci .mode_set = dce_virtual_encoder_mode_set, 5908c2ecf20Sopenharmony_ci .commit = dce_virtual_encoder_commit, 5918c2ecf20Sopenharmony_ci .disable = dce_virtual_encoder_disable, 5928c2ecf20Sopenharmony_ci}; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic void dce_virtual_encoder_destroy(struct drm_encoder *encoder) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci drm_encoder_cleanup(encoder); 5978c2ecf20Sopenharmony_ci kfree(encoder); 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic const struct drm_encoder_funcs dce_virtual_encoder_funcs = { 6018c2ecf20Sopenharmony_ci .destroy = dce_virtual_encoder_destroy, 6028c2ecf20Sopenharmony_ci}; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic int dce_virtual_connector_encoder_init(struct amdgpu_device *adev, 6058c2ecf20Sopenharmony_ci int index) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct drm_encoder *encoder; 6088c2ecf20Sopenharmony_ci struct drm_connector *connector; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* add a new encoder */ 6118c2ecf20Sopenharmony_ci encoder = kzalloc(sizeof(struct drm_encoder), GFP_KERNEL); 6128c2ecf20Sopenharmony_ci if (!encoder) 6138c2ecf20Sopenharmony_ci return -ENOMEM; 6148c2ecf20Sopenharmony_ci encoder->possible_crtcs = 1 << index; 6158c2ecf20Sopenharmony_ci drm_encoder_init(adev_to_drm(adev), encoder, &dce_virtual_encoder_funcs, 6168c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_VIRTUAL, NULL); 6178c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &dce_virtual_encoder_helper_funcs); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci connector = kzalloc(sizeof(struct drm_connector), GFP_KERNEL); 6208c2ecf20Sopenharmony_ci if (!connector) { 6218c2ecf20Sopenharmony_ci kfree(encoder); 6228c2ecf20Sopenharmony_ci return -ENOMEM; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* add a new connector */ 6268c2ecf20Sopenharmony_ci drm_connector_init(adev_to_drm(adev), connector, &dce_virtual_connector_funcs, 6278c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_VIRTUAL); 6288c2ecf20Sopenharmony_ci drm_connector_helper_add(connector, &dce_virtual_connector_helper_funcs); 6298c2ecf20Sopenharmony_ci connector->display_info.subpixel_order = SubPixelHorizontalRGB; 6308c2ecf20Sopenharmony_ci connector->interlace_allowed = false; 6318c2ecf20Sopenharmony_ci connector->doublescan_allowed = false; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* link them */ 6348c2ecf20Sopenharmony_ci drm_connector_attach_encoder(connector, encoder); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci return 0; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic const struct amdgpu_display_funcs dce_virtual_display_funcs = { 6408c2ecf20Sopenharmony_ci .bandwidth_update = &dce_virtual_bandwidth_update, 6418c2ecf20Sopenharmony_ci .vblank_get_counter = &dce_virtual_vblank_get_counter, 6428c2ecf20Sopenharmony_ci .backlight_set_level = NULL, 6438c2ecf20Sopenharmony_ci .backlight_get_level = NULL, 6448c2ecf20Sopenharmony_ci .hpd_sense = &dce_virtual_hpd_sense, 6458c2ecf20Sopenharmony_ci .hpd_set_polarity = &dce_virtual_hpd_set_polarity, 6468c2ecf20Sopenharmony_ci .hpd_get_gpio_reg = &dce_virtual_hpd_get_gpio_reg, 6478c2ecf20Sopenharmony_ci .page_flip = &dce_virtual_page_flip, 6488c2ecf20Sopenharmony_ci .page_flip_get_scanoutpos = &dce_virtual_crtc_get_scanoutpos, 6498c2ecf20Sopenharmony_ci .add_encoder = NULL, 6508c2ecf20Sopenharmony_ci .add_connector = NULL, 6518c2ecf20Sopenharmony_ci}; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic void dce_virtual_set_display_funcs(struct amdgpu_device *adev) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci adev->mode_info.funcs = &dce_virtual_display_funcs; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int dce_virtual_pageflip(struct amdgpu_device *adev, 6598c2ecf20Sopenharmony_ci unsigned crtc_id) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci unsigned long flags; 6628c2ecf20Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc; 6638c2ecf20Sopenharmony_ci struct amdgpu_flip_work *works; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci amdgpu_crtc = adev->mode_info.crtcs[crtc_id]; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (crtc_id >= adev->mode_info.num_crtc) { 6688c2ecf20Sopenharmony_ci DRM_ERROR("invalid pageflip crtc %d\n", crtc_id); 6698c2ecf20Sopenharmony_ci return -EINVAL; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* IRQ could occur when in initial stage */ 6738c2ecf20Sopenharmony_ci if (amdgpu_crtc == NULL) 6748c2ecf20Sopenharmony_ci return 0; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); 6778c2ecf20Sopenharmony_ci works = amdgpu_crtc->pflip_works; 6788c2ecf20Sopenharmony_ci if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) { 6798c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d != " 6808c2ecf20Sopenharmony_ci "AMDGPU_FLIP_SUBMITTED(%d)\n", 6818c2ecf20Sopenharmony_ci amdgpu_crtc->pflip_status, 6828c2ecf20Sopenharmony_ci AMDGPU_FLIP_SUBMITTED); 6838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); 6848c2ecf20Sopenharmony_ci return 0; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* page flip completed. clean up */ 6888c2ecf20Sopenharmony_ci amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE; 6898c2ecf20Sopenharmony_ci amdgpu_crtc->pflip_works = NULL; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* wakeup usersapce */ 6928c2ecf20Sopenharmony_ci if (works->event) 6938c2ecf20Sopenharmony_ci drm_crtc_send_vblank_event(&amdgpu_crtc->base, works->event); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci drm_crtc_vblank_put(&amdgpu_crtc->base); 6988c2ecf20Sopenharmony_ci amdgpu_bo_unref(&works->old_abo); 6998c2ecf20Sopenharmony_ci kfree(works->shared); 7008c2ecf20Sopenharmony_ci kfree(works); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci return 0; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vblank_timer) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = container_of(vblank_timer, 7088c2ecf20Sopenharmony_ci struct amdgpu_crtc, vblank_timer); 7098c2ecf20Sopenharmony_ci struct drm_device *ddev = amdgpu_crtc->base.dev; 7108c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(ddev); 7118c2ecf20Sopenharmony_ci struct amdgpu_irq_src *source = adev->irq.client[AMDGPU_IRQ_CLIENTID_LEGACY].sources 7128c2ecf20Sopenharmony_ci [VISLANDS30_IV_SRCID_SMU_DISP_TIMER2_TRIGGER]; 7138c2ecf20Sopenharmony_ci int irq_type = amdgpu_display_crtc_idx_to_irq_type(adev, 7148c2ecf20Sopenharmony_ci amdgpu_crtc->crtc_id); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (amdgpu_irq_enabled(adev, source, irq_type)) { 7178c2ecf20Sopenharmony_ci drm_handle_vblank(ddev, amdgpu_crtc->crtc_id); 7188c2ecf20Sopenharmony_ci dce_virtual_pageflip(adev, amdgpu_crtc->crtc_id); 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci hrtimer_start(vblank_timer, DCE_VIRTUAL_VBLANK_PERIOD, 7218c2ecf20Sopenharmony_ci HRTIMER_MODE_REL); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci return HRTIMER_NORESTART; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev, 7278c2ecf20Sopenharmony_ci int crtc, 7288c2ecf20Sopenharmony_ci enum amdgpu_interrupt_state state) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci if (crtc >= adev->mode_info.num_crtc || !adev->mode_info.crtcs[crtc]) { 7318c2ecf20Sopenharmony_ci DRM_DEBUG("invalid crtc %d\n", crtc); 7328c2ecf20Sopenharmony_ci return; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci adev->mode_info.crtcs[crtc]->vsync_timer_enabled = state; 7368c2ecf20Sopenharmony_ci DRM_DEBUG("[FM]set crtc %d vblank interrupt state %d\n", crtc, state); 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_cistatic int dce_virtual_set_crtc_irq_state(struct amdgpu_device *adev, 7418c2ecf20Sopenharmony_ci struct amdgpu_irq_src *source, 7428c2ecf20Sopenharmony_ci unsigned type, 7438c2ecf20Sopenharmony_ci enum amdgpu_interrupt_state state) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci if (type > AMDGPU_CRTC_IRQ_VBLANK6) 7468c2ecf20Sopenharmony_ci return -EINVAL; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci dce_virtual_set_crtc_vblank_interrupt_state(adev, type, state); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci return 0; 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cistatic const struct amdgpu_irq_src_funcs dce_virtual_crtc_irq_funcs = { 7548c2ecf20Sopenharmony_ci .set = dce_virtual_set_crtc_irq_state, 7558c2ecf20Sopenharmony_ci .process = NULL, 7568c2ecf20Sopenharmony_ci}; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic void dce_virtual_set_irq_funcs(struct amdgpu_device *adev) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_VBLANK6 + 1; 7618c2ecf20Sopenharmony_ci adev->crtc_irq.funcs = &dce_virtual_crtc_irq_funcs; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ciconst struct amdgpu_ip_block_version dce_virtual_ip_block = 7658c2ecf20Sopenharmony_ci{ 7668c2ecf20Sopenharmony_ci .type = AMD_IP_BLOCK_TYPE_DCE, 7678c2ecf20Sopenharmony_ci .major = 1, 7688c2ecf20Sopenharmony_ci .minor = 0, 7698c2ecf20Sopenharmony_ci .rev = 0, 7708c2ecf20Sopenharmony_ci .funcs = &dce_virtual_ip_funcs, 7718c2ecf20Sopenharmony_ci}; 772