blob: 788c0231d193ed5933fb22506e84c4ca20ee20d4 [file] [log] [blame]
Emily Dengc6e14f42016-08-08 11:30:50 +08001/*
2 * Copyright 2014 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 */
23#include "drmP.h"
24#include "amdgpu.h"
25#include "amdgpu_pm.h"
26#include "amdgpu_i2c.h"
27#include "atom.h"
Emily Dengc6e14f42016-08-08 11:30:50 +080028#include "amdgpu_pll.h"
29#include "amdgpu_connectors.h"
Alex Deuchera1d37042016-09-29 23:36:12 -040030#ifdef CONFIG_DRM_AMDGPU_SI
31#include "dce_v6_0.h"
32#endif
Emily Deng83c9b022016-08-08 11:33:11 +080033#ifdef CONFIG_DRM_AMDGPU_CIK
34#include "dce_v8_0.h"
35#endif
36#include "dce_v10_0.h"
37#include "dce_v11_0.h"
Emily Deng46ac3622016-08-08 11:35:39 +080038#include "dce_virtual.h"
Emily Dengc6e14f42016-08-08 11:30:50 +080039
Alex Deucher623fea12016-10-13 17:36:46 -040040#define DCE_VIRTUAL_VBLANK_PERIOD 16666666
41
42
Emily Dengc6e14f42016-08-08 11:30:50 +080043static void dce_virtual_set_display_funcs(struct amdgpu_device *adev);
44static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev);
Alex Deucher66264ba2016-09-30 12:37:36 -040045static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev,
46 int index);
Emily Dengc6e14f42016-08-08 11:30:50 +080047
Emily Deng8e6de752016-08-08 11:31:13 +080048/**
49 * dce_virtual_vblank_wait - vblank wait asic callback.
50 *
51 * @adev: amdgpu_device pointer
52 * @crtc: crtc to wait for vblank on
53 *
54 * Wait for vblank on the requested crtc (evergreen+).
55 */
56static void dce_virtual_vblank_wait(struct amdgpu_device *adev, int crtc)
57{
58 return;
59}
60
61static u32 dce_virtual_vblank_get_counter(struct amdgpu_device *adev, int crtc)
62{
Emily Deng041aa652016-08-17 14:59:20 +080063 return 0;
Emily Deng8e6de752016-08-08 11:31:13 +080064}
65
66static void dce_virtual_page_flip(struct amdgpu_device *adev,
67 int crtc_id, u64 crtc_base, bool async)
68{
69 return;
70}
71
72static int dce_virtual_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
73 u32 *vbl, u32 *position)
74{
Emily Deng8e6de752016-08-08 11:31:13 +080075 *vbl = 0;
76 *position = 0;
77
Emily Deng041aa652016-08-17 14:59:20 +080078 return -EINVAL;
Emily Deng8e6de752016-08-08 11:31:13 +080079}
80
81static bool dce_virtual_hpd_sense(struct amdgpu_device *adev,
82 enum amdgpu_hpd_id hpd)
83{
84 return true;
85}
86
87static void dce_virtual_hpd_set_polarity(struct amdgpu_device *adev,
88 enum amdgpu_hpd_id hpd)
89{
90 return;
91}
92
93static u32 dce_virtual_hpd_get_gpio_reg(struct amdgpu_device *adev)
94{
95 return 0;
96}
97
Baoyou Xie4d446652016-09-18 22:09:35 +080098static void dce_virtual_stop_mc_access(struct amdgpu_device *adev,
Emily Deng8e6de752016-08-08 11:31:13 +080099 struct amdgpu_mode_mc_save *save)
100{
Emily Deng83c9b022016-08-08 11:33:11 +0800101 switch (adev->asic_type) {
Alex Deuchera1d37042016-09-29 23:36:12 -0400102#ifdef CONFIG_DRM_AMDGPU_SI
103 case CHIP_TAHITI:
104 case CHIP_PITCAIRN:
105 case CHIP_VERDE:
106 case CHIP_OLAND:
107 dce_v6_0_disable_dce(adev);
108 break;
109#endif
Alex Deucher8cb619d2016-09-29 23:20:29 -0400110#ifdef CONFIG_DRM_AMDGPU_CIK
Emily Deng83c9b022016-08-08 11:33:11 +0800111 case CHIP_BONAIRE:
112 case CHIP_HAWAII:
113 case CHIP_KAVERI:
114 case CHIP_KABINI:
115 case CHIP_MULLINS:
Emily Deng83c9b022016-08-08 11:33:11 +0800116 dce_v8_0_disable_dce(adev);
Emily Deng83c9b022016-08-08 11:33:11 +0800117 break;
Alex Deucher8cb619d2016-09-29 23:20:29 -0400118#endif
Emily Deng83c9b022016-08-08 11:33:11 +0800119 case CHIP_FIJI:
120 case CHIP_TONGA:
121 dce_v10_0_disable_dce(adev);
122 break;
123 case CHIP_CARRIZO:
124 case CHIP_STONEY:
Emily Deng83c9b022016-08-08 11:33:11 +0800125 case CHIP_POLARIS10:
Alex Deucher2fc53382017-03-03 12:57:37 -0500126 case CHIP_POLARIS11:
127 case CHIP_POLARIS12:
Emily Deng83c9b022016-08-08 11:33:11 +0800128 dce_v11_0_disable_dce(adev);
129 break;
Alex Deucher2579de42016-08-08 14:40:04 -0400130 case CHIP_TOPAZ:
Alex Deuchera1d37042016-09-29 23:36:12 -0400131#ifdef CONFIG_DRM_AMDGPU_SI
132 case CHIP_HAINAN:
133#endif
Alex Deucher2579de42016-08-08 14:40:04 -0400134 /* no DCE */
135 return;
Emily Deng83c9b022016-08-08 11:33:11 +0800136 default:
Alex Deucher2579de42016-08-08 14:40:04 -0400137 DRM_ERROR("Virtual display unsupported ASIC type: 0x%X\n", adev->asic_type);
Emily Deng83c9b022016-08-08 11:33:11 +0800138 }
139
Emily Deng8e6de752016-08-08 11:31:13 +0800140 return;
141}
Baoyou Xie4d446652016-09-18 22:09:35 +0800142static void dce_virtual_resume_mc_access(struct amdgpu_device *adev,
Emily Deng8e6de752016-08-08 11:31:13 +0800143 struct amdgpu_mode_mc_save *save)
144{
145 return;
146}
147
Baoyou Xie4d446652016-09-18 22:09:35 +0800148static void dce_virtual_set_vga_render_state(struct amdgpu_device *adev,
Emily Deng8e6de752016-08-08 11:31:13 +0800149 bool render)
150{
151 return;
152}
153
154/**
155 * dce_virtual_bandwidth_update - program display watermarks
156 *
157 * @adev: amdgpu_device pointer
158 *
159 * Calculate and program the display watermarks and line
160 * buffer allocation (CIK).
161 */
162static void dce_virtual_bandwidth_update(struct amdgpu_device *adev)
163{
164 return;
165}
166
Emily Deng0d43f3b2016-08-08 11:32:22 +0800167static int dce_virtual_crtc_gamma_set(struct drm_crtc *crtc, u16 *red,
168 u16 *green, u16 *blue, uint32_t size)
169{
170 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
171 int i;
172
173 /* userspace palettes are always correct as is */
174 for (i = 0; i < size; i++) {
175 amdgpu_crtc->lut_r[i] = red[i] >> 6;
176 amdgpu_crtc->lut_g[i] = green[i] >> 6;
177 amdgpu_crtc->lut_b[i] = blue[i] >> 6;
178 }
179
180 return 0;
181}
182
183static void dce_virtual_crtc_destroy(struct drm_crtc *crtc)
184{
185 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
186
187 drm_crtc_cleanup(crtc);
188 kfree(amdgpu_crtc);
189}
190
Emily Dengc6e14f42016-08-08 11:30:50 +0800191static const struct drm_crtc_funcs dce_virtual_crtc_funcs = {
192 .cursor_set2 = NULL,
193 .cursor_move = NULL,
Emily Deng0d43f3b2016-08-08 11:32:22 +0800194 .gamma_set = dce_virtual_crtc_gamma_set,
195 .set_config = amdgpu_crtc_set_config,
196 .destroy = dce_virtual_crtc_destroy,
Michel Dänzer325cbba2016-08-04 12:39:37 +0900197 .page_flip_target = amdgpu_crtc_page_flip_target,
Emily Dengc6e14f42016-08-08 11:30:50 +0800198};
199
Emily Dengf1f5ef92016-08-08 11:32:00 +0800200static void dce_virtual_crtc_dpms(struct drm_crtc *crtc, int mode)
201{
202 struct drm_device *dev = crtc->dev;
203 struct amdgpu_device *adev = dev->dev_private;
204 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
205 unsigned type;
206
207 switch (mode) {
208 case DRM_MODE_DPMS_ON:
209 amdgpu_crtc->enabled = true;
Alex Deucher82b9f812016-09-30 11:19:41 -0400210 /* Make sure VBLANK interrupts are still enabled */
Emily Dengf1f5ef92016-08-08 11:32:00 +0800211 type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id);
212 amdgpu_irq_update(adev, &adev->crtc_irq, type);
Daniel Vetter2d1e3312016-11-14 10:02:54 +0100213 drm_crtc_vblank_on(crtc);
Emily Dengf1f5ef92016-08-08 11:32:00 +0800214 break;
215 case DRM_MODE_DPMS_STANDBY:
216 case DRM_MODE_DPMS_SUSPEND:
217 case DRM_MODE_DPMS_OFF:
Daniel Vetter2d1e3312016-11-14 10:02:54 +0100218 drm_crtc_vblank_off(crtc);
Emily Dengf1f5ef92016-08-08 11:32:00 +0800219 amdgpu_crtc->enabled = false;
220 break;
221 }
222}
223
224
225static void dce_virtual_crtc_prepare(struct drm_crtc *crtc)
226{
227 dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
228}
229
230static void dce_virtual_crtc_commit(struct drm_crtc *crtc)
231{
232 dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
233}
234
235static void dce_virtual_crtc_disable(struct drm_crtc *crtc)
236{
237 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
238
239 dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
240 if (crtc->primary->fb) {
241 int r;
242 struct amdgpu_framebuffer *amdgpu_fb;
Christian König765e7fb2016-09-15 15:06:50 +0200243 struct amdgpu_bo *abo;
Emily Dengf1f5ef92016-08-08 11:32:00 +0800244
245 amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb);
Christian König765e7fb2016-09-15 15:06:50 +0200246 abo = gem_to_amdgpu_bo(amdgpu_fb->obj);
247 r = amdgpu_bo_reserve(abo, false);
Emily Dengf1f5ef92016-08-08 11:32:00 +0800248 if (unlikely(r))
Christian König765e7fb2016-09-15 15:06:50 +0200249 DRM_ERROR("failed to reserve abo before unpin\n");
Emily Dengf1f5ef92016-08-08 11:32:00 +0800250 else {
Christian König765e7fb2016-09-15 15:06:50 +0200251 amdgpu_bo_unpin(abo);
252 amdgpu_bo_unreserve(abo);
Emily Dengf1f5ef92016-08-08 11:32:00 +0800253 }
254 }
255
256 amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
257 amdgpu_crtc->encoder = NULL;
258 amdgpu_crtc->connector = NULL;
259}
260
261static int dce_virtual_crtc_mode_set(struct drm_crtc *crtc,
262 struct drm_display_mode *mode,
263 struct drm_display_mode *adjusted_mode,
264 int x, int y, struct drm_framebuffer *old_fb)
265{
266 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
267
268 /* update the hw version fpr dpm */
269 amdgpu_crtc->hw_mode = *adjusted_mode;
270
271 return 0;
272}
273
274static bool dce_virtual_crtc_mode_fixup(struct drm_crtc *crtc,
275 const struct drm_display_mode *mode,
276 struct drm_display_mode *adjusted_mode)
277{
Emily Dengf1f5ef92016-08-08 11:32:00 +0800278 return true;
279}
280
281
282static int dce_virtual_crtc_set_base(struct drm_crtc *crtc, int x, int y,
283 struct drm_framebuffer *old_fb)
284{
285 return 0;
286}
287
288static void dce_virtual_crtc_load_lut(struct drm_crtc *crtc)
289{
290 return;
291}
292
293static int dce_virtual_crtc_set_base_atomic(struct drm_crtc *crtc,
294 struct drm_framebuffer *fb,
295 int x, int y, enum mode_set_atomic state)
296{
297 return 0;
298}
299
Emily Dengc6e14f42016-08-08 11:30:50 +0800300static const struct drm_crtc_helper_funcs dce_virtual_crtc_helper_funcs = {
Emily Dengf1f5ef92016-08-08 11:32:00 +0800301 .dpms = dce_virtual_crtc_dpms,
302 .mode_fixup = dce_virtual_crtc_mode_fixup,
303 .mode_set = dce_virtual_crtc_mode_set,
304 .mode_set_base = dce_virtual_crtc_set_base,
305 .mode_set_base_atomic = dce_virtual_crtc_set_base_atomic,
306 .prepare = dce_virtual_crtc_prepare,
307 .commit = dce_virtual_crtc_commit,
308 .load_lut = dce_virtual_crtc_load_lut,
309 .disable = dce_virtual_crtc_disable,
Emily Dengc6e14f42016-08-08 11:30:50 +0800310};
311
312static int dce_virtual_crtc_init(struct amdgpu_device *adev, int index)
313{
314 struct amdgpu_crtc *amdgpu_crtc;
315 int i;
316
317 amdgpu_crtc = kzalloc(sizeof(struct amdgpu_crtc) +
318 (AMDGPUFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
319 if (amdgpu_crtc == NULL)
320 return -ENOMEM;
321
322 drm_crtc_init(adev->ddev, &amdgpu_crtc->base, &dce_virtual_crtc_funcs);
323
324 drm_mode_crtc_set_gamma_size(&amdgpu_crtc->base, 256);
325 amdgpu_crtc->crtc_id = index;
326 adev->mode_info.crtcs[index] = amdgpu_crtc;
327
328 for (i = 0; i < 256; i++) {
329 amdgpu_crtc->lut_r[i] = i << 2;
330 amdgpu_crtc->lut_g[i] = i << 2;
331 amdgpu_crtc->lut_b[i] = i << 2;
332 }
333
334 amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
335 amdgpu_crtc->encoder = NULL;
336 amdgpu_crtc->connector = NULL;
Emily Deng0f663562016-09-30 13:02:18 -0400337 amdgpu_crtc->vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE;
Emily Dengc6e14f42016-08-08 11:30:50 +0800338 drm_crtc_helper_add(&amdgpu_crtc->base, &dce_virtual_crtc_helper_funcs);
339
340 return 0;
341}
342
343static int dce_virtual_early_init(void *handle)
344{
345 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
346
347 dce_virtual_set_display_funcs(adev);
348 dce_virtual_set_irq_funcs(adev);
349
Emily Dengc6e14f42016-08-08 11:30:50 +0800350 adev->mode_info.num_hpd = 1;
351 adev->mode_info.num_dig = 1;
352 return 0;
353}
354
Alex Deucher66264ba2016-09-30 12:37:36 -0400355static struct drm_encoder *
356dce_virtual_encoder(struct drm_connector *connector)
Emily Dengc6e14f42016-08-08 11:30:50 +0800357{
Alex Deucher66264ba2016-09-30 12:37:36 -0400358 int enc_id = connector->encoder_ids[0];
359 struct drm_encoder *encoder;
360 int i;
Emily Dengc6e14f42016-08-08 11:30:50 +0800361
Alex Deucher66264ba2016-09-30 12:37:36 -0400362 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
363 if (connector->encoder_ids[i] == 0)
364 break;
Emily Dengc6e14f42016-08-08 11:30:50 +0800365
Alex Deucher66264ba2016-09-30 12:37:36 -0400366 encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
367 if (!encoder)
368 continue;
Emily Dengc6e14f42016-08-08 11:30:50 +0800369
Alex Deucher66264ba2016-09-30 12:37:36 -0400370 if (encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL)
371 return encoder;
372 }
Emily Dengc6e14f42016-08-08 11:30:50 +0800373
Alex Deucher66264ba2016-09-30 12:37:36 -0400374 /* pick the first one */
375 if (enc_id)
376 return drm_encoder_find(connector->dev, enc_id);
377 return NULL;
Emily Dengc6e14f42016-08-08 11:30:50 +0800378}
379
Alex Deucher66264ba2016-09-30 12:37:36 -0400380static int dce_virtual_get_modes(struct drm_connector *connector)
381{
382 struct drm_device *dev = connector->dev;
383 struct drm_display_mode *mode = NULL;
384 unsigned i;
385 static const struct mode_size {
386 int w;
387 int h;
388 } common_modes[17] = {
389 { 640, 480},
390 { 720, 480},
391 { 800, 600},
392 { 848, 480},
393 {1024, 768},
394 {1152, 768},
395 {1280, 720},
396 {1280, 800},
397 {1280, 854},
398 {1280, 960},
399 {1280, 1024},
400 {1440, 900},
401 {1400, 1050},
402 {1680, 1050},
403 {1600, 1200},
404 {1920, 1080},
405 {1920, 1200}
406 };
407
408 for (i = 0; i < 17; i++) {
409 mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false);
410 drm_mode_probed_add(connector, mode);
411 }
412
413 return 0;
414}
415
416static int dce_virtual_mode_valid(struct drm_connector *connector,
417 struct drm_display_mode *mode)
418{
419 return MODE_OK;
420}
421
422static int
423dce_virtual_dpms(struct drm_connector *connector, int mode)
424{
425 return 0;
426}
427
Alex Deucher66264ba2016-09-30 12:37:36 -0400428static int
429dce_virtual_set_property(struct drm_connector *connector,
430 struct drm_property *property,
431 uint64_t val)
432{
433 return 0;
434}
435
436static void dce_virtual_destroy(struct drm_connector *connector)
437{
438 drm_connector_unregister(connector);
439 drm_connector_cleanup(connector);
440 kfree(connector);
441}
442
443static void dce_virtual_force(struct drm_connector *connector)
444{
445 return;
446}
447
448static const struct drm_connector_helper_funcs dce_virtual_connector_helper_funcs = {
449 .get_modes = dce_virtual_get_modes,
450 .mode_valid = dce_virtual_mode_valid,
451 .best_encoder = dce_virtual_encoder,
452};
453
454static const struct drm_connector_funcs dce_virtual_connector_funcs = {
455 .dpms = dce_virtual_dpms,
Alex Deucher66264ba2016-09-30 12:37:36 -0400456 .fill_modes = drm_helper_probe_single_connector_modes,
457 .set_property = dce_virtual_set_property,
458 .destroy = dce_virtual_destroy,
459 .force = dce_virtual_force,
460};
461
Emily Dengc6e14f42016-08-08 11:30:50 +0800462static int dce_virtual_sw_init(void *handle)
463{
464 int r, i;
465 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
466
Alex Deucherd766e6a2016-03-29 18:28:50 -0400467 r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 229, &adev->crtc_irq);
Emily Dengc6e14f42016-08-08 11:30:50 +0800468 if (r)
469 return r;
470
Emily Deng041aa652016-08-17 14:59:20 +0800471 adev->ddev->max_vblank_count = 0;
472
Emily Dengc6e14f42016-08-08 11:30:50 +0800473 adev->ddev->mode_config.funcs = &amdgpu_mode_funcs;
474
475 adev->ddev->mode_config.max_width = 16384;
476 adev->ddev->mode_config.max_height = 16384;
477
478 adev->ddev->mode_config.preferred_depth = 24;
479 adev->ddev->mode_config.prefer_shadow = 1;
480
481 adev->ddev->mode_config.fb_base = adev->mc.aper_base;
482
483 r = amdgpu_modeset_create_props(adev);
484 if (r)
485 return r;
486
487 adev->ddev->mode_config.max_width = 16384;
488 adev->ddev->mode_config.max_height = 16384;
489
Alex Deucher66264ba2016-09-30 12:37:36 -0400490 /* allocate crtcs, encoders, connectors */
Emily Dengc6e14f42016-08-08 11:30:50 +0800491 for (i = 0; i < adev->mode_info.num_crtc; i++) {
492 r = dce_virtual_crtc_init(adev, i);
493 if (r)
494 return r;
Alex Deucher66264ba2016-09-30 12:37:36 -0400495 r = dce_virtual_connector_encoder_init(adev, i);
496 if (r)
497 return r;
Emily Dengc6e14f42016-08-08 11:30:50 +0800498 }
499
Emily Dengc6e14f42016-08-08 11:30:50 +0800500 drm_kms_helper_poll_init(adev->ddev);
501
502 adev->mode_info.mode_config_initialized = true;
503 return 0;
504}
505
506static int dce_virtual_sw_fini(void *handle)
507{
508 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
509
510 kfree(adev->mode_info.bios_hardcoded_edid);
511
512 drm_kms_helper_poll_fini(adev->ddev);
513
514 drm_mode_config_cleanup(adev->ddev);
515 adev->mode_info.mode_config_initialized = false;
516 return 0;
517}
518
519static int dce_virtual_hw_init(void *handle)
520{
521 return 0;
522}
523
524static int dce_virtual_hw_fini(void *handle)
525{
526 return 0;
527}
528
529static int dce_virtual_suspend(void *handle)
530{
531 return dce_virtual_hw_fini(handle);
532}
533
534static int dce_virtual_resume(void *handle)
535{
Masahiro Yamadad912ade2016-09-14 23:39:08 +0900536 return dce_virtual_hw_init(handle);
Emily Dengc6e14f42016-08-08 11:30:50 +0800537}
538
539static bool dce_virtual_is_idle(void *handle)
540{
541 return true;
542}
543
544static int dce_virtual_wait_for_idle(void *handle)
545{
546 return 0;
547}
548
549static int dce_virtual_soft_reset(void *handle)
550{
551 return 0;
552}
553
554static int dce_virtual_set_clockgating_state(void *handle,
555 enum amd_clockgating_state state)
556{
557 return 0;
558}
559
560static int dce_virtual_set_powergating_state(void *handle,
561 enum amd_powergating_state state)
562{
563 return 0;
564}
565
Alex Deuchera1255102016-10-13 17:41:13 -0400566static const struct amd_ip_funcs dce_virtual_ip_funcs = {
Emily Dengc6e14f42016-08-08 11:30:50 +0800567 .name = "dce_virtual",
568 .early_init = dce_virtual_early_init,
569 .late_init = NULL,
570 .sw_init = dce_virtual_sw_init,
571 .sw_fini = dce_virtual_sw_fini,
572 .hw_init = dce_virtual_hw_init,
573 .hw_fini = dce_virtual_hw_fini,
574 .suspend = dce_virtual_suspend,
575 .resume = dce_virtual_resume,
576 .is_idle = dce_virtual_is_idle,
577 .wait_for_idle = dce_virtual_wait_for_idle,
578 .soft_reset = dce_virtual_soft_reset,
579 .set_clockgating_state = dce_virtual_set_clockgating_state,
580 .set_powergating_state = dce_virtual_set_powergating_state,
581};
582
Emily Deng8e6de752016-08-08 11:31:13 +0800583/* these are handled by the primary encoders */
584static void dce_virtual_encoder_prepare(struct drm_encoder *encoder)
585{
586 return;
587}
588
589static void dce_virtual_encoder_commit(struct drm_encoder *encoder)
590{
591 return;
592}
593
594static void
595dce_virtual_encoder_mode_set(struct drm_encoder *encoder,
Alex Deucher66264ba2016-09-30 12:37:36 -0400596 struct drm_display_mode *mode,
597 struct drm_display_mode *adjusted_mode)
Emily Deng8e6de752016-08-08 11:31:13 +0800598{
599 return;
600}
601
602static void dce_virtual_encoder_disable(struct drm_encoder *encoder)
603{
604 return;
605}
606
607static void
608dce_virtual_encoder_dpms(struct drm_encoder *encoder, int mode)
609{
610 return;
611}
612
613static bool dce_virtual_encoder_mode_fixup(struct drm_encoder *encoder,
614 const struct drm_display_mode *mode,
615 struct drm_display_mode *adjusted_mode)
616{
Emily Deng8e6de752016-08-08 11:31:13 +0800617 return true;
618}
619
620static const struct drm_encoder_helper_funcs dce_virtual_encoder_helper_funcs = {
621 .dpms = dce_virtual_encoder_dpms,
622 .mode_fixup = dce_virtual_encoder_mode_fixup,
623 .prepare = dce_virtual_encoder_prepare,
624 .mode_set = dce_virtual_encoder_mode_set,
625 .commit = dce_virtual_encoder_commit,
626 .disable = dce_virtual_encoder_disable,
627};
628
629static void dce_virtual_encoder_destroy(struct drm_encoder *encoder)
630{
Emily Deng8e6de752016-08-08 11:31:13 +0800631 drm_encoder_cleanup(encoder);
Xiangliang Yu3a1d19a2017-01-19 09:57:41 +0800632 kfree(encoder);
Emily Deng8e6de752016-08-08 11:31:13 +0800633}
634
635static const struct drm_encoder_funcs dce_virtual_encoder_funcs = {
636 .destroy = dce_virtual_encoder_destroy,
637};
638
Alex Deucher66264ba2016-09-30 12:37:36 -0400639static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev,
640 int index)
Emily Deng8e6de752016-08-08 11:31:13 +0800641{
Emily Deng8e6de752016-08-08 11:31:13 +0800642 struct drm_encoder *encoder;
Alex Deucher66264ba2016-09-30 12:37:36 -0400643 struct drm_connector *connector;
Emily Deng8e6de752016-08-08 11:31:13 +0800644
Alex Deucher66264ba2016-09-30 12:37:36 -0400645 /* add a new encoder */
646 encoder = kzalloc(sizeof(struct drm_encoder), GFP_KERNEL);
647 if (!encoder)
648 return -ENOMEM;
649 encoder->possible_crtcs = 1 << index;
650 drm_encoder_init(adev->ddev, encoder, &dce_virtual_encoder_funcs,
651 DRM_MODE_ENCODER_VIRTUAL, NULL);
652 drm_encoder_helper_add(encoder, &dce_virtual_encoder_helper_funcs);
Emily Deng8e6de752016-08-08 11:31:13 +0800653
Alex Deucher66264ba2016-09-30 12:37:36 -0400654 connector = kzalloc(sizeof(struct drm_connector), GFP_KERNEL);
655 if (!connector) {
656 kfree(encoder);
657 return -ENOMEM;
Emily Deng8e6de752016-08-08 11:31:13 +0800658 }
659
Alex Deucher66264ba2016-09-30 12:37:36 -0400660 /* add a new connector */
661 drm_connector_init(adev->ddev, connector, &dce_virtual_connector_funcs,
662 DRM_MODE_CONNECTOR_VIRTUAL);
663 drm_connector_helper_add(connector, &dce_virtual_connector_helper_funcs);
664 connector->display_info.subpixel_order = SubPixelHorizontalRGB;
665 connector->interlace_allowed = false;
666 connector->doublescan_allowed = false;
667 drm_connector_register(connector);
Emily Deng8e6de752016-08-08 11:31:13 +0800668
Alex Deucher66264ba2016-09-30 12:37:36 -0400669 /* link them */
670 drm_mode_connector_attach_encoder(connector, encoder);
Emily Deng8e6de752016-08-08 11:31:13 +0800671
Alex Deucher66264ba2016-09-30 12:37:36 -0400672 return 0;
Emily Deng8e6de752016-08-08 11:31:13 +0800673}
674
Emily Dengc6e14f42016-08-08 11:30:50 +0800675static const struct amdgpu_display_funcs dce_virtual_display_funcs = {
Emily Deng8e6de752016-08-08 11:31:13 +0800676 .set_vga_render_state = &dce_virtual_set_vga_render_state,
677 .bandwidth_update = &dce_virtual_bandwidth_update,
678 .vblank_get_counter = &dce_virtual_vblank_get_counter,
679 .vblank_wait = &dce_virtual_vblank_wait,
Emily Dengc6e14f42016-08-08 11:30:50 +0800680 .backlight_set_level = NULL,
681 .backlight_get_level = NULL,
Emily Deng8e6de752016-08-08 11:31:13 +0800682 .hpd_sense = &dce_virtual_hpd_sense,
683 .hpd_set_polarity = &dce_virtual_hpd_set_polarity,
684 .hpd_get_gpio_reg = &dce_virtual_hpd_get_gpio_reg,
685 .page_flip = &dce_virtual_page_flip,
686 .page_flip_get_scanoutpos = &dce_virtual_crtc_get_scanoutpos,
Alex Deucher66264ba2016-09-30 12:37:36 -0400687 .add_encoder = NULL,
688 .add_connector = NULL,
Emily Deng8e6de752016-08-08 11:31:13 +0800689 .stop_mc_access = &dce_virtual_stop_mc_access,
690 .resume_mc_access = &dce_virtual_resume_mc_access,
Emily Dengc6e14f42016-08-08 11:30:50 +0800691};
692
693static void dce_virtual_set_display_funcs(struct amdgpu_device *adev)
694{
695 if (adev->mode_info.funcs == NULL)
696 adev->mode_info.funcs = &dce_virtual_display_funcs;
697}
698
Alex Deucher9405e472016-09-30 11:41:37 -0400699static int dce_virtual_pageflip(struct amdgpu_device *adev,
700 unsigned crtc_id)
701{
702 unsigned long flags;
703 struct amdgpu_crtc *amdgpu_crtc;
704 struct amdgpu_flip_work *works;
705
706 amdgpu_crtc = adev->mode_info.crtcs[crtc_id];
707
708 if (crtc_id >= adev->mode_info.num_crtc) {
709 DRM_ERROR("invalid pageflip crtc %d\n", crtc_id);
710 return -EINVAL;
711 }
712
713 /* IRQ could occur when in initial stage */
714 if (amdgpu_crtc == NULL)
715 return 0;
716
717 spin_lock_irqsave(&adev->ddev->event_lock, flags);
718 works = amdgpu_crtc->pflip_works;
719 if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) {
720 DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d != "
721 "AMDGPU_FLIP_SUBMITTED(%d)\n",
722 amdgpu_crtc->pflip_status,
723 AMDGPU_FLIP_SUBMITTED);
724 spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
725 return 0;
726 }
727
728 /* page flip completed. clean up */
729 amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE;
730 amdgpu_crtc->pflip_works = NULL;
731
732 /* wakeup usersapce */
733 if (works->event)
734 drm_crtc_send_vblank_event(&amdgpu_crtc->base, works->event);
735
736 spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
737
738 drm_crtc_vblank_put(&amdgpu_crtc->base);
739 schedule_work(&works->unpin_work);
740
741 return 0;
742}
743
Emily Deng46ac3622016-08-08 11:35:39 +0800744static enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vblank_timer)
745{
Emily Deng0f663562016-09-30 13:02:18 -0400746 struct amdgpu_crtc *amdgpu_crtc = container_of(vblank_timer,
747 struct amdgpu_crtc, vblank_timer);
748 struct drm_device *ddev = amdgpu_crtc->base.dev;
749 struct amdgpu_device *adev = ddev->dev_private;
Alex Deucher9405e472016-09-30 11:41:37 -0400750
Emily Deng0f663562016-09-30 13:02:18 -0400751 drm_handle_vblank(ddev, amdgpu_crtc->crtc_id);
752 dce_virtual_pageflip(adev, amdgpu_crtc->crtc_id);
Thomas Gleixner8b0e1952016-12-25 12:30:41 +0100753 hrtimer_start(vblank_timer, DCE_VIRTUAL_VBLANK_PERIOD,
Alex Deucher9405e472016-09-30 11:41:37 -0400754 HRTIMER_MODE_REL);
755
Emily Deng46ac3622016-08-08 11:35:39 +0800756 return HRTIMER_NORESTART;
757}
758
Emily Denge13273d2016-08-08 11:31:37 +0800759static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev,
Alex Deucher82b9f812016-09-30 11:19:41 -0400760 int crtc,
761 enum amdgpu_interrupt_state state)
Emily Denge13273d2016-08-08 11:31:37 +0800762{
763 if (crtc >= adev->mode_info.num_crtc) {
764 DRM_DEBUG("invalid crtc %d\n", crtc);
765 return;
766 }
Emily Deng46ac3622016-08-08 11:35:39 +0800767
Emily Deng0f663562016-09-30 13:02:18 -0400768 if (state && !adev->mode_info.crtcs[crtc]->vsync_timer_enabled) {
Emily Deng46ac3622016-08-08 11:35:39 +0800769 DRM_DEBUG("Enable software vsync timer\n");
Emily Deng0f663562016-09-30 13:02:18 -0400770 hrtimer_init(&adev->mode_info.crtcs[crtc]->vblank_timer,
771 CLOCK_MONOTONIC, HRTIMER_MODE_REL);
772 hrtimer_set_expires(&adev->mode_info.crtcs[crtc]->vblank_timer,
Thomas Gleixner8b0e1952016-12-25 12:30:41 +0100773 DCE_VIRTUAL_VBLANK_PERIOD);
Emily Deng0f663562016-09-30 13:02:18 -0400774 adev->mode_info.crtcs[crtc]->vblank_timer.function =
775 dce_virtual_vblank_timer_handle;
776 hrtimer_start(&adev->mode_info.crtcs[crtc]->vblank_timer,
Thomas Gleixner8b0e1952016-12-25 12:30:41 +0100777 DCE_VIRTUAL_VBLANK_PERIOD, HRTIMER_MODE_REL);
Emily Deng0f663562016-09-30 13:02:18 -0400778 } else if (!state && adev->mode_info.crtcs[crtc]->vsync_timer_enabled) {
Emily Deng46ac3622016-08-08 11:35:39 +0800779 DRM_DEBUG("Disable software vsync timer\n");
Emily Deng0f663562016-09-30 13:02:18 -0400780 hrtimer_cancel(&adev->mode_info.crtcs[crtc]->vblank_timer);
Emily Deng46ac3622016-08-08 11:35:39 +0800781 }
782
Emily Deng0f663562016-09-30 13:02:18 -0400783 adev->mode_info.crtcs[crtc]->vsync_timer_enabled = state;
Emily Deng46ac3622016-08-08 11:35:39 +0800784 DRM_DEBUG("[FM]set crtc %d vblank interrupt state %d\n", crtc, state);
Emily Denge13273d2016-08-08 11:31:37 +0800785}
786
Emily Deng46ac3622016-08-08 11:35:39 +0800787
Emily Denge13273d2016-08-08 11:31:37 +0800788static int dce_virtual_set_crtc_irq_state(struct amdgpu_device *adev,
Alex Deucher82b9f812016-09-30 11:19:41 -0400789 struct amdgpu_irq_src *source,
790 unsigned type,
791 enum amdgpu_interrupt_state state)
Emily Denge13273d2016-08-08 11:31:37 +0800792{
Emily Deng0f663562016-09-30 13:02:18 -0400793 if (type > AMDGPU_CRTC_IRQ_VBLANK6)
794 return -EINVAL;
795
796 dce_virtual_set_crtc_vblank_interrupt_state(adev, type, state);
797
Emily Denge13273d2016-08-08 11:31:37 +0800798 return 0;
799}
800
Emily Dengc6e14f42016-08-08 11:30:50 +0800801static const struct amdgpu_irq_src_funcs dce_virtual_crtc_irq_funcs = {
Emily Denge13273d2016-08-08 11:31:37 +0800802 .set = dce_virtual_set_crtc_irq_state,
Alex Deucherbf2335a2016-09-30 11:23:30 -0400803 .process = NULL,
Emily Dengc6e14f42016-08-08 11:30:50 +0800804};
805
Emily Dengc6e14f42016-08-08 11:30:50 +0800806static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev)
807{
808 adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_LAST;
809 adev->crtc_irq.funcs = &dce_virtual_crtc_irq_funcs;
Emily Dengc6e14f42016-08-08 11:30:50 +0800810}
811
Alex Deuchera1255102016-10-13 17:41:13 -0400812const struct amdgpu_ip_block_version dce_virtual_ip_block =
813{
814 .type = AMD_IP_BLOCK_TYPE_DCE,
815 .major = 1,
816 .minor = 0,
817 .rev = 0,
818 .funcs = &dce_virtual_ip_funcs,
819};