1b843c749SSergey Zigachev /*
2b843c749SSergey Zigachev * Copyright 2014 Advanced Micro Devices, Inc.
3b843c749SSergey Zigachev *
4b843c749SSergey Zigachev * Permission is hereby granted, free of charge, to any person obtaining a
5b843c749SSergey Zigachev * copy of this software and associated documentation files (the "Software"),
6b843c749SSergey Zigachev * to deal in the Software without restriction, including without limitation
7b843c749SSergey Zigachev * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b843c749SSergey Zigachev * and/or sell copies of the Software, and to permit persons to whom the
9b843c749SSergey Zigachev * Software is furnished to do so, subject to the following conditions:
10b843c749SSergey Zigachev *
11b843c749SSergey Zigachev * The above copyright notice and this permission notice shall be included in
12b843c749SSergey Zigachev * all copies or substantial portions of the Software.
13b843c749SSergey Zigachev *
14b843c749SSergey Zigachev * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15b843c749SSergey Zigachev * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16b843c749SSergey Zigachev * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17b843c749SSergey Zigachev * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18b843c749SSergey Zigachev * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19b843c749SSergey Zigachev * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20b843c749SSergey Zigachev * OTHER DEALINGS IN THE SOFTWARE.
21b843c749SSergey Zigachev *
22b843c749SSergey Zigachev */
23b843c749SSergey Zigachev #include <drm/drmP.h>
24b843c749SSergey Zigachev #include "amdgpu.h"
25b843c749SSergey Zigachev #include "amdgpu_pm.h"
26b843c749SSergey Zigachev #include "amdgpu_i2c.h"
27b843c749SSergey Zigachev #include "atom.h"
28b843c749SSergey Zigachev #include "amdgpu_pll.h"
29b843c749SSergey Zigachev #include "amdgpu_connectors.h"
30b843c749SSergey Zigachev #ifdef CONFIG_DRM_AMDGPU_SI
31b843c749SSergey Zigachev #include "dce_v6_0.h"
32b843c749SSergey Zigachev #endif
33b843c749SSergey Zigachev #ifdef CONFIG_DRM_AMDGPU_CIK
34b843c749SSergey Zigachev #include "dce_v8_0.h"
35b843c749SSergey Zigachev #endif
36b843c749SSergey Zigachev #include "dce_v10_0.h"
37b843c749SSergey Zigachev #include "dce_v11_0.h"
38b843c749SSergey Zigachev #include "dce_virtual.h"
39b843c749SSergey Zigachev #include "ivsrcid/ivsrcid_vislands30.h"
40b843c749SSergey Zigachev
41b843c749SSergey Zigachev #define DCE_VIRTUAL_VBLANK_PERIOD 16666666
42b843c749SSergey Zigachev
43b843c749SSergey Zigachev
44b843c749SSergey Zigachev static void dce_virtual_set_display_funcs(struct amdgpu_device *adev);
45b843c749SSergey Zigachev static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev);
46b843c749SSergey Zigachev static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev,
47b843c749SSergey Zigachev int index);
48b843c749SSergey Zigachev static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev,
49b843c749SSergey Zigachev int crtc,
50b843c749SSergey Zigachev enum amdgpu_interrupt_state state);
51b843c749SSergey Zigachev
dce_virtual_vblank_get_counter(struct amdgpu_device * adev,int crtc)52b843c749SSergey Zigachev static u32 dce_virtual_vblank_get_counter(struct amdgpu_device *adev, int crtc)
53b843c749SSergey Zigachev {
54b843c749SSergey Zigachev return 0;
55b843c749SSergey Zigachev }
56b843c749SSergey Zigachev
dce_virtual_page_flip(struct amdgpu_device * adev,int crtc_id,u64 crtc_base,bool async)57b843c749SSergey Zigachev static void dce_virtual_page_flip(struct amdgpu_device *adev,
58b843c749SSergey Zigachev int crtc_id, u64 crtc_base, bool async)
59b843c749SSergey Zigachev {
60b843c749SSergey Zigachev return;
61b843c749SSergey Zigachev }
62b843c749SSergey Zigachev
dce_virtual_crtc_get_scanoutpos(struct amdgpu_device * adev,int crtc,u32 * vbl,u32 * position)63b843c749SSergey Zigachev static int dce_virtual_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
64b843c749SSergey Zigachev u32 *vbl, u32 *position)
65b843c749SSergey Zigachev {
66b843c749SSergey Zigachev *vbl = 0;
67b843c749SSergey Zigachev *position = 0;
68b843c749SSergey Zigachev
69b843c749SSergey Zigachev return -EINVAL;
70b843c749SSergey Zigachev }
71b843c749SSergey Zigachev
dce_virtual_hpd_sense(struct amdgpu_device * adev,enum amdgpu_hpd_id hpd)72b843c749SSergey Zigachev static bool dce_virtual_hpd_sense(struct amdgpu_device *adev,
73b843c749SSergey Zigachev enum amdgpu_hpd_id hpd)
74b843c749SSergey Zigachev {
75b843c749SSergey Zigachev return true;
76b843c749SSergey Zigachev }
77b843c749SSergey Zigachev
dce_virtual_hpd_set_polarity(struct amdgpu_device * adev,enum amdgpu_hpd_id hpd)78b843c749SSergey Zigachev static void dce_virtual_hpd_set_polarity(struct amdgpu_device *adev,
79b843c749SSergey Zigachev enum amdgpu_hpd_id hpd)
80b843c749SSergey Zigachev {
81b843c749SSergey Zigachev return;
82b843c749SSergey Zigachev }
83b843c749SSergey Zigachev
dce_virtual_hpd_get_gpio_reg(struct amdgpu_device * adev)84b843c749SSergey Zigachev static u32 dce_virtual_hpd_get_gpio_reg(struct amdgpu_device *adev)
85b843c749SSergey Zigachev {
86b843c749SSergey Zigachev return 0;
87b843c749SSergey Zigachev }
88b843c749SSergey Zigachev
89b843c749SSergey Zigachev /**
90b843c749SSergey Zigachev * dce_virtual_bandwidth_update - program display watermarks
91b843c749SSergey Zigachev *
92b843c749SSergey Zigachev * @adev: amdgpu_device pointer
93b843c749SSergey Zigachev *
94b843c749SSergey Zigachev * Calculate and program the display watermarks and line
95b843c749SSergey Zigachev * buffer allocation (CIK).
96b843c749SSergey Zigachev */
dce_virtual_bandwidth_update(struct amdgpu_device * adev)97b843c749SSergey Zigachev static void dce_virtual_bandwidth_update(struct amdgpu_device *adev)
98b843c749SSergey Zigachev {
99b843c749SSergey Zigachev return;
100b843c749SSergey Zigachev }
101b843c749SSergey Zigachev
dce_virtual_crtc_gamma_set(struct drm_crtc * crtc,u16 * red,u16 * green,u16 * blue,uint32_t size,struct drm_modeset_acquire_ctx * ctx)102b843c749SSergey Zigachev static int dce_virtual_crtc_gamma_set(struct drm_crtc *crtc, u16 *red,
103b843c749SSergey Zigachev u16 *green, u16 *blue, uint32_t size,
104b843c749SSergey Zigachev struct drm_modeset_acquire_ctx *ctx)
105b843c749SSergey Zigachev {
106b843c749SSergey Zigachev return 0;
107b843c749SSergey Zigachev }
108b843c749SSergey Zigachev
dce_virtual_crtc_destroy(struct drm_crtc * crtc)109b843c749SSergey Zigachev static void dce_virtual_crtc_destroy(struct drm_crtc *crtc)
110b843c749SSergey Zigachev {
111b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
112b843c749SSergey Zigachev
113b843c749SSergey Zigachev drm_crtc_cleanup(crtc);
114b843c749SSergey Zigachev kfree(amdgpu_crtc);
115b843c749SSergey Zigachev }
116b843c749SSergey Zigachev
117b843c749SSergey Zigachev static const struct drm_crtc_funcs dce_virtual_crtc_funcs = {
118b843c749SSergey Zigachev .cursor_set2 = NULL,
119b843c749SSergey Zigachev .cursor_move = NULL,
120b843c749SSergey Zigachev .gamma_set = dce_virtual_crtc_gamma_set,
121b843c749SSergey Zigachev .set_config = amdgpu_display_crtc_set_config,
122b843c749SSergey Zigachev .destroy = dce_virtual_crtc_destroy,
123b843c749SSergey Zigachev .page_flip_target = amdgpu_display_crtc_page_flip_target,
124b843c749SSergey Zigachev };
125b843c749SSergey Zigachev
dce_virtual_crtc_dpms(struct drm_crtc * crtc,int mode)126b843c749SSergey Zigachev static void dce_virtual_crtc_dpms(struct drm_crtc *crtc, int mode)
127b843c749SSergey Zigachev {
128b843c749SSergey Zigachev struct drm_device *dev = crtc->dev;
129b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private;
130b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
131b843c749SSergey Zigachev unsigned type;
132b843c749SSergey Zigachev
133b843c749SSergey Zigachev if (amdgpu_sriov_vf(adev))
134b843c749SSergey Zigachev return;
135b843c749SSergey Zigachev
136b843c749SSergey Zigachev switch (mode) {
137b843c749SSergey Zigachev case DRM_MODE_DPMS_ON:
138b843c749SSergey Zigachev amdgpu_crtc->enabled = true;
139b843c749SSergey Zigachev /* Make sure VBLANK interrupts are still enabled */
140b843c749SSergey Zigachev type = amdgpu_display_crtc_idx_to_irq_type(adev,
141b843c749SSergey Zigachev amdgpu_crtc->crtc_id);
142b843c749SSergey Zigachev amdgpu_irq_update(adev, &adev->crtc_irq, type);
143b843c749SSergey Zigachev drm_crtc_vblank_on(crtc);
144b843c749SSergey Zigachev break;
145b843c749SSergey Zigachev case DRM_MODE_DPMS_STANDBY:
146b843c749SSergey Zigachev case DRM_MODE_DPMS_SUSPEND:
147b843c749SSergey Zigachev case DRM_MODE_DPMS_OFF:
148b843c749SSergey Zigachev drm_crtc_vblank_off(crtc);
149b843c749SSergey Zigachev amdgpu_crtc->enabled = false;
150b843c749SSergey Zigachev break;
151b843c749SSergey Zigachev }
152b843c749SSergey Zigachev }
153b843c749SSergey Zigachev
154b843c749SSergey Zigachev
dce_virtual_crtc_prepare(struct drm_crtc * crtc)155b843c749SSergey Zigachev static void dce_virtual_crtc_prepare(struct drm_crtc *crtc)
156b843c749SSergey Zigachev {
157b843c749SSergey Zigachev dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
158b843c749SSergey Zigachev }
159b843c749SSergey Zigachev
dce_virtual_crtc_commit(struct drm_crtc * crtc)160b843c749SSergey Zigachev static void dce_virtual_crtc_commit(struct drm_crtc *crtc)
161b843c749SSergey Zigachev {
162b843c749SSergey Zigachev dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
163b843c749SSergey Zigachev }
164b843c749SSergey Zigachev
dce_virtual_crtc_disable(struct drm_crtc * crtc)165b843c749SSergey Zigachev static void dce_virtual_crtc_disable(struct drm_crtc *crtc)
166b843c749SSergey Zigachev {
167b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
168b843c749SSergey Zigachev
169b843c749SSergey Zigachev dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
170b843c749SSergey Zigachev if (crtc->primary->fb) {
171b843c749SSergey Zigachev int r;
172b843c749SSergey Zigachev struct amdgpu_bo *abo;
173b843c749SSergey Zigachev
174b843c749SSergey Zigachev abo = gem_to_amdgpu_bo(crtc->primary->fb->obj[0]);
175b843c749SSergey Zigachev r = amdgpu_bo_reserve(abo, true);
176b843c749SSergey Zigachev if (unlikely(r))
177b843c749SSergey Zigachev DRM_ERROR("failed to reserve abo before unpin\n");
178b843c749SSergey Zigachev else {
179b843c749SSergey Zigachev amdgpu_bo_unpin(abo);
180b843c749SSergey Zigachev amdgpu_bo_unreserve(abo);
181b843c749SSergey Zigachev }
182b843c749SSergey Zigachev }
183b843c749SSergey Zigachev
184b843c749SSergey Zigachev amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
185b843c749SSergey Zigachev amdgpu_crtc->encoder = NULL;
186b843c749SSergey Zigachev amdgpu_crtc->connector = NULL;
187b843c749SSergey Zigachev }
188b843c749SSergey Zigachev
dce_virtual_crtc_mode_set(struct drm_crtc * crtc,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode,int x,int y,struct drm_framebuffer * old_fb)189b843c749SSergey Zigachev static int dce_virtual_crtc_mode_set(struct drm_crtc *crtc,
190b843c749SSergey Zigachev struct drm_display_mode *mode,
191b843c749SSergey Zigachev struct drm_display_mode *adjusted_mode,
192b843c749SSergey Zigachev int x, int y, struct drm_framebuffer *old_fb)
193b843c749SSergey Zigachev {
194b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
195b843c749SSergey Zigachev
196b843c749SSergey Zigachev /* update the hw version fpr dpm */
197b843c749SSergey Zigachev amdgpu_crtc->hw_mode = *adjusted_mode;
198b843c749SSergey Zigachev
199b843c749SSergey Zigachev return 0;
200b843c749SSergey Zigachev }
201b843c749SSergey Zigachev
dce_virtual_crtc_mode_fixup(struct drm_crtc * crtc,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)202b843c749SSergey Zigachev static bool dce_virtual_crtc_mode_fixup(struct drm_crtc *crtc,
203b843c749SSergey Zigachev const struct drm_display_mode *mode,
204b843c749SSergey Zigachev struct drm_display_mode *adjusted_mode)
205b843c749SSergey Zigachev {
206b843c749SSergey Zigachev return true;
207b843c749SSergey Zigachev }
208b843c749SSergey Zigachev
209b843c749SSergey Zigachev
dce_virtual_crtc_set_base(struct drm_crtc * crtc,int x,int y,struct drm_framebuffer * old_fb)210b843c749SSergey Zigachev static int dce_virtual_crtc_set_base(struct drm_crtc *crtc, int x, int y,
211b843c749SSergey Zigachev struct drm_framebuffer *old_fb)
212b843c749SSergey Zigachev {
213b843c749SSergey Zigachev return 0;
214b843c749SSergey Zigachev }
215b843c749SSergey Zigachev
dce_virtual_crtc_set_base_atomic(struct drm_crtc * crtc,struct drm_framebuffer * fb,int x,int y,enum mode_set_atomic state)216b843c749SSergey Zigachev static int dce_virtual_crtc_set_base_atomic(struct drm_crtc *crtc,
217b843c749SSergey Zigachev struct drm_framebuffer *fb,
218b843c749SSergey Zigachev int x, int y, enum mode_set_atomic state)
219b843c749SSergey Zigachev {
220b843c749SSergey Zigachev return 0;
221b843c749SSergey Zigachev }
222b843c749SSergey Zigachev
223b843c749SSergey Zigachev static const struct drm_crtc_helper_funcs dce_virtual_crtc_helper_funcs = {
224b843c749SSergey Zigachev .dpms = dce_virtual_crtc_dpms,
225b843c749SSergey Zigachev .mode_fixup = dce_virtual_crtc_mode_fixup,
226b843c749SSergey Zigachev .mode_set = dce_virtual_crtc_mode_set,
227b843c749SSergey Zigachev .mode_set_base = dce_virtual_crtc_set_base,
228b843c749SSergey Zigachev .mode_set_base_atomic = dce_virtual_crtc_set_base_atomic,
229b843c749SSergey Zigachev .prepare = dce_virtual_crtc_prepare,
230b843c749SSergey Zigachev .commit = dce_virtual_crtc_commit,
231b843c749SSergey Zigachev .disable = dce_virtual_crtc_disable,
232b843c749SSergey Zigachev };
233b843c749SSergey Zigachev
dce_virtual_crtc_init(struct amdgpu_device * adev,int index)234b843c749SSergey Zigachev static int dce_virtual_crtc_init(struct amdgpu_device *adev, int index)
235b843c749SSergey Zigachev {
236b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc;
237b843c749SSergey Zigachev
238b843c749SSergey Zigachev amdgpu_crtc = kzalloc(sizeof(struct amdgpu_crtc) +
239b843c749SSergey Zigachev (AMDGPUFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
240b843c749SSergey Zigachev if (amdgpu_crtc == NULL)
241b843c749SSergey Zigachev return -ENOMEM;
242b843c749SSergey Zigachev
243b843c749SSergey Zigachev drm_crtc_init(adev->ddev, &amdgpu_crtc->base, &dce_virtual_crtc_funcs);
244b843c749SSergey Zigachev
245b843c749SSergey Zigachev drm_mode_crtc_set_gamma_size(&amdgpu_crtc->base, 256);
246b843c749SSergey Zigachev amdgpu_crtc->crtc_id = index;
247b843c749SSergey Zigachev adev->mode_info.crtcs[index] = amdgpu_crtc;
248b843c749SSergey Zigachev
249b843c749SSergey Zigachev amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
250b843c749SSergey Zigachev amdgpu_crtc->encoder = NULL;
251b843c749SSergey Zigachev amdgpu_crtc->connector = NULL;
252b843c749SSergey Zigachev amdgpu_crtc->vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE;
253b843c749SSergey Zigachev drm_crtc_helper_add(&amdgpu_crtc->base, &dce_virtual_crtc_helper_funcs);
254b843c749SSergey Zigachev
255b843c749SSergey Zigachev return 0;
256b843c749SSergey Zigachev }
257b843c749SSergey Zigachev
dce_virtual_early_init(void * handle)258b843c749SSergey Zigachev static int dce_virtual_early_init(void *handle)
259b843c749SSergey Zigachev {
260b843c749SSergey Zigachev struct amdgpu_device *adev = (struct amdgpu_device *)handle;
261b843c749SSergey Zigachev
262b843c749SSergey Zigachev dce_virtual_set_display_funcs(adev);
263b843c749SSergey Zigachev dce_virtual_set_irq_funcs(adev);
264b843c749SSergey Zigachev
265b843c749SSergey Zigachev adev->mode_info.num_hpd = 1;
266b843c749SSergey Zigachev adev->mode_info.num_dig = 1;
267b843c749SSergey Zigachev return 0;
268b843c749SSergey Zigachev }
269b843c749SSergey Zigachev
270b843c749SSergey Zigachev static struct drm_encoder *
dce_virtual_encoder(struct drm_connector * connector)271b843c749SSergey Zigachev dce_virtual_encoder(struct drm_connector *connector)
272b843c749SSergey Zigachev {
273b843c749SSergey Zigachev struct drm_encoder *encoder;
274b843c749SSergey Zigachev int i;
275b843c749SSergey Zigachev
276b843c749SSergey Zigachev drm_connector_for_each_possible_encoder(connector, encoder, i) {
277b843c749SSergey Zigachev if (encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL)
278b843c749SSergey Zigachev return encoder;
279b843c749SSergey Zigachev }
280b843c749SSergey Zigachev
281b843c749SSergey Zigachev /* pick the first one */
282b843c749SSergey Zigachev drm_connector_for_each_possible_encoder(connector, encoder, i)
283b843c749SSergey Zigachev return encoder;
284b843c749SSergey Zigachev
285b843c749SSergey Zigachev return NULL;
286b843c749SSergey Zigachev }
287b843c749SSergey Zigachev
dce_virtual_get_modes(struct drm_connector * connector)288b843c749SSergey Zigachev static int dce_virtual_get_modes(struct drm_connector *connector)
289b843c749SSergey Zigachev {
290b843c749SSergey Zigachev struct drm_device *dev = connector->dev;
291b843c749SSergey Zigachev struct drm_display_mode *mode = NULL;
292b843c749SSergey Zigachev unsigned i;
293b843c749SSergey Zigachev static const struct mode_size {
294b843c749SSergey Zigachev int w;
295b843c749SSergey Zigachev int h;
296b843c749SSergey Zigachev } common_modes[17] = {
297b843c749SSergey Zigachev { 640, 480},
298b843c749SSergey Zigachev { 720, 480},
299b843c749SSergey Zigachev { 800, 600},
300b843c749SSergey Zigachev { 848, 480},
301b843c749SSergey Zigachev {1024, 768},
302b843c749SSergey Zigachev {1152, 768},
303b843c749SSergey Zigachev {1280, 720},
304b843c749SSergey Zigachev {1280, 800},
305b843c749SSergey Zigachev {1280, 854},
306b843c749SSergey Zigachev {1280, 960},
307b843c749SSergey Zigachev {1280, 1024},
308b843c749SSergey Zigachev {1440, 900},
309b843c749SSergey Zigachev {1400, 1050},
310b843c749SSergey Zigachev {1680, 1050},
311b843c749SSergey Zigachev {1600, 1200},
312b843c749SSergey Zigachev {1920, 1080},
313b843c749SSergey Zigachev {1920, 1200}
314b843c749SSergey Zigachev };
315b843c749SSergey Zigachev
316b843c749SSergey Zigachev for (i = 0; i < 17; i++) {
317b843c749SSergey Zigachev mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false);
318b843c749SSergey Zigachev drm_mode_probed_add(connector, mode);
319b843c749SSergey Zigachev }
320b843c749SSergey Zigachev
321b843c749SSergey Zigachev return 0;
322b843c749SSergey Zigachev }
323b843c749SSergey Zigachev
dce_virtual_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)324b843c749SSergey Zigachev static enum drm_mode_status dce_virtual_mode_valid(struct drm_connector *connector,
325b843c749SSergey Zigachev struct drm_display_mode *mode)
326b843c749SSergey Zigachev {
327b843c749SSergey Zigachev return MODE_OK;
328b843c749SSergey Zigachev }
329b843c749SSergey Zigachev
330b843c749SSergey Zigachev static int
dce_virtual_dpms(struct drm_connector * connector,int mode)331b843c749SSergey Zigachev dce_virtual_dpms(struct drm_connector *connector, int mode)
332b843c749SSergey Zigachev {
333b843c749SSergey Zigachev return 0;
334b843c749SSergey Zigachev }
335b843c749SSergey Zigachev
336b843c749SSergey Zigachev static int
dce_virtual_set_property(struct drm_connector * connector,struct drm_property * property,uint64_t val)337b843c749SSergey Zigachev dce_virtual_set_property(struct drm_connector *connector,
338b843c749SSergey Zigachev struct drm_property *property,
339b843c749SSergey Zigachev uint64_t val)
340b843c749SSergey Zigachev {
341b843c749SSergey Zigachev return 0;
342b843c749SSergey Zigachev }
343b843c749SSergey Zigachev
dce_virtual_destroy(struct drm_connector * connector)344b843c749SSergey Zigachev static void dce_virtual_destroy(struct drm_connector *connector)
345b843c749SSergey Zigachev {
346b843c749SSergey Zigachev drm_connector_unregister(connector);
347b843c749SSergey Zigachev drm_connector_cleanup(connector);
348b843c749SSergey Zigachev kfree(connector);
349b843c749SSergey Zigachev }
350b843c749SSergey Zigachev
dce_virtual_force(struct drm_connector * connector)351b843c749SSergey Zigachev static void dce_virtual_force(struct drm_connector *connector)
352b843c749SSergey Zigachev {
353b843c749SSergey Zigachev return;
354b843c749SSergey Zigachev }
355b843c749SSergey Zigachev
356b843c749SSergey Zigachev static const struct drm_connector_helper_funcs dce_virtual_connector_helper_funcs = {
357b843c749SSergey Zigachev .get_modes = dce_virtual_get_modes,
358b843c749SSergey Zigachev .mode_valid = dce_virtual_mode_valid,
359b843c749SSergey Zigachev .best_encoder = dce_virtual_encoder,
360b843c749SSergey Zigachev };
361b843c749SSergey Zigachev
362b843c749SSergey Zigachev static const struct drm_connector_funcs dce_virtual_connector_funcs = {
363b843c749SSergey Zigachev .dpms = dce_virtual_dpms,
364b843c749SSergey Zigachev .fill_modes = drm_helper_probe_single_connector_modes,
365b843c749SSergey Zigachev .set_property = dce_virtual_set_property,
366b843c749SSergey Zigachev .destroy = dce_virtual_destroy,
367b843c749SSergey Zigachev .force = dce_virtual_force,
368b843c749SSergey Zigachev };
369b843c749SSergey Zigachev
dce_virtual_sw_init(void * handle)370b843c749SSergey Zigachev static int dce_virtual_sw_init(void *handle)
371b843c749SSergey Zigachev {
372b843c749SSergey Zigachev int r, i;
373b843c749SSergey Zigachev struct amdgpu_device *adev = (struct amdgpu_device *)handle;
374b843c749SSergey Zigachev
375b843c749SSergey Zigachev r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_SMU_DISP_TIMER2_TRIGGER, &adev->crtc_irq);
376b843c749SSergey Zigachev if (r)
377b843c749SSergey Zigachev return r;
378b843c749SSergey Zigachev
379b843c749SSergey Zigachev adev->ddev->max_vblank_count = 0;
380b843c749SSergey Zigachev
381b843c749SSergey Zigachev adev->ddev->mode_config.funcs = &amdgpu_mode_funcs;
382b843c749SSergey Zigachev
383b843c749SSergey Zigachev adev->ddev->mode_config.max_width = 16384;
384b843c749SSergey Zigachev adev->ddev->mode_config.max_height = 16384;
385b843c749SSergey Zigachev
386b843c749SSergey Zigachev adev->ddev->mode_config.preferred_depth = 24;
387b843c749SSergey Zigachev adev->ddev->mode_config.prefer_shadow = 1;
388b843c749SSergey Zigachev
389b843c749SSergey Zigachev adev->ddev->mode_config.fb_base = adev->gmc.aper_base;
390b843c749SSergey Zigachev
391b843c749SSergey Zigachev r = amdgpu_display_modeset_create_props(adev);
392b843c749SSergey Zigachev if (r)
393b843c749SSergey Zigachev return r;
394b843c749SSergey Zigachev
395b843c749SSergey Zigachev adev->ddev->mode_config.max_width = 16384;
396b843c749SSergey Zigachev adev->ddev->mode_config.max_height = 16384;
397b843c749SSergey Zigachev
398b843c749SSergey Zigachev /* allocate crtcs, encoders, connectors */
399b843c749SSergey Zigachev for (i = 0; i < adev->mode_info.num_crtc; i++) {
400b843c749SSergey Zigachev r = dce_virtual_crtc_init(adev, i);
401b843c749SSergey Zigachev if (r)
402b843c749SSergey Zigachev return r;
403b843c749SSergey Zigachev r = dce_virtual_connector_encoder_init(adev, i);
404b843c749SSergey Zigachev if (r)
405b843c749SSergey Zigachev return r;
406b843c749SSergey Zigachev }
407b843c749SSergey Zigachev
408b843c749SSergey Zigachev drm_kms_helper_poll_init(adev->ddev);
409b843c749SSergey Zigachev
410b843c749SSergey Zigachev adev->mode_info.mode_config_initialized = true;
411b843c749SSergey Zigachev return 0;
412b843c749SSergey Zigachev }
413b843c749SSergey Zigachev
dce_virtual_sw_fini(void * handle)414b843c749SSergey Zigachev static int dce_virtual_sw_fini(void *handle)
415b843c749SSergey Zigachev {
416b843c749SSergey Zigachev struct amdgpu_device *adev = (struct amdgpu_device *)handle;
417b843c749SSergey Zigachev
418b843c749SSergey Zigachev kfree(adev->mode_info.bios_hardcoded_edid);
419b843c749SSergey Zigachev
420b843c749SSergey Zigachev drm_kms_helper_poll_fini(adev->ddev);
421b843c749SSergey Zigachev
422b843c749SSergey Zigachev drm_mode_config_cleanup(adev->ddev);
423b843c749SSergey Zigachev /* clear crtcs pointer to avoid dce irq finish routine access freed data */
424b843c749SSergey Zigachev memset(adev->mode_info.crtcs, 0, sizeof(adev->mode_info.crtcs[0]) * AMDGPU_MAX_CRTCS);
425b843c749SSergey Zigachev adev->mode_info.mode_config_initialized = false;
426b843c749SSergey Zigachev return 0;
427b843c749SSergey Zigachev }
428b843c749SSergey Zigachev
dce_virtual_hw_init(void * handle)429b843c749SSergey Zigachev static int dce_virtual_hw_init(void *handle)
430b843c749SSergey Zigachev {
431b843c749SSergey Zigachev struct amdgpu_device *adev = (struct amdgpu_device *)handle;
432b843c749SSergey Zigachev
433b843c749SSergey Zigachev switch (adev->asic_type) {
434b843c749SSergey Zigachev #ifdef CONFIG_DRM_AMDGPU_SI
435b843c749SSergey Zigachev case CHIP_TAHITI:
436b843c749SSergey Zigachev case CHIP_PITCAIRN:
437b843c749SSergey Zigachev case CHIP_VERDE:
438b843c749SSergey Zigachev case CHIP_OLAND:
439b843c749SSergey Zigachev dce_v6_0_disable_dce(adev);
440b843c749SSergey Zigachev break;
441b843c749SSergey Zigachev #endif
442b843c749SSergey Zigachev #ifdef CONFIG_DRM_AMDGPU_CIK
443b843c749SSergey Zigachev case CHIP_BONAIRE:
444b843c749SSergey Zigachev case CHIP_HAWAII:
445b843c749SSergey Zigachev case CHIP_KAVERI:
446b843c749SSergey Zigachev case CHIP_KABINI:
447b843c749SSergey Zigachev case CHIP_MULLINS:
448b843c749SSergey Zigachev dce_v8_0_disable_dce(adev);
449b843c749SSergey Zigachev break;
450b843c749SSergey Zigachev #endif
451b843c749SSergey Zigachev case CHIP_FIJI:
452b843c749SSergey Zigachev case CHIP_TONGA:
453b843c749SSergey Zigachev dce_v10_0_disable_dce(adev);
454b843c749SSergey Zigachev break;
455b843c749SSergey Zigachev case CHIP_CARRIZO:
456b843c749SSergey Zigachev case CHIP_STONEY:
457b843c749SSergey Zigachev case CHIP_POLARIS10:
458b843c749SSergey Zigachev case CHIP_POLARIS11:
459b843c749SSergey Zigachev case CHIP_VEGAM:
460b843c749SSergey Zigachev dce_v11_0_disable_dce(adev);
461b843c749SSergey Zigachev break;
462b843c749SSergey Zigachev case CHIP_TOPAZ:
463b843c749SSergey Zigachev #ifdef CONFIG_DRM_AMDGPU_SI
464b843c749SSergey Zigachev case CHIP_HAINAN:
465b843c749SSergey Zigachev #endif
466b843c749SSergey Zigachev /* no DCE */
467b843c749SSergey Zigachev break;
468b843c749SSergey Zigachev case CHIP_VEGA10:
469b843c749SSergey Zigachev case CHIP_VEGA12:
470b843c749SSergey Zigachev case CHIP_VEGA20:
471b843c749SSergey Zigachev break;
472b843c749SSergey Zigachev default:
473b843c749SSergey Zigachev DRM_ERROR("Virtual display unsupported ASIC type: 0x%X\n", adev->asic_type);
474b843c749SSergey Zigachev }
475b843c749SSergey Zigachev return 0;
476b843c749SSergey Zigachev }
477b843c749SSergey Zigachev
dce_virtual_hw_fini(void * handle)478b843c749SSergey Zigachev static int dce_virtual_hw_fini(void *handle)
479b843c749SSergey Zigachev {
480b843c749SSergey Zigachev struct amdgpu_device *adev = (struct amdgpu_device *)handle;
481b843c749SSergey Zigachev int i = 0;
482b843c749SSergey Zigachev
483b843c749SSergey Zigachev for (i = 0; i<adev->mode_info.num_crtc; i++)
484b843c749SSergey Zigachev if (adev->mode_info.crtcs[i])
485b843c749SSergey Zigachev dce_virtual_set_crtc_vblank_interrupt_state(adev, i, AMDGPU_IRQ_STATE_DISABLE);
486b843c749SSergey Zigachev
487b843c749SSergey Zigachev return 0;
488b843c749SSergey Zigachev }
489b843c749SSergey Zigachev
dce_virtual_suspend(void * handle)490b843c749SSergey Zigachev static int dce_virtual_suspend(void *handle)
491b843c749SSergey Zigachev {
492b843c749SSergey Zigachev return dce_virtual_hw_fini(handle);
493b843c749SSergey Zigachev }
494b843c749SSergey Zigachev
dce_virtual_resume(void * handle)495b843c749SSergey Zigachev static int dce_virtual_resume(void *handle)
496b843c749SSergey Zigachev {
497b843c749SSergey Zigachev return dce_virtual_hw_init(handle);
498b843c749SSergey Zigachev }
499b843c749SSergey Zigachev
dce_virtual_is_idle(void * handle)500b843c749SSergey Zigachev static bool dce_virtual_is_idle(void *handle)
501b843c749SSergey Zigachev {
502b843c749SSergey Zigachev return true;
503b843c749SSergey Zigachev }
504b843c749SSergey Zigachev
dce_virtual_wait_for_idle(void * handle)505b843c749SSergey Zigachev static int dce_virtual_wait_for_idle(void *handle)
506b843c749SSergey Zigachev {
507b843c749SSergey Zigachev return 0;
508b843c749SSergey Zigachev }
509b843c749SSergey Zigachev
dce_virtual_soft_reset(void * handle)510b843c749SSergey Zigachev static int dce_virtual_soft_reset(void *handle)
511b843c749SSergey Zigachev {
512b843c749SSergey Zigachev return 0;
513b843c749SSergey Zigachev }
514b843c749SSergey Zigachev
dce_virtual_set_clockgating_state(void * handle,enum amd_clockgating_state state)515b843c749SSergey Zigachev static int dce_virtual_set_clockgating_state(void *handle,
516b843c749SSergey Zigachev enum amd_clockgating_state state)
517b843c749SSergey Zigachev {
518b843c749SSergey Zigachev return 0;
519b843c749SSergey Zigachev }
520b843c749SSergey Zigachev
dce_virtual_set_powergating_state(void * handle,enum amd_powergating_state state)521b843c749SSergey Zigachev static int dce_virtual_set_powergating_state(void *handle,
522b843c749SSergey Zigachev enum amd_powergating_state state)
523b843c749SSergey Zigachev {
524b843c749SSergey Zigachev return 0;
525b843c749SSergey Zigachev }
526b843c749SSergey Zigachev
527b843c749SSergey Zigachev static const struct amd_ip_funcs dce_virtual_ip_funcs = {
528b843c749SSergey Zigachev .name = "dce_virtual",
529b843c749SSergey Zigachev .early_init = dce_virtual_early_init,
530b843c749SSergey Zigachev .late_init = NULL,
531b843c749SSergey Zigachev .sw_init = dce_virtual_sw_init,
532b843c749SSergey Zigachev .sw_fini = dce_virtual_sw_fini,
533b843c749SSergey Zigachev .hw_init = dce_virtual_hw_init,
534b843c749SSergey Zigachev .hw_fini = dce_virtual_hw_fini,
535b843c749SSergey Zigachev .suspend = dce_virtual_suspend,
536b843c749SSergey Zigachev .resume = dce_virtual_resume,
537b843c749SSergey Zigachev .is_idle = dce_virtual_is_idle,
538b843c749SSergey Zigachev .wait_for_idle = dce_virtual_wait_for_idle,
539b843c749SSergey Zigachev .soft_reset = dce_virtual_soft_reset,
540b843c749SSergey Zigachev .set_clockgating_state = dce_virtual_set_clockgating_state,
541b843c749SSergey Zigachev .set_powergating_state = dce_virtual_set_powergating_state,
542b843c749SSergey Zigachev };
543b843c749SSergey Zigachev
544b843c749SSergey Zigachev /* these are handled by the primary encoders */
dce_virtual_encoder_prepare(struct drm_encoder * encoder)545b843c749SSergey Zigachev static void dce_virtual_encoder_prepare(struct drm_encoder *encoder)
546b843c749SSergey Zigachev {
547b843c749SSergey Zigachev return;
548b843c749SSergey Zigachev }
549b843c749SSergey Zigachev
dce_virtual_encoder_commit(struct drm_encoder * encoder)550b843c749SSergey Zigachev static void dce_virtual_encoder_commit(struct drm_encoder *encoder)
551b843c749SSergey Zigachev {
552b843c749SSergey Zigachev return;
553b843c749SSergey Zigachev }
554b843c749SSergey Zigachev
555b843c749SSergey Zigachev static void
dce_virtual_encoder_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)556b843c749SSergey Zigachev dce_virtual_encoder_mode_set(struct drm_encoder *encoder,
557b843c749SSergey Zigachev struct drm_display_mode *mode,
558b843c749SSergey Zigachev struct drm_display_mode *adjusted_mode)
559b843c749SSergey Zigachev {
560b843c749SSergey Zigachev return;
561b843c749SSergey Zigachev }
562b843c749SSergey Zigachev
dce_virtual_encoder_disable(struct drm_encoder * encoder)563b843c749SSergey Zigachev static void dce_virtual_encoder_disable(struct drm_encoder *encoder)
564b843c749SSergey Zigachev {
565b843c749SSergey Zigachev return;
566b843c749SSergey Zigachev }
567b843c749SSergey Zigachev
568b843c749SSergey Zigachev static void
dce_virtual_encoder_dpms(struct drm_encoder * encoder,int mode)569b843c749SSergey Zigachev dce_virtual_encoder_dpms(struct drm_encoder *encoder, int mode)
570b843c749SSergey Zigachev {
571b843c749SSergey Zigachev return;
572b843c749SSergey Zigachev }
573b843c749SSergey Zigachev
dce_virtual_encoder_mode_fixup(struct drm_encoder * encoder,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)574b843c749SSergey Zigachev static bool dce_virtual_encoder_mode_fixup(struct drm_encoder *encoder,
575b843c749SSergey Zigachev const struct drm_display_mode *mode,
576b843c749SSergey Zigachev struct drm_display_mode *adjusted_mode)
577b843c749SSergey Zigachev {
578b843c749SSergey Zigachev return true;
579b843c749SSergey Zigachev }
580b843c749SSergey Zigachev
581b843c749SSergey Zigachev static const struct drm_encoder_helper_funcs dce_virtual_encoder_helper_funcs = {
582b843c749SSergey Zigachev .dpms = dce_virtual_encoder_dpms,
583b843c749SSergey Zigachev .mode_fixup = dce_virtual_encoder_mode_fixup,
584b843c749SSergey Zigachev .prepare = dce_virtual_encoder_prepare,
585b843c749SSergey Zigachev .mode_set = dce_virtual_encoder_mode_set,
586b843c749SSergey Zigachev .commit = dce_virtual_encoder_commit,
587b843c749SSergey Zigachev .disable = dce_virtual_encoder_disable,
588b843c749SSergey Zigachev };
589b843c749SSergey Zigachev
dce_virtual_encoder_destroy(struct drm_encoder * encoder)590b843c749SSergey Zigachev static void dce_virtual_encoder_destroy(struct drm_encoder *encoder)
591b843c749SSergey Zigachev {
592b843c749SSergey Zigachev drm_encoder_cleanup(encoder);
593b843c749SSergey Zigachev kfree(encoder);
594b843c749SSergey Zigachev }
595b843c749SSergey Zigachev
596b843c749SSergey Zigachev static const struct drm_encoder_funcs dce_virtual_encoder_funcs = {
597b843c749SSergey Zigachev .destroy = dce_virtual_encoder_destroy,
598b843c749SSergey Zigachev };
599b843c749SSergey Zigachev
dce_virtual_connector_encoder_init(struct amdgpu_device * adev,int index)600b843c749SSergey Zigachev static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev,
601b843c749SSergey Zigachev int index)
602b843c749SSergey Zigachev {
603b843c749SSergey Zigachev struct drm_encoder *encoder;
604b843c749SSergey Zigachev struct drm_connector *connector;
605b843c749SSergey Zigachev
606b843c749SSergey Zigachev /* add a new encoder */
607b843c749SSergey Zigachev encoder = kzalloc(sizeof(struct drm_encoder), GFP_KERNEL);
608b843c749SSergey Zigachev if (!encoder)
609b843c749SSergey Zigachev return -ENOMEM;
610b843c749SSergey Zigachev encoder->possible_crtcs = 1 << index;
611b843c749SSergey Zigachev drm_encoder_init(adev->ddev, encoder, &dce_virtual_encoder_funcs,
612b843c749SSergey Zigachev DRM_MODE_ENCODER_VIRTUAL, NULL);
613b843c749SSergey Zigachev drm_encoder_helper_add(encoder, &dce_virtual_encoder_helper_funcs);
614b843c749SSergey Zigachev
615b843c749SSergey Zigachev connector = kzalloc(sizeof(struct drm_connector), GFP_KERNEL);
616b843c749SSergey Zigachev if (!connector) {
617b843c749SSergey Zigachev kfree(encoder);
618b843c749SSergey Zigachev return -ENOMEM;
619b843c749SSergey Zigachev }
620b843c749SSergey Zigachev
621b843c749SSergey Zigachev /* add a new connector */
622b843c749SSergey Zigachev drm_connector_init(adev->ddev, connector, &dce_virtual_connector_funcs,
623b843c749SSergey Zigachev DRM_MODE_CONNECTOR_VIRTUAL);
624b843c749SSergey Zigachev drm_connector_helper_add(connector, &dce_virtual_connector_helper_funcs);
625b843c749SSergey Zigachev connector->display_info.subpixel_order = SubPixelHorizontalRGB;
626b843c749SSergey Zigachev connector->interlace_allowed = false;
627b843c749SSergey Zigachev connector->doublescan_allowed = false;
628b843c749SSergey Zigachev drm_connector_register(connector);
629b843c749SSergey Zigachev
630b843c749SSergey Zigachev /* link them */
631*78973132SSergey Zigachev drm_mode_connector_attach_encoder(connector, encoder);
632b843c749SSergey Zigachev
633b843c749SSergey Zigachev return 0;
634b843c749SSergey Zigachev }
635b843c749SSergey Zigachev
636b843c749SSergey Zigachev static const struct amdgpu_display_funcs dce_virtual_display_funcs = {
637b843c749SSergey Zigachev .bandwidth_update = &dce_virtual_bandwidth_update,
638b843c749SSergey Zigachev .vblank_get_counter = &dce_virtual_vblank_get_counter,
639b843c749SSergey Zigachev .backlight_set_level = NULL,
640b843c749SSergey Zigachev .backlight_get_level = NULL,
641b843c749SSergey Zigachev .hpd_sense = &dce_virtual_hpd_sense,
642b843c749SSergey Zigachev .hpd_set_polarity = &dce_virtual_hpd_set_polarity,
643b843c749SSergey Zigachev .hpd_get_gpio_reg = &dce_virtual_hpd_get_gpio_reg,
644b843c749SSergey Zigachev .page_flip = &dce_virtual_page_flip,
645b843c749SSergey Zigachev .page_flip_get_scanoutpos = &dce_virtual_crtc_get_scanoutpos,
646b843c749SSergey Zigachev .add_encoder = NULL,
647b843c749SSergey Zigachev .add_connector = NULL,
648b843c749SSergey Zigachev };
649b843c749SSergey Zigachev
dce_virtual_set_display_funcs(struct amdgpu_device * adev)650b843c749SSergey Zigachev static void dce_virtual_set_display_funcs(struct amdgpu_device *adev)
651b843c749SSergey Zigachev {
652b843c749SSergey Zigachev if (adev->mode_info.funcs == NULL)
653b843c749SSergey Zigachev adev->mode_info.funcs = &dce_virtual_display_funcs;
654b843c749SSergey Zigachev }
655b843c749SSergey Zigachev
dce_virtual_pageflip(struct amdgpu_device * adev,unsigned crtc_id)656b843c749SSergey Zigachev static int dce_virtual_pageflip(struct amdgpu_device *adev,
657b843c749SSergey Zigachev unsigned crtc_id)
658b843c749SSergey Zigachev {
659b843c749SSergey Zigachev unsigned long flags;
660b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc;
661b843c749SSergey Zigachev struct amdgpu_flip_work *works;
662b843c749SSergey Zigachev
663b843c749SSergey Zigachev amdgpu_crtc = adev->mode_info.crtcs[crtc_id];
664b843c749SSergey Zigachev
665b843c749SSergey Zigachev if (crtc_id >= adev->mode_info.num_crtc) {
666b843c749SSergey Zigachev DRM_ERROR("invalid pageflip crtc %d\n", crtc_id);
667b843c749SSergey Zigachev return -EINVAL;
668b843c749SSergey Zigachev }
669b843c749SSergey Zigachev
670b843c749SSergey Zigachev /* IRQ could occur when in initial stage */
671b843c749SSergey Zigachev if (amdgpu_crtc == NULL)
672b843c749SSergey Zigachev return 0;
673b843c749SSergey Zigachev
674b843c749SSergey Zigachev spin_lock_irqsave(&adev->ddev->event_lock, flags);
675b843c749SSergey Zigachev works = amdgpu_crtc->pflip_works;
676b843c749SSergey Zigachev if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) {
677b843c749SSergey Zigachev DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d != "
678b843c749SSergey Zigachev "AMDGPU_FLIP_SUBMITTED(%d)\n",
679b843c749SSergey Zigachev amdgpu_crtc->pflip_status,
680b843c749SSergey Zigachev AMDGPU_FLIP_SUBMITTED);
681b843c749SSergey Zigachev spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
682b843c749SSergey Zigachev return 0;
683b843c749SSergey Zigachev }
684b843c749SSergey Zigachev
685b843c749SSergey Zigachev /* page flip completed. clean up */
686b843c749SSergey Zigachev amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE;
687b843c749SSergey Zigachev amdgpu_crtc->pflip_works = NULL;
688b843c749SSergey Zigachev
689b843c749SSergey Zigachev /* wakeup usersapce */
690b843c749SSergey Zigachev if (works->event)
691b843c749SSergey Zigachev drm_crtc_send_vblank_event(&amdgpu_crtc->base, works->event);
692b843c749SSergey Zigachev
693b843c749SSergey Zigachev spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
694b843c749SSergey Zigachev
695b843c749SSergey Zigachev drm_crtc_vblank_put(&amdgpu_crtc->base);
696b843c749SSergey Zigachev schedule_work(&works->unpin_work);
697b843c749SSergey Zigachev
698b843c749SSergey Zigachev return 0;
699b843c749SSergey Zigachev }
700b843c749SSergey Zigachev
dce_virtual_vblank_timer_handle(struct hrtimer * vblank_timer)701b843c749SSergey Zigachev static enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vblank_timer)
702b843c749SSergey Zigachev {
703b843c749SSergey Zigachev struct amdgpu_crtc *amdgpu_crtc = container_of(vblank_timer,
704b843c749SSergey Zigachev struct amdgpu_crtc, vblank_timer);
705b843c749SSergey Zigachev struct drm_device *ddev = amdgpu_crtc->base.dev;
706b843c749SSergey Zigachev struct amdgpu_device *adev = ddev->dev_private;
707b843c749SSergey Zigachev
708b843c749SSergey Zigachev drm_handle_vblank(ddev, amdgpu_crtc->crtc_id);
709b843c749SSergey Zigachev dce_virtual_pageflip(adev, amdgpu_crtc->crtc_id);
710b843c749SSergey Zigachev hrtimer_start(vblank_timer, DCE_VIRTUAL_VBLANK_PERIOD,
711b843c749SSergey Zigachev HRTIMER_MODE_REL);
712b843c749SSergey Zigachev
713b843c749SSergey Zigachev return HRTIMER_NORESTART;
714b843c749SSergey Zigachev }
715b843c749SSergey Zigachev
dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device * adev,int crtc,enum amdgpu_interrupt_state state)716b843c749SSergey Zigachev static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev,
717b843c749SSergey Zigachev int crtc,
718b843c749SSergey Zigachev enum amdgpu_interrupt_state state)
719b843c749SSergey Zigachev {
720b843c749SSergey Zigachev if (crtc >= adev->mode_info.num_crtc || !adev->mode_info.crtcs[crtc]) {
721b843c749SSergey Zigachev DRM_DEBUG("invalid crtc %d\n", crtc);
722b843c749SSergey Zigachev return;
723b843c749SSergey Zigachev }
724b843c749SSergey Zigachev
725b843c749SSergey Zigachev if (state && !adev->mode_info.crtcs[crtc]->vsync_timer_enabled) {
726b843c749SSergey Zigachev DRM_DEBUG("Enable software vsync timer\n");
727b843c749SSergey Zigachev hrtimer_init(&adev->mode_info.crtcs[crtc]->vblank_timer,
728b843c749SSergey Zigachev CLOCK_MONOTONIC, HRTIMER_MODE_REL);
729b843c749SSergey Zigachev hrtimer_set_expires(&adev->mode_info.crtcs[crtc]->vblank_timer,
730b843c749SSergey Zigachev DCE_VIRTUAL_VBLANK_PERIOD);
731b843c749SSergey Zigachev adev->mode_info.crtcs[crtc]->vblank_timer.function =
732b843c749SSergey Zigachev dce_virtual_vblank_timer_handle;
733b843c749SSergey Zigachev hrtimer_start(&adev->mode_info.crtcs[crtc]->vblank_timer,
734b843c749SSergey Zigachev DCE_VIRTUAL_VBLANK_PERIOD, HRTIMER_MODE_REL);
735b843c749SSergey Zigachev } else if (!state && adev->mode_info.crtcs[crtc]->vsync_timer_enabled) {
736b843c749SSergey Zigachev DRM_DEBUG("Disable software vsync timer\n");
737b843c749SSergey Zigachev hrtimer_cancel(&adev->mode_info.crtcs[crtc]->vblank_timer);
738b843c749SSergey Zigachev }
739b843c749SSergey Zigachev
740b843c749SSergey Zigachev adev->mode_info.crtcs[crtc]->vsync_timer_enabled = state;
741b843c749SSergey Zigachev DRM_DEBUG("[FM]set crtc %d vblank interrupt state %d\n", crtc, state);
742b843c749SSergey Zigachev }
743b843c749SSergey Zigachev
744b843c749SSergey Zigachev
dce_virtual_set_crtc_irq_state(struct amdgpu_device * adev,struct amdgpu_irq_src * source,unsigned type,enum amdgpu_interrupt_state state)745b843c749SSergey Zigachev static int dce_virtual_set_crtc_irq_state(struct amdgpu_device *adev,
746b843c749SSergey Zigachev struct amdgpu_irq_src *source,
747b843c749SSergey Zigachev unsigned type,
748b843c749SSergey Zigachev enum amdgpu_interrupt_state state)
749b843c749SSergey Zigachev {
750b843c749SSergey Zigachev if (type > AMDGPU_CRTC_IRQ_VBLANK6)
751b843c749SSergey Zigachev return -EINVAL;
752b843c749SSergey Zigachev
753b843c749SSergey Zigachev dce_virtual_set_crtc_vblank_interrupt_state(adev, type, state);
754b843c749SSergey Zigachev
755b843c749SSergey Zigachev return 0;
756b843c749SSergey Zigachev }
757b843c749SSergey Zigachev
758b843c749SSergey Zigachev static const struct amdgpu_irq_src_funcs dce_virtual_crtc_irq_funcs = {
759b843c749SSergey Zigachev .set = dce_virtual_set_crtc_irq_state,
760b843c749SSergey Zigachev .process = NULL,
761b843c749SSergey Zigachev };
762b843c749SSergey Zigachev
dce_virtual_set_irq_funcs(struct amdgpu_device * adev)763b843c749SSergey Zigachev static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev)
764b843c749SSergey Zigachev {
765b843c749SSergey Zigachev adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_VBLANK6 + 1;
766b843c749SSergey Zigachev adev->crtc_irq.funcs = &dce_virtual_crtc_irq_funcs;
767b843c749SSergey Zigachev }
768b843c749SSergey Zigachev
769b843c749SSergey Zigachev const struct amdgpu_ip_block_version dce_virtual_ip_block =
770b843c749SSergey Zigachev {
771b843c749SSergey Zigachev .type = AMD_IP_BLOCK_TYPE_DCE,
772b843c749SSergey Zigachev .major = 1,
773b843c749SSergey Zigachev .minor = 0,
774b843c749SSergey Zigachev .rev = 0,
775b843c749SSergey Zigachev .funcs = &dce_virtual_ip_funcs,
776b843c749SSergey Zigachev };
777