]> git.ipfire.org Git - people/ms/linux.git/commitdiff
Merge drm/drm-next into drm-intel-next
authorRodrigo Vivi <rodrigo.vivi@intel.com>
Wed, 15 Sep 2021 14:12:51 +0000 (10:12 -0400)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Wed, 15 Sep 2021 14:12:51 +0000 (10:12 -0400)
Catch-up on 5.15-rc1 and sync with drm-intel-gt-next
to prepare the PXP topic branch.

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
71 files changed:
Documentation/gpu/i915.rst
drivers/gpu/drm/drm_connector.c
drivers/gpu/drm/drm_crtc_internal.h
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/display/g4x_dp.c
drivers/gpu/drm/i915/display/icl_dsi.c
drivers/gpu/drm/i915/display/intel_acpi.c
drivers/gpu/drm/i915/display/intel_acpi.h
drivers/gpu/drm/i915/display/intel_backlight.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_backlight.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_bios.c
drivers/gpu/drm/i915/display/intel_cdclk.c
drivers/gpu/drm/i915/display/intel_connector.c
drivers/gpu/drm/i915/display/intel_ddi.c
drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c
drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_display.h
drivers/gpu/drm/i915/display/intel_display_debugfs.c
drivers/gpu/drm/i915/display/intel_display_types.h
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/intel_dp.h
drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
drivers/gpu/drm/i915/display/intel_dp_hdcp.c
drivers/gpu/drm/i915/display/intel_dp_link_training.c
drivers/gpu/drm/i915/display/intel_dp_mst.c
drivers/gpu/drm/i915/display/intel_dpll.c
drivers/gpu/drm/i915/display/intel_dpll.h
drivers/gpu/drm/i915/display/intel_dpll_mgr.c
drivers/gpu/drm/i915/display/intel_dpll_mgr.h
drivers/gpu/drm/i915/display/intel_dpt.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dpt.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_drrs.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_drrs.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_dsi_dcs_backlight.c
drivers/gpu/drm/i915/display/intel_dvo.c
drivers/gpu/drm/i915/display/intel_fb.c
drivers/gpu/drm/i915/display/intel_fb.h
drivers/gpu/drm/i915/display/intel_fbc.c
drivers/gpu/drm/i915/display/intel_fbc.h
drivers/gpu/drm/i915/display/intel_fbdev.c
drivers/gpu/drm/i915/display/intel_fdi.c
drivers/gpu/drm/i915/display/intel_fdi.h
drivers/gpu/drm/i915/display/intel_frontbuffer.c
drivers/gpu/drm/i915/display/intel_frontbuffer.h
drivers/gpu/drm/i915/display/intel_hdcp.c
drivers/gpu/drm/i915/display/intel_hdmi.c
drivers/gpu/drm/i915/display/intel_lvds.c
drivers/gpu/drm/i915/display/intel_opregion.c
drivers/gpu/drm/i915/display/intel_panel.c
drivers/gpu/drm/i915/display/intel_panel.h
drivers/gpu/drm/i915/display/intel_psr.c
drivers/gpu/drm/i915/display/intel_snps_phy.c
drivers/gpu/drm/i915/display/intel_snps_phy.h
drivers/gpu/drm/i915/display/vlv_dsi.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_irq.h
drivers/gpu/drm/i915/i915_pci.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_pm.h
drivers/gpu/drm/i915/intel_runtime_pm.h
drivers/usb/typec/altmodes/Kconfig
drivers/usb/typec/altmodes/displayport.c
drivers/video/fbdev/efifb.c
include/drm/drm_connector.h
include/drm/drm_displayid.h
include/drm/i915_pciids.h

index 204ebdaadb45abb2415c44a6412db0ee8d4ad79f..101dde3eb1ea939487fe37f9c2e625b239afe273 100644 (file)
@@ -183,26 +183,23 @@ Frame Buffer Compression (FBC)
 Display Refresh Rate Switching (DRRS)
 -------------------------------------
 
-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
    :doc: Display Refresh Rate Switching (DRRS)
 
-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
-   :functions: intel_dp_set_drrs_state
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
+   :functions: intel_drrs_enable
 
-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
-   :functions: intel_edp_drrs_enable
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
+   :functions: intel_drrs_disable
 
-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
-   :functions: intel_edp_drrs_disable
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
+   :functions: intel_drrs_invalidate
 
-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
-   :functions: intel_edp_drrs_invalidate
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
+   :functions: intel_drrs_flush
 
-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
-   :functions: intel_edp_drrs_flush
-
-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
-   :functions: intel_dp_drrs_init
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
+   :functions: intel_drrs_init
 
 DPIO
 ----
index 2ba257b1ae20857662253c96e3487b982c88c0b3..e0a30e0ee86ab77768854d2c0dbde21ae5800c78 100644 (file)
  * support can instead use e.g. drm_helper_hpd_irq_event().
  */
 
+/*
+ * Global connector list for drm_connector_find_by_fwnode().
+ * Note drm_connector_[un]register() first take connector->lock and then
+ * take the connector_list_lock.
+ */
+static DEFINE_MUTEX(connector_list_lock);
+static LIST_HEAD(connector_list);
+
 struct drm_conn_prop_enum_list {
        int type;
        const char *name;
@@ -267,6 +275,7 @@ int drm_connector_init(struct drm_device *dev,
                goto out_put_type_id;
        }
 
+       INIT_LIST_HEAD(&connector->global_connector_list_entry);
        INIT_LIST_HEAD(&connector->probed_modes);
        INIT_LIST_HEAD(&connector->modes);
        mutex_init(&connector->mutex);
@@ -474,6 +483,8 @@ void drm_connector_cleanup(struct drm_connector *connector)
        drm_mode_object_unregister(dev, &connector->base);
        kfree(connector->name);
        connector->name = NULL;
+       fwnode_handle_put(connector->fwnode);
+       connector->fwnode = NULL;
        spin_lock_irq(&dev->mode_config.connector_list_lock);
        list_del(&connector->head);
        dev->mode_config.num_connector--;
@@ -532,6 +543,9 @@ int drm_connector_register(struct drm_connector *connector)
        /* Let userspace know we have a new connector */
        drm_sysfs_hotplug_event(connector->dev);
 
+       mutex_lock(&connector_list_lock);
+       list_add_tail(&connector->global_connector_list_entry, &connector_list);
+       mutex_unlock(&connector_list_lock);
        goto unlock;
 
 err_debugfs:
@@ -560,6 +574,10 @@ void drm_connector_unregister(struct drm_connector *connector)
                return;
        }
 
+       mutex_lock(&connector_list_lock);
+       list_del_init(&connector->global_connector_list_entry);
+       mutex_unlock(&connector_list_lock);
+
        if (connector->funcs->early_unregister)
                connector->funcs->early_unregister(connector);
 
@@ -2543,6 +2561,67 @@ out:
        return ret;
 }
 
+/**
+ * drm_connector_find_by_fwnode - Find a connector based on the associated fwnode
+ * @fwnode: fwnode for which to find the matching drm_connector
+ *
+ * This functions looks up a drm_connector based on its associated fwnode. When
+ * a connector is found a reference to the connector is returned. The caller must
+ * call drm_connector_put() to release this reference when it is done with the
+ * connector.
+ *
+ * Returns: A reference to the found connector or an ERR_PTR().
+ */
+struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode)
+{
+       struct drm_connector *connector, *found = ERR_PTR(-ENODEV);
+
+       if (!fwnode)
+               return ERR_PTR(-ENODEV);
+
+       mutex_lock(&connector_list_lock);
+
+       list_for_each_entry(connector, &connector_list, global_connector_list_entry) {
+               if (connector->fwnode == fwnode ||
+                   (connector->fwnode && connector->fwnode->secondary == fwnode)) {
+                       drm_connector_get(connector);
+                       found = connector;
+                       break;
+               }
+       }
+
+       mutex_unlock(&connector_list_lock);
+
+       return found;
+}
+
+/**
+ * drm_connector_oob_hotplug_event - Report out-of-band hotplug event to connector
+ * @connector: connector to report the event on
+ *
+ * On some hardware a hotplug event notification may come from outside the display
+ * driver / device. An example of this is some USB Type-C setups where the hardware
+ * muxes the DisplayPort data and aux-lines but does not pass the altmode HPD
+ * status bit to the GPU's DP HPD pin.
+ *
+ * This function can be used to report these out-of-band events after obtaining
+ * a drm_connector reference through calling drm_connector_find_by_fwnode().
+ */
+void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode)
+{
+       struct drm_connector *connector;
+
+       connector = drm_connector_find_by_fwnode(connector_fwnode);
+       if (IS_ERR(connector))
+               return;
+
+       if (connector->funcs->oob_hotplug_event)
+               connector->funcs->oob_hotplug_event(connector);
+
+       drm_connector_put(connector);
+}
+EXPORT_SYMBOL(drm_connector_oob_hotplug_event);
+
 
 /**
  * DOC: Tile group
index edb772947cb4a928896d501e6bf7358343b2ef62..63279e984342cd0f293e7d7e1d4cdc51934c2286 100644 (file)
@@ -58,6 +58,7 @@ struct drm_property;
 struct edid;
 struct kref;
 struct work_struct;
+struct fwnode_handle;
 
 /* drm_crtc.c */
 int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
@@ -186,6 +187,7 @@ int drm_connector_set_obj_prop(struct drm_mode_object *obj,
 int drm_connector_create_standard_properties(struct drm_device *dev);
 const char *drm_get_connector_force_name(enum drm_connector_force force);
 void drm_connector_free_work_fn(struct work_struct *work);
+struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode);
 
 /* IOCTL */
 int drm_connector_property_set_ioctl(struct drm_device *dev,
index 6325877c5fd6e642169f350fa17d08593aaa95a0..c45c225267ca58e66120dbd9133d3a3da052d153 100644 (file)
@@ -28,6 +28,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include <linux/bitfield.h>
 #include <linux/hdmi.h>
 #include <linux/i2c.h>
 #include <linux/kernel.h>
        (((edid)->version > (maj)) || \
         ((edid)->version == (maj) && (edid)->revision > (min)))
 
+static int oui(u8 first, u8 second, u8 third)
+{
+       return (first << 16) | (second << 8) | third;
+}
+
 #define EDID_EST_TIMINGS 16
 #define EDID_STD_TIMINGS 8
 #define EDID_DETAILED_TIMINGS 4
@@ -4113,32 +4119,24 @@ cea_db_offsets(const u8 *cea, int *start, int *end)
 
 static bool cea_db_is_hdmi_vsdb(const u8 *db)
 {
-       int hdmi_id;
-
        if (cea_db_tag(db) != VENDOR_BLOCK)
                return false;
 
        if (cea_db_payload_len(db) < 5)
                return false;
 
-       hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16);
-
-       return hdmi_id == HDMI_IEEE_OUI;
+       return oui(db[3], db[2], db[1]) == HDMI_IEEE_OUI;
 }
 
 static bool cea_db_is_hdmi_forum_vsdb(const u8 *db)
 {
-       unsigned int oui;
-
        if (cea_db_tag(db) != VENDOR_BLOCK)
                return false;
 
        if (cea_db_payload_len(db) < 7)
                return false;
 
-       oui = db[3] << 16 | db[2] << 8 | db[1];
-
-       return oui == HDMI_FORUM_IEEE_OUI;
+       return oui(db[3], db[2], db[1]) == HDMI_FORUM_IEEE_OUI;
 }
 
 static bool cea_db_is_vcdb(const u8 *db)
@@ -5148,6 +5146,71 @@ void drm_get_monitor_range(struct drm_connector *connector,
                      info->monitor_range.max_vfreq);
 }
 
+static void drm_parse_vesa_mso_data(struct drm_connector *connector,
+                                   const struct displayid_block *block)
+{
+       struct displayid_vesa_vendor_specific_block *vesa =
+               (struct displayid_vesa_vendor_specific_block *)block;
+       struct drm_display_info *info = &connector->display_info;
+
+       if (block->num_bytes < 3) {
+               drm_dbg_kms(connector->dev, "Unexpected vendor block size %u\n",
+                           block->num_bytes);
+               return;
+       }
+
+       if (oui(vesa->oui[0], vesa->oui[1], vesa->oui[2]) != VESA_IEEE_OUI)
+               return;
+
+       if (sizeof(*vesa) != sizeof(*block) + block->num_bytes) {
+               drm_dbg_kms(connector->dev, "Unexpected VESA vendor block size\n");
+               return;
+       }
+
+       switch (FIELD_GET(DISPLAYID_VESA_MSO_MODE, vesa->mso)) {
+       default:
+               drm_dbg_kms(connector->dev, "Reserved MSO mode value\n");
+               fallthrough;
+       case 0:
+               info->mso_stream_count = 0;
+               break;
+       case 1:
+               info->mso_stream_count = 2; /* 2 or 4 links */
+               break;
+       case 2:
+               info->mso_stream_count = 4; /* 4 links */
+               break;
+       }
+
+       if (!info->mso_stream_count) {
+               info->mso_pixel_overlap = 0;
+               return;
+       }
+
+       info->mso_pixel_overlap = FIELD_GET(DISPLAYID_VESA_MSO_OVERLAP, vesa->mso);
+       if (info->mso_pixel_overlap > 8) {
+               drm_dbg_kms(connector->dev, "Reserved MSO pixel overlap value %u\n",
+                           info->mso_pixel_overlap);
+               info->mso_pixel_overlap = 8;
+       }
+
+       drm_dbg_kms(connector->dev, "MSO stream count %u, pixel overlap %u\n",
+                   info->mso_stream_count, info->mso_pixel_overlap);
+}
+
+static void drm_update_mso(struct drm_connector *connector, const struct edid *edid)
+{
+       const struct displayid_block *block;
+       struct displayid_iter iter;
+
+       displayid_iter_edid_begin(edid, &iter);
+       displayid_iter_for_each(block, &iter) {
+               if (block->tag == DATA_BLOCK_2_VENDOR_SPECIFIC)
+                       drm_parse_vesa_mso_data(connector, block);
+       }
+       displayid_iter_end(&iter);
+}
+
 /* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
  * all of the values which would have been set from EDID
  */
@@ -5171,6 +5234,9 @@ drm_reset_display_info(struct drm_connector *connector)
 
        info->non_desktop = 0;
        memset(&info->monitor_range, 0, sizeof(info->monitor_range));
+
+       info->mso_stream_count = 0;
+       info->mso_pixel_overlap = 0;
 }
 
 u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
@@ -5249,6 +5315,9 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi
                info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
        if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
                info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
+
+       drm_update_mso(connector, edid);
+
        return quirks;
 }
 
index 968a9560b4aa312798540d6bab32e27c883cb612..76ff6ec3421b0a776d5f6244aed80972b39c884f 100644 (file)
@@ -10,6 +10,7 @@
  * Copyright (c) 2003-2004 IBM Corp.
  */
 
+#include <linux/acpi.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/export.h>
@@ -50,8 +51,45 @@ static struct device_type drm_sysfs_device_minor = {
        .name = "drm_minor"
 };
 
+static struct device_type drm_sysfs_device_connector = {
+       .name = "drm_connector",
+};
+
 struct class *drm_class;
 
+#ifdef CONFIG_ACPI
+static bool drm_connector_acpi_bus_match(struct device *dev)
+{
+       return dev->type == &drm_sysfs_device_connector;
+}
+
+static struct acpi_device *drm_connector_acpi_find_companion(struct device *dev)
+{
+       struct drm_connector *connector = to_drm_connector(dev);
+
+       return to_acpi_device_node(connector->fwnode);
+}
+
+static struct acpi_bus_type drm_connector_acpi_bus = {
+       .name = "drm_connector",
+       .match = drm_connector_acpi_bus_match,
+       .find_companion = drm_connector_acpi_find_companion,
+};
+
+static void drm_sysfs_acpi_register(void)
+{
+       register_acpi_bus_type(&drm_connector_acpi_bus);
+}
+
+static void drm_sysfs_acpi_unregister(void)
+{
+       unregister_acpi_bus_type(&drm_connector_acpi_bus);
+}
+#else
+static void drm_sysfs_acpi_register(void) { }
+static void drm_sysfs_acpi_unregister(void) { }
+#endif
+
 static char *drm_devnode(struct device *dev, umode_t *mode)
 {
        return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
@@ -85,6 +123,8 @@ int drm_sysfs_init(void)
        }
 
        drm_class->devnode = drm_devnode;
+
+       drm_sysfs_acpi_register();
        return 0;
 }
 
@@ -97,11 +137,17 @@ void drm_sysfs_destroy(void)
 {
        if (IS_ERR_OR_NULL(drm_class))
                return;
+       drm_sysfs_acpi_unregister();
        class_remove_file(drm_class, &class_attr_version.attr);
        class_destroy(drm_class);
        drm_class = NULL;
 }
 
+static void drm_sysfs_release(struct device *dev)
+{
+       kfree(dev);
+}
+
 /*
  * Connector properties
  */
@@ -273,27 +319,47 @@ static const struct attribute_group *connector_dev_groups[] = {
 int drm_sysfs_connector_add(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
+       struct device *kdev;
+       int r;
 
        if (connector->kdev)
                return 0;
 
-       connector->kdev =
-               device_create_with_groups(drm_class, dev->primary->kdev, 0,
-                                         connector, connector_dev_groups,
-                                         "card%d-%s", dev->primary->index,
-                                         connector->name);
+       kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
+       if (!kdev)
+               return -ENOMEM;
+
+       device_initialize(kdev);
+       kdev->class = drm_class;
+       kdev->type = &drm_sysfs_device_connector;
+       kdev->parent = dev->primary->kdev;
+       kdev->groups = connector_dev_groups;
+       kdev->release = drm_sysfs_release;
+       dev_set_drvdata(kdev, connector);
+
+       r = dev_set_name(kdev, "card%d-%s", dev->primary->index, connector->name);
+       if (r)
+               goto err_free;
+
        DRM_DEBUG("adding \"%s\" to sysfs\n",
                  connector->name);
 
-       if (IS_ERR(connector->kdev)) {
-               DRM_ERROR("failed to register connector device: %ld\n", PTR_ERR(connector->kdev));
-               return PTR_ERR(connector->kdev);
+       r = device_add(kdev);
+       if (r) {
+               drm_err(dev, "failed to register connector device: %d\n", r);
+               goto err_free;
        }
 
+       connector->kdev = kdev;
+
        if (connector->ddc)
                return sysfs_create_link(&connector->kdev->kobj,
                                 &connector->ddc->dev.kobj, "ddc");
        return 0;
+
+err_free:
+       put_device(kdev);
+       return r;
 }
 
 void drm_sysfs_connector_remove(struct drm_connector *connector)
@@ -374,11 +440,6 @@ void drm_sysfs_connector_status_event(struct drm_connector *connector,
 }
 EXPORT_SYMBOL(drm_sysfs_connector_status_event);
 
-static void drm_sysfs_release(struct device *dev)
-{
-       kfree(dev);
-}
-
 struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
 {
        const char *minor_str;
index 642a5b5a1b81c4cf803c06e74eddd9ff9453a13d..c36c8a4f071637896631cd5d49e209a8fbc0211c 100644 (file)
@@ -212,6 +212,8 @@ i915-y += \
        display/intel_dpio_phy.o \
        display/intel_dpll.o \
        display/intel_dpll_mgr.o \
+       display/intel_dpt.o \
+       display/intel_drrs.o \
        display/intel_dsb.o \
        display/intel_fb.o \
        display/intel_fbc.o \
@@ -248,6 +250,7 @@ i915-y += \
        display/g4x_dp.o \
        display/g4x_hdmi.o \
        display/icl_dsi.o \
+       display/intel_backlight.o \
        display/intel_crt.o \
        display/intel_ddi.o \
        display/intel_ddi_buf_trans.o \
index de0f358184aa337f49c11f1ea865182f80b5d6f1..9577f6843f79cab3b1d0e7870a2c70897c38b17a 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "g4x_dp.h"
 #include "intel_audio.h"
+#include "intel_backlight.h"
 #include "intel_connector.h"
 #include "intel_de.h"
 #include "intel_display_types.h"
@@ -16,7 +17,6 @@
 #include "intel_fifo_underrun.h"
 #include "intel_hdmi.h"
 #include "intel_hotplug.h"
-#include "intel_panel.h"
 #include "intel_pps.h"
 #include "intel_sideband.h"
 
@@ -1334,7 +1334,7 @@ bool g4x_dp_init(struct drm_i915_private *dev_priv,
        intel_encoder->get_config = intel_dp_get_config;
        intel_encoder->sync_state = intel_dp_sync_state;
        intel_encoder->initial_fastset_check = intel_dp_initial_fastset_check;
-       intel_encoder->update_pipe = intel_panel_update_backlight;
+       intel_encoder->update_pipe = intel_backlight_update;
        intel_encoder->suspend = intel_dp_encoder_suspend;
        intel_encoder->shutdown = intel_dp_encoder_shutdown;
        if (IS_CHERRYVIEW(dev_priv)) {
index 43ec7fcd3f5d284c08d275640d110b69ae64a159..060bc8fb0d3072d22b0a81a759e340c241d3b39d 100644 (file)
@@ -29,6 +29,7 @@
 #include <drm/drm_mipi_dsi.h>
 
 #include "intel_atomic.h"
+#include "intel_backlight.h"
 #include "intel_combo_phy.h"
 #include "intel_connector.h"
 #include "intel_crtc.h"
@@ -54,20 +55,28 @@ static int payload_credits_available(struct drm_i915_private *dev_priv,
                >> FREE_PLOAD_CREDIT_SHIFT;
 }
 
-static void wait_for_header_credits(struct drm_i915_private *dev_priv,
-                                   enum transcoder dsi_trans)
+static bool wait_for_header_credits(struct drm_i915_private *dev_priv,
+                                   enum transcoder dsi_trans, int hdr_credit)
 {
        if (wait_for_us(header_credits_available(dev_priv, dsi_trans) >=
-                       MAX_HEADER_CREDIT, 100))
+                       hdr_credit, 100)) {
                drm_err(&dev_priv->drm, "DSI header credits not released\n");
+               return false;
+       }
+
+       return true;
 }
 
-static void wait_for_payload_credits(struct drm_i915_private *dev_priv,
-                                    enum transcoder dsi_trans)
+static bool wait_for_payload_credits(struct drm_i915_private *dev_priv,
+                                    enum transcoder dsi_trans, int payld_credit)
 {
        if (wait_for_us(payload_credits_available(dev_priv, dsi_trans) >=
-                       MAX_PLOAD_CREDIT, 100))
+                       payld_credit, 100)) {
                drm_err(&dev_priv->drm, "DSI payload credits not released\n");
+               return false;
+       }
+
+       return true;
 }
 
 static enum transcoder dsi_port_to_transcoder(enum port port)
@@ -90,8 +99,8 @@ static void wait_for_cmds_dispatched_to_panel(struct intel_encoder *encoder)
        /* wait for header/payload credits to be released */
        for_each_dsi_port(port, intel_dsi->ports) {
                dsi_trans = dsi_port_to_transcoder(port);
-               wait_for_header_credits(dev_priv, dsi_trans);
-               wait_for_payload_credits(dev_priv, dsi_trans);
+               wait_for_header_credits(dev_priv, dsi_trans, MAX_HEADER_CREDIT);
+               wait_for_payload_credits(dev_priv, dsi_trans, MAX_PLOAD_CREDIT);
        }
 
        /* send nop DCS command */
@@ -108,7 +117,7 @@ static void wait_for_cmds_dispatched_to_panel(struct intel_encoder *encoder)
        /* wait for header credits to be released */
        for_each_dsi_port(port, intel_dsi->ports) {
                dsi_trans = dsi_port_to_transcoder(port);
-               wait_for_header_credits(dev_priv, dsi_trans);
+               wait_for_header_credits(dev_priv, dsi_trans, MAX_HEADER_CREDIT);
        }
 
        /* wait for LP TX in progress bit to be cleared */
@@ -126,18 +135,13 @@ static bool add_payld_to_queue(struct intel_dsi_host *host, const u8 *data,
        struct intel_dsi *intel_dsi = host->intel_dsi;
        struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
        enum transcoder dsi_trans = dsi_port_to_transcoder(host->port);
-       int free_credits;
        int i, j;
 
        for (i = 0; i < len; i += 4) {
                u32 tmp = 0;
 
-               free_credits = payload_credits_available(dev_priv, dsi_trans);
-               if (free_credits < 1) {
-                       drm_err(&dev_priv->drm,
-                               "Payload credit not available\n");
+               if (!wait_for_payload_credits(dev_priv, dsi_trans, 1))
                        return false;
-               }
 
                for (j = 0; j < min_t(u32, len - i, 4); j++)
                        tmp |= *data++ << 8 * j;
@@ -155,15 +159,10 @@ static int dsi_send_pkt_hdr(struct intel_dsi_host *host,
        struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
        enum transcoder dsi_trans = dsi_port_to_transcoder(host->port);
        u32 tmp;
-       int free_credits;
 
        /* check if header credit available */
-       free_credits = header_credits_available(dev_priv, dsi_trans);
-       if (free_credits < 1) {
-               drm_err(&dev_priv->drm,
-                       "send pkt header failed, not enough hdr credits\n");
+       if (!wait_for_header_credits(dev_priv, dsi_trans, 1))
                return -1;
-       }
 
        tmp = intel_de_read(dev_priv, DSI_CMD_TXHDR(dsi_trans));
 
@@ -1270,6 +1269,26 @@ static void icl_apply_kvmr_pipe_a_wa(struct intel_encoder *encoder,
                             IGNORE_KVMR_PIPE_A,
                             enable ? IGNORE_KVMR_PIPE_A : 0);
 }
+
+/*
+ * Wa_16012360555:adl-p
+ * SW will have to program the "LP to HS Wakeup Guardband"
+ * to account for the repeaters on the HS Request/Ready
+ * PPI signaling between the Display engine and the DPHY.
+ */
+static void adlp_set_lp_hs_wakeup_gb(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
+       enum port port;
+
+       if (DISPLAY_VER(i915) == 13) {
+               for_each_dsi_port(port, intel_dsi->ports)
+                       intel_de_rmw(i915, TGL_DSI_CHKN_REG(port),
+                                    TGL_DSI_CHKN_LSHS_GB, 0x4);
+       }
+}
+
 static void gen11_dsi_enable(struct intel_atomic_state *state,
                             struct intel_encoder *encoder,
                             const struct intel_crtc_state *crtc_state,
@@ -1283,11 +1302,14 @@ static void gen11_dsi_enable(struct intel_atomic_state *state,
        /* Wa_1409054076:icl,jsl,ehl */
        icl_apply_kvmr_pipe_a_wa(encoder, crtc->pipe, true);
 
+       /* Wa_16012360555:adl-p */
+       adlp_set_lp_hs_wakeup_gb(encoder);
+
        /* step6d: enable dsi transcoder */
        gen11_dsi_enable_transcoder(encoder);
 
        /* step7: enable backlight */
-       intel_panel_enable_backlight(crtc_state, conn_state);
+       intel_backlight_enable(crtc_state, conn_state);
        intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
 
        intel_crtc_vblank_on(crtc_state);
@@ -1440,7 +1462,7 @@ static void gen11_dsi_disable(struct intel_atomic_state *state,
 
        /* step1: turn off backlight */
        intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF);
-       intel_panel_disable_backlight(old_conn_state);
+       intel_backlight_disable(old_conn_state);
 
        /* step2d,e: disable transcoder and wait */
        gen11_dsi_disable_transcoder(encoder);
@@ -1651,9 +1673,9 @@ static int gen11_dsi_compute_config(struct intel_encoder *encoder,
        int ret;
 
        pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-       intel_fixed_panel_mode(fixed_mode, adjusted_mode);
+       intel_panel_fixed_mode(fixed_mode, adjusted_mode);
 
-       ret = intel_pch_panel_fitting(pipe_config, conn_state);
+       ret = intel_panel_fitting(pipe_config, conn_state);
        if (ret)
                return ret;
 
@@ -1809,11 +1831,6 @@ static ssize_t gen11_dsi_host_transfer(struct mipi_dsi_host *host,
        if (msg->flags & MIPI_DSI_MSG_USE_LPM)
                enable_lpdt = true;
 
-       /* send packet header */
-       ret  = dsi_send_pkt_hdr(intel_dsi_host, dsi_pkt, enable_lpdt);
-       if (ret < 0)
-               return ret;
-
        /* only long packet contains payload */
        if (mipi_dsi_packet_format_is_long(msg->type)) {
                ret = dsi_send_pkt_payld(intel_dsi_host, dsi_pkt);
@@ -1821,6 +1838,11 @@ static ssize_t gen11_dsi_host_transfer(struct mipi_dsi_host *host,
                        return ret;
        }
 
+       /* send packet header */
+       ret  = dsi_send_pkt_hdr(intel_dsi_host, dsi_pkt, enable_lpdt);
+       if (ret < 0)
+               return ret;
+
        //TODO: add payload receive code if needed
 
        ret = sizeof(dsi_pkt.header) + dsi_pkt.payload_length;
@@ -2008,7 +2030,7 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
        encoder->port = port;
        encoder->get_config = gen11_dsi_get_config;
        encoder->sync_state = gen11_dsi_sync_state;
-       encoder->update_pipe = intel_panel_update_backlight;
+       encoder->update_pipe = intel_backlight_update;
        encoder->compute_config = gen11_dsi_compute_config;
        encoder->get_hw_state = gen11_dsi_get_hw_state;
        encoder->initial_fastset_check = gen11_dsi_initial_fastset_check;
@@ -2042,7 +2064,7 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
        }
 
        intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
-       intel_panel_setup_backlight(connector, INVALID_PIPE);
+       intel_backlight_setup(intel_connector, INVALID_PIPE);
 
        if (dev_priv->vbt.dsi.config->dual_link)
                intel_dsi->ports = BIT(PORT_A) | BIT(PORT_B);
index 7cfe91fc05f2470a21133cb2f7d7d3a1bc28e1c6..72cac55c0f0f5892bf8369702f3203553363a76a 100644 (file)
@@ -282,3 +282,49 @@ void intel_acpi_device_id_update(struct drm_i915_private *dev_priv)
        }
        drm_connector_list_iter_end(&conn_iter);
 }
+
+/* NOTE: The connector order must be final before this is called. */
+void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915)
+{
+       struct drm_connector_list_iter conn_iter;
+       struct drm_device *drm_dev = &i915->drm;
+       struct fwnode_handle *fwnode = NULL;
+       struct drm_connector *connector;
+       struct acpi_device *adev;
+
+       drm_connector_list_iter_begin(drm_dev, &conn_iter);
+       drm_for_each_connector_iter(connector, &conn_iter) {
+               /* Always getting the next, even when the last was not used. */
+               fwnode = device_get_next_child_node(drm_dev->dev, fwnode);
+               if (!fwnode)
+                       break;
+
+               switch (connector->connector_type) {
+               case DRM_MODE_CONNECTOR_LVDS:
+               case DRM_MODE_CONNECTOR_eDP:
+               case DRM_MODE_CONNECTOR_DSI:
+                       /*
+                        * Integrated displays have a specific address 0x1f on
+                        * most Intel platforms, but not on all of them.
+                        */
+                       adev = acpi_find_child_device(ACPI_COMPANION(drm_dev->dev),
+                                                     0x1f, 0);
+                       if (adev) {
+                               connector->fwnode =
+                                       fwnode_handle_get(acpi_fwnode_handle(adev));
+                               break;
+                       }
+                       fallthrough;
+               default:
+                       connector->fwnode = fwnode_handle_get(fwnode);
+                       break;
+               }
+       }
+       drm_connector_list_iter_end(&conn_iter);
+       /*
+        * device_get_next_child_node() takes a reference on the fwnode, if
+        * we stopped iterating because we are out of connectors we need to
+        * put this, otherwise fwnode is NULL and the put is a no-op.
+        */
+       fwnode_handle_put(fwnode);
+}
index 9f197401c313cb355dc3ea958cbf5636c97597d7..4a760a2baed9fc685d9f1cc653c01a2c79bdb217 100644 (file)
@@ -13,6 +13,7 @@ void intel_register_dsm_handler(void);
 void intel_unregister_dsm_handler(void);
 void intel_dsm_get_bios_data_funcs_supported(struct drm_i915_private *i915);
 void intel_acpi_device_id_update(struct drm_i915_private *i915);
+void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915);
 #else
 static inline void intel_register_dsm_handler(void) { return; }
 static inline void intel_unregister_dsm_handler(void) { return; }
@@ -20,6 +21,8 @@ static inline
 void intel_dsm_get_bios_data_funcs_supported(struct drm_i915_private *i915) { return; }
 static inline
 void intel_acpi_device_id_update(struct drm_i915_private *i915) { return; }
+static inline
+void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915) { return; }
 #endif /* CONFIG_ACPI */
 
 #endif /* __INTEL_ACPI_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c
new file mode 100644 (file)
index 0000000..9523411
--- /dev/null
@@ -0,0 +1,1776 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright Â© 2021 Intel Corporation
+ */
+
+#include <linux/kernel.h>
+#include <linux/pwm.h>
+
+#include "intel_backlight.h"
+#include "intel_connector.h"
+#include "intel_de.h"
+#include "intel_display_types.h"
+#include "intel_dp_aux_backlight.h"
+#include "intel_dsi_dcs_backlight.h"
+#include "intel_panel.h"
+
+/**
+ * scale - scale values from one range to another
+ * @source_val: value in range [@source_min..@source_max]
+ * @source_min: minimum legal value for @source_val
+ * @source_max: maximum legal value for @source_val
+ * @target_min: corresponding target value for @source_min
+ * @target_max: corresponding target value for @source_max
+ *
+ * Return @source_val in range [@source_min..@source_max] scaled to range
+ * [@target_min..@target_max].
+ */
+static u32 scale(u32 source_val,
+                u32 source_min, u32 source_max,
+                u32 target_min, u32 target_max)
+{
+       u64 target_val;
+
+       WARN_ON(source_min > source_max);
+       WARN_ON(target_min > target_max);
+
+       /* defensive */
+       source_val = clamp(source_val, source_min, source_max);
+
+       /* avoid overflows */
+       target_val = mul_u32_u32(source_val - source_min,
+                                target_max - target_min);
+       target_val = DIV_ROUND_CLOSEST_ULL(target_val, source_max - source_min);
+       target_val += target_min;
+
+       return target_val;
+}
+
+/*
+ * Scale user_level in range [0..user_max] to [0..hw_max], clamping the result
+ * to [hw_min..hw_max].
+ */
+static u32 clamp_user_to_hw(struct intel_connector *connector,
+                           u32 user_level, u32 user_max)
+{
+       struct intel_panel *panel = &connector->panel;
+       u32 hw_level;
+
+       hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max);
+       hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max);
+
+       return hw_level;
+}
+
+/* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */
+static u32 scale_hw_to_user(struct intel_connector *connector,
+                           u32 hw_level, u32 user_max)
+{
+       struct intel_panel *panel = &connector->panel;
+
+       return scale(hw_level, panel->backlight.min, panel->backlight.max,
+                    0, user_max);
+}
+
+u32 intel_backlight_invert_pwm_level(struct intel_connector *connector, u32 val)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0);
+
+       if (dev_priv->params.invert_brightness < 0)
+               return val;
+
+       if (dev_priv->params.invert_brightness > 0 ||
+           dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
+               return panel->backlight.pwm_level_max - val + panel->backlight.pwm_level_min;
+       }
+
+       return val;
+}
+
+void intel_backlight_set_pwm_level(const struct drm_connector_state *conn_state, u32 val)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *i915 = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       drm_dbg_kms(&i915->drm, "set backlight PWM = %d\n", val);
+       panel->backlight.pwm_funcs->set(conn_state, val);
+}
+
+u32 intel_backlight_level_to_pwm(struct intel_connector *connector, u32 val)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       drm_WARN_ON_ONCE(&dev_priv->drm,
+                        panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0);
+
+       val = scale(val, panel->backlight.min, panel->backlight.max,
+                   panel->backlight.pwm_level_min, panel->backlight.pwm_level_max);
+
+       return intel_backlight_invert_pwm_level(connector, val);
+}
+
+u32 intel_backlight_level_from_pwm(struct intel_connector *connector, u32 val)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       drm_WARN_ON_ONCE(&dev_priv->drm,
+                        panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0);
+
+       if (dev_priv->params.invert_brightness > 0 ||
+           (dev_priv->params.invert_brightness == 0 && dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS))
+               val = panel->backlight.pwm_level_max - (val - panel->backlight.pwm_level_min);
+
+       return scale(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max,
+                    panel->backlight.min, panel->backlight.max);
+}
+
+static u32 lpt_get_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       return intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
+}
+
+static u32 pch_get_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       return intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+}
+
+static u32 i9xx_get_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 val;
+
+       val = intel_de_read(dev_priv, BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+       if (DISPLAY_VER(dev_priv) < 4)
+               val >>= 1;
+
+       if (panel->backlight.combination_mode) {
+               u8 lbpc;
+
+               pci_read_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, &lbpc);
+               val *= lbpc;
+       }
+
+       return val;
+}
+
+static u32 vlv_get_backlight(struct intel_connector *connector, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B))
+               return 0;
+
+       return intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK;
+}
+
+static u32 bxt_get_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       return intel_de_read(dev_priv,
+                            BXT_BLC_PWM_DUTY(panel->backlight.controller));
+}
+
+static u32 ext_pwm_get_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct intel_panel *panel = &connector->panel;
+       struct pwm_state state;
+
+       pwm_get_state(panel->backlight.pwm, &state);
+       return pwm_get_relative_duty_cycle(&state, 100);
+}
+
+static void lpt_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       u32 val = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+       intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, val | level);
+}
+
+static void pch_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       u32 tmp;
+
+       tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+       intel_de_write(dev_priv, BLC_PWM_CPU_CTL, tmp | level);
+}
+
+static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 tmp, mask;
+
+       drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0);
+
+       if (panel->backlight.combination_mode) {
+               u8 lbpc;
+
+               lbpc = level * 0xfe / panel->backlight.pwm_level_max + 1;
+               level /= lbpc;
+               pci_write_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, lbpc);
+       }
+
+       if (DISPLAY_VER(dev_priv) == 4) {
+               mask = BACKLIGHT_DUTY_CYCLE_MASK;
+       } else {
+               level <<= 1;
+               mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV;
+       }
+
+       tmp = intel_de_read(dev_priv, BLC_PWM_CTL) & ~mask;
+       intel_de_write(dev_priv, BLC_PWM_CTL, tmp | level);
+}
+
+static void vlv_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe;
+       u32 tmp;
+
+       tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+       intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), tmp | level);
+}
+
+static void bxt_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       intel_de_write(dev_priv,
+                      BXT_BLC_PWM_DUTY(panel->backlight.controller), level);
+}
+
+static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;
+
+       pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
+       pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
+}
+
+static void
+intel_panel_actually_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *i915 = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       drm_dbg_kms(&i915->drm, "set backlight level = %d\n", level);
+
+       panel->backlight.funcs->set(conn_state, level);
+}
+
+/* set backlight brightness to level in range [0..max], assuming hw min is
+ * respected.
+ */
+void intel_backlight_set_acpi(const struct drm_connector_state *conn_state,
+                             u32 user_level, u32 user_max)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 hw_level;
+
+       /*
+        * Lack of crtc may occur during driver init because
+        * connection_mutex isn't held across the entire backlight
+        * setup + modeset readout, and the BIOS can issue the
+        * requests at any time.
+        */
+       if (!panel->backlight.present || !conn_state->crtc)
+               return;
+
+       mutex_lock(&dev_priv->backlight_lock);
+
+       drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0);
+
+       hw_level = clamp_user_to_hw(connector, user_level, user_max);
+       panel->backlight.level = hw_level;
+
+       if (panel->backlight.device)
+               panel->backlight.device->props.brightness =
+                       scale_hw_to_user(connector,
+                                        panel->backlight.level,
+                                        panel->backlight.device->props.max_brightness);
+
+       if (panel->backlight.enabled)
+               intel_panel_actually_set_backlight(conn_state, hw_level);
+
+       mutex_unlock(&dev_priv->backlight_lock);
+}
+
+static void lpt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       u32 tmp;
+
+       intel_backlight_set_pwm_level(old_conn_state, level);
+
+       /*
+        * Although we don't support or enable CPU PWM with LPT/SPT based
+        * systems, it may have been enabled prior to loading the
+        * driver. Disable to avoid warnings on LCPLL disable.
+        *
+        * This needs rework if we need to add support for CPU PWM on PCH split
+        * platforms.
+        */
+       tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
+       if (tmp & BLM_PWM_ENABLE) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "cpu backlight was enabled, disabling\n");
+               intel_de_write(dev_priv, BLC_PWM_CPU_CTL2,
+                              tmp & ~BLM_PWM_ENABLE);
+       }
+
+       tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
+       intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
+}
+
+static void pch_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       u32 tmp;
+
+       intel_backlight_set_pwm_level(old_conn_state, val);
+
+       tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
+       intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
+
+       tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
+       intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
+}
+
+static void i9xx_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
+{
+       intel_backlight_set_pwm_level(old_conn_state, val);
+}
+
+static void i965_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
+{
+       struct drm_i915_private *dev_priv = to_i915(old_conn_state->connector->dev);
+       u32 tmp;
+
+       intel_backlight_set_pwm_level(old_conn_state, val);
+
+       tmp = intel_de_read(dev_priv, BLC_PWM_CTL2);
+       intel_de_write(dev_priv, BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE);
+}
+
+static void vlv_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       enum pipe pipe = to_intel_crtc(old_conn_state->crtc)->pipe;
+       u32 tmp;
+
+       intel_backlight_set_pwm_level(old_conn_state, val);
+
+       tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
+       intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe),
+                      tmp & ~BLM_PWM_ENABLE);
+}
+
+static void bxt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 tmp;
+
+       intel_backlight_set_pwm_level(old_conn_state, val);
+
+       tmp = intel_de_read(dev_priv,
+                           BXT_BLC_PWM_CTL(panel->backlight.controller));
+       intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
+                      tmp & ~BXT_BLC_PWM_ENABLE);
+
+       if (panel->backlight.controller == 1) {
+               val = intel_de_read(dev_priv, UTIL_PIN_CTL);
+               val &= ~UTIL_PIN_ENABLE;
+               intel_de_write(dev_priv, UTIL_PIN_CTL, val);
+       }
+}
+
+static void cnp_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 tmp;
+
+       intel_backlight_set_pwm_level(old_conn_state, val);
+
+       tmp = intel_de_read(dev_priv,
+                           BXT_BLC_PWM_CTL(panel->backlight.controller));
+       intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
+                      tmp & ~BXT_BLC_PWM_ENABLE);
+}
+
+static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct intel_panel *panel = &connector->panel;
+
+       panel->backlight.pwm_state.enabled = false;
+       pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
+}
+
+void intel_backlight_disable(const struct drm_connector_state *old_conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       if (!panel->backlight.present)
+               return;
+
+       /*
+        * Do not disable backlight on the vga_switcheroo path. When switching
+        * away from i915, the other client may depend on i915 to handle the
+        * backlight. This will leave the backlight on unnecessarily when
+        * another client is not activated.
+        */
+       if (dev_priv->drm.switch_power_state == DRM_SWITCH_POWER_CHANGING) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "Skipping backlight disable on vga switch\n");
+               return;
+       }
+
+       mutex_lock(&dev_priv->backlight_lock);
+
+       if (panel->backlight.device)
+               panel->backlight.device->props.power = FB_BLANK_POWERDOWN;
+       panel->backlight.enabled = false;
+       panel->backlight.funcs->disable(old_conn_state, 0);
+
+       mutex_unlock(&dev_priv->backlight_lock);
+}
+
+static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 pch_ctl1, pch_ctl2, schicken;
+
+       pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
+       if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
+               drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n");
+               pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
+               intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1);
+       }
+
+       if (HAS_PCH_LPT(dev_priv)) {
+               schicken = intel_de_read(dev_priv, SOUTH_CHICKEN2);
+               if (panel->backlight.alternate_pwm_increment)
+                       schicken |= LPT_PWM_GRANULARITY;
+               else
+                       schicken &= ~LPT_PWM_GRANULARITY;
+               intel_de_write(dev_priv, SOUTH_CHICKEN2, schicken);
+       } else {
+               schicken = intel_de_read(dev_priv, SOUTH_CHICKEN1);
+               if (panel->backlight.alternate_pwm_increment)
+                       schicken |= SPT_PWM_GRANULARITY;
+               else
+                       schicken &= ~SPT_PWM_GRANULARITY;
+               intel_de_write(dev_priv, SOUTH_CHICKEN1, schicken);
+       }
+
+       pch_ctl2 = panel->backlight.pwm_level_max << 16;
+       intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2);
+
+       pch_ctl1 = 0;
+       if (panel->backlight.active_low_pwm)
+               pch_ctl1 |= BLM_PCH_POLARITY;
+
+       /* After LPT, override is the default. */
+       if (HAS_PCH_LPT(dev_priv))
+               pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE;
+
+       intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1);
+       intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1);
+       intel_de_write(dev_priv, BLC_PWM_PCH_CTL1,
+                      pch_ctl1 | BLM_PCH_PWM_ENABLE);
+
+       /* This won't stick until the above enable. */
+       intel_backlight_set_pwm_level(conn_state, level);
+}
+
+static void pch_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       u32 cpu_ctl2, pch_ctl1, pch_ctl2;
+
+       cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
+       if (cpu_ctl2 & BLM_PWM_ENABLE) {
+               drm_dbg_kms(&dev_priv->drm, "cpu backlight already enabled\n");
+               cpu_ctl2 &= ~BLM_PWM_ENABLE;
+               intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2);
+       }
+
+       pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
+       if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
+               drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n");
+               pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
+               intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1);
+       }
+
+       if (cpu_transcoder == TRANSCODER_EDP)
+               cpu_ctl2 = BLM_TRANSCODER_EDP;
+       else
+               cpu_ctl2 = BLM_PIPE(cpu_transcoder);
+       intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2);
+       intel_de_posting_read(dev_priv, BLC_PWM_CPU_CTL2);
+       intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
+
+       /* This won't stick until the above enable. */
+       intel_backlight_set_pwm_level(conn_state, level);
+
+       pch_ctl2 = panel->backlight.pwm_level_max << 16;
+       intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2);
+
+       pch_ctl1 = 0;
+       if (panel->backlight.active_low_pwm)
+               pch_ctl1 |= BLM_PCH_POLARITY;
+
+       intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1);
+       intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1);
+       intel_de_write(dev_priv, BLC_PWM_PCH_CTL1,
+                      pch_ctl1 | BLM_PCH_PWM_ENABLE);
+}
+
+static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                 const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 ctl, freq;
+
+       ctl = intel_de_read(dev_priv, BLC_PWM_CTL);
+       if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) {
+               drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
+               intel_de_write(dev_priv, BLC_PWM_CTL, 0);
+       }
+
+       freq = panel->backlight.pwm_level_max;
+       if (panel->backlight.combination_mode)
+               freq /= 0xff;
+
+       ctl = freq << 17;
+       if (panel->backlight.combination_mode)
+               ctl |= BLM_LEGACY_MODE;
+       if (IS_PINEVIEW(dev_priv) && panel->backlight.active_low_pwm)
+               ctl |= BLM_POLARITY_PNV;
+
+       intel_de_write(dev_priv, BLC_PWM_CTL, ctl);
+       intel_de_posting_read(dev_priv, BLC_PWM_CTL);
+
+       /* XXX: combine this into above write? */
+       intel_backlight_set_pwm_level(conn_state, level);
+
+       /*
+        * Needed to enable backlight on some 855gm models. BLC_HIST_CTL is
+        * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2
+        * that has backlight.
+        */
+       if (DISPLAY_VER(dev_priv) == 2)
+               intel_de_write(dev_priv, BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE);
+}
+
+static void i965_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                 const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe;
+       u32 ctl, ctl2, freq;
+
+       ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2);
+       if (ctl2 & BLM_PWM_ENABLE) {
+               drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
+               ctl2 &= ~BLM_PWM_ENABLE;
+               intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2);
+       }
+
+       freq = panel->backlight.pwm_level_max;
+       if (panel->backlight.combination_mode)
+               freq /= 0xff;
+
+       ctl = freq << 16;
+       intel_de_write(dev_priv, BLC_PWM_CTL, ctl);
+
+       ctl2 = BLM_PIPE(pipe);
+       if (panel->backlight.combination_mode)
+               ctl2 |= BLM_COMBINATION_MODE;
+       if (panel->backlight.active_low_pwm)
+               ctl2 |= BLM_POLARITY_I965;
+       intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2);
+       intel_de_posting_read(dev_priv, BLC_PWM_CTL2);
+       intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE);
+
+       intel_backlight_set_pwm_level(conn_state, level);
+}
+
+static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
+       u32 ctl, ctl2;
+
+       ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
+       if (ctl2 & BLM_PWM_ENABLE) {
+               drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
+               ctl2 &= ~BLM_PWM_ENABLE;
+               intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2);
+       }
+
+       ctl = panel->backlight.pwm_level_max << 16;
+       intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), ctl);
+
+       /* XXX: combine this into above write? */
+       intel_backlight_set_pwm_level(conn_state, level);
+
+       ctl2 = 0;
+       if (panel->backlight.active_low_pwm)
+               ctl2 |= BLM_POLARITY_I965;
+       intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2);
+       intel_de_posting_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
+       intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe),
+                      ctl2 | BLM_PWM_ENABLE);
+}
+
+static void bxt_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
+       u32 pwm_ctl, val;
+
+       /* Controller 1 uses the utility pin. */
+       if (panel->backlight.controller == 1) {
+               val = intel_de_read(dev_priv, UTIL_PIN_CTL);
+               if (val & UTIL_PIN_ENABLE) {
+                       drm_dbg_kms(&dev_priv->drm,
+                                   "util pin already enabled\n");
+                       val &= ~UTIL_PIN_ENABLE;
+                       intel_de_write(dev_priv, UTIL_PIN_CTL, val);
+               }
+
+               val = 0;
+               if (panel->backlight.util_pin_active_low)
+                       val |= UTIL_PIN_POLARITY;
+               intel_de_write(dev_priv, UTIL_PIN_CTL,
+                              val | UTIL_PIN_PIPE(pipe) | UTIL_PIN_MODE_PWM | UTIL_PIN_ENABLE);
+       }
+
+       pwm_ctl = intel_de_read(dev_priv,
+                               BXT_BLC_PWM_CTL(panel->backlight.controller));
+       if (pwm_ctl & BXT_BLC_PWM_ENABLE) {
+               drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
+               pwm_ctl &= ~BXT_BLC_PWM_ENABLE;
+               intel_de_write(dev_priv,
+                              BXT_BLC_PWM_CTL(panel->backlight.controller),
+                              pwm_ctl);
+       }
+
+       intel_de_write(dev_priv,
+                      BXT_BLC_PWM_FREQ(panel->backlight.controller),
+                      panel->backlight.pwm_level_max);
+
+       intel_backlight_set_pwm_level(conn_state, level);
+
+       pwm_ctl = 0;
+       if (panel->backlight.active_low_pwm)
+               pwm_ctl |= BXT_BLC_PWM_POLARITY;
+
+       intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
+                      pwm_ctl);
+       intel_de_posting_read(dev_priv,
+                             BXT_BLC_PWM_CTL(panel->backlight.controller));
+       intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
+                      pwm_ctl | BXT_BLC_PWM_ENABLE);
+}
+
+static void cnp_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 pwm_ctl;
+
+       pwm_ctl = intel_de_read(dev_priv,
+                               BXT_BLC_PWM_CTL(panel->backlight.controller));
+       if (pwm_ctl & BXT_BLC_PWM_ENABLE) {
+               drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
+               pwm_ctl &= ~BXT_BLC_PWM_ENABLE;
+               intel_de_write(dev_priv,
+                              BXT_BLC_PWM_CTL(panel->backlight.controller),
+                              pwm_ctl);
+       }
+
+       intel_de_write(dev_priv,
+                      BXT_BLC_PWM_FREQ(panel->backlight.controller),
+                      panel->backlight.pwm_level_max);
+
+       intel_backlight_set_pwm_level(conn_state, level);
+
+       pwm_ctl = 0;
+       if (panel->backlight.active_low_pwm)
+               pwm_ctl |= BXT_BLC_PWM_POLARITY;
+
+       intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
+                      pwm_ctl);
+       intel_de_posting_read(dev_priv,
+                             BXT_BLC_PWM_CTL(panel->backlight.controller));
+       intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
+                      pwm_ctl | BXT_BLC_PWM_ENABLE);
+}
+
+static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                    const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct intel_panel *panel = &connector->panel;
+
+       pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
+       panel->backlight.pwm_state.enabled = true;
+       pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
+}
+
+static void __intel_backlight_enable(const struct intel_crtc_state *crtc_state,
+                                    const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct intel_panel *panel = &connector->panel;
+
+       WARN_ON(panel->backlight.max == 0);
+
+       if (panel->backlight.level <= panel->backlight.min) {
+               panel->backlight.level = panel->backlight.max;
+               if (panel->backlight.device)
+                       panel->backlight.device->props.brightness =
+                               scale_hw_to_user(connector,
+                                                panel->backlight.level,
+                                                panel->backlight.device->props.max_brightness);
+       }
+
+       panel->backlight.funcs->enable(crtc_state, conn_state, panel->backlight.level);
+       panel->backlight.enabled = true;
+       if (panel->backlight.device)
+               panel->backlight.device->props.power = FB_BLANK_UNBLANK;
+}
+
+void intel_backlight_enable(const struct intel_crtc_state *crtc_state,
+                           const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
+
+       if (!panel->backlight.present)
+               return;
+
+       drm_dbg_kms(&dev_priv->drm, "pipe %c\n", pipe_name(pipe));
+
+       mutex_lock(&dev_priv->backlight_lock);
+
+       __intel_backlight_enable(crtc_state, conn_state);
+
+       mutex_unlock(&dev_priv->backlight_lock);
+}
+
+#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
+static u32 intel_panel_get_backlight(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 val = 0;
+
+       mutex_lock(&dev_priv->backlight_lock);
+
+       if (panel->backlight.enabled)
+               val = panel->backlight.funcs->get(connector, intel_connector_get_pipe(connector));
+
+       mutex_unlock(&dev_priv->backlight_lock);
+
+       drm_dbg_kms(&dev_priv->drm, "get backlight PWM = %d\n", val);
+       return val;
+}
+
+/* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */
+static u32 scale_user_to_hw(struct intel_connector *connector,
+                           u32 user_level, u32 user_max)
+{
+       struct intel_panel *panel = &connector->panel;
+
+       return scale(user_level, 0, user_max,
+                    panel->backlight.min, panel->backlight.max);
+}
+
+/* set backlight brightness to level in range [0..max], scaling wrt hw min */
+static void intel_panel_set_backlight(const struct drm_connector_state *conn_state,
+                                     u32 user_level, u32 user_max)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 hw_level;
+
+       if (!panel->backlight.present)
+               return;
+
+       mutex_lock(&dev_priv->backlight_lock);
+
+       drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0);
+
+       hw_level = scale_user_to_hw(connector, user_level, user_max);
+       panel->backlight.level = hw_level;
+
+       if (panel->backlight.enabled)
+               intel_panel_actually_set_backlight(conn_state, hw_level);
+
+       mutex_unlock(&dev_priv->backlight_lock);
+}
+
+static int intel_backlight_device_update_status(struct backlight_device *bd)
+{
+       struct intel_connector *connector = bl_get_data(bd);
+       struct intel_panel *panel = &connector->panel;
+       struct drm_device *dev = connector->base.dev;
+
+       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+       DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
+                     bd->props.brightness, bd->props.max_brightness);
+       intel_panel_set_backlight(connector->base.state, bd->props.brightness,
+                                 bd->props.max_brightness);
+
+       /*
+        * Allow flipping bl_power as a sub-state of enabled. Sadly the
+        * backlight class device does not make it easy to differentiate
+        * between callbacks for brightness and bl_power, so our backlight_power
+        * callback needs to take this into account.
+        */
+       if (panel->backlight.enabled) {
+               if (panel->backlight.power) {
+                       bool enable = bd->props.power == FB_BLANK_UNBLANK &&
+                               bd->props.brightness != 0;
+                       panel->backlight.power(connector, enable);
+               }
+       } else {
+               bd->props.power = FB_BLANK_POWERDOWN;
+       }
+
+       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+       return 0;
+}
+
+static int intel_backlight_device_get_brightness(struct backlight_device *bd)
+{
+       struct intel_connector *connector = bl_get_data(bd);
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       intel_wakeref_t wakeref;
+       int ret = 0;
+
+       with_intel_runtime_pm(&dev_priv->runtime_pm, wakeref) {
+               u32 hw_level;
+
+               drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+
+               hw_level = intel_panel_get_backlight(connector);
+               ret = scale_hw_to_user(connector,
+                                      hw_level, bd->props.max_brightness);
+
+               drm_modeset_unlock(&dev->mode_config.connection_mutex);
+       }
+
+       return ret;
+}
+
+static const struct backlight_ops intel_backlight_device_ops = {
+       .update_status = intel_backlight_device_update_status,
+       .get_brightness = intel_backlight_device_get_brightness,
+};
+
+int intel_backlight_device_register(struct intel_connector *connector)
+{
+       struct drm_i915_private *i915 = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       struct backlight_properties props;
+       struct backlight_device *bd;
+       const char *name;
+       int ret = 0;
+
+       if (WARN_ON(panel->backlight.device))
+               return -ENODEV;
+
+       if (!panel->backlight.present)
+               return 0;
+
+       WARN_ON(panel->backlight.max == 0);
+
+       memset(&props, 0, sizeof(props));
+       props.type = BACKLIGHT_RAW;
+
+       /*
+        * Note: Everything should work even if the backlight device max
+        * presented to the userspace is arbitrarily chosen.
+        */
+       props.max_brightness = panel->backlight.max;
+       props.brightness = scale_hw_to_user(connector,
+                                           panel->backlight.level,
+                                           props.max_brightness);
+
+       if (panel->backlight.enabled)
+               props.power = FB_BLANK_UNBLANK;
+       else
+               props.power = FB_BLANK_POWERDOWN;
+
+       name = kstrdup("intel_backlight", GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+
+       bd = backlight_device_register(name, connector->base.kdev, connector,
+                                      &intel_backlight_device_ops, &props);
+
+       /*
+        * Using the same name independent of the drm device or connector
+        * prevents registration of multiple backlight devices in the
+        * driver. However, we need to use the default name for backward
+        * compatibility. Use unique names for subsequent backlight devices as a
+        * fallback when the default name already exists.
+        */
+       if (IS_ERR(bd) && PTR_ERR(bd) == -EEXIST) {
+               kfree(name);
+               name = kasprintf(GFP_KERNEL, "card%d-%s-backlight",
+                                i915->drm.primary->index, connector->base.name);
+               if (!name)
+                       return -ENOMEM;
+
+               bd = backlight_device_register(name, connector->base.kdev, connector,
+                                              &intel_backlight_device_ops, &props);
+       }
+
+       if (IS_ERR(bd)) {
+               drm_err(&i915->drm,
+                       "[CONNECTOR:%d:%s] backlight device %s register failed: %ld\n",
+                       connector->base.base.id, connector->base.name, name, PTR_ERR(bd));
+               ret = PTR_ERR(bd);
+               goto out;
+       }
+
+       panel->backlight.device = bd;
+
+       drm_dbg_kms(&i915->drm,
+                   "[CONNECTOR:%d:%s] backlight device %s registered\n",
+                   connector->base.base.id, connector->base.name, name);
+
+out:
+       kfree(name);
+
+       return ret;
+}
+
+void intel_backlight_device_unregister(struct intel_connector *connector)
+{
+       struct intel_panel *panel = &connector->panel;
+
+       if (panel->backlight.device) {
+               backlight_device_unregister(panel->backlight.device);
+               panel->backlight.device = NULL;
+       }
+}
+#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
+
+/*
+ * CNP: PWM clock frequency is 19.2 MHz or 24 MHz.
+ *      PWM increment = 1
+ */
+static u32 cnp_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq),
+                                pwm_freq_hz);
+}
+
+/*
+ * BXT: PWM clock frequency = 19.2 MHz.
+ */
+static u32 bxt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       return DIV_ROUND_CLOSEST(KHz(19200), pwm_freq_hz);
+}
+
+/*
+ * SPT: This value represents the period of the PWM stream in clock periods
+ * multiplied by 16 (default increment) or 128 (alternate increment selected in
+ * SCHICKEN_1 bit 0). PWM clock is 24 MHz.
+ */
+static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct intel_panel *panel = &connector->panel;
+       u32 mul;
+
+       if (panel->backlight.alternate_pwm_increment)
+               mul = 128;
+       else
+               mul = 16;
+
+       return DIV_ROUND_CLOSEST(MHz(24), pwm_freq_hz * mul);
+}
+
+/*
+ * LPT: This value represents the period of the PWM stream in clock periods
+ * multiplied by 128 (default increment) or 16 (alternate increment, selected in
+ * LPT SOUTH_CHICKEN2 register bit 5).
+ */
+static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 mul, clock;
+
+       if (panel->backlight.alternate_pwm_increment)
+               mul = 16;
+       else
+               mul = 128;
+
+       if (HAS_PCH_LPT_H(dev_priv))
+               clock = MHz(135); /* LPT:H */
+       else
+               clock = MHz(24); /* LPT:LP */
+
+       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
+}
+
+/*
+ * ILK/SNB/IVB: This value represents the period of the PWM stream in PCH
+ * display raw clocks multiplied by 128.
+ */
+static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq),
+                                pwm_freq_hz * 128);
+}
+
+/*
+ * Gen2: This field determines the number of time base events (display core
+ * clock frequency/32) in total for a complete cycle of modulated backlight
+ * control.
+ *
+ * Gen3: A time base event equals the display core clock ([DevPNV] HRAW clock)
+ * divided by 32.
+ */
+static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       int clock;
+
+       if (IS_PINEVIEW(dev_priv))
+               clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq);
+       else
+               clock = KHz(dev_priv->cdclk.hw.cdclk);
+
+       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 32);
+}
+
+/*
+ * Gen4: This value represents the period of the PWM stream in display core
+ * clocks ([DevCTG] HRAW clocks) multiplied by 128.
+ *
+ */
+static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       int clock;
+
+       if (IS_G4X(dev_priv))
+               clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq);
+       else
+               clock = KHz(dev_priv->cdclk.hw.cdclk);
+
+       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 128);
+}
+
+/*
+ * VLV: This value represents the period of the PWM stream in display core
+ * clocks ([DevCTG] 200MHz HRAW clocks) multiplied by 128 or 25MHz S0IX clocks
+ * multiplied by 16. CHV uses a 19.2MHz S0IX clock.
+ */
+static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       int mul, clock;
+
+       if ((intel_de_read(dev_priv, CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) {
+               if (IS_CHERRYVIEW(dev_priv))
+                       clock = KHz(19200);
+               else
+                       clock = MHz(25);
+               mul = 16;
+       } else {
+               clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq);
+               mul = 128;
+       }
+
+       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
+}
+
+static u16 get_vbt_pwm_freq(struct drm_i915_private *dev_priv)
+{
+       u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz;
+
+       if (pwm_freq_hz) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "VBT defined backlight frequency %u Hz\n",
+                           pwm_freq_hz);
+       } else {
+               pwm_freq_hz = 200;
+               drm_dbg_kms(&dev_priv->drm,
+                           "default backlight frequency %u Hz\n",
+                           pwm_freq_hz);
+       }
+
+       return pwm_freq_hz;
+}
+
+static u32 get_backlight_max_vbt(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv);
+       u32 pwm;
+
+       if (!panel->backlight.pwm_funcs->hz_to_pwm) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "backlight frequency conversion not supported\n");
+               return 0;
+       }
+
+       pwm = panel->backlight.pwm_funcs->hz_to_pwm(connector, pwm_freq_hz);
+       if (!pwm) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "backlight frequency conversion failed\n");
+               return 0;
+       }
+
+       return pwm;
+}
+
+/*
+ * Note: The setup hooks can't assume pipe is set!
+ */
+static u32 get_backlight_min_vbt(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       int min;
+
+       drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0);
+
+       /*
+        * XXX: If the vbt value is 255, it makes min equal to max, which leads
+        * to problems. There are such machines out there. Either our
+        * interpretation is wrong or the vbt has bogus data. Or both. Safeguard
+        * against this by letting the minimum be at most (arbitrarily chosen)
+        * 25% of the max.
+        */
+       min = clamp_t(int, dev_priv->vbt.backlight.min_brightness, 0, 64);
+       if (min != dev_priv->vbt.backlight.min_brightness) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "clamping VBT min backlight %d/255 to %d/255\n",
+                           dev_priv->vbt.backlight.min_brightness, min);
+       }
+
+       /* vbt value is a coefficient in range [0..255] */
+       return scale(min, 0, 255, 0, panel->backlight.pwm_level_max);
+}
+
+static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
+       bool alt, cpu_mode;
+
+       if (HAS_PCH_LPT(dev_priv))
+               alt = intel_de_read(dev_priv, SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY;
+       else
+               alt = intel_de_read(dev_priv, SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY;
+       panel->backlight.alternate_pwm_increment = alt;
+
+       pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
+       panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
+
+       pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2);
+       panel->backlight.pwm_level_max = pch_ctl2 >> 16;
+
+       cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
+
+       if (!panel->backlight.pwm_level_max)
+               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
+
+       if (!panel->backlight.pwm_level_max)
+               return -ENODEV;
+
+       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
+
+       panel->backlight.pwm_enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE;
+
+       cpu_mode = panel->backlight.pwm_enabled && HAS_PCH_LPT(dev_priv) &&
+                  !(pch_ctl1 & BLM_PCH_OVERRIDE_ENABLE) &&
+                  (cpu_ctl2 & BLM_PWM_ENABLE);
+
+       if (cpu_mode) {
+               val = pch_get_backlight(connector, unused);
+
+               drm_dbg_kms(&dev_priv->drm,
+                           "CPU backlight register was enabled, switching to PCH override\n");
+
+               /* Write converted CPU PWM value to PCH override register */
+               lpt_set_backlight(connector->base.state, val);
+               intel_de_write(dev_priv, BLC_PWM_PCH_CTL1,
+                              pch_ctl1 | BLM_PCH_OVERRIDE_ENABLE);
+
+               intel_de_write(dev_priv, BLC_PWM_CPU_CTL2,
+                              cpu_ctl2 & ~BLM_PWM_ENABLE);
+       }
+
+       return 0;
+}
+
+static int pch_setup_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 cpu_ctl2, pch_ctl1, pch_ctl2;
+
+       pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
+       panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
+
+       pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2);
+       panel->backlight.pwm_level_max = pch_ctl2 >> 16;
+
+       if (!panel->backlight.pwm_level_max)
+               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
+
+       if (!panel->backlight.pwm_level_max)
+               return -ENODEV;
+
+       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
+
+       cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
+       panel->backlight.pwm_enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
+               (pch_ctl1 & BLM_PCH_PWM_ENABLE);
+
+       return 0;
+}
+
+static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 ctl, val;
+
+       ctl = intel_de_read(dev_priv, BLC_PWM_CTL);
+
+       if (DISPLAY_VER(dev_priv) == 2 || IS_I915GM(dev_priv) || IS_I945GM(dev_priv))
+               panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
+
+       if (IS_PINEVIEW(dev_priv))
+               panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;
+
+       panel->backlight.pwm_level_max = ctl >> 17;
+
+       if (!panel->backlight.pwm_level_max) {
+               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
+               panel->backlight.pwm_level_max >>= 1;
+       }
+
+       if (!panel->backlight.pwm_level_max)
+               return -ENODEV;
+
+       if (panel->backlight.combination_mode)
+               panel->backlight.pwm_level_max *= 0xff;
+
+       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
+
+       val = i9xx_get_backlight(connector, unused);
+       val = intel_backlight_invert_pwm_level(connector, val);
+       val = clamp(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max);
+
+       panel->backlight.pwm_enabled = val != 0;
+
+       return 0;
+}
+
+static int i965_setup_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 ctl, ctl2;
+
+       ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2);
+       panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE;
+       panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
+
+       ctl = intel_de_read(dev_priv, BLC_PWM_CTL);
+       panel->backlight.pwm_level_max = ctl >> 16;
+
+       if (!panel->backlight.pwm_level_max)
+               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
+
+       if (!panel->backlight.pwm_level_max)
+               return -ENODEV;
+
+       if (panel->backlight.combination_mode)
+               panel->backlight.pwm_level_max *= 0xff;
+
+       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
+
+       panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE;
+
+       return 0;
+}
+
+static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 ctl, ctl2;
+
+       if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B))
+               return -ENODEV;
+
+       ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
+       panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
+
+       ctl = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe));
+       panel->backlight.pwm_level_max = ctl >> 16;
+
+       if (!panel->backlight.pwm_level_max)
+               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
+
+       if (!panel->backlight.pwm_level_max)
+               return -ENODEV;
+
+       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
+
+       panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE;
+
+       return 0;
+}
+
+static int
+bxt_setup_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 pwm_ctl, val;
+
+       panel->backlight.controller = dev_priv->vbt.backlight.controller;
+
+       pwm_ctl = intel_de_read(dev_priv,
+                               BXT_BLC_PWM_CTL(panel->backlight.controller));
+
+       /* Controller 1 uses the utility pin. */
+       if (panel->backlight.controller == 1) {
+               val = intel_de_read(dev_priv, UTIL_PIN_CTL);
+               panel->backlight.util_pin_active_low =
+                                       val & UTIL_PIN_POLARITY;
+       }
+
+       panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
+       panel->backlight.pwm_level_max =
+               intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller));
+
+       if (!panel->backlight.pwm_level_max)
+               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
+
+       if (!panel->backlight.pwm_level_max)
+               return -ENODEV;
+
+       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
+
+       panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
+
+       return 0;
+}
+
+static int
+cnp_setup_backlight(struct intel_connector *connector, enum pipe unused)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       u32 pwm_ctl;
+
+       /*
+        * CNP has the BXT implementation of backlight, but with only one
+        * controller. TODO: ICP has multiple controllers but we only use
+        * controller 0 for now.
+        */
+       panel->backlight.controller = 0;
+
+       pwm_ctl = intel_de_read(dev_priv,
+                               BXT_BLC_PWM_CTL(panel->backlight.controller));
+
+       panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
+       panel->backlight.pwm_level_max =
+               intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller));
+
+       if (!panel->backlight.pwm_level_max)
+               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
+
+       if (!panel->backlight.pwm_level_max)
+               return -ENODEV;
+
+       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
+
+       panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
+
+       return 0;
+}
+
+static int ext_pwm_setup_backlight(struct intel_connector *connector,
+                                  enum pipe pipe)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_panel *panel = &connector->panel;
+       const char *desc;
+       u32 level;
+
+       /* Get the right PWM chip for DSI backlight according to VBT */
+       if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) {
+               panel->backlight.pwm = pwm_get(dev->dev, "pwm_pmic_backlight");
+               desc = "PMIC";
+       } else {
+               panel->backlight.pwm = pwm_get(dev->dev, "pwm_soc_backlight");
+               desc = "SoC";
+       }
+
+       if (IS_ERR(panel->backlight.pwm)) {
+               drm_err(&dev_priv->drm, "Failed to get the %s PWM chip\n",
+                       desc);
+               panel->backlight.pwm = NULL;
+               return -ENODEV;
+       }
+
+       panel->backlight.pwm_level_max = 100; /* 100% */
+       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
+
+       if (pwm_is_enabled(panel->backlight.pwm)) {
+               /* PWM is already enabled, use existing settings */
+               pwm_get_state(panel->backlight.pwm, &panel->backlight.pwm_state);
+
+               level = pwm_get_relative_duty_cycle(&panel->backlight.pwm_state,
+                                                   100);
+               level = intel_backlight_invert_pwm_level(connector, level);
+               panel->backlight.pwm_enabled = true;
+
+               drm_dbg_kms(&dev_priv->drm, "PWM already enabled at freq %ld, VBT freq %d, level %d\n",
+                           NSEC_PER_SEC / (unsigned long)panel->backlight.pwm_state.period,
+                           get_vbt_pwm_freq(dev_priv), level);
+       } else {
+               /* Set period from VBT frequency, leave other settings at 0. */
+               panel->backlight.pwm_state.period =
+                       NSEC_PER_SEC / get_vbt_pwm_freq(dev_priv);
+       }
+
+       drm_info(&dev_priv->drm, "Using %s PWM for LCD backlight control\n",
+                desc);
+       return 0;
+}
+
+static void intel_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct intel_panel *panel = &connector->panel;
+
+       panel->backlight.pwm_funcs->set(conn_state,
+                                       intel_backlight_invert_pwm_level(connector, level));
+}
+
+static u32 intel_pwm_get_backlight(struct intel_connector *connector, enum pipe pipe)
+{
+       struct intel_panel *panel = &connector->panel;
+
+       return intel_backlight_invert_pwm_level(connector,
+                                           panel->backlight.pwm_funcs->get(connector, pipe));
+}
+
+static void intel_pwm_enable_backlight(const struct intel_crtc_state *crtc_state,
+                                      const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct intel_panel *panel = &connector->panel;
+
+       panel->backlight.pwm_funcs->enable(crtc_state, conn_state,
+                                          intel_backlight_invert_pwm_level(connector, level));
+}
+
+static void intel_pwm_disable_backlight(const struct drm_connector_state *conn_state, u32 level)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct intel_panel *panel = &connector->panel;
+
+       panel->backlight.pwm_funcs->disable(conn_state,
+                                           intel_backlight_invert_pwm_level(connector, level));
+}
+
+static int intel_pwm_setup_backlight(struct intel_connector *connector, enum pipe pipe)
+{
+       struct intel_panel *panel = &connector->panel;
+       int ret = panel->backlight.pwm_funcs->setup(connector, pipe);
+
+       if (ret < 0)
+               return ret;
+
+       panel->backlight.min = panel->backlight.pwm_level_min;
+       panel->backlight.max = panel->backlight.pwm_level_max;
+       panel->backlight.level = intel_pwm_get_backlight(connector, pipe);
+       panel->backlight.enabled = panel->backlight.pwm_enabled;
+
+       return 0;
+}
+
+void intel_backlight_update(struct intel_atomic_state *state,
+                           struct intel_encoder *encoder,
+                           const struct intel_crtc_state *crtc_state,
+                           const struct drm_connector_state *conn_state)
+{
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+
+       if (!panel->backlight.present)
+               return;
+
+       mutex_lock(&dev_priv->backlight_lock);
+       if (!panel->backlight.enabled)
+               __intel_backlight_enable(crtc_state, conn_state);
+
+       mutex_unlock(&dev_priv->backlight_lock);
+}
+
+int intel_backlight_setup(struct intel_connector *connector, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
+       int ret;
+
+       if (!dev_priv->vbt.backlight.present) {
+               if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) {
+                       drm_dbg_kms(&dev_priv->drm,
+                                   "no backlight present per VBT, but present per quirk\n");
+               } else {
+                       drm_dbg_kms(&dev_priv->drm,
+                                   "no backlight present per VBT\n");
+                       return 0;
+               }
+       }
+
+       /* ensure intel_panel has been initialized first */
+       if (drm_WARN_ON(&dev_priv->drm, !panel->backlight.funcs))
+               return -ENODEV;
+
+       /* set level and max in panel struct */
+       mutex_lock(&dev_priv->backlight_lock);
+       ret = panel->backlight.funcs->setup(connector, pipe);
+       mutex_unlock(&dev_priv->backlight_lock);
+
+       if (ret) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "failed to setup backlight for connector %s\n",
+                           connector->base.name);
+               return ret;
+       }
+
+       panel->backlight.present = true;
+
+       drm_dbg_kms(&dev_priv->drm,
+                   "Connector %s backlight initialized, %s, brightness %u/%u\n",
+                   connector->base.name,
+                   enableddisabled(panel->backlight.enabled),
+                   panel->backlight.level, panel->backlight.max);
+
+       return 0;
+}
+
+void intel_backlight_destroy(struct intel_panel *panel)
+{
+       /* dispose of the pwm */
+       if (panel->backlight.pwm)
+               pwm_put(panel->backlight.pwm);
+
+       panel->backlight.present = false;
+}
+
+static const struct intel_panel_bl_funcs bxt_pwm_funcs = {
+       .setup = bxt_setup_backlight,
+       .enable = bxt_enable_backlight,
+       .disable = bxt_disable_backlight,
+       .set = bxt_set_backlight,
+       .get = bxt_get_backlight,
+       .hz_to_pwm = bxt_hz_to_pwm,
+};
+
+static const struct intel_panel_bl_funcs cnp_pwm_funcs = {
+       .setup = cnp_setup_backlight,
+       .enable = cnp_enable_backlight,
+       .disable = cnp_disable_backlight,
+       .set = bxt_set_backlight,
+       .get = bxt_get_backlight,
+       .hz_to_pwm = cnp_hz_to_pwm,
+};
+
+static const struct intel_panel_bl_funcs lpt_pwm_funcs = {
+       .setup = lpt_setup_backlight,
+       .enable = lpt_enable_backlight,
+       .disable = lpt_disable_backlight,
+       .set = lpt_set_backlight,
+       .get = lpt_get_backlight,
+       .hz_to_pwm = lpt_hz_to_pwm,
+};
+
+static const struct intel_panel_bl_funcs spt_pwm_funcs = {
+       .setup = lpt_setup_backlight,
+       .enable = lpt_enable_backlight,
+       .disable = lpt_disable_backlight,
+       .set = lpt_set_backlight,
+       .get = lpt_get_backlight,
+       .hz_to_pwm = spt_hz_to_pwm,
+};
+
+static const struct intel_panel_bl_funcs pch_pwm_funcs = {
+       .setup = pch_setup_backlight,
+       .enable = pch_enable_backlight,
+       .disable = pch_disable_backlight,
+       .set = pch_set_backlight,
+       .get = pch_get_backlight,
+       .hz_to_pwm = pch_hz_to_pwm,
+};
+
+static const struct intel_panel_bl_funcs ext_pwm_funcs = {
+       .setup = ext_pwm_setup_backlight,
+       .enable = ext_pwm_enable_backlight,
+       .disable = ext_pwm_disable_backlight,
+       .set = ext_pwm_set_backlight,
+       .get = ext_pwm_get_backlight,
+};
+
+static const struct intel_panel_bl_funcs vlv_pwm_funcs = {
+       .setup = vlv_setup_backlight,
+       .enable = vlv_enable_backlight,
+       .disable = vlv_disable_backlight,
+       .set = vlv_set_backlight,
+       .get = vlv_get_backlight,
+       .hz_to_pwm = vlv_hz_to_pwm,
+};
+
+static const struct intel_panel_bl_funcs i965_pwm_funcs = {
+       .setup = i965_setup_backlight,
+       .enable = i965_enable_backlight,
+       .disable = i965_disable_backlight,
+       .set = i9xx_set_backlight,
+       .get = i9xx_get_backlight,
+       .hz_to_pwm = i965_hz_to_pwm,
+};
+
+static const struct intel_panel_bl_funcs i9xx_pwm_funcs = {
+       .setup = i9xx_setup_backlight,
+       .enable = i9xx_enable_backlight,
+       .disable = i9xx_disable_backlight,
+       .set = i9xx_set_backlight,
+       .get = i9xx_get_backlight,
+       .hz_to_pwm = i9xx_hz_to_pwm,
+};
+
+static const struct intel_panel_bl_funcs pwm_bl_funcs = {
+       .setup = intel_pwm_setup_backlight,
+       .enable = intel_pwm_enable_backlight,
+       .disable = intel_pwm_disable_backlight,
+       .set = intel_pwm_set_backlight,
+       .get = intel_pwm_get_backlight,
+};
+
+/* Set up chip specific backlight functions */
+void intel_backlight_init_funcs(struct intel_panel *panel)
+{
+       struct intel_connector *connector =
+               container_of(panel, struct intel_connector, panel);
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+
+       if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI &&
+           intel_dsi_dcs_init_backlight_funcs(connector) == 0)
+               return;
+
+       if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) {
+               panel->backlight.pwm_funcs = &bxt_pwm_funcs;
+       } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) {
+               panel->backlight.pwm_funcs = &cnp_pwm_funcs;
+       } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_LPT) {
+               if (HAS_PCH_LPT(dev_priv))
+                       panel->backlight.pwm_funcs = &lpt_pwm_funcs;
+               else
+                       panel->backlight.pwm_funcs = &spt_pwm_funcs;
+       } else if (HAS_PCH_SPLIT(dev_priv)) {
+               panel->backlight.pwm_funcs = &pch_pwm_funcs;
+       } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) {
+                       panel->backlight.pwm_funcs = &ext_pwm_funcs;
+               } else {
+                       panel->backlight.pwm_funcs = &vlv_pwm_funcs;
+               }
+       } else if (DISPLAY_VER(dev_priv) == 4) {
+               panel->backlight.pwm_funcs = &i965_pwm_funcs;
+       } else {
+               panel->backlight.pwm_funcs = &i9xx_pwm_funcs;
+       }
+
+       if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP &&
+           intel_dp_aux_init_backlight_funcs(connector) == 0)
+               return;
+
+       /* We're using a standard PWM backlight interface */
+       panel->backlight.funcs = &pwm_bl_funcs;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_backlight.h b/drivers/gpu/drm/i915/display/intel_backlight.h
new file mode 100644 (file)
index 0000000..339643f
--- /dev/null
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright Â© 2021 Intel Corporation
+ */
+
+#ifndef __INTEL_BACKLIGHT_H__
+#define __INTEL_BACKLIGHT_H__
+
+#include <linux/types.h>
+
+struct drm_connector_state;
+struct intel_atomic_state;
+struct intel_connector;
+struct intel_crtc_state;
+struct intel_encoder;
+struct intel_panel;
+enum pipe;
+
+void intel_backlight_init_funcs(struct intel_panel *panel);
+int intel_backlight_setup(struct intel_connector *connector, enum pipe pipe);
+void intel_backlight_destroy(struct intel_panel *panel);
+
+void intel_backlight_enable(const struct intel_crtc_state *crtc_state,
+                           const struct drm_connector_state *conn_state);
+void intel_backlight_update(struct intel_atomic_state *state,
+                           struct intel_encoder *encoder,
+                           const struct intel_crtc_state *crtc_state,
+                           const struct drm_connector_state *conn_state);
+void intel_backlight_disable(const struct drm_connector_state *old_conn_state);
+
+void intel_backlight_set_acpi(const struct drm_connector_state *conn_state,
+                             u32 level, u32 max);
+void intel_backlight_set_pwm_level(const struct drm_connector_state *conn_state,
+                                  u32 level);
+u32 intel_backlight_invert_pwm_level(struct intel_connector *connector, u32 level);
+u32 intel_backlight_level_to_pwm(struct intel_connector *connector, u32 level);
+u32 intel_backlight_level_from_pwm(struct intel_connector *connector, u32 val);
+
+#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
+int intel_backlight_device_register(struct intel_connector *connector);
+void intel_backlight_device_unregister(struct intel_connector *connector);
+#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */
+static inline int intel_backlight_device_register(struct intel_connector *connector)
+{
+       return 0;
+}
+static inline void intel_backlight_device_unregister(struct intel_connector *connector)
+{
+}
+#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
+
+#endif /* __INTEL_BACKLIGHT_H__ */
index e86e6ed2d3bf20613e45f2e86882fd511d850863..3c25926092de35367ec3dd0e819c5ce5c6da2a21 100644 (file)
@@ -483,6 +483,9 @@ parse_lfp_backlight(struct drm_i915_private *i915,
                        level = 255;
                }
                i915->vbt.backlight.min_brightness = min_level;
+
+               i915->vbt.backlight.brightness_precision_bits =
+                       backlight_data->brightness_precision_bits[panel_type];
        } else {
                level = backlight_data->level[panel_type];
                i915->vbt.backlight.min_brightness = entry->min_brightness;
@@ -1501,39 +1504,130 @@ static u8 translate_iboost(u8 val)
        return mapping[val];
 }
 
+static const u8 cnp_ddc_pin_map[] = {
+       [0] = 0, /* N/A */
+       [DDC_BUS_DDI_B] = GMBUS_PIN_1_BXT,
+       [DDC_BUS_DDI_C] = GMBUS_PIN_2_BXT,
+       [DDC_BUS_DDI_D] = GMBUS_PIN_4_CNP, /* sic */
+       [DDC_BUS_DDI_F] = GMBUS_PIN_3_BXT, /* sic */
+};
+
+static const u8 icp_ddc_pin_map[] = {
+       [ICL_DDC_BUS_DDI_A] = GMBUS_PIN_1_BXT,
+       [ICL_DDC_BUS_DDI_B] = GMBUS_PIN_2_BXT,
+       [TGL_DDC_BUS_DDI_C] = GMBUS_PIN_3_BXT,
+       [ICL_DDC_BUS_PORT_1] = GMBUS_PIN_9_TC1_ICP,
+       [ICL_DDC_BUS_PORT_2] = GMBUS_PIN_10_TC2_ICP,
+       [ICL_DDC_BUS_PORT_3] = GMBUS_PIN_11_TC3_ICP,
+       [ICL_DDC_BUS_PORT_4] = GMBUS_PIN_12_TC4_ICP,
+       [TGL_DDC_BUS_PORT_5] = GMBUS_PIN_13_TC5_TGP,
+       [TGL_DDC_BUS_PORT_6] = GMBUS_PIN_14_TC6_TGP,
+};
+
+static const u8 rkl_pch_tgp_ddc_pin_map[] = {
+       [ICL_DDC_BUS_DDI_A] = GMBUS_PIN_1_BXT,
+       [ICL_DDC_BUS_DDI_B] = GMBUS_PIN_2_BXT,
+       [RKL_DDC_BUS_DDI_D] = GMBUS_PIN_9_TC1_ICP,
+       [RKL_DDC_BUS_DDI_E] = GMBUS_PIN_10_TC2_ICP,
+};
+
+static const u8 adls_ddc_pin_map[] = {
+       [ICL_DDC_BUS_DDI_A] = GMBUS_PIN_1_BXT,
+       [ADLS_DDC_BUS_PORT_TC1] = GMBUS_PIN_9_TC1_ICP,
+       [ADLS_DDC_BUS_PORT_TC2] = GMBUS_PIN_10_TC2_ICP,
+       [ADLS_DDC_BUS_PORT_TC3] = GMBUS_PIN_11_TC3_ICP,
+       [ADLS_DDC_BUS_PORT_TC4] = GMBUS_PIN_12_TC4_ICP,
+};
+
+static const u8 gen9bc_tgp_ddc_pin_map[] = {
+       [DDC_BUS_DDI_B] = GMBUS_PIN_2_BXT,
+       [DDC_BUS_DDI_C] = GMBUS_PIN_9_TC1_ICP,
+       [DDC_BUS_DDI_D] = GMBUS_PIN_10_TC2_ICP,
+};
+
+static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin)
+{
+       const u8 *ddc_pin_map;
+       int n_entries;
+
+       if (IS_ALDERLAKE_S(i915)) {
+               ddc_pin_map = adls_ddc_pin_map;
+               n_entries = ARRAY_SIZE(adls_ddc_pin_map);
+       } else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) {
+               return vbt_pin;
+       } else if (IS_ROCKETLAKE(i915) && INTEL_PCH_TYPE(i915) == PCH_TGP) {
+               ddc_pin_map = rkl_pch_tgp_ddc_pin_map;
+               n_entries = ARRAY_SIZE(rkl_pch_tgp_ddc_pin_map);
+       } else if (HAS_PCH_TGP(i915) && DISPLAY_VER(i915) == 9) {
+               ddc_pin_map = gen9bc_tgp_ddc_pin_map;
+               n_entries = ARRAY_SIZE(gen9bc_tgp_ddc_pin_map);
+       } else if (INTEL_PCH_TYPE(i915) >= PCH_ICP) {
+               ddc_pin_map = icp_ddc_pin_map;
+               n_entries = ARRAY_SIZE(icp_ddc_pin_map);
+       } else if (HAS_PCH_CNP(i915)) {
+               ddc_pin_map = cnp_ddc_pin_map;
+               n_entries = ARRAY_SIZE(cnp_ddc_pin_map);
+       } else {
+               /* Assuming direct map */
+               return vbt_pin;
+       }
+
+       if (vbt_pin < n_entries && ddc_pin_map[vbt_pin] != 0)
+               return ddc_pin_map[vbt_pin];
+
+       drm_dbg_kms(&i915->drm,
+                   "Ignoring alternate pin: VBT claims DDC pin %d, which is not valid for this platform\n",
+                   vbt_pin);
+       return 0;
+}
+
 static enum port get_port_by_ddc_pin(struct drm_i915_private *i915, u8 ddc_pin)
 {
-       const struct ddi_vbt_port_info *info;
+       const struct intel_bios_encoder_data *devdata;
        enum port port;
 
        if (!ddc_pin)
                return PORT_NONE;
 
        for_each_port(port) {
-               info = &i915->vbt.ddi_port_info[port];
+               devdata = i915->vbt.ports[port];
 
-               if (info->devdata && ddc_pin == info->alternate_ddc_pin)
+               if (devdata && ddc_pin == devdata->child.ddc_pin)
                        return port;
        }
 
        return PORT_NONE;
 }
 
-static void sanitize_ddc_pin(struct drm_i915_private *i915,
+static void sanitize_ddc_pin(struct intel_bios_encoder_data *devdata,
                             enum port port)
 {
-       struct ddi_vbt_port_info *info = &i915->vbt.ddi_port_info[port];
+       struct drm_i915_private *i915 = devdata->i915;
        struct child_device_config *child;
+       u8 mapped_ddc_pin;
        enum port p;
 
-       p = get_port_by_ddc_pin(i915, info->alternate_ddc_pin);
+       if (!devdata->child.ddc_pin)
+               return;
+
+       mapped_ddc_pin = map_ddc_pin(i915, devdata->child.ddc_pin);
+       if (!intel_gmbus_is_valid_pin(i915, mapped_ddc_pin)) {
+               drm_dbg_kms(&i915->drm,
+                           "Port %c has invalid DDC pin %d, "
+                           "sticking to defaults\n",
+                           port_name(port), mapped_ddc_pin);
+               devdata->child.ddc_pin = 0;
+               return;
+       }
+
+       p = get_port_by_ddc_pin(i915, devdata->child.ddc_pin);
        if (p == PORT_NONE)
                return;
 
        drm_dbg_kms(&i915->drm,
                    "port %c trying to use the same DDC pin (0x%x) as port %c, "
                    "disabling port %c DVI/HDMI support\n",
-                   port_name(port), info->alternate_ddc_pin,
+                   port_name(port), mapped_ddc_pin,
                    port_name(p), port_name(p));
 
        /*
@@ -1545,48 +1639,47 @@ static void sanitize_ddc_pin(struct drm_i915_private *i915,
         * there are real machines (eg. Asrock B250M-HDV) where VBT has both
         * port A and port E with the same AUX ch and we must pick port E :(
         */
-       info = &i915->vbt.ddi_port_info[p];
-       child = &info->devdata->child;
+       child = &i915->vbt.ports[p]->child;
 
        child->device_type &= ~DEVICE_TYPE_TMDS_DVI_SIGNALING;
        child->device_type |= DEVICE_TYPE_NOT_HDMI_OUTPUT;
 
-       info->alternate_ddc_pin = 0;
+       child->ddc_pin = 0;
 }
 
 static enum port get_port_by_aux_ch(struct drm_i915_private *i915, u8 aux_ch)
 {
-       const struct ddi_vbt_port_info *info;
+       const struct intel_bios_encoder_data *devdata;
        enum port port;
 
        if (!aux_ch)
                return PORT_NONE;
 
        for_each_port(port) {
-               info = &i915->vbt.ddi_port_info[port];
+               devdata = i915->vbt.ports[port];
 
-               if (info->devdata && aux_ch == info->alternate_aux_channel)
+               if (devdata && aux_ch == devdata->child.aux_channel)
                        return port;
        }
 
        return PORT_NONE;
 }
 
-static void sanitize_aux_ch(struct drm_i915_private *i915,
+static void sanitize_aux_ch(struct intel_bios_encoder_data *devdata,
                            enum port port)
 {
-       struct ddi_vbt_port_info *info = &i915->vbt.ddi_port_info[port];
+       struct drm_i915_private *i915 = devdata->i915;
        struct child_device_config *child;
        enum port p;
 
-       p = get_port_by_aux_ch(i915, info->alternate_aux_channel);
+       p = get_port_by_aux_ch(i915, devdata->child.aux_channel);
        if (p == PORT_NONE)
                return;
 
        drm_dbg_kms(&i915->drm,
                    "port %c trying to use the same AUX CH (0x%x) as port %c, "
                    "disabling port %c DP support\n",
-                   port_name(port), info->alternate_aux_channel,
+                   port_name(port), devdata->child.aux_channel,
                    port_name(p), port_name(p));
 
        /*
@@ -1598,88 +1691,10 @@ static void sanitize_aux_ch(struct drm_i915_private *i915,
         * there are real machines (eg. Asrock B250M-HDV) where VBT has both
         * port A and port E with the same AUX ch and we must pick port E :(
         */
-       info = &i915->vbt.ddi_port_info[p];
-       child = &info->devdata->child;
+       child = &i915->vbt.ports[p]->child;
 
        child->device_type &= ~DEVICE_TYPE_DISPLAYPORT_OUTPUT;
-       info->alternate_aux_channel = 0;
-}
-
-static const u8 cnp_ddc_pin_map[] = {
-       [0] = 0, /* N/A */
-       [DDC_BUS_DDI_B] = GMBUS_PIN_1_BXT,
-       [DDC_BUS_DDI_C] = GMBUS_PIN_2_BXT,
-       [DDC_BUS_DDI_D] = GMBUS_PIN_4_CNP, /* sic */
-       [DDC_BUS_DDI_F] = GMBUS_PIN_3_BXT, /* sic */
-};
-
-static const u8 icp_ddc_pin_map[] = {
-       [ICL_DDC_BUS_DDI_A] = GMBUS_PIN_1_BXT,
-       [ICL_DDC_BUS_DDI_B] = GMBUS_PIN_2_BXT,
-       [TGL_DDC_BUS_DDI_C] = GMBUS_PIN_3_BXT,
-       [ICL_DDC_BUS_PORT_1] = GMBUS_PIN_9_TC1_ICP,
-       [ICL_DDC_BUS_PORT_2] = GMBUS_PIN_10_TC2_ICP,
-       [ICL_DDC_BUS_PORT_3] = GMBUS_PIN_11_TC3_ICP,
-       [ICL_DDC_BUS_PORT_4] = GMBUS_PIN_12_TC4_ICP,
-       [TGL_DDC_BUS_PORT_5] = GMBUS_PIN_13_TC5_TGP,
-       [TGL_DDC_BUS_PORT_6] = GMBUS_PIN_14_TC6_TGP,
-};
-
-static const u8 rkl_pch_tgp_ddc_pin_map[] = {
-       [ICL_DDC_BUS_DDI_A] = GMBUS_PIN_1_BXT,
-       [ICL_DDC_BUS_DDI_B] = GMBUS_PIN_2_BXT,
-       [RKL_DDC_BUS_DDI_D] = GMBUS_PIN_9_TC1_ICP,
-       [RKL_DDC_BUS_DDI_E] = GMBUS_PIN_10_TC2_ICP,
-};
-
-static const u8 adls_ddc_pin_map[] = {
-       [ICL_DDC_BUS_DDI_A] = GMBUS_PIN_1_BXT,
-       [ADLS_DDC_BUS_PORT_TC1] = GMBUS_PIN_9_TC1_ICP,
-       [ADLS_DDC_BUS_PORT_TC2] = GMBUS_PIN_10_TC2_ICP,
-       [ADLS_DDC_BUS_PORT_TC3] = GMBUS_PIN_11_TC3_ICP,
-       [ADLS_DDC_BUS_PORT_TC4] = GMBUS_PIN_12_TC4_ICP,
-};
-
-static const u8 gen9bc_tgp_ddc_pin_map[] = {
-       [DDC_BUS_DDI_B] = GMBUS_PIN_2_BXT,
-       [DDC_BUS_DDI_C] = GMBUS_PIN_9_TC1_ICP,
-       [DDC_BUS_DDI_D] = GMBUS_PIN_10_TC2_ICP,
-};
-
-static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin)
-{
-       const u8 *ddc_pin_map;
-       int n_entries;
-
-       if (IS_ALDERLAKE_S(i915)) {
-               ddc_pin_map = adls_ddc_pin_map;
-               n_entries = ARRAY_SIZE(adls_ddc_pin_map);
-       } else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) {
-               return vbt_pin;
-       } else if (IS_ROCKETLAKE(i915) && INTEL_PCH_TYPE(i915) == PCH_TGP) {
-               ddc_pin_map = rkl_pch_tgp_ddc_pin_map;
-               n_entries = ARRAY_SIZE(rkl_pch_tgp_ddc_pin_map);
-       } else if (HAS_PCH_TGP(i915) && DISPLAY_VER(i915) == 9) {
-               ddc_pin_map = gen9bc_tgp_ddc_pin_map;
-               n_entries = ARRAY_SIZE(gen9bc_tgp_ddc_pin_map);
-       } else if (INTEL_PCH_TYPE(i915) >= PCH_ICP) {
-               ddc_pin_map = icp_ddc_pin_map;
-               n_entries = ARRAY_SIZE(icp_ddc_pin_map);
-       } else if (HAS_PCH_CNP(i915)) {
-               ddc_pin_map = cnp_ddc_pin_map;
-               n_entries = ARRAY_SIZE(cnp_ddc_pin_map);
-       } else {
-               /* Assuming direct map */
-               return vbt_pin;
-       }
-
-       if (vbt_pin < n_entries && ddc_pin_map[vbt_pin] != 0)
-               return ddc_pin_map[vbt_pin];
-
-       drm_dbg_kms(&i915->drm,
-                   "Ignoring alternate pin: VBT claims DDC pin %d, which is not valid for this platform\n",
-                   vbt_pin);
-       return 0;
+       child->aux_channel = 0;
 }
 
 static enum port __dvo_port_to_port(int n_ports, int n_dvo,
@@ -1815,6 +1830,17 @@ static int parse_bdb_216_dp_max_link_rate(const int vbt_max_link_rate)
        }
 }
 
+static int _intel_bios_dp_max_link_rate(const struct intel_bios_encoder_data *devdata)
+{
+       if (!devdata || devdata->i915->vbt.version < 216)
+               return 0;
+
+       if (devdata->i915->vbt.version >= 230)
+               return parse_bdb_230_dp_max_link_rate(devdata->child.dp_max_link_rate);
+       else
+               return parse_bdb_216_dp_max_link_rate(devdata->child.dp_max_link_rate);
+}
+
 static void sanitize_device_type(struct intel_bios_encoder_data *devdata,
                                 enum port port)
 {
@@ -1868,6 +1894,32 @@ intel_bios_encoder_supports_edp(const struct intel_bios_encoder_data *devdata)
                devdata->child.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR;
 }
 
+static int _intel_bios_hdmi_level_shift(const struct intel_bios_encoder_data *devdata)
+{
+       if (!devdata || devdata->i915->vbt.version < 158)
+               return -1;
+
+       return devdata->child.hdmi_level_shifter_value;
+}
+
+static int _intel_bios_max_tmds_clock(const struct intel_bios_encoder_data *devdata)
+{
+       if (!devdata || devdata->i915->vbt.version < 204)
+               return 0;
+
+       switch (devdata->child.hdmi_max_data_rate) {
+       default:
+               MISSING_CASE(devdata->child.hdmi_max_data_rate);
+               fallthrough;
+       case HDMI_MAX_DATA_RATE_PLATFORM:
+               return 0;
+       case HDMI_MAX_DATA_RATE_297:
+               return 297000;
+       case HDMI_MAX_DATA_RATE_165:
+               return 165000;
+       }
+}
+
 static bool is_port_valid(struct drm_i915_private *i915, enum port port)
 {
        /*
@@ -1885,9 +1937,8 @@ static void parse_ddi_port(struct drm_i915_private *i915,
                           struct intel_bios_encoder_data *devdata)
 {
        const struct child_device_config *child = &devdata->child;
-       struct ddi_vbt_port_info *info;
        bool is_dvi, is_hdmi, is_dp, is_edp, is_crt, supports_typec_usb, supports_tbt;
-       int dp_boost_level, hdmi_boost_level;
+       int dp_boost_level, dp_max_link_rate, hdmi_boost_level, hdmi_level_shift, max_tmds_clock;
        enum port port;
 
        port = dvo_port_to_port(i915, child->dvo_port);
@@ -1901,9 +1952,7 @@ static void parse_ddi_port(struct drm_i915_private *i915,
                return;
        }
 
-       info = &i915->vbt.ddi_port_info[port];
-
-       if (info->devdata) {
+       if (i915->vbt.ports[port]) {
                drm_dbg_kms(&i915->drm,
                            "More than one child device for port %c in VBT, using the first.\n",
                            port_name(port));
@@ -1928,62 +1977,24 @@ static void parse_ddi_port(struct drm_i915_private *i915,
                    supports_typec_usb, supports_tbt,
                    devdata->dsc != NULL);
 
-       if (is_dvi) {
-               u8 ddc_pin;
+       if (is_dvi)
+               sanitize_ddc_pin(devdata, port);
 
-               ddc_pin = map_ddc_pin(i915, child->ddc_pin);
-               if (intel_gmbus_is_valid_pin(i915, ddc_pin)) {
-                       info->alternate_ddc_pin = ddc_pin;
-                       sanitize_ddc_pin(i915, port);
-               } else {
-                       drm_dbg_kms(&i915->drm,
-                                   "Port %c has invalid DDC pin %d, "
-                                   "sticking to defaults\n",
-                                   port_name(port), ddc_pin);
-               }
-       }
-
-       if (is_dp) {
-               info->alternate_aux_channel = child->aux_channel;
-
-               sanitize_aux_ch(i915, port);
-       }
+       if (is_dp)
+               sanitize_aux_ch(devdata, port);
 
-       if (i915->vbt.version >= 158) {
-               /* The VBT HDMI level shift values match the table we have. */
-               u8 hdmi_level_shift = child->hdmi_level_shifter_value;
+       hdmi_level_shift = _intel_bios_hdmi_level_shift(devdata);
+       if (hdmi_level_shift >= 0) {
                drm_dbg_kms(&i915->drm,
                            "Port %c VBT HDMI level shift: %d\n",
-                           port_name(port),
-                           hdmi_level_shift);
-               info->hdmi_level_shift = hdmi_level_shift;
-               info->hdmi_level_shift_set = true;
+                           port_name(port), hdmi_level_shift);
        }
 
-       if (i915->vbt.version >= 204) {
-               int max_tmds_clock;
-
-               switch (child->hdmi_max_data_rate) {
-               default:
-                       MISSING_CASE(child->hdmi_max_data_rate);
-                       fallthrough;
-               case HDMI_MAX_DATA_RATE_PLATFORM:
-                       max_tmds_clock = 0;
-                       break;
-               case HDMI_MAX_DATA_RATE_297:
-                       max_tmds_clock = 297000;
-                       break;
-               case HDMI_MAX_DATA_RATE_165:
-                       max_tmds_clock = 165000;
-                       break;
-               }
-
-               if (max_tmds_clock)
-                       drm_dbg_kms(&i915->drm,
-                                   "Port %c VBT HDMI max TMDS clock: %d kHz\n",
-                                   port_name(port), max_tmds_clock);
-               info->max_tmds_clock = max_tmds_clock;
-       }
+       max_tmds_clock = _intel_bios_max_tmds_clock(devdata);
+       if (max_tmds_clock)
+               drm_dbg_kms(&i915->drm,
+                           "Port %c VBT HDMI max TMDS clock: %d kHz\n",
+                           port_name(port), max_tmds_clock);
 
        /* I_boost config for SKL and above */
        dp_boost_level = intel_bios_encoder_dp_boost_level(devdata);
@@ -1998,19 +2009,13 @@ static void parse_ddi_port(struct drm_i915_private *i915,
                            "Port %c VBT HDMI boost level: %d\n",
                            port_name(port), hdmi_boost_level);
 
-       /* DP max link rate for GLK+ */
-       if (i915->vbt.version >= 216) {
-               if (i915->vbt.version >= 230)
-                       info->dp_max_link_rate = parse_bdb_230_dp_max_link_rate(child->dp_max_link_rate);
-               else
-                       info->dp_max_link_rate = parse_bdb_216_dp_max_link_rate(child->dp_max_link_rate);
-
+       dp_max_link_rate = _intel_bios_dp_max_link_rate(devdata);
+       if (dp_max_link_rate)
                drm_dbg_kms(&i915->drm,
                            "Port %c VBT DP max link rate: %d\n",
-                           port_name(port), info->dp_max_link_rate);
-       }
+                           port_name(port), dp_max_link_rate);
 
-       info->devdata = devdata;
+       i915->vbt.ports[port] = devdata;
 }
 
 static void parse_ddi_ports(struct drm_i915_private *i915)
@@ -2548,12 +2553,8 @@ bool intel_bios_is_port_present(struct drm_i915_private *i915, enum port port)
                [PORT_F] = { DVO_PORT_DPF, DVO_PORT_HDMIF, },
        };
 
-       if (HAS_DDI(i915)) {
-               const struct ddi_vbt_port_info *port_info =
-                       &i915->vbt.ddi_port_info[port];
-
-               return port_info->devdata;
-       }
+       if (HAS_DDI(i915))
+               return i915->vbt.ports[port];
 
        /* FIXME maybe deal with port A as well? */
        if (drm_WARN_ON(&i915->drm,
@@ -2804,8 +2805,7 @@ bool
 intel_bios_is_port_hpd_inverted(const struct drm_i915_private *i915,
                                enum port port)
 {
-       const struct intel_bios_encoder_data *devdata =
-               i915->vbt.ddi_port_info[port].devdata;
+       const struct intel_bios_encoder_data *devdata = i915->vbt.ports[port];
 
        if (drm_WARN_ON_ONCE(&i915->drm,
                             !IS_GEMINILAKE(i915) && !IS_BROXTON(i915)))
@@ -2825,8 +2825,7 @@ bool
 intel_bios_is_lspcon_present(const struct drm_i915_private *i915,
                             enum port port)
 {
-       const struct intel_bios_encoder_data *devdata =
-               i915->vbt.ddi_port_info[port].devdata;
+       const struct intel_bios_encoder_data *devdata = i915->vbt.ports[port];
 
        return HAS_LSPCON(i915) && devdata && devdata->child.lspcon;
 }
@@ -2842,8 +2841,7 @@ bool
 intel_bios_is_lane_reversal_needed(const struct drm_i915_private *i915,
                                   enum port port)
 {
-       const struct intel_bios_encoder_data *devdata =
-               i915->vbt.ddi_port_info[port].devdata;
+       const struct intel_bios_encoder_data *devdata = i915->vbt.ports[port];
 
        return devdata && devdata->child.lane_reversal;
 }
@@ -2851,11 +2849,10 @@ intel_bios_is_lane_reversal_needed(const struct drm_i915_private *i915,
 enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *i915,
                                   enum port port)
 {
-       const struct ddi_vbt_port_info *info =
-               &i915->vbt.ddi_port_info[port];
+       const struct intel_bios_encoder_data *devdata = i915->vbt.ports[port];
        enum aux_ch aux_ch;
 
-       if (!info->alternate_aux_channel) {
+       if (!devdata || !devdata->child.aux_channel) {
                aux_ch = (enum aux_ch)port;
 
                drm_dbg_kms(&i915->drm,
@@ -2871,7 +2868,7 @@ enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *i915,
         * ADL-S VBT uses PHY based mapping. Combo PHYs A,B,C,D,E
         * map to DDI A,TC1,TC2,TC3,TC4 respectively.
         */
-       switch (info->alternate_aux_channel) {
+       switch (devdata->child.aux_channel) {
        case DP_AUX_A:
                aux_ch = AUX_CH_A;
                break;
@@ -2932,7 +2929,7 @@ enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *i915,
                        aux_ch = AUX_CH_I;
                break;
        default:
-               MISSING_CASE(info->alternate_aux_channel);
+               MISSING_CASE(devdata->child.aux_channel);
                aux_ch = AUX_CH_A;
                break;
        }
@@ -2946,17 +2943,18 @@ enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *i915,
 int intel_bios_max_tmds_clock(struct intel_encoder *encoder)
 {
        struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+       const struct intel_bios_encoder_data *devdata = i915->vbt.ports[encoder->port];
 
-       return i915->vbt.ddi_port_info[encoder->port].max_tmds_clock;
+       return _intel_bios_max_tmds_clock(devdata);
 }
 
+/* This is an index in the HDMI/DVI DDI buffer translation table, or -1 */
 int intel_bios_hdmi_level_shift(struct intel_encoder *encoder)
 {
        struct drm_i915_private *i915 = to_i915(encoder->base.dev);
-       const struct ddi_vbt_port_info *info =
-               &i915->vbt.ddi_port_info[encoder->port];
+       const struct intel_bios_encoder_data *devdata = i915->vbt.ports[encoder->port];
 
-       return info->hdmi_level_shift_set ? info->hdmi_level_shift : -1;
+       return _intel_bios_hdmi_level_shift(devdata);
 }
 
 int intel_bios_encoder_dp_boost_level(const struct intel_bios_encoder_data *devdata)
@@ -2978,15 +2976,20 @@ int intel_bios_encoder_hdmi_boost_level(const struct intel_bios_encoder_data *de
 int intel_bios_dp_max_link_rate(struct intel_encoder *encoder)
 {
        struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+       const struct intel_bios_encoder_data *devdata = i915->vbt.ports[encoder->port];
 
-       return i915->vbt.ddi_port_info[encoder->port].dp_max_link_rate;
+       return _intel_bios_dp_max_link_rate(devdata);
 }
 
 int intel_bios_alternate_ddc_pin(struct intel_encoder *encoder)
 {
        struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+       const struct intel_bios_encoder_data *devdata = i915->vbt.ports[encoder->port];
+
+       if (!devdata || !devdata->child.ddc_pin)
+               return 0;
 
-       return i915->vbt.ddi_port_info[encoder->port].alternate_ddc_pin;
+       return map_ddc_pin(i915, devdata->child.ddc_pin);
 }
 
 bool intel_bios_encoder_supports_typec_usb(const struct intel_bios_encoder_data *devdata)
@@ -3002,5 +3005,5 @@ bool intel_bios_encoder_supports_tbt(const struct intel_bios_encoder_data *devda
 const struct intel_bios_encoder_data *
 intel_bios_encoder_data_lookup(struct drm_i915_private *i915, enum port port)
 {
-       return i915->vbt.ddi_port_info[port].devdata;
+       return i915->vbt.ports[port];
 }
index 34fa4130d5c4f68fc0adc2d3096a8eaad1a5e029..9aec17b33819e764394694b7c1aaef087d6cef75 100644 (file)
@@ -2139,6 +2139,16 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state)
        /* Account for additional needs from the planes */
        min_cdclk = max(intel_planes_min_cdclk(crtc_state), min_cdclk);
 
+       /*
+        * VDSC engine can process only 1 pixel per Cd clock.
+        * In case VDSC is used and max slice count == 1,
+        * max supported pixel clock should be 100% of CD clock.
+        * Then do min_cdclk and pixel clock comparison to get cdclk.
+        */
+       if (crtc_state->dsc.compression_enable &&
+           crtc_state->dsc.slice_count == 1)
+               min_cdclk = max(min_cdclk, (int)crtc_state->pixel_rate);
+
        /*
         * HACK. Currently for TGL platforms we calculate
         * min_cdclk initially based on pixel_rate divided
index 9bed1ccecea0d249f94929a4b42d197336c9abf7..4f49d782eca2324af271af61b26832eaa7b40889 100644 (file)
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 
-#include "display/intel_panel.h"
-
 #include "i915_drv.h"
+#include "intel_backlight.h"
 #include "intel_connector.h"
 #include "intel_display_debugfs.h"
 #include "intel_display_types.h"
 #include "intel_hdcp.h"
+#include "intel_panel.h"
 
 int intel_connector_init(struct intel_connector *connector)
 {
index 9903a78df896fd141d035810f75351d5c0c0ade7..23ef291f7b30a6a27edd27eea24fc66e185a5694 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "i915_drv.h"
 #include "intel_audio.h"
+#include "intel_backlight.h"
 #include "intel_combo_phy.h"
 #include "intel_connector.h"
 #include "intel_crtc.h"
@@ -40,6 +41,7 @@
 #include "intel_dp_link_training.h"
 #include "intel_dp_mst.h"
 #include "intel_dpio_phy.h"
+#include "intel_drrs.h"
 #include "intel_dsi.h"
 #include "intel_fdi.h"
 #include "intel_fifo_underrun.h"
@@ -48,7 +50,6 @@
 #include "intel_hdmi.h"
 #include "intel_hotplug.h"
 #include "intel_lspcon.h"
-#include "intel_panel.h"
 #include "intel_pps.h"
 #include "intel_psr.h"
 #include "intel_snps_phy.h"
@@ -1371,7 +1372,8 @@ static int translate_signal_level(struct intel_dp *intel_dp,
        return 0;
 }
 
-static int intel_ddi_dp_level(struct intel_dp *intel_dp)
+static int intel_ddi_dp_level(struct intel_dp *intel_dp,
+                             const struct intel_crtc_state *crtc_state)
 {
        u8 train_set = intel_dp->train_set[0];
        u8 signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
@@ -1385,9 +1387,9 @@ dg2_set_signal_levels(struct intel_dp *intel_dp,
                      const struct intel_crtc_state *crtc_state)
 {
        struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-       int level = intel_ddi_dp_level(intel_dp);
+       int level = intel_ddi_dp_level(intel_dp, crtc_state);
 
-       intel_snps_phy_ddi_vswing_sequence(encoder, level);
+       intel_snps_phy_ddi_vswing_sequence(encoder, crtc_state, level);
 }
 
 static void
@@ -1395,7 +1397,7 @@ tgl_set_signal_levels(struct intel_dp *intel_dp,
                      const struct intel_crtc_state *crtc_state)
 {
        struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-       int level = intel_ddi_dp_level(intel_dp);
+       int level = intel_ddi_dp_level(intel_dp, crtc_state);
 
        tgl_ddi_vswing_sequence(encoder, crtc_state, level);
 }
@@ -1405,7 +1407,7 @@ icl_set_signal_levels(struct intel_dp *intel_dp,
                      const struct intel_crtc_state *crtc_state)
 {
        struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-       int level = intel_ddi_dp_level(intel_dp);
+       int level = intel_ddi_dp_level(intel_dp, crtc_state);
 
        icl_ddi_vswing_sequence(encoder, crtc_state, level);
 }
@@ -1415,7 +1417,7 @@ bxt_set_signal_levels(struct intel_dp *intel_dp,
                      const struct intel_crtc_state *crtc_state)
 {
        struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-       int level = intel_ddi_dp_level(intel_dp);
+       int level = intel_ddi_dp_level(intel_dp, crtc_state);
 
        bxt_ddi_vswing_sequence(encoder, crtc_state, level);
 }
@@ -1426,7 +1428,7 @@ hsw_set_signal_levels(struct intel_dp *intel_dp,
 {
        struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       int level = intel_ddi_dp_level(intel_dp);
+       int level = intel_ddi_dp_level(intel_dp, crtc_state);
        enum port port = encoder->port;
        u32 signal_levels;
 
@@ -2332,7 +2334,7 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state,
        enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
        struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
        bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
-       int level = intel_ddi_dp_level(intel_dp);
+       int level = intel_ddi_dp_level(intel_dp, crtc_state);
 
        intel_dp_set_link_params(intel_dp, crtc_state->port_clock,
                                 crtc_state->lane_count);
@@ -2391,7 +2393,7 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state,
         */
 
        /* 5.e Configure voltage swing and related IO settings */
-       intel_snps_phy_ddi_vswing_sequence(encoder, level);
+       intel_snps_phy_ddi_vswing_sequence(encoder, crtc_state, level);
 
        /*
         * 5.f Configure and enable DDI_BUF_CTL
@@ -2406,6 +2408,7 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state,
        if (!is_mst)
                intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
 
+       intel_dp_configure_protocol_converter(intel_dp, crtc_state);
        intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true);
        /*
         * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit
@@ -2413,6 +2416,8 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state,
         * training
         */
        intel_dp_sink_set_fec_ready(intel_dp, crtc_state);
+       intel_dp_check_frl_training(intel_dp);
+       intel_dp_pcon_dsc_configure(intel_dp, crtc_state);
 
        /*
         * 5.h Follow DisplayPort specification training sequence (see notes for
@@ -2442,7 +2447,7 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
        enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
        struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
        bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
-       int level = intel_ddi_dp_level(intel_dp);
+       int level = intel_ddi_dp_level(intel_dp, crtc_state);
 
        intel_dp_set_link_params(intel_dp,
                                 crtc_state->port_clock,
@@ -2585,7 +2590,7 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
        enum phy phy = intel_port_to_phy(dev_priv, port);
        struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
        bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
-       int level = intel_ddi_dp_level(intel_dp);
+       int level = intel_ddi_dp_level(intel_dp, crtc_state);
 
        if (DISPLAY_VER(dev_priv) < 11)
                drm_WARN_ON(&dev_priv->drm,
@@ -3010,7 +3015,7 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state,
        if (!dig_port->lspcon.active || dig_port->dp.has_hdmi_sink)
                intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
 
-       intel_edp_drrs_enable(intel_dp, crtc_state);
+       intel_drrs_enable(intel_dp, crtc_state);
 
        if (crtc_state->has_audio)
                intel_audio_codec_enable(encoder, crtc_state, conn_state);
@@ -3057,7 +3062,7 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state,
                            connector->base.id, connector->name);
 
        if (IS_DG2(dev_priv))
-               intel_snps_phy_ddi_vswing_sequence(encoder, U32_MAX);
+               intel_snps_phy_ddi_vswing_sequence(encoder, crtc_state, level);
        else if (DISPLAY_VER(dev_priv) >= 12)
                tgl_ddi_vswing_sequence(encoder, crtc_state, level);
        else if (DISPLAY_VER(dev_priv) == 11)
@@ -3198,7 +3203,7 @@ static void intel_pre_disable_ddi(struct intel_atomic_state *state,
                return;
 
        intel_dp = enc_to_intel_dp(encoder);
-       intel_edp_drrs_disable(intel_dp, old_crtc_state);
+       intel_drrs_disable(intel_dp, old_crtc_state);
        intel_psr_disable(intel_dp, old_crtc_state);
 }
 
@@ -3228,9 +3233,9 @@ static void intel_ddi_update_pipe_dp(struct intel_atomic_state *state,
 
        intel_psr_update(intel_dp, crtc_state, conn_state);
        intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
-       intel_edp_drrs_update(intel_dp, crtc_state);
+       intel_drrs_update(intel_dp, crtc_state);
 
-       intel_panel_update_backlight(state, encoder, crtc_state, conn_state);
+       intel_backlight_update(state, encoder, crtc_state, conn_state);
 }
 
 void intel_ddi_update_pipe(struct intel_atomic_state *state,
index ba2c08f1a797cd9ef66473d51a45dd2347c32aa6..796dd04eae012362c1a9864841cc053f0de6e9c1 100644 (file)
@@ -983,6 +983,49 @@ static const struct intel_ddi_buf_trans adlp_dkl_phy_ddi_translations_dp_hbr2_hb
        .num_entries = ARRAY_SIZE(_adlp_dkl_phy_ddi_translations_dp_hbr2_hbr3),
 };
 
+static const union intel_ddi_buf_trans_entry _dg2_snps_translations[] = {
+       { .snps = { 26, 0, 0 } },       /* VS 0, pre-emph 0 */
+       { .snps = { 33, 0, 6 } },       /* VS 0, pre-emph 1 */
+       { .snps = { 38, 0, 12 } },      /* VS 0, pre-emph 2 */
+       { .snps = { 43, 0, 19 } },      /* VS 0, pre-emph 3 */
+       { .snps = { 39, 0, 0 } },       /* VS 1, pre-emph 0 */
+       { .snps = { 44, 0, 8 } },       /* VS 1, pre-emph 1 */
+       { .snps = { 47, 0, 15 } },      /* VS 1, pre-emph 2 */
+       { .snps = { 52, 0, 0 } },       /* VS 2, pre-emph 0 */
+       { .snps = { 51, 0, 10 } },      /* VS 2, pre-emph 1 */
+       { .snps = { 62, 0, 0 } },       /* VS 3, pre-emph 0 */
+};
+
+static const struct intel_ddi_buf_trans dg2_snps_translations = {
+       .entries = _dg2_snps_translations,
+       .num_entries = ARRAY_SIZE(_dg2_snps_translations),
+       .hdmi_default_entry = ARRAY_SIZE(_dg2_snps_translations) - 1,
+};
+
+static const union intel_ddi_buf_trans_entry _dg2_snps_translations_uhbr[] = {
+       { .snps = { 62, 0, 0 } },       /* preset 0 */
+       { .snps = { 56, 0, 6 } },       /* preset 1 */
+       { .snps = { 51, 0, 11 } },      /* preset 2 */
+       { .snps = { 48, 0, 14 } },      /* preset 3 */
+       { .snps = { 43, 0, 19 } },      /* preset 4 */
+       { .snps = { 59, 3, 0 } },       /* preset 5 */
+       { .snps = { 53, 3, 6 } },       /* preset 6 */
+       { .snps = { 49, 3, 10 } },      /* preset 7 */
+       { .snps = { 45, 3, 14 } },      /* preset 8 */
+       { .snps = { 42, 3, 17 } },      /* preset 9 */
+       { .snps = { 56, 6, 0 } },       /* preset 10 */
+       { .snps = { 50, 6, 6 } },       /* preset 11 */
+       { .snps = { 47, 6, 9 } },       /* preset 12 */
+       { .snps = { 42, 6, 14 } },      /* preset 13 */
+       { .snps = { 46, 8, 8 } },       /* preset 14 */
+       { .snps = { 56, 3, 3 } },       /* preset 15 */
+};
+
+static const struct intel_ddi_buf_trans dg2_snps_translations_uhbr = {
+       .entries = _dg2_snps_translations_uhbr,
+       .num_entries = ARRAY_SIZE(_dg2_snps_translations_uhbr),
+};
+
 bool is_hobl_buf_trans(const struct intel_ddi_buf_trans *table)
 {
        return table == &tgl_combo_phy_ddi_translations_edp_hbr2_hobl;
@@ -1563,6 +1606,17 @@ adlp_get_dkl_buf_trans(struct intel_encoder *encoder,
                return adlp_get_dkl_buf_trans_dp(encoder, crtc_state, n_entries);
 }
 
+static const struct intel_ddi_buf_trans *
+dg2_get_snps_buf_trans(struct intel_encoder *encoder,
+                      const struct intel_crtc_state *crtc_state,
+                      int *n_entries)
+{
+       if (crtc_state->port_clock > 1000000)
+               return intel_get_buf_trans(&dg2_snps_translations_uhbr, n_entries);
+       else
+               return intel_get_buf_trans(&dg2_snps_translations, n_entries);
+}
+
 int intel_ddi_hdmi_num_entries(struct intel_encoder *encoder,
                               const struct intel_crtc_state *crtc_state,
                               int *default_entry)
@@ -1588,7 +1642,9 @@ void intel_ddi_buf_trans_init(struct intel_encoder *encoder)
        struct drm_i915_private *i915 = to_i915(encoder->base.dev);
        enum phy phy = intel_port_to_phy(i915, encoder->port);
 
-       if (IS_ALDERLAKE_P(i915)) {
+       if (IS_DG2(i915)) {
+               encoder->get_buf_trans = dg2_get_snps_buf_trans;
+       } else if (IS_ALDERLAKE_P(i915)) {
                if (intel_phy_is_combo(i915, phy))
                        encoder->get_buf_trans = adlp_get_combo_buf_trans;
                else
index 2acd720f9d4fd90efd375909288b062c4bd270dd..94d338287f61aff8f8c05cb262d5bc6ccd334207 100644 (file)
@@ -45,12 +45,19 @@ struct tgl_dkl_phy_ddi_buf_trans {
        u32 dkl_de_emphasis_control;
 };
 
+struct dg2_snps_phy_buf_trans {
+       u8 snps_vswing;
+       u8 snps_pre_cursor;
+       u8 snps_post_cursor;
+};
+
 union intel_ddi_buf_trans_entry {
        struct hsw_ddi_buf_trans hsw;
        struct bxt_ddi_buf_trans bxt;
        struct icl_ddi_buf_trans icl;
        struct icl_mg_phy_ddi_buf_trans mg;
        struct tgl_dkl_phy_ddi_buf_trans dkl;
+       struct dg2_snps_phy_buf_trans snps;
 };
 
 struct intel_ddi_buf_trans {
index 134a6acbd8fbe396584e2c7590c2c8796da1aaf2..a7ca38613f89a2cb9418d2632abb6ba01997045e 100644 (file)
@@ -52,6 +52,7 @@
 #include "display/intel_dp_mst.h"
 #include "display/intel_dpll.h"
 #include "display/intel_dpll_mgr.h"
+#include "display/intel_drrs.h"
 #include "display/intel_dsi.h"
 #include "display/intel_dvo.h"
 #include "display/intel_fb.h"
@@ -84,6 +85,7 @@
 #include "intel_display_types.h"
 #include "intel_dmc.h"
 #include "intel_dp_link_training.h"
+#include "intel_dpt.h"
 #include "intel_fbc.h"
 #include "intel_fdi.h"
 #include "intel_fbdev.h"
@@ -92,6 +94,7 @@
 #include "intel_hdcp.h"
 #include "intel_hotplug.h"
 #include "intel_overlay.h"
+#include "intel_panel.h"
 #include "intel_pipe_crc.h"
 #include "intel_pm.h"
 #include "intel_pps.h"
@@ -110,9 +113,6 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
 static void ilk_pch_clock_get(struct intel_crtc *crtc,
                              struct intel_crtc_state *pipe_config);
 
-static int intel_framebuffer_init(struct intel_framebuffer *ifb,
-                                 struct drm_i915_gem_object *obj,
-                                 struct drm_mode_fb_cmd2 *mode_cmd);
 static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state);
 static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state);
 static void intel_cpu_transcoder_set_m_n(const struct intel_crtc_state *crtc_state,
@@ -126,182 +126,6 @@ static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state);
 static void intel_modeset_setup_hw_state(struct drm_device *dev,
                                         struct drm_modeset_acquire_ctx *ctx);
 
-struct i915_dpt {
-       struct i915_address_space vm;
-
-       struct drm_i915_gem_object *obj;
-       struct i915_vma *vma;
-       void __iomem *iomem;
-};
-
-#define i915_is_dpt(vm) ((vm)->is_dpt)
-
-static inline struct i915_dpt *
-i915_vm_to_dpt(struct i915_address_space *vm)
-{
-       BUILD_BUG_ON(offsetof(struct i915_dpt, vm));
-       GEM_BUG_ON(!i915_is_dpt(vm));
-       return container_of(vm, struct i915_dpt, vm);
-}
-
-#define dpt_total_entries(dpt) ((dpt)->vm.total >> PAGE_SHIFT)
-
-static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte)
-{
-       writeq(pte, addr);
-}
-
-static void dpt_insert_page(struct i915_address_space *vm,
-                           dma_addr_t addr,
-                           u64 offset,
-                           enum i915_cache_level level,
-                           u32 flags)
-{
-       struct i915_dpt *dpt = i915_vm_to_dpt(vm);
-       gen8_pte_t __iomem *base = dpt->iomem;
-
-       gen8_set_pte(base + offset / I915_GTT_PAGE_SIZE,
-                    vm->pte_encode(addr, level, flags));
-}
-
-static void dpt_insert_entries(struct i915_address_space *vm,
-                              struct i915_vma *vma,
-                              enum i915_cache_level level,
-                              u32 flags)
-{
-       struct i915_dpt *dpt = i915_vm_to_dpt(vm);
-       gen8_pte_t __iomem *base = dpt->iomem;
-       const gen8_pte_t pte_encode = vm->pte_encode(0, level, flags);
-       struct sgt_iter sgt_iter;
-       dma_addr_t addr;
-       int i;
-
-       /*
-        * Note that we ignore PTE_READ_ONLY here. The caller must be careful
-        * not to allow the user to override access to a read only page.
-        */
-
-       i = vma->node.start / I915_GTT_PAGE_SIZE;
-       for_each_sgt_daddr(addr, sgt_iter, vma->pages)
-               gen8_set_pte(&base[i++], pte_encode | addr);
-}
-
-static void dpt_clear_range(struct i915_address_space *vm,
-                           u64 start, u64 length)
-{
-}
-
-static void dpt_bind_vma(struct i915_address_space *vm,
-                        struct i915_vm_pt_stash *stash,
-                        struct i915_vma *vma,
-                        enum i915_cache_level cache_level,
-                        u32 flags)
-{
-       struct drm_i915_gem_object *obj = vma->obj;
-       u32 pte_flags;
-
-       /* Applicable to VLV (gen8+ do not support RO in the GGTT) */
-       pte_flags = 0;
-       if (vma->vm->has_read_only && i915_gem_object_is_readonly(obj))
-               pte_flags |= PTE_READ_ONLY;
-       if (i915_gem_object_is_lmem(obj))
-               pte_flags |= PTE_LM;
-
-       vma->vm->insert_entries(vma->vm, vma, cache_level, pte_flags);
-
-       vma->page_sizes.gtt = I915_GTT_PAGE_SIZE;
-
-       /*
-        * Without aliasing PPGTT there's no difference between
-        * GLOBAL/LOCAL_BIND, it's all the same ptes. Hence unconditionally
-        * upgrade to both bound if we bind either to avoid double-binding.
-        */
-       atomic_or(I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND, &vma->flags);
-}
-
-static void dpt_unbind_vma(struct i915_address_space *vm, struct i915_vma *vma)
-{
-       vm->clear_range(vm, vma->node.start, vma->size);
-}
-
-static void dpt_cleanup(struct i915_address_space *vm)
-{
-       struct i915_dpt *dpt = i915_vm_to_dpt(vm);
-
-       i915_gem_object_put(dpt->obj);
-}
-
-static struct i915_address_space *
-intel_dpt_create(struct intel_framebuffer *fb)
-{
-       struct drm_gem_object *obj = &intel_fb_obj(&fb->base)->base;
-       struct drm_i915_private *i915 = to_i915(obj->dev);
-       struct drm_i915_gem_object *dpt_obj;
-       struct i915_address_space *vm;
-       struct i915_dpt *dpt;
-       size_t size;
-       int ret;
-
-       if (intel_fb_needs_pot_stride_remap(fb))
-               size = intel_remapped_info_size(&fb->remapped_view.gtt.remapped);
-       else
-               size = DIV_ROUND_UP_ULL(obj->size, I915_GTT_PAGE_SIZE);
-
-       size = round_up(size * sizeof(gen8_pte_t), I915_GTT_PAGE_SIZE);
-
-       if (HAS_LMEM(i915))
-               dpt_obj = i915_gem_object_create_lmem(i915, size, 0);
-       else
-               dpt_obj = i915_gem_object_create_stolen(i915, size);
-       if (IS_ERR(dpt_obj))
-               return ERR_CAST(dpt_obj);
-
-       ret = i915_gem_object_set_cache_level(dpt_obj, I915_CACHE_NONE);
-       if (ret) {
-               i915_gem_object_put(dpt_obj);
-               return ERR_PTR(ret);
-       }
-
-       dpt = kzalloc(sizeof(*dpt), GFP_KERNEL);
-       if (!dpt) {
-               i915_gem_object_put(dpt_obj);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       vm = &dpt->vm;
-
-       vm->gt = &i915->gt;
-       vm->i915 = i915;
-       vm->dma = i915->drm.dev;
-       vm->total = (size / sizeof(gen8_pte_t)) * I915_GTT_PAGE_SIZE;
-       vm->is_dpt = true;
-
-       i915_address_space_init(vm, VM_CLASS_DPT);
-
-       vm->insert_page = dpt_insert_page;
-       vm->clear_range = dpt_clear_range;
-       vm->insert_entries = dpt_insert_entries;
-       vm->cleanup = dpt_cleanup;
-
-       vm->vma_ops.bind_vma    = dpt_bind_vma;
-       vm->vma_ops.unbind_vma  = dpt_unbind_vma;
-       vm->vma_ops.set_pages   = ggtt_set_pages;
-       vm->vma_ops.clear_pages = clear_pages;
-
-       vm->pte_encode = gen8_ggtt_pte_encode;
-
-       dpt->obj = dpt_obj;
-
-       return &dpt->vm;
-}
-
-static void intel_dpt_destroy(struct i915_address_space *vm)
-{
-       struct i915_dpt *dpt = i915_vm_to_dpt(vm);
-
-       i915_vm_close(&dpt->vm);
-}
-
 /* returns HPLL frequency in kHz */
 int vlv_get_hpll_vco(struct drm_i915_private *dev_priv)
 {
@@ -1053,69 +877,6 @@ intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info,
               info->num_planes == (is_ccs_modifier(modifier) ? 4 : 2);
 }
 
-unsigned int
-intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
-{
-       struct drm_i915_private *dev_priv = to_i915(fb->dev);
-       unsigned int cpp = fb->format->cpp[color_plane];
-
-       switch (fb->modifier) {
-       case DRM_FORMAT_MOD_LINEAR:
-               return intel_tile_size(dev_priv);
-       case I915_FORMAT_MOD_X_TILED:
-               if (DISPLAY_VER(dev_priv) == 2)
-                       return 128;
-               else
-                       return 512;
-       case I915_FORMAT_MOD_Y_TILED_CCS:
-               if (is_ccs_plane(fb, color_plane))
-                       return 128;
-               fallthrough;
-       case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
-       case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
-       case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
-               if (is_ccs_plane(fb, color_plane))
-                       return 64;
-               fallthrough;
-       case I915_FORMAT_MOD_Y_TILED:
-               if (DISPLAY_VER(dev_priv) == 2 || HAS_128_BYTE_Y_TILING(dev_priv))
-                       return 128;
-               else
-                       return 512;
-       case I915_FORMAT_MOD_Yf_TILED_CCS:
-               if (is_ccs_plane(fb, color_plane))
-                       return 128;
-               fallthrough;
-       case I915_FORMAT_MOD_Yf_TILED:
-               switch (cpp) {
-               case 1:
-                       return 64;
-               case 2:
-               case 4:
-                       return 128;
-               case 8:
-               case 16:
-                       return 256;
-               default:
-                       MISSING_CASE(cpp);
-                       return cpp;
-               }
-               break;
-       default:
-               MISSING_CASE(fb->modifier);
-               return cpp;
-       }
-}
-
-unsigned int
-intel_fb_align_height(const struct drm_framebuffer *fb,
-                     int color_plane, unsigned int height)
-{
-       unsigned int tile_height = intel_tile_height(fb, color_plane);
-
-       return ALIGN(height, tile_height);
-}
-
 unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info)
 {
        unsigned int size = 0;
@@ -1138,75 +899,6 @@ unsigned int intel_remapped_info_size(const struct intel_remapped_info *rem_info
        return size;
 }
 
-static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv)
-{
-       if (DISPLAY_VER(dev_priv) >= 9)
-               return 256 * 1024;
-       else if (IS_I965G(dev_priv) || IS_I965GM(dev_priv) ||
-                IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-               return 128 * 1024;
-       else if (DISPLAY_VER(dev_priv) >= 4)
-               return 4 * 1024;
-       else
-               return 0;
-}
-
-static bool has_async_flips(struct drm_i915_private *i915)
-{
-       return DISPLAY_VER(i915) >= 5;
-}
-
-unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
-                                 int color_plane)
-{
-       struct drm_i915_private *dev_priv = to_i915(fb->dev);
-
-       if (intel_fb_uses_dpt(fb))
-               return 512 * 4096;
-
-       /* AUX_DIST needs only 4K alignment */
-       if (is_ccs_plane(fb, color_plane))
-               return 4096;
-
-       if (is_semiplanar_uv_plane(fb, color_plane)) {
-               /*
-                * TODO: cross-check wrt. the bspec stride in bytes * 64 bytes
-                * alignment for linear UV planes on all platforms.
-                */
-               if (DISPLAY_VER(dev_priv) >= 12) {
-                       if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
-                               return intel_linear_alignment(dev_priv);
-
-                       return intel_tile_row_size(fb, color_plane);
-               }
-
-               return 4096;
-       }
-
-       drm_WARN_ON(&dev_priv->drm, color_plane != 0);
-
-       switch (fb->modifier) {
-       case DRM_FORMAT_MOD_LINEAR:
-               return intel_linear_alignment(dev_priv);
-       case I915_FORMAT_MOD_X_TILED:
-               if (has_async_flips(dev_priv))
-                       return 256 * 1024;
-               return 0;
-       case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
-       case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
-       case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
-               return 16 * 1024;
-       case I915_FORMAT_MOD_Y_TILED_CCS:
-       case I915_FORMAT_MOD_Yf_TILED_CCS:
-       case I915_FORMAT_MOD_Y_TILED:
-       case I915_FORMAT_MOD_Yf_TILED:
-               return 1 * 1024 * 1024;
-       default:
-               MISSING_CASE(fb->modifier);
-               return 0;
-       }
-}
-
 static bool intel_plane_uses_fence(const struct intel_plane_state *plane_state)
 {
        struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
@@ -1440,22 +1132,6 @@ void intel_add_fb_offsets(int *x, int *y,
        *y += state->view.color_plane[color_plane].y;
 }
 
-static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
-{
-       switch (fb_modifier) {
-       case I915_FORMAT_MOD_X_TILED:
-               return I915_TILING_X;
-       case I915_FORMAT_MOD_Y_TILED:
-       case I915_FORMAT_MOD_Y_TILED_CCS:
-       case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
-       case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
-       case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
-               return I915_TILING_Y;
-       default:
-               return I915_TILING_NONE;
-       }
-}
-
 /*
  * From the Sky Lake PRM:
  * "The Color Control Surface (CCS) contains the compression status of
@@ -1586,12 +1262,6 @@ intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
        }
 }
 
-static int gen12_ccs_aux_stride(struct drm_framebuffer *fb, int ccs_plane)
-{
-       return DIV_ROUND_UP(fb->pitches[skl_ccs_to_main_plane(fb, ccs_plane)],
-                           512) * 64;
-}
-
 u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
                              u32 pixel_format, u64 modifier)
 {
@@ -1616,71 +1286,6 @@ u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
                                 DRM_MODE_ROTATE_0);
 }
 
-static
-u32 intel_fb_max_stride(struct drm_i915_private *dev_priv,
-                       u32 pixel_format, u64 modifier)
-{
-       /*
-        * Arbitrary limit for gen4+ chosen to match the
-        * render engine max stride.
-        *
-        * The new CCS hash mode makes remapping impossible
-        */
-       if (DISPLAY_VER(dev_priv) < 4 || is_ccs_modifier(modifier) ||
-           intel_modifier_uses_dpt(dev_priv, modifier))
-               return intel_plane_fb_max_stride(dev_priv, pixel_format, modifier);
-       else if (DISPLAY_VER(dev_priv) >= 7)
-               return 256 * 1024;
-       else
-               return 128 * 1024;
-}
-
-static u32
-intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
-{
-       struct drm_i915_private *dev_priv = to_i915(fb->dev);
-       u32 tile_width;
-
-       if (is_surface_linear(fb, color_plane)) {
-               u32 max_stride = intel_plane_fb_max_stride(dev_priv,
-                                                          fb->format->format,
-                                                          fb->modifier);
-
-               /*
-                * To make remapping with linear generally feasible
-                * we need the stride to be page aligned.
-                */
-               if (fb->pitches[color_plane] > max_stride &&
-                   !is_ccs_modifier(fb->modifier))
-                       return intel_tile_size(dev_priv);
-               else
-                       return 64;
-       }
-
-       tile_width = intel_tile_width_bytes(fb, color_plane);
-       if (is_ccs_modifier(fb->modifier)) {
-               /*
-                * Display WA #0531: skl,bxt,kbl,glk
-                *
-                * Render decompression and plane width > 3840
-                * combined with horizontal panning requires the
-                * plane stride to be a multiple of 4. We'll just
-                * require the entire fb to accommodate that to avoid
-                * potential runtime errors at plane configuration time.
-                */
-               if ((DISPLAY_VER(dev_priv) == 9 || IS_GEMINILAKE(dev_priv)) &&
-                   color_plane == 0 && fb->width > 3840)
-                       tile_width *= 4;
-               /*
-                * The main surface pitch must be padded to a multiple of four
-                * tile widths.
-                */
-               else if (DISPLAY_VER(dev_priv) >= 12)
-                       tile_width *= 4;
-       }
-       return tile_width;
-}
-
 static struct i915_vma *
 initial_plane_vma(struct drm_i915_private *i915,
                  struct intel_initial_plane_config *plane_config)
@@ -1879,49 +1484,6 @@ static void intel_plane_disable_noatomic(struct intel_crtc *crtc,
        intel_wait_for_vblank(dev_priv, crtc->pipe);
 }
 
-static struct i915_vma *intel_dpt_pin(struct i915_address_space *vm)
-{
-       struct drm_i915_private *i915 = vm->i915;
-       struct i915_dpt *dpt = i915_vm_to_dpt(vm);
-       intel_wakeref_t wakeref;
-       struct i915_vma *vma;
-       void __iomem *iomem;
-
-       wakeref = intel_runtime_pm_get(&i915->runtime_pm);
-       atomic_inc(&i915->gpu_error.pending_fb_pin);
-
-       vma = i915_gem_object_ggtt_pin(dpt->obj, NULL, 0, 4096,
-                                      HAS_LMEM(i915) ? 0 : PIN_MAPPABLE);
-       if (IS_ERR(vma))
-               goto err;
-
-       iomem = i915_vma_pin_iomap(vma);
-       i915_vma_unpin(vma);
-       if (IS_ERR(iomem)) {
-               vma = iomem;
-               goto err;
-       }
-
-       dpt->vma = vma;
-       dpt->iomem = iomem;
-
-       i915_vma_get(vma);
-
-err:
-       atomic_dec(&i915->gpu_error.pending_fb_pin);
-       intel_runtime_pm_put(&i915->runtime_pm, wakeref);
-
-       return vma;
-}
-
-static void intel_dpt_unpin(struct i915_address_space *vm)
-{
-       struct i915_dpt *dpt = i915_vm_to_dpt(vm);
-
-       i915_vma_unpin_iomap(dpt->vma);
-       i915_vma_put(dpt->vma);
-}
-
 static bool
 intel_reuse_initial_plane_obj(struct drm_i915_private *i915,
                              const struct intel_initial_plane_config *plane_config,
@@ -2449,55 +2011,6 @@ static void ilk_pch_transcoder_set_timings(const struct intel_crtc_state *crtc_s
                       intel_de_read(dev_priv, VSYNCSHIFT(cpu_transcoder)));
 }
 
-static void cpt_set_fdi_bc_bifurcation(struct drm_i915_private *dev_priv, bool enable)
-{
-       u32 temp;
-
-       temp = intel_de_read(dev_priv, SOUTH_CHICKEN1);
-       if (!!(temp & FDI_BC_BIFURCATION_SELECT) == enable)
-               return;
-
-       drm_WARN_ON(&dev_priv->drm,
-                   intel_de_read(dev_priv, FDI_RX_CTL(PIPE_B)) &
-                   FDI_RX_ENABLE);
-       drm_WARN_ON(&dev_priv->drm,
-                   intel_de_read(dev_priv, FDI_RX_CTL(PIPE_C)) &
-                   FDI_RX_ENABLE);
-
-       temp &= ~FDI_BC_BIFURCATION_SELECT;
-       if (enable)
-               temp |= FDI_BC_BIFURCATION_SELECT;
-
-       drm_dbg_kms(&dev_priv->drm, "%sabling fdi C rx\n",
-                   enable ? "en" : "dis");
-       intel_de_write(dev_priv, SOUTH_CHICKEN1, temp);
-       intel_de_posting_read(dev_priv, SOUTH_CHICKEN1);
-}
-
-static void ivb_update_fdi_bc_bifurcation(const struct intel_crtc_state *crtc_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-
-       switch (crtc->pipe) {
-       case PIPE_A:
-               break;
-       case PIPE_B:
-               if (crtc_state->fdi_lanes > 2)
-                       cpt_set_fdi_bc_bifurcation(dev_priv, false);
-               else
-                       cpt_set_fdi_bc_bifurcation(dev_priv, true);
-
-               break;
-       case PIPE_C:
-               cpt_set_fdi_bc_bifurcation(dev_priv, true);
-
-               break;
-       default:
-               BUG();
-       }
-}
-
 /*
  * Finds the encoder associated with the given CRTC. This can only be
  * used when we know that the CRTC isn't feeding multiple encoders!
@@ -2547,14 +2060,6 @@ static void ilk_pch_enable(const struct intel_atomic_state *state,
 
        assert_pch_transcoder_disabled(dev_priv, pipe);
 
-       if (IS_IVYBRIDGE(dev_priv))
-               ivb_update_fdi_bc_bifurcation(crtc_state);
-
-       /* Write the TU size bits before fdi link training, so that error
-        * detection works. */
-       intel_de_write(dev_priv, FDI_RX_TUSIZE1(pipe),
-                      intel_de_read(dev_priv, PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
-
        /* For PCH output, training FDI link */
        dev_priv->display.fdi_link_train(crtc, crtc_state);
 
@@ -2875,6 +2380,7 @@ static void intel_post_plane_update(struct intel_atomic_state *state,
                hsw_enable_ips(new_crtc_state);
 
        intel_fbc_post_update(state, crtc);
+       intel_drrs_page_flip(state, crtc);
 
        if (needs_nv12_wa(old_crtc_state) &&
            !needs_nv12_wa(new_crtc_state))
@@ -3360,9 +2866,6 @@ static void ilk_crtc_enable(struct intel_atomic_state *state,
        intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
        intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
 
-       if (new_crtc_state->has_pch_encoder)
-               intel_prepare_shared_dpll(new_crtc_state);
-
        if (intel_crtc_has_dp_encoder(new_crtc_state))
                intel_dp_set_m_n(new_crtc_state, M1_N1);
 
@@ -4015,13 +3518,10 @@ static void valleyview_crtc_enable(struct intel_atomic_state *state,
 
        intel_encoders_pre_pll_enable(state, crtc);
 
-       if (IS_CHERRYVIEW(dev_priv)) {
-               chv_prepare_pll(crtc, new_crtc_state);
-               chv_enable_pll(crtc, new_crtc_state);
-       } else {
-               vlv_prepare_pll(crtc, new_crtc_state);
-               vlv_enable_pll(crtc, new_crtc_state);
-       }
+       if (IS_CHERRYVIEW(dev_priv))
+               chv_enable_pll(new_crtc_state);
+       else
+               vlv_enable_pll(new_crtc_state);
 
        intel_encoders_pre_enable(state, crtc);
 
@@ -4040,17 +3540,6 @@ static void valleyview_crtc_enable(struct intel_atomic_state *state,
        intel_encoders_enable(state, crtc);
 }
 
-static void i9xx_set_pll_dividers(const struct intel_crtc_state *crtc_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-
-       intel_de_write(dev_priv, FP0(crtc->pipe),
-                      crtc_state->dpll_hw_state.fp0);
-       intel_de_write(dev_priv, FP1(crtc->pipe),
-                      crtc_state->dpll_hw_state.fp1);
-}
-
 static void i9xx_crtc_enable(struct intel_atomic_state *state,
                             struct intel_crtc *crtc)
 {
@@ -4062,8 +3551,6 @@ static void i9xx_crtc_enable(struct intel_atomic_state *state,
        if (drm_WARN_ON(&dev_priv->drm, crtc->active))
                return;
 
-       i9xx_set_pll_dividers(new_crtc_state);
-
        if (intel_crtc_has_dp_encoder(new_crtc_state))
                intel_dp_set_m_n(new_crtc_state, M1_N1);
 
@@ -4079,7 +3566,7 @@ static void i9xx_crtc_enable(struct intel_atomic_state *state,
 
        intel_encoders_pre_enable(state, crtc);
 
-       i9xx_enable_pll(crtc, new_crtc_state);
+       i9xx_enable_pll(new_crtc_state);
 
        i9xx_pfit_enable(new_crtc_state);
 
@@ -4239,7 +3726,6 @@ static void intel_crtc_disable_noatomic(struct intel_crtc *crtc,
 
        intel_display_power_put_all_in_set(dev_priv, &crtc->enabled_power_domains);
 
-       dev_priv->active_pipes &= ~BIT(pipe);
        cdclk_state->min_cdclk[pipe] = 0;
        cdclk_state->min_voltage_level[pipe] = 0;
        cdclk_state->active_pipes &= ~BIT(pipe);
@@ -5412,102 +4898,6 @@ static void ilk_init_pch_refclk(struct drm_i915_private *dev_priv)
        BUG_ON(val != final);
 }
 
-static void lpt_reset_fdi_mphy(struct drm_i915_private *dev_priv)
-{
-       u32 tmp;
-
-       tmp = intel_de_read(dev_priv, SOUTH_CHICKEN2);
-       tmp |= FDI_MPHY_IOSFSB_RESET_CTL;
-       intel_de_write(dev_priv, SOUTH_CHICKEN2, tmp);
-
-       if (wait_for_us(intel_de_read(dev_priv, SOUTH_CHICKEN2) &
-                       FDI_MPHY_IOSFSB_RESET_STATUS, 100))
-               drm_err(&dev_priv->drm, "FDI mPHY reset assert timeout\n");
-
-       tmp = intel_de_read(dev_priv, SOUTH_CHICKEN2);
-       tmp &= ~FDI_MPHY_IOSFSB_RESET_CTL;
-       intel_de_write(dev_priv, SOUTH_CHICKEN2, tmp);
-
-       if (wait_for_us((intel_de_read(dev_priv, SOUTH_CHICKEN2) &
-                        FDI_MPHY_IOSFSB_RESET_STATUS) == 0, 100))
-               drm_err(&dev_priv->drm, "FDI mPHY reset de-assert timeout\n");
-}
-
-/* WaMPhyProgramming:hsw */
-static void lpt_program_fdi_mphy(struct drm_i915_private *dev_priv)
-{
-       u32 tmp;
-
-       tmp = intel_sbi_read(dev_priv, 0x8008, SBI_MPHY);
-       tmp &= ~(0xFF << 24);
-       tmp |= (0x12 << 24);
-       intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x2008, SBI_MPHY);
-       tmp |= (1 << 11);
-       intel_sbi_write(dev_priv, 0x2008, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x2108, SBI_MPHY);
-       tmp |= (1 << 11);
-       intel_sbi_write(dev_priv, 0x2108, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x206C, SBI_MPHY);
-       tmp |= (1 << 24) | (1 << 21) | (1 << 18);
-       intel_sbi_write(dev_priv, 0x206C, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x216C, SBI_MPHY);
-       tmp |= (1 << 24) | (1 << 21) | (1 << 18);
-       intel_sbi_write(dev_priv, 0x216C, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY);
-       tmp &= ~(7 << 13);
-       tmp |= (5 << 13);
-       intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY);
-       tmp &= ~(7 << 13);
-       tmp |= (5 << 13);
-       intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x208C, SBI_MPHY);
-       tmp &= ~0xFF;
-       tmp |= 0x1C;
-       intel_sbi_write(dev_priv, 0x208C, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x218C, SBI_MPHY);
-       tmp &= ~0xFF;
-       tmp |= 0x1C;
-       intel_sbi_write(dev_priv, 0x218C, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x2098, SBI_MPHY);
-       tmp &= ~(0xFF << 16);
-       tmp |= (0x1C << 16);
-       intel_sbi_write(dev_priv, 0x2098, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x2198, SBI_MPHY);
-       tmp &= ~(0xFF << 16);
-       tmp |= (0x1C << 16);
-       intel_sbi_write(dev_priv, 0x2198, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY);
-       tmp |= (1 << 27);
-       intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY);
-       tmp |= (1 << 27);
-       intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY);
-       tmp &= ~(0xF << 28);
-       tmp |= (4 << 28);
-       intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY);
-
-       tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY);
-       tmp &= ~(0xF << 28);
-       tmp |= (4 << 28);
-       intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY);
-}
-
 /* Implements 3 different sequences from BSpec chapter "Display iCLK
  * Programming" based on the parameters passed:
  * - Sequence to enable CLKOUT_DP
@@ -5540,10 +4930,8 @@ static void lpt_enable_clkout_dp(struct drm_i915_private *dev_priv,
                tmp &= ~SBI_SSCCTL_PATHALT;
                intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
 
-               if (with_fdi) {
-                       lpt_reset_fdi_mphy(dev_priv);
-                       lpt_program_fdi_mphy(dev_priv);
-               }
+               if (with_fdi)
+                       lpt_fdi_program_mphy(dev_priv);
        }
 
        reg = HAS_PCH_LPT_LP(dev_priv) ? SBI_GEN0 : SBI_DBUFF0;
@@ -6531,28 +5919,6 @@ static const struct drm_display_mode load_detect_mode = {
                 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
 };
 
-struct drm_framebuffer *
-intel_framebuffer_create(struct drm_i915_gem_object *obj,
-                        struct drm_mode_fb_cmd2 *mode_cmd)
-{
-       struct intel_framebuffer *intel_fb;
-       int ret;
-
-       intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
-       if (!intel_fb)
-               return ERR_PTR(-ENOMEM);
-
-       ret = intel_framebuffer_init(intel_fb, obj, mode_cmd);
-       if (ret)
-               goto err;
-
-       return &intel_fb->base;
-
-err:
-       kfree(intel_fb);
-       return ERR_PTR(ret);
-}
-
 static int intel_modeset_disable_planes(struct drm_atomic_state *state,
                                        struct drm_crtc *crtc)
 {
@@ -6780,7 +6146,6 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       enum pipe pipe = crtc->pipe;
        u32 dpll = pipe_config->dpll_hw_state.dpll;
        u32 fp;
        struct dpll clock;
@@ -6830,11 +6195,13 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
                else
                        port_clock = i9xx_calc_dpll_params(refclk, &clock);
        } else {
-               u32 lvds = IS_I830(dev_priv) ? 0 : intel_de_read(dev_priv,
-                                                                LVDS);
-               bool is_lvds = (pipe == 1) && (lvds & LVDS_PORT_EN);
+               enum pipe lvds_pipe;
+
+               if (IS_I85X(dev_priv) &&
+                   intel_lvds_port_enabled(dev_priv, LVDS, &lvds_pipe) &&
+                   lvds_pipe == crtc->pipe) {
+                       u32 lvds = intel_de_read(dev_priv, LVDS);
 
-               if (is_lvds) {
                        clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >>
                                       DPLL_FPA01_P1_POST_DIV_SHIFT);
 
@@ -7366,7 +6733,7 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state,
            dev_priv->display.crtc_compute_clock &&
            !crtc_state->bigjoiner_slave &&
            !drm_WARN_ON(&dev_priv->drm, crtc_state->shared_dpll)) {
-               ret = dev_priv->display.crtc_compute_clock(crtc, crtc_state);
+               ret = dev_priv->display.crtc_compute_clock(crtc_state);
                if (ret)
                        return ret;
        }
@@ -10404,10 +9771,7 @@ static void intel_update_crtc(struct intel_atomic_state *state,
                        intel_encoders_update_pipe(state, crtc);
        }
 
-       if (new_crtc_state->update_pipe && !new_crtc_state->enable_fbc)
-               intel_fbc_disable(crtc);
-       else
-               intel_fbc_enable(state, crtc);
+       intel_fbc_update(state, crtc);
 
        /* Perform vblank evasion around commit operation */
        intel_pipe_update_start(new_crtc_state);
@@ -11491,6 +10855,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
                intel_ddi_init(dev_priv, PORT_TC2);
                intel_ddi_init(dev_priv, PORT_TC3);
                intel_ddi_init(dev_priv, PORT_TC4);
+               icl_dsi_init(dev_priv);
        } else if (IS_ALDERLAKE_S(dev_priv)) {
                intel_ddi_init(dev_priv, PORT_A);
                intel_ddi_init(dev_priv, PORT_TC1);
@@ -11708,249 +11073,6 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
        drm_helper_move_panel_connectors_to_head(&dev_priv->drm);
 }
 
-static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
-{
-       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
-
-       drm_framebuffer_cleanup(fb);
-
-       if (intel_fb_uses_dpt(fb))
-               intel_dpt_destroy(intel_fb->dpt_vm);
-
-       intel_frontbuffer_put(intel_fb->frontbuffer);
-
-       kfree(intel_fb);
-}
-
-static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb,
-                                               struct drm_file *file,
-                                               unsigned int *handle)
-{
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-       struct drm_i915_private *i915 = to_i915(obj->base.dev);
-
-       if (i915_gem_object_is_userptr(obj)) {
-               drm_dbg(&i915->drm,
-                       "attempting to use a userptr for a framebuffer, denied\n");
-               return -EINVAL;
-       }
-
-       return drm_gem_handle_create(file, &obj->base, handle);
-}
-
-static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb,
-                                       struct drm_file *file,
-                                       unsigned flags, unsigned color,
-                                       struct drm_clip_rect *clips,
-                                       unsigned num_clips)
-{
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-
-       i915_gem_object_flush_if_display(obj);
-       intel_frontbuffer_flush(to_intel_frontbuffer(fb), ORIGIN_DIRTYFB);
-
-       return 0;
-}
-
-static const struct drm_framebuffer_funcs intel_fb_funcs = {
-       .destroy = intel_user_framebuffer_destroy,
-       .create_handle = intel_user_framebuffer_create_handle,
-       .dirty = intel_user_framebuffer_dirty,
-};
-
-static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
-                                 struct drm_i915_gem_object *obj,
-                                 struct drm_mode_fb_cmd2 *mode_cmd)
-{
-       struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
-       struct drm_framebuffer *fb = &intel_fb->base;
-       u32 max_stride;
-       unsigned int tiling, stride;
-       int ret = -EINVAL;
-       int i;
-
-       intel_fb->frontbuffer = intel_frontbuffer_get(obj);
-       if (!intel_fb->frontbuffer)
-               return -ENOMEM;
-
-       i915_gem_object_lock(obj, NULL);
-       tiling = i915_gem_object_get_tiling(obj);
-       stride = i915_gem_object_get_stride(obj);
-       i915_gem_object_unlock(obj);
-
-       if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) {
-               /*
-                * If there's a fence, enforce that
-                * the fb modifier and tiling mode match.
-                */
-               if (tiling != I915_TILING_NONE &&
-                   tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
-                       drm_dbg_kms(&dev_priv->drm,
-                                   "tiling_mode doesn't match fb modifier\n");
-                       goto err;
-               }
-       } else {
-               if (tiling == I915_TILING_X) {
-                       mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED;
-               } else if (tiling == I915_TILING_Y) {
-                       drm_dbg_kms(&dev_priv->drm,
-                                   "No Y tiling for legacy addfb\n");
-                       goto err;
-               }
-       }
-
-       if (!drm_any_plane_has_format(&dev_priv->drm,
-                                     mode_cmd->pixel_format,
-                                     mode_cmd->modifier[0])) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "unsupported pixel format %p4cc / modifier 0x%llx\n",
-                           &mode_cmd->pixel_format, mode_cmd->modifier[0]);
-               goto err;
-       }
-
-       /*
-        * gen2/3 display engine uses the fence if present,
-        * so the tiling mode must match the fb modifier exactly.
-        */
-       if (DISPLAY_VER(dev_priv) < 4 &&
-           tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "tiling_mode must match fb modifier exactly on gen2/3\n");
-               goto err;
-       }
-
-       max_stride = intel_fb_max_stride(dev_priv, mode_cmd->pixel_format,
-                                        mode_cmd->modifier[0]);
-       if (mode_cmd->pitches[0] > max_stride) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "%s pitch (%u) must be at most %d\n",
-                           mode_cmd->modifier[0] != DRM_FORMAT_MOD_LINEAR ?
-                           "tiled" : "linear",
-                           mode_cmd->pitches[0], max_stride);
-               goto err;
-       }
-
-       /*
-        * If there's a fence, enforce that
-        * the fb pitch and fence stride match.
-        */
-       if (tiling != I915_TILING_NONE && mode_cmd->pitches[0] != stride) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "pitch (%d) must match tiling stride (%d)\n",
-                           mode_cmd->pitches[0], stride);
-               goto err;
-       }
-
-       /* FIXME need to adjust LINOFF/TILEOFF accordingly. */
-       if (mode_cmd->offsets[0] != 0) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "plane 0 offset (0x%08x) must be 0\n",
-                           mode_cmd->offsets[0]);
-               goto err;
-       }
-
-       drm_helper_mode_fill_fb_struct(&dev_priv->drm, fb, mode_cmd);
-
-       for (i = 0; i < fb->format->num_planes; i++) {
-               u32 stride_alignment;
-
-               if (mode_cmd->handles[i] != mode_cmd->handles[0]) {
-                       drm_dbg_kms(&dev_priv->drm, "bad plane %d handle\n",
-                                   i);
-                       goto err;
-               }
-
-               stride_alignment = intel_fb_stride_alignment(fb, i);
-               if (fb->pitches[i] & (stride_alignment - 1)) {
-                       drm_dbg_kms(&dev_priv->drm,
-                                   "plane %d pitch (%d) must be at least %u byte aligned\n",
-                                   i, fb->pitches[i], stride_alignment);
-                       goto err;
-               }
-
-               if (is_gen12_ccs_plane(fb, i) && !is_gen12_ccs_cc_plane(fb, i)) {
-                       int ccs_aux_stride = gen12_ccs_aux_stride(fb, i);
-
-                       if (fb->pitches[i] != ccs_aux_stride) {
-                               drm_dbg_kms(&dev_priv->drm,
-                                           "ccs aux plane %d pitch (%d) must be %d\n",
-                                           i,
-                                           fb->pitches[i], ccs_aux_stride);
-                               goto err;
-                       }
-               }
-
-               /* TODO: Add POT stride remapping support for CCS formats as well. */
-               if (IS_ALDERLAKE_P(dev_priv) &&
-                   mode_cmd->modifier[i] != DRM_FORMAT_MOD_LINEAR &&
-                   !intel_fb_needs_pot_stride_remap(intel_fb) &&
-                   !is_power_of_2(mode_cmd->pitches[i])) {
-                       drm_dbg_kms(&dev_priv->drm,
-                                   "plane %d pitch (%d) must be power of two for tiled buffers\n",
-                                   i, mode_cmd->pitches[i]);
-                       goto err;
-               }
-
-               fb->obj[i] = &obj->base;
-       }
-
-       ret = intel_fill_fb_info(dev_priv, intel_fb);
-       if (ret)
-               goto err;
-
-       if (intel_fb_uses_dpt(fb)) {
-               struct i915_address_space *vm;
-
-               vm = intel_dpt_create(intel_fb);
-               if (IS_ERR(vm)) {
-                       ret = PTR_ERR(vm);
-                       goto err;
-               }
-
-               intel_fb->dpt_vm = vm;
-       }
-
-       ret = drm_framebuffer_init(&dev_priv->drm, fb, &intel_fb_funcs);
-       if (ret) {
-               drm_err(&dev_priv->drm, "framebuffer init failed %d\n", ret);
-               goto err;
-       }
-
-       return 0;
-
-err:
-       intel_frontbuffer_put(intel_fb->frontbuffer);
-       return ret;
-}
-
-static struct drm_framebuffer *
-intel_user_framebuffer_create(struct drm_device *dev,
-                             struct drm_file *filp,
-                             const struct drm_mode_fb_cmd2 *user_mode_cmd)
-{
-       struct drm_framebuffer *fb;
-       struct drm_i915_gem_object *obj;
-       struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd;
-       struct drm_i915_private *i915;
-
-       obj = i915_gem_object_lookup(filp, mode_cmd.handles[0]);
-       if (!obj)
-               return ERR_PTR(-ENOENT);
-
-       /* object is backed with LMEM for discrete */
-       i915 = to_i915(obj->base.dev);
-       if (HAS_LMEM(i915) && !i915_gem_object_can_migrate(obj, INTEL_REGION_LMEM)) {
-               /* object is "remote", not in local memory */
-               i915_gem_object_put(obj);
-               return ERR_PTR(-EREMOTE);
-       }
-
-       fb = intel_framebuffer_create(obj, &mode_cmd);
-       i915_gem_object_put(obj);
-
-       return fb;
-}
-
 static enum drm_mode_status
 intel_mode_valid(struct drm_device *dev,
                 const struct drm_display_mode *mode)
@@ -12271,22 +11393,6 @@ fail:
        drm_modeset_acquire_fini(&ctx);
 }
 
-static void intel_update_fdi_pll_freq(struct drm_i915_private *dev_priv)
-{
-       if (IS_IRONLAKE(dev_priv)) {
-               u32 fdi_pll_clk =
-                       intel_de_read(dev_priv, FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK;
-
-               dev_priv->fdi_pll_freq = (fdi_pll_clk + 2) * 10000;
-       } else if (IS_SANDYBRIDGE(dev_priv) || IS_IVYBRIDGE(dev_priv)) {
-               dev_priv->fdi_pll_freq = 270000;
-       } else {
-               return;
-       }
-
-       drm_dbg(&dev_priv->drm, "FDI PLL freq=%d\n", dev_priv->fdi_pll_freq);
-}
-
 static int intel_initial_commit(struct drm_device *dev)
 {
        struct drm_atomic_state *state = NULL;
@@ -12381,7 +11487,7 @@ static void intel_mode_config_init(struct drm_i915_private *i915)
 
        mode_config->funcs = &intel_mode_funcs;
 
-       mode_config->async_page_flip = has_async_flips(i915);
+       mode_config->async_page_flip = HAS_ASYNC_FLIPS(i915);
 
        /*
         * Maximum framebuffer dimensions, chosen to match
@@ -12540,7 +11646,7 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915)
 
        intel_plane_possible_crtcs_init(i915);
        intel_shared_dpll_init(dev);
-       intel_update_fdi_pll_freq(i915);
+       intel_fdi_pll_freq_update(i915);
 
        intel_update_czclk(i915);
        intel_modeset_init_hw(i915);
@@ -12564,6 +11670,7 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915)
 
        drm_modeset_lock_all(dev);
        intel_modeset_setup_hw_state(dev, dev->mode_config.acquire_ctx);
+       intel_acpi_assign_connector_fwnodes(i915);
        drm_modeset_unlock_all(dev);
 
        for_each_intel_crtc(dev, crtc) {
@@ -13076,8 +12183,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                            enableddisabled(crtc_state->hw.active));
        }
 
-       dev_priv->active_pipes = cdclk_state->active_pipes =
-               dbuf_state->active_pipes = active_pipes;
+       cdclk_state->active_pipes = dbuf_state->active_pipes = active_pipes;
 
        readout_plane_state(dev_priv);
 
index 284936f0ddab26049543d1b844ebcbea0de4408f..4719ffc97fce9384bc969b763ff44dbeb7469291 100644 (file)
@@ -548,8 +548,6 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv);
 unsigned int intel_fb_xy_to_linear(int x, int y,
                                   const struct intel_plane_state *state,
                                   int plane);
-unsigned int intel_fb_align_height(const struct drm_framebuffer *fb,
-                                  int color_plane, unsigned int height);
 void intel_add_fb_offsets(int *x, int *y,
                          const struct intel_plane_state *state, int plane);
 unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info);
@@ -630,10 +628,6 @@ struct intel_encoder *
 intel_get_crtc_new_encoder(const struct intel_atomic_state *state,
                           const struct intel_crtc_state *crtc_state);
 
-unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
-                                 int color_plane);
-unsigned int intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane);
-
 void intel_display_driver_register(struct drm_i915_private *i915);
 void intel_display_driver_unregister(struct drm_i915_private *i915);
 
index 8fdacb252bb1984a597c94a1af3a5b79b1b153c3..68f4ba8c46e755acd13e806f19211dabd6aad112 100644 (file)
@@ -13,6 +13,7 @@
 #include "intel_display_types.h"
 #include "intel_dmc.h"
 #include "intel_dp.h"
+#include "intel_drrs.h"
 #include "intel_fbc.h"
 #include "intel_hdcp.h"
 #include "intel_hdmi.h"
@@ -1323,9 +1324,6 @@ static int i915_drrs_status(struct seq_file *m, void *unused)
        return 0;
 }
 
-#define LPSP_STATUS(COND) (COND ? seq_puts(m, "LPSP: enabled\n") : \
-                               seq_puts(m, "LPSP: disabled\n"))
-
 static bool
 intel_lpsp_power_well_enabled(struct drm_i915_private *i915,
                              enum i915_power_well_id power_well_id)
@@ -1344,32 +1342,20 @@ intel_lpsp_power_well_enabled(struct drm_i915_private *i915,
 static int i915_lpsp_status(struct seq_file *m, void *unused)
 {
        struct drm_i915_private *i915 = node_to_i915(m->private);
-
-       if (DISPLAY_VER(i915) >= 13) {
-               LPSP_STATUS(!intel_lpsp_power_well_enabled(i915,
-                                                          SKL_DISP_PW_2));
+       bool lpsp_enabled = false;
+
+       if (DISPLAY_VER(i915) >= 13 || IS_DISPLAY_VER(i915, 9, 10)) {
+               lpsp_enabled = !intel_lpsp_power_well_enabled(i915, SKL_DISP_PW_2);
+       } else if (IS_DISPLAY_VER(i915, 11, 12)) {
+               lpsp_enabled = !intel_lpsp_power_well_enabled(i915, ICL_DISP_PW_3);
+       } else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) {
+               lpsp_enabled = !intel_lpsp_power_well_enabled(i915, HSW_DISP_PW_GLOBAL);
+       } else {
+               seq_puts(m, "LPSP: not supported\n");
                return 0;
        }
 
-       switch (DISPLAY_VER(i915)) {
-       case 12:
-       case 11:
-               LPSP_STATUS(!intel_lpsp_power_well_enabled(i915, ICL_DISP_PW_3));
-               break;
-       case 10:
-       case 9:
-               LPSP_STATUS(!intel_lpsp_power_well_enabled(i915, SKL_DISP_PW_2));
-               break;
-       default:
-               /*
-                * Apart from HASWELL/BROADWELL other legacy platform doesn't
-                * support lpsp.
-                */
-               if (IS_HASWELL(i915) || IS_BROADWELL(i915))
-                       LPSP_STATUS(!intel_lpsp_power_well_enabled(i915, HSW_DISP_PW_GLOBAL));
-               else
-                       seq_puts(m, "LPSP: not supported\n");
-       }
+       seq_printf(m, "LPSP: %s\n", enableddisabled(lpsp_enabled));
 
        return 0;
 }
@@ -2044,11 +2030,9 @@ static int i915_drrs_ctl_set(void *data, u64 val)
 
                        intel_dp = enc_to_intel_dp(encoder);
                        if (val)
-                               intel_edp_drrs_enable(intel_dp,
-                                                     crtc_state);
+                               intel_drrs_enable(intel_dp, crtc_state);
                        else
-                               intel_edp_drrs_disable(intel_dp,
-                                                      crtc_state);
+                               intel_drrs_disable(intel_dp, crtc_state);
                }
                drm_connector_list_iter_end(&conn_iter);
 
@@ -2240,14 +2224,12 @@ static int i915_psr_status_show(struct seq_file *m, void *data)
 }
 DEFINE_SHOW_ATTRIBUTE(i915_psr_status);
 
-#define LPSP_CAPABLE(COND) (COND ? seq_puts(m, "LPSP: capable\n") : \
-                               seq_puts(m, "LPSP: incapable\n"))
-
 static int i915_lpsp_capability_show(struct seq_file *m, void *data)
 {
        struct drm_connector *connector = m->private;
        struct drm_i915_private *i915 = to_i915(connector->dev);
        struct intel_encoder *encoder;
+       bool lpsp_capable = false;
 
        encoder = intel_attached_encoder(to_intel_connector(connector));
        if (!encoder)
@@ -2256,35 +2238,27 @@ static int i915_lpsp_capability_show(struct seq_file *m, void *data)
        if (connector->status != connector_status_connected)
                return -ENODEV;
 
-       if (DISPLAY_VER(i915) >= 13) {
-               LPSP_CAPABLE(encoder->port <= PORT_B);
-               return 0;
-       }
-
-       switch (DISPLAY_VER(i915)) {
-       case 12:
+       if (DISPLAY_VER(i915) >= 13)
+               lpsp_capable = encoder->port <= PORT_B;
+       else if (DISPLAY_VER(i915) >= 12)
                /*
                 * Actually TGL can drive LPSP on port till DDI_C
                 * but there is no physical connected DDI_C on TGL sku's,
                 * even driver is not initilizing DDI_C port for gen12.
                 */
-               LPSP_CAPABLE(encoder->port <= PORT_B);
-               break;
-       case 11:
-               LPSP_CAPABLE(connector->connector_type == DRM_MODE_CONNECTOR_DSI ||
-                            connector->connector_type == DRM_MODE_CONNECTOR_eDP);
-               break;
-       case 10:
-       case 9:
-               LPSP_CAPABLE(encoder->port == PORT_A &&
-                            (connector->connector_type == DRM_MODE_CONNECTOR_DSI ||
-                            connector->connector_type == DRM_MODE_CONNECTOR_eDP  ||
-                            connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort));
-               break;
-       default:
-               if (IS_HASWELL(i915) || IS_BROADWELL(i915))
-                       LPSP_CAPABLE(connector->connector_type == DRM_MODE_CONNECTOR_eDP);
-       }
+               lpsp_capable = encoder->port <= PORT_B;
+       else if (DISPLAY_VER(i915) == 11)
+               lpsp_capable = (connector->connector_type == DRM_MODE_CONNECTOR_DSI ||
+                               connector->connector_type == DRM_MODE_CONNECTOR_eDP);
+       else if (IS_DISPLAY_VER(i915, 9, 10))
+               lpsp_capable = (encoder->port == PORT_A &&
+                               (connector->connector_type == DRM_MODE_CONNECTOR_DSI ||
+                                connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+                                connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort));
+       else if (IS_HASWELL(i915) || IS_BROADWELL(i915))
+               lpsp_capable = connector->connector_type == DRM_MODE_CONNECTOR_eDP;
+
+       seq_printf(m, "LPSP: %s\n", lpsp_capable ? "capable" : "incapable");
 
        return 0;
 }
index 6beeeeba1bed28299e7e69915881dec30de8cfce..e9e806d90eec4341de1d25e75e13370c954d6d8f 100644 (file)
@@ -428,10 +428,6 @@ struct intel_hdcp_shim {
        int (*hdcp_2_2_capable)(struct intel_digital_port *dig_port,
                                bool *capable);
 
-       /* Detects whether a HDCP 1.4 sink connected in MST topology */
-       int (*streams_type1_capable)(struct intel_connector *connector,
-                                    bool *capable);
-
        /* Write HDCP2.2 messages */
        int (*write_2_2_msg)(struct intel_digital_port *dig_port,
                             void *buf, size_t size);
@@ -1684,6 +1680,8 @@ struct intel_digital_port {
        bool hdcp_auth_status;
        /* HDCP port data need to pass to security f/w */
        struct hdcp_port_data hdcp_port_data;
+       /* Whether the MST topology supports HDCP Type 1 Content */
+       bool hdcp_mst_type1_capable;
 
        void (*write_infoframe)(struct intel_encoder *encoder,
                                const struct intel_crtc_state *crtc_state,
@@ -2035,28 +2033,6 @@ to_intel_frontbuffer(struct drm_framebuffer *fb)
        return fb ? to_intel_framebuffer(fb)->frontbuffer : NULL;
 }
 
-static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
-{
-       if (dev_priv->params.panel_use_ssc >= 0)
-               return dev_priv->params.panel_use_ssc != 0;
-       return dev_priv->vbt.lvds_use_ssc
-               && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
-}
-
-static inline u32 i9xx_dpll_compute_fp(struct dpll *dpll)
-{
-       return dpll->n << 16 | dpll->m1 << 8 | dpll->m2;
-}
-
-static inline u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv,
-                                     const struct intel_crtc_state *pipe_config)
-{
-       if (HAS_DDI(dev_priv))
-               return pipe_config->port_clock; /* SPLL */
-       else
-               return dev_priv->fdi_pll_freq;
-}
-
 static inline bool is_ccs_modifier(u64 modifier)
 {
        return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
index 04175f359fd6857c4941095cf0e6489cd9bb74bc..2db606ad59a2cec175f9338b5ff6c9a39fc774fc 100644 (file)
@@ -44,6 +44,7 @@
 #include "i915_drv.h"
 #include "intel_atomic.h"
 #include "intel_audio.h"
+#include "intel_backlight.h"
 #include "intel_connector.h"
 #include "intel_ddi.h"
 #include "intel_de.h"
@@ -55,6 +56,7 @@
 #include "intel_dp_mst.h"
 #include "intel_dpio_phy.h"
 #include "intel_dpll.h"
+#include "intel_drrs.h"
 #include "intel_fifo_underrun.h"
 #include "intel_hdcp.h"
 #include "intel_hdmi.h"
@@ -100,6 +102,8 @@ static const u8 valid_dsc_slicecount[] = {1, 2, 4};
  *
  * If a CPU or PCH DP output is attached to an eDP panel, this function
  * will return true, and false otherwise.
+ *
+ * This function is not safe to use prior to encoder type being set.
  */
 bool intel_dp_is_edp(struct intel_dp *intel_dp)
 {
@@ -141,6 +145,26 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
                intel_dp->sink_rates[i] = dp_rates[i];
        }
 
+       /*
+        * Sink rates for 128b/132b. If set, sink should support all 8b/10b
+        * rates and 10 Gbps.
+        */
+       if (intel_dp->dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_128B132B) {
+               u8 uhbr_rates = 0;
+
+               BUILD_BUG_ON(ARRAY_SIZE(intel_dp->sink_rates) < ARRAY_SIZE(dp_rates) + 3);
+
+               drm_dp_dpcd_readb(&intel_dp->aux,
+                                 DP_128B132B_SUPPORTED_LINK_RATES, &uhbr_rates);
+
+               if (uhbr_rates & DP_UHBR10)
+                       intel_dp->sink_rates[i++] = 1000000;
+               if (uhbr_rates & DP_UHBR13_5)
+                       intel_dp->sink_rates[i++] = 1350000;
+               if (uhbr_rates & DP_UHBR20)
+                       intel_dp->sink_rates[i++] = 2000000;
+       }
+
        intel_dp->num_sink_rates = i;
 }
 
@@ -192,6 +216,10 @@ int intel_dp_max_lane_count(struct intel_dp *intel_dp)
        return intel_dp->max_link_lane_count;
 }
 
+/*
+ * The required data bandwidth for a mode with given pixel clock and bpp. This
+ * is the required net bandwidth independent of the data bandwidth efficiency.
+ */
 int
 intel_dp_link_required(int pixel_clock, int bpp)
 {
@@ -199,16 +227,52 @@ intel_dp_link_required(int pixel_clock, int bpp)
        return DIV_ROUND_UP(pixel_clock * bpp, 8);
 }
 
+/*
+ * Given a link rate and lanes, get the data bandwidth.
+ *
+ * Data bandwidth is the actual payload rate, which depends on the data
+ * bandwidth efficiency and the link rate.
+ *
+ * For 8b/10b channel encoding, SST and non-FEC, the data bandwidth efficiency
+ * is 80%. For example, for a 1.62 Gbps link, 1.62*10^9 bps * 0.80 * (1/8) =
+ * 162000 kBps. With 8-bit symbols, we have 162000 kHz symbol clock. Just by
+ * coincidence, the port clock in kHz matches the data bandwidth in kBps, and
+ * they equal the link bit rate in Gbps multiplied by 100000. (Note that this no
+ * longer holds for data bandwidth as soon as FEC or MST is taken into account!)
+ *
+ * For 128b/132b channel encoding, the data bandwidth efficiency is 96.71%. For
+ * example, for a 10 Gbps link, 10*10^9 bps * 0.9671 * (1/8) = 1208875
+ * kBps. With 32-bit symbols, we have 312500 kHz symbol clock. The value 1000000
+ * does not match the symbol clock, the port clock (not even if you think in
+ * terms of a byte clock), nor the data bandwidth. It only matches the link bit
+ * rate in units of 10000 bps.
+ */
 int
-intel_dp_max_data_rate(int max_link_clock, int max_lanes)
+intel_dp_max_data_rate(int max_link_rate, int max_lanes)
 {
-       /* max_link_clock is the link symbol clock (LS_Clk) in kHz and not the
-        * link rate that is generally expressed in Gbps. Since, 8 bits of data
-        * is transmitted every LS_Clk per lane, there is no need to account for
-        * the channel encoding that is done in the PHY layer here.
+       if (max_link_rate >= 1000000) {
+               /*
+                * UHBR rates always use 128b/132b channel encoding, and have
+                * 97.71% data bandwidth efficiency. Consider max_link_rate the
+                * link bit rate in units of 10000 bps.
+                */
+               int max_link_rate_kbps = max_link_rate * 10;
+
+               max_link_rate_kbps = DIV_ROUND_CLOSEST_ULL(max_link_rate_kbps * 9671, 10000);
+               max_link_rate = max_link_rate_kbps / 8;
+       }
+
+       /*
+        * Lower than UHBR rates always use 8b/10b channel encoding, and have
+        * 80% data bandwidth efficiency for SST non-FEC. However, this turns
+        * out to be a nop by coincidence, and can be skipped:
+        *
+        *      int max_link_rate_kbps = max_link_rate * 10;
+        *      max_link_rate_kbps = DIV_ROUND_CLOSEST_ULL(max_link_rate_kbps * 8, 10);
+        *      max_link_rate = max_link_rate_kbps / 8;
         */
 
-       return max_link_clock * max_lanes;
+       return max_link_rate * max_lanes;
 }
 
 bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp)
@@ -222,6 +286,20 @@ bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp)
                 encoder->port != PORT_A);
 }
 
+static int dg2_max_source_rate(struct intel_dp *intel_dp)
+{
+       return intel_dp_is_edp(intel_dp) ? 810000 : 1350000;
+}
+
+static bool is_low_voltage_sku(struct drm_i915_private *i915, enum phy phy)
+{
+       u32 voltage;
+
+       voltage = intel_de_read(i915, ICL_PORT_COMP_DW3(phy)) & VOLTAGE_INFO_MASK;
+
+       return voltage == VOLTAGE_INFO_0_85V;
+}
+
 static int icl_max_source_rate(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
@@ -229,7 +307,7 @@ static int icl_max_source_rate(struct intel_dp *intel_dp)
        enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port);
 
        if (intel_phy_is_combo(dev_priv, phy) &&
-           !intel_dp_is_edp(intel_dp))
+           (is_low_voltage_sku(dev_priv, phy) || !intel_dp_is_edp(intel_dp)))
                return 540000;
 
        return 810000;
@@ -237,7 +315,23 @@ static int icl_max_source_rate(struct intel_dp *intel_dp)
 
 static int ehl_max_source_rate(struct intel_dp *intel_dp)
 {
-       if (intel_dp_is_edp(intel_dp))
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+       enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port);
+
+       if (intel_dp_is_edp(intel_dp) || is_low_voltage_sku(dev_priv, phy))
+               return 540000;
+
+       return 810000;
+}
+
+static int dg1_max_source_rate(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+       enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
+
+       if (intel_phy_is_combo(i915, phy) && is_low_voltage_sku(i915, phy))
                return 540000;
 
        return 810000;
@@ -248,7 +342,8 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp)
 {
        /* The values must be in increasing order */
        static const int icl_rates[] = {
-               162000, 216000, 270000, 324000, 432000, 540000, 648000, 810000
+               162000, 216000, 270000, 324000, 432000, 540000, 648000, 810000,
+               1000000, 1350000,
        };
        static const int bxt_rates[] = {
                162000, 216000, 243000, 270000, 324000, 432000, 540000
@@ -275,7 +370,12 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp)
        if (DISPLAY_VER(dev_priv) >= 11) {
                source_rates = icl_rates;
                size = ARRAY_SIZE(icl_rates);
-               if (IS_JSL_EHL(dev_priv))
+               if (IS_DG2(dev_priv))
+                       max_rate = dg2_max_source_rate(intel_dp);
+               else if (IS_ALDERLAKE_P(dev_priv) || IS_ALDERLAKE_S(dev_priv) ||
+                        IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv))
+                       max_rate = dg1_max_source_rate(intel_dp);
+               else if (IS_JSL_EHL(dev_priv))
                        max_rate = ehl_max_source_rate(intel_dp);
                else
                        max_rate = icl_max_source_rate(intel_dp);
@@ -461,7 +561,9 @@ u32 intel_dp_mode_to_fec_clock(u32 mode_clock)
 static int
 small_joiner_ram_size_bits(struct drm_i915_private *i915)
 {
-       if (DISPLAY_VER(i915) >= 11)
+       if (DISPLAY_VER(i915) >= 13)
+               return 17280 * 8;
+       else if (DISPLAY_VER(i915) >= 11)
                return 7680 * 8;
        else
                return 6144 * 8;
@@ -1044,7 +1146,8 @@ intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
                                                    intel_dp->num_common_rates,
                                                    intel_dp->compliance.test_link_rate);
                        if (index >= 0)
-                               limits->min_clock = limits->max_clock = index;
+                               limits->min_rate = limits->max_rate =
+                                       intel_dp->compliance.test_link_rate;
                        limits->min_lane_count = limits->max_lane_count =
                                intel_dp->compliance.test_lane_count;
                }
@@ -1058,8 +1161,8 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
                                  const struct link_config_limits *limits)
 {
        struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
-       int bpp, clock, lane_count;
-       int mode_rate, link_clock, link_avail;
+       int bpp, i, lane_count;
+       int mode_rate, link_rate, link_avail;
 
        for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
                int output_bpp = intel_dp_output_bpp(pipe_config->output_format, bpp);
@@ -1067,18 +1170,22 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
                mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
                                                   output_bpp);
 
-               for (clock = limits->min_clock; clock <= limits->max_clock; clock++) {
+               for (i = 0; i < intel_dp->num_common_rates; i++) {
+                       link_rate = intel_dp->common_rates[i];
+                       if (link_rate < limits->min_rate ||
+                           link_rate > limits->max_rate)
+                               continue;
+
                        for (lane_count = limits->min_lane_count;
                             lane_count <= limits->max_lane_count;
                             lane_count <<= 1) {
-                               link_clock = intel_dp->common_rates[clock];
-                               link_avail = intel_dp_max_data_rate(link_clock,
+                               link_avail = intel_dp_max_data_rate(link_rate,
                                                                    lane_count);
 
                                if (mode_rate <= link_avail) {
                                        pipe_config->lane_count = lane_count;
                                        pipe_config->pipe_bpp = bpp;
-                                       pipe_config->port_clock = link_clock;
+                                       pipe_config->port_clock = link_rate;
 
                                        return 0;
                                }
@@ -1212,7 +1319,7 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
         * with DSC enabled for the requested mode.
         */
        pipe_config->pipe_bpp = pipe_bpp;
-       pipe_config->port_clock = intel_dp->common_rates[limits->max_clock];
+       pipe_config->port_clock = limits->max_rate;
        pipe_config->lane_count = limits->max_lane_count;
 
        if (intel_dp_is_edp(intel_dp)) {
@@ -1321,8 +1428,8 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
        /* No common link rates between source and sink */
        drm_WARN_ON(encoder->base.dev, common_len <= 0);
 
-       limits.min_clock = 0;
-       limits.max_clock = common_len - 1;
+       limits.min_rate = intel_dp->common_rates[0];
+       limits.max_rate = intel_dp->common_rates[common_len - 1];
 
        limits.min_lane_count = 1;
        limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
@@ -1340,15 +1447,14 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
                 * values correspond to the native resolution of the panel.
                 */
                limits.min_lane_count = limits.max_lane_count;
-               limits.min_clock = limits.max_clock;
+               limits.min_rate = limits.max_rate;
        }
 
        intel_dp_adjust_compliance_config(intel_dp, pipe_config, &limits);
 
        drm_dbg_kms(&i915->drm, "DP link computation with max lane count %i "
                    "max rate %d max bpp %d pixel clock %iKHz\n",
-                   limits.max_lane_count,
-                   intel_dp->common_rates[limits.max_clock],
+                   limits.max_lane_count, limits.max_rate,
                    limits.max_bpp, adjusted_mode->crtc_clock);
 
        if ((adjusted_mode->crtc_clock > i915->max_dotclk_freq ||
@@ -1603,46 +1709,6 @@ intel_dp_compute_hdr_metadata_infoframe_sdp(struct intel_dp *intel_dp,
                intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_METADATA);
 }
 
-static void
-intel_dp_drrs_compute_config(struct intel_dp *intel_dp,
-                            struct intel_crtc_state *pipe_config,
-                            int output_bpp, bool constant_n)
-{
-       struct intel_connector *intel_connector = intel_dp->attached_connector;
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       int pixel_clock;
-
-       if (pipe_config->vrr.enable)
-               return;
-
-       /*
-        * DRRS and PSR can't be enable together, so giving preference to PSR
-        * as it allows more power-savings by complete shutting down display,
-        * so to guarantee this, intel_dp_drrs_compute_config() must be called
-        * after intel_psr_compute_config().
-        */
-       if (pipe_config->has_psr)
-               return;
-
-       if (!intel_connector->panel.downclock_mode ||
-           dev_priv->drrs.type != SEAMLESS_DRRS_SUPPORT)
-               return;
-
-       pipe_config->has_drrs = true;
-
-       pixel_clock = intel_connector->panel.downclock_mode->clock;
-       if (pipe_config->splitter.enable)
-               pixel_clock /= pipe_config->splitter.link_count;
-
-       intel_link_compute_m_n(output_bpp, pipe_config->lane_count, pixel_clock,
-                              pipe_config->port_clock, &pipe_config->dp_m2_n2,
-                              constant_n, pipe_config->fec_enable);
-
-       /* FIXME: abstract this better */
-       if (pipe_config->splitter.enable)
-               pipe_config->dp_m2_n2.gmch_m *= pipe_config->splitter.link_count;
-}
-
 int
 intel_dp_compute_config(struct intel_encoder *encoder,
                        struct intel_crtc_state *pipe_config,
@@ -1665,7 +1731,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                                                            adjusted_mode);
 
        if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
-               ret = intel_pch_panel_fitting(pipe_config, conn_state);
+               ret = intel_panel_fitting(pipe_config, conn_state);
                if (ret)
                        return ret;
        }
@@ -1678,13 +1744,10 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                pipe_config->has_audio = intel_conn_state->force_audio == HDMI_AUDIO_ON;
 
        if (intel_dp_is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
-               intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
+               intel_panel_fixed_mode(intel_connector->panel.fixed_mode,
                                       adjusted_mode);
 
-               if (HAS_GMCH(dev_priv))
-                       ret = intel_gmch_panel_fitting(pipe_config, conn_state);
-               else
-                       ret = intel_pch_panel_fitting(pipe_config, conn_state);
+               ret = intel_panel_fitting(pipe_config, conn_state);
                if (ret)
                        return ret;
        }
@@ -1751,8 +1814,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 
        intel_vrr_compute_config(pipe_config, conn_state);
        intel_psr_compute_config(intel_dp, pipe_config);
-       intel_dp_drrs_compute_config(intel_dp, pipe_config, output_bpp,
-                                    constant_n);
+       intel_drrs_compute_config(intel_dp, pipe_config, output_bpp,
+                                 constant_n);
        intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
        intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state);
 
@@ -1779,7 +1842,7 @@ void intel_edp_backlight_on(const struct intel_crtc_state *crtc_state,
 
        drm_dbg_kms(&i915->drm, "\n");
 
-       intel_panel_enable_backlight(crtc_state, conn_state);
+       intel_backlight_enable(crtc_state, conn_state);
        intel_pps_backlight_on(intel_dp);
 }
 
@@ -1795,7 +1858,7 @@ void intel_edp_backlight_off(const struct drm_connector_state *old_conn_state)
        drm_dbg_kms(&i915->drm, "\n");
 
        intel_pps_backlight_off(intel_dp);
-       intel_panel_disable_backlight(old_conn_state);
+       intel_backlight_disable(old_conn_state);
 }
 
 static bool downstream_hpd_needs_d0(struct intel_dp *intel_dp)
@@ -2389,6 +2452,8 @@ static void intel_edp_mso_mode_fixup(struct intel_connector *connector,
 static void intel_edp_mso_init(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+       struct intel_connector *connector = intel_dp->attached_connector;
+       struct drm_display_info *info = &connector->base.display_info;
        u8 mso;
 
        if (intel_dp->edp_dpcd[0] < DP_EDP_14)
@@ -2407,8 +2472,9 @@ static void intel_edp_mso_init(struct intel_dp *intel_dp)
        }
 
        if (mso) {
-               drm_dbg_kms(&i915->drm, "Sink MSO %ux%u configuration\n",
-                           mso, drm_dp_max_lane_count(intel_dp->dpcd) / mso);
+               drm_dbg_kms(&i915->drm, "Sink MSO %ux%u configuration, pixel overlap %u\n",
+                           mso, drm_dp_max_lane_count(intel_dp->dpcd) / mso,
+                           info->mso_pixel_overlap);
                if (!HAS_MSO(i915)) {
                        drm_err(&i915->drm, "No source MSO support, disabling\n");
                        mso = 0;
@@ -2416,7 +2482,7 @@ static void intel_edp_mso_init(struct intel_dp *intel_dp)
        }
 
        intel_dp->mso_link_count = mso;
-       intel_dp->mso_pixel_overlap = 0; /* FIXME: read from DisplayID v2.0 */
+       intel_dp->mso_pixel_overlap = mso ? info->mso_pixel_overlap : 0;
 }
 
 static bool
@@ -2445,11 +2511,14 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)
         */
        if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_DPCD_REV,
                             intel_dp->edp_dpcd, sizeof(intel_dp->edp_dpcd)) ==
-                            sizeof(intel_dp->edp_dpcd))
+                            sizeof(intel_dp->edp_dpcd)) {
                drm_dbg_kms(&dev_priv->drm, "eDP DPCD: %*ph\n",
                            (int)sizeof(intel_dp->edp_dpcd),
                            intel_dp->edp_dpcd);
 
+               intel_dp->use_max_params = intel_dp->edp_dpcd[0] < DP_EDP_14;
+       }
+
        /*
         * This has to be called after intel_dp->edp_dpcd is filled, PSR checks
         * for SET_POWER_CAPABLE bit in intel_dp->edp_dpcd[1]
@@ -2502,8 +2571,6 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)
         */
        intel_edp_init_source_oui(intel_dp, true);
 
-       intel_edp_mso_init(intel_dp);
-
        return true;
 }
 
@@ -4585,6 +4652,17 @@ static int intel_dp_connector_atomic_check(struct drm_connector *conn,
        return intel_modeset_synced_crtcs(state, conn);
 }
 
+static void intel_dp_oob_hotplug_event(struct drm_connector *connector)
+{
+       struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector));
+       struct drm_i915_private *i915 = to_i915(connector->dev);
+
+       spin_lock_irq(&i915->irq_lock);
+       i915->hotplug.event_bits |= BIT(encoder->hpd_pin);
+       spin_unlock_irq(&i915->irq_lock);
+       queue_delayed_work(system_wq, &i915->hotplug.hotplug_work, 0);
+}
+
 static const struct drm_connector_funcs intel_dp_connector_funcs = {
        .force = intel_dp_force,
        .fill_modes = drm_helper_probe_single_connector_modes,
@@ -4595,6 +4673,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
        .destroy = intel_connector_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
        .atomic_duplicate_state = intel_digital_connector_duplicate_state,
+       .oob_hotplug_event = intel_dp_oob_hotplug_event,
 };
 
 static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
@@ -4710,432 +4789,6 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
                drm_connector_attach_vrr_capable_property(connector);
 }
 
-/**
- * intel_dp_set_drrs_state - program registers for RR switch to take effect
- * @dev_priv: i915 device
- * @crtc_state: a pointer to the active intel_crtc_state
- * @refresh_rate: RR to be programmed
- *
- * This function gets called when refresh rate (RR) has to be changed from
- * one frequency to another. Switches can be between high and low RR
- * supported by the panel or to any other RR based on media playback (in
- * this case, RR value needs to be passed from user space).
- *
- * The caller of this function needs to take a lock on dev_priv->drrs.
- */
-static void intel_dp_set_drrs_state(struct drm_i915_private *dev_priv,
-                                   const struct intel_crtc_state *crtc_state,
-                                   int refresh_rate)
-{
-       struct intel_dp *intel_dp = dev_priv->drrs.dp;
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
-       enum drrs_refresh_rate_type index = DRRS_HIGH_RR;
-
-       if (refresh_rate <= 0) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "Refresh rate should be positive non-zero.\n");
-               return;
-       }
-
-       if (intel_dp == NULL) {
-               drm_dbg_kms(&dev_priv->drm, "DRRS not supported.\n");
-               return;
-       }
-
-       if (!crtc) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "DRRS: intel_crtc not initialized\n");
-               return;
-       }
-
-       if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) {
-               drm_dbg_kms(&dev_priv->drm, "Only Seamless DRRS supported.\n");
-               return;
-       }
-
-       if (drm_mode_vrefresh(intel_dp->attached_connector->panel.downclock_mode) ==
-                       refresh_rate)
-               index = DRRS_LOW_RR;
-
-       if (index == dev_priv->drrs.refresh_rate_type) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "DRRS requested for previously set RR...ignoring\n");
-               return;
-       }
-
-       if (!crtc_state->hw.active) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "eDP encoder disabled. CRTC not Active\n");
-               return;
-       }
-
-       if (DISPLAY_VER(dev_priv) >= 8 && !IS_CHERRYVIEW(dev_priv)) {
-               switch (index) {
-               case DRRS_HIGH_RR:
-                       intel_dp_set_m_n(crtc_state, M1_N1);
-                       break;
-               case DRRS_LOW_RR:
-                       intel_dp_set_m_n(crtc_state, M2_N2);
-                       break;
-               case DRRS_MAX_RR:
-               default:
-                       drm_err(&dev_priv->drm,
-                               "Unsupported refreshrate type\n");
-               }
-       } else if (DISPLAY_VER(dev_priv) > 6) {
-               i915_reg_t reg = PIPECONF(crtc_state->cpu_transcoder);
-               u32 val;
-
-               val = intel_de_read(dev_priv, reg);
-               if (index > DRRS_HIGH_RR) {
-                       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-                               val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
-                       else
-                               val |= PIPECONF_EDP_RR_MODE_SWITCH;
-               } else {
-                       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-                               val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV;
-                       else
-                               val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
-               }
-               intel_de_write(dev_priv, reg, val);
-       }
-
-       dev_priv->drrs.refresh_rate_type = index;
-
-       drm_dbg_kms(&dev_priv->drm, "eDP Refresh Rate set to : %dHz\n",
-                   refresh_rate);
-}
-
-static void
-intel_edp_drrs_enable_locked(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       dev_priv->drrs.busy_frontbuffer_bits = 0;
-       dev_priv->drrs.dp = intel_dp;
-}
-
-/**
- * intel_edp_drrs_enable - init drrs struct if supported
- * @intel_dp: DP struct
- * @crtc_state: A pointer to the active crtc state.
- *
- * Initializes frontbuffer_bits and drrs.dp
- */
-void intel_edp_drrs_enable(struct intel_dp *intel_dp,
-                          const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       if (!crtc_state->has_drrs)
-               return;
-
-       drm_dbg_kms(&dev_priv->drm, "Enabling DRRS\n");
-
-       mutex_lock(&dev_priv->drrs.mutex);
-
-       if (dev_priv->drrs.dp) {
-               drm_warn(&dev_priv->drm, "DRRS already enabled\n");
-               goto unlock;
-       }
-
-       intel_edp_drrs_enable_locked(intel_dp);
-
-unlock:
-       mutex_unlock(&dev_priv->drrs.mutex);
-}
-
-static void
-intel_edp_drrs_disable_locked(struct intel_dp *intel_dp,
-                             const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) {
-               int refresh;
-
-               refresh = drm_mode_vrefresh(intel_dp->attached_connector->panel.fixed_mode);
-               intel_dp_set_drrs_state(dev_priv, crtc_state, refresh);
-       }
-
-       dev_priv->drrs.dp = NULL;
-}
-
-/**
- * intel_edp_drrs_disable - Disable DRRS
- * @intel_dp: DP struct
- * @old_crtc_state: Pointer to old crtc_state.
- *
- */
-void intel_edp_drrs_disable(struct intel_dp *intel_dp,
-                           const struct intel_crtc_state *old_crtc_state)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       if (!old_crtc_state->has_drrs)
-               return;
-
-       mutex_lock(&dev_priv->drrs.mutex);
-       if (!dev_priv->drrs.dp) {
-               mutex_unlock(&dev_priv->drrs.mutex);
-               return;
-       }
-
-       intel_edp_drrs_disable_locked(intel_dp, old_crtc_state);
-       mutex_unlock(&dev_priv->drrs.mutex);
-
-       cancel_delayed_work_sync(&dev_priv->drrs.work);
-}
-
-/**
- * intel_edp_drrs_update - Update DRRS state
- * @intel_dp: Intel DP
- * @crtc_state: new CRTC state
- *
- * This function will update DRRS states, disabling or enabling DRRS when
- * executing fastsets. For full modeset, intel_edp_drrs_disable() and
- * intel_edp_drrs_enable() should be called instead.
- */
-void
-intel_edp_drrs_update(struct intel_dp *intel_dp,
-                     const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       if (dev_priv->drrs.type != SEAMLESS_DRRS_SUPPORT)
-               return;
-
-       mutex_lock(&dev_priv->drrs.mutex);
-
-       /* New state matches current one? */
-       if (crtc_state->has_drrs == !!dev_priv->drrs.dp)
-               goto unlock;
-
-       if (crtc_state->has_drrs)
-               intel_edp_drrs_enable_locked(intel_dp);
-       else
-               intel_edp_drrs_disable_locked(intel_dp, crtc_state);
-
-unlock:
-       mutex_unlock(&dev_priv->drrs.mutex);
-}
-
-static void intel_edp_drrs_downclock_work(struct work_struct *work)
-{
-       struct drm_i915_private *dev_priv =
-               container_of(work, typeof(*dev_priv), drrs.work.work);
-       struct intel_dp *intel_dp;
-
-       mutex_lock(&dev_priv->drrs.mutex);
-
-       intel_dp = dev_priv->drrs.dp;
-
-       if (!intel_dp)
-               goto unlock;
-
-       /*
-        * The delayed work can race with an invalidate hence we need to
-        * recheck.
-        */
-
-       if (dev_priv->drrs.busy_frontbuffer_bits)
-               goto unlock;
-
-       if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR) {
-               struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
-
-               intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
-                       drm_mode_vrefresh(intel_dp->attached_connector->panel.downclock_mode));
-       }
-
-unlock:
-       mutex_unlock(&dev_priv->drrs.mutex);
-}
-
-/**
- * intel_edp_drrs_invalidate - Disable Idleness DRRS
- * @dev_priv: i915 device
- * @frontbuffer_bits: frontbuffer plane tracking bits
- *
- * This function gets called everytime rendering on the given planes start.
- * Hence DRRS needs to be Upclocked, i.e. (LOW_RR -> HIGH_RR).
- *
- * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
- */
-void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
-                              unsigned int frontbuffer_bits)
-{
-       struct intel_dp *intel_dp;
-       struct drm_crtc *crtc;
-       enum pipe pipe;
-
-       if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
-               return;
-
-       cancel_delayed_work(&dev_priv->drrs.work);
-
-       mutex_lock(&dev_priv->drrs.mutex);
-
-       intel_dp = dev_priv->drrs.dp;
-       if (!intel_dp) {
-               mutex_unlock(&dev_priv->drrs.mutex);
-               return;
-       }
-
-       crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
-       pipe = to_intel_crtc(crtc)->pipe;
-
-       frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
-       dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
-
-       /* invalidate means busy screen hence upclock */
-       if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
-               intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
-                                       drm_mode_vrefresh(intel_dp->attached_connector->panel.fixed_mode));
-
-       mutex_unlock(&dev_priv->drrs.mutex);
-}
-
-/**
- * intel_edp_drrs_flush - Restart Idleness DRRS
- * @dev_priv: i915 device
- * @frontbuffer_bits: frontbuffer plane tracking bits
- *
- * This function gets called every time rendering on the given planes has
- * completed or flip on a crtc is completed. So DRRS should be upclocked
- * (LOW_RR -> HIGH_RR). And also Idleness detection should be started again,
- * if no other planes are dirty.
- *
- * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
- */
-void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
-                         unsigned int frontbuffer_bits)
-{
-       struct intel_dp *intel_dp;
-       struct drm_crtc *crtc;
-       enum pipe pipe;
-
-       if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
-               return;
-
-       cancel_delayed_work(&dev_priv->drrs.work);
-
-       mutex_lock(&dev_priv->drrs.mutex);
-
-       intel_dp = dev_priv->drrs.dp;
-       if (!intel_dp) {
-               mutex_unlock(&dev_priv->drrs.mutex);
-               return;
-       }
-
-       crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
-       pipe = to_intel_crtc(crtc)->pipe;
-
-       frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
-       dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
-
-       /* flush means busy screen hence upclock */
-       if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
-               intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
-                                       drm_mode_vrefresh(intel_dp->attached_connector->panel.fixed_mode));
-
-       /*
-        * flush also means no more activity hence schedule downclock, if all
-        * other fbs are quiescent too
-        */
-       if (!dev_priv->drrs.busy_frontbuffer_bits)
-               schedule_delayed_work(&dev_priv->drrs.work,
-                               msecs_to_jiffies(1000));
-       mutex_unlock(&dev_priv->drrs.mutex);
-}
-
-/**
- * DOC: Display Refresh Rate Switching (DRRS)
- *
- * Display Refresh Rate Switching (DRRS) is a power conservation feature
- * which enables swtching between low and high refresh rates,
- * dynamically, based on the usage scenario. This feature is applicable
- * for internal panels.
- *
- * Indication that the panel supports DRRS is given by the panel EDID, which
- * would list multiple refresh rates for one resolution.
- *
- * DRRS is of 2 types - static and seamless.
- * Static DRRS involves changing refresh rate (RR) by doing a full modeset
- * (may appear as a blink on screen) and is used in dock-undock scenario.
- * Seamless DRRS involves changing RR without any visual effect to the user
- * and can be used during normal system usage. This is done by programming
- * certain registers.
- *
- * Support for static/seamless DRRS may be indicated in the VBT based on
- * inputs from the panel spec.
- *
- * DRRS saves power by switching to low RR based on usage scenarios.
- *
- * The implementation is based on frontbuffer tracking implementation.  When
- * there is a disturbance on the screen triggered by user activity or a periodic
- * system activity, DRRS is disabled (RR is changed to high RR).  When there is
- * no movement on screen, after a timeout of 1 second, a switch to low RR is
- * made.
- *
- * For integration with frontbuffer tracking code, intel_edp_drrs_invalidate()
- * and intel_edp_drrs_flush() are called.
- *
- * DRRS can be further extended to support other internal panels and also
- * the scenario of video playback wherein RR is set based on the rate
- * requested by userspace.
- */
-
-/**
- * intel_dp_drrs_init - Init basic DRRS work and mutex.
- * @connector: eDP connector
- * @fixed_mode: preferred mode of panel
- *
- * This function is  called only once at driver load to initialize basic
- * DRRS stuff.
- *
- * Returns:
- * Downclock mode if panel supports it, else return NULL.
- * DRRS support is determined by the presence of downclock mode (apart
- * from VBT setting).
- */
-static struct drm_display_mode *
-intel_dp_drrs_init(struct intel_connector *connector,
-                  struct drm_display_mode *fixed_mode)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct drm_display_mode *downclock_mode = NULL;
-
-       INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work);
-       mutex_init(&dev_priv->drrs.mutex);
-
-       if (DISPLAY_VER(dev_priv) <= 6) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "DRRS supported for Gen7 and above\n");
-               return NULL;
-       }
-
-       if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
-               drm_dbg_kms(&dev_priv->drm, "VBT doesn't support DRRS\n");
-               return NULL;
-       }
-
-       downclock_mode = intel_panel_edid_downclock_mode(connector, fixed_mode);
-       if (!downclock_mode) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "Downclock mode is not found. DRRS not supported\n");
-               return NULL;
-       }
-
-       dev_priv->drrs.type = dev_priv->vbt.drrs_type;
-
-       dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR;
-       drm_dbg_kms(&dev_priv->drm,
-                   "seamless DRRS supported for eDP panel.\n");
-       return downclock_mode;
-}
-
 static bool intel_edp_init_connector(struct intel_dp *intel_dp,
                                     struct intel_connector *intel_connector)
 {
@@ -5194,7 +4847,10 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
 
        fixed_mode = intel_panel_edid_fixed_mode(intel_connector);
        if (fixed_mode)
-               downclock_mode = intel_dp_drrs_init(intel_connector, fixed_mode);
+               downclock_mode = intel_drrs_init(intel_connector, fixed_mode);
+
+       /* MSO requires information from the EDID */
+       intel_edp_mso_init(intel_dp);
 
        /* multiply the mode clock and horizontal timings for MSO */
        intel_edp_mso_mode_fixup(intel_connector, fixed_mode);
@@ -5227,7 +4883,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
        if (!(dev_priv->quirks & QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK))
                intel_connector->panel.backlight.power = intel_pps_backlight_power;
-       intel_panel_setup_backlight(connector, pipe);
+       intel_backlight_setup(intel_connector, pipe);
 
        if (fixed_mode) {
                drm_connector_set_panel_orientation_with_quirk(connector,
@@ -5289,8 +4945,6 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
                     intel_encoder->base.name))
                return false;
 
-       intel_dp_set_source_rates(intel_dp);
-
        intel_dp->reset_link_params = true;
        intel_dp->pps.pps_pipe = INVALID_PIPE;
        intel_dp->pps.active_pipe = INVALID_PIPE;
@@ -5306,28 +4960,22 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
                 */
                drm_WARN_ON(dev, intel_phy_is_tc(dev_priv, phy));
                type = DRM_MODE_CONNECTOR_eDP;
+               intel_encoder->type = INTEL_OUTPUT_EDP;
+
+               /* eDP only on port B and/or C on vlv/chv */
+               if (drm_WARN_ON(dev, (IS_VALLEYVIEW(dev_priv) ||
+                                     IS_CHERRYVIEW(dev_priv)) &&
+                               port != PORT_B && port != PORT_C))
+                       return false;
        } else {
                type = DRM_MODE_CONNECTOR_DisplayPort;
        }
 
+       intel_dp_set_source_rates(intel_dp);
+
        if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
                intel_dp->pps.active_pipe = vlv_active_pipe(intel_dp);
 
-       /*
-        * For eDP we always set the encoder type to INTEL_OUTPUT_EDP, but
-        * for DP the encoder type can be set by the caller to
-        * INTEL_OUTPUT_UNKNOWN for DDI, so don't rewrite it.
-        */
-       if (type == DRM_MODE_CONNECTOR_eDP)
-               intel_encoder->type = INTEL_OUTPUT_EDP;
-
-       /* eDP only on port B and/or C on vlv/chv */
-       if (drm_WARN_ON(dev, (IS_VALLEYVIEW(dev_priv) ||
-                             IS_CHERRYVIEW(dev_priv)) &&
-                       intel_dp_is_edp(intel_dp) &&
-                       port != PORT_B && port != PORT_C))
-               return false;
-
        drm_dbg_kms(&dev_priv->drm,
                    "Adding %s connector on [ENCODER:%d:%s]\n",
                    type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP",
index 680631b5b437817d31e47e2558d392ace7427bab..a28fff286c21adc33e2f9bdff82214146c97c03a 100644 (file)
@@ -26,7 +26,7 @@ struct intel_dp;
 struct intel_encoder;
 
 struct link_config_limits {
-       int min_clock, max_clock;
+       int min_rate, max_rate;
        int min_lane_count, max_lane_count;
        int min_bpp, max_bpp;
 };
@@ -70,17 +70,6 @@ int intel_dp_max_link_rate(struct intel_dp *intel_dp);
 int intel_dp_max_lane_count(struct intel_dp *intel_dp);
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
 
-void intel_edp_drrs_enable(struct intel_dp *intel_dp,
-                          const struct intel_crtc_state *crtc_state);
-void intel_edp_drrs_disable(struct intel_dp *intel_dp,
-                           const struct intel_crtc_state *crtc_state);
-void intel_edp_drrs_update(struct intel_dp *intel_dp,
-                          const struct intel_crtc_state *crtc_state);
-void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
-                              unsigned int frontbuffer_bits);
-void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
-                         unsigned int frontbuffer_bits);
-
 void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
                           u8 *link_bw, u8 *rate_select);
 bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
@@ -88,7 +77,7 @@ bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp);
 
 bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp);
 int intel_dp_link_required(int pixel_clock, int bpp);
-int intel_dp_max_data_rate(int max_link_clock, int max_lanes);
+int intel_dp_max_data_rate(int max_link_rate, int max_lanes);
 bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp);
 bool intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state,
                            const struct drm_connector_state *conn_state);
index 6ac568617ef37a63d6869b9a19dedabda9bcce5a..569d17b4d00f0bd4136604cd3dd7439c8d99137e 100644 (file)
@@ -34,9 +34,9 @@
  * for some reason.
  */
 
+#include "intel_backlight.h"
 #include "intel_display_types.h"
 #include "intel_dp_aux_backlight.h"
-#include "intel_panel.h"
 
 /* TODO:
  * Implement HDR, right now we just implement the bare minimum to bring us back into SDR mode so we
@@ -146,7 +146,7 @@ intel_dp_aux_hdr_get_backlight(struct intel_connector *connector, enum pipe pipe
                if (!panel->backlight.edp.intel.sdr_uses_aux) {
                        u32 pwm_level = panel->backlight.pwm_funcs->get(connector, pipe);
 
-                       return intel_panel_backlight_level_from_pwm(connector, pwm_level);
+                       return intel_backlight_level_from_pwm(connector, pwm_level);
                }
 
                /* Assume 100% brightness if backlight controls aren't enabled yet */
@@ -187,9 +187,9 @@ intel_dp_aux_hdr_set_backlight(const struct drm_connector_state *conn_state, u32
        if (panel->backlight.edp.intel.sdr_uses_aux) {
                intel_dp_aux_hdr_set_aux_backlight(conn_state, level);
        } else {
-               const u32 pwm_level = intel_panel_backlight_level_to_pwm(connector, level);
+               const u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
 
-               intel_panel_set_pwm_level(conn_state, pwm_level);
+               intel_backlight_set_pwm_level(conn_state, pwm_level);
        }
 }
 
@@ -215,7 +215,7 @@ intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state,
                ctrl |= INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE;
                intel_dp_aux_hdr_set_aux_backlight(conn_state, level);
        } else {
-               u32 pwm_level = intel_panel_backlight_level_to_pwm(connector, level);
+               u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
 
                panel->backlight.pwm_funcs->enable(crtc_state, conn_state, pwm_level);
 
@@ -238,7 +238,7 @@ intel_dp_aux_hdr_disable_backlight(const struct drm_connector_state *conn_state,
                return;
 
        /* Note we want the actual pwm_level to be 0, regardless of pwm_min */
-       panel->backlight.pwm_funcs->disable(conn_state, intel_panel_invert_pwm_level(connector, 0));
+       panel->backlight.pwm_funcs->disable(conn_state, intel_backlight_invert_pwm_level(connector, 0));
 }
 
 static int
index d697d169e8c1381f5d92e5663792502c082d9580..540a669e01dd44735fb6b59669dc7ddf93ada10d 100644 (file)
@@ -446,8 +446,6 @@ static
 int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port,
                             void *buf, size_t size)
 {
-       struct intel_dp *dp = &dig_port->dp;
-       struct intel_hdcp *hdcp = &dp->attached_connector->hdcp;
        unsigned int offset;
        u8 *byte = buf;
        ssize_t ret, bytes_to_write, len;
@@ -463,8 +461,6 @@ int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port,
        bytes_to_write = size - 1;
        byte++;
 
-       hdcp->cp_irq_count_cached = atomic_read(&hdcp->cp_irq_count);
-
        while (bytes_to_write) {
                len = bytes_to_write > DP_AUX_MAX_PAYLOAD_BYTES ?
                                DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_write;
@@ -482,29 +478,11 @@ int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port,
        return size;
 }
 
-static int
-get_rxinfo_hdcp_1_dev_downstream(struct intel_digital_port *dig_port, bool *hdcp_1_x)
-{
-       u8 rx_info[HDCP_2_2_RXINFO_LEN];
-       int ret;
-
-       ret = drm_dp_dpcd_read(&dig_port->dp.aux,
-                              DP_HDCP_2_2_REG_RXINFO_OFFSET,
-                              (void *)rx_info, HDCP_2_2_RXINFO_LEN);
-
-       if (ret != HDCP_2_2_RXINFO_LEN)
-               return ret >= 0 ? -EIO : ret;
-
-       *hdcp_1_x = HDCP_2_2_HDCP1_DEVICE_CONNECTED(rx_info[1]) ? true : false;
-       return 0;
-}
-
 static
-ssize_t get_receiver_id_list_size(struct intel_digital_port *dig_port)
+ssize_t get_receiver_id_list_rx_info(struct intel_digital_port *dig_port, u32 *dev_cnt, u8 *byte)
 {
-       u8 rx_info[HDCP_2_2_RXINFO_LEN];
-       u32 dev_cnt;
        ssize_t ret;
+       u8 *rx_info = byte;
 
        ret = drm_dp_dpcd_read(&dig_port->dp.aux,
                               DP_HDCP_2_2_REG_RXINFO_OFFSET,
@@ -512,15 +490,11 @@ ssize_t get_receiver_id_list_size(struct intel_digital_port *dig_port)
        if (ret != HDCP_2_2_RXINFO_LEN)
                return ret >= 0 ? -EIO : ret;
 
-       dev_cnt = (HDCP_2_2_DEV_COUNT_HI(rx_info[0]) << 4 |
+       *dev_cnt = (HDCP_2_2_DEV_COUNT_HI(rx_info[0]) << 4 |
                   HDCP_2_2_DEV_COUNT_LO(rx_info[1]));
 
-       if (dev_cnt > HDCP_2_2_MAX_DEVICE_COUNT)
-               dev_cnt = HDCP_2_2_MAX_DEVICE_COUNT;
-
-       ret = sizeof(struct hdcp2_rep_send_receiverid_list) -
-               HDCP_2_2_RECEIVER_IDS_MAX_LEN +
-               (dev_cnt * HDCP_2_2_RECEIVER_ID_LEN);
+       if (*dev_cnt > HDCP_2_2_MAX_DEVICE_COUNT)
+               *dev_cnt = HDCP_2_2_MAX_DEVICE_COUNT;
 
        return ret;
 }
@@ -530,12 +504,15 @@ int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port,
                            u8 msg_id, void *buf, size_t size)
 {
        struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+       struct intel_dp *dp = &dig_port->dp;
+       struct intel_hdcp *hdcp = &dp->attached_connector->hdcp;
        unsigned int offset;
        u8 *byte = buf;
        ssize_t ret, bytes_to_recv, len;
        const struct hdcp2_dp_msg_data *hdcp2_msg_data;
        ktime_t msg_end = ktime_set(0, 0);
        bool msg_expired;
+       u32 dev_cnt;
 
        hdcp2_msg_data = get_hdcp2_dp_msg_data(msg_id);
        if (!hdcp2_msg_data)
@@ -546,17 +523,24 @@ int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port,
        if (ret < 0)
                return ret;
 
+       hdcp->cp_irq_count_cached = atomic_read(&hdcp->cp_irq_count);
+
+       /* DP adaptation msgs has no msg_id */
+       byte++;
+
        if (msg_id == HDCP_2_2_REP_SEND_RECVID_LIST) {
-               ret = get_receiver_id_list_size(dig_port);
+               ret = get_receiver_id_list_rx_info(dig_port, &dev_cnt, byte);
                if (ret < 0)
                        return ret;
 
-               size = ret;
+               byte += ret;
+               size = sizeof(struct hdcp2_rep_send_receiverid_list) -
+               HDCP_2_2_RXINFO_LEN - HDCP_2_2_RECEIVER_IDS_MAX_LEN +
+               (dev_cnt * HDCP_2_2_RECEIVER_ID_LEN);
+               offset += HDCP_2_2_RXINFO_LEN;
        }
-       bytes_to_recv = size - 1;
 
-       /* DP adaptation msgs has no msg_id */
-       byte++;
+       bytes_to_recv = size - 1;
 
        while (bytes_to_recv) {
                len = bytes_to_recv > DP_AUX_MAX_PAYLOAD_BYTES ?
@@ -664,27 +648,6 @@ int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port,
        return 0;
 }
 
-static
-int intel_dp_mst_streams_type1_capable(struct intel_connector *connector,
-                                      bool *capable)
-{
-       struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
-       struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-       int ret;
-       bool hdcp_1_x;
-
-       ret = get_rxinfo_hdcp_1_dev_downstream(dig_port, &hdcp_1_x);
-       if (ret) {
-               drm_dbg_kms(&i915->drm,
-                           "[%s:%d] failed to read RxInfo ret=%d\n",
-                           connector->base.name, connector->base.base.id, ret);
-               return ret;
-       }
-
-       *capable = !hdcp_1_x;
-       return 0;
-}
-
 static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
        .write_an_aksv = intel_dp_hdcp_write_an_aksv,
        .read_bksv = intel_dp_hdcp_read_bksv,
@@ -833,7 +796,6 @@ static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
        .stream_2_2_encryption = intel_dp_mst_hdcp2_stream_encryption,
        .check_2_2_link = intel_dp_mst_hdcp2_check_link,
        .hdcp_2_2_capable = intel_dp_hdcp2_capable,
-       .streams_type1_capable = intel_dp_mst_streams_type1_capable,
        .protocol = HDCP_PROTOCOL_DP,
 };
 
index 053a3c2f726776b5e50aaaf72c40b31630fe5674..508a514c5e37dc241d0b6e3cdd7aab44ab0eb617 100644 (file)
@@ -848,7 +848,7 @@ intel_dp_link_train_all_phys(struct intel_dp *intel_dp,
        }
 
        if (ret)
-               intel_dp_link_train_phy(intel_dp, crtc_state, DP_PHY_DPRX);
+               ret = intel_dp_link_train_phy(intel_dp, crtc_state, DP_PHY_DPRX);
 
        if (intel_dp->set_idle_link_train)
                intel_dp->set_idle_link_train(intel_dp, crtc_state);
index 8d13d7b26a25b2623408d86161468ade848c9bf3..d104441344c066143d71664c74efd083f7383206 100644 (file)
@@ -61,7 +61,7 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
        int bpp, slots = -EINVAL;
 
        crtc_state->lane_count = limits->max_lane_count;
-       crtc_state->port_clock = limits->max_clock;
+       crtc_state->port_clock = limits->max_rate;
 
        for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
                crtc_state->pipe_bpp = bpp;
@@ -131,8 +131,8 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
         * for MST we always configure max link bw - the spec doesn't
         * seem to suggest we should do otherwise.
         */
-       limits.min_clock =
-       limits.max_clock = intel_dp_max_link_rate(intel_dp);
+       limits.min_rate =
+       limits.max_rate = intel_dp_max_link_rate(intel_dp);
 
        limits.min_lane_count =
        limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
@@ -396,7 +396,6 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state,
                to_intel_connector(old_conn_state->connector);
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
        bool last_mst_stream;
-       u32 val;
 
        intel_dp->active_mst_links--;
        last_mst_stream = intel_dp->active_mst_links == 0;
@@ -412,12 +411,8 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state,
 
        clear_act_sent(encoder, old_crtc_state);
 
-       val = intel_de_read(dev_priv,
-                           TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder));
-       val &= ~TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
-       intel_de_write(dev_priv,
-                      TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder),
-                      val);
+       intel_de_rmw(dev_priv, TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder),
+                    TRANS_DDI_DP_VC_PAYLOAD_ALLOC, 0);
 
        wait_for_act_sent(encoder, old_crtc_state);
 
index 14515e62c05e6dd88d5fc3fed8a640301a25a094..210f91f4a576765f2fb70b2ee3570b8d4aab1e21 100644 (file)
@@ -309,7 +309,7 @@ int pnv_calc_dpll_params(int refclk, struct dpll *clock)
        return clock->dot;
 }
 
-static u32 i9xx_dpll_compute_m(struct dpll *dpll)
+static u32 i9xx_dpll_compute_m(const struct dpll *dpll)
 {
        return 5 * (dpll->m1 + 2) + (dpll->m2 + 2);
 }
@@ -428,7 +428,8 @@ i9xx_select_p2_div(const struct intel_limit *limit,
 static bool
 i9xx_find_best_dpll(const struct intel_limit *limit,
                    struct intel_crtc_state *crtc_state,
-                   int target, int refclk, struct dpll *match_clock,
+                   int target, int refclk,
+                   const struct dpll *match_clock,
                    struct dpll *best_clock)
 {
        struct drm_device *dev = crtc_state->uapi.crtc->dev;
@@ -486,7 +487,8 @@ i9xx_find_best_dpll(const struct intel_limit *limit,
 static bool
 pnv_find_best_dpll(const struct intel_limit *limit,
                   struct intel_crtc_state *crtc_state,
-                  int target, int refclk, struct dpll *match_clock,
+                  int target, int refclk,
+                  const struct dpll *match_clock,
                   struct dpll *best_clock)
 {
        struct drm_device *dev = crtc_state->uapi.crtc->dev;
@@ -542,7 +544,8 @@ pnv_find_best_dpll(const struct intel_limit *limit,
 static bool
 g4x_find_best_dpll(const struct intel_limit *limit,
                   struct intel_crtc_state *crtc_state,
-                  int target, int refclk, struct dpll *match_clock,
+                  int target, int refclk,
+                  const struct dpll *match_clock,
                   struct dpll *best_clock)
 {
        struct drm_device *dev = crtc_state->uapi.crtc->dev;
@@ -636,7 +639,8 @@ static bool vlv_PLL_is_optimal(struct drm_device *dev, int target_freq,
 static bool
 vlv_find_best_dpll(const struct intel_limit *limit,
                   struct intel_crtc_state *crtc_state,
-                  int target, int refclk, struct dpll *match_clock,
+                  int target, int refclk,
+                  const struct dpll *match_clock,
                   struct dpll *best_clock)
 {
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
@@ -696,7 +700,8 @@ vlv_find_best_dpll(const struct intel_limit *limit,
 static bool
 chv_find_best_dpll(const struct intel_limit *limit,
                   struct intel_crtc_state *crtc_state,
-                  int target, int refclk, struct dpll *match_clock,
+                  int target, int refclk,
+                  const struct dpll *match_clock,
                   struct dpll *best_clock)
 {
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
@@ -763,47 +768,45 @@ bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state,
                                  NULL, best_clock);
 }
 
-static u32 pnv_dpll_compute_fp(struct dpll *dpll)
+u32 i9xx_dpll_compute_fp(const struct dpll *dpll)
+{
+       return dpll->n << 16 | dpll->m1 << 8 | dpll->m2;
+}
+
+static u32 pnv_dpll_compute_fp(const struct dpll *dpll)
 {
        return (1 << dpll->n) << 16 | dpll->m2;
 }
 
-static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
-                                    struct intel_crtc_state *crtc_state,
-                                    struct dpll *reduced_clock)
+static void i9xx_update_pll_dividers(struct intel_crtc_state *crtc_state,
+                                    const struct dpll *clock,
+                                    const struct dpll *reduced_clock)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       u32 fp, fp2 = 0;
+       u32 fp, fp2;
 
        if (IS_PINEVIEW(dev_priv)) {
-               fp = pnv_dpll_compute_fp(&crtc_state->dpll);
-               if (reduced_clock)
-                       fp2 = pnv_dpll_compute_fp(reduced_clock);
+               fp = pnv_dpll_compute_fp(clock);
+               fp2 = pnv_dpll_compute_fp(reduced_clock);
        } else {
-               fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
-               if (reduced_clock)
-                       fp2 = i9xx_dpll_compute_fp(reduced_clock);
+               fp = i9xx_dpll_compute_fp(clock);
+               fp2 = i9xx_dpll_compute_fp(reduced_clock);
        }
 
        crtc_state->dpll_hw_state.fp0 = fp;
-
-       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
-           reduced_clock) {
-               crtc_state->dpll_hw_state.fp1 = fp2;
-       } else {
-               crtc_state->dpll_hw_state.fp1 = fp;
-       }
+       crtc_state->dpll_hw_state.fp1 = fp2;
 }
 
-static void i9xx_compute_dpll(struct intel_crtc *crtc,
-                             struct intel_crtc_state *crtc_state,
-                             struct dpll *reduced_clock)
+static void i9xx_compute_dpll(struct intel_crtc_state *crtc_state,
+                             const struct dpll *clock,
+                             const struct dpll *reduced_clock)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        u32 dpll;
-       struct dpll *clock = &crtc_state->dpll;
 
-       i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
+       i9xx_update_pll_dividers(crtc_state, clock, reduced_clock);
 
        dpll = DPLL_VGA_MODE_DIS;
 
@@ -826,13 +829,17 @@ static void i9xx_compute_dpll(struct intel_crtc *crtc,
                dpll |= DPLL_SDVO_HIGH_SPEED;
 
        /* compute bitmask from p1 value */
-       if (IS_PINEVIEW(dev_priv))
+       if (IS_G4X(dev_priv)) {
+               dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+               dpll |= (1 << (reduced_clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+       } else if (IS_PINEVIEW(dev_priv)) {
                dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
-       else {
+               WARN_ON(reduced_clock->p1 != clock->p1);
+       } else {
                dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
-               if (IS_G4X(dev_priv) && reduced_clock)
-                       dpll |= (1 << (reduced_clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+               WARN_ON(reduced_clock->p1 != clock->p1);
        }
+
        switch (clock->p2) {
        case 5:
                dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
@@ -847,6 +854,8 @@ static void i9xx_compute_dpll(struct intel_crtc *crtc,
                dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
                break;
        }
+       WARN_ON(reduced_clock->p2 != clock->p2);
+
        if (DISPLAY_VER(dev_priv) >= 4)
                dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
 
@@ -868,16 +877,15 @@ static void i9xx_compute_dpll(struct intel_crtc *crtc,
        }
 }
 
-static void i8xx_compute_dpll(struct intel_crtc *crtc,
-                             struct intel_crtc_state *crtc_state,
-                             struct dpll *reduced_clock)
+static void i8xx_compute_dpll(struct intel_crtc_state *crtc_state,
+                             const struct dpll *clock,
+                             const struct dpll *reduced_clock)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        u32 dpll;
-       struct dpll *clock = &crtc_state->dpll;
 
-       i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
+       i9xx_update_pll_dividers(crtc_state, clock, reduced_clock);
 
        dpll = DPLL_VGA_MODE_DIS;
 
@@ -891,6 +899,8 @@ static void i8xx_compute_dpll(struct intel_crtc *crtc,
                if (clock->p2 == 4)
                        dpll |= PLL_P2_DIVIDE_BY_4;
        }
+       WARN_ON(reduced_clock->p1 != clock->p1);
+       WARN_ON(reduced_clock->p2 != clock->p2);
 
        /*
         * Bspec:
@@ -918,9 +928,9 @@ static void i8xx_compute_dpll(struct intel_crtc *crtc,
        crtc_state->dpll_hw_state.dpll = dpll;
 }
 
-static int hsw_crtc_compute_clock(struct intel_crtc *crtc,
-                                 struct intel_crtc_state *crtc_state)
+static int hsw_crtc_compute_clock(struct intel_crtc_state *crtc_state)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        struct intel_atomic_state *state =
                to_intel_atomic_state(crtc_state->uapi.state);
@@ -942,18 +952,18 @@ static int hsw_crtc_compute_clock(struct intel_crtc *crtc,
        return 0;
 }
 
-static bool ilk_needs_fb_cb_tune(struct dpll *dpll, int factor)
+static bool ilk_needs_fb_cb_tune(const struct dpll *dpll, int factor)
 {
-       return i9xx_dpll_compute_m(dpll) < factor * dpll->n;
+       return dpll->m < factor * dpll->n;
 }
 
-
-static void ilk_compute_dpll(struct intel_crtc *crtc,
-                            struct intel_crtc_state *crtc_state,
-                            struct dpll *reduced_clock)
+static void ilk_update_pll_dividers(struct intel_crtc_state *crtc_state,
+                                   const struct dpll *clock,
+                                   const struct dpll *reduced_clock)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       u32 dpll, fp, fp2;
+       u32 fp, fp2;
        int factor;
 
        /* Enable autotuning of the PLL clock (if permissible) */
@@ -968,19 +978,27 @@ static void ilk_compute_dpll(struct intel_crtc *crtc,
                factor = 20;
        }
 
-       fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
-
-       if (ilk_needs_fb_cb_tune(&crtc_state->dpll, factor))
+       fp = i9xx_dpll_compute_fp(clock);
+       if (ilk_needs_fb_cb_tune(clock, factor))
                fp |= FP_CB_TUNE;
 
-       if (reduced_clock) {
-               fp2 = i9xx_dpll_compute_fp(reduced_clock);
+       fp2 = i9xx_dpll_compute_fp(reduced_clock);
+       if (ilk_needs_fb_cb_tune(reduced_clock, factor))
+               fp2 |= FP_CB_TUNE;
 
-               if (reduced_clock->m < factor * reduced_clock->n)
-                       fp2 |= FP_CB_TUNE;
-       } else {
-               fp2 = fp;
-       }
+       crtc_state->dpll_hw_state.fp0 = fp;
+       crtc_state->dpll_hw_state.fp1 = fp2;
+}
+
+static void ilk_compute_dpll(struct intel_crtc_state *crtc_state,
+                            const struct dpll *clock,
+                            const struct dpll *reduced_clock)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       u32 dpll;
+
+       ilk_update_pll_dividers(crtc_state, clock, reduced_clock);
 
        dpll = 0;
 
@@ -1018,11 +1036,11 @@ static void ilk_compute_dpll(struct intel_crtc *crtc,
                dpll |= DPLL_SDVO_HIGH_SPEED;
 
        /* compute bitmask from p1 value */
-       dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+       dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
        /* also FPA1 */
-       dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+       dpll |= (1 << (reduced_clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
 
-       switch (crtc_state->dpll.p2) {
+       switch (clock->p2) {
        case 5:
                dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
                break;
@@ -1036,6 +1054,7 @@ static void ilk_compute_dpll(struct intel_crtc *crtc,
                dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
                break;
        }
+       WARN_ON(reduced_clock->p2 != clock->p2);
 
        if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
            intel_panel_use_ssc(dev_priv))
@@ -1046,13 +1065,11 @@ static void ilk_compute_dpll(struct intel_crtc *crtc,
        dpll |= DPLL_VCO_ENABLE;
 
        crtc_state->dpll_hw_state.dpll = dpll;
-       crtc_state->dpll_hw_state.fp0 = fp;
-       crtc_state->dpll_hw_state.fp1 = fp2;
 }
 
-static int ilk_crtc_compute_clock(struct intel_crtc *crtc,
-                                 struct intel_crtc_state *crtc_state)
+static int ilk_crtc_compute_clock(struct intel_crtc_state *crtc_state)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        struct intel_atomic_state *state =
                to_intel_atomic_state(crtc_state->uapi.state);
@@ -1097,7 +1114,8 @@ static int ilk_crtc_compute_clock(struct intel_crtc *crtc,
                return -EINVAL;
        }
 
-       ilk_compute_dpll(crtc, crtc_state, NULL);
+       ilk_compute_dpll(crtc_state, &crtc_state->dpll,
+                        &crtc_state->dpll);
 
        if (!intel_reserve_shared_dplls(state, crtc, NULL)) {
                drm_dbg_kms(&dev_priv->drm,
@@ -1109,41 +1127,42 @@ static int ilk_crtc_compute_clock(struct intel_crtc *crtc,
        return 0;
 }
 
-void vlv_compute_dpll(struct intel_crtc *crtc,
-                     struct intel_crtc_state *pipe_config)
+void vlv_compute_dpll(struct intel_crtc_state *crtc_state)
 {
-       pipe_config->dpll_hw_state.dpll = DPLL_INTEGRATED_REF_CLK_VLV |
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+
+       crtc_state->dpll_hw_state.dpll = DPLL_INTEGRATED_REF_CLK_VLV |
                DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
        if (crtc->pipe != PIPE_A)
-               pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
+               crtc_state->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
 
        /* DPLL not used with DSI, but still need the rest set up */
-       if (!intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DSI))
-               pipe_config->dpll_hw_state.dpll |= DPLL_VCO_ENABLE |
+       if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
+               crtc_state->dpll_hw_state.dpll |= DPLL_VCO_ENABLE |
                        DPLL_EXT_BUFFER_ENABLE_VLV;
 
-       pipe_config->dpll_hw_state.dpll_md =
-               (pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+       crtc_state->dpll_hw_state.dpll_md =
+               (crtc_state->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
 }
 
-void chv_compute_dpll(struct intel_crtc *crtc,
-                     struct intel_crtc_state *pipe_config)
+void chv_compute_dpll(struct intel_crtc_state *crtc_state)
 {
-       pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLK_CHV |
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+
+       crtc_state->dpll_hw_state.dpll = DPLL_SSC_REF_CLK_CHV |
                DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
        if (crtc->pipe != PIPE_A)
-               pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
+               crtc_state->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
 
        /* DPLL not used with DSI, but still need the rest set up */
-       if (!intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DSI))
-               pipe_config->dpll_hw_state.dpll |= DPLL_VCO_ENABLE;
+       if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
+               crtc_state->dpll_hw_state.dpll |= DPLL_VCO_ENABLE;
 
-       pipe_config->dpll_hw_state.dpll_md =
-               (pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+       crtc_state->dpll_hw_state.dpll_md =
+               (crtc_state->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
 }
 
-static int chv_crtc_compute_clock(struct intel_crtc *crtc,
-                                 struct intel_crtc_state *crtc_state)
+static int chv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
 {
        int refclk = 100000;
        const struct intel_limit *limit = &intel_limits_chv;
@@ -1159,13 +1178,12 @@ static int chv_crtc_compute_clock(struct intel_crtc *crtc,
                return -EINVAL;
        }
 
-       chv_compute_dpll(crtc, crtc_state);
+       chv_compute_dpll(crtc_state);
 
        return 0;
 }
 
-static int vlv_crtc_compute_clock(struct intel_crtc *crtc,
-                                 struct intel_crtc_state *crtc_state)
+static int vlv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
 {
        int refclk = 100000;
        const struct intel_limit *limit = &intel_limits_vlv;
@@ -1181,14 +1199,14 @@ static int vlv_crtc_compute_clock(struct intel_crtc *crtc,
                return -EINVAL;
        }
 
-       vlv_compute_dpll(crtc, crtc_state);
+       vlv_compute_dpll(crtc_state);
 
        return 0;
 }
 
-static int g4x_crtc_compute_clock(struct intel_crtc *crtc,
-                                 struct intel_crtc_state *crtc_state)
+static int g4x_crtc_compute_clock(struct intel_crtc_state *crtc_state)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        const struct intel_limit *limit;
        int refclk = 96000;
@@ -1226,16 +1244,16 @@ static int g4x_crtc_compute_clock(struct intel_crtc *crtc,
                return -EINVAL;
        }
 
-       i9xx_compute_dpll(crtc, crtc_state, NULL);
+       i9xx_compute_dpll(crtc_state, &crtc_state->dpll,
+                         &crtc_state->dpll);
 
        return 0;
 }
 
-static int pnv_crtc_compute_clock(struct intel_crtc *crtc,
-                                 struct intel_crtc_state *crtc_state)
+static int pnv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        const struct intel_limit *limit;
        int refclk = 96000;
 
@@ -1263,16 +1281,16 @@ static int pnv_crtc_compute_clock(struct intel_crtc *crtc,
                return -EINVAL;
        }
 
-       i9xx_compute_dpll(crtc, crtc_state, NULL);
+       i9xx_compute_dpll(crtc_state, &crtc_state->dpll,
+                         &crtc_state->dpll);
 
        return 0;
 }
 
-static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
-                                  struct intel_crtc_state *crtc_state)
+static int i9xx_crtc_compute_clock(struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        const struct intel_limit *limit;
        int refclk = 96000;
 
@@ -1300,16 +1318,16 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
                return -EINVAL;
        }
 
-       i9xx_compute_dpll(crtc, crtc_state, NULL);
+       i9xx_compute_dpll(crtc_state, &crtc_state->dpll,
+                         &crtc_state->dpll);
 
        return 0;
 }
 
-static int i8xx_crtc_compute_clock(struct intel_crtc *crtc,
-                                  struct intel_crtc_state *crtc_state)
+static int i8xx_crtc_compute_clock(struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        const struct intel_limit *limit;
        int refclk = 48000;
 
@@ -1339,7 +1357,8 @@ static int i8xx_crtc_compute_clock(struct intel_crtc *crtc,
                return -EINVAL;
        }
 
-       i8xx_compute_dpll(crtc, crtc_state, NULL);
+       i8xx_compute_dpll(crtc_state, &crtc_state->dpll,
+                         &crtc_state->dpll);
 
        return 0;
 }
@@ -1373,34 +1392,37 @@ static bool i9xx_has_pps(struct drm_i915_private *dev_priv)
        return IS_PINEVIEW(dev_priv) || IS_MOBILE(dev_priv);
 }
 
-void i9xx_enable_pll(struct intel_crtc *crtc,
-                    const struct intel_crtc_state *crtc_state)
+void i9xx_enable_pll(const struct intel_crtc_state *crtc_state)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       i915_reg_t reg = DPLL(crtc->pipe);
        u32 dpll = crtc_state->dpll_hw_state.dpll;
+       enum pipe pipe = crtc->pipe;
        int i;
 
        assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder);
 
        /* PLL is protected by panel, make sure we can write it */
        if (i9xx_has_pps(dev_priv))
-               assert_panel_unlocked(dev_priv, crtc->pipe);
+               assert_panel_unlocked(dev_priv, pipe);
+
+       intel_de_write(dev_priv, FP0(pipe), crtc_state->dpll_hw_state.fp0);
+       intel_de_write(dev_priv, FP1(pipe), crtc_state->dpll_hw_state.fp1);
 
        /*
         * Apparently we need to have VGA mode enabled prior to changing
         * the P1/P2 dividers. Otherwise the DPLL will keep using the old
         * dividers, even though the register value does change.
         */
-       intel_de_write(dev_priv, reg, dpll & ~DPLL_VGA_MODE_DIS);
-       intel_de_write(dev_priv, reg, dpll);
+       intel_de_write(dev_priv, DPLL(pipe), dpll & ~DPLL_VGA_MODE_DIS);
+       intel_de_write(dev_priv, DPLL(pipe), dpll);
 
        /* Wait for the clocks to stabilize. */
-       intel_de_posting_read(dev_priv, reg);
+       intel_de_posting_read(dev_priv, DPLL(pipe));
        udelay(150);
 
        if (DISPLAY_VER(dev_priv) >= 4) {
-               intel_de_write(dev_priv, DPLL_MD(crtc->pipe),
+               intel_de_write(dev_priv, DPLL_MD(pipe),
                               crtc_state->dpll_hw_state.dpll_md);
        } else {
                /* The pixel multiplier can only be updated once the
@@ -1408,13 +1430,13 @@ void i9xx_enable_pll(struct intel_crtc *crtc,
                 *
                 * So write it again.
                 */
-               intel_de_write(dev_priv, reg, dpll);
+               intel_de_write(dev_priv, DPLL(pipe), dpll);
        }
 
        /* We do this three times for luck */
        for (i = 0; i < 3; i++) {
-               intel_de_write(dev_priv, reg, dpll);
-               intel_de_posting_read(dev_priv, reg);
+               intel_de_write(dev_priv, DPLL(pipe), dpll);
+               intel_de_posting_read(dev_priv, DPLL(pipe));
                udelay(150); /* wait for warmup */
        }
 }
@@ -1448,136 +1470,22 @@ static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv,
        vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val);
 }
 
-static void _vlv_enable_pll(struct intel_crtc *crtc,
-                           const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       enum pipe pipe = crtc->pipe;
-
-       intel_de_write(dev_priv, DPLL(pipe), pipe_config->dpll_hw_state.dpll);
-       intel_de_posting_read(dev_priv, DPLL(pipe));
-       udelay(150);
-
-       if (intel_de_wait_for_set(dev_priv, DPLL(pipe), DPLL_LOCK_VLV, 1))
-               drm_err(&dev_priv->drm, "DPLL %d failed to lock\n", pipe);
-}
-
-void vlv_enable_pll(struct intel_crtc *crtc,
-                   const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       enum pipe pipe = crtc->pipe;
-
-       assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder);
-
-       /* PLL is protected by panel, make sure we can write it */
-       assert_panel_unlocked(dev_priv, pipe);
-
-       if (pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE)
-               _vlv_enable_pll(crtc, pipe_config);
-
-       intel_de_write(dev_priv, DPLL_MD(pipe),
-                      pipe_config->dpll_hw_state.dpll_md);
-       intel_de_posting_read(dev_priv, DPLL_MD(pipe));
-}
-
-
-static void _chv_enable_pll(struct intel_crtc *crtc,
-                           const struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       enum pipe pipe = crtc->pipe;
-       enum dpio_channel port = vlv_pipe_to_channel(pipe);
-       u32 tmp;
-
-       vlv_dpio_get(dev_priv);
-
-       /* Enable back the 10bit clock to display controller */
-       tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port));
-       tmp |= DPIO_DCLKP_EN;
-       vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), tmp);
-
-       vlv_dpio_put(dev_priv);
-
-       /*
-        * Need to wait > 100ns between dclkp clock enable bit and PLL enable.
-        */
-       udelay(1);
-
-       /* Enable PLL */
-       intel_de_write(dev_priv, DPLL(pipe), pipe_config->dpll_hw_state.dpll);
-
-       /* Check PLL is locked */
-       if (intel_de_wait_for_set(dev_priv, DPLL(pipe), DPLL_LOCK_VLV, 1))
-               drm_err(&dev_priv->drm, "PLL %d failed to lock\n", pipe);
-}
-
-void chv_enable_pll(struct intel_crtc *crtc,
-                   const struct intel_crtc_state *pipe_config)
+static void vlv_prepare_pll(const struct intel_crtc_state *crtc_state)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        enum pipe pipe = crtc->pipe;
-
-       assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder);
-
-       /* PLL is protected by panel, make sure we can write it */
-       assert_panel_unlocked(dev_priv, pipe);
-
-       if (pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE)
-               _chv_enable_pll(crtc, pipe_config);
-
-       if (pipe != PIPE_A) {
-               /*
-                * WaPixelRepeatModeFixForC0:chv
-                *
-                * DPLLCMD is AWOL. Use chicken bits to propagate
-                * the value from DPLLBMD to either pipe B or C.
-                */
-               intel_de_write(dev_priv, CBR4_VLV, CBR_DPLLBMD_PIPE(pipe));
-               intel_de_write(dev_priv, DPLL_MD(PIPE_B),
-                              pipe_config->dpll_hw_state.dpll_md);
-               intel_de_write(dev_priv, CBR4_VLV, 0);
-               dev_priv->chv_dpll_md[pipe] = pipe_config->dpll_hw_state.dpll_md;
-
-               /*
-                * DPLLB VGA mode also seems to cause problems.
-                * We should always have it disabled.
-                */
-               drm_WARN_ON(&dev_priv->drm,
-                           (intel_de_read(dev_priv, DPLL(PIPE_B)) &
-                            DPLL_VGA_MODE_DIS) == 0);
-       } else {
-               intel_de_write(dev_priv, DPLL_MD(pipe),
-                              pipe_config->dpll_hw_state.dpll_md);
-               intel_de_posting_read(dev_priv, DPLL_MD(pipe));
-       }
-}
-
-void vlv_prepare_pll(struct intel_crtc *crtc,
-                    const struct intel_crtc_state *pipe_config)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       enum pipe pipe = crtc->pipe;
        u32 mdiv;
        u32 bestn, bestm1, bestm2, bestp1, bestp2;
        u32 coreclk, reg_val;
 
-       /* Enable Refclk */
-       intel_de_write(dev_priv, DPLL(pipe),
-                      pipe_config->dpll_hw_state.dpll & ~(DPLL_VCO_ENABLE | DPLL_EXT_BUFFER_ENABLE_VLV));
-
-       /* No need to actually set up the DPLL with DSI */
-       if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0)
-               return;
-
        vlv_dpio_get(dev_priv);
 
-       bestn = pipe_config->dpll.n;
-       bestm1 = pipe_config->dpll.m1;
-       bestm2 = pipe_config->dpll.m2;
-       bestp1 = pipe_config->dpll.p1;
-       bestp2 = pipe_config->dpll.p2;
+       bestn = crtc_state->dpll.n;
+       bestm1 = crtc_state->dpll.m1;
+       bestm2 = crtc_state->dpll.m2;
+       bestp1 = crtc_state->dpll.p1;
+       bestp2 = crtc_state->dpll.p2;
 
        /* See eDP HDMI DPIO driver vbios notes doc */
 
@@ -1614,16 +1522,16 @@ void vlv_prepare_pll(struct intel_crtc *crtc,
        vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv);
 
        /* Set HBR and RBR LPF coefficients */
-       if (pipe_config->port_clock == 162000 ||
-           intel_crtc_has_type(pipe_config, INTEL_OUTPUT_ANALOG) ||
-           intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI))
+       if (crtc_state->port_clock == 162000 ||
+           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG) ||
+           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
                vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe),
                                 0x009f0003);
        else
                vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe),
                                 0x00d0000f);
 
-       if (intel_crtc_has_dp_encoder(pipe_config)) {
+       if (intel_crtc_has_dp_encoder(crtc_state)) {
                /* Use SSC source */
                if (pipe == PIPE_A)
                        vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe),
@@ -1643,7 +1551,7 @@ void vlv_prepare_pll(struct intel_crtc *crtc,
 
        coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe));
        coreclk = (coreclk & 0x0000ff00) | 0x01c00000;
-       if (intel_crtc_has_dp_encoder(pipe_config))
+       if (intel_crtc_has_dp_encoder(crtc_state))
                coreclk |= 0x01000000;
        vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk);
 
@@ -1652,11 +1560,50 @@ void vlv_prepare_pll(struct intel_crtc *crtc,
        vlv_dpio_put(dev_priv);
 }
 
-void chv_prepare_pll(struct intel_crtc *crtc,
-                    const struct intel_crtc_state *pipe_config)
+static void _vlv_enable_pll(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+
+       intel_de_write(dev_priv, DPLL(pipe), crtc_state->dpll_hw_state.dpll);
+       intel_de_posting_read(dev_priv, DPLL(pipe));
+       udelay(150);
+
+       if (intel_de_wait_for_set(dev_priv, DPLL(pipe), DPLL_LOCK_VLV, 1))
+               drm_err(&dev_priv->drm, "DPLL %d failed to lock\n", pipe);
+}
+
+void vlv_enable_pll(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+
+       assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder);
+
+       /* PLL is protected by panel, make sure we can write it */
+       assert_panel_unlocked(dev_priv, pipe);
+
+       /* Enable Refclk */
+       intel_de_write(dev_priv, DPLL(pipe),
+                      crtc_state->dpll_hw_state.dpll &
+                      ~(DPLL_VCO_ENABLE | DPLL_EXT_BUFFER_ENABLE_VLV));
+
+       if (crtc_state->dpll_hw_state.dpll & DPLL_VCO_ENABLE) {
+               vlv_prepare_pll(crtc_state);
+               _vlv_enable_pll(crtc_state);
+       }
+
+       intel_de_write(dev_priv, DPLL_MD(pipe),
+                      crtc_state->dpll_hw_state.dpll_md);
+       intel_de_posting_read(dev_priv, DPLL_MD(pipe));
+}
+
+static void chv_prepare_pll(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        enum pipe pipe = crtc->pipe;
        enum dpio_channel port = vlv_pipe_to_channel(pipe);
        u32 loopfilter, tribuf_calcntr;
@@ -1664,21 +1611,13 @@ void chv_prepare_pll(struct intel_crtc *crtc,
        u32 dpio_val;
        int vco;
 
-       /* Enable Refclk and SSC */
-       intel_de_write(dev_priv, DPLL(pipe),
-                      pipe_config->dpll_hw_state.dpll & ~DPLL_VCO_ENABLE);
-
-       /* No need to actually set up the DPLL with DSI */
-       if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0)
-               return;
-
-       bestn = pipe_config->dpll.n;
-       bestm2_frac = pipe_config->dpll.m2 & 0x3fffff;
-       bestm1 = pipe_config->dpll.m1;
-       bestm2 = pipe_config->dpll.m2 >> 22;
-       bestp1 = pipe_config->dpll.p1;
-       bestp2 = pipe_config->dpll.p2;
-       vco = pipe_config->dpll.vco;
+       bestn = crtc_state->dpll.n;
+       bestm2_frac = crtc_state->dpll.m2 & 0x3fffff;
+       bestm1 = crtc_state->dpll.m1;
+       bestm2 = crtc_state->dpll.m2 >> 22;
+       bestp1 = crtc_state->dpll.p1;
+       bestp2 = crtc_state->dpll.p2;
+       vco = crtc_state->dpll.vco;
        dpio_val = 0;
        loopfilter = 0;
 
@@ -1757,6 +1696,83 @@ void chv_prepare_pll(struct intel_crtc *crtc,
        vlv_dpio_put(dev_priv);
 }
 
+static void _chv_enable_pll(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+       enum dpio_channel port = vlv_pipe_to_channel(pipe);
+       u32 tmp;
+
+       vlv_dpio_get(dev_priv);
+
+       /* Enable back the 10bit clock to display controller */
+       tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port));
+       tmp |= DPIO_DCLKP_EN;
+       vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), tmp);
+
+       vlv_dpio_put(dev_priv);
+
+       /*
+        * Need to wait > 100ns between dclkp clock enable bit and PLL enable.
+        */
+       udelay(1);
+
+       /* Enable PLL */
+       intel_de_write(dev_priv, DPLL(pipe), crtc_state->dpll_hw_state.dpll);
+
+       /* Check PLL is locked */
+       if (intel_de_wait_for_set(dev_priv, DPLL(pipe), DPLL_LOCK_VLV, 1))
+               drm_err(&dev_priv->drm, "PLL %d failed to lock\n", pipe);
+}
+
+void chv_enable_pll(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+
+       assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder);
+
+       /* PLL is protected by panel, make sure we can write it */
+       assert_panel_unlocked(dev_priv, pipe);
+
+       /* Enable Refclk and SSC */
+       intel_de_write(dev_priv, DPLL(pipe),
+                      crtc_state->dpll_hw_state.dpll & ~DPLL_VCO_ENABLE);
+
+       if (crtc_state->dpll_hw_state.dpll & DPLL_VCO_ENABLE) {
+               chv_prepare_pll(crtc_state);
+               _chv_enable_pll(crtc_state);
+       }
+
+       if (pipe != PIPE_A) {
+               /*
+                * WaPixelRepeatModeFixForC0:chv
+                *
+                * DPLLCMD is AWOL. Use chicken bits to propagate
+                * the value from DPLLBMD to either pipe B or C.
+                */
+               intel_de_write(dev_priv, CBR4_VLV, CBR_DPLLBMD_PIPE(pipe));
+               intel_de_write(dev_priv, DPLL_MD(PIPE_B),
+                              crtc_state->dpll_hw_state.dpll_md);
+               intel_de_write(dev_priv, CBR4_VLV, 0);
+               dev_priv->chv_dpll_md[pipe] = crtc_state->dpll_hw_state.dpll_md;
+
+               /*
+                * DPLLB VGA mode also seems to cause problems.
+                * We should always have it disabled.
+                */
+               drm_WARN_ON(&dev_priv->drm,
+                           (intel_de_read(dev_priv, DPLL(PIPE_B)) &
+                            DPLL_VGA_MODE_DIS) == 0);
+       } else {
+               intel_de_write(dev_priv, DPLL_MD(pipe),
+                              crtc_state->dpll_hw_state.dpll_md);
+               intel_de_posting_read(dev_priv, DPLL_MD(pipe));
+       }
+}
+
 /**
  * vlv_force_pll_on - forcibly enable just the PLL
  * @dev_priv: i915 private structure
@@ -1771,27 +1787,26 @@ int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe,
                     const struct dpll *dpll)
 {
        struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
-       struct intel_crtc_state *pipe_config;
+       struct intel_crtc_state *crtc_state;
 
-       pipe_config = intel_crtc_state_alloc(crtc);
-       if (!pipe_config)
+       crtc_state = intel_crtc_state_alloc(crtc);
+       if (!crtc_state)
                return -ENOMEM;
 
-       pipe_config->cpu_transcoder = (enum transcoder)pipe;
-       pipe_config->pixel_multiplier = 1;
-       pipe_config->dpll = *dpll;
+       crtc_state->cpu_transcoder = (enum transcoder)pipe;
+       crtc_state->pixel_multiplier = 1;
+       crtc_state->dpll = *dpll;
+       crtc_state->output_types = BIT(INTEL_OUTPUT_EDP);
 
        if (IS_CHERRYVIEW(dev_priv)) {
-               chv_compute_dpll(crtc, pipe_config);
-               chv_prepare_pll(crtc, pipe_config);
-               chv_enable_pll(crtc, pipe_config);
+               chv_compute_dpll(crtc_state);
+               chv_enable_pll(crtc_state);
        } else {
-               vlv_compute_dpll(crtc, pipe_config);
-               vlv_prepare_pll(crtc, pipe_config);
-               vlv_enable_pll(crtc, pipe_config);
+               vlv_compute_dpll(crtc_state);
+               vlv_enable_pll(crtc_state);
        }
 
-       kfree(pipe_config);
+       kfree(crtc_state);
 
        return 0;
 }
index 88247027fd5aaee4cb612b41374eb04b567aa453..db396b3e114112a1ad4a8070981329ea9ce1d37f 100644 (file)
@@ -18,27 +18,20 @@ void intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv);
 int vlv_calc_dpll_params(int refclk, struct dpll *clock);
 int pnv_calc_dpll_params(int refclk, struct dpll *clock);
 int i9xx_calc_dpll_params(int refclk, struct dpll *clock);
-void vlv_compute_dpll(struct intel_crtc *crtc,
-                     struct intel_crtc_state *pipe_config);
-void chv_compute_dpll(struct intel_crtc *crtc,
-                     struct intel_crtc_state *pipe_config);
+u32 i9xx_dpll_compute_fp(const struct dpll *dpll);
+void vlv_compute_dpll(struct intel_crtc_state *crtc_state);
+void chv_compute_dpll(struct intel_crtc_state *crtc_state);
 
 int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe,
                     const struct dpll *dpll);
 void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe);
-void i9xx_enable_pll(struct intel_crtc *crtc,
-                    const struct intel_crtc_state *crtc_state);
-void vlv_enable_pll(struct intel_crtc *crtc,
-                   const struct intel_crtc_state *pipe_config);
-void chv_enable_pll(struct intel_crtc *crtc,
-                   const struct intel_crtc_state *pipe_config);
-void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe);
+
+void chv_enable_pll(const struct intel_crtc_state *crtc_state);
 void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe);
+void vlv_enable_pll(const struct intel_crtc_state *crtc_state);
+void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe);
+void i9xx_enable_pll(const struct intel_crtc_state *crtc_state);
 void i9xx_disable_pll(const struct intel_crtc_state *crtc_state);
-void vlv_prepare_pll(struct intel_crtc *crtc,
-                    const struct intel_crtc_state *pipe_config);
-void chv_prepare_pll(struct intel_crtc *crtc,
-                    const struct intel_crtc_state *pipe_config);
 bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state,
                        struct dpll *best_clock);
 int chv_calc_dpll_params(int refclk, struct dpll *pll_clock);
index 5c91d125a3371d7186b6d8c25c229501fe76bd77..055992d099c7c354cdddd3025854377b7663d394 100644 (file)
@@ -184,34 +184,6 @@ intel_tc_pll_enable_reg(struct drm_i915_private *i915,
        return MG_PLL_ENABLE(tc_port);
 }
 
-/**
- * intel_prepare_shared_dpll - call a dpll's prepare hook
- * @crtc_state: CRTC, and its state, which has a shared dpll
- *
- * This calls the PLL's prepare hook if it has one and if the PLL is not
- * already enabled. The prepare hook is platform specific.
- */
-void intel_prepare_shared_dpll(const struct intel_crtc_state *crtc_state)
-{
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       struct intel_shared_dpll *pll = crtc_state->shared_dpll;
-
-       if (drm_WARN_ON(&dev_priv->drm, pll == NULL))
-               return;
-
-       mutex_lock(&dev_priv->dpll.lock);
-       drm_WARN_ON(&dev_priv->drm, !pll->state.pipe_mask);
-       if (!pll->active_mask) {
-               drm_dbg(&dev_priv->drm, "setting up %s\n", pll->info->name);
-               drm_WARN_ON(&dev_priv->drm, pll->on);
-               assert_shared_dpll_disabled(dev_priv, pll);
-
-               pll->info->funcs->prepare(dev_priv, pll);
-       }
-       mutex_unlock(&dev_priv->dpll.lock);
-}
-
 /**
  * intel_enable_shared_dpll - enable a CRTC's shared DPLL
  * @crtc_state: CRTC, and its state, which has a shared DPLL
@@ -451,15 +423,6 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
        return val & DPLL_VCO_ENABLE;
 }
 
-static void ibx_pch_dpll_prepare(struct drm_i915_private *dev_priv,
-                                struct intel_shared_dpll *pll)
-{
-       const enum intel_dpll_id id = pll->info->id;
-
-       intel_de_write(dev_priv, PCH_FP0(id), pll->state.hw_state.fp0);
-       intel_de_write(dev_priv, PCH_FP1(id), pll->state.hw_state.fp1);
-}
-
 static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
 {
        u32 val;
@@ -481,6 +444,9 @@ static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
        /* PCH refclock must be enabled first */
        ibx_assert_pch_refclk_enabled(dev_priv);
 
+       intel_de_write(dev_priv, PCH_FP0(id), pll->state.hw_state.fp0);
+       intel_de_write(dev_priv, PCH_FP1(id), pll->state.hw_state.fp1);
+
        intel_de_write(dev_priv, PCH_DPLL(id), pll->state.hw_state.dpll);
 
        /* Wait for the clocks to stabilize. */
@@ -558,7 +524,6 @@ static void ibx_dump_hw_state(struct drm_i915_private *dev_priv,
 }
 
 static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = {
-       .prepare = ibx_pch_dpll_prepare,
        .enable = ibx_pch_dpll_enable,
        .disable = ibx_pch_dpll_disable,
        .get_hw_state = ibx_pch_dpll_get_hw_state,
index 30e0aa5ca1093e568f892fc3e5e1647d120ad852..2f59d863be4c0ff7a85229e19c136ed3a21b3de5 100644 (file)
@@ -255,16 +255,6 @@ struct intel_shared_dpll_state {
  * struct intel_shared_dpll_funcs - platform specific hooks for managing DPLLs
  */
 struct intel_shared_dpll_funcs {
-       /**
-        * @prepare:
-        *
-        * Optional hook to perform operations prior to enabling the PLL.
-        * Called from intel_prepare_shared_dpll() function unless the PLL
-        * is already enabled.
-        */
-       void (*prepare)(struct drm_i915_private *dev_priv,
-                       struct intel_shared_dpll *pll);
-
        /**
         * @enable:
         *
@@ -404,7 +394,6 @@ int intel_dpll_get_freq(struct drm_i915_private *i915,
 bool intel_dpll_get_hw_state(struct drm_i915_private *i915,
                             struct intel_shared_dpll *pll,
                             struct intel_dpll_hw_state *hw_state);
-void intel_prepare_shared_dpll(const struct intel_crtc_state *crtc_state);
 void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state);
 void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state);
 void intel_shared_dpll_swap_state(struct intel_atomic_state *state);
diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c
new file mode 100644 (file)
index 0000000..de62bd7
--- /dev/null
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright Â© 2021 Intel Corporation
+ */
+
+#include "i915_drv.h"
+#include "intel_display_types.h"
+#include "intel_dpt.h"
+#include "intel_fb.h"
+#include "gt/gen8_ppgtt.h"
+
+struct i915_dpt {
+       struct i915_address_space vm;
+
+       struct drm_i915_gem_object *obj;
+       struct i915_vma *vma;
+       void __iomem *iomem;
+};
+
+#define i915_is_dpt(vm) ((vm)->is_dpt)
+
+static inline struct i915_dpt *
+i915_vm_to_dpt(struct i915_address_space *vm)
+{
+       BUILD_BUG_ON(offsetof(struct i915_dpt, vm));
+       GEM_BUG_ON(!i915_is_dpt(vm));
+       return container_of(vm, struct i915_dpt, vm);
+}
+
+#define dpt_total_entries(dpt) ((dpt)->vm.total >> PAGE_SHIFT)
+
+static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte)
+{
+       writeq(pte, addr);
+}
+
+static void dpt_insert_page(struct i915_address_space *vm,
+                           dma_addr_t addr,
+                           u64 offset,
+                           enum i915_cache_level level,
+                           u32 flags)
+{
+       struct i915_dpt *dpt = i915_vm_to_dpt(vm);
+       gen8_pte_t __iomem *base = dpt->iomem;
+
+       gen8_set_pte(base + offset / I915_GTT_PAGE_SIZE,
+                    vm->pte_encode(addr, level, flags));
+}
+
+static void dpt_insert_entries(struct i915_address_space *vm,
+                              struct i915_vma *vma,
+                              enum i915_cache_level level,
+                              u32 flags)
+{
+       struct i915_dpt *dpt = i915_vm_to_dpt(vm);
+       gen8_pte_t __iomem *base = dpt->iomem;
+       const gen8_pte_t pte_encode = vm->pte_encode(0, level, flags);
+       struct sgt_iter sgt_iter;
+       dma_addr_t addr;
+       int i;
+
+       /*
+        * Note that we ignore PTE_READ_ONLY here. The caller must be careful
+        * not to allow the user to override access to a read only page.
+        */
+
+       i = vma->node.start / I915_GTT_PAGE_SIZE;
+       for_each_sgt_daddr(addr, sgt_iter, vma->pages)
+               gen8_set_pte(&base[i++], pte_encode | addr);
+}
+
+static void dpt_clear_range(struct i915_address_space *vm,
+                           u64 start, u64 length)
+{
+}
+
+static void dpt_bind_vma(struct i915_address_space *vm,
+                        struct i915_vm_pt_stash *stash,
+                        struct i915_vma *vma,
+                        enum i915_cache_level cache_level,
+                        u32 flags)
+{
+       struct drm_i915_gem_object *obj = vma->obj;
+       u32 pte_flags;
+
+       /* Applicable to VLV (gen8+ do not support RO in the GGTT) */
+       pte_flags = 0;
+       if (vma->vm->has_read_only && i915_gem_object_is_readonly(obj))
+               pte_flags |= PTE_READ_ONLY;
+       if (i915_gem_object_is_lmem(obj))
+               pte_flags |= PTE_LM;
+
+       vma->vm->insert_entries(vma->vm, vma, cache_level, pte_flags);
+
+       vma->page_sizes.gtt = I915_GTT_PAGE_SIZE;
+
+       /*
+        * Without aliasing PPGTT there's no difference between
+        * GLOBAL/LOCAL_BIND, it's all the same ptes. Hence unconditionally
+        * upgrade to both bound if we bind either to avoid double-binding.
+        */
+       atomic_or(I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND, &vma->flags);
+}
+
+static void dpt_unbind_vma(struct i915_address_space *vm, struct i915_vma *vma)
+{
+       vm->clear_range(vm, vma->node.start, vma->size);
+}
+
+static void dpt_cleanup(struct i915_address_space *vm)
+{
+       struct i915_dpt *dpt = i915_vm_to_dpt(vm);
+
+       i915_gem_object_put(dpt->obj);
+}
+
+struct i915_vma *intel_dpt_pin(struct i915_address_space *vm)
+{
+       struct drm_i915_private *i915 = vm->i915;
+       struct i915_dpt *dpt = i915_vm_to_dpt(vm);
+       intel_wakeref_t wakeref;
+       struct i915_vma *vma;
+       void __iomem *iomem;
+
+       wakeref = intel_runtime_pm_get(&i915->runtime_pm);
+       atomic_inc(&i915->gpu_error.pending_fb_pin);
+
+       vma = i915_gem_object_ggtt_pin(dpt->obj, NULL, 0, 4096,
+                                      HAS_LMEM(i915) ? 0 : PIN_MAPPABLE);
+       if (IS_ERR(vma))
+               goto err;
+
+       iomem = i915_vma_pin_iomap(vma);
+       i915_vma_unpin(vma);
+       if (IS_ERR(iomem)) {
+               vma = ERR_CAST(iomem);
+               goto err;
+       }
+
+       dpt->vma = vma;
+       dpt->iomem = iomem;
+
+       i915_vma_get(vma);
+
+err:
+       atomic_dec(&i915->gpu_error.pending_fb_pin);
+       intel_runtime_pm_put(&i915->runtime_pm, wakeref);
+
+       return vma;
+}
+
+void intel_dpt_unpin(struct i915_address_space *vm)
+{
+       struct i915_dpt *dpt = i915_vm_to_dpt(vm);
+
+       i915_vma_unpin_iomap(dpt->vma);
+       i915_vma_put(dpt->vma);
+}
+
+struct i915_address_space *
+intel_dpt_create(struct intel_framebuffer *fb)
+{
+       struct drm_gem_object *obj = &intel_fb_obj(&fb->base)->base;
+       struct drm_i915_private *i915 = to_i915(obj->dev);
+       struct drm_i915_gem_object *dpt_obj;
+       struct i915_address_space *vm;
+       struct i915_dpt *dpt;
+       size_t size;
+       int ret;
+
+       if (intel_fb_needs_pot_stride_remap(fb))
+               size = intel_remapped_info_size(&fb->remapped_view.gtt.remapped);
+       else
+               size = DIV_ROUND_UP_ULL(obj->size, I915_GTT_PAGE_SIZE);
+
+       size = round_up(size * sizeof(gen8_pte_t), I915_GTT_PAGE_SIZE);
+
+       if (HAS_LMEM(i915))
+               dpt_obj = i915_gem_object_create_lmem(i915, size, 0);
+       else
+               dpt_obj = i915_gem_object_create_stolen(i915, size);
+       if (IS_ERR(dpt_obj))
+               return ERR_CAST(dpt_obj);
+
+       ret = i915_gem_object_set_cache_level(dpt_obj, I915_CACHE_NONE);
+       if (ret) {
+               i915_gem_object_put(dpt_obj);
+               return ERR_PTR(ret);
+       }
+
+       dpt = kzalloc(sizeof(*dpt), GFP_KERNEL);
+       if (!dpt) {
+               i915_gem_object_put(dpt_obj);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       vm = &dpt->vm;
+
+       vm->gt = &i915->gt;
+       vm->i915 = i915;
+       vm->dma = i915->drm.dev;
+       vm->total = (size / sizeof(gen8_pte_t)) * I915_GTT_PAGE_SIZE;
+       vm->is_dpt = true;
+
+       i915_address_space_init(vm, VM_CLASS_DPT);
+
+       vm->insert_page = dpt_insert_page;
+       vm->clear_range = dpt_clear_range;
+       vm->insert_entries = dpt_insert_entries;
+       vm->cleanup = dpt_cleanup;
+
+       vm->vma_ops.bind_vma    = dpt_bind_vma;
+       vm->vma_ops.unbind_vma  = dpt_unbind_vma;
+       vm->vma_ops.set_pages   = ggtt_set_pages;
+       vm->vma_ops.clear_pages = clear_pages;
+
+       vm->pte_encode = gen8_ggtt_pte_encode;
+
+       dpt->obj = dpt_obj;
+
+       return &dpt->vm;
+}
+
+void intel_dpt_destroy(struct i915_address_space *vm)
+{
+       struct i915_dpt *dpt = i915_vm_to_dpt(vm);
+
+       i915_vm_close(&dpt->vm);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dpt.h b/drivers/gpu/drm/i915/display/intel_dpt.h
new file mode 100644 (file)
index 0000000..45142b8
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright Â© 2021 Intel Corporation
+ */
+
+#ifndef __INTEL_DPT_H__
+#define __INTEL_DPT_H__
+
+struct i915_address_space;
+struct i915_vma;
+struct intel_framebuffer;
+
+void intel_dpt_destroy(struct i915_address_space *vm);
+struct i915_vma *intel_dpt_pin(struct i915_address_space *vm);
+void intel_dpt_unpin(struct i915_address_space *vm);
+struct i915_address_space *
+intel_dpt_create(struct intel_framebuffer *fb);
+
+#endif /* __INTEL_DPT_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c
new file mode 100644 (file)
index 0000000..c1439fc
--- /dev/null
@@ -0,0 +1,437 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright Â© 2021 Intel Corporation
+ */
+
+#include "i915_drv.h"
+#include "intel_atomic.h"
+#include "intel_de.h"
+#include "intel_display_types.h"
+#include "intel_drrs.h"
+#include "intel_panel.h"
+
+/**
+ * DOC: Display Refresh Rate Switching (DRRS)
+ *
+ * Display Refresh Rate Switching (DRRS) is a power conservation feature
+ * which enables swtching between low and high refresh rates,
+ * dynamically, based on the usage scenario. This feature is applicable
+ * for internal panels.
+ *
+ * Indication that the panel supports DRRS is given by the panel EDID, which
+ * would list multiple refresh rates for one resolution.
+ *
+ * DRRS is of 2 types - static and seamless.
+ * Static DRRS involves changing refresh rate (RR) by doing a full modeset
+ * (may appear as a blink on screen) and is used in dock-undock scenario.
+ * Seamless DRRS involves changing RR without any visual effect to the user
+ * and can be used during normal system usage. This is done by programming
+ * certain registers.
+ *
+ * Support for static/seamless DRRS may be indicated in the VBT based on
+ * inputs from the panel spec.
+ *
+ * DRRS saves power by switching to low RR based on usage scenarios.
+ *
+ * The implementation is based on frontbuffer tracking implementation.  When
+ * there is a disturbance on the screen triggered by user activity or a periodic
+ * system activity, DRRS is disabled (RR is changed to high RR).  When there is
+ * no movement on screen, after a timeout of 1 second, a switch to low RR is
+ * made.
+ *
+ * For integration with frontbuffer tracking code, intel_drrs_invalidate()
+ * and intel_drrs_flush() are called.
+ *
+ * DRRS can be further extended to support other internal panels and also
+ * the scenario of video playback wherein RR is set based on the rate
+ * requested by userspace.
+ */
+
+void
+intel_drrs_compute_config(struct intel_dp *intel_dp,
+                         struct intel_crtc_state *pipe_config,
+                         int output_bpp, bool constant_n)
+{
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       int pixel_clock;
+
+       if (pipe_config->vrr.enable)
+               return;
+
+       /*
+        * DRRS and PSR can't be enable together, so giving preference to PSR
+        * as it allows more power-savings by complete shutting down display,
+        * so to guarantee this, intel_drrs_compute_config() must be called
+        * after intel_psr_compute_config().
+        */
+       if (pipe_config->has_psr)
+               return;
+
+       if (!intel_connector->panel.downclock_mode ||
+           dev_priv->drrs.type != SEAMLESS_DRRS_SUPPORT)
+               return;
+
+       pipe_config->has_drrs = true;
+
+       pixel_clock = intel_connector->panel.downclock_mode->clock;
+       if (pipe_config->splitter.enable)
+               pixel_clock /= pipe_config->splitter.link_count;
+
+       intel_link_compute_m_n(output_bpp, pipe_config->lane_count, pixel_clock,
+                              pipe_config->port_clock, &pipe_config->dp_m2_n2,
+                              constant_n, pipe_config->fec_enable);
+
+       /* FIXME: abstract this better */
+       if (pipe_config->splitter.enable)
+               pipe_config->dp_m2_n2.gmch_m *= pipe_config->splitter.link_count;
+}
+
+static void intel_drrs_set_state(struct drm_i915_private *dev_priv,
+                                const struct intel_crtc_state *crtc_state,
+                                enum drrs_refresh_rate_type refresh_type)
+{
+       struct intel_dp *intel_dp = dev_priv->drrs.dp;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_display_mode *mode;
+
+       if (!intel_dp) {
+               drm_dbg_kms(&dev_priv->drm, "DRRS not supported.\n");
+               return;
+       }
+
+       if (!crtc) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "DRRS: intel_crtc not initialized\n");
+               return;
+       }
+
+       if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) {
+               drm_dbg_kms(&dev_priv->drm, "Only Seamless DRRS supported.\n");
+               return;
+       }
+
+       if (refresh_type == dev_priv->drrs.refresh_rate_type)
+               return;
+
+       if (!crtc_state->hw.active) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "eDP encoder disabled. CRTC not Active\n");
+               return;
+       }
+
+       if (DISPLAY_VER(dev_priv) >= 8 && !IS_CHERRYVIEW(dev_priv)) {
+               switch (refresh_type) {
+               case DRRS_HIGH_RR:
+                       intel_dp_set_m_n(crtc_state, M1_N1);
+                       break;
+               case DRRS_LOW_RR:
+                       intel_dp_set_m_n(crtc_state, M2_N2);
+                       break;
+               case DRRS_MAX_RR:
+               default:
+                       drm_err(&dev_priv->drm,
+                               "Unsupported refreshrate type\n");
+               }
+       } else if (DISPLAY_VER(dev_priv) > 6) {
+               i915_reg_t reg = PIPECONF(crtc_state->cpu_transcoder);
+               u32 val;
+
+               val = intel_de_read(dev_priv, reg);
+               if (refresh_type == DRRS_LOW_RR) {
+                       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+                               val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
+                       else
+                               val |= PIPECONF_EDP_RR_MODE_SWITCH;
+               } else {
+                       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+                               val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV;
+                       else
+                               val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
+               }
+               intel_de_write(dev_priv, reg, val);
+       }
+
+       dev_priv->drrs.refresh_rate_type = refresh_type;
+
+       if (refresh_type == DRRS_LOW_RR)
+               mode = intel_dp->attached_connector->panel.downclock_mode;
+       else
+               mode = intel_dp->attached_connector->panel.fixed_mode;
+       drm_dbg_kms(&dev_priv->drm, "eDP Refresh Rate set to : %dHz\n",
+                   drm_mode_vrefresh(mode));
+}
+
+static void
+intel_drrs_enable_locked(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       dev_priv->drrs.busy_frontbuffer_bits = 0;
+       dev_priv->drrs.dp = intel_dp;
+}
+
+/**
+ * intel_drrs_enable - init drrs struct if supported
+ * @intel_dp: DP struct
+ * @crtc_state: A pointer to the active crtc state.
+ *
+ * Initializes frontbuffer_bits and drrs.dp
+ */
+void intel_drrs_enable(struct intel_dp *intel_dp,
+                      const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       if (!crtc_state->has_drrs)
+               return;
+
+       drm_dbg_kms(&dev_priv->drm, "Enabling DRRS\n");
+
+       mutex_lock(&dev_priv->drrs.mutex);
+
+       if (dev_priv->drrs.dp) {
+               drm_warn(&dev_priv->drm, "DRRS already enabled\n");
+               goto unlock;
+       }
+
+       intel_drrs_enable_locked(intel_dp);
+
+unlock:
+       mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+static void
+intel_drrs_disable_locked(struct intel_dp *intel_dp,
+                         const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       intel_drrs_set_state(dev_priv, crtc_state, DRRS_HIGH_RR);
+       dev_priv->drrs.dp = NULL;
+}
+
+/**
+ * intel_drrs_disable - Disable DRRS
+ * @intel_dp: DP struct
+ * @old_crtc_state: Pointer to old crtc_state.
+ *
+ */
+void intel_drrs_disable(struct intel_dp *intel_dp,
+                       const struct intel_crtc_state *old_crtc_state)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       if (!old_crtc_state->has_drrs)
+               return;
+
+       mutex_lock(&dev_priv->drrs.mutex);
+       if (!dev_priv->drrs.dp) {
+               mutex_unlock(&dev_priv->drrs.mutex);
+               return;
+       }
+
+       intel_drrs_disable_locked(intel_dp, old_crtc_state);
+       mutex_unlock(&dev_priv->drrs.mutex);
+
+       cancel_delayed_work_sync(&dev_priv->drrs.work);
+}
+
+/**
+ * intel_drrs_update - Update DRRS state
+ * @intel_dp: Intel DP
+ * @crtc_state: new CRTC state
+ *
+ * This function will update DRRS states, disabling or enabling DRRS when
+ * executing fastsets. For full modeset, intel_drrs_disable() and
+ * intel_drrs_enable() should be called instead.
+ */
+void
+intel_drrs_update(struct intel_dp *intel_dp,
+                 const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       if (dev_priv->drrs.type != SEAMLESS_DRRS_SUPPORT)
+               return;
+
+       mutex_lock(&dev_priv->drrs.mutex);
+
+       /* New state matches current one? */
+       if (crtc_state->has_drrs == !!dev_priv->drrs.dp)
+               goto unlock;
+
+       if (crtc_state->has_drrs)
+               intel_drrs_enable_locked(intel_dp);
+       else
+               intel_drrs_disable_locked(intel_dp, crtc_state);
+
+unlock:
+       mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+static void intel_drrs_downclock_work(struct work_struct *work)
+{
+       struct drm_i915_private *dev_priv =
+               container_of(work, typeof(*dev_priv), drrs.work.work);
+       struct intel_dp *intel_dp;
+       struct drm_crtc *crtc;
+
+       mutex_lock(&dev_priv->drrs.mutex);
+
+       intel_dp = dev_priv->drrs.dp;
+
+       if (!intel_dp)
+               goto unlock;
+
+       /*
+        * The delayed work can race with an invalidate hence we need to
+        * recheck.
+        */
+
+       if (dev_priv->drrs.busy_frontbuffer_bits)
+               goto unlock;
+
+       crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
+       intel_drrs_set_state(dev_priv, to_intel_crtc(crtc)->config, DRRS_LOW_RR);
+
+unlock:
+       mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+static void intel_drrs_frontbuffer_update(struct drm_i915_private *dev_priv,
+                                         unsigned int frontbuffer_bits,
+                                         bool invalidate)
+{
+       struct intel_dp *intel_dp;
+       struct drm_crtc *crtc;
+       enum pipe pipe;
+
+       if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
+               return;
+
+       cancel_delayed_work(&dev_priv->drrs.work);
+
+       mutex_lock(&dev_priv->drrs.mutex);
+
+       intel_dp = dev_priv->drrs.dp;
+       if (!intel_dp) {
+               mutex_unlock(&dev_priv->drrs.mutex);
+               return;
+       }
+
+       crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
+       pipe = to_intel_crtc(crtc)->pipe;
+
+       frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
+       if (invalidate)
+               dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
+       else
+               dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
+
+       /* flush/invalidate means busy screen hence upclock */
+       if (frontbuffer_bits)
+               intel_drrs_set_state(dev_priv, to_intel_crtc(crtc)->config,
+                                    DRRS_HIGH_RR);
+
+       /*
+        * flush also means no more activity hence schedule downclock, if all
+        * other fbs are quiescent too
+        */
+       if (!invalidate && !dev_priv->drrs.busy_frontbuffer_bits)
+               schedule_delayed_work(&dev_priv->drrs.work,
+                                     msecs_to_jiffies(1000));
+       mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+/**
+ * intel_drrs_invalidate - Disable Idleness DRRS
+ * @dev_priv: i915 device
+ * @frontbuffer_bits: frontbuffer plane tracking bits
+ *
+ * This function gets called everytime rendering on the given planes start.
+ * Hence DRRS needs to be Upclocked, i.e. (LOW_RR -> HIGH_RR).
+ *
+ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
+ */
+void intel_drrs_invalidate(struct drm_i915_private *dev_priv,
+                          unsigned int frontbuffer_bits)
+{
+       intel_drrs_frontbuffer_update(dev_priv, frontbuffer_bits, true);
+}
+
+/**
+ * intel_drrs_flush - Restart Idleness DRRS
+ * @dev_priv: i915 device
+ * @frontbuffer_bits: frontbuffer plane tracking bits
+ *
+ * This function gets called every time rendering on the given planes has
+ * completed or flip on a crtc is completed. So DRRS should be upclocked
+ * (LOW_RR -> HIGH_RR). And also Idleness detection should be started again,
+ * if no other planes are dirty.
+ *
+ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
+ */
+void intel_drrs_flush(struct drm_i915_private *dev_priv,
+                     unsigned int frontbuffer_bits)
+{
+       intel_drrs_frontbuffer_update(dev_priv, frontbuffer_bits, false);
+}
+
+void intel_drrs_page_flip(struct intel_atomic_state *state,
+                         struct intel_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+       unsigned int frontbuffer_bits = INTEL_FRONTBUFFER_ALL_MASK(crtc->pipe);
+
+       intel_drrs_frontbuffer_update(dev_priv, frontbuffer_bits, false);
+}
+
+/**
+ * intel_drrs_init - Init basic DRRS work and mutex.
+ * @connector: eDP connector
+ * @fixed_mode: preferred mode of panel
+ *
+ * This function is  called only once at driver load to initialize basic
+ * DRRS stuff.
+ *
+ * Returns:
+ * Downclock mode if panel supports it, else return NULL.
+ * DRRS support is determined by the presence of downclock mode (apart
+ * from VBT setting).
+ */
+struct drm_display_mode *
+intel_drrs_init(struct intel_connector *connector,
+               struct drm_display_mode *fixed_mode)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct drm_display_mode *downclock_mode = NULL;
+
+       INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_drrs_downclock_work);
+       mutex_init(&dev_priv->drrs.mutex);
+
+       if (DISPLAY_VER(dev_priv) <= 6) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "DRRS supported for Gen7 and above\n");
+               return NULL;
+       }
+
+       if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
+               drm_dbg_kms(&dev_priv->drm, "VBT doesn't support DRRS\n");
+               return NULL;
+       }
+
+       downclock_mode = intel_panel_edid_downclock_mode(connector, fixed_mode);
+       if (!downclock_mode) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "Downclock mode is not found. DRRS not supported\n");
+               return NULL;
+       }
+
+       dev_priv->drrs.type = dev_priv->vbt.drrs_type;
+
+       dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR;
+       drm_dbg_kms(&dev_priv->drm,
+                   "seamless DRRS supported for eDP panel.\n");
+       return downclock_mode;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_drrs.h b/drivers/gpu/drm/i915/display/intel_drrs.h
new file mode 100644 (file)
index 0000000..9ec9c44
--- /dev/null
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright Â© 2021 Intel Corporation
+ */
+
+#ifndef __INTEL_DRRS_H__
+#define __INTEL_DRRS_H__
+
+#include <linux/types.h>
+
+struct drm_i915_private;
+struct intel_atomic_state;
+struct intel_crtc;
+struct intel_crtc_state;
+struct intel_connector;
+struct intel_dp;
+
+void intel_drrs_enable(struct intel_dp *intel_dp,
+                      const struct intel_crtc_state *crtc_state);
+void intel_drrs_disable(struct intel_dp *intel_dp,
+                       const struct intel_crtc_state *crtc_state);
+void intel_drrs_update(struct intel_dp *intel_dp,
+                      const struct intel_crtc_state *crtc_state);
+void intel_drrs_invalidate(struct drm_i915_private *dev_priv,
+                          unsigned int frontbuffer_bits);
+void intel_drrs_flush(struct drm_i915_private *dev_priv,
+                     unsigned int frontbuffer_bits);
+void intel_drrs_page_flip(struct intel_atomic_state *state,
+                         struct intel_crtc *crtc);
+void intel_drrs_compute_config(struct intel_dp *intel_dp,
+                              struct intel_crtc_state *pipe_config,
+                              int output_bpp, bool constant_n);
+struct drm_display_mode *intel_drrs_init(struct intel_connector *connector,
+                                        struct drm_display_mode *fixed_mode);
+
+#endif /* __INTEL_DRRS_H__ */
index 584c14c4cbd0e17f2c56e90bb5f7b01cf0a53572..f61ed82e8867126ce7d7d734b1949c3a7948bf6a 100644 (file)
@@ -47,33 +47,42 @@ static u32 dcs_get_backlight(struct intel_connector *connector, enum pipe unused
 {
        struct intel_encoder *encoder = intel_attached_encoder(connector);
        struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
+       struct intel_panel *panel = &connector->panel;
        struct mipi_dsi_device *dsi_device;
-       u8 data = 0;
+       u8 data[2] = {};
        enum port port;
+       size_t len = panel->backlight.max > U8_MAX ? 2 : 1;
 
-       /* FIXME: Need to take care of 16 bit brightness level */
        for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
                dsi_device = intel_dsi->dsi_hosts[port]->device;
                mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
-                                 &data, sizeof(data));
+                                 &data, len);
                break;
        }
 
-       return data;
+       return (data[1] << 8) | data[0];
 }
 
 static void dcs_set_backlight(const struct drm_connector_state *conn_state, u32 level)
 {
        struct intel_dsi *intel_dsi = enc_to_intel_dsi(to_intel_encoder(conn_state->best_encoder));
+       struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;
        struct mipi_dsi_device *dsi_device;
-       u8 data = level;
+       u8 data[2] = {};
        enum port port;
+       size_t len = panel->backlight.max > U8_MAX ? 2 : 1;
+
+       if (len == 1) {
+               data[0] = level;
+       } else {
+               data[0] = level >> 8;
+               data[1] = level;
+       }
 
-       /* FIXME: Need to take care of 16 bit brightness level */
        for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
                dsi_device = intel_dsi->dsi_hosts[port]->device;
                mipi_dsi_dcs_write(dsi_device, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
-                                  &data, sizeof(data));
+                                  &data, len);
        }
 }
 
@@ -147,10 +156,16 @@ static void dcs_enable_backlight(const struct intel_crtc_state *crtc_state,
 static int dcs_setup_backlight(struct intel_connector *connector,
                               enum pipe unused)
 {
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_panel *panel = &connector->panel;
 
-       panel->backlight.max = PANEL_PWM_MAX_VALUE;
-       panel->backlight.level = PANEL_PWM_MAX_VALUE;
+       if (dev_priv->vbt.backlight.brightness_precision_bits > 8)
+               panel->backlight.max = (1 << dev_priv->vbt.backlight.brightness_precision_bits) - 1;
+       else
+               panel->backlight.max = PANEL_PWM_MAX_VALUE;
+
+       panel->backlight.level = panel->backlight.max;
 
        return 0;
 }
index 77419f8c05e9f720f58bddd6bf931dbff95fe4a5..86c903e9df604f7484de087b48ca9eceddd7befc 100644 (file)
@@ -265,7 +265,7 @@ static int intel_dvo_compute_config(struct intel_encoder *encoder,
         * of the original mode.
         */
        if (fixed_mode)
-               intel_fixed_panel_mode(fixed_mode, adjusted_mode);
+               intel_panel_fixed_mode(fixed_mode, adjusted_mode);
 
        if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return -EINVAL;
index c60a81a81c09cdaa3db90af9d29e585b94ad7c5e..e4b8602ec0cd203c3fe747645f6039b605852b97 100644 (file)
@@ -4,9 +4,11 @@
  */
 
 #include <drm/drm_framebuffer.h>
+#include <drm/drm_modeset_helper.h>
 
 #include "intel_display.h"
 #include "intel_display_types.h"
+#include "intel_dpt.h"
 #include "intel_fb.h"
 
 #define check_array_bounds(i915, a, i) drm_WARN_ON(&(i915)->drm, (i) >= ARRAY_SIZE(a))
@@ -61,6 +63,12 @@ int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane)
        return ccs_plane - fb->format->num_planes / 2;
 }
 
+static int gen12_ccs_aux_stride(struct drm_framebuffer *fb, int ccs_plane)
+{
+       return DIV_ROUND_UP(fb->pitches[skl_ccs_to_main_plane(fb, ccs_plane)],
+                           512) * 64;
+}
+
 int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane)
 {
        struct drm_i915_private *i915 = to_i915(fb->dev);
@@ -79,6 +87,60 @@ unsigned int intel_tile_size(const struct drm_i915_private *i915)
        return DISPLAY_VER(i915) == 2 ? 2048 : 4096;
 }
 
+unsigned int
+intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
+{
+       struct drm_i915_private *dev_priv = to_i915(fb->dev);
+       unsigned int cpp = fb->format->cpp[color_plane];
+
+       switch (fb->modifier) {
+       case DRM_FORMAT_MOD_LINEAR:
+               return intel_tile_size(dev_priv);
+       case I915_FORMAT_MOD_X_TILED:
+               if (DISPLAY_VER(dev_priv) == 2)
+                       return 128;
+               else
+                       return 512;
+       case I915_FORMAT_MOD_Y_TILED_CCS:
+               if (is_ccs_plane(fb, color_plane))
+                       return 128;
+               fallthrough;
+       case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
+       case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
+       case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
+               if (is_ccs_plane(fb, color_plane))
+                       return 64;
+               fallthrough;
+       case I915_FORMAT_MOD_Y_TILED:
+               if (DISPLAY_VER(dev_priv) == 2 || HAS_128_BYTE_Y_TILING(dev_priv))
+                       return 128;
+               else
+                       return 512;
+       case I915_FORMAT_MOD_Yf_TILED_CCS:
+               if (is_ccs_plane(fb, color_plane))
+                       return 128;
+               fallthrough;
+       case I915_FORMAT_MOD_Yf_TILED:
+               switch (cpp) {
+               case 1:
+                       return 64;
+               case 2:
+               case 4:
+                       return 128;
+               case 8:
+               case 16:
+                       return 256;
+               default:
+                       MISSING_CASE(cpp);
+                       return cpp;
+               }
+               break;
+       default:
+               MISSING_CASE(fb->modifier);
+               return cpp;
+       }
+}
+
 unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
 {
        if (is_gen12_ccs_plane(fb, color_plane))
@@ -109,6 +171,31 @@ unsigned int intel_tile_row_size(const struct drm_framebuffer *fb, int color_pla
        return fb->pitches[color_plane] * tile_height;
 }
 
+unsigned int
+intel_fb_align_height(const struct drm_framebuffer *fb,
+                     int color_plane, unsigned int height)
+{
+       unsigned int tile_height = intel_tile_height(fb, color_plane);
+
+       return ALIGN(height, tile_height);
+}
+
+static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
+{
+       switch (fb_modifier) {
+       case I915_FORMAT_MOD_X_TILED:
+               return I915_TILING_X;
+       case I915_FORMAT_MOD_Y_TILED:
+       case I915_FORMAT_MOD_Y_TILED_CCS:
+       case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
+       case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
+       case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
+               return I915_TILING_Y;
+       default:
+               return I915_TILING_NONE;
+       }
+}
+
 unsigned int intel_cursor_alignment(const struct drm_i915_private *i915)
 {
        if (IS_I830(i915))
@@ -121,6 +208,70 @@ unsigned int intel_cursor_alignment(const struct drm_i915_private *i915)
                return 4 * 1024;
 }
 
+static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv)
+{
+       if (DISPLAY_VER(dev_priv) >= 9)
+               return 256 * 1024;
+       else if (IS_I965G(dev_priv) || IS_I965GM(dev_priv) ||
+                IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               return 128 * 1024;
+       else if (DISPLAY_VER(dev_priv) >= 4)
+               return 4 * 1024;
+       else
+               return 0;
+}
+
+unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
+                                 int color_plane)
+{
+       struct drm_i915_private *dev_priv = to_i915(fb->dev);
+
+       if (intel_fb_uses_dpt(fb))
+               return 512 * 4096;
+
+       /* AUX_DIST needs only 4K alignment */
+       if (is_ccs_plane(fb, color_plane))
+               return 4096;
+
+       if (is_semiplanar_uv_plane(fb, color_plane)) {
+               /*
+                * TODO: cross-check wrt. the bspec stride in bytes * 64 bytes
+                * alignment for linear UV planes on all platforms.
+                */
+               if (DISPLAY_VER(dev_priv) >= 12) {
+                       if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
+                               return intel_linear_alignment(dev_priv);
+
+                       return intel_tile_row_size(fb, color_plane);
+               }
+
+               return 4096;
+       }
+
+       drm_WARN_ON(&dev_priv->drm, color_plane != 0);
+
+       switch (fb->modifier) {
+       case DRM_FORMAT_MOD_LINEAR:
+               return intel_linear_alignment(dev_priv);
+       case I915_FORMAT_MOD_X_TILED:
+               if (HAS_ASYNC_FLIPS(dev_priv))
+                       return 256 * 1024;
+               return 0;
+       case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
+       case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
+       case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
+               return 16 * 1024;
+       case I915_FORMAT_MOD_Y_TILED_CCS:
+       case I915_FORMAT_MOD_Yf_TILED_CCS:
+       case I915_FORMAT_MOD_Y_TILED:
+       case I915_FORMAT_MOD_Yf_TILED:
+               return 1 * 1024 * 1024;
+       default:
+               MISSING_CASE(fb->modifier);
+               return 0;
+       }
+}
+
 void intel_fb_plane_get_subsampling(int *hsub, int *vsub,
                                    const struct drm_framebuffer *fb,
                                    int color_plane)
@@ -918,6 +1069,71 @@ void intel_fb_fill_view(const struct intel_framebuffer *fb, unsigned int rotatio
                *view = fb->normal_view;
 }
 
+static
+u32 intel_fb_max_stride(struct drm_i915_private *dev_priv,
+                       u32 pixel_format, u64 modifier)
+{
+       /*
+        * Arbitrary limit for gen4+ chosen to match the
+        * render engine max stride.
+        *
+        * The new CCS hash mode makes remapping impossible
+        */
+       if (DISPLAY_VER(dev_priv) < 4 || is_ccs_modifier(modifier) ||
+           intel_modifier_uses_dpt(dev_priv, modifier))
+               return intel_plane_fb_max_stride(dev_priv, pixel_format, modifier);
+       else if (DISPLAY_VER(dev_priv) >= 7)
+               return 256 * 1024;
+       else
+               return 128 * 1024;
+}
+
+static u32
+intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
+{
+       struct drm_i915_private *dev_priv = to_i915(fb->dev);
+       u32 tile_width;
+
+       if (is_surface_linear(fb, color_plane)) {
+               u32 max_stride = intel_plane_fb_max_stride(dev_priv,
+                                                          fb->format->format,
+                                                          fb->modifier);
+
+               /*
+                * To make remapping with linear generally feasible
+                * we need the stride to be page aligned.
+                */
+               if (fb->pitches[color_plane] > max_stride &&
+                   !is_ccs_modifier(fb->modifier))
+                       return intel_tile_size(dev_priv);
+               else
+                       return 64;
+       }
+
+       tile_width = intel_tile_width_bytes(fb, color_plane);
+       if (is_ccs_modifier(fb->modifier)) {
+               /*
+                * Display WA #0531: skl,bxt,kbl,glk
+                *
+                * Render decompression and plane width > 3840
+                * combined with horizontal panning requires the
+                * plane stride to be a multiple of 4. We'll just
+                * require the entire fb to accommodate that to avoid
+                * potential runtime errors at plane configuration time.
+                */
+               if ((DISPLAY_VER(dev_priv) == 9 || IS_GEMINILAKE(dev_priv)) &&
+                   color_plane == 0 && fb->width > 3840)
+                       tile_width *= 4;
+               /*
+                * The main surface pitch must be padded to a multiple of four
+                * tile widths.
+                */
+               else if (DISPLAY_VER(dev_priv) >= 12)
+                       tile_width *= 4;
+       }
+       return tile_width;
+}
+
 static int intel_plane_check_stride(const struct intel_plane_state *plane_state)
 {
        struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
@@ -981,3 +1197,268 @@ int intel_plane_compute_gtt(struct intel_plane_state *plane_state)
 
        return intel_plane_check_stride(plane_state);
 }
+
+static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+
+       drm_framebuffer_cleanup(fb);
+
+       if (intel_fb_uses_dpt(fb))
+               intel_dpt_destroy(intel_fb->dpt_vm);
+
+       intel_frontbuffer_put(intel_fb->frontbuffer);
+
+       kfree(intel_fb);
+}
+
+static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb,
+                                               struct drm_file *file,
+                                               unsigned int *handle)
+{
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       struct drm_i915_private *i915 = to_i915(obj->base.dev);
+
+       if (i915_gem_object_is_userptr(obj)) {
+               drm_dbg(&i915->drm,
+                       "attempting to use a userptr for a framebuffer, denied\n");
+               return -EINVAL;
+       }
+
+       return drm_gem_handle_create(file, &obj->base, handle);
+}
+
+static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb,
+                                       struct drm_file *file,
+                                       unsigned int flags, unsigned int color,
+                                       struct drm_clip_rect *clips,
+                                       unsigned int num_clips)
+{
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+
+       i915_gem_object_flush_if_display(obj);
+       intel_frontbuffer_flush(to_intel_frontbuffer(fb), ORIGIN_DIRTYFB);
+
+       return 0;
+}
+
+static const struct drm_framebuffer_funcs intel_fb_funcs = {
+       .destroy = intel_user_framebuffer_destroy,
+       .create_handle = intel_user_framebuffer_create_handle,
+       .dirty = intel_user_framebuffer_dirty,
+};
+
+int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
+                          struct drm_i915_gem_object *obj,
+                          struct drm_mode_fb_cmd2 *mode_cmd)
+{
+       struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
+       struct drm_framebuffer *fb = &intel_fb->base;
+       u32 max_stride;
+       unsigned int tiling, stride;
+       int ret = -EINVAL;
+       int i;
+
+       intel_fb->frontbuffer = intel_frontbuffer_get(obj);
+       if (!intel_fb->frontbuffer)
+               return -ENOMEM;
+
+       i915_gem_object_lock(obj, NULL);
+       tiling = i915_gem_object_get_tiling(obj);
+       stride = i915_gem_object_get_stride(obj);
+       i915_gem_object_unlock(obj);
+
+       if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) {
+               /*
+                * If there's a fence, enforce that
+                * the fb modifier and tiling mode match.
+                */
+               if (tiling != I915_TILING_NONE &&
+                   tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
+                       drm_dbg_kms(&dev_priv->drm,
+                                   "tiling_mode doesn't match fb modifier\n");
+                       goto err;
+               }
+       } else {
+               if (tiling == I915_TILING_X) {
+                       mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED;
+               } else if (tiling == I915_TILING_Y) {
+                       drm_dbg_kms(&dev_priv->drm,
+                                   "No Y tiling for legacy addfb\n");
+                       goto err;
+               }
+       }
+
+       if (!drm_any_plane_has_format(&dev_priv->drm,
+                                     mode_cmd->pixel_format,
+                                     mode_cmd->modifier[0])) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "unsupported pixel format %p4cc / modifier 0x%llx\n",
+                           &mode_cmd->pixel_format, mode_cmd->modifier[0]);
+               goto err;
+       }
+
+       /*
+        * gen2/3 display engine uses the fence if present,
+        * so the tiling mode must match the fb modifier exactly.
+        */
+       if (DISPLAY_VER(dev_priv) < 4 &&
+           tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "tiling_mode must match fb modifier exactly on gen2/3\n");
+               goto err;
+       }
+
+       max_stride = intel_fb_max_stride(dev_priv, mode_cmd->pixel_format,
+                                        mode_cmd->modifier[0]);
+       if (mode_cmd->pitches[0] > max_stride) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "%s pitch (%u) must be at most %d\n",
+                           mode_cmd->modifier[0] != DRM_FORMAT_MOD_LINEAR ?
+                           "tiled" : "linear",
+                           mode_cmd->pitches[0], max_stride);
+               goto err;
+       }
+
+       /*
+        * If there's a fence, enforce that
+        * the fb pitch and fence stride match.
+        */
+       if (tiling != I915_TILING_NONE && mode_cmd->pitches[0] != stride) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "pitch (%d) must match tiling stride (%d)\n",
+                           mode_cmd->pitches[0], stride);
+               goto err;
+       }
+
+       /* FIXME need to adjust LINOFF/TILEOFF accordingly. */
+       if (mode_cmd->offsets[0] != 0) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "plane 0 offset (0x%08x) must be 0\n",
+                           mode_cmd->offsets[0]);
+               goto err;
+       }
+
+       drm_helper_mode_fill_fb_struct(&dev_priv->drm, fb, mode_cmd);
+
+       for (i = 0; i < fb->format->num_planes; i++) {
+               u32 stride_alignment;
+
+               if (mode_cmd->handles[i] != mode_cmd->handles[0]) {
+                       drm_dbg_kms(&dev_priv->drm, "bad plane %d handle\n",
+                                   i);
+                       goto err;
+               }
+
+               stride_alignment = intel_fb_stride_alignment(fb, i);
+               if (fb->pitches[i] & (stride_alignment - 1)) {
+                       drm_dbg_kms(&dev_priv->drm,
+                                   "plane %d pitch (%d) must be at least %u byte aligned\n",
+                                   i, fb->pitches[i], stride_alignment);
+                       goto err;
+               }
+
+               if (is_gen12_ccs_plane(fb, i) && !is_gen12_ccs_cc_plane(fb, i)) {
+                       int ccs_aux_stride = gen12_ccs_aux_stride(fb, i);
+
+                       if (fb->pitches[i] != ccs_aux_stride) {
+                               drm_dbg_kms(&dev_priv->drm,
+                                           "ccs aux plane %d pitch (%d) must be %d\n",
+                                           i,
+                                           fb->pitches[i], ccs_aux_stride);
+                               goto err;
+                       }
+               }
+
+               /* TODO: Add POT stride remapping support for CCS formats as well. */
+               if (IS_ALDERLAKE_P(dev_priv) &&
+                   mode_cmd->modifier[i] != DRM_FORMAT_MOD_LINEAR &&
+                   !intel_fb_needs_pot_stride_remap(intel_fb) &&
+                   !is_power_of_2(mode_cmd->pitches[i])) {
+                       drm_dbg_kms(&dev_priv->drm,
+                                   "plane %d pitch (%d) must be power of two for tiled buffers\n",
+                                   i, mode_cmd->pitches[i]);
+                       goto err;
+               }
+
+               fb->obj[i] = &obj->base;
+       }
+
+       ret = intel_fill_fb_info(dev_priv, intel_fb);
+       if (ret)
+               goto err;
+
+       if (intel_fb_uses_dpt(fb)) {
+               struct i915_address_space *vm;
+
+               vm = intel_dpt_create(intel_fb);
+               if (IS_ERR(vm)) {
+                       ret = PTR_ERR(vm);
+                       goto err;
+               }
+
+               intel_fb->dpt_vm = vm;
+       }
+
+       ret = drm_framebuffer_init(&dev_priv->drm, fb, &intel_fb_funcs);
+       if (ret) {
+               drm_err(&dev_priv->drm, "framebuffer init failed %d\n", ret);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       intel_frontbuffer_put(intel_fb->frontbuffer);
+       return ret;
+}
+
+struct drm_framebuffer *
+intel_user_framebuffer_create(struct drm_device *dev,
+                             struct drm_file *filp,
+                             const struct drm_mode_fb_cmd2 *user_mode_cmd)
+{
+       struct drm_framebuffer *fb;
+       struct drm_i915_gem_object *obj;
+       struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd;
+       struct drm_i915_private *i915;
+
+       obj = i915_gem_object_lookup(filp, mode_cmd.handles[0]);
+       if (!obj)
+               return ERR_PTR(-ENOENT);
+
+       /* object is backed with LMEM for discrete */
+       i915 = to_i915(obj->base.dev);
+       if (HAS_LMEM(i915) && !i915_gem_object_can_migrate(obj, INTEL_REGION_LMEM)) {
+               /* object is "remote", not in local memory */
+               i915_gem_object_put(obj);
+               return ERR_PTR(-EREMOTE);
+       }
+
+       fb = intel_framebuffer_create(obj, &mode_cmd);
+       i915_gem_object_put(obj);
+
+       return fb;
+}
+
+struct drm_framebuffer *
+intel_framebuffer_create(struct drm_i915_gem_object *obj,
+                        struct drm_mode_fb_cmd2 *mode_cmd)
+{
+       struct intel_framebuffer *intel_fb;
+       int ret;
+
+       intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+       if (!intel_fb)
+               return ERR_PTR(-ENOMEM);
+
+       ret = intel_framebuffer_init(intel_fb, obj, mode_cmd);
+       if (ret)
+               goto err;
+
+       return &intel_fb->base;
+
+err:
+       kfree(intel_fb);
+       return ERR_PTR(ret);
+}
index 739d1b91754bd339bf13af421deb4df77f7edbc8..1cbdd84502bddfb0dbfea9911eb2d3ef7a164527 100644 (file)
@@ -8,10 +8,12 @@
 
 #include <linux/types.h>
 
+struct drm_device;
+struct drm_file;
 struct drm_framebuffer;
-
+struct drm_i915_gem_object;
 struct drm_i915_private;
-
+struct drm_mode_fb_cmd2;
 struct intel_fb_view;
 struct intel_framebuffer;
 struct intel_plane_state;
@@ -28,10 +30,14 @@ int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane);
 int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane);
 
 unsigned int intel_tile_size(const struct drm_i915_private *i915);
+unsigned int intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane);
 unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane);
 unsigned int intel_tile_row_size(const struct drm_framebuffer *fb, int color_plane);
-
+unsigned int intel_fb_align_height(const struct drm_framebuffer *fb,
+                                  int color_plane, unsigned int height);
 unsigned int intel_cursor_alignment(const struct drm_i915_private *i915);
+unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
+                                 int color_plane);
 
 void intel_fb_plane_get_subsampling(int *hsub, int *vsub,
                                    const struct drm_framebuffer *fb,
@@ -53,4 +59,12 @@ void intel_fb_fill_view(const struct intel_framebuffer *fb, unsigned int rotatio
                        struct intel_fb_view *view);
 int intel_plane_compute_gtt(struct intel_plane_state *plane_state);
 
+int intel_framebuffer_init(struct intel_framebuffer *ifb,
+                          struct drm_i915_gem_object *obj,
+                          struct drm_mode_fb_cmd2 *mode_cmd);
+struct drm_framebuffer *
+intel_user_framebuffer_create(struct drm_device *dev,
+                             struct drm_file *filp,
+                             const struct drm_mode_fb_cmd2 *user_mode_cmd);
+
 #endif /* __INTEL_FB_H__ */
index ddfc17e21668aebe0efe8fc57d5554ad434182e7..b1c1a23c36be3febc02c01de6b1470dd458f7bc8 100644 (file)
@@ -232,16 +232,16 @@ static void i965_fbc_recompress(struct drm_i915_private *dev_priv)
 /* This function forces a CFB recompression through the nuke operation. */
 static void snb_fbc_recompress(struct drm_i915_private *dev_priv)
 {
-       struct intel_fbc *fbc = &dev_priv->fbc;
-
-       trace_intel_fbc_nuke(fbc->crtc);
-
        intel_de_write(dev_priv, MSG_FBC_REND_STATE, FBC_REND_NUKE);
        intel_de_posting_read(dev_priv, MSG_FBC_REND_STATE);
 }
 
 static void intel_fbc_recompress(struct drm_i915_private *dev_priv)
 {
+       struct intel_fbc *fbc = &dev_priv->fbc;
+
+       trace_intel_fbc_nuke(fbc->crtc);
+
        if (DISPLAY_VER(dev_priv) >= 6)
                snb_fbc_recompress(dev_priv);
        else if (DISPLAY_VER(dev_priv) >= 4)
@@ -280,8 +280,6 @@ static void ilk_fbc_activate(struct drm_i915_private *dev_priv)
                       params->fence_y_offset);
        /* enable it... */
        intel_de_write(dev_priv, ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
-
-       intel_fbc_recompress(dev_priv);
 }
 
 static void ilk_fbc_deactivate(struct drm_i915_private *dev_priv)
@@ -308,14 +306,15 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv)
 
        /* Display WA #0529: skl, kbl, bxt. */
        if (DISPLAY_VER(dev_priv) == 9) {
-               u32 val = intel_de_read(dev_priv, CHICKEN_MISC_4);
+               u32 val = 0;
 
-               val &= ~(FBC_STRIDE_OVERRIDE | FBC_STRIDE_MASK);
+               if (params->override_cfb_stride)
+                       val |= CHICKEN_FBC_STRIDE_OVERRIDE |
+                               CHICKEN_FBC_STRIDE(params->override_cfb_stride);
 
-               if (params->gen9_wa_cfb_stride)
-                       val |= FBC_STRIDE_OVERRIDE | params->gen9_wa_cfb_stride;
-
-               intel_de_write(dev_priv, CHICKEN_MISC_4, val);
+               intel_de_rmw(dev_priv, CHICKEN_MISC_4,
+                            CHICKEN_FBC_STRIDE_OVERRIDE |
+                            CHICKEN_FBC_STRIDE_MASK, val);
        }
 
        dpfc_ctl = 0;
@@ -339,8 +338,6 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv)
                dpfc_ctl |= FBC_CTL_FALSE_COLOR;
 
        intel_de_write(dev_priv, ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
-
-       intel_fbc_recompress(dev_priv);
 }
 
 static bool intel_fbc_hw_is_active(struct drm_i915_private *dev_priv)
@@ -402,6 +399,12 @@ bool intel_fbc_is_active(struct drm_i915_private *dev_priv)
        return dev_priv->fbc.active;
 }
 
+static void intel_fbc_activate(struct drm_i915_private *dev_priv)
+{
+       intel_fbc_hw_activate(dev_priv);
+       intel_fbc_recompress(dev_priv);
+}
+
 static void intel_fbc_deactivate(struct drm_i915_private *dev_priv,
                                 const char *reason)
 {
@@ -675,11 +678,9 @@ static bool tiling_is_valid(struct drm_i915_private *dev_priv,
 {
        switch (modifier) {
        case DRM_FORMAT_MOD_LINEAR:
-               if (DISPLAY_VER(dev_priv) >= 9)
-                       return true;
-               return false;
-       case I915_FORMAT_MOD_X_TILED:
        case I915_FORMAT_MOD_Y_TILED:
+               return DISPLAY_VER(dev_priv) >= 9;
+       case I915_FORMAT_MOD_X_TILED:
                return true;
        default:
                return false;
@@ -749,7 +750,7 @@ static bool intel_fbc_cfb_size_changed(struct drm_i915_private *dev_priv)
                fbc->compressed_fb.size * fbc->limit;
 }
 
-static u16 intel_fbc_gen9_wa_cfb_stride(struct drm_i915_private *dev_priv)
+static u16 intel_fbc_override_cfb_stride(struct drm_i915_private *dev_priv)
 {
        struct intel_fbc *fbc = &dev_priv->fbc;
        struct intel_fbc_state_cache *cache = &fbc->state_cache;
@@ -761,11 +762,11 @@ static u16 intel_fbc_gen9_wa_cfb_stride(struct drm_i915_private *dev_priv)
                return 0;
 }
 
-static bool intel_fbc_gen9_wa_cfb_stride_changed(struct drm_i915_private *dev_priv)
+static bool intel_fbc_override_cfb_stride_changed(struct drm_i915_private *dev_priv)
 {
        struct intel_fbc *fbc = &dev_priv->fbc;
 
-       return fbc->params.gen9_wa_cfb_stride != intel_fbc_gen9_wa_cfb_stride(dev_priv);
+       return fbc->params.override_cfb_stride != intel_fbc_override_cfb_stride(dev_priv);
 }
 
 static bool intel_fbc_can_enable(struct drm_i915_private *dev_priv)
@@ -950,7 +951,7 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc,
 
        params->cfb_size = intel_fbc_calculate_cfb_size(dev_priv, cache);
 
-       params->gen9_wa_cfb_stride = cache->gen9_wa_cfb_stride;
+       params->override_cfb_stride = cache->override_cfb_stride;
 
        params->plane_visible = cache->plane.visible;
 }
@@ -984,7 +985,7 @@ static bool intel_fbc_can_flip_nuke(const struct intel_crtc_state *crtc_state)
        if (params->cfb_size != intel_fbc_calculate_cfb_size(dev_priv, cache))
                return false;
 
-       if (params->gen9_wa_cfb_stride != cache->gen9_wa_cfb_stride)
+       if (params->override_cfb_stride != cache->override_cfb_stride)
                return false;
 
        return true;
@@ -1090,7 +1091,7 @@ static void __intel_fbc_post_update(struct intel_crtc *crtc)
                return;
 
        if (!fbc->busy_bits)
-               intel_fbc_hw_activate(dev_priv);
+               intel_fbc_activate(dev_priv);
        else
                intel_fbc_deactivate(dev_priv, "frontbuffer write");
 }
@@ -1129,7 +1130,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
        if (!HAS_FBC(dev_priv))
                return;
 
-       if (origin == ORIGIN_GTT || origin == ORIGIN_FLIP)
+       if (origin == ORIGIN_FLIP)
                return;
 
        mutex_lock(&fbc->lock);
@@ -1150,14 +1151,6 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv,
        if (!HAS_FBC(dev_priv))
                return;
 
-       /*
-        * GTT tracking does not nuke the entire cfb
-        * so don't clear busy_bits set for some other
-        * reason.
-        */
-       if (origin == ORIGIN_GTT)
-               return;
-
        mutex_lock(&fbc->lock);
 
        fbc->busy_bits &= ~frontbuffer_bits;
@@ -1246,8 +1239,8 @@ out:
  * intel_fbc_enable multiple times for the same pipe without an
  * intel_fbc_disable in the middle, as long as it is deactivated.
  */
-void intel_fbc_enable(struct intel_atomic_state *state,
-                     struct intel_crtc *crtc)
+static void intel_fbc_enable(struct intel_atomic_state *state,
+                            struct intel_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        struct intel_plane *plane = to_intel_plane(crtc->base.primary);
@@ -1266,7 +1259,7 @@ void intel_fbc_enable(struct intel_atomic_state *state,
        if (fbc->crtc) {
                if (fbc->crtc != crtc ||
                    (!intel_fbc_cfb_size_changed(dev_priv) &&
-                    !intel_fbc_gen9_wa_cfb_stride_changed(dev_priv)))
+                    !intel_fbc_override_cfb_stride_changed(dev_priv)))
                        goto out;
 
                __intel_fbc_disable(dev_priv);
@@ -1288,7 +1281,7 @@ void intel_fbc_enable(struct intel_atomic_state *state,
                goto out;
        }
 
-       cache->gen9_wa_cfb_stride = intel_fbc_gen9_wa_cfb_stride(dev_priv);
+       cache->override_cfb_stride = intel_fbc_override_cfb_stride(dev_priv);
 
        drm_dbg_kms(&dev_priv->drm, "Enabling FBC on pipe %c\n",
                    pipe_name(crtc->pipe));
@@ -1322,6 +1315,28 @@ void intel_fbc_disable(struct intel_crtc *crtc)
        mutex_unlock(&fbc->lock);
 }
 
+/**
+ * intel_fbc_update: enable/disable FBC on the CRTC
+ * @state: atomic state
+ * @crtc: the CRTC
+ *
+ * This function checks if the given CRTC was chosen for FBC, then enables it if
+ * possible. Notice that it doesn't activate FBC. It is valid to call
+ * intel_fbc_update multiple times for the same pipe without an
+ * intel_fbc_disable in the middle.
+ */
+void intel_fbc_update(struct intel_atomic_state *state,
+                     struct intel_crtc *crtc)
+{
+       const struct intel_crtc_state *crtc_state =
+               intel_atomic_get_new_crtc_state(state, crtc);
+
+       if (crtc_state->update_pipe && !crtc_state->enable_fbc)
+               intel_fbc_disable(crtc);
+       else
+               intel_fbc_enable(state, crtc);
+}
+
 /**
  * intel_fbc_global_disable - globally disable FBC
  * @dev_priv: i915 device instance
index 6dc1edefe81be51ddbc0a891df35ef6845e06409..b97d908738e6216cfc452a3e3beb38ef400c8aee 100644 (file)
@@ -24,7 +24,7 @@ bool intel_fbc_pre_update(struct intel_atomic_state *state,
 void intel_fbc_post_update(struct intel_atomic_state *state,
                           struct intel_crtc *crtc);
 void intel_fbc_init(struct drm_i915_private *dev_priv);
-void intel_fbc_enable(struct intel_atomic_state *state,
+void intel_fbc_update(struct intel_atomic_state *state,
                      struct intel_crtc *crtc);
 void intel_fbc_disable(struct intel_crtc *crtc);
 void intel_fbc_global_disable(struct drm_i915_private *dev_priv);
index df05d285f0bd4984caf44e6ffd3d76c6e2aa5f46..60d3ded27047653a6e6b774eddc3e29d76cf85d4 100644 (file)
@@ -45,6 +45,7 @@
 
 #include "i915_drv.h"
 #include "intel_display_types.h"
+#include "intel_fb.h"
 #include "intel_fbdev.h"
 #include "intel_frontbuffer.h"
 
index e10b9cd8e86eb8ed312362384252193929709f2a..fc09b781f15faa585efbc86928f91d63bee6cd61 100644 (file)
@@ -2,11 +2,13 @@
 /*
  * Copyright Â© 2020 Intel Corporation
  */
+
 #include "intel_atomic.h"
 #include "intel_ddi.h"
 #include "intel_de.h"
 #include "intel_display_types.h"
 #include "intel_fdi.h"
+#include "intel_sideband.h"
 
 /* units of 100MHz */
 static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
@@ -91,8 +93,34 @@ static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
                }
                return 0;
        default:
-               BUG();
+               MISSING_CASE(pipe);
+               return 0;
+       }
+}
+
+void intel_fdi_pll_freq_update(struct drm_i915_private *i915)
+{
+       if (IS_IRONLAKE(i915)) {
+               u32 fdi_pll_clk =
+                       intel_de_read(i915, FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK;
+
+               i915->fdi_pll_freq = (fdi_pll_clk + 2) * 10000;
+       } else if (IS_SANDYBRIDGE(i915) || IS_IVYBRIDGE(i915)) {
+               i915->fdi_pll_freq = 270000;
+       } else {
+               return;
        }
+
+       drm_dbg(&i915->drm, "FDI PLL freq=%d\n", i915->fdi_pll_freq);
+}
+
+int intel_fdi_link_freq(struct drm_i915_private *i915,
+                       const struct intel_crtc_state *pipe_config)
+{
+       if (HAS_DDI(i915))
+               return pipe_config->port_clock; /* SPLL */
+       else
+               return i915->fdi_pll_freq;
 }
 
 int ilk_fdi_compute_config(struct intel_crtc *crtc,
@@ -145,6 +173,55 @@ retry:
        return ret;
 }
 
+static void cpt_set_fdi_bc_bifurcation(struct drm_i915_private *dev_priv, bool enable)
+{
+       u32 temp;
+
+       temp = intel_de_read(dev_priv, SOUTH_CHICKEN1);
+       if (!!(temp & FDI_BC_BIFURCATION_SELECT) == enable)
+               return;
+
+       drm_WARN_ON(&dev_priv->drm,
+                   intel_de_read(dev_priv, FDI_RX_CTL(PIPE_B)) &
+                   FDI_RX_ENABLE);
+       drm_WARN_ON(&dev_priv->drm,
+                   intel_de_read(dev_priv, FDI_RX_CTL(PIPE_C)) &
+                   FDI_RX_ENABLE);
+
+       temp &= ~FDI_BC_BIFURCATION_SELECT;
+       if (enable)
+               temp |= FDI_BC_BIFURCATION_SELECT;
+
+       drm_dbg_kms(&dev_priv->drm, "%sabling fdi C rx\n",
+                   enable ? "en" : "dis");
+       intel_de_write(dev_priv, SOUTH_CHICKEN1, temp);
+       intel_de_posting_read(dev_priv, SOUTH_CHICKEN1);
+}
+
+static void ivb_update_fdi_bc_bifurcation(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+
+       switch (crtc->pipe) {
+       case PIPE_A:
+               break;
+       case PIPE_B:
+               if (crtc_state->fdi_lanes > 2)
+                       cpt_set_fdi_bc_bifurcation(dev_priv, false);
+               else
+                       cpt_set_fdi_bc_bifurcation(dev_priv, true);
+
+               break;
+       case PIPE_C:
+               cpt_set_fdi_bc_bifurcation(dev_priv, true);
+
+               break;
+       default:
+               MISSING_CASE(crtc->pipe);
+       }
+}
+
 void intel_fdi_normal_train(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
@@ -196,6 +273,13 @@ static void ilk_fdi_link_train(struct intel_crtc *crtc,
        i915_reg_t reg;
        u32 temp, tries;
 
+       /*
+        * Write the TU size bits before fdi link training, so that error
+        * detection works.
+        */
+       intel_de_write(dev_priv, FDI_RX_TUSIZE1(pipe),
+                      intel_de_read(dev_priv, PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
+
        /* FDI needs bits from pipe first */
        assert_pipe_enabled(dev_priv, crtc_state->cpu_transcoder);
 
@@ -299,6 +383,13 @@ static void gen6_fdi_link_train(struct intel_crtc *crtc,
        i915_reg_t reg;
        u32 temp, i, retry;
 
+       /*
+        * Write the TU size bits before fdi link training, so that error
+        * detection works.
+        */
+       intel_de_write(dev_priv, FDI_RX_TUSIZE1(pipe),
+                      intel_de_read(dev_priv, PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
+
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
        reg = FDI_RX_IMR(pipe);
@@ -436,6 +527,15 @@ static void ivb_manual_fdi_link_train(struct intel_crtc *crtc,
        i915_reg_t reg;
        u32 temp, i, j;
 
+       ivb_update_fdi_bc_bifurcation(crtc_state);
+
+       /*
+        * Write the TU size bits before fdi link training, so that error
+        * detection works.
+        */
+       intel_de_write(dev_priv, FDI_RX_TUSIZE1(pipe),
+                      intel_de_read(dev_priv, PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
+
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
        reg = FDI_RX_IMR(pipe);
@@ -807,6 +907,104 @@ void ilk_fdi_disable(struct intel_crtc *crtc)
        udelay(100);
 }
 
+static void lpt_fdi_reset_mphy(struct drm_i915_private *dev_priv)
+{
+       u32 tmp;
+
+       tmp = intel_de_read(dev_priv, SOUTH_CHICKEN2);
+       tmp |= FDI_MPHY_IOSFSB_RESET_CTL;
+       intel_de_write(dev_priv, SOUTH_CHICKEN2, tmp);
+
+       if (wait_for_us(intel_de_read(dev_priv, SOUTH_CHICKEN2) &
+                       FDI_MPHY_IOSFSB_RESET_STATUS, 100))
+               drm_err(&dev_priv->drm, "FDI mPHY reset assert timeout\n");
+
+       tmp = intel_de_read(dev_priv, SOUTH_CHICKEN2);
+       tmp &= ~FDI_MPHY_IOSFSB_RESET_CTL;
+       intel_de_write(dev_priv, SOUTH_CHICKEN2, tmp);
+
+       if (wait_for_us((intel_de_read(dev_priv, SOUTH_CHICKEN2) &
+                        FDI_MPHY_IOSFSB_RESET_STATUS) == 0, 100))
+               drm_err(&dev_priv->drm, "FDI mPHY reset de-assert timeout\n");
+}
+
+/* WaMPhyProgramming:hsw */
+void lpt_fdi_program_mphy(struct drm_i915_private *dev_priv)
+{
+       u32 tmp;
+
+       lpt_fdi_reset_mphy(dev_priv);
+
+       tmp = intel_sbi_read(dev_priv, 0x8008, SBI_MPHY);
+       tmp &= ~(0xFF << 24);
+       tmp |= (0x12 << 24);
+       intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x2008, SBI_MPHY);
+       tmp |= (1 << 11);
+       intel_sbi_write(dev_priv, 0x2008, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x2108, SBI_MPHY);
+       tmp |= (1 << 11);
+       intel_sbi_write(dev_priv, 0x2108, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x206C, SBI_MPHY);
+       tmp |= (1 << 24) | (1 << 21) | (1 << 18);
+       intel_sbi_write(dev_priv, 0x206C, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x216C, SBI_MPHY);
+       tmp |= (1 << 24) | (1 << 21) | (1 << 18);
+       intel_sbi_write(dev_priv, 0x216C, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY);
+       tmp &= ~(7 << 13);
+       tmp |= (5 << 13);
+       intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY);
+       tmp &= ~(7 << 13);
+       tmp |= (5 << 13);
+       intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x208C, SBI_MPHY);
+       tmp &= ~0xFF;
+       tmp |= 0x1C;
+       intel_sbi_write(dev_priv, 0x208C, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x218C, SBI_MPHY);
+       tmp &= ~0xFF;
+       tmp |= 0x1C;
+       intel_sbi_write(dev_priv, 0x218C, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x2098, SBI_MPHY);
+       tmp &= ~(0xFF << 16);
+       tmp |= (0x1C << 16);
+       intel_sbi_write(dev_priv, 0x2098, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x2198, SBI_MPHY);
+       tmp &= ~(0xFF << 16);
+       tmp |= (0x1C << 16);
+       intel_sbi_write(dev_priv, 0x2198, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY);
+       tmp |= (1 << 27);
+       intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY);
+       tmp |= (1 << 27);
+       intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY);
+       tmp &= ~(0xF << 28);
+       tmp |= (4 << 28);
+       intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY);
+       tmp &= ~(0xF << 28);
+       tmp |= (4 << 28);
+       intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY);
+}
+
 void
 intel_fdi_init_hook(struct drm_i915_private *dev_priv)
 {
index af01d2c173a8213103a22cd7605504cd11aa5f32..60acf213314539fe16c668a227786c1536b18b1e 100644 (file)
@@ -12,6 +12,8 @@ struct intel_crtc_state;
 struct intel_encoder;
 
 #define I915_DISPLAY_CONFIG_RETRY 1
+int intel_fdi_link_freq(struct drm_i915_private *i915,
+                       const struct intel_crtc_state *pipe_config);
 int ilk_fdi_compute_config(struct intel_crtc *intel_crtc,
                           struct intel_crtc_state *pipe_config);
 void intel_fdi_normal_train(struct intel_crtc *crtc);
@@ -21,5 +23,7 @@ void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state);
 void intel_fdi_init_hook(struct drm_i915_private *dev_priv);
 void hsw_fdi_link_train(struct intel_encoder *encoder,
                        const struct intel_crtc_state *crtc_state);
+void intel_fdi_pll_freq_update(struct drm_i915_private *i915);
+void lpt_fdi_program_mphy(struct drm_i915_private *i915);
 
 #endif
index 8e75debcce1a9360497065d5d537cab791c77ede..0492446cd04add9df8e1a1e0ab6b657196263256 100644 (file)
@@ -62,6 +62,7 @@
 #include "intel_display_types.h"
 #include "intel_fbc.h"
 #include "intel_frontbuffer.h"
+#include "intel_drrs.h"
 #include "intel_psr.h"
 
 /**
@@ -91,7 +92,7 @@ static void frontbuffer_flush(struct drm_i915_private *i915,
        trace_intel_frontbuffer_flush(frontbuffer_bits, origin);
 
        might_sleep();
-       intel_edp_drrs_flush(i915, frontbuffer_bits);
+       intel_drrs_flush(i915, frontbuffer_bits);
        intel_psr_flush(i915, frontbuffer_bits, origin);
        intel_fbc_flush(i915, frontbuffer_bits, origin);
 }
@@ -180,7 +181,7 @@ void __intel_fb_invalidate(struct intel_frontbuffer *front,
 
        might_sleep();
        intel_psr_invalidate(i915, frontbuffer_bits, origin);
-       intel_edp_drrs_invalidate(i915, frontbuffer_bits);
+       intel_drrs_invalidate(i915, frontbuffer_bits);
        intel_fbc_invalidate(i915, frontbuffer_bits, origin);
 }
 
index 6d41f539442508b373bed76d584ca08657cddcec..4b977c1e4d52b683c9d385a7545dc22bfd66fb92 100644 (file)
@@ -33,8 +33,7 @@
 struct drm_i915_private;
 
 enum fb_op_origin {
-       ORIGIN_GTT,
-       ORIGIN_CPU,
+       ORIGIN_CPU = 0,
        ORIGIN_CS,
        ORIGIN_FLIP,
        ORIGIN_DIRTYFB,
index ebc2e32aec0bc4b4b0ef387ce1f123bd07314243..9b9fd9d13043370da4cfeac6c7f539113c14c9ac 100644 (file)
@@ -33,21 +33,6 @@ static int intel_conn_to_vcpi(struct intel_connector *connector)
        return connector->port  ? connector->port->vcpi.vcpi : 0;
 }
 
-static bool
-intel_streams_type1_capable(struct intel_connector *connector)
-{
-       const struct intel_hdcp_shim *shim = connector->hdcp.shim;
-       bool capable = false;
-
-       if (!shim)
-               return capable;
-
-       if (shim->streams_type1_capable)
-               shim->streams_type1_capable(connector, &capable);
-
-       return capable;
-}
-
 /*
  * intel_hdcp_required_content_stream selects the most highest common possible HDCP
  * content_type for all streams in DP MST topology because security f/w doesn't
@@ -86,7 +71,7 @@ intel_hdcp_required_content_stream(struct intel_digital_port *dig_port)
                if (conn_dig_port != dig_port)
                        continue;
 
-               if (!enforce_type0 && !intel_streams_type1_capable(connector))
+               if (!enforce_type0 && !dig_port->hdcp_mst_type1_capable)
                        enforce_type0 = true;
 
                data->streams[data->k].stream_id = intel_conn_to_vcpi(connector);
@@ -112,6 +97,25 @@ intel_hdcp_required_content_stream(struct intel_digital_port *dig_port)
        return 0;
 }
 
+static int intel_hdcp_prepare_streams(struct intel_connector *connector)
+{
+       struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
+       struct hdcp_port_data *data = &dig_port->hdcp_port_data;
+       struct intel_hdcp *hdcp = &connector->hdcp;
+       int ret;
+
+       if (!intel_encoder_is_mst(intel_attached_encoder(connector))) {
+               data->k = 1;
+               data->streams[0].stream_type = hdcp->content_type;
+       } else {
+               ret = intel_hdcp_required_content_stream(dig_port);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static
 bool intel_hdcp_is_ksv_valid(u8 *ksv)
 {
@@ -1632,6 +1636,14 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector)
                return -EINVAL;
        }
 
+       /*
+        * MST topology is not Type 1 capable if it contains a downstream
+        * device that is only HDCP 1.x or Legacy HDCP 2.0/2.1 compliant.
+        */
+       dig_port->hdcp_mst_type1_capable =
+               !HDCP_2_2_HDCP1_DEVICE_CONNECTED(rx_info[1]) &&
+               !HDCP_2_2_HDCP_2_0_REP_CONNECTED(rx_info[1]);
+
        /* Converting and Storing the seq_num_v to local variable as DWORD */
        seq_num_v =
                drm_hdcp_be24_to_cpu((const u8 *)msgs.recvid_list.seq_num_v);
@@ -1876,6 +1888,14 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
        for (i = 0; i < tries && !dig_port->hdcp_auth_status; i++) {
                ret = hdcp2_authenticate_sink(connector);
                if (!ret) {
+                       ret = intel_hdcp_prepare_streams(connector);
+                       if (ret) {
+                               drm_dbg_kms(&i915->drm,
+                                           "Prepare streams failed.(%d)\n",
+                                           ret);
+                               break;
+                       }
+
                        ret = hdcp2_propagate_stream_management_info(connector);
                        if (ret) {
                                drm_dbg_kms(&i915->drm,
@@ -1921,9 +1941,7 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
 
 static int _intel_hdcp2_enable(struct intel_connector *connector)
 {
-       struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct drm_i915_private *i915 = to_i915(connector->base.dev);
-       struct hdcp_port_data *data = &dig_port->hdcp_port_data;
        struct intel_hdcp *hdcp = &connector->hdcp;
        int ret;
 
@@ -1931,16 +1949,6 @@ static int _intel_hdcp2_enable(struct intel_connector *connector)
                    connector->base.name, connector->base.base.id,
                    hdcp->content_type);
 
-       /* Stream which requires encryption */
-       if (!intel_encoder_is_mst(intel_attached_encoder(connector))) {
-               data->k = 1;
-               data->streams[0].stream_type = hdcp->content_type;
-       } else {
-               ret = intel_hdcp_required_content_stream(dig_port);
-               if (ret)
-                       return ret;
-       }
-
        ret = hdcp2_authenticate_and_encrypt(connector);
        if (ret) {
                drm_dbg_kms(&i915->drm, "HDCP2 Type%d  Enabling Failed. (%d)\n",
index b04685bb6439cf4c9b049114b4b0d2834de47883..1bc33766ed39b2b68fba925bdf6acd160928e965 100644 (file)
@@ -2210,7 +2210,7 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
                return ret;
 
        if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
-               ret = intel_pch_panel_fitting(pipe_config, conn_state);
+               ret = intel_panel_fitting(pipe_config, conn_state);
                if (ret)
                        return ret;
        }
index e0381b0fce9142a988ab8bc0eba3f4d9b44a1aba..e9fb402708a7bfe2c59086cf59d54815d18e1388 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "i915_drv.h"
 #include "intel_atomic.h"
+#include "intel_backlight.h"
 #include "intel_connector.h"
 #include "intel_de.h"
 #include "intel_display_types.h"
@@ -323,7 +324,7 @@ static void intel_enable_lvds(struct intel_atomic_state *state,
                drm_err(&dev_priv->drm,
                        "timed out waiting for panel to power on\n");
 
-       intel_panel_enable_backlight(pipe_config, conn_state);
+       intel_backlight_enable(pipe_config, conn_state);
 }
 
 static void intel_disable_lvds(struct intel_atomic_state *state,
@@ -351,7 +352,7 @@ static void gmch_disable_lvds(struct intel_atomic_state *state,
                              const struct drm_connector_state *old_conn_state)
 
 {
-       intel_panel_disable_backlight(old_conn_state);
+       intel_backlight_disable(old_conn_state);
 
        intel_disable_lvds(state, encoder, old_crtc_state, old_conn_state);
 }
@@ -361,7 +362,7 @@ static void pch_disable_lvds(struct intel_atomic_state *state,
                             const struct intel_crtc_state *old_crtc_state,
                             const struct drm_connector_state *old_conn_state)
 {
-       intel_panel_disable_backlight(old_conn_state);
+       intel_backlight_disable(old_conn_state);
 }
 
 static void pch_post_disable_lvds(struct intel_atomic_state *state,
@@ -441,7 +442,7 @@ static int intel_lvds_compute_config(struct intel_encoder *intel_encoder,
         * with the panel scaling set up to source from the H/VDisplay
         * of the original mode.
         */
-       intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
+       intel_panel_fixed_mode(intel_connector->panel.fixed_mode,
                               adjusted_mode);
 
        if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
@@ -450,10 +451,7 @@ static int intel_lvds_compute_config(struct intel_encoder *intel_encoder,
        if (HAS_PCH_SPLIT(dev_priv))
                pipe_config->has_pch_encoder = true;
 
-       if (HAS_GMCH(dev_priv))
-               ret = intel_gmch_panel_fitting(pipe_config, conn_state);
-       else
-               ret = intel_pch_panel_fitting(pipe_config, conn_state);
+       ret = intel_panel_fitting(pipe_config, conn_state);
        if (ret)
                return ret;
 
@@ -906,7 +904,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
        }
        intel_encoder->get_hw_state = intel_lvds_get_hw_state;
        intel_encoder->get_config = intel_lvds_get_config;
-       intel_encoder->update_pipe = intel_panel_update_backlight;
+       intel_encoder->update_pipe = intel_backlight_update;
        intel_encoder->shutdown = intel_lvds_shutdown;
        intel_connector->get_hw_state = intel_connector_get_hw_state;
 
@@ -999,7 +997,7 @@ out:
        mutex_unlock(&dev->mode_config.mutex);
 
        intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
-       intel_panel_setup_backlight(connector, INVALID_PIPE);
+       intel_backlight_setup(intel_connector, INVALID_PIPE);
 
        lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder);
        drm_dbg_kms(&dev_priv->drm, "detected %s-link lvds configuration\n",
index 3855fba709807727d4b019e313e17d76d97f9d10..0065111593a6029e4d4169eb5c822632fff52522 100644 (file)
 #include <linux/firmware.h>
 #include <acpi/video.h>
 
-#include "display/intel_panel.h"
-
 #include "i915_drv.h"
 #include "intel_acpi.h"
+#include "intel_backlight.h"
 #include "intel_display_types.h"
 #include "intel_opregion.h"
 
@@ -450,7 +449,7 @@ static u32 asle_set_backlight(struct drm_i915_private *dev_priv, u32 bclp)
                    bclp);
        drm_connector_list_iter_begin(dev, &conn_iter);
        for_each_intel_connector_iter(connector, &conn_iter)
-               intel_panel_set_backlight_acpi(connector->base.state, bclp, 255);
+               intel_backlight_set_acpi(connector->base.state, bclp, 255);
        drm_connector_list_iter_end(&conn_iter);
        asle->cblv = DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID;
 
index 7d7a60b4d2de765192a71e9a3dceae765ca8e0c7..4804b6b86798528ce8c8cd3376135f4918d8c376 100644 (file)
  *      Chris Wilson <chris@chris-wilson.co.uk>
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/kernel.h>
-#include <linux/moduleparam.h>
 #include <linux/pwm.h>
 
+#include "intel_backlight.h"
 #include "intel_connector.h"
 #include "intel_de.h"
 #include "intel_display_types.h"
-#include "intel_dp_aux_backlight.h"
-#include "intel_dsi_dcs_backlight.h"
 #include "intel_panel.h"
 
-void
-intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
-                      struct drm_display_mode *adjusted_mode)
+bool intel_panel_use_ssc(struct drm_i915_private *i915)
+{
+       if (i915->params.panel_use_ssc >= 0)
+               return i915->params.panel_use_ssc != 0;
+       return i915->vbt.lvds_use_ssc
+               && !(i915->quirks & QUIRK_LVDS_SSC_DISABLE);
+}
+
+void intel_panel_fixed_mode(const struct drm_display_mode *fixed_mode,
+                           struct drm_display_mode *adjusted_mode)
 {
        drm_mode_copy(adjusted_mode, fixed_mode);
 
@@ -175,8 +178,8 @@ intel_panel_vbt_fixed_mode(struct intel_connector *connector)
 }
 
 /* adjusted_mode has been preset to be the panel's fixed mode */
-int intel_pch_panel_fitting(struct intel_crtc_state *crtc_state,
-                           const struct drm_connector_state *conn_state)
+static int pch_panel_fitting(struct intel_crtc_state *crtc_state,
+                            const struct drm_connector_state *conn_state)
 {
        const struct drm_display_mode *adjusted_mode =
                &crtc_state->hw.adjusted_mode;
@@ -381,8 +384,8 @@ static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state,
        }
 }
 
-int intel_gmch_panel_fitting(struct intel_crtc_state *crtc_state,
-                            const struct drm_connector_state *conn_state)
+static int gmch_panel_fitting(struct intel_crtc_state *crtc_state,
+                             const struct drm_connector_state *conn_state)
 {
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
@@ -456,1765 +459,16 @@ out:
        return 0;
 }
 
-/**
- * scale - scale values from one range to another
- * @source_val: value in range [@source_min..@source_max]
- * @source_min: minimum legal value for @source_val
- * @source_max: maximum legal value for @source_val
- * @target_min: corresponding target value for @source_min
- * @target_max: corresponding target value for @source_max
- *
- * Return @source_val in range [@source_min..@source_max] scaled to range
- * [@target_min..@target_max].
- */
-static u32 scale(u32 source_val,
-                u32 source_min, u32 source_max,
-                u32 target_min, u32 target_max)
-{
-       u64 target_val;
-
-       WARN_ON(source_min > source_max);
-       WARN_ON(target_min > target_max);
-
-       /* defensive */
-       source_val = clamp(source_val, source_min, source_max);
-
-       /* avoid overflows */
-       target_val = mul_u32_u32(source_val - source_min,
-                                target_max - target_min);
-       target_val = DIV_ROUND_CLOSEST_ULL(target_val, source_max - source_min);
-       target_val += target_min;
-
-       return target_val;
-}
-
-/* Scale user_level in range [0..user_max] to [0..hw_max], clamping the result
- * to [hw_min..hw_max]. */
-static u32 clamp_user_to_hw(struct intel_connector *connector,
-                           u32 user_level, u32 user_max)
-{
-       struct intel_panel *panel = &connector->panel;
-       u32 hw_level;
-
-       hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max);
-       hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max);
-
-       return hw_level;
-}
-
-/* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */
-static u32 scale_hw_to_user(struct intel_connector *connector,
-                           u32 hw_level, u32 user_max)
-{
-       struct intel_panel *panel = &connector->panel;
-
-       return scale(hw_level, panel->backlight.min, panel->backlight.max,
-                    0, user_max);
-}
-
-u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 val)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0);
-
-       if (dev_priv->params.invert_brightness < 0)
-               return val;
-
-       if (dev_priv->params.invert_brightness > 0 ||
-           dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
-               return panel->backlight.pwm_level_max - val + panel->backlight.pwm_level_min;
-       }
-
-       return val;
-}
-
-void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 val)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *i915 = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       drm_dbg_kms(&i915->drm, "set backlight PWM = %d\n", val);
-       panel->backlight.pwm_funcs->set(conn_state, val);
-}
-
-u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 val)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       drm_WARN_ON_ONCE(&dev_priv->drm,
-                        panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0);
-
-       val = scale(val, panel->backlight.min, panel->backlight.max,
-                   panel->backlight.pwm_level_min, panel->backlight.pwm_level_max);
-
-       return intel_panel_invert_pwm_level(connector, val);
-}
-
-u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       drm_WARN_ON_ONCE(&dev_priv->drm,
-                        panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0);
-
-       if (dev_priv->params.invert_brightness > 0 ||
-           (dev_priv->params.invert_brightness == 0 && dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS))
-               val = panel->backlight.pwm_level_max - (val - panel->backlight.pwm_level_min);
-
-       return scale(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max,
-                    panel->backlight.min, panel->backlight.max);
-}
-
-static u32 lpt_get_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       return intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
-}
-
-static u32 pch_get_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       return intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
-}
-
-static u32 i9xx_get_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 val;
-
-       val = intel_de_read(dev_priv, BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
-       if (DISPLAY_VER(dev_priv) < 4)
-               val >>= 1;
-
-       if (panel->backlight.combination_mode) {
-               u8 lbpc;
-
-               pci_read_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, &lbpc);
-               val *= lbpc;
-       }
-
-       return val;
-}
-
-static u32 vlv_get_backlight(struct intel_connector *connector, enum pipe pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B))
-               return 0;
-
-       return intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK;
-}
-
-static u32 bxt_get_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       return intel_de_read(dev_priv,
-                            BXT_BLC_PWM_DUTY(panel->backlight.controller));
-}
-
-static u32 ext_pwm_get_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct intel_panel *panel = &connector->panel;
-       struct pwm_state state;
-
-       pwm_get_state(panel->backlight.pwm, &state);
-       return pwm_get_relative_duty_cycle(&state, 100);
-}
-
-static void lpt_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       u32 val = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-       intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, val | level);
-}
-
-static void pch_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       u32 tmp;
-
-       tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-       intel_de_write(dev_priv, BLC_PWM_CPU_CTL, tmp | level);
-}
-
-static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 tmp, mask;
-
-       drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0);
-
-       if (panel->backlight.combination_mode) {
-               u8 lbpc;
-
-               lbpc = level * 0xfe / panel->backlight.pwm_level_max + 1;
-               level /= lbpc;
-               pci_write_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, lbpc);
-       }
-
-       if (DISPLAY_VER(dev_priv) == 4) {
-               mask = BACKLIGHT_DUTY_CYCLE_MASK;
-       } else {
-               level <<= 1;
-               mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV;
-       }
-
-       tmp = intel_de_read(dev_priv, BLC_PWM_CTL) & ~mask;
-       intel_de_write(dev_priv, BLC_PWM_CTL, tmp | level);
-}
-
-static void vlv_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe;
-       u32 tmp;
-
-       tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-       intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), tmp | level);
-}
-
-static void bxt_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       intel_de_write(dev_priv,
-                      BXT_BLC_PWM_DUTY(panel->backlight.controller), level);
-}
-
-static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;
-
-       pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
-       pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
-}
-
-static void
-intel_panel_actually_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *i915 = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       drm_dbg_kms(&i915->drm, "set backlight level = %d\n", level);
-
-       panel->backlight.funcs->set(conn_state, level);
-}
-
-/* set backlight brightness to level in range [0..max], assuming hw min is
- * respected.
- */
-void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state,
-                                   u32 user_level, u32 user_max)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 hw_level;
-
-       /*
-        * Lack of crtc may occur during driver init because
-        * connection_mutex isn't held across the entire backlight
-        * setup + modeset readout, and the BIOS can issue the
-        * requests at any time.
-        */
-       if (!panel->backlight.present || !conn_state->crtc)
-               return;
-
-       mutex_lock(&dev_priv->backlight_lock);
-
-       drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0);
-
-       hw_level = clamp_user_to_hw(connector, user_level, user_max);
-       panel->backlight.level = hw_level;
-
-       if (panel->backlight.device)
-               panel->backlight.device->props.brightness =
-                       scale_hw_to_user(connector,
-                                        panel->backlight.level,
-                                        panel->backlight.device->props.max_brightness);
-
-       if (panel->backlight.enabled)
-               intel_panel_actually_set_backlight(conn_state, hw_level);
-
-       mutex_unlock(&dev_priv->backlight_lock);
-}
-
-static void lpt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       u32 tmp;
-
-       intel_panel_set_pwm_level(old_conn_state, level);
-
-       /*
-        * Although we don't support or enable CPU PWM with LPT/SPT based
-        * systems, it may have been enabled prior to loading the
-        * driver. Disable to avoid warnings on LCPLL disable.
-        *
-        * This needs rework if we need to add support for CPU PWM on PCH split
-        * platforms.
-        */
-       tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
-       if (tmp & BLM_PWM_ENABLE) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "cpu backlight was enabled, disabling\n");
-               intel_de_write(dev_priv, BLC_PWM_CPU_CTL2,
-                              tmp & ~BLM_PWM_ENABLE);
-       }
-
-       tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
-       intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
-}
-
-static void pch_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
-{
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       u32 tmp;
-
-       intel_panel_set_pwm_level(old_conn_state, val);
-
-       tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
-       intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
-
-       tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
-       intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
-}
-
-static void i9xx_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
-{
-       intel_panel_set_pwm_level(old_conn_state, val);
-}
-
-static void i965_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
-{
-       struct drm_i915_private *dev_priv = to_i915(old_conn_state->connector->dev);
-       u32 tmp;
-
-       intel_panel_set_pwm_level(old_conn_state, val);
-
-       tmp = intel_de_read(dev_priv, BLC_PWM_CTL2);
-       intel_de_write(dev_priv, BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE);
-}
-
-static void vlv_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
-{
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       enum pipe pipe = to_intel_crtc(old_conn_state->crtc)->pipe;
-       u32 tmp;
-
-       intel_panel_set_pwm_level(old_conn_state, val);
-
-       tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
-       intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe),
-                      tmp & ~BLM_PWM_ENABLE);
-}
-
-static void bxt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
-{
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 tmp;
-
-       intel_panel_set_pwm_level(old_conn_state, val);
-
-       tmp = intel_de_read(dev_priv,
-                           BXT_BLC_PWM_CTL(panel->backlight.controller));
-       intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
-                      tmp & ~BXT_BLC_PWM_ENABLE);
-
-       if (panel->backlight.controller == 1) {
-               val = intel_de_read(dev_priv, UTIL_PIN_CTL);
-               val &= ~UTIL_PIN_ENABLE;
-               intel_de_write(dev_priv, UTIL_PIN_CTL, val);
-       }
-}
-
-static void cnp_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
-{
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 tmp;
-
-       intel_panel_set_pwm_level(old_conn_state, val);
-
-       tmp = intel_de_read(dev_priv,
-                           BXT_BLC_PWM_CTL(panel->backlight.controller));
-       intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
-                      tmp & ~BXT_BLC_PWM_ENABLE);
-}
-
-static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct intel_panel *panel = &connector->panel;
-
-       panel->backlight.pwm_state.enabled = false;
-       pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
-}
-
-void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state)
+int intel_panel_fitting(struct intel_crtc_state *crtc_state,
+                       const struct drm_connector_state *conn_state)
 {
-       struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       if (!panel->backlight.present)
-               return;
-
-       /*
-        * Do not disable backlight on the vga_switcheroo path. When switching
-        * away from i915, the other client may depend on i915 to handle the
-        * backlight. This will leave the backlight on unnecessarily when
-        * another client is not activated.
-        */
-       if (dev_priv->drm.switch_power_state == DRM_SWITCH_POWER_CHANGING) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "Skipping backlight disable on vga switch\n");
-               return;
-       }
-
-       mutex_lock(&dev_priv->backlight_lock);
-
-       if (panel->backlight.device)
-               panel->backlight.device->props.power = FB_BLANK_POWERDOWN;
-       panel->backlight.enabled = false;
-       panel->backlight.funcs->disable(old_conn_state, 0);
-
-       mutex_unlock(&dev_priv->backlight_lock);
-}
-
-static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 pch_ctl1, pch_ctl2, schicken;
-
-       pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
-       if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
-               drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n");
-               pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
-               intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1);
-       }
-
-       if (HAS_PCH_LPT(dev_priv)) {
-               schicken = intel_de_read(dev_priv, SOUTH_CHICKEN2);
-               if (panel->backlight.alternate_pwm_increment)
-                       schicken |= LPT_PWM_GRANULARITY;
-               else
-                       schicken &= ~LPT_PWM_GRANULARITY;
-               intel_de_write(dev_priv, SOUTH_CHICKEN2, schicken);
-       } else {
-               schicken = intel_de_read(dev_priv, SOUTH_CHICKEN1);
-               if (panel->backlight.alternate_pwm_increment)
-                       schicken |= SPT_PWM_GRANULARITY;
-               else
-                       schicken &= ~SPT_PWM_GRANULARITY;
-               intel_de_write(dev_priv, SOUTH_CHICKEN1, schicken);
-       }
-
-       pch_ctl2 = panel->backlight.pwm_level_max << 16;
-       intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2);
-
-       pch_ctl1 = 0;
-       if (panel->backlight.active_low_pwm)
-               pch_ctl1 |= BLM_PCH_POLARITY;
-
-       /* After LPT, override is the default. */
-       if (HAS_PCH_LPT(dev_priv))
-               pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE;
-
-       intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1);
-       intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1);
-       intel_de_write(dev_priv, BLC_PWM_PCH_CTL1,
-                      pch_ctl1 | BLM_PCH_PWM_ENABLE);
-
-       /* This won't stick until the above enable. */
-       intel_panel_set_pwm_level(conn_state, level);
-}
-
-static void pch_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-       u32 cpu_ctl2, pch_ctl1, pch_ctl2;
-
-       cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
-       if (cpu_ctl2 & BLM_PWM_ENABLE) {
-               drm_dbg_kms(&dev_priv->drm, "cpu backlight already enabled\n");
-               cpu_ctl2 &= ~BLM_PWM_ENABLE;
-               intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2);
-       }
-
-       pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
-       if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
-               drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n");
-               pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
-               intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1);
-       }
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
 
-       if (cpu_transcoder == TRANSCODER_EDP)
-               cpu_ctl2 = BLM_TRANSCODER_EDP;
+       if (HAS_GMCH(i915))
+               return gmch_panel_fitting(crtc_state, conn_state);
        else
-               cpu_ctl2 = BLM_PIPE(cpu_transcoder);
-       intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2);
-       intel_de_posting_read(dev_priv, BLC_PWM_CPU_CTL2);
-       intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
-
-       /* This won't stick until the above enable. */
-       intel_panel_set_pwm_level(conn_state, level);
-
-       pch_ctl2 = panel->backlight.pwm_level_max << 16;
-       intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2);
-
-       pch_ctl1 = 0;
-       if (panel->backlight.active_low_pwm)
-               pch_ctl1 |= BLM_PCH_POLARITY;
-
-       intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1);
-       intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1);
-       intel_de_write(dev_priv, BLC_PWM_PCH_CTL1,
-                      pch_ctl1 | BLM_PCH_PWM_ENABLE);
-}
-
-static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 ctl, freq;
-
-       ctl = intel_de_read(dev_priv, BLC_PWM_CTL);
-       if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) {
-               drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
-               intel_de_write(dev_priv, BLC_PWM_CTL, 0);
-       }
-
-       freq = panel->backlight.pwm_level_max;
-       if (panel->backlight.combination_mode)
-               freq /= 0xff;
-
-       ctl = freq << 17;
-       if (panel->backlight.combination_mode)
-               ctl |= BLM_LEGACY_MODE;
-       if (IS_PINEVIEW(dev_priv) && panel->backlight.active_low_pwm)
-               ctl |= BLM_POLARITY_PNV;
-
-       intel_de_write(dev_priv, BLC_PWM_CTL, ctl);
-       intel_de_posting_read(dev_priv, BLC_PWM_CTL);
-
-       /* XXX: combine this into above write? */
-       intel_panel_set_pwm_level(conn_state, level);
-
-       /*
-        * Needed to enable backlight on some 855gm models. BLC_HIST_CTL is
-        * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2
-        * that has backlight.
-        */
-       if (DISPLAY_VER(dev_priv) == 2)
-               intel_de_write(dev_priv, BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE);
-}
-
-static void i965_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe;
-       u32 ctl, ctl2, freq;
-
-       ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2);
-       if (ctl2 & BLM_PWM_ENABLE) {
-               drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
-               ctl2 &= ~BLM_PWM_ENABLE;
-               intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2);
-       }
-
-       freq = panel->backlight.pwm_level_max;
-       if (panel->backlight.combination_mode)
-               freq /= 0xff;
-
-       ctl = freq << 16;
-       intel_de_write(dev_priv, BLC_PWM_CTL, ctl);
-
-       ctl2 = BLM_PIPE(pipe);
-       if (panel->backlight.combination_mode)
-               ctl2 |= BLM_COMBINATION_MODE;
-       if (panel->backlight.active_low_pwm)
-               ctl2 |= BLM_POLARITY_I965;
-       intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2);
-       intel_de_posting_read(dev_priv, BLC_PWM_CTL2);
-       intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE);
-
-       intel_panel_set_pwm_level(conn_state, level);
-}
-
-static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
-       u32 ctl, ctl2;
-
-       ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
-       if (ctl2 & BLM_PWM_ENABLE) {
-               drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
-               ctl2 &= ~BLM_PWM_ENABLE;
-               intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2);
-       }
-
-       ctl = panel->backlight.pwm_level_max << 16;
-       intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), ctl);
-
-       /* XXX: combine this into above write? */
-       intel_panel_set_pwm_level(conn_state, level);
-
-       ctl2 = 0;
-       if (panel->backlight.active_low_pwm)
-               ctl2 |= BLM_POLARITY_I965;
-       intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2);
-       intel_de_posting_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
-       intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe),
-                      ctl2 | BLM_PWM_ENABLE);
-}
-
-static void bxt_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
-       u32 pwm_ctl, val;
-
-       /* Controller 1 uses the utility pin. */
-       if (panel->backlight.controller == 1) {
-               val = intel_de_read(dev_priv, UTIL_PIN_CTL);
-               if (val & UTIL_PIN_ENABLE) {
-                       drm_dbg_kms(&dev_priv->drm,
-                                   "util pin already enabled\n");
-                       val &= ~UTIL_PIN_ENABLE;
-                       intel_de_write(dev_priv, UTIL_PIN_CTL, val);
-               }
-
-               val = 0;
-               if (panel->backlight.util_pin_active_low)
-                       val |= UTIL_PIN_POLARITY;
-               intel_de_write(dev_priv, UTIL_PIN_CTL,
-                              val | UTIL_PIN_PIPE(pipe) | UTIL_PIN_MODE_PWM | UTIL_PIN_ENABLE);
-       }
-
-       pwm_ctl = intel_de_read(dev_priv,
-                               BXT_BLC_PWM_CTL(panel->backlight.controller));
-       if (pwm_ctl & BXT_BLC_PWM_ENABLE) {
-               drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
-               pwm_ctl &= ~BXT_BLC_PWM_ENABLE;
-               intel_de_write(dev_priv,
-                              BXT_BLC_PWM_CTL(panel->backlight.controller),
-                              pwm_ctl);
-       }
-
-       intel_de_write(dev_priv,
-                      BXT_BLC_PWM_FREQ(panel->backlight.controller),
-                      panel->backlight.pwm_level_max);
-
-       intel_panel_set_pwm_level(conn_state, level);
-
-       pwm_ctl = 0;
-       if (panel->backlight.active_low_pwm)
-               pwm_ctl |= BXT_BLC_PWM_POLARITY;
-
-       intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
-                      pwm_ctl);
-       intel_de_posting_read(dev_priv,
-                             BXT_BLC_PWM_CTL(panel->backlight.controller));
-       intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
-                      pwm_ctl | BXT_BLC_PWM_ENABLE);
-}
-
-static void cnp_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 pwm_ctl;
-
-       pwm_ctl = intel_de_read(dev_priv,
-                               BXT_BLC_PWM_CTL(panel->backlight.controller));
-       if (pwm_ctl & BXT_BLC_PWM_ENABLE) {
-               drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
-               pwm_ctl &= ~BXT_BLC_PWM_ENABLE;
-               intel_de_write(dev_priv,
-                              BXT_BLC_PWM_CTL(panel->backlight.controller),
-                              pwm_ctl);
-       }
-
-       intel_de_write(dev_priv,
-                      BXT_BLC_PWM_FREQ(panel->backlight.controller),
-                      panel->backlight.pwm_level_max);
-
-       intel_panel_set_pwm_level(conn_state, level);
-
-       pwm_ctl = 0;
-       if (panel->backlight.active_low_pwm)
-               pwm_ctl |= BXT_BLC_PWM_POLARITY;
-
-       intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
-                      pwm_ctl);
-       intel_de_posting_read(dev_priv,
-                             BXT_BLC_PWM_CTL(panel->backlight.controller));
-       intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
-                      pwm_ctl | BXT_BLC_PWM_ENABLE);
-}
-
-static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                    const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct intel_panel *panel = &connector->panel;
-
-       pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
-       panel->backlight.pwm_state.enabled = true;
-       pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
-}
-
-static void __intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                          const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct intel_panel *panel = &connector->panel;
-
-       WARN_ON(panel->backlight.max == 0);
-
-       if (panel->backlight.level <= panel->backlight.min) {
-               panel->backlight.level = panel->backlight.max;
-               if (panel->backlight.device)
-                       panel->backlight.device->props.brightness =
-                               scale_hw_to_user(connector,
-                                                panel->backlight.level,
-                                                panel->backlight.device->props.max_brightness);
-       }
-
-       panel->backlight.funcs->enable(crtc_state, conn_state, panel->backlight.level);
-       panel->backlight.enabled = true;
-       if (panel->backlight.device)
-               panel->backlight.device->props.power = FB_BLANK_UNBLANK;
-}
-
-void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
-
-       if (!panel->backlight.present)
-               return;
-
-       drm_dbg_kms(&dev_priv->drm, "pipe %c\n", pipe_name(pipe));
-
-       mutex_lock(&dev_priv->backlight_lock);
-
-       __intel_panel_enable_backlight(crtc_state, conn_state);
-
-       mutex_unlock(&dev_priv->backlight_lock);
-}
-
-#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
-static u32 intel_panel_get_backlight(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 val = 0;
-
-       mutex_lock(&dev_priv->backlight_lock);
-
-       if (panel->backlight.enabled)
-               val = panel->backlight.funcs->get(connector, intel_connector_get_pipe(connector));
-
-       mutex_unlock(&dev_priv->backlight_lock);
-
-       drm_dbg_kms(&dev_priv->drm, "get backlight PWM = %d\n", val);
-       return val;
-}
-
-/* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */
-static u32 scale_user_to_hw(struct intel_connector *connector,
-                           u32 user_level, u32 user_max)
-{
-       struct intel_panel *panel = &connector->panel;
-
-       return scale(user_level, 0, user_max,
-                    panel->backlight.min, panel->backlight.max);
-}
-
-/* set backlight brightness to level in range [0..max], scaling wrt hw min */
-static void intel_panel_set_backlight(const struct drm_connector_state *conn_state,
-                                     u32 user_level, u32 user_max)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 hw_level;
-
-       if (!panel->backlight.present)
-               return;
-
-       mutex_lock(&dev_priv->backlight_lock);
-
-       drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0);
-
-       hw_level = scale_user_to_hw(connector, user_level, user_max);
-       panel->backlight.level = hw_level;
-
-       if (panel->backlight.enabled)
-               intel_panel_actually_set_backlight(conn_state, hw_level);
-
-       mutex_unlock(&dev_priv->backlight_lock);
-}
-
-static int intel_backlight_device_update_status(struct backlight_device *bd)
-{
-       struct intel_connector *connector = bl_get_data(bd);
-       struct intel_panel *panel = &connector->panel;
-       struct drm_device *dev = connector->base.dev;
-
-       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-       DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
-                     bd->props.brightness, bd->props.max_brightness);
-       intel_panel_set_backlight(connector->base.state, bd->props.brightness,
-                                 bd->props.max_brightness);
-
-       /*
-        * Allow flipping bl_power as a sub-state of enabled. Sadly the
-        * backlight class device does not make it easy to to differentiate
-        * between callbacks for brightness and bl_power, so our backlight_power
-        * callback needs to take this into account.
-        */
-       if (panel->backlight.enabled) {
-               if (panel->backlight.power) {
-                       bool enable = bd->props.power == FB_BLANK_UNBLANK &&
-                               bd->props.brightness != 0;
-                       panel->backlight.power(connector, enable);
-               }
-       } else {
-               bd->props.power = FB_BLANK_POWERDOWN;
-       }
-
-       drm_modeset_unlock(&dev->mode_config.connection_mutex);
-       return 0;
-}
-
-static int intel_backlight_device_get_brightness(struct backlight_device *bd)
-{
-       struct intel_connector *connector = bl_get_data(bd);
-       struct drm_device *dev = connector->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       intel_wakeref_t wakeref;
-       int ret = 0;
-
-       with_intel_runtime_pm(&dev_priv->runtime_pm, wakeref) {
-               u32 hw_level;
-
-               drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-
-               hw_level = intel_panel_get_backlight(connector);
-               ret = scale_hw_to_user(connector,
-                                      hw_level, bd->props.max_brightness);
-
-               drm_modeset_unlock(&dev->mode_config.connection_mutex);
-       }
-
-       return ret;
-}
-
-static const struct backlight_ops intel_backlight_device_ops = {
-       .update_status = intel_backlight_device_update_status,
-       .get_brightness = intel_backlight_device_get_brightness,
-};
-
-int intel_backlight_device_register(struct intel_connector *connector)
-{
-       struct drm_i915_private *i915 = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       struct backlight_properties props;
-       struct backlight_device *bd;
-       const char *name;
-       int ret = 0;
-
-       if (WARN_ON(panel->backlight.device))
-               return -ENODEV;
-
-       if (!panel->backlight.present)
-               return 0;
-
-       WARN_ON(panel->backlight.max == 0);
-
-       memset(&props, 0, sizeof(props));
-       props.type = BACKLIGHT_RAW;
-
-       /*
-        * Note: Everything should work even if the backlight device max
-        * presented to the userspace is arbitrarily chosen.
-        */
-       props.max_brightness = panel->backlight.max;
-       props.brightness = scale_hw_to_user(connector,
-                                           panel->backlight.level,
-                                           props.max_brightness);
-
-       if (panel->backlight.enabled)
-               props.power = FB_BLANK_UNBLANK;
-       else
-               props.power = FB_BLANK_POWERDOWN;
-
-       name = kstrdup("intel_backlight", GFP_KERNEL);
-       if (!name)
-               return -ENOMEM;
-
-       bd = backlight_device_register(name, connector->base.kdev, connector,
-                                      &intel_backlight_device_ops, &props);
-
-       /*
-        * Using the same name independent of the drm device or connector
-        * prevents registration of multiple backlight devices in the
-        * driver. However, we need to use the default name for backward
-        * compatibility. Use unique names for subsequent backlight devices as a
-        * fallback when the default name already exists.
-        */
-       if (IS_ERR(bd) && PTR_ERR(bd) == -EEXIST) {
-               kfree(name);
-               name = kasprintf(GFP_KERNEL, "card%d-%s-backlight",
-                                i915->drm.primary->index, connector->base.name);
-               if (!name)
-                       return -ENOMEM;
-
-               bd = backlight_device_register(name, connector->base.kdev, connector,
-                                              &intel_backlight_device_ops, &props);
-       }
-
-       if (IS_ERR(bd)) {
-               drm_err(&i915->drm,
-                       "[CONNECTOR:%d:%s] backlight device %s register failed: %ld\n",
-                       connector->base.base.id, connector->base.name, name, PTR_ERR(bd));
-               ret = PTR_ERR(bd);
-               goto out;
-       }
-
-       panel->backlight.device = bd;
-
-       drm_dbg_kms(&i915->drm,
-                   "[CONNECTOR:%d:%s] backlight device %s registered\n",
-                   connector->base.base.id, connector->base.name, name);
-
-out:
-       kfree(name);
-
-       return ret;
-}
-
-void intel_backlight_device_unregister(struct intel_connector *connector)
-{
-       struct intel_panel *panel = &connector->panel;
-
-       if (panel->backlight.device) {
-               backlight_device_unregister(panel->backlight.device);
-               panel->backlight.device = NULL;
-       }
-}
-#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
-
-/*
- * CNP: PWM clock frequency is 19.2 MHz or 24 MHz.
- *      PWM increment = 1
- */
-static u32 cnp_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq),
-                                pwm_freq_hz);
-}
-
-/*
- * BXT: PWM clock frequency = 19.2 MHz.
- */
-static u32 bxt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       return DIV_ROUND_CLOSEST(KHz(19200), pwm_freq_hz);
-}
-
-/*
- * SPT: This value represents the period of the PWM stream in clock periods
- * multiplied by 16 (default increment) or 128 (alternate increment selected in
- * SCHICKEN_1 bit 0). PWM clock is 24 MHz.
- */
-static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct intel_panel *panel = &connector->panel;
-       u32 mul;
-
-       if (panel->backlight.alternate_pwm_increment)
-               mul = 128;
-       else
-               mul = 16;
-
-       return DIV_ROUND_CLOSEST(MHz(24), pwm_freq_hz * mul);
-}
-
-/*
- * LPT: This value represents the period of the PWM stream in clock periods
- * multiplied by 128 (default increment) or 16 (alternate increment, selected in
- * LPT SOUTH_CHICKEN2 register bit 5).
- */
-static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 mul, clock;
-
-       if (panel->backlight.alternate_pwm_increment)
-               mul = 16;
-       else
-               mul = 128;
-
-       if (HAS_PCH_LPT_H(dev_priv))
-               clock = MHz(135); /* LPT:H */
-       else
-               clock = MHz(24); /* LPT:LP */
-
-       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
-}
-
-/*
- * ILK/SNB/IVB: This value represents the period of the PWM stream in PCH
- * display raw clocks multiplied by 128.
- */
-static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq),
-                                pwm_freq_hz * 128);
-}
-
-/*
- * Gen2: This field determines the number of time base events (display core
- * clock frequency/32) in total for a complete cycle of modulated backlight
- * control.
- *
- * Gen3: A time base event equals the display core clock ([DevPNV] HRAW clock)
- * divided by 32.
- */
-static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       int clock;
-
-       if (IS_PINEVIEW(dev_priv))
-               clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq);
-       else
-               clock = KHz(dev_priv->cdclk.hw.cdclk);
-
-       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 32);
-}
-
-/*
- * Gen4: This value represents the period of the PWM stream in display core
- * clocks ([DevCTG] HRAW clocks) multiplied by 128.
- *
- */
-static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       int clock;
-
-       if (IS_G4X(dev_priv))
-               clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq);
-       else
-               clock = KHz(dev_priv->cdclk.hw.cdclk);
-
-       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 128);
-}
-
-/*
- * VLV: This value represents the period of the PWM stream in display core
- * clocks ([DevCTG] 200MHz HRAW clocks) multiplied by 128 or 25MHz S0IX clocks
- * multiplied by 16. CHV uses a 19.2MHz S0IX clock.
- */
-static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       int mul, clock;
-
-       if ((intel_de_read(dev_priv, CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) {
-               if (IS_CHERRYVIEW(dev_priv))
-                       clock = KHz(19200);
-               else
-                       clock = MHz(25);
-               mul = 16;
-       } else {
-               clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq);
-               mul = 128;
-       }
-
-       return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
-}
-
-static u16 get_vbt_pwm_freq(struct drm_i915_private *dev_priv)
-{
-       u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz;
-
-       if (pwm_freq_hz) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "VBT defined backlight frequency %u Hz\n",
-                           pwm_freq_hz);
-       } else {
-               pwm_freq_hz = 200;
-               drm_dbg_kms(&dev_priv->drm,
-                           "default backlight frequency %u Hz\n",
-                           pwm_freq_hz);
-       }
-
-       return pwm_freq_hz;
-}
-
-static u32 get_backlight_max_vbt(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv);
-       u32 pwm;
-
-       if (!panel->backlight.pwm_funcs->hz_to_pwm) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "backlight frequency conversion not supported\n");
-               return 0;
-       }
-
-       pwm = panel->backlight.pwm_funcs->hz_to_pwm(connector, pwm_freq_hz);
-       if (!pwm) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "backlight frequency conversion failed\n");
-               return 0;
-       }
-
-       return pwm;
-}
-
-/*
- * Note: The setup hooks can't assume pipe is set!
- */
-static u32 get_backlight_min_vbt(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       int min;
-
-       drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0);
-
-       /*
-        * XXX: If the vbt value is 255, it makes min equal to max, which leads
-        * to problems. There are such machines out there. Either our
-        * interpretation is wrong or the vbt has bogus data. Or both. Safeguard
-        * against this by letting the minimum be at most (arbitrarily chosen)
-        * 25% of the max.
-        */
-       min = clamp_t(int, dev_priv->vbt.backlight.min_brightness, 0, 64);
-       if (min != dev_priv->vbt.backlight.min_brightness) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "clamping VBT min backlight %d/255 to %d/255\n",
-                           dev_priv->vbt.backlight.min_brightness, min);
-       }
-
-       /* vbt value is a coefficient in range [0..255] */
-       return scale(min, 0, 255, 0, panel->backlight.pwm_level_max);
-}
-
-static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
-       bool alt, cpu_mode;
-
-       if (HAS_PCH_LPT(dev_priv))
-               alt = intel_de_read(dev_priv, SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY;
-       else
-               alt = intel_de_read(dev_priv, SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY;
-       panel->backlight.alternate_pwm_increment = alt;
-
-       pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
-       panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
-
-       pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2);
-       panel->backlight.pwm_level_max = pch_ctl2 >> 16;
-
-       cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
-
-       if (!panel->backlight.pwm_level_max)
-               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
-
-       if (!panel->backlight.pwm_level_max)
-               return -ENODEV;
-
-       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
-
-       panel->backlight.pwm_enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE;
-
-       cpu_mode = panel->backlight.pwm_enabled && HAS_PCH_LPT(dev_priv) &&
-                  !(pch_ctl1 & BLM_PCH_OVERRIDE_ENABLE) &&
-                  (cpu_ctl2 & BLM_PWM_ENABLE);
-
-       if (cpu_mode) {
-               val = pch_get_backlight(connector, unused);
-
-               drm_dbg_kms(&dev_priv->drm,
-                           "CPU backlight register was enabled, switching to PCH override\n");
-
-               /* Write converted CPU PWM value to PCH override register */
-               lpt_set_backlight(connector->base.state, val);
-               intel_de_write(dev_priv, BLC_PWM_PCH_CTL1,
-                              pch_ctl1 | BLM_PCH_OVERRIDE_ENABLE);
-
-               intel_de_write(dev_priv, BLC_PWM_CPU_CTL2,
-                              cpu_ctl2 & ~BLM_PWM_ENABLE);
-       }
-
-       return 0;
-}
-
-static int pch_setup_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 cpu_ctl2, pch_ctl1, pch_ctl2;
-
-       pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
-       panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
-
-       pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2);
-       panel->backlight.pwm_level_max = pch_ctl2 >> 16;
-
-       if (!panel->backlight.pwm_level_max)
-               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
-
-       if (!panel->backlight.pwm_level_max)
-               return -ENODEV;
-
-       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
-
-       cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
-       panel->backlight.pwm_enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
-               (pch_ctl1 & BLM_PCH_PWM_ENABLE);
-
-       return 0;
-}
-
-static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 ctl, val;
-
-       ctl = intel_de_read(dev_priv, BLC_PWM_CTL);
-
-       if (DISPLAY_VER(dev_priv) == 2 || IS_I915GM(dev_priv) || IS_I945GM(dev_priv))
-               panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
-
-       if (IS_PINEVIEW(dev_priv))
-               panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;
-
-       panel->backlight.pwm_level_max = ctl >> 17;
-
-       if (!panel->backlight.pwm_level_max) {
-               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
-               panel->backlight.pwm_level_max >>= 1;
-       }
-
-       if (!panel->backlight.pwm_level_max)
-               return -ENODEV;
-
-       if (panel->backlight.combination_mode)
-               panel->backlight.pwm_level_max *= 0xff;
-
-       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
-
-       val = i9xx_get_backlight(connector, unused);
-       val = intel_panel_invert_pwm_level(connector, val);
-       val = clamp(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max);
-
-       panel->backlight.pwm_enabled = val != 0;
-
-       return 0;
-}
-
-static int i965_setup_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 ctl, ctl2;
-
-       ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2);
-       panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE;
-       panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
-
-       ctl = intel_de_read(dev_priv, BLC_PWM_CTL);
-       panel->backlight.pwm_level_max = ctl >> 16;
-
-       if (!panel->backlight.pwm_level_max)
-               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
-
-       if (!panel->backlight.pwm_level_max)
-               return -ENODEV;
-
-       if (panel->backlight.combination_mode)
-               panel->backlight.pwm_level_max *= 0xff;
-
-       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
-
-       panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE;
-
-       return 0;
-}
-
-static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 ctl, ctl2;
-
-       if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B))
-               return -ENODEV;
-
-       ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
-       panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
-
-       ctl = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe));
-       panel->backlight.pwm_level_max = ctl >> 16;
-
-       if (!panel->backlight.pwm_level_max)
-               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
-
-       if (!panel->backlight.pwm_level_max)
-               return -ENODEV;
-
-       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
-
-       panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE;
-
-       return 0;
-}
-
-static int
-bxt_setup_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 pwm_ctl, val;
-
-       panel->backlight.controller = dev_priv->vbt.backlight.controller;
-
-       pwm_ctl = intel_de_read(dev_priv,
-                               BXT_BLC_PWM_CTL(panel->backlight.controller));
-
-       /* Controller 1 uses the utility pin. */
-       if (panel->backlight.controller == 1) {
-               val = intel_de_read(dev_priv, UTIL_PIN_CTL);
-               panel->backlight.util_pin_active_low =
-                                       val & UTIL_PIN_POLARITY;
-       }
-
-       panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
-       panel->backlight.pwm_level_max =
-               intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller));
-
-       if (!panel->backlight.pwm_level_max)
-               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
-
-       if (!panel->backlight.pwm_level_max)
-               return -ENODEV;
-
-       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
-
-       panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
-
-       return 0;
-}
-
-static int
-cnp_setup_backlight(struct intel_connector *connector, enum pipe unused)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-       u32 pwm_ctl;
-
-       /*
-        * CNP has the BXT implementation of backlight, but with only one
-        * controller. TODO: ICP has multiple controllers but we only use
-        * controller 0 for now.
-        */
-       panel->backlight.controller = 0;
-
-       pwm_ctl = intel_de_read(dev_priv,
-                               BXT_BLC_PWM_CTL(panel->backlight.controller));
-
-       panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
-       panel->backlight.pwm_level_max =
-               intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller));
-
-       if (!panel->backlight.pwm_level_max)
-               panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
-
-       if (!panel->backlight.pwm_level_max)
-               return -ENODEV;
-
-       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
-
-       panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
-
-       return 0;
-}
-
-static int ext_pwm_setup_backlight(struct intel_connector *connector,
-                                  enum pipe pipe)
-{
-       struct drm_device *dev = connector->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_panel *panel = &connector->panel;
-       const char *desc;
-       u32 level;
-
-       /* Get the right PWM chip for DSI backlight according to VBT */
-       if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) {
-               panel->backlight.pwm = pwm_get(dev->dev, "pwm_pmic_backlight");
-               desc = "PMIC";
-       } else {
-               panel->backlight.pwm = pwm_get(dev->dev, "pwm_soc_backlight");
-               desc = "SoC";
-       }
-
-       if (IS_ERR(panel->backlight.pwm)) {
-               drm_err(&dev_priv->drm, "Failed to get the %s PWM chip\n",
-                       desc);
-               panel->backlight.pwm = NULL;
-               return -ENODEV;
-       }
-
-       panel->backlight.pwm_level_max = 100; /* 100% */
-       panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
-
-       if (pwm_is_enabled(panel->backlight.pwm)) {
-               /* PWM is already enabled, use existing settings */
-               pwm_get_state(panel->backlight.pwm, &panel->backlight.pwm_state);
-
-               level = pwm_get_relative_duty_cycle(&panel->backlight.pwm_state,
-                                                   100);
-               level = intel_panel_invert_pwm_level(connector, level);
-               panel->backlight.pwm_enabled = true;
-
-               drm_dbg_kms(&dev_priv->drm, "PWM already enabled at freq %ld, VBT freq %d, level %d\n",
-                           NSEC_PER_SEC / (unsigned long)panel->backlight.pwm_state.period,
-                           get_vbt_pwm_freq(dev_priv), level);
-       } else {
-               /* Set period from VBT frequency, leave other settings at 0. */
-               panel->backlight.pwm_state.period =
-                       NSEC_PER_SEC / get_vbt_pwm_freq(dev_priv);
-       }
-
-       drm_info(&dev_priv->drm, "Using %s PWM for LCD backlight control\n",
-                desc);
-       return 0;
-}
-
-static void intel_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct intel_panel *panel = &connector->panel;
-
-       panel->backlight.pwm_funcs->set(conn_state,
-                                      intel_panel_invert_pwm_level(connector, level));
-}
-
-static u32 intel_pwm_get_backlight(struct intel_connector *connector, enum pipe pipe)
-{
-       struct intel_panel *panel = &connector->panel;
-
-       return intel_panel_invert_pwm_level(connector,
-                                           panel->backlight.pwm_funcs->get(connector, pipe));
-}
-
-static void intel_pwm_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                      const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct intel_panel *panel = &connector->panel;
-
-       panel->backlight.pwm_funcs->enable(crtc_state, conn_state,
-                                          intel_panel_invert_pwm_level(connector, level));
-}
-
-static void intel_pwm_disable_backlight(const struct drm_connector_state *conn_state, u32 level)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct intel_panel *panel = &connector->panel;
-
-       panel->backlight.pwm_funcs->disable(conn_state,
-                                           intel_panel_invert_pwm_level(connector, level));
-}
-
-static int intel_pwm_setup_backlight(struct intel_connector *connector, enum pipe pipe)
-{
-       struct intel_panel *panel = &connector->panel;
-       int ret = panel->backlight.pwm_funcs->setup(connector, pipe);
-
-       if (ret < 0)
-               return ret;
-
-       panel->backlight.min = panel->backlight.pwm_level_min;
-       panel->backlight.max = panel->backlight.pwm_level_max;
-       panel->backlight.level = intel_pwm_get_backlight(connector, pipe);
-       panel->backlight.enabled = panel->backlight.pwm_enabled;
-
-       return 0;
-}
-
-void intel_panel_update_backlight(struct intel_atomic_state *state,
-                                 struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state)
-{
-       struct intel_connector *connector = to_intel_connector(conn_state->connector);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_panel *panel = &connector->panel;
-
-       if (!panel->backlight.present)
-               return;
-
-       mutex_lock(&dev_priv->backlight_lock);
-       if (!panel->backlight.enabled)
-               __intel_panel_enable_backlight(crtc_state, conn_state);
-
-       mutex_unlock(&dev_priv->backlight_lock);
-}
-
-int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct intel_panel *panel = &intel_connector->panel;
-       int ret;
-
-       if (!dev_priv->vbt.backlight.present) {
-               if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) {
-                       drm_dbg_kms(&dev_priv->drm,
-                                   "no backlight present per VBT, but present per quirk\n");
-               } else {
-                       drm_dbg_kms(&dev_priv->drm,
-                                   "no backlight present per VBT\n");
-                       return 0;
-               }
-       }
-
-       /* ensure intel_panel has been initialized first */
-       if (drm_WARN_ON(&dev_priv->drm, !panel->backlight.funcs))
-               return -ENODEV;
-
-       /* set level and max in panel struct */
-       mutex_lock(&dev_priv->backlight_lock);
-       ret = panel->backlight.funcs->setup(intel_connector, pipe);
-       mutex_unlock(&dev_priv->backlight_lock);
-
-       if (ret) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "failed to setup backlight for connector %s\n",
-                           connector->name);
-               return ret;
-       }
-
-       panel->backlight.present = true;
-
-       drm_dbg_kms(&dev_priv->drm,
-                   "Connector %s backlight initialized, %s, brightness %u/%u\n",
-                   connector->name,
-                   enableddisabled(panel->backlight.enabled),
-                   panel->backlight.level, panel->backlight.max);
-
-       return 0;
-}
-
-static void intel_panel_destroy_backlight(struct intel_panel *panel)
-{
-       /* dispose of the pwm */
-       if (panel->backlight.pwm)
-               pwm_put(panel->backlight.pwm);
-
-       panel->backlight.present = false;
-}
-
-static const struct intel_panel_bl_funcs bxt_pwm_funcs = {
-       .setup = bxt_setup_backlight,
-       .enable = bxt_enable_backlight,
-       .disable = bxt_disable_backlight,
-       .set = bxt_set_backlight,
-       .get = bxt_get_backlight,
-       .hz_to_pwm = bxt_hz_to_pwm,
-};
-
-static const struct intel_panel_bl_funcs cnp_pwm_funcs = {
-       .setup = cnp_setup_backlight,
-       .enable = cnp_enable_backlight,
-       .disable = cnp_disable_backlight,
-       .set = bxt_set_backlight,
-       .get = bxt_get_backlight,
-       .hz_to_pwm = cnp_hz_to_pwm,
-};
-
-static const struct intel_panel_bl_funcs lpt_pwm_funcs = {
-       .setup = lpt_setup_backlight,
-       .enable = lpt_enable_backlight,
-       .disable = lpt_disable_backlight,
-       .set = lpt_set_backlight,
-       .get = lpt_get_backlight,
-       .hz_to_pwm = lpt_hz_to_pwm,
-};
-
-static const struct intel_panel_bl_funcs spt_pwm_funcs = {
-       .setup = lpt_setup_backlight,
-       .enable = lpt_enable_backlight,
-       .disable = lpt_disable_backlight,
-       .set = lpt_set_backlight,
-       .get = lpt_get_backlight,
-       .hz_to_pwm = spt_hz_to_pwm,
-};
-
-static const struct intel_panel_bl_funcs pch_pwm_funcs = {
-       .setup = pch_setup_backlight,
-       .enable = pch_enable_backlight,
-       .disable = pch_disable_backlight,
-       .set = pch_set_backlight,
-       .get = pch_get_backlight,
-       .hz_to_pwm = pch_hz_to_pwm,
-};
-
-static const struct intel_panel_bl_funcs ext_pwm_funcs = {
-       .setup = ext_pwm_setup_backlight,
-       .enable = ext_pwm_enable_backlight,
-       .disable = ext_pwm_disable_backlight,
-       .set = ext_pwm_set_backlight,
-       .get = ext_pwm_get_backlight,
-};
-
-static const struct intel_panel_bl_funcs vlv_pwm_funcs = {
-       .setup = vlv_setup_backlight,
-       .enable = vlv_enable_backlight,
-       .disable = vlv_disable_backlight,
-       .set = vlv_set_backlight,
-       .get = vlv_get_backlight,
-       .hz_to_pwm = vlv_hz_to_pwm,
-};
-
-static const struct intel_panel_bl_funcs i965_pwm_funcs = {
-       .setup = i965_setup_backlight,
-       .enable = i965_enable_backlight,
-       .disable = i965_disable_backlight,
-       .set = i9xx_set_backlight,
-       .get = i9xx_get_backlight,
-       .hz_to_pwm = i965_hz_to_pwm,
-};
-
-static const struct intel_panel_bl_funcs i9xx_pwm_funcs = {
-       .setup = i9xx_setup_backlight,
-       .enable = i9xx_enable_backlight,
-       .disable = i9xx_disable_backlight,
-       .set = i9xx_set_backlight,
-       .get = i9xx_get_backlight,
-       .hz_to_pwm = i9xx_hz_to_pwm,
-};
-
-static const struct intel_panel_bl_funcs pwm_bl_funcs = {
-       .setup = intel_pwm_setup_backlight,
-       .enable = intel_pwm_enable_backlight,
-       .disable = intel_pwm_disable_backlight,
-       .set = intel_pwm_set_backlight,
-       .get = intel_pwm_get_backlight,
-};
-
-/* Set up chip specific backlight functions */
-static void
-intel_panel_init_backlight_funcs(struct intel_panel *panel)
-{
-       struct intel_connector *connector =
-               container_of(panel, struct intel_connector, panel);
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI &&
-           intel_dsi_dcs_init_backlight_funcs(connector) == 0)
-               return;
-
-       if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) {
-               panel->backlight.pwm_funcs = &bxt_pwm_funcs;
-       } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) {
-               panel->backlight.pwm_funcs = &cnp_pwm_funcs;
-       } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_LPT) {
-               if (HAS_PCH_LPT(dev_priv))
-                       panel->backlight.pwm_funcs = &lpt_pwm_funcs;
-               else
-                       panel->backlight.pwm_funcs = &spt_pwm_funcs;
-       } else if (HAS_PCH_SPLIT(dev_priv)) {
-               panel->backlight.pwm_funcs = &pch_pwm_funcs;
-       } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) {
-                       panel->backlight.pwm_funcs = &ext_pwm_funcs;
-               } else {
-                       panel->backlight.pwm_funcs = &vlv_pwm_funcs;
-               }
-       } else if (DISPLAY_VER(dev_priv) == 4) {
-               panel->backlight.pwm_funcs = &i965_pwm_funcs;
-       } else {
-               panel->backlight.pwm_funcs = &i9xx_pwm_funcs;
-       }
-
-       if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP &&
-           intel_dp_aux_init_backlight_funcs(connector) == 0)
-               return;
-
-       /* We're using a standard PWM backlight interface */
-       panel->backlight.funcs = &pwm_bl_funcs;
+               return pch_panel_fitting(crtc_state, conn_state);
 }
 
 enum drm_connector_status
@@ -2232,7 +486,7 @@ int intel_panel_init(struct intel_panel *panel,
                     struct drm_display_mode *fixed_mode,
                     struct drm_display_mode *downclock_mode)
 {
-       intel_panel_init_backlight_funcs(panel);
+       intel_backlight_init_funcs(panel);
 
        panel->fixed_mode = fixed_mode;
        panel->downclock_mode = downclock_mode;
@@ -2245,7 +499,7 @@ void intel_panel_fini(struct intel_panel *panel)
        struct intel_connector *intel_connector =
                container_of(panel, struct intel_connector, panel);
 
-       intel_panel_destroy_backlight(panel);
+       intel_backlight_destroy(panel);
 
        if (panel->fixed_mode)
                drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode);
index 1d340f77bffc7926fc2118326e83112a8b856a67..f6af1a98290c09729d432423b50c922472af1e1f 100644 (file)
@@ -8,15 +8,13 @@
 
 #include <linux/types.h>
 
-#include "intel_display.h"
-
+enum drm_connector_status;
 struct drm_connector;
 struct drm_connector_state;
 struct drm_display_mode;
+struct drm_i915_private;
 struct intel_connector;
-struct intel_crtc;
 struct intel_crtc_state;
-struct intel_encoder;
 struct intel_panel;
 
 int intel_panel_init(struct intel_panel *panel,
@@ -25,23 +23,11 @@ int intel_panel_init(struct intel_panel *panel,
 void intel_panel_fini(struct intel_panel *panel);
 enum drm_connector_status
 intel_panel_detect(struct drm_connector *connector, bool force);
-void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
+bool intel_panel_use_ssc(struct drm_i915_private *i915);
+void intel_panel_fixed_mode(const struct drm_display_mode *fixed_mode,
                            struct drm_display_mode *adjusted_mode);
-int intel_pch_panel_fitting(struct intel_crtc_state *crtc_state,
-                           const struct drm_connector_state *conn_state);
-int intel_gmch_panel_fitting(struct intel_crtc_state *crtc_state,
-                            const struct drm_connector_state *conn_state);
-void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state,
-                                   u32 level, u32 max);
-int intel_panel_setup_backlight(struct drm_connector *connector,
-                               enum pipe pipe);
-void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state);
-void intel_panel_update_backlight(struct intel_atomic_state *state,
-                                 struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state,
-                                 const struct drm_connector_state *conn_state);
-void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state);
+int intel_panel_fitting(struct intel_crtc_state *crtc_state,
+                       const struct drm_connector_state *conn_state);
 struct drm_display_mode *
 intel_panel_edid_downclock_mode(struct intel_connector *connector,
                                const struct drm_display_mode *fixed_mode);
@@ -49,22 +35,5 @@ struct drm_display_mode *
 intel_panel_edid_fixed_mode(struct intel_connector *connector);
 struct drm_display_mode *
 intel_panel_vbt_fixed_mode(struct intel_connector *connector);
-void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 level);
-u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 level);
-u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 level);
-u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val);
-
-#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
-int intel_backlight_device_register(struct intel_connector *connector);
-void intel_backlight_device_unregister(struct intel_connector *connector);
-#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */
-static inline int intel_backlight_device_register(struct intel_connector *connector)
-{
-       return 0;
-}
-static inline void intel_backlight_device_unregister(struct intel_connector *connector)
-{
-}
-#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
 
 #endif /* __INTEL_PANEL_H__ */
index 1b0daf649e82393116a1ede14282abd1d025a31a..3f6fb7d67f84d906a6ba03579ebd0841117c34dd 100644 (file)
@@ -364,41 +364,6 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp)
        }
 }
 
-static void hsw_psr_setup_aux(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       u32 aux_clock_divider, aux_ctl;
-       int i;
-       static const u8 aux_msg[] = {
-               [0] = DP_AUX_NATIVE_WRITE << 4,
-               [1] = DP_SET_POWER >> 8,
-               [2] = DP_SET_POWER & 0xff,
-               [3] = 1 - 1,
-               [4] = DP_SET_POWER_D0,
-       };
-       u32 psr_aux_mask = EDP_PSR_AUX_CTL_TIME_OUT_MASK |
-                          EDP_PSR_AUX_CTL_MESSAGE_SIZE_MASK |
-                          EDP_PSR_AUX_CTL_PRECHARGE_2US_MASK |
-                          EDP_PSR_AUX_CTL_BIT_CLOCK_2X_MASK;
-
-       BUILD_BUG_ON(sizeof(aux_msg) > 20);
-       for (i = 0; i < sizeof(aux_msg); i += 4)
-               intel_de_write(dev_priv,
-                              EDP_PSR_AUX_DATA(intel_dp->psr.transcoder, i >> 2),
-                              intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i));
-
-       aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0);
-
-       /* Start with bits set for DDI_AUX_CTL register */
-       aux_ctl = intel_dp->get_aux_send_ctl(intel_dp, sizeof(aux_msg),
-                                            aux_clock_divider);
-
-       /* Select only valid bits for SRD_AUX_CTL */
-       aux_ctl &= psr_aux_mask;
-       intel_de_write(dev_priv, EDP_PSR_AUX_CTL(intel_dp->psr.transcoder),
-                      aux_ctl);
-}
-
 static void intel_psr_enable_sink(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -621,9 +586,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp)
 static bool
 transcoder_has_psr2(struct drm_i915_private *dev_priv, enum transcoder trans)
 {
-       if (DISPLAY_VER(dev_priv) < 9)
-               return false;
-       else if (DISPLAY_VER(dev_priv) >= 12)
+       if (DISPLAY_VER(dev_priv) >= 12)
                return trans == TRANSCODER_A;
        else
                return trans == TRANSCODER_EDP;
@@ -1114,12 +1077,6 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp)
        enum transcoder cpu_transcoder = intel_dp->psr.transcoder;
        u32 mask;
 
-       /* Only HSW and BDW have PSR AUX registers that need to be setup. SKL+
-        * use hardcoded values PSR AUX transactions
-        */
-       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
-               hsw_psr_setup_aux(intel_dp);
-
        if (intel_dp->psr.psr2_enabled && DISPLAY_VER(dev_priv) == 9) {
                i915_reg_t reg = CHICKEN_TRANS(cpu_transcoder);
                u32 chicken = intel_de_read(dev_priv, reg);
@@ -1460,23 +1417,16 @@ static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
 
-       if (DISPLAY_VER(dev_priv) >= 9)
-               /*
-                * Display WA #0884: skl+
-                * This documented WA for bxt can be safely applied
-                * broadly so we can force HW tracking to exit PSR
-                * instead of disabling and re-enabling.
-                * Workaround tells us to write 0 to CUR_SURFLIVE_A,
-                * but it makes more sense write to the current active
-                * pipe.
-                */
-               intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0);
-       else
-               /*
-                * A write to CURSURFLIVE do not cause HW tracking to exit PSR
-                * on older gens so doing the manual exit instead.
-                */
-               intel_psr_exit(intel_dp);
+       /*
+        * Display WA #0884: skl+
+        * This documented WA for bxt can be safely applied
+        * broadly so we can force HW tracking to exit PSR
+        * instead of disabling and re-enabling.
+        * Workaround tells us to write 0 to CUR_SURFLIVE_A,
+        * but it makes more sense write to the current active
+        * pipe.
+        */
+       intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0);
 }
 
 void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane,
@@ -1487,8 +1437,8 @@ void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane,
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
        enum pipe pipe = plane->pipe;
        const struct drm_rect *clip;
-       u32 val, offset;
-       int ret, x, y;
+       u32 val;
+       int x, y;
 
        if (!crtc_state->enable_psr2_sel_fetch)
                return;
@@ -1508,10 +1458,6 @@ void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane,
        /* TODO: consider auxiliary surfaces */
        x = plane_state->uapi.src.x1 >> 16;
        y = (plane_state->uapi.src.y1 >> 16) + clip->y1;
-       ret = skl_calc_main_surface_offset(plane_state, &x, &y, &offset);
-       if (ret)
-               drm_warn_once(&dev_priv->drm, "skl_calc_main_surface_offset() returned %i\n",
-                             ret);
        val = y << 16 | x;
        intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_OFFSET(pipe, plane->id),
                          val);
@@ -1748,7 +1694,6 @@ void intel_psr_update(struct intel_dp *intel_dp,
                      const struct intel_crtc_state *crtc_state,
                      const struct drm_connector_state *conn_state)
 {
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
        struct intel_psr *psr = &intel_dp->psr;
        bool enable, psr2_enable;
 
@@ -1765,15 +1710,6 @@ void intel_psr_update(struct intel_dp *intel_dp,
                /* Force a PSR exit when enabling CRC to avoid CRC timeouts */
                if (crtc_state->crc_enabled && psr->enabled)
                        psr_force_hw_tracking_exit(intel_dp);
-               else if (DISPLAY_VER(dev_priv) < 9 && psr->enabled) {
-                       /*
-                        * Activate PSR again after a force exit when enabling
-                        * CRC in older gens
-                        */
-                       if (!intel_dp->psr.active &&
-                           !intel_dp->psr.busy_frontbuffer_bits)
-                               schedule_work(&intel_dp->psr.work);
-               }
 
                goto unlock;
        }
@@ -2186,23 +2122,12 @@ void intel_psr_init(struct intel_dp *intel_dp)
 
        intel_dp->psr.source_support = true;
 
-       if (IS_HASWELL(dev_priv))
-               /*
-                * HSW don't have PSR registers on the same space as transcoder
-                * so set this to a value that when subtract to the register
-                * in transcoder space results in the right offset for HSW
-                */
-               dev_priv->hsw_psr_mmio_adjust = _SRD_CTL_EDP - _HSW_EDP_PSR_BASE;
-
        if (dev_priv->params.enable_psr == -1)
-               if (DISPLAY_VER(dev_priv) < 9 || !dev_priv->vbt.psr.enable)
+               if (!dev_priv->vbt.psr.enable)
                        dev_priv->params.enable_psr = 0;
 
        /* Set link_standby x link_off defaults */
-       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
-               /* HSW and BDW require workarounds that we don't implement. */
-               intel_dp->psr.link_standby = false;
-       else if (DISPLAY_VER(dev_priv) < 12)
+       if (DISPLAY_VER(dev_priv) < 12)
                /* For new platforms up to TGL let's respect VBT back again */
                intel_dp->psr.link_standby = dev_priv->vbt.psr.full_link;
 
index 18b52b64af955aa8c003bb48f07450b13021fff7..2405f70d82ded50d5115a213e4cb8aa19fb5a5d5 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/util_macros.h>
 
+#include "intel_ddi_buf_trans.h"
 #include "intel_de.h"
 #include "intel_display_types.h"
 #include "intel_snps_phy.h"
@@ -50,58 +51,30 @@ void intel_snps_phy_update_psr_power_state(struct drm_i915_private *dev_priv,
                         SNPS_PHY_TX_REQ_LN_DIS_PWR_STATE_PSR, val);
 }
 
-static const u32 dg2_ddi_translations[] = {
-       /* VS 0, pre-emph 0 */
-       REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 26),
-
-       /* VS 0, pre-emph 1 */
-       REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 33) |
-               REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 6),
-
-       /* VS 0, pre-emph 2 */
-       REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 38) |
-               REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 12),
-
-       /* VS 0, pre-emph 3 */
-       REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 43) |
-               REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 19),
-
-       /* VS 1, pre-emph 0 */
-       REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 39),
-
-       /* VS 1, pre-emph 1 */
-       REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 44) |
-               REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 8),
-
-       /* VS 1, pre-emph 2 */
-       REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 47) |
-               REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 15),
-
-       /* VS 2, pre-emph 0 */
-       REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 52),
-
-       /* VS 2, pre-emph 1 */
-       REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 51) |
-               REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 10),
-
-       /* VS 3, pre-emph 0 */
-       REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 62),
-};
-
 void intel_snps_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
-                                       u32 level)
+                                       const struct intel_crtc_state *crtc_state,
+                                       int level)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       const struct intel_ddi_buf_trans *ddi_translations;
        enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
        int n_entries, ln;
 
-       n_entries = ARRAY_SIZE(dg2_ddi_translations);
-       if (level >= n_entries)
+       ddi_translations = encoder->get_buf_trans(encoder, crtc_state, &n_entries);
+       if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations))
+               return;
+       if (drm_WARN_ON_ONCE(&dev_priv->drm, level < 0 || level >= n_entries))
                level = n_entries - 1;
 
-       for (ln = 0; ln < 4; ln++)
-               intel_de_write(dev_priv, SNPS_PHY_TX_EQ(ln, phy),
-                              dg2_ddi_translations[level]);
+       for (ln = 0; ln < 4; ln++) {
+               u32 val = 0;
+
+               val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, ddi_translations->entries[level].snps.snps_vswing);
+               val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_PRE, ddi_translations->entries[level].snps.snps_pre_cursor);
+               val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, ddi_translations->entries[level].snps.snps_post_cursor);
+
+               intel_de_write(dev_priv, SNPS_PHY_TX_EQ(ln, phy), val);
+       }
 }
 
 /*
@@ -198,11 +171,81 @@ static const struct intel_mpllb_state dg2_dp_hbr3_100 = {
                REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 1),
 };
 
-static const struct intel_mpllb_state *dg2_dp_100_tables[] = {
+static const struct intel_mpllb_state dg2_dp_uhbr10_100 = {
+       .clock = 1000000,
+       .ref_control =
+               REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
+       .mpllb_cp =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 4) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 21) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
+       .mpllb_div =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_CLK_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_MULTIPLIER, 8) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_WORD_DIV2_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DP2_MODE, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2),
+       .mpllb_div2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 2) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 368),
+       .mpllb_fracn1 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 1),
+
+       /*
+        * SSC will be enabled, DP UHBR has a minimum SSC requirement.
+        */
+       .mpllb_sscen =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_PEAK, 58982),
+       .mpllb_sscstep =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 76101),
+};
+
+static const struct intel_mpllb_state dg2_dp_uhbr13_100 = {
+       .clock = 1350000,
+       .ref_control =
+               REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
+       .mpllb_cp =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 5) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 45) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
+       .mpllb_div =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_CLK_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_MULTIPLIER, 8) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_WORD_DIV2_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DP2_MODE, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 3),
+       .mpllb_div2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 2) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 508),
+       .mpllb_fracn1 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 1),
+
+       /*
+        * SSC will be enabled, DP UHBR has a minimum SSC requirement.
+        */
+       .mpllb_sscen =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_PEAK, 79626),
+       .mpllb_sscstep =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 102737),
+};
+
+static const struct intel_mpllb_state * const dg2_dp_100_tables[] = {
        &dg2_dp_rbr_100,
        &dg2_dp_hbr1_100,
        &dg2_dp_hbr2_100,
        &dg2_dp_hbr3_100,
+       &dg2_dp_uhbr10_100,
+       &dg2_dp_uhbr13_100,
        NULL,
 };
 
@@ -311,11 +354,88 @@ static const struct intel_mpllb_state dg2_dp_hbr3_38_4 = {
                REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 61440),
 };
 
-static const struct intel_mpllb_state *dg2_dp_38_4_tables[] = {
+static const struct intel_mpllb_state dg2_dp_uhbr10_38_4 = {
+       .clock = 1000000,
+       .ref_control =
+               REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 1),
+       .mpllb_cp =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 5) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 26) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
+       .mpllb_div =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_CLK_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_MULTIPLIER, 8) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_WORD_DIV2_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DP2_MODE, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2),
+       .mpllb_div2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 488),
+       .mpllb_fracn1 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 3),
+       .mpllb_fracn2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 2) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 27306),
+
+       /*
+        * SSC will be enabled, DP UHBR has a minimum SSC requirement.
+        */
+       .mpllb_sscen =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_PEAK, 76800),
+       .mpllb_sscstep =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 129024),
+};
+
+static const struct intel_mpllb_state dg2_dp_uhbr13_38_4 = {
+       .clock = 1350000,
+       .ref_control =
+               REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 1),
+       .mpllb_cp =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 56) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
+       .mpllb_div =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_CLK_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_MULTIPLIER, 8) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_WORD_DIV2_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DP2_MODE, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 3),
+       .mpllb_div2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 670),
+       .mpllb_fracn1 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 1),
+       .mpllb_fracn2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 36864),
+
+       /*
+        * SSC will be enabled, DP UHBR has a minimum SSC requirement.
+        */
+       .mpllb_sscen =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_PEAK, 103680),
+       .mpllb_sscstep =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 174182),
+};
+
+static const struct intel_mpllb_state * const dg2_dp_38_4_tables[] = {
        &dg2_dp_rbr_38_4,
        &dg2_dp_hbr1_38_4,
        &dg2_dp_hbr2_38_4,
        &dg2_dp_hbr3_38_4,
+       &dg2_dp_uhbr10_38_4,
+       &dg2_dp_uhbr13_38_4,
        NULL,
 };
 
@@ -448,7 +568,7 @@ static const struct intel_mpllb_state dg2_edp_r432 = {
                REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 65752),
 };
 
-static const struct intel_mpllb_state *dg2_edp_tables[] = {
+static const struct intel_mpllb_state * const dg2_edp_tables[] = {
        &dg2_dp_rbr_100,
        &dg2_edp_r216,
        &dg2_edp_r243,
@@ -611,7 +731,7 @@ static const struct intel_mpllb_state dg2_hdmi_594 = {
                REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
 };
 
-static const struct intel_mpllb_state *dg2_hdmi_tables[] = {
+static const struct intel_mpllb_state * const dg2_hdmi_tables[] = {
        &dg2_hdmi_25_175,
        &dg2_hdmi_27_0,
        &dg2_hdmi_74_25,
@@ -620,7 +740,7 @@ static const struct intel_mpllb_state *dg2_hdmi_tables[] = {
        NULL,
 };
 
-static const struct intel_mpllb_state **
+static const struct intel_mpllb_state * const *
 intel_mpllb_tables_get(struct intel_crtc_state *crtc_state,
                       struct intel_encoder *encoder)
 {
@@ -654,7 +774,7 @@ intel_mpllb_tables_get(struct intel_crtc_state *crtc_state,
 int intel_mpllb_calc_state(struct intel_crtc_state *crtc_state,
                           struct intel_encoder *encoder)
 {
-       const struct intel_mpllb_state **tables;
+       const struct intel_mpllb_state * const *tables;
        int i;
 
        if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
@@ -850,7 +970,7 @@ void intel_mpllb_readout_hw_state(struct intel_encoder *encoder,
 
 int intel_snps_phy_check_hdmi_link_rate(int clock)
 {
-       const struct intel_mpllb_state **tables = dg2_hdmi_tables;
+       const struct intel_mpllb_state * const *tables = dg2_hdmi_tables;
        int i;
 
        for (i = 0; tables[i]; i++) {
index 6261ff88ef5c6ed056916874a4b7975d6d8f76e6..a68547a6fee52d4a951f6c7e8478bce6c889ffa5 100644 (file)
@@ -30,6 +30,7 @@ int intel_mpllb_calc_port_clock(struct intel_encoder *encoder,
 
 int intel_snps_phy_check_hdmi_link_rate(int clock);
 void intel_snps_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
-                                       u32 level);
+                                       const struct intel_crtc_state *crtc_state,
+                                       int level);
 
 #endif /* __INTEL_SNPS_PHY_H__ */
index 0ee4ff341e25d2cbb000501f31a3f5ea0c5d963f..b0a2b6b96799122419fe791091eb19b31796627a 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "i915_drv.h"
 #include "intel_atomic.h"
+#include "intel_backlight.h"
 #include "intel_connector.h"
 #include "intel_crtc.h"
 #include "intel_de.h"
@@ -278,12 +279,9 @@ static int intel_dsi_compute_config(struct intel_encoder *encoder,
        pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
 
        if (fixed_mode) {
-               intel_fixed_panel_mode(fixed_mode, adjusted_mode);
+               intel_panel_fixed_mode(fixed_mode, adjusted_mode);
 
-               if (HAS_GMCH(dev_priv))
-                       ret = intel_gmch_panel_fitting(pipe_config, conn_state);
-               else
-                       ret = intel_pch_panel_fitting(pipe_config, conn_state);
+               ret = intel_panel_fitting(pipe_config, conn_state);
                if (ret)
                        return ret;
        }
@@ -883,7 +881,7 @@ static void intel_dsi_pre_enable(struct intel_atomic_state *state,
                intel_dsi_port_enable(encoder, pipe_config);
        }
 
-       intel_panel_enable_backlight(pipe_config, conn_state);
+       intel_backlight_enable(pipe_config, conn_state);
        intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
 }
 
@@ -913,7 +911,7 @@ static void intel_dsi_disable(struct intel_atomic_state *state,
        drm_dbg_kms(&i915->drm, "\n");
 
        intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF);
-       intel_panel_disable_backlight(old_conn_state);
+       intel_backlight_disable(old_conn_state);
 
        /*
         * According to the spec we should send SHUTDOWN before
@@ -1876,7 +1874,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
        intel_encoder->post_disable = intel_dsi_post_disable;
        intel_encoder->get_hw_state = intel_dsi_get_hw_state;
        intel_encoder->get_config = intel_dsi_get_config;
-       intel_encoder->update_pipe = intel_panel_update_backlight;
+       intel_encoder->update_pipe = intel_backlight_update;
        intel_encoder->shutdown = intel_dsi_shutdown;
 
        intel_connector->get_hw_state = intel_connector_get_hw_state;
@@ -1964,7 +1962,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
        }
 
        intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
-       intel_panel_setup_backlight(connector, INVALID_PIPE);
+       intel_backlight_setup(intel_connector, INVALID_PIPE);
 
        vlv_dsi_add_properties(intel_connector);
 
index 005b1cec70075d9e6474cf5669fd56e30c6e0fdc..a8129153d1dbbe726fa1ba75db2d7502f6c4f280 100644 (file)
@@ -352,8 +352,7 @@ struct drm_i915_display_funcs {
                                struct intel_crtc_state *);
        void (*get_initial_plane_config)(struct intel_crtc *,
                                         struct intel_initial_plane_config *);
-       int (*crtc_compute_clock)(struct intel_crtc *crtc,
-                                 struct intel_crtc_state *crtc_state);
+       int (*crtc_compute_clock)(struct intel_crtc_state *crtc_state);
        void (*crtc_enable)(struct intel_atomic_state *state,
                            struct intel_crtc *crtc);
        void (*crtc_disable)(struct intel_atomic_state *state,
@@ -454,7 +453,7 @@ struct intel_fbc {
                } fb;
 
                unsigned int fence_y_offset;
-               u16 gen9_wa_cfb_stride;
+               u16 override_cfb_stride;
                u16 interval;
                s8 fence_id;
                bool psr2_active;
@@ -481,7 +480,7 @@ struct intel_fbc {
 
                int cfb_size;
                unsigned int fence_y_offset;
-               u16 gen9_wa_cfb_stride;
+               u16 override_cfb_stride;
                u16 interval;
                s8 fence_id;
                bool plane_visible;
@@ -636,22 +635,6 @@ i915_fence_timeout(const struct drm_i915_private *i915)
 /* Amount of PSF GV points, BSpec precisely defines this */
 #define I915_NUM_PSF_GV_POINTS 3
 
-struct ddi_vbt_port_info {
-       /* Non-NULL if port present. */
-       struct intel_bios_encoder_data *devdata;
-
-       int max_tmds_clock;
-
-       /* This is an index in the HDMI/DVI DDI buffer translation table. */
-       u8 hdmi_level_shift;
-       u8 hdmi_level_shift_set:1;
-
-       u8 alternate_aux_channel;
-       u8 alternate_ddc_pin;
-
-       int dp_max_link_rate;           /* 0 for not limited by VBT */
-};
-
 enum psr_lines_to_wait {
        PSR_0_LINES_TO_WAIT = 0,
        PSR_1_LINE_TO_WAIT,
@@ -706,6 +689,7 @@ struct intel_vbt_data {
 
        struct {
                u16 pwm_freq_hz;
+               u16 brightness_precision_bits;
                bool present;
                bool active_low_pwm;
                u8 min_brightness;      /* min_brightness/255 of max */
@@ -732,7 +716,7 @@ struct intel_vbt_data {
 
        struct list_head display_devices;
 
-       struct ddi_vbt_port_info ddi_port_info[I915_MAX_PORTS];
+       struct intel_bios_encoder_data *ports[I915_MAX_PORTS]; /* Non-NULL if port present. */
        struct sdvo_device_mapping sdvo_mappings[2];
 };
 
@@ -886,8 +870,6 @@ struct drm_i915_private {
         */
        u32 gpio_mmio_base;
 
-       u32 hsw_psr_mmio_adjust;
-
        /* MMIO base address for MIPI regs */
        u32 mipi_mmio_base;
 
@@ -1016,12 +998,6 @@ struct drm_i915_private {
 
        struct list_head global_obj_list;
 
-       /*
-        * For reading active_pipes holding any crtc lock is
-        * sufficient, for writing must hold all of them.
-        */
-       u8 active_pipes;
-
        struct i915_wa_list gt_wa_list;
 
        struct i915_frontbuffer_tracking fb_tracking;
@@ -1721,6 +1697,8 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
 
 #define HAS_VRR(i915)  (GRAPHICS_VER(i915) >= 12)
 
+#define HAS_ASYNC_FLIPS(i915)          (DISPLAY_VER(i915) >= 5)
+
 /* Only valid when HAS_DISPLAY() is true */
 #define INTEL_DISPLAY_ENABLED(dev_priv) \
        (drm_WARN_ON(&(dev_priv)->drm, !HAS_DISPLAY(dev_priv)), !(dev_priv)->params.disable_display)
index 9bc4f4a8e12ec8f2016196c545a6ccdf57fdf56c..0a1681384c84b81c91793eaa47f0a146558bbe42 100644 (file)
@@ -359,9 +359,8 @@ void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv,
  * @interrupt_mask: mask of interrupt bits to update
  * @enabled_irq_mask: mask of interrupt bits to enable
  */
-void ilk_update_display_irq(struct drm_i915_private *dev_priv,
-                           u32 interrupt_mask,
-                           u32 enabled_irq_mask)
+static void ilk_update_display_irq(struct drm_i915_private *dev_priv,
+                                  u32 interrupt_mask, u32 enabled_irq_mask)
 {
        u32 new_val;
 
@@ -380,6 +379,16 @@ void ilk_update_display_irq(struct drm_i915_private *dev_priv,
        }
 }
 
+void ilk_enable_display_irq(struct drm_i915_private *i915, u32 bits)
+{
+       ilk_update_display_irq(i915, bits, bits);
+}
+
+void ilk_disable_display_irq(struct drm_i915_private *i915, u32 bits)
+{
+       ilk_update_display_irq(i915, bits, 0);
+}
+
 /**
  * bdw_update_port_irq - update DE port interrupt
  * @dev_priv: driver private
@@ -419,10 +428,9 @@ static void bdw_update_port_irq(struct drm_i915_private *dev_priv,
  * @interrupt_mask: mask of interrupt bits to update
  * @enabled_irq_mask: mask of interrupt bits to enable
  */
-void bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
-                        enum pipe pipe,
-                        u32 interrupt_mask,
-                        u32 enabled_irq_mask)
+static void bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
+                               enum pipe pipe, u32 interrupt_mask,
+                               u32 enabled_irq_mask)
 {
        u32 new_val;
 
@@ -444,15 +452,27 @@ void bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
        }
 }
 
+void bdw_enable_pipe_irq(struct drm_i915_private *i915,
+                        enum pipe pipe, u32 bits)
+{
+       bdw_update_pipe_irq(i915, pipe, bits, bits);
+}
+
+void bdw_disable_pipe_irq(struct drm_i915_private *i915,
+                         enum pipe pipe, u32 bits)
+{
+       bdw_update_pipe_irq(i915, pipe, bits, 0);
+}
+
 /**
  * ibx_display_interrupt_update - update SDEIMR
  * @dev_priv: driver private
  * @interrupt_mask: mask of interrupt bits to update
  * @enabled_irq_mask: mask of interrupt bits to enable
  */
-void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
-                                 u32 interrupt_mask,
-                                 u32 enabled_irq_mask)
+static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
+                                        u32 interrupt_mask,
+                                        u32 enabled_irq_mask)
 {
        u32 sdeimr = intel_uncore_read(&dev_priv->uncore, SDEIMR);
        sdeimr &= ~interrupt_mask;
@@ -469,6 +489,16 @@ void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
        intel_uncore_posting_read(&dev_priv->uncore, SDEIMR);
 }
 
+void ibx_enable_display_interrupt(struct drm_i915_private *i915, u32 bits)
+{
+       ibx_display_interrupt_update(i915, bits, bits);
+}
+
+void ibx_disable_display_interrupt(struct drm_i915_private *i915, u32 bits)
+{
+       ibx_display_interrupt_update(i915, bits, 0);
+}
+
 u32 i915_pipestat_enable_mask(struct drm_i915_private *dev_priv,
                              enum pipe pipe)
 {
@@ -2093,22 +2123,6 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
        if (de_iir & DE_ERR_INT_IVB)
                ivb_err_int_handler(dev_priv);
 
-       if (de_iir & DE_EDP_PSR_INT_HSW) {
-               struct intel_encoder *encoder;
-
-               for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) {
-                       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
-                       u32 psr_iir = intel_uncore_read(&dev_priv->uncore,
-                                                       EDP_PSR_IIR);
-
-                       intel_psr_irq_handler(intel_dp, psr_iir);
-                       intel_uncore_write(&dev_priv->uncore,
-                                          EDP_PSR_IIR, psr_iir);
-                       break;
-               }
-       }
-
        if (de_iir & DE_AUX_CHANNEL_A_IVB)
                dp_aux_irq_handler(dev_priv);
 
index e43b6734f21b73c917e7ce6226ef45d1e16b9bdb..0eb90d271fa70ee0b44fcf4ad14c6109576d8f0e 100644 (file)
@@ -9,9 +9,9 @@
 #include <linux/ktime.h>
 #include <linux/types.h>
 
-#include "display/intel_display.h"
 #include "i915_reg.h"
 
+enum pipe;
 struct drm_crtc;
 struct drm_device;
 struct drm_display_mode;
@@ -40,46 +40,15 @@ void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv);
 void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv,
                                   u32 mask,
                                   u32 bits);
-void ilk_update_display_irq(struct drm_i915_private *dev_priv,
-                           u32 interrupt_mask,
-                           u32 enabled_irq_mask);
-static inline void
-ilk_enable_display_irq(struct drm_i915_private *dev_priv, u32 bits)
-{
-       ilk_update_display_irq(dev_priv, bits, bits);
-}
-static inline void
-ilk_disable_display_irq(struct drm_i915_private *dev_priv, u32 bits)
-{
-       ilk_update_display_irq(dev_priv, bits, 0);
-}
-void bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
-                        enum pipe pipe,
-                        u32 interrupt_mask,
-                        u32 enabled_irq_mask);
-static inline void bdw_enable_pipe_irq(struct drm_i915_private *dev_priv,
-                                      enum pipe pipe, u32 bits)
-{
-       bdw_update_pipe_irq(dev_priv, pipe, bits, bits);
-}
-static inline void bdw_disable_pipe_irq(struct drm_i915_private *dev_priv,
-                                       enum pipe pipe, u32 bits)
-{
-       bdw_update_pipe_irq(dev_priv, pipe, bits, 0);
-}
-void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
-                                 u32 interrupt_mask,
-                                 u32 enabled_irq_mask);
-static inline void
-ibx_enable_display_interrupt(struct drm_i915_private *dev_priv, u32 bits)
-{
-       ibx_display_interrupt_update(dev_priv, bits, bits);
-}
-static inline void
-ibx_disable_display_interrupt(struct drm_i915_private *dev_priv, u32 bits)
-{
-       ibx_display_interrupt_update(dev_priv, bits, 0);
-}
+
+void ilk_enable_display_irq(struct drm_i915_private *i915, u32 bits);
+void ilk_disable_display_irq(struct drm_i915_private *i915, u32 bits);
+
+void bdw_enable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits);
+void bdw_disable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits);
+
+void ibx_enable_display_interrupt(struct drm_i915_private *i915, u32 bits);
+void ibx_disable_display_interrupt(struct drm_i915_private *i915, u32 bits);
 
 void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, u32 mask);
 void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, u32 mask);
index 1bbd09ad528733f666107f2134b394b65eb42b91..52c04369559f365f1e78fac5ed3d4d53339178a6 100644 (file)
@@ -537,8 +537,6 @@ static const struct intel_device_info vlv_info = {
                BIT(TRANSCODER_C) | BIT(TRANSCODER_EDP), \
        .display.has_ddi = 1, \
        .display.has_fpga_dbg = 1, \
-       .display.has_psr = 1, \
-       .display.has_psr_hw_tracking = 1, \
        .display.has_dp_mst = 1, \
        .has_rc6p = 0 /* RC6p removed-by HSW */, \
        HSW_PIPE_OFFSETS, \
@@ -642,6 +640,8 @@ static const struct intel_device_info chv_info = {
        .has_gt_uc = 1, \
        .display.has_hdcp = 1, \
        .display.has_ipc = 1, \
+       .display.has_psr = 1, \
+       .display.has_psr_hw_tracking = 1, \
        .dbuf.size = 896 - 4, /* 4 blocks for bypass path allocation */ \
        .dbuf.slice_mask = BIT(DBUF_S1)
 
index 664970f2bc62a76cf78956aa990b4d0186396fe7..bd63760207b0ac44c77e7eab9e40d3706bbebd95 100644 (file)
@@ -2237,10 +2237,14 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 
 #define SNPS_PHY_MPLLB_DIV(phy)                        _MMIO_SNPS(phy, 0x168004)
 #define   SNPS_PHY_MPLLB_FORCE_EN              REG_BIT(31)
+#define   SNPS_PHY_MPLLB_DIV_CLK_EN            REG_BIT(30)
 #define   SNPS_PHY_MPLLB_DIV5_CLK_EN           REG_BIT(29)
 #define   SNPS_PHY_MPLLB_V2I                   REG_GENMASK(27, 26)
 #define   SNPS_PHY_MPLLB_FREQ_VCO              REG_GENMASK(25, 24)
+#define   SNPS_PHY_MPLLB_DIV_MULTIPLIER                REG_GENMASK(23, 16)
 #define   SNPS_PHY_MPLLB_PMIX_EN               REG_BIT(10)
+#define   SNPS_PHY_MPLLB_DP2_MODE              REG_BIT(9)
+#define   SNPS_PHY_MPLLB_WORD_DIV2_EN          REG_BIT(8)
 #define   SNPS_PHY_MPLLB_TX_CLK_DIV            REG_GENMASK(7, 5)
 
 #define SNPS_PHY_MPLLB_FRACN1(phy)             _MMIO_SNPS(phy, 0x168008)
@@ -4509,11 +4513,9 @@ enum {
  * HSW PSR registers are relative to DDIA(_DDI_BUF_CTL_A + 0x800) with just one
  * instance of it
  */
-#define _HSW_EDP_PSR_BASE                      0x64800
 #define _SRD_CTL_A                             0x60800
 #define _SRD_CTL_EDP                           0x6f800
-#define _PSR_ADJ(tran, reg)                    (_TRANS2(tran, reg) - dev_priv->hsw_psr_mmio_adjust)
-#define EDP_PSR_CTL(tran)                      _MMIO(_PSR_ADJ(tran, _SRD_CTL_A))
+#define EDP_PSR_CTL(tran)                      _MMIO(_TRANS2(tran, _SRD_CTL_A))
 #define   EDP_PSR_ENABLE                       (1 << 31)
 #define   BDW_PSR_SINGLE_FRAME                 (1 << 30)
 #define   EDP_PSR_RESTORE_PSR_ACTIVE_CTX_MASK  (1 << 29) /* SW can't modify */
@@ -4557,22 +4559,13 @@ enum {
 #define   EDP_PSR_POST_EXIT(trans)             (0x2 << _EDP_PSR_TRANS_SHIFT(trans))
 #define   EDP_PSR_PRE_ENTRY(trans)             (0x1 << _EDP_PSR_TRANS_SHIFT(trans))
 
-#define _SRD_AUX_CTL_A                         0x60810
-#define _SRD_AUX_CTL_EDP                       0x6f810
-#define EDP_PSR_AUX_CTL(tran)                  _MMIO(_PSR_ADJ(tran, _SRD_AUX_CTL_A))
-#define   EDP_PSR_AUX_CTL_TIME_OUT_MASK                (3 << 26)
-#define   EDP_PSR_AUX_CTL_MESSAGE_SIZE_MASK    (0x1f << 20)
-#define   EDP_PSR_AUX_CTL_PRECHARGE_2US_MASK   (0xf << 16)
-#define   EDP_PSR_AUX_CTL_ERROR_INTERRUPT      (1 << 11)
-#define   EDP_PSR_AUX_CTL_BIT_CLOCK_2X_MASK    (0x7ff)
-
 #define _SRD_AUX_DATA_A                                0x60814
 #define _SRD_AUX_DATA_EDP                      0x6f814
-#define EDP_PSR_AUX_DATA(tran, i)              _MMIO(_PSR_ADJ(tran, _SRD_AUX_DATA_A) + (i) + 4) /* 5 registers */
+#define EDP_PSR_AUX_DATA(tran, i)              _MMIO(_TRANS2(tran, _SRD_AUX_DATA_A) + (i) + 4) /* 5 registers */
 
 #define _SRD_STATUS_A                          0x60840
 #define _SRD_STATUS_EDP                                0x6f840
-#define EDP_PSR_STATUS(tran)                   _MMIO(_PSR_ADJ(tran, _SRD_STATUS_A))
+#define EDP_PSR_STATUS(tran)                   _MMIO(_TRANS2(tran, _SRD_STATUS_A))
 #define   EDP_PSR_STATUS_STATE_MASK            (7 << 29)
 #define   EDP_PSR_STATUS_STATE_SHIFT           29
 #define   EDP_PSR_STATUS_STATE_IDLE            (0 << 29)
@@ -4599,13 +4592,13 @@ enum {
 
 #define _SRD_PERF_CNT_A                        0x60844
 #define _SRD_PERF_CNT_EDP              0x6f844
-#define EDP_PSR_PERF_CNT(tran)         _MMIO(_PSR_ADJ(tran, _SRD_PERF_CNT_A))
+#define EDP_PSR_PERF_CNT(tran)         _MMIO(_TRANS2(tran, _SRD_PERF_CNT_A))
 #define   EDP_PSR_PERF_CNT_MASK                0xffffff
 
 /* PSR_MASK on SKL+ */
 #define _SRD_DEBUG_A                           0x60860
 #define _SRD_DEBUG_EDP                         0x6f860
-#define EDP_PSR_DEBUG(tran)                    _MMIO(_PSR_ADJ(tran, _SRD_DEBUG_A))
+#define EDP_PSR_DEBUG(tran)                    _MMIO(_TRANS2(tran, _SRD_DEBUG_A))
 #define   EDP_PSR_DEBUG_MASK_MAX_SLEEP         (1 << 28)
 #define   EDP_PSR_DEBUG_MASK_LPSP              (1 << 27)
 #define   EDP_PSR_DEBUG_MASK_MEMUP             (1 << 26)
@@ -8176,8 +8169,9 @@ enum {
 #define  GLK_CL0_PWR_DOWN      (1 << 10)
 
 #define CHICKEN_MISC_4         _MMIO(0x4208c)
-#define   FBC_STRIDE_OVERRIDE  (1 << 13)
-#define   FBC_STRIDE_MASK      0x1FFF
+#define   CHICKEN_FBC_STRIDE_OVERRIDE  REG_BIT(13)
+#define   CHICKEN_FBC_STRIDE_MASK      REG_GENMASK(12, 0)
+#define   CHICKEN_FBC_STRIDE(x)                REG_FIELD_PREP(CHICKEN_FBC_STRIDE_MASK, (x))
 
 #define _CHICKEN_PIPESL_1_A    0x420b0
 #define _CHICKEN_PIPESL_1_B    0x420b4
@@ -9096,6 +9090,29 @@ enum {
 #define  TRANS_DP_HSYNC_ACTIVE_LOW     0
 #define  TRANS_DP_SYNC_MASK    (3 << 3)
 
+#define _TRANS_DP2_CTL_A                       0x600a0
+#define _TRANS_DP2_CTL_B                       0x610a0
+#define _TRANS_DP2_CTL_C                       0x620a0
+#define _TRANS_DP2_CTL_D                       0x630a0
+#define TRANS_DP2_CTL(trans)                   _MMIO_TRANS(trans, _TRANS_DP2_CTL_A, _TRANS_DP2_CTL_B)
+#define  TRANS_DP2_128B132B_CHANNEL_CODING     REG_BIT(31)
+#define  TRANS_DP2_PANEL_REPLAY_ENABLE         REG_BIT(30)
+#define  TRANS_DP2_DEBUG_ENABLE                        REG_BIT(23)
+
+#define _TRANS_DP2_VFREQHIGH_A                 0x600a4
+#define _TRANS_DP2_VFREQHIGH_B                 0x610a4
+#define _TRANS_DP2_VFREQHIGH_C                 0x620a4
+#define _TRANS_DP2_VFREQHIGH_D                 0x630a4
+#define TRANS_DP2_VFREQHIGH(trans)             _MMIO_TRANS(trans, _TRANS_DP2_VFREQHIGH_A, _TRANS_DP2_VFREQHIGH_B)
+#define  TRANS_DP2_VFREQ_PIXEL_CLOCK_MASK      REG_GENMASK(31, 8)
+#define  TRANS_DP2_VFREQ_PIXEL_CLOCK(clk_hz)   REG_FIELD_PREP(TRANS_DP2_VFREQ_PIXEL_CLOCK_MASK, (clk_hz))
+
+#define _TRANS_DP2_VFREQLOW_A                  0x600a8
+#define _TRANS_DP2_VFREQLOW_B                  0x610a8
+#define _TRANS_DP2_VFREQLOW_C                  0x620a8
+#define _TRANS_DP2_VFREQLOW_D                  0x630a8
+#define TRANS_DP2_VFREQLOW(trans)              _MMIO_TRANS(trans, _TRANS_DP2_VFREQLOW_A, _TRANS_DP2_VFREQLOW_B)
+
 /* SNB eDP training params */
 /* SNB A-stepping */
 #define  EDP_LINK_TRAIN_400MV_0DB_SNB_A                (0x38 << 22)
@@ -11611,6 +11628,14 @@ enum skl_power_gate {
                                                    _ICL_DSI_IO_MODECTL_1)
 #define  COMBO_PHY_MODE_DSI                            (1 << 0)
 
+/* TGL DSI Chicken register */
+#define _TGL_DSI_CHKN_REG_0                    0x6B0C0
+#define _TGL_DSI_CHKN_REG_1                    0x6B8C0
+#define TGL_DSI_CHKN_REG(port)         _MMIO_PORT(port,        \
+                                                   _TGL_DSI_CHKN_REG_0, \
+                                                   _TGL_DSI_CHKN_REG_1)
+#define TGL_DSI_CHKN_LSHS_GB                   REG_GENMASK(15, 12)
+
 /* Display Stream Splitter Control */
 #define DSS_CTL1                               _MMIO(0x67400)
 #define  SPLITTER_ENABLE                       (1 << 31)
index 65bc3709f54c5aa4b1a9b9b981c7da6d62287df2..cfc41f8fa74a743f85e0938149bf3627b36a8aba 100644 (file)
@@ -2859,6 +2859,7 @@ static void intel_read_wm_latency(struct drm_i915_private *dev_priv,
                u32 val;
                int ret, i;
                int level, max_level = ilk_wm_max_level(dev_priv);
+               int mult = IS_DG2(dev_priv) ? 2 : 1;
 
                /* read the first set of memory latencies[0:3] */
                val = 0; /* data0 to be programmed to 0 for first set */
@@ -2872,13 +2873,13 @@ static void intel_read_wm_latency(struct drm_i915_private *dev_priv,
                        return;
                }
 
-               wm[0] = val & GEN9_MEM_LATENCY_LEVEL_MASK;
-               wm[1] = (val >> GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT) &
-                               GEN9_MEM_LATENCY_LEVEL_MASK;
-               wm[2] = (val >> GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT) &
-                               GEN9_MEM_LATENCY_LEVEL_MASK;
-               wm[3] = (val >> GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT) &
-                               GEN9_MEM_LATENCY_LEVEL_MASK;
+               wm[0] = (val & GEN9_MEM_LATENCY_LEVEL_MASK) * mult;
+               wm[1] = ((val >> GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT) &
+                               GEN9_MEM_LATENCY_LEVEL_MASK) * mult;
+               wm[2] = ((val >> GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT) &
+                               GEN9_MEM_LATENCY_LEVEL_MASK) * mult;
+               wm[3] = ((val >> GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT) &
+                               GEN9_MEM_LATENCY_LEVEL_MASK) * mult;
 
                /* read the second set of memory latencies[4:7] */
                val = 1; /* data0 to be programmed to 1 for second set */
@@ -2891,13 +2892,13 @@ static void intel_read_wm_latency(struct drm_i915_private *dev_priv,
                        return;
                }
 
-               wm[4] = val & GEN9_MEM_LATENCY_LEVEL_MASK;
-               wm[5] = (val >> GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT) &
-                               GEN9_MEM_LATENCY_LEVEL_MASK;
-               wm[6] = (val >> GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT) &
-                               GEN9_MEM_LATENCY_LEVEL_MASK;
-               wm[7] = (val >> GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT) &
-                               GEN9_MEM_LATENCY_LEVEL_MASK;
+               wm[4] = (val & GEN9_MEM_LATENCY_LEVEL_MASK) * mult;
+               wm[5] = ((val >> GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT) &
+                               GEN9_MEM_LATENCY_LEVEL_MASK) * mult;
+               wm[6] = ((val >> GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT) &
+                               GEN9_MEM_LATENCY_LEVEL_MASK) * mult;
+               wm[7] = ((val >> GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT) &
+                               GEN9_MEM_LATENCY_LEVEL_MASK) * mult;
 
                /*
                 * If a level n (n > 1) has a 0us latency, all levels m (m >= n)
index 91f23b7f0af2ed075742752e2fa7930ebd5415b4..941b3ae555c8e9e5953679ddac6325917101e4ba 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <linux/types.h>
 
-#include "display/intel_bw.h"
 #include "display/intel_display.h"
 #include "display/intel_global_state.h"
 
@@ -19,6 +18,7 @@ struct drm_device;
 struct drm_i915_private;
 struct i915_request;
 struct intel_atomic_state;
+struct intel_bw_state;
 struct intel_crtc;
 struct intel_crtc_state;
 struct intel_plane;
index 183ea2b187fe9aa9361cc926dff6d1ef5db7cee9..47a85fab4130787067575ccbd2c7c2d374644083 100644 (file)
@@ -8,8 +8,6 @@
 
 #include <linux/types.h>
 
-#include "display/intel_display.h"
-
 #include "intel_wakeref.h"
 
 #include "i915_utils.h"
index 60d375e9c3c7cb12a8a1b74541f5ae7de65c5d3a..1a6b5e872b0d98ce5e34d1bc66cc26f02bbc4720 100644 (file)
@@ -4,6 +4,7 @@ menu "USB Type-C Alternate Mode drivers"
 
 config TYPEC_DP_ALTMODE
        tristate "DisplayPort Alternate Mode driver"
+       depends on DRM
        help
          DisplayPort USB Type-C Alternate Mode allows DisplayPort
          displays and adapters to be attached to the USB Type-C
index b7f094435b00ab58d71334281d770a1c5c6abd5b..c1d8c23baa399cdafcb64c628a49e7ab9e3909fd 100644 (file)
 #include <linux/delay.h>
 #include <linux/mutex.h>
 #include <linux/module.h>
+#include <linux/property.h>
 #include <linux/usb/pd_vdo.h>
 #include <linux/usb/typec_dp.h>
+#include <drm/drm_connector.h>
 #include "displayport.h"
 
 #define DP_HEADER(_dp, ver, cmd)       (VDO((_dp)->alt->svid, 1, ver, cmd)     \
@@ -57,19 +59,28 @@ struct dp_altmode {
        struct typec_displayport_data data;
 
        enum dp_state state;
+       bool hpd;
 
        struct mutex lock; /* device lock */
        struct work_struct work;
        struct typec_altmode *alt;
        const struct typec_altmode *port;
+       struct fwnode_handle *connector_fwnode;
 };
 
 static int dp_altmode_notify(struct dp_altmode *dp)
 {
-       u8 state = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf));
+       unsigned long conf;
+       u8 state;
+
+       if (dp->data.conf) {
+               state = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf));
+               conf = TYPEC_MODAL_STATE(state);
+       } else {
+               conf = TYPEC_STATE_USB;
+       }
 
-       return typec_altmode_notify(dp->alt, TYPEC_MODAL_STATE(state),
-                                  &dp->data);
+       return typec_altmode_notify(dp->alt, conf, &dp->data);
 }
 
 static int dp_altmode_configure(struct dp_altmode *dp, u8 con)
@@ -118,6 +129,7 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 con)
 static int dp_altmode_status_update(struct dp_altmode *dp)
 {
        bool configured = !!DP_CONF_GET_PIN_ASSIGN(dp->data.conf);
+       bool hpd = !!(dp->data.status & DP_STATUS_HPD_STATE);
        u8 con = DP_STATUS_CONNECTION(dp->data.status);
        int ret = 0;
 
@@ -130,6 +142,11 @@ static int dp_altmode_status_update(struct dp_altmode *dp)
                ret = dp_altmode_configure(dp, con);
                if (!ret)
                        dp->state = DP_STATE_CONFIGURE;
+       } else {
+               if (dp->hpd != hpd) {
+                       drm_connector_oob_hotplug_event(dp->connector_fwnode);
+                       dp->hpd = hpd;
+               }
        }
 
        return ret;
@@ -137,21 +154,10 @@ static int dp_altmode_status_update(struct dp_altmode *dp)
 
 static int dp_altmode_configured(struct dp_altmode *dp)
 {
-       int ret;
-
        sysfs_notify(&dp->alt->dev.kobj, "displayport", "configuration");
-
-       if (!dp->data.conf)
-               return typec_altmode_notify(dp->alt, TYPEC_STATE_USB,
-                                           &dp->data);
-
-       ret = dp_altmode_notify(dp);
-       if (ret)
-               return ret;
-
        sysfs_notify(&dp->alt->dev.kobj, "displayport", "pin_assignment");
 
-       return 0;
+       return dp_altmode_notify(dp);
 }
 
 static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf)
@@ -172,13 +178,8 @@ static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf)
        }
 
        ret = typec_altmode_vdm(dp->alt, header, &conf, 2);
-       if (ret) {
-               if (DP_CONF_GET_PIN_ASSIGN(dp->data.conf))
-                       dp_altmode_notify(dp);
-               else
-                       typec_altmode_notify(dp->alt, TYPEC_STATE_USB,
-                                            &dp->data);
-       }
+       if (ret)
+               dp_altmode_notify(dp);
 
        return ret;
 }
@@ -521,6 +522,7 @@ static const struct attribute_group dp_altmode_group = {
 int dp_altmode_probe(struct typec_altmode *alt)
 {
        const struct typec_altmode *port = typec_altmode_get_partner(alt);
+       struct fwnode_handle *fwnode;
        struct dp_altmode *dp;
        int ret;
 
@@ -549,6 +551,11 @@ int dp_altmode_probe(struct typec_altmode *alt)
        alt->desc = "DisplayPort";
        alt->ops = &dp_altmode_ops;
 
+       fwnode = dev_fwnode(alt->dev.parent->parent); /* typec_port fwnode */
+       dp->connector_fwnode = fwnode_find_reference(fwnode, "displayport", 0);
+       if (IS_ERR(dp->connector_fwnode))
+               dp->connector_fwnode = NULL;
+
        typec_altmode_set_drvdata(alt, dp);
 
        dp->state = DP_STATE_ENTER;
@@ -564,6 +571,13 @@ void dp_altmode_remove(struct typec_altmode *alt)
 
        sysfs_remove_group(&alt->dev.kobj, &dp_altmode_group);
        cancel_work_sync(&dp->work);
+
+       if (dp->connector_fwnode) {
+               if (dp->hpd)
+                       drm_connector_oob_hotplug_event(dp->connector_fwnode);
+
+               fwnode_handle_put(dp->connector_fwnode);
+       }
 }
 EXPORT_SYMBOL_GPL(dp_altmode_remove);
 
index 8ea8f079cde267282f8e6bfb5805f56232994fea..edca3703b9640ccf905cc627140535852806738c 100644 (file)
@@ -47,6 +47,8 @@ static bool use_bgrt = true;
 static bool request_mem_succeeded = false;
 static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
 
+static struct pci_dev *efifb_pci_dev;  /* dev with BAR covering the efifb */
+
 static struct fb_var_screeninfo efifb_defined = {
        .activate               = FB_ACTIVATE_NOW,
        .height                 = -1,
@@ -243,6 +245,9 @@ static inline void efifb_show_boot_graphics(struct fb_info *info) {}
 
 static void efifb_destroy(struct fb_info *info)
 {
+       if (efifb_pci_dev)
+               pm_runtime_put(&efifb_pci_dev->dev);
+
        if (info->screen_base) {
                if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
                        iounmap(info->screen_base);
@@ -333,7 +338,6 @@ ATTRIBUTE_GROUPS(efifb);
 
 static bool pci_dev_disabled;  /* FB base matches BAR of a disabled device */
 
-static struct pci_dev *efifb_pci_dev;  /* dev with BAR covering the efifb */
 static struct resource *bar_resource;
 static u64 bar_offset;
 
@@ -569,17 +573,22 @@ static int efifb_probe(struct platform_device *dev)
                pr_err("efifb: cannot allocate colormap\n");
                goto err_groups;
        }
+
+       if (efifb_pci_dev)
+               WARN_ON(pm_runtime_get_sync(&efifb_pci_dev->dev) < 0);
+
        err = register_framebuffer(info);
        if (err < 0) {
                pr_err("efifb: cannot register framebuffer\n");
-               goto err_fb_dealoc;
+               goto err_put_rpm_ref;
        }
        fb_info(info, "%s frame buffer device\n", info->fix.id);
-       if (efifb_pci_dev)
-               pm_runtime_get_sync(&efifb_pci_dev->dev);
        return 0;
 
-err_fb_dealoc:
+err_put_rpm_ref:
+       if (efifb_pci_dev)
+               pm_runtime_put(&efifb_pci_dev->dev);
+
        fb_dealloc_cmap(&info->cmap);
 err_groups:
        sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
@@ -603,8 +612,6 @@ static int efifb_remove(struct platform_device *pdev)
        unregister_framebuffer(info);
        sysfs_remove_groups(&pdev->dev.kobj, efifb_groups);
        framebuffer_release(info);
-       if (efifb_pci_dev)
-               pm_runtime_put(&efifb_pci_dev->dev);
 
        return 0;
 }
index 1647960c9e5063cb64a78a25e25112905690290e..379746d3266f0b4e3dabfd906b2c422ba1f15b5c 100644 (file)
@@ -590,6 +590,18 @@ struct drm_display_info {
         * @monitor_range: Frequency range supported by monitor range descriptor
         */
        struct drm_monitor_range_info monitor_range;
+
+       /**
+        * @mso_stream_count: eDP Multi-SST Operation (MSO) stream count from
+        * the DisplayID VESA vendor block. 0 for conventional Single-Stream
+        * Transport (SST), or 2 or 4 MSO streams.
+        */
+       u8 mso_stream_count;
+
+       /**
+        * @mso_pixel_overlap: eDP MSO segment pixel overlap, 0-8 pixels.
+        */
+       u8 mso_pixel_overlap;
 };
 
 int drm_display_info_set_bus_formats(struct drm_display_info *info,
@@ -1084,6 +1096,14 @@ struct drm_connector_funcs {
         */
        void (*atomic_print_state)(struct drm_printer *p,
                                   const struct drm_connector_state *state);
+
+       /**
+        * @oob_hotplug_event:
+        *
+        * This will get called when a hotplug-event for a drm-connector
+        * has been received from a source outside the display driver / device.
+        */
+       void (*oob_hotplug_event)(struct drm_connector *connector);
 };
 
 /**
@@ -1228,6 +1248,14 @@ struct drm_connector {
        struct device *kdev;
        /** @attr: sysfs attributes */
        struct device_attribute *attr;
+       /**
+        * @fwnode: associated fwnode supplied by platform firmware
+        *
+        * Drivers can set this to associate a fwnode with a connector, drivers
+        * are expected to get a reference on the fwnode when setting this.
+        * drm_connector_cleanup() will call fwnode_handle_put() on this.
+        */
+       struct fwnode_handle *fwnode;
 
        /**
         * @head:
@@ -1239,6 +1267,14 @@ struct drm_connector {
         */
        struct list_head head;
 
+       /**
+        * @global_connector_list_entry:
+        *
+        * Connector entry in the global connector-list, used by
+        * drm_connector_find_by_fwnode().
+        */
+       struct list_head global_connector_list_entry;
+
        /** @base: base KMS object */
        struct drm_mode_object base;
 
@@ -1650,6 +1686,7 @@ drm_connector_is_unregistered(struct drm_connector *connector)
                DRM_CONNECTOR_UNREGISTERED;
 }
 
+void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode);
 const char *drm_get_connector_type_name(unsigned int connector_type);
 const char *drm_get_connector_status_name(enum drm_connector_status status);
 const char *drm_get_subpixel_order_name(enum subpixel_order order);
index ec64d141f578e76a645fb89b024146da865ec04c..7ffbd9f7bfc7343f1ff6b90ac5831685b372c6da 100644 (file)
 #define DRM_DISPLAYID_H
 
 #include <linux/types.h>
+#include <linux/bits.h>
 
 struct edid;
 
-#define DATA_BLOCK_PRODUCT_ID 0x00
-#define DATA_BLOCK_DISPLAY_PARAMETERS 0x01
-#define DATA_BLOCK_COLOR_CHARACTERISTICS 0x02
-#define DATA_BLOCK_TYPE_1_DETAILED_TIMING 0x03
-#define DATA_BLOCK_TYPE_2_DETAILED_TIMING 0x04
-#define DATA_BLOCK_TYPE_3_SHORT_TIMING 0x05
-#define DATA_BLOCK_TYPE_4_DMT_TIMING 0x06
-#define DATA_BLOCK_VESA_TIMING 0x07
-#define DATA_BLOCK_CEA_TIMING 0x08
-#define DATA_BLOCK_VIDEO_TIMING_RANGE 0x09
-#define DATA_BLOCK_PRODUCT_SERIAL_NUMBER 0x0a
-#define DATA_BLOCK_GP_ASCII_STRING 0x0b
-#define DATA_BLOCK_DISPLAY_DEVICE_DATA 0x0c
-#define DATA_BLOCK_INTERFACE_POWER_SEQUENCING 0x0d
-#define DATA_BLOCK_TRANSFER_CHARACTERISTICS 0x0e
-#define DATA_BLOCK_DISPLAY_INTERFACE 0x0f
-#define DATA_BLOCK_STEREO_DISPLAY_INTERFACE 0x10
-#define DATA_BLOCK_TILED_DISPLAY 0x12
-#define DATA_BLOCK_CTA 0x81
-
-#define DATA_BLOCK_VENDOR_SPECIFIC 0x7f
-
-#define PRODUCT_TYPE_EXTENSION 0
-#define PRODUCT_TYPE_TEST 1
-#define PRODUCT_TYPE_PANEL 2
-#define PRODUCT_TYPE_MONITOR 3
-#define PRODUCT_TYPE_TV 4
-#define PRODUCT_TYPE_REPEATER 5
-#define PRODUCT_TYPE_DIRECT_DRIVE 6
+#define VESA_IEEE_OUI                          0x3a0292
+
+/* DisplayID Structure versions */
+#define DISPLAY_ID_STRUCTURE_VER_12            0x12
+#define DISPLAY_ID_STRUCTURE_VER_20            0x20
+
+/* DisplayID Structure v1r2 Data Blocks */
+#define DATA_BLOCK_PRODUCT_ID                  0x00
+#define DATA_BLOCK_DISPLAY_PARAMETERS          0x01
+#define DATA_BLOCK_COLOR_CHARACTERISTICS       0x02
+#define DATA_BLOCK_TYPE_1_DETAILED_TIMING      0x03
+#define DATA_BLOCK_TYPE_2_DETAILED_TIMING      0x04
+#define DATA_BLOCK_TYPE_3_SHORT_TIMING         0x05
+#define DATA_BLOCK_TYPE_4_DMT_TIMING           0x06
+#define DATA_BLOCK_VESA_TIMING                 0x07
+#define DATA_BLOCK_CEA_TIMING                  0x08
+#define DATA_BLOCK_VIDEO_TIMING_RANGE          0x09
+#define DATA_BLOCK_PRODUCT_SERIAL_NUMBER       0x0a
+#define DATA_BLOCK_GP_ASCII_STRING             0x0b
+#define DATA_BLOCK_DISPLAY_DEVICE_DATA         0x0c
+#define DATA_BLOCK_INTERFACE_POWER_SEQUENCING  0x0d
+#define DATA_BLOCK_TRANSFER_CHARACTERISTICS    0x0e
+#define DATA_BLOCK_DISPLAY_INTERFACE           0x0f
+#define DATA_BLOCK_STEREO_DISPLAY_INTERFACE    0x10
+#define DATA_BLOCK_TILED_DISPLAY               0x12
+#define DATA_BLOCK_VENDOR_SPECIFIC             0x7f
+#define DATA_BLOCK_CTA                         0x81
+
+/* DisplayID Structure v2r0 Data Blocks */
+#define DATA_BLOCK_2_PRODUCT_ID                        0x20
+#define DATA_BLOCK_2_DISPLAY_PARAMETERS                0x21
+#define DATA_BLOCK_2_TYPE_7_DETAILED_TIMING    0x22
+#define DATA_BLOCK_2_TYPE_8_ENUMERATED_TIMING  0x23
+#define DATA_BLOCK_2_TYPE_9_FORMULA_TIMING     0x24
+#define DATA_BLOCK_2_DYNAMIC_VIDEO_TIMING      0x25
+#define DATA_BLOCK_2_DISPLAY_INTERFACE_FEATURES        0x26
+#define DATA_BLOCK_2_STEREO_DISPLAY_INTERFACE  0x27
+#define DATA_BLOCK_2_TILED_DISPLAY_TOPOLOGY    0x28
+#define DATA_BLOCK_2_CONTAINER_ID              0x29
+#define DATA_BLOCK_2_VENDOR_SPECIFIC           0x7e
+#define DATA_BLOCK_2_CTA_DISPLAY_ID            0x81
+
+/* DisplayID Structure v1r2 Product Type */
+#define PRODUCT_TYPE_EXTENSION                 0
+#define PRODUCT_TYPE_TEST                      1
+#define PRODUCT_TYPE_PANEL                     2
+#define PRODUCT_TYPE_MONITOR                   3
+#define PRODUCT_TYPE_TV                                4
+#define PRODUCT_TYPE_REPEATER                  5
+#define PRODUCT_TYPE_DIRECT_DRIVE              6
+
+/* DisplayID Structure v2r0 Display Product Primary Use Case (~Product Type) */
+#define PRIMARY_USE_EXTENSION                  0
+#define PRIMARY_USE_TEST                       1
+#define PRIMARY_USE_GENERIC                    2
+#define PRIMARY_USE_TV                         3
+#define PRIMARY_USE_DESKTOP_PRODUCTIVITY       4
+#define PRIMARY_USE_DESKTOP_GAMING             5
+#define PRIMARY_USE_PRESENTATION               6
+#define PRIMARY_USE_HEAD_MOUNTED_VR            7
+#define PRIMARY_USE_HEAD_MOUNTED_AR            8
 
 struct displayid_header {
        u8 rev;
@@ -96,6 +129,16 @@ struct displayid_detailed_timing_block {
        struct displayid_detailed_timings_1 timings[];
 };
 
+#define DISPLAYID_VESA_MSO_OVERLAP     GENMASK(3, 0)
+#define DISPLAYID_VESA_MSO_MODE                GENMASK(6, 5)
+
+struct displayid_vesa_vendor_specific_block {
+       struct displayid_block base;
+       u8 oui[3];
+       u8 data_structure_type;
+       u8 mso;
+} __packed;
+
 /* DisplayID iteration */
 struct displayid_iter {
        const struct edid *edid;
index eee18fa53b54750340e9f8e3787789678f76e917..c00ac54692d704462be886d8ce32c08dcf81748c 100644 (file)
        INTEL_VGA_DEVICE(0x4905, info), \
        INTEL_VGA_DEVICE(0x4906, info), \
        INTEL_VGA_DEVICE(0x4907, info), \
-       INTEL_VGA_DEVICE(0x4908, info)
+       INTEL_VGA_DEVICE(0x4908, info), \
+       INTEL_VGA_DEVICE(0x4909, info)
 
 /* ADL-S */
 #define INTEL_ADLS_IDS(info) \
        INTEL_VGA_DEVICE(0x4680, info), \
-       INTEL_VGA_DEVICE(0x4681, info), \
        INTEL_VGA_DEVICE(0x4682, info), \
-       INTEL_VGA_DEVICE(0x4683, info), \
        INTEL_VGA_DEVICE(0x4688, info), \
-       INTEL_VGA_DEVICE(0x4689, info), \
+       INTEL_VGA_DEVICE(0x468A, info), \
        INTEL_VGA_DEVICE(0x4690, info), \
-       INTEL_VGA_DEVICE(0x4691, info), \
        INTEL_VGA_DEVICE(0x4692, info), \
        INTEL_VGA_DEVICE(0x4693, info)