mirror of
https://github.com/torvalds/linux.git
synced 2026-06-09 07:03:37 +02:00
Merge d1b803f4ca ("Merge drm/drm-next into drm-intel-next") into android-mainline
Steps on the way to 5.16-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I80ee3d85d9cc001253ea4a759885ed2299989f18
This commit is contained in:
commit
b57a50c79d
|
|
@ -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
|
||||
----
|
||||
|
|
|
|||
|
|
@ -65,6 +65,14 @@
|
|||
* 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 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
|
|||
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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -49,6 +50,11 @@
|
|||
(((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
|
||||
|
|
@ -4122,32 +4128,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)
|
||||
|
|
@ -5157,6 +5155,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
|
||||
*/
|
||||
|
|
@ -5180,6 +5243,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)
|
||||
|
|
@ -5258,6 +5324,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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -211,6 +211,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 \
|
||||
|
|
@ -247,6 +249,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 \
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -1657,9 +1679,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;
|
||||
|
||||
|
|
@ -1815,11 +1837,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);
|
||||
|
|
@ -1827,6 +1844,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;
|
||||
|
|
@ -2014,7 +2036,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;
|
||||
|
|
@ -2048,7 +2070,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);
|
||||
|
|
|
|||
|
|
@ -285,3 +285,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
1776
drivers/gpu/drm/i915/display/intel_backlight.c
Normal file
1776
drivers/gpu/drm/i915/display/intel_backlight.c
Normal file
File diff suppressed because it is too large
Load Diff
52
drivers/gpu/drm/i915/display/intel_backlight.h
Normal file
52
drivers/gpu/drm/i915/display/intel_backlight.h
Normal file
|
|
@ -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__ */
|
||||
|
|
@ -493,6 +493,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;
|
||||
|
|
@ -1511,110 +1514,6 @@ static u8 translate_iboost(u8 val)
|
|||
return mapping[val];
|
||||
}
|
||||
|
||||
static enum port get_port_by_ddc_pin(struct drm_i915_private *i915, u8 ddc_pin)
|
||||
{
|
||||
const struct ddi_vbt_port_info *info;
|
||||
enum port port;
|
||||
|
||||
if (!ddc_pin)
|
||||
return PORT_NONE;
|
||||
|
||||
for_each_port(port) {
|
||||
info = &i915->vbt.ddi_port_info[port];
|
||||
|
||||
if (info->devdata && ddc_pin == info->alternate_ddc_pin)
|
||||
return port;
|
||||
}
|
||||
|
||||
return PORT_NONE;
|
||||
}
|
||||
|
||||
static void sanitize_ddc_pin(struct drm_i915_private *i915,
|
||||
enum port port)
|
||||
{
|
||||
struct ddi_vbt_port_info *info = &i915->vbt.ddi_port_info[port];
|
||||
struct child_device_config *child;
|
||||
enum port p;
|
||||
|
||||
p = get_port_by_ddc_pin(i915, info->alternate_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(p), port_name(p));
|
||||
|
||||
/*
|
||||
* If we have multiple ports supposedly sharing the pin, then dvi/hdmi
|
||||
* couldn't exist on the shared port. Otherwise they share the same ddc
|
||||
* pin and system couldn't communicate with them separately.
|
||||
*
|
||||
* Give inverse child device order the priority, last one wins. Yes,
|
||||
* 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->device_type &= ~DEVICE_TYPE_TMDS_DVI_SIGNALING;
|
||||
child->device_type |= DEVICE_TYPE_NOT_HDMI_OUTPUT;
|
||||
|
||||
info->alternate_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;
|
||||
enum port port;
|
||||
|
||||
if (!aux_ch)
|
||||
return PORT_NONE;
|
||||
|
||||
for_each_port(port) {
|
||||
info = &i915->vbt.ddi_port_info[port];
|
||||
|
||||
if (info->devdata && aux_ch == info->alternate_aux_channel)
|
||||
return port;
|
||||
}
|
||||
|
||||
return PORT_NONE;
|
||||
}
|
||||
|
||||
static void sanitize_aux_ch(struct drm_i915_private *i915,
|
||||
enum port port)
|
||||
{
|
||||
struct ddi_vbt_port_info *info = &i915->vbt.ddi_port_info[port];
|
||||
struct child_device_config *child;
|
||||
enum port p;
|
||||
|
||||
p = get_port_by_aux_ch(i915, info->alternate_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(p), port_name(p));
|
||||
|
||||
/*
|
||||
* If we have multiple ports supposedly sharing the aux channel, then DP
|
||||
* couldn't exist on the shared port. Otherwise they share the same aux
|
||||
* channel and system couldn't communicate with them separately.
|
||||
*
|
||||
* Give inverse child device order the priority, last one wins. Yes,
|
||||
* 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->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,
|
||||
|
|
@ -1692,6 +1591,122 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static enum port get_port_by_ddc_pin(struct drm_i915_private *i915, u8 ddc_pin)
|
||||
{
|
||||
const struct intel_bios_encoder_data *devdata;
|
||||
enum port port;
|
||||
|
||||
if (!ddc_pin)
|
||||
return PORT_NONE;
|
||||
|
||||
for_each_port(port) {
|
||||
devdata = i915->vbt.ports[port];
|
||||
|
||||
if (devdata && ddc_pin == devdata->child.ddc_pin)
|
||||
return port;
|
||||
}
|
||||
|
||||
return PORT_NONE;
|
||||
}
|
||||
|
||||
static void sanitize_ddc_pin(struct intel_bios_encoder_data *devdata,
|
||||
enum port port)
|
||||
{
|
||||
struct drm_i915_private *i915 = devdata->i915;
|
||||
struct child_device_config *child;
|
||||
u8 mapped_ddc_pin;
|
||||
enum port p;
|
||||
|
||||
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), mapped_ddc_pin,
|
||||
port_name(p), port_name(p));
|
||||
|
||||
/*
|
||||
* If we have multiple ports supposedly sharing the pin, then dvi/hdmi
|
||||
* couldn't exist on the shared port. Otherwise they share the same ddc
|
||||
* pin and system couldn't communicate with them separately.
|
||||
*
|
||||
* Give inverse child device order the priority, last one wins. Yes,
|
||||
* 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 :(
|
||||
*/
|
||||
child = &i915->vbt.ports[p]->child;
|
||||
|
||||
child->device_type &= ~DEVICE_TYPE_TMDS_DVI_SIGNALING;
|
||||
child->device_type |= DEVICE_TYPE_NOT_HDMI_OUTPUT;
|
||||
|
||||
child->ddc_pin = 0;
|
||||
}
|
||||
|
||||
static enum port get_port_by_aux_ch(struct drm_i915_private *i915, u8 aux_ch)
|
||||
{
|
||||
const struct intel_bios_encoder_data *devdata;
|
||||
enum port port;
|
||||
|
||||
if (!aux_ch)
|
||||
return PORT_NONE;
|
||||
|
||||
for_each_port(port) {
|
||||
devdata = i915->vbt.ports[port];
|
||||
|
||||
if (devdata && aux_ch == devdata->child.aux_channel)
|
||||
return port;
|
||||
}
|
||||
|
||||
return PORT_NONE;
|
||||
}
|
||||
|
||||
static void sanitize_aux_ch(struct intel_bios_encoder_data *devdata,
|
||||
enum port port)
|
||||
{
|
||||
struct drm_i915_private *i915 = devdata->i915;
|
||||
struct child_device_config *child;
|
||||
enum port p;
|
||||
|
||||
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), devdata->child.aux_channel,
|
||||
port_name(p), port_name(p));
|
||||
|
||||
/*
|
||||
* If we have multiple ports supposedly sharing the aux channel, then DP
|
||||
* couldn't exist on the shared port. Otherwise they share the same aux
|
||||
* channel and system couldn't communicate with them separately.
|
||||
*
|
||||
* Give inverse child device order the priority, last one wins. Yes,
|
||||
* 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 :(
|
||||
*/
|
||||
child = &i915->vbt.ports[p]->child;
|
||||
|
||||
child->device_type &= ~DEVICE_TYPE_DISPLAYPORT_OUTPUT;
|
||||
child->aux_channel = 0;
|
||||
}
|
||||
|
||||
static enum port __dvo_port_to_port(int n_ports, int n_dvo,
|
||||
const int port_mapping[][3], u8 dvo_port)
|
||||
{
|
||||
|
|
@ -1825,6 +1840,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)
|
||||
{
|
||||
|
|
@ -1878,6 +1904,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)
|
||||
{
|
||||
/*
|
||||
|
|
@ -1895,9 +1947,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);
|
||||
|
|
@ -1911,9 +1962,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));
|
||||
|
|
@ -1938,62 +1987,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)
|
||||
sanitize_aux_ch(devdata, port);
|
||||
|
||||
if (is_dp) {
|
||||
info->alternate_aux_channel = child->aux_channel;
|
||||
|
||||
sanitize_aux_ch(i915, 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);
|
||||
|
|
@ -2008,19 +2019,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)
|
||||
|
|
@ -2558,12 +2563,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,
|
||||
|
|
@ -2814,8 +2815,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)))
|
||||
|
|
@ -2835,8 +2835,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;
|
||||
}
|
||||
|
|
@ -2852,8 +2851,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;
|
||||
}
|
||||
|
|
@ -2861,11 +2859,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,
|
||||
|
|
@ -2881,7 +2878,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;
|
||||
|
|
@ -2942,7 +2939,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;
|
||||
}
|
||||
|
|
@ -2956,17 +2953,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)
|
||||
|
|
@ -2988,15 +2986,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];
|
||||
|
||||
return i915->vbt.ddi_port_info[encoder->port].alternate_ddc_pin;
|
||||
if (!devdata || !devdata->child.ddc_pin)
|
||||
return 0;
|
||||
|
||||
return map_ddc_pin(i915, devdata->child.ddc_pin);
|
||||
}
|
||||
|
||||
bool intel_bios_encoder_supports_typec_usb(const struct intel_bios_encoder_data *devdata)
|
||||
|
|
@ -3012,5 +3015,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];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@
|
|||
#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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
bool lpsp_enabled = false;
|
||||
|
||||
if (DISPLAY_VER(i915) >= 13) {
|
||||
LPSP_STATUS(!intel_lpsp_power_well_enabled(i915,
|
||||
SKL_DISP_PW_2));
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -2392,6 +2455,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)
|
||||
|
|
@ -2410,8 +2475,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;
|
||||
|
|
@ -2419,7 +2485,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
|
||||
|
|
@ -2508,8 +2574,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;
|
||||
}
|
||||
|
||||
|
|
@ -4591,6 +4655,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,
|
||||
|
|
@ -4601,6 +4676,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 = {
|
||||
|
|
@ -4716,432 +4792,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)
|
||||
{
|
||||
|
|
@ -5200,7 +4850,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);
|
||||
|
|
@ -5233,7 +4886,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,
|
||||
|
|
@ -5295,8 +4948,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;
|
||||
|
|
@ -5312,28 +4963,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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,18 +523,25 @@ int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (msg_id == HDCP_2_2_REP_SEND_RECVID_LIST) {
|
||||
ret = get_receiver_id_list_size(dig_port);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
size = ret;
|
||||
}
|
||||
bytes_to_recv = size - 1;
|
||||
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_rx_info(dig_port, &dev_cnt, byte);
|
||||
if (ret < 0)
|
||||
return 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;
|
||||
|
||||
while (bytes_to_recv) {
|
||||
len = bytes_to_recv > DP_AUX_MAX_PAYLOAD_BYTES ?
|
||||
DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_recv;
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
|
||||
else {
|
||||
if (IS_G4X(dev_priv)) {
|
||||
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;
|
||||
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;
|
||||
WARN_ON(reduced_clock->p1 != clock->p1);
|
||||
} else {
|
||||
dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_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)
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
229
drivers/gpu/drm/i915/display/intel_dpt.c
Normal file
229
drivers/gpu/drm/i915/display/intel_dpt.c
Normal file
|
|
@ -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);
|
||||
}
|
||||
19
drivers/gpu/drm/i915/display/intel_dpt.h
Normal file
19
drivers/gpu/drm/i915/display/intel_dpt.h
Normal file
|
|
@ -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__ */
|
||||
437
drivers/gpu/drm/i915/display/intel_drrs.c
Normal file
437
drivers/gpu/drm/i915/display/intel_drrs.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
36
drivers/gpu/drm/i915/display/intel_drrs.h
Normal file
36
drivers/gpu/drm/i915/display/intel_drrs.h
Normal file
|
|
@ -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__ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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 @@ void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv,
|
|||
* 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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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,10 +93,36 @@ 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,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
{
|
||||
|
|
@ -145,6 +173,55 @@ int ilk_fdi_compute_config(struct intel_crtc *crtc,
|
|||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
|
|||
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",
|
||||
|
|
|
|||
|
|
@ -30,10 +30,9 @@
|
|||
#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;
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -9101,6 +9095,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)
|
||||
|
|
@ -11608,6 +11625,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)
|
||||
|
|
|
|||
|
|
@ -2871,6 +2871,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 */
|
||||
|
|
@ -2884,13 +2885,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 */
|
||||
|
|
@ -2903,13 +2904,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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "display/intel_display.h"
|
||||
|
||||
#include "intel_wakeref.h"
|
||||
|
||||
#include "i915_utils.h"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@
|
|||
#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;
|
||||
|
||||
return typec_altmode_notify(dp->alt, TYPEC_MODAL_STATE(state),
|
||||
&dp->data);
|
||||
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, 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -23,38 +23,71 @@
|
|||
#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 VESA_IEEE_OUI 0x3a0292
|
||||
|
||||
#define DATA_BLOCK_VENDOR_SPECIFIC 0x7f
|
||||
/* DisplayID Structure versions */
|
||||
#define DISPLAY_ID_STRUCTURE_VER_12 0x12
|
||||
#define DISPLAY_ID_STRUCTURE_VER_20 0x20
|
||||
|
||||
#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 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;
|
||||
|
|
|
|||
|
|
@ -632,18 +632,16 @@
|
|||
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)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user