/* SPDX-License-Identifier: MIT */ /* * Copyright © 2019 Intel Corporation */ #include <linux/string_helpers.h> #include "i915_drv.h" #include "i915_irq.h" #include "i915_reg.h" #include "intel_backlight_regs.h" #include "intel_cdclk.h" #include "intel_clock_gating.h" #include "intel_combo_phy.h" #include "intel_de.h" #include "intel_display_power.h" #include "intel_display_power_map.h" #include "intel_display_power_well.h" #include "intel_display_types.h" #include "intel_dmc.h" #include "intel_mchbar_regs.h" #include "intel_pch_refclk.h" #include "intel_pcode.h" #include "intel_pmdemand.h" #include "intel_pps_regs.h" #include "intel_snps_phy.h" #include "skl_watermark.h" #include "skl_watermark_regs.h" #include "vlv_sideband.h" #define for_each_power_domain_well(__dev_priv, __power_well, __domain) … #define for_each_power_domain_well_reverse(__dev_priv, __power_well, __domain) … const char * intel_display_power_domain_str(enum intel_display_power_domain domain) { … } /** * __intel_display_power_is_enabled - unlocked check for a power domain * @dev_priv: i915 device instance * @domain: power domain to check * * This is the unlocked version of intel_display_power_is_enabled() and should * only be used from error capture and recovery code where deadlocks are * possible. * * Returns: * True when the power domain is enabled, false otherwise. */ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { … } /** * intel_display_power_is_enabled - check for a power domain * @dev_priv: i915 device instance * @domain: power domain to check * * This function can be used to check the hw power domain state. It is mostly * used in hardware state readout functions. Everywhere else code should rely * upon explicit power domain reference counting to ensure that the hardware * block is powered up before accessing it. * * Callers must hold the relevant modesetting locks to ensure that concurrent * threads can't disable the power well while the caller tries to read a few * registers. * * Returns: * True when the power domain is enabled, false otherwise. */ bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { … } static u32 sanitize_target_dc_state(struct drm_i915_private *i915, u32 target_dc_state) { … } /** * intel_display_power_set_target_dc_state - Set target dc state. * @dev_priv: i915 device * @state: state which needs to be set as target_dc_state. * * This function set the "DC off" power well target_dc_state, * based upon this target_dc_stste, "DC off" power well will * enable desired DC state. */ void intel_display_power_set_target_dc_state(struct drm_i915_private *dev_priv, u32 state) { … } static void __async_put_domains_mask(struct i915_power_domains *power_domains, struct intel_power_domain_mask *mask) { … } #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) static bool assert_async_put_domain_masks_disjoint(struct i915_power_domains *power_domains) { … } static bool __async_put_domains_state_ok(struct i915_power_domains *power_domains) { … } static void print_power_domains(struct i915_power_domains *power_domains, const char *prefix, struct intel_power_domain_mask *mask) { … } static void print_async_put_domains_state(struct i915_power_domains *power_domains) { … } static void verify_async_put_domains_state(struct i915_power_domains *power_domains) { … } #else static void assert_async_put_domain_masks_disjoint(struct i915_power_domains *power_domains) { } static void verify_async_put_domains_state(struct i915_power_domains *power_domains) { } #endif /* CONFIG_DRM_I915_DEBUG_RUNTIME_PM */ static void async_put_domains_mask(struct i915_power_domains *power_domains, struct intel_power_domain_mask *mask) { … } static void async_put_domains_clear_domain(struct i915_power_domains *power_domains, enum intel_display_power_domain domain) { … } static void cancel_async_put_work(struct i915_power_domains *power_domains, bool sync) { … } static bool intel_display_power_grab_async_put_ref(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { … } static void __intel_display_power_get_domain(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { … } /** * intel_display_power_get - grab a power domain reference * @dev_priv: i915 device instance * @domain: power domain to reference * * This function grabs a power domain reference for @domain and ensures that the * power domain and all its parents are powered up. Therefore users should only * grab a reference to the innermost power domain they need. * * Any power domain reference obtained by this function must have a symmetric * call to intel_display_power_put() to release the reference again. */ intel_wakeref_t intel_display_power_get(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { … } /** * intel_display_power_get_if_enabled - grab a reference for an enabled display power domain * @dev_priv: i915 device instance * @domain: power domain to reference * * This function grabs a power domain reference for @domain and ensures that the * power domain and all its parents are powered up. Therefore users should only * grab a reference to the innermost power domain they need. * * Any power domain reference obtained by this function must have a symmetric * call to intel_display_power_put() to release the reference again. */ intel_wakeref_t intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { … } static void __intel_display_power_put_domain(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { … } static void __intel_display_power_put(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { … } static void queue_async_put_domains_work(struct i915_power_domains *power_domains, intel_wakeref_t wakeref, int delay_ms) { … } static void release_async_put_domains(struct i915_power_domains *power_domains, struct intel_power_domain_mask *mask) { … } static void intel_display_power_put_async_work(struct work_struct *work) { … } /** * __intel_display_power_put_async - release a power domain reference asynchronously * @i915: i915 device instance * @domain: power domain to reference * @wakeref: wakeref acquired for the reference that is being released * @delay_ms: delay of powering down the power domain * * This function drops the power domain reference obtained by * intel_display_power_get*() and schedules a work to power down the * corresponding hardware block if this is the last reference. * The power down is delayed by @delay_ms if this is >= 0, or by a default * 100 ms otherwise. */ void __intel_display_power_put_async(struct drm_i915_private *i915, enum intel_display_power_domain domain, intel_wakeref_t wakeref, int delay_ms) { … } /** * intel_display_power_flush_work - flushes the async display power disabling work * @i915: i915 device instance * * Flushes any pending work that was scheduled by a preceding * intel_display_power_put_async() call, completing the disabling of the * corresponding power domains. * * Note that the work handler function may still be running after this * function returns; to ensure that the work handler isn't running use * intel_display_power_flush_work_sync() instead. */ void intel_display_power_flush_work(struct drm_i915_private *i915) { … } /** * intel_display_power_flush_work_sync - flushes and syncs the async display power disabling work * @i915: i915 device instance * * Like intel_display_power_flush_work(), but also ensure that the work * handler function is not running any more when this function returns. */ static void intel_display_power_flush_work_sync(struct drm_i915_private *i915) { … } #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) /** * intel_display_power_put - release a power domain reference * @dev_priv: i915 device instance * @domain: power domain to reference * @wakeref: wakeref acquired for the reference that is being released * * This function drops the power domain reference obtained by * intel_display_power_get() and might power down the corresponding hardware * block right away if this is the last reference. */ void intel_display_power_put(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain, intel_wakeref_t wakeref) { … } #else /** * intel_display_power_put_unchecked - release an unchecked power domain reference * @dev_priv: i915 device instance * @domain: power domain to reference * * This function drops the power domain reference obtained by * intel_display_power_get() and might power down the corresponding hardware * block right away if this is the last reference. * * This function is only for the power domain code's internal use to suppress wakeref * tracking when the correspondig debug kconfig option is disabled, should not * be used otherwise. */ void intel_display_power_put_unchecked(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { __intel_display_power_put(dev_priv, domain); intel_runtime_pm_put_unchecked(&dev_priv->runtime_pm); } #endif void intel_display_power_get_in_set(struct drm_i915_private *i915, struct intel_display_power_domain_set *power_domain_set, enum intel_display_power_domain domain) { … } bool intel_display_power_get_in_set_if_enabled(struct drm_i915_private *i915, struct intel_display_power_domain_set *power_domain_set, enum intel_display_power_domain domain) { … } void intel_display_power_put_mask_in_set(struct drm_i915_private *i915, struct intel_display_power_domain_set *power_domain_set, struct intel_power_domain_mask *mask) { … } static int sanitize_disable_power_well_option(const struct drm_i915_private *dev_priv, int disable_power_well) { … } static u32 get_allowed_dc_mask(const struct drm_i915_private *dev_priv, int enable_dc) { … } /** * intel_power_domains_init - initializes the power domain structures * @dev_priv: i915 device instance * * Initializes the power domain structures for @dev_priv depending upon the * supported platform. */ int intel_power_domains_init(struct drm_i915_private *dev_priv) { … } /** * intel_power_domains_cleanup - clean up power domains resources * @dev_priv: i915 device instance * * Release any resources acquired by intel_power_domains_init() */ void intel_power_domains_cleanup(struct drm_i915_private *dev_priv) { … } static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv) { … } static void gen9_dbuf_slice_set(struct drm_i915_private *dev_priv, enum dbuf_slice slice, bool enable) { … } void gen9_dbuf_slices_update(struct drm_i915_private *dev_priv, u8 req_slices) { … } static void gen9_dbuf_enable(struct drm_i915_private *dev_priv) { … } static void gen9_dbuf_disable(struct drm_i915_private *dev_priv) { … } static void gen12_dbuf_slices_config(struct drm_i915_private *dev_priv) { … } static void icl_mbus_init(struct drm_i915_private *dev_priv) { … } static void hsw_assert_cdclk(struct drm_i915_private *dev_priv) { … } static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) { … } static u32 hsw_read_dcomp(struct drm_i915_private *dev_priv) { … } static void hsw_write_dcomp(struct drm_i915_private *dev_priv, u32 val) { … } /* * This function implements pieces of two sequences from BSpec: * - Sequence for display software to disable LCPLL * - Sequence for display software to allow package C8+ * The steps implemented here are just the steps that actually touch the LCPLL * register. Callers should take care of disabling all the display engine * functions, doing the mode unset, fixing interrupts, etc. */ static void hsw_disable_lcpll(struct drm_i915_private *dev_priv, bool switch_to_fclk, bool allow_power_down) { … } /* * Fully restores LCPLL, disallowing power down and switching back to LCPLL * source. */ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv) { … } /* * Package states C8 and deeper are really deep PC states that can only be * reached when all the devices on the system allow it, so even if the graphics * device allows PC8+, it doesn't mean the system will actually get to these * states. Our driver only allows PC8+ when going into runtime PM. * * The requirements for PC8+ are that all the outputs are disabled, the power * well is disabled and most interrupts are disabled, and these are also * requirements for runtime PM. When these conditions are met, we manually do * the other conditions: disable the interrupts, clocks and switch LCPLL refclk * to Fclk. If we're in PC8+ and we get an non-hotplug interrupt, we can hard * hang the machine. * * When we really reach PC8 or deeper states (not just when we allow it) we lose * the state of some registers, so when we come back from PC8+ we need to * restore this state. We don't get into PC8+ if we're not in RC6, so we don't * need to take care of the registers kept by RC6. Notice that this happens even * if we don't put the device in PCI D3 state (which is what currently happens * because of the runtime PM support). * * For more, read "Display Sequences for Package C8" on the hardware * documentation. */ static void hsw_enable_pc8(struct drm_i915_private *dev_priv) { … } static void hsw_disable_pc8(struct drm_i915_private *dev_priv) { … } static void intel_pch_reset_handshake(struct drm_i915_private *dev_priv, bool enable) { … } static void skl_display_core_init(struct drm_i915_private *dev_priv, bool resume) { … } static void skl_display_core_uninit(struct drm_i915_private *dev_priv) { … } static void bxt_display_core_init(struct drm_i915_private *dev_priv, bool resume) { … } static void bxt_display_core_uninit(struct drm_i915_private *dev_priv) { … } struct buddy_page_mask { … }; static const struct buddy_page_mask tgl_buddy_page_masks[] = …; static const struct buddy_page_mask wa_1409767108_buddy_page_masks[] = …; static void tgl_bw_buddy_init(struct drm_i915_private *dev_priv) { … } static void icl_display_core_init(struct drm_i915_private *dev_priv, bool resume) { … } static void icl_display_core_uninit(struct drm_i915_private *dev_priv) { … } static void chv_phy_control_init(struct drm_i915_private *dev_priv) { … } static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv) { … } static bool vlv_punit_is_power_gated(struct drm_i915_private *dev_priv, u32 reg0) { … } static void assert_ved_power_gated(struct drm_i915_private *dev_priv) { … } static void assert_isp_power_gated(struct drm_i915_private *dev_priv) { … } static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv); /** * intel_power_domains_init_hw - initialize hardware power domain state * @i915: i915 device instance * @resume: Called from resume code paths or not * * This function initializes the hardware power domain state and enables all * power wells belonging to the INIT power domain. Power wells in other * domains (and not in the INIT domain) are referenced or disabled by * intel_modeset_readout_hw_state(). After that the reference count of each * power well must match its HW enabled state, see * intel_power_domains_verify_state(). * * It will return with power domains disabled (to be enabled later by * intel_power_domains_enable()) and must be paired with * intel_power_domains_driver_remove(). */ void intel_power_domains_init_hw(struct drm_i915_private *i915, bool resume) { … } /** * intel_power_domains_driver_remove - deinitialize hw power domain state * @i915: i915 device instance * * De-initializes the display power domain HW state. It also ensures that the * device stays powered up so that the driver can be reloaded. * * It must be called with power domains already disabled (after a call to * intel_power_domains_disable()) and must be paired with * intel_power_domains_init_hw(). */ void intel_power_domains_driver_remove(struct drm_i915_private *i915) { … } /** * intel_power_domains_sanitize_state - sanitize power domains state * @i915: i915 device instance * * Sanitize the power domains state during driver loading and system resume. * The function will disable all display power wells that BIOS has enabled * without a user for it (any user for a power well has taken a reference * on it by the time this function is called, after the state of all the * pipe, encoder, etc. HW resources have been sanitized). */ void intel_power_domains_sanitize_state(struct drm_i915_private *i915) { … } /** * intel_power_domains_enable - enable toggling of display power wells * @i915: i915 device instance * * Enable the ondemand enabling/disabling of the display power wells. Note that * power wells not belonging to POWER_DOMAIN_INIT are allowed to be toggled * only at specific points of the display modeset sequence, thus they are not * affected by the intel_power_domains_enable()/disable() calls. The purpose * of these function is to keep the rest of power wells enabled until the end * of display HW readout (which will acquire the power references reflecting * the current HW state). */ void intel_power_domains_enable(struct drm_i915_private *i915) { … } /** * intel_power_domains_disable - disable toggling of display power wells * @i915: i915 device instance * * Disable the ondemand enabling/disabling of the display power wells. See * intel_power_domains_enable() for which power wells this call controls. */ void intel_power_domains_disable(struct drm_i915_private *i915) { … } /** * intel_power_domains_suspend - suspend power domain state * @i915: i915 device instance * @s2idle: specifies whether we go to idle, or deeper sleep * * This function prepares the hardware power domain state before entering * system suspend. * * It must be called with power domains already disabled (after a call to * intel_power_domains_disable()) and paired with intel_power_domains_resume(). */ void intel_power_domains_suspend(struct drm_i915_private *i915, bool s2idle) { … } /** * intel_power_domains_resume - resume power domain state * @i915: i915 device instance * * This function resume the hardware power domain state during system resume. * * It will return with power domain support disabled (to be enabled later by * intel_power_domains_enable()) and must be paired with * intel_power_domains_suspend(). */ void intel_power_domains_resume(struct drm_i915_private *i915) { … } #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) static void intel_power_domains_dump_info(struct drm_i915_private *i915) { … } /** * intel_power_domains_verify_state - verify the HW/SW state for all power wells * @i915: i915 device instance * * Verify if the reference count of each power well matches its HW enabled * state and the total refcount of the domains it belongs to. This must be * called after modeset HW state sanitization, which is responsible for * acquiring reference counts for any power wells in use and disabling the * ones left on by BIOS but not required by any active output. */ static void intel_power_domains_verify_state(struct drm_i915_private *i915) { … } #else static void intel_power_domains_verify_state(struct drm_i915_private *i915) { } #endif void intel_display_power_suspend_late(struct drm_i915_private *i915) { … } void intel_display_power_resume_early(struct drm_i915_private *i915) { … } void intel_display_power_suspend(struct drm_i915_private *i915) { … } void intel_display_power_resume(struct drm_i915_private *i915) { … } void intel_display_power_debug(struct drm_i915_private *i915, struct seq_file *m) { … } struct intel_ddi_port_domains { … }; static const struct intel_ddi_port_domains i9xx_port_domains[] = …; static const struct intel_ddi_port_domains d11_port_domains[] = …; static const struct intel_ddi_port_domains d12_port_domains[] = …; static const struct intel_ddi_port_domains d13_port_domains[] = …; static void intel_port_domains_for_platform(struct drm_i915_private *i915, const struct intel_ddi_port_domains **domains, int *domains_size) { … } static const struct intel_ddi_port_domains * intel_port_domains_for_port(struct drm_i915_private *i915, enum port port) { … } enum intel_display_power_domain intel_display_power_ddi_io_domain(struct drm_i915_private *i915, enum port port) { … } enum intel_display_power_domain intel_display_power_ddi_lanes_domain(struct drm_i915_private *i915, enum port port) { … } static const struct intel_ddi_port_domains * intel_port_domains_for_aux_ch(struct drm_i915_private *i915, enum aux_ch aux_ch) { … } enum intel_display_power_domain intel_display_power_aux_io_domain(struct drm_i915_private *i915, enum aux_ch aux_ch) { … } enum intel_display_power_domain intel_display_power_legacy_aux_domain(struct drm_i915_private *i915, enum aux_ch aux_ch) { … } enum intel_display_power_domain intel_display_power_tbt_aux_domain(struct drm_i915_private *i915, enum aux_ch aux_ch) { … }