Linux Audio

Check our new training course

Open-source upstreaming

Need help get the support for your hardware in upstream Linux?
Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright © 2023 Intel Corporation
  4 */
  5
  6#include "xe_display.h"
  7#include "regs/xe_irq_regs.h"
  8
  9#include <linux/fb.h>
 10
 11#include <drm/drm_drv.h>
 12#include <drm/drm_managed.h>
 13#include <drm/drm_probe_helper.h>
 14#include <uapi/drm/xe_drm.h>
 15
 16#include "soc/intel_dram.h"
 17#include "intel_acpi.h"
 18#include "intel_audio.h"
 19#include "intel_bw.h"
 20#include "intel_display.h"
 21#include "intel_display_driver.h"
 22#include "intel_display_irq.h"
 23#include "intel_display_types.h"
 24#include "intel_dmc.h"
 25#include "intel_dp.h"
 26#include "intel_encoder.h"
 27#include "intel_fbdev.h"
 28#include "intel_hdcp.h"
 29#include "intel_hotplug.h"
 30#include "intel_opregion.h"
 31#include "xe_module.h"
 32
 33/* Xe device functions */
 34
 35static bool has_display(struct xe_device *xe)
 36{
 37	return HAS_DISPLAY(&xe->display);
 38}
 39
 40/**
 41 * xe_display_driver_probe_defer - Detect if we need to wait for other drivers
 42 *				   early on
 43 * @pdev: PCI device
 44 *
 45 * Returns: true if probe needs to be deferred, false otherwise
 46 */
 47bool xe_display_driver_probe_defer(struct pci_dev *pdev)
 48{
 49	if (!xe_modparam.probe_display)
 50		return 0;
 51
 52	return intel_display_driver_probe_defer(pdev);
 53}
 54
 55/**
 56 * xe_display_driver_set_hooks - Add driver flags and hooks for display
 57 * @driver: DRM device driver
 58 *
 59 * Set features and function hooks in @driver that are needed for driving the
 60 * display IP. This sets the driver's capability of driving display, regardless
 61 * if the device has it enabled
 62 */
 63void xe_display_driver_set_hooks(struct drm_driver *driver)
 64{
 65	if (!xe_modparam.probe_display)
 66		return;
 67
 68	driver->driver_features |= DRIVER_MODESET | DRIVER_ATOMIC;
 69}
 70
 71static void unset_display_features(struct xe_device *xe)
 72{
 73	xe->drm.driver_features &= ~(DRIVER_MODESET | DRIVER_ATOMIC);
 74}
 75
 76static void display_destroy(struct drm_device *dev, void *dummy)
 77{
 78	struct xe_device *xe = to_xe_device(dev);
 79
 80	destroy_workqueue(xe->display.hotplug.dp_wq);
 81}
 82
 83/**
 84 * xe_display_create - create display struct
 85 * @xe: XE device instance
 86 *
 87 * Initialize all fields used by the display part.
 88 *
 89 * TODO: once everything can be inside a single struct, make the struct opaque
 90 * to the rest of xe and return it to be xe->display.
 91 *
 92 * Returns: 0 on success
 93 */
 94int xe_display_create(struct xe_device *xe)
 95{
 96	spin_lock_init(&xe->display.fb_tracking.lock);
 97
 98	xe->display.hotplug.dp_wq = alloc_ordered_workqueue("xe-dp", 0);
 99
100	return drmm_add_action_or_reset(&xe->drm, display_destroy, NULL);
101}
102
103static void xe_display_fini_nommio(struct drm_device *dev, void *dummy)
104{
105	struct xe_device *xe = to_xe_device(dev);
106
107	if (!xe->info.probe_display)
108		return;
109
110	intel_power_domains_cleanup(xe);
111}
112
113int xe_display_init_nommio(struct xe_device *xe)
114{
115	if (!xe->info.probe_display)
116		return 0;
117
118	/* Fake uncore lock */
119	spin_lock_init(&xe->uncore.lock);
120
121	/* This must be called before any calls to HAS_PCH_* */
122	intel_detect_pch(xe);
123
124	return drmm_add_action_or_reset(&xe->drm, xe_display_fini_nommio, xe);
125}
126
127static void xe_display_fini_noirq(void *arg)
128{
129	struct xe_device *xe = arg;
130	struct intel_display *display = &xe->display;
131
132	if (!xe->info.probe_display)
133		return;
134
135	intel_display_driver_remove_noirq(xe);
136	intel_opregion_cleanup(display);
137}
138
139int xe_display_init_noirq(struct xe_device *xe)
140{
141	struct intel_display *display = &xe->display;
142	int err;
143
144	if (!xe->info.probe_display)
145		return 0;
146
147	intel_display_driver_early_probe(xe);
148
149	/* Early display init.. */
150	intel_opregion_setup(display);
151
152	/*
153	 * Fill the dram structure to get the system dram info. This will be
154	 * used for memory latency calculation.
155	 */
156	intel_dram_detect(xe);
157
158	intel_bw_init_hw(xe);
159
160	intel_display_device_info_runtime_init(xe);
161
162	err = intel_display_driver_probe_noirq(xe);
163	if (err) {
164		intel_opregion_cleanup(display);
165		return err;
166	}
167
168	return devm_add_action_or_reset(xe->drm.dev, xe_display_fini_noirq, xe);
169}
170
171static void xe_display_fini_noaccel(void *arg)
172{
173	struct xe_device *xe = arg;
174
175	if (!xe->info.probe_display)
176		return;
177
178	intel_display_driver_remove_nogem(xe);
179}
180
181int xe_display_init_noaccel(struct xe_device *xe)
182{
183	int err;
184
185	if (!xe->info.probe_display)
186		return 0;
187
188	err = intel_display_driver_probe_nogem(xe);
189	if (err)
190		return err;
191
192	return devm_add_action_or_reset(xe->drm.dev, xe_display_fini_noaccel, xe);
193}
194
195int xe_display_init(struct xe_device *xe)
196{
197	if (!xe->info.probe_display)
198		return 0;
199
200	return intel_display_driver_probe(xe);
201}
202
203void xe_display_fini(struct xe_device *xe)
204{
205	struct intel_display *display = &xe->display;
206
207	if (!xe->info.probe_display)
208		return;
209
210	intel_hpd_poll_fini(xe);
211
212	intel_hdcp_component_fini(display);
213	intel_audio_deinit(xe);
214}
215
216void xe_display_register(struct xe_device *xe)
217{
218	if (!xe->info.probe_display)
219		return;
220
221	intel_display_driver_register(xe);
222	intel_register_dsm_handler();
223	intel_power_domains_enable(xe);
224}
225
226void xe_display_unregister(struct xe_device *xe)
227{
228	if (!xe->info.probe_display)
229		return;
230
231	intel_unregister_dsm_handler();
232	intel_power_domains_disable(xe);
233	intel_display_driver_unregister(xe);
234}
235
236void xe_display_driver_remove(struct xe_device *xe)
237{
238	if (!xe->info.probe_display)
239		return;
240
241	intel_display_driver_remove(xe);
242}
243
244/* IRQ-related functions */
245
246void xe_display_irq_handler(struct xe_device *xe, u32 master_ctl)
247{
248	if (!xe->info.probe_display)
249		return;
250
251	if (master_ctl & DISPLAY_IRQ)
252		gen11_display_irq_handler(xe);
253}
254
255void xe_display_irq_enable(struct xe_device *xe, u32 gu_misc_iir)
256{
257	struct intel_display *display = &xe->display;
258
259	if (!xe->info.probe_display)
260		return;
261
262	if (gu_misc_iir & GU_MISC_GSE)
263		intel_opregion_asle_intr(display);
264}
265
266void xe_display_irq_reset(struct xe_device *xe)
267{
268	if (!xe->info.probe_display)
269		return;
270
271	gen11_display_irq_reset(xe);
272}
273
274void xe_display_irq_postinstall(struct xe_device *xe, struct xe_gt *gt)
275{
276	if (!xe->info.probe_display)
277		return;
278
279	if (gt->info.id == XE_GT0)
280		gen11_de_irq_postinstall(xe);
281}
282
283static bool suspend_to_idle(void)
284{
285#if IS_ENABLED(CONFIG_ACPI_SLEEP)
286	if (acpi_target_system_state() < ACPI_STATE_S3)
287		return true;
288#endif
289	return false;
290}
291
292static void xe_display_flush_cleanup_work(struct xe_device *xe)
293{
294	struct intel_crtc *crtc;
295
296	for_each_intel_crtc(&xe->drm, crtc) {
297		struct drm_crtc_commit *commit;
298
299		spin_lock(&crtc->base.commit_lock);
300		commit = list_first_entry_or_null(&crtc->base.commit_list,
301						  struct drm_crtc_commit, commit_entry);
302		if (commit)
303			drm_crtc_commit_get(commit);
304		spin_unlock(&crtc->base.commit_lock);
305
306		if (commit) {
307			wait_for_completion(&commit->cleanup_done);
308			drm_crtc_commit_put(commit);
309		}
310	}
311}
312
313/* TODO: System and runtime suspend/resume sequences will be sanitized as a follow-up. */
314static void __xe_display_pm_suspend(struct xe_device *xe, bool runtime)
315{
316	struct intel_display *display = &xe->display;
317	bool s2idle = suspend_to_idle();
318	if (!xe->info.probe_display)
319		return;
320
321	/*
322	 * We do a lot of poking in a lot of registers, make sure they work
323	 * properly.
324	 */
325	intel_power_domains_disable(xe);
326	if (!runtime)
327		intel_fbdev_set_suspend(&xe->drm, FBINFO_STATE_SUSPENDED, true);
328
329	if (!runtime && has_display(xe)) {
330		drm_kms_helper_poll_disable(&xe->drm);
331		intel_display_driver_disable_user_access(xe);
332		intel_display_driver_suspend(xe);
333	}
334
335	xe_display_flush_cleanup_work(xe);
336
337	if (!runtime)
338		intel_dp_mst_suspend(xe);
339
340	intel_hpd_cancel_work(xe);
341
342	if (!runtime && has_display(xe)) {
343		intel_display_driver_suspend_access(xe);
344		intel_encoder_suspend_all(&xe->display);
345	}
346
347	intel_opregion_suspend(display, s2idle ? PCI_D1 : PCI_D3cold);
348
349	intel_dmc_suspend(display);
350
351	if (runtime && has_display(xe))
352		intel_hpd_poll_enable(xe);
353}
354
355void xe_display_pm_suspend(struct xe_device *xe)
356{
357	__xe_display_pm_suspend(xe, false);
358}
359
360void xe_display_pm_shutdown(struct xe_device *xe)
361{
362	struct intel_display *display = &xe->display;
363
364	if (!xe->info.probe_display)
365		return;
366
367	intel_power_domains_disable(xe);
368	intel_fbdev_set_suspend(&xe->drm, FBINFO_STATE_SUSPENDED, true);
369	if (has_display(xe)) {
370		drm_kms_helper_poll_disable(&xe->drm);
371		intel_display_driver_disable_user_access(xe);
372		intel_display_driver_suspend(xe);
373	}
374
375	xe_display_flush_cleanup_work(xe);
376	intel_dp_mst_suspend(xe);
377	intel_hpd_cancel_work(xe);
378
379	if (has_display(xe))
380		intel_display_driver_suspend_access(xe);
381
382	intel_encoder_suspend_all(display);
383	intel_encoder_shutdown_all(display);
384
385	intel_opregion_suspend(display, PCI_D3cold);
386
387	intel_dmc_suspend(display);
388}
389
390void xe_display_pm_runtime_suspend(struct xe_device *xe)
391{
392	if (!xe->info.probe_display)
393		return;
394
395	if (xe->d3cold.allowed) {
396		__xe_display_pm_suspend(xe, true);
397		return;
398	}
399
400	intel_hpd_poll_enable(xe);
401}
402
403void xe_display_pm_suspend_late(struct xe_device *xe)
404{
405	bool s2idle = suspend_to_idle();
406	if (!xe->info.probe_display)
407		return;
408
409	intel_power_domains_suspend(xe, s2idle);
410
411	intel_display_power_suspend_late(xe);
412}
413
414void xe_display_pm_shutdown_late(struct xe_device *xe)
415{
416	if (!xe->info.probe_display)
417		return;
418
419	/*
420	 * The only requirement is to reboot with display DC states disabled,
421	 * for now leaving all display power wells in the INIT power domain
422	 * enabled.
423	 */
424	intel_power_domains_driver_remove(xe);
425}
426
427void xe_display_pm_resume_early(struct xe_device *xe)
428{
429	if (!xe->info.probe_display)
430		return;
431
432	intel_display_power_resume_early(xe);
433
434	intel_power_domains_resume(xe);
435}
436
437static void __xe_display_pm_resume(struct xe_device *xe, bool runtime)
438{
439	struct intel_display *display = &xe->display;
440
441	if (!xe->info.probe_display)
442		return;
443
444	intel_dmc_resume(display);
445
446	if (has_display(xe))
447		drm_mode_config_reset(&xe->drm);
448
449	intel_display_driver_init_hw(xe);
450	intel_hpd_init(xe);
451
452	if (!runtime && has_display(xe))
453		intel_display_driver_resume_access(xe);
454
455	/* MST sideband requires HPD interrupts enabled */
456	if (!runtime)
457		intel_dp_mst_resume(xe);
458
459	if (!runtime && has_display(xe)) {
460		intel_display_driver_resume(xe);
461		drm_kms_helper_poll_enable(&xe->drm);
462		intel_display_driver_enable_user_access(xe);
463	}
464
465	if (has_display(xe))
466		intel_hpd_poll_disable(xe);
467
468	intel_opregion_resume(display);
469
470	if (!runtime)
471		intel_fbdev_set_suspend(&xe->drm, FBINFO_STATE_RUNNING, false);
472
473	intel_power_domains_enable(xe);
474}
475
476void xe_display_pm_resume(struct xe_device *xe)
477{
478	__xe_display_pm_resume(xe, false);
479}
480
481void xe_display_pm_runtime_resume(struct xe_device *xe)
482{
483	if (!xe->info.probe_display)
484		return;
485
486	if (xe->d3cold.allowed) {
487		__xe_display_pm_resume(xe, true);
488		return;
489	}
490
491	intel_hpd_init(xe);
492	intel_hpd_poll_disable(xe);
493}
494
495
496static void display_device_remove(struct drm_device *dev, void *arg)
497{
498	struct xe_device *xe = arg;
499
500	intel_display_device_remove(xe);
501}
502
503int xe_display_probe(struct xe_device *xe)
504{
505	int err;
506
507	if (!xe->info.probe_display)
508		goto no_display;
509
510	intel_display_device_probe(xe);
511
512	err = drmm_add_action_or_reset(&xe->drm, display_device_remove, xe);
513	if (err)
514		return err;
515
516	if (has_display(xe))
517		return 0;
518
519no_display:
520	xe->info.probe_display = false;
521	unset_display_features(xe);
522	return 0;
523}