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:
Greg Kroah-Hartman 2021-11-11 08:51:28 +01:00
commit b57a50c79d
70 changed files with 5095 additions and 4495 deletions

View File

@ -183,26 +183,23 @@ Frame Buffer Compression (FBC)
Display Refresh Rate Switching (DRRS)
-------------------------------------
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
:doc: Display Refresh Rate Switching (DRRS)
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
:functions: intel_dp_set_drrs_state
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
:functions: intel_drrs_enable
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
:functions: intel_edp_drrs_enable
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
:functions: intel_drrs_disable
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
:functions: intel_edp_drrs_disable
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
:functions: intel_drrs_invalidate
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
:functions: intel_edp_drrs_invalidate
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
:functions: intel_drrs_flush
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
:functions: intel_edp_drrs_flush
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c
:functions: intel_dp_drrs_init
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
:functions: intel_drrs_init
DPIO
----

View File

@ -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

View File

@ -58,6 +58,7 @@ struct drm_property;
struct edid;
struct kref;
struct work_struct;
struct fwnode_handle;
/* drm_crtc.c */
int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
@ -186,6 +187,7 @@ int drm_connector_set_obj_prop(struct drm_mode_object *obj,
int drm_connector_create_standard_properties(struct drm_device *dev);
const char *drm_get_connector_force_name(enum drm_connector_force force);
void drm_connector_free_work_fn(struct work_struct *work);
struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode);
/* IOCTL */
int drm_connector_property_set_ioctl(struct drm_device *dev,

View File

@ -28,6 +28,7 @@
* DEALINGS IN THE SOFTWARE.
*/
#include <linux/bitfield.h>
#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
@ -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;
}

View File

@ -10,6 +10,7 @@
* Copyright (c) 2003-2004 IBM Corp.
*/
#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
@ -50,8 +51,45 @@ static struct device_type drm_sysfs_device_minor = {
.name = "drm_minor"
};
static struct device_type drm_sysfs_device_connector = {
.name = "drm_connector",
};
struct class *drm_class;
#ifdef CONFIG_ACPI
static bool drm_connector_acpi_bus_match(struct device *dev)
{
return dev->type == &drm_sysfs_device_connector;
}
static struct acpi_device *drm_connector_acpi_find_companion(struct device *dev)
{
struct drm_connector *connector = to_drm_connector(dev);
return to_acpi_device_node(connector->fwnode);
}
static struct acpi_bus_type drm_connector_acpi_bus = {
.name = "drm_connector",
.match = drm_connector_acpi_bus_match,
.find_companion = drm_connector_acpi_find_companion,
};
static void drm_sysfs_acpi_register(void)
{
register_acpi_bus_type(&drm_connector_acpi_bus);
}
static void drm_sysfs_acpi_unregister(void)
{
unregister_acpi_bus_type(&drm_connector_acpi_bus);
}
#else
static void drm_sysfs_acpi_register(void) { }
static void drm_sysfs_acpi_unregister(void) { }
#endif
static char *drm_devnode(struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
@ -85,6 +123,8 @@ int drm_sysfs_init(void)
}
drm_class->devnode = drm_devnode;
drm_sysfs_acpi_register();
return 0;
}
@ -97,11 +137,17 @@ void drm_sysfs_destroy(void)
{
if (IS_ERR_OR_NULL(drm_class))
return;
drm_sysfs_acpi_unregister();
class_remove_file(drm_class, &class_attr_version.attr);
class_destroy(drm_class);
drm_class = NULL;
}
static void drm_sysfs_release(struct device *dev)
{
kfree(dev);
}
/*
* Connector properties
*/
@ -273,27 +319,47 @@ static const struct attribute_group *connector_dev_groups[] = {
int drm_sysfs_connector_add(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct device *kdev;
int r;
if (connector->kdev)
return 0;
connector->kdev =
device_create_with_groups(drm_class, dev->primary->kdev, 0,
connector, connector_dev_groups,
"card%d-%s", dev->primary->index,
connector->name);
kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
if (!kdev)
return -ENOMEM;
device_initialize(kdev);
kdev->class = drm_class;
kdev->type = &drm_sysfs_device_connector;
kdev->parent = dev->primary->kdev;
kdev->groups = connector_dev_groups;
kdev->release = drm_sysfs_release;
dev_set_drvdata(kdev, connector);
r = dev_set_name(kdev, "card%d-%s", dev->primary->index, connector->name);
if (r)
goto err_free;
DRM_DEBUG("adding \"%s\" to sysfs\n",
connector->name);
if (IS_ERR(connector->kdev)) {
DRM_ERROR("failed to register connector device: %ld\n", PTR_ERR(connector->kdev));
return PTR_ERR(connector->kdev);
r = device_add(kdev);
if (r) {
drm_err(dev, "failed to register connector device: %d\n", r);
goto err_free;
}
connector->kdev = kdev;
if (connector->ddc)
return sysfs_create_link(&connector->kdev->kobj,
&connector->ddc->dev.kobj, "ddc");
return 0;
err_free:
put_device(kdev);
return r;
}
void drm_sysfs_connector_remove(struct drm_connector *connector)
@ -374,11 +440,6 @@ void drm_sysfs_connector_status_event(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_sysfs_connector_status_event);
static void drm_sysfs_release(struct device *dev)
{
kfree(dev);
}
struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
{
const char *minor_str;

View File

@ -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 \

View File

@ -7,6 +7,7 @@
#include "g4x_dp.h"
#include "intel_audio.h"
#include "intel_backlight.h"
#include "intel_connector.h"
#include "intel_de.h"
#include "intel_display_types.h"
@ -16,7 +17,6 @@
#include "intel_fifo_underrun.h"
#include "intel_hdmi.h"
#include "intel_hotplug.h"
#include "intel_panel.h"
#include "intel_pps.h"
#include "intel_sideband.h"
@ -1334,7 +1334,7 @@ bool g4x_dp_init(struct drm_i915_private *dev_priv,
intel_encoder->get_config = intel_dp_get_config;
intel_encoder->sync_state = intel_dp_sync_state;
intel_encoder->initial_fastset_check = intel_dp_initial_fastset_check;
intel_encoder->update_pipe = intel_panel_update_backlight;
intel_encoder->update_pipe = intel_backlight_update;
intel_encoder->suspend = intel_dp_encoder_suspend;
intel_encoder->shutdown = intel_dp_encoder_shutdown;
if (IS_CHERRYVIEW(dev_priv)) {

View File

@ -29,6 +29,7 @@
#include <drm/drm_mipi_dsi.h>
#include "intel_atomic.h"
#include "intel_backlight.h"
#include "intel_combo_phy.h"
#include "intel_connector.h"
#include "intel_crtc.h"
@ -54,20 +55,28 @@ static int payload_credits_available(struct drm_i915_private *dev_priv,
>> FREE_PLOAD_CREDIT_SHIFT;
}
static void wait_for_header_credits(struct drm_i915_private *dev_priv,
enum transcoder dsi_trans)
static bool wait_for_header_credits(struct drm_i915_private *dev_priv,
enum transcoder dsi_trans, int hdr_credit)
{
if (wait_for_us(header_credits_available(dev_priv, dsi_trans) >=
MAX_HEADER_CREDIT, 100))
hdr_credit, 100)) {
drm_err(&dev_priv->drm, "DSI header credits not released\n");
return false;
}
return true;
}
static void wait_for_payload_credits(struct drm_i915_private *dev_priv,
enum transcoder dsi_trans)
static bool wait_for_payload_credits(struct drm_i915_private *dev_priv,
enum transcoder dsi_trans, int payld_credit)
{
if (wait_for_us(payload_credits_available(dev_priv, dsi_trans) >=
MAX_PLOAD_CREDIT, 100))
payld_credit, 100)) {
drm_err(&dev_priv->drm, "DSI payload credits not released\n");
return false;
}
return true;
}
static enum transcoder dsi_port_to_transcoder(enum port port)
@ -90,8 +99,8 @@ static void wait_for_cmds_dispatched_to_panel(struct intel_encoder *encoder)
/* wait for header/payload credits to be released */
for_each_dsi_port(port, intel_dsi->ports) {
dsi_trans = dsi_port_to_transcoder(port);
wait_for_header_credits(dev_priv, dsi_trans);
wait_for_payload_credits(dev_priv, dsi_trans);
wait_for_header_credits(dev_priv, dsi_trans, MAX_HEADER_CREDIT);
wait_for_payload_credits(dev_priv, dsi_trans, MAX_PLOAD_CREDIT);
}
/* send nop DCS command */
@ -108,7 +117,7 @@ static void wait_for_cmds_dispatched_to_panel(struct intel_encoder *encoder)
/* wait for header credits to be released */
for_each_dsi_port(port, intel_dsi->ports) {
dsi_trans = dsi_port_to_transcoder(port);
wait_for_header_credits(dev_priv, dsi_trans);
wait_for_header_credits(dev_priv, dsi_trans, MAX_HEADER_CREDIT);
}
/* wait for LP TX in progress bit to be cleared */
@ -126,18 +135,13 @@ static bool add_payld_to_queue(struct intel_dsi_host *host, const u8 *data,
struct intel_dsi *intel_dsi = host->intel_dsi;
struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
enum transcoder dsi_trans = dsi_port_to_transcoder(host->port);
int free_credits;
int i, j;
for (i = 0; i < len; i += 4) {
u32 tmp = 0;
free_credits = payload_credits_available(dev_priv, dsi_trans);
if (free_credits < 1) {
drm_err(&dev_priv->drm,
"Payload credit not available\n");
if (!wait_for_payload_credits(dev_priv, dsi_trans, 1))
return false;
}
for (j = 0; j < min_t(u32, len - i, 4); j++)
tmp |= *data++ << 8 * j;
@ -155,15 +159,10 @@ static int dsi_send_pkt_hdr(struct intel_dsi_host *host,
struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
enum transcoder dsi_trans = dsi_port_to_transcoder(host->port);
u32 tmp;
int free_credits;
/* check if header credit available */
free_credits = header_credits_available(dev_priv, dsi_trans);
if (free_credits < 1) {
drm_err(&dev_priv->drm,
"send pkt header failed, not enough hdr credits\n");
if (!wait_for_header_credits(dev_priv, dsi_trans, 1))
return -1;
}
tmp = intel_de_read(dev_priv, DSI_CMD_TXHDR(dsi_trans));
@ -1270,6 +1269,26 @@ static void icl_apply_kvmr_pipe_a_wa(struct intel_encoder *encoder,
IGNORE_KVMR_PIPE_A,
enable ? IGNORE_KVMR_PIPE_A : 0);
}
/*
* Wa_16012360555:adl-p
* SW will have to program the "LP to HS Wakeup Guardband"
* to account for the repeaters on the HS Request/Ready
* PPI signaling between the Display engine and the DPHY.
*/
static void adlp_set_lp_hs_wakeup_gb(struct intel_encoder *encoder)
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
enum port port;
if (DISPLAY_VER(i915) == 13) {
for_each_dsi_port(port, intel_dsi->ports)
intel_de_rmw(i915, TGL_DSI_CHKN_REG(port),
TGL_DSI_CHKN_LSHS_GB, 0x4);
}
}
static void gen11_dsi_enable(struct intel_atomic_state *state,
struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
@ -1283,11 +1302,14 @@ static void gen11_dsi_enable(struct intel_atomic_state *state,
/* Wa_1409054076:icl,jsl,ehl */
icl_apply_kvmr_pipe_a_wa(encoder, crtc->pipe, true);
/* Wa_16012360555:adl-p */
adlp_set_lp_hs_wakeup_gb(encoder);
/* step6d: enable dsi transcoder */
gen11_dsi_enable_transcoder(encoder);
/* step7: enable backlight */
intel_panel_enable_backlight(crtc_state, conn_state);
intel_backlight_enable(crtc_state, conn_state);
intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
intel_crtc_vblank_on(crtc_state);
@ -1440,7 +1462,7 @@ static void gen11_dsi_disable(struct intel_atomic_state *state,
/* step1: turn off backlight */
intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF);
intel_panel_disable_backlight(old_conn_state);
intel_backlight_disable(old_conn_state);
/* step2d,e: disable transcoder and wait */
gen11_dsi_disable_transcoder(encoder);
@ -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);

View File

@ -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);
}

View File

@ -13,6 +13,7 @@ void intel_register_dsm_handler(void);
void intel_unregister_dsm_handler(void);
void intel_dsm_get_bios_data_funcs_supported(struct drm_i915_private *i915);
void intel_acpi_device_id_update(struct drm_i915_private *i915);
void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915);
#else
static inline void intel_register_dsm_handler(void) { return; }
static inline void intel_unregister_dsm_handler(void) { return; }
@ -20,6 +21,8 @@ static inline
void intel_dsm_get_bios_data_funcs_supported(struct drm_i915_private *i915) { return; }
static inline
void intel_acpi_device_id_update(struct drm_i915_private *i915) { return; }
static inline
void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915) { return; }
#endif /* CONFIG_ACPI */
#endif /* __INTEL_ACPI_H__ */

File diff suppressed because it is too large Load Diff

View 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__ */

View File

@ -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];
}

View File

@ -2139,6 +2139,16 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state)
/* Account for additional needs from the planes */
min_cdclk = max(intel_planes_min_cdclk(crtc_state), min_cdclk);
/*
* VDSC engine can process only 1 pixel per Cd clock.
* In case VDSC is used and max slice count == 1,
* max supported pixel clock should be 100% of CD clock.
* Then do min_cdclk and pixel clock comparison to get cdclk.
*/
if (crtc_state->dsc.compression_enable &&
crtc_state->dsc.slice_count == 1)
min_cdclk = max(min_cdclk, (int)crtc_state->pixel_rate);
/*
* HACK. Currently for TGL platforms we calculate
* min_cdclk initially based on pixel_rate divided

View File

@ -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)
{

View File

@ -29,6 +29,7 @@
#include "i915_drv.h"
#include "intel_audio.h"
#include "intel_backlight.h"
#include "intel_combo_phy.h"
#include "intel_connector.h"
#include "intel_crtc.h"
@ -40,6 +41,7 @@
#include "intel_dp_link_training.h"
#include "intel_dp_mst.h"
#include "intel_dpio_phy.h"
#include "intel_drrs.h"
#include "intel_dsi.h"
#include "intel_fdi.h"
#include "intel_fifo_underrun.h"
@ -48,7 +50,6 @@
#include "intel_hdmi.h"
#include "intel_hotplug.h"
#include "intel_lspcon.h"
#include "intel_panel.h"
#include "intel_pps.h"
#include "intel_psr.h"
#include "intel_snps_phy.h"
@ -1371,7 +1372,8 @@ static int translate_signal_level(struct intel_dp *intel_dp,
return 0;
}
static int intel_ddi_dp_level(struct intel_dp *intel_dp)
static int intel_ddi_dp_level(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
u8 train_set = intel_dp->train_set[0];
u8 signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
@ -1385,9 +1387,9 @@ dg2_set_signal_levels(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
int level = intel_ddi_dp_level(intel_dp);
int level = intel_ddi_dp_level(intel_dp, crtc_state);
intel_snps_phy_ddi_vswing_sequence(encoder, level);
intel_snps_phy_ddi_vswing_sequence(encoder, crtc_state, level);
}
static void
@ -1395,7 +1397,7 @@ tgl_set_signal_levels(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
int level = intel_ddi_dp_level(intel_dp);
int level = intel_ddi_dp_level(intel_dp, crtc_state);
tgl_ddi_vswing_sequence(encoder, crtc_state, level);
}
@ -1405,7 +1407,7 @@ icl_set_signal_levels(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
int level = intel_ddi_dp_level(intel_dp);
int level = intel_ddi_dp_level(intel_dp, crtc_state);
icl_ddi_vswing_sequence(encoder, crtc_state, level);
}
@ -1415,7 +1417,7 @@ bxt_set_signal_levels(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
int level = intel_ddi_dp_level(intel_dp);
int level = intel_ddi_dp_level(intel_dp, crtc_state);
bxt_ddi_vswing_sequence(encoder, crtc_state, level);
}
@ -1426,7 +1428,7 @@ hsw_set_signal_levels(struct intel_dp *intel_dp,
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
int level = intel_ddi_dp_level(intel_dp);
int level = intel_ddi_dp_level(intel_dp, crtc_state);
enum port port = encoder->port;
u32 signal_levels;
@ -2332,7 +2334,7 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state,
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
int level = intel_ddi_dp_level(intel_dp);
int level = intel_ddi_dp_level(intel_dp, crtc_state);
intel_dp_set_link_params(intel_dp, crtc_state->port_clock,
crtc_state->lane_count);
@ -2391,7 +2393,7 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state,
*/
/* 5.e Configure voltage swing and related IO settings */
intel_snps_phy_ddi_vswing_sequence(encoder, level);
intel_snps_phy_ddi_vswing_sequence(encoder, crtc_state, level);
/*
* 5.f Configure and enable DDI_BUF_CTL
@ -2406,6 +2408,7 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state,
if (!is_mst)
intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
intel_dp_configure_protocol_converter(intel_dp, crtc_state);
intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true);
/*
* DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit
@ -2413,6 +2416,8 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state,
* training
*/
intel_dp_sink_set_fec_ready(intel_dp, crtc_state);
intel_dp_check_frl_training(intel_dp);
intel_dp_pcon_dsc_configure(intel_dp, crtc_state);
/*
* 5.h Follow DisplayPort specification training sequence (see notes for
@ -2442,7 +2447,7 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
int level = intel_ddi_dp_level(intel_dp);
int level = intel_ddi_dp_level(intel_dp, crtc_state);
intel_dp_set_link_params(intel_dp,
crtc_state->port_clock,
@ -2585,7 +2590,7 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
enum phy phy = intel_port_to_phy(dev_priv, port);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
int level = intel_ddi_dp_level(intel_dp);
int level = intel_ddi_dp_level(intel_dp, crtc_state);
if (DISPLAY_VER(dev_priv) < 11)
drm_WARN_ON(&dev_priv->drm,
@ -3010,7 +3015,7 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state,
if (!dig_port->lspcon.active || dig_port->dp.has_hdmi_sink)
intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
intel_edp_drrs_enable(intel_dp, crtc_state);
intel_drrs_enable(intel_dp, crtc_state);
if (crtc_state->has_audio)
intel_audio_codec_enable(encoder, crtc_state, conn_state);
@ -3057,7 +3062,7 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state,
connector->base.id, connector->name);
if (IS_DG2(dev_priv))
intel_snps_phy_ddi_vswing_sequence(encoder, U32_MAX);
intel_snps_phy_ddi_vswing_sequence(encoder, crtc_state, level);
else if (DISPLAY_VER(dev_priv) >= 12)
tgl_ddi_vswing_sequence(encoder, crtc_state, level);
else if (DISPLAY_VER(dev_priv) == 11)
@ -3198,7 +3203,7 @@ static void intel_pre_disable_ddi(struct intel_atomic_state *state,
return;
intel_dp = enc_to_intel_dp(encoder);
intel_edp_drrs_disable(intel_dp, old_crtc_state);
intel_drrs_disable(intel_dp, old_crtc_state);
intel_psr_disable(intel_dp, old_crtc_state);
}
@ -3228,9 +3233,9 @@ static void intel_ddi_update_pipe_dp(struct intel_atomic_state *state,
intel_psr_update(intel_dp, crtc_state, conn_state);
intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
intel_edp_drrs_update(intel_dp, crtc_state);
intel_drrs_update(intel_dp, crtc_state);
intel_panel_update_backlight(state, encoder, crtc_state, conn_state);
intel_backlight_update(state, encoder, crtc_state, conn_state);
}
void intel_ddi_update_pipe(struct intel_atomic_state *state,

View File

@ -983,6 +983,49 @@ static const struct intel_ddi_buf_trans adlp_dkl_phy_ddi_translations_dp_hbr2_hb
.num_entries = ARRAY_SIZE(_adlp_dkl_phy_ddi_translations_dp_hbr2_hbr3),
};
static const union intel_ddi_buf_trans_entry _dg2_snps_translations[] = {
{ .snps = { 26, 0, 0 } }, /* VS 0, pre-emph 0 */
{ .snps = { 33, 0, 6 } }, /* VS 0, pre-emph 1 */
{ .snps = { 38, 0, 12 } }, /* VS 0, pre-emph 2 */
{ .snps = { 43, 0, 19 } }, /* VS 0, pre-emph 3 */
{ .snps = { 39, 0, 0 } }, /* VS 1, pre-emph 0 */
{ .snps = { 44, 0, 8 } }, /* VS 1, pre-emph 1 */
{ .snps = { 47, 0, 15 } }, /* VS 1, pre-emph 2 */
{ .snps = { 52, 0, 0 } }, /* VS 2, pre-emph 0 */
{ .snps = { 51, 0, 10 } }, /* VS 2, pre-emph 1 */
{ .snps = { 62, 0, 0 } }, /* VS 3, pre-emph 0 */
};
static const struct intel_ddi_buf_trans dg2_snps_translations = {
.entries = _dg2_snps_translations,
.num_entries = ARRAY_SIZE(_dg2_snps_translations),
.hdmi_default_entry = ARRAY_SIZE(_dg2_snps_translations) - 1,
};
static const union intel_ddi_buf_trans_entry _dg2_snps_translations_uhbr[] = {
{ .snps = { 62, 0, 0 } }, /* preset 0 */
{ .snps = { 56, 0, 6 } }, /* preset 1 */
{ .snps = { 51, 0, 11 } }, /* preset 2 */
{ .snps = { 48, 0, 14 } }, /* preset 3 */
{ .snps = { 43, 0, 19 } }, /* preset 4 */
{ .snps = { 59, 3, 0 } }, /* preset 5 */
{ .snps = { 53, 3, 6 } }, /* preset 6 */
{ .snps = { 49, 3, 10 } }, /* preset 7 */
{ .snps = { 45, 3, 14 } }, /* preset 8 */
{ .snps = { 42, 3, 17 } }, /* preset 9 */
{ .snps = { 56, 6, 0 } }, /* preset 10 */
{ .snps = { 50, 6, 6 } }, /* preset 11 */
{ .snps = { 47, 6, 9 } }, /* preset 12 */
{ .snps = { 42, 6, 14 } }, /* preset 13 */
{ .snps = { 46, 8, 8 } }, /* preset 14 */
{ .snps = { 56, 3, 3 } }, /* preset 15 */
};
static const struct intel_ddi_buf_trans dg2_snps_translations_uhbr = {
.entries = _dg2_snps_translations_uhbr,
.num_entries = ARRAY_SIZE(_dg2_snps_translations_uhbr),
};
bool is_hobl_buf_trans(const struct intel_ddi_buf_trans *table)
{
return table == &tgl_combo_phy_ddi_translations_edp_hbr2_hobl;
@ -1563,6 +1606,17 @@ adlp_get_dkl_buf_trans(struct intel_encoder *encoder,
return adlp_get_dkl_buf_trans_dp(encoder, crtc_state, n_entries);
}
static const struct intel_ddi_buf_trans *
dg2_get_snps_buf_trans(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
int *n_entries)
{
if (crtc_state->port_clock > 1000000)
return intel_get_buf_trans(&dg2_snps_translations_uhbr, n_entries);
else
return intel_get_buf_trans(&dg2_snps_translations, n_entries);
}
int intel_ddi_hdmi_num_entries(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
int *default_entry)
@ -1588,7 +1642,9 @@ void intel_ddi_buf_trans_init(struct intel_encoder *encoder)
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
enum phy phy = intel_port_to_phy(i915, encoder->port);
if (IS_ALDERLAKE_P(i915)) {
if (IS_DG2(i915)) {
encoder->get_buf_trans = dg2_get_snps_buf_trans;
} else if (IS_ALDERLAKE_P(i915)) {
if (intel_phy_is_combo(i915, phy))
encoder->get_buf_trans = adlp_get_combo_buf_trans;
else

View File

@ -45,12 +45,19 @@ struct tgl_dkl_phy_ddi_buf_trans {
u32 dkl_de_emphasis_control;
};
struct dg2_snps_phy_buf_trans {
u8 snps_vswing;
u8 snps_pre_cursor;
u8 snps_post_cursor;
};
union intel_ddi_buf_trans_entry {
struct hsw_ddi_buf_trans hsw;
struct bxt_ddi_buf_trans bxt;
struct icl_ddi_buf_trans icl;
struct icl_mg_phy_ddi_buf_trans mg;
struct tgl_dkl_phy_ddi_buf_trans dkl;
struct dg2_snps_phy_buf_trans snps;
};
struct intel_ddi_buf_trans {

File diff suppressed because it is too large Load Diff

View File

@ -548,8 +548,6 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv);
unsigned int intel_fb_xy_to_linear(int x, int y,
const struct intel_plane_state *state,
int plane);
unsigned int intel_fb_align_height(const struct drm_framebuffer *fb,
int color_plane, unsigned int height);
void intel_add_fb_offsets(int *x, int *y,
const struct intel_plane_state *state, int plane);
unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info);
@ -630,10 +628,6 @@ struct intel_encoder *
intel_get_crtc_new_encoder(const struct intel_atomic_state *state,
const struct intel_crtc_state *crtc_state);
unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
int color_plane);
unsigned int intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane);
void intel_display_driver_register(struct drm_i915_private *i915);
void intel_display_driver_unregister(struct drm_i915_private *i915);

View File

@ -13,6 +13,7 @@
#include "intel_display_types.h"
#include "intel_dmc.h"
#include "intel_dp.h"
#include "intel_drrs.h"
#include "intel_fbc.h"
#include "intel_hdcp.h"
#include "intel_hdmi.h"
@ -1323,9 +1324,6 @@ static int i915_drrs_status(struct seq_file *m, void *unused)
return 0;
}
#define LPSP_STATUS(COND) (COND ? seq_puts(m, "LPSP: enabled\n") : \
seq_puts(m, "LPSP: disabled\n"))
static bool
intel_lpsp_power_well_enabled(struct drm_i915_private *i915,
enum i915_power_well_id power_well_id)
@ -1344,32 +1342,20 @@ intel_lpsp_power_well_enabled(struct drm_i915_private *i915,
static int i915_lpsp_status(struct seq_file *m, void *unused)
{
struct drm_i915_private *i915 = node_to_i915(m->private);
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;
}

View File

@ -428,10 +428,6 @@ struct intel_hdcp_shim {
int (*hdcp_2_2_capable)(struct intel_digital_port *dig_port,
bool *capable);
/* Detects whether a HDCP 1.4 sink connected in MST topology */
int (*streams_type1_capable)(struct intel_connector *connector,
bool *capable);
/* Write HDCP2.2 messages */
int (*write_2_2_msg)(struct intel_digital_port *dig_port,
void *buf, size_t size);
@ -1684,6 +1680,8 @@ struct intel_digital_port {
bool hdcp_auth_status;
/* HDCP port data need to pass to security f/w */
struct hdcp_port_data hdcp_port_data;
/* Whether the MST topology supports HDCP Type 1 Content */
bool hdcp_mst_type1_capable;
void (*write_infoframe)(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
@ -2035,28 +2033,6 @@ to_intel_frontbuffer(struct drm_framebuffer *fb)
return fb ? to_intel_framebuffer(fb)->frontbuffer : NULL;
}
static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
{
if (dev_priv->params.panel_use_ssc >= 0)
return dev_priv->params.panel_use_ssc != 0;
return dev_priv->vbt.lvds_use_ssc
&& !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
}
static inline u32 i9xx_dpll_compute_fp(struct dpll *dpll)
{
return dpll->n << 16 | dpll->m1 << 8 | dpll->m2;
}
static inline u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv,
const struct intel_crtc_state *pipe_config)
{
if (HAS_DDI(dev_priv))
return pipe_config->port_clock; /* SPLL */
else
return dev_priv->fdi_pll_freq;
}
static inline bool is_ccs_modifier(u64 modifier)
{
return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||

View File

@ -44,6 +44,7 @@
#include "i915_drv.h"
#include "intel_atomic.h"
#include "intel_audio.h"
#include "intel_backlight.h"
#include "intel_connector.h"
#include "intel_ddi.h"
#include "intel_de.h"
@ -55,6 +56,7 @@
#include "intel_dp_mst.h"
#include "intel_dpio_phy.h"
#include "intel_dpll.h"
#include "intel_drrs.h"
#include "intel_fifo_underrun.h"
#include "intel_hdcp.h"
#include "intel_hdmi.h"
@ -100,6 +102,8 @@ static const u8 valid_dsc_slicecount[] = {1, 2, 4};
*
* If a CPU or PCH DP output is attached to an eDP panel, this function
* will return true, and false otherwise.
*
* This function is not safe to use prior to encoder type being set.
*/
bool intel_dp_is_edp(struct intel_dp *intel_dp)
{
@ -141,6 +145,26 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
intel_dp->sink_rates[i] = dp_rates[i];
}
/*
* Sink rates for 128b/132b. If set, sink should support all 8b/10b
* rates and 10 Gbps.
*/
if (intel_dp->dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_128B132B) {
u8 uhbr_rates = 0;
BUILD_BUG_ON(ARRAY_SIZE(intel_dp->sink_rates) < ARRAY_SIZE(dp_rates) + 3);
drm_dp_dpcd_readb(&intel_dp->aux,
DP_128B132B_SUPPORTED_LINK_RATES, &uhbr_rates);
if (uhbr_rates & DP_UHBR10)
intel_dp->sink_rates[i++] = 1000000;
if (uhbr_rates & DP_UHBR13_5)
intel_dp->sink_rates[i++] = 1350000;
if (uhbr_rates & DP_UHBR20)
intel_dp->sink_rates[i++] = 2000000;
}
intel_dp->num_sink_rates = i;
}
@ -192,6 +216,10 @@ int intel_dp_max_lane_count(struct intel_dp *intel_dp)
return intel_dp->max_link_lane_count;
}
/*
* The required data bandwidth for a mode with given pixel clock and bpp. This
* is the required net bandwidth independent of the data bandwidth efficiency.
*/
int
intel_dp_link_required(int pixel_clock, int bpp)
{
@ -199,16 +227,52 @@ intel_dp_link_required(int pixel_clock, int bpp)
return DIV_ROUND_UP(pixel_clock * bpp, 8);
}
/*
* Given a link rate and lanes, get the data bandwidth.
*
* Data bandwidth is the actual payload rate, which depends on the data
* bandwidth efficiency and the link rate.
*
* For 8b/10b channel encoding, SST and non-FEC, the data bandwidth efficiency
* is 80%. For example, for a 1.62 Gbps link, 1.62*10^9 bps * 0.80 * (1/8) =
* 162000 kBps. With 8-bit symbols, we have 162000 kHz symbol clock. Just by
* coincidence, the port clock in kHz matches the data bandwidth in kBps, and
* they equal the link bit rate in Gbps multiplied by 100000. (Note that this no
* longer holds for data bandwidth as soon as FEC or MST is taken into account!)
*
* For 128b/132b channel encoding, the data bandwidth efficiency is 96.71%. For
* example, for a 10 Gbps link, 10*10^9 bps * 0.9671 * (1/8) = 1208875
* kBps. With 32-bit symbols, we have 312500 kHz symbol clock. The value 1000000
* does not match the symbol clock, the port clock (not even if you think in
* terms of a byte clock), nor the data bandwidth. It only matches the link bit
* rate in units of 10000 bps.
*/
int
intel_dp_max_data_rate(int max_link_clock, int max_lanes)
intel_dp_max_data_rate(int max_link_rate, int max_lanes)
{
/* max_link_clock is the link symbol clock (LS_Clk) in kHz and not the
* link rate that is generally expressed in Gbps. Since, 8 bits of data
* is transmitted every LS_Clk per lane, there is no need to account for
* the channel encoding that is done in the PHY layer here.
if (max_link_rate >= 1000000) {
/*
* UHBR rates always use 128b/132b channel encoding, and have
* 97.71% data bandwidth efficiency. Consider max_link_rate the
* link bit rate in units of 10000 bps.
*/
int max_link_rate_kbps = max_link_rate * 10;
max_link_rate_kbps = DIV_ROUND_CLOSEST_ULL(max_link_rate_kbps * 9671, 10000);
max_link_rate = max_link_rate_kbps / 8;
}
/*
* Lower than UHBR rates always use 8b/10b channel encoding, and have
* 80% data bandwidth efficiency for SST non-FEC. However, this turns
* out to be a nop by coincidence, and can be skipped:
*
* int max_link_rate_kbps = max_link_rate * 10;
* max_link_rate_kbps = DIV_ROUND_CLOSEST_ULL(max_link_rate_kbps * 8, 10);
* max_link_rate = max_link_rate_kbps / 8;
*/
return max_link_clock * max_lanes;
return max_link_rate * max_lanes;
}
bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp)
@ -222,6 +286,20 @@ bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp)
encoder->port != PORT_A);
}
static int dg2_max_source_rate(struct intel_dp *intel_dp)
{
return intel_dp_is_edp(intel_dp) ? 810000 : 1350000;
}
static bool is_low_voltage_sku(struct drm_i915_private *i915, enum phy phy)
{
u32 voltage;
voltage = intel_de_read(i915, ICL_PORT_COMP_DW3(phy)) & VOLTAGE_INFO_MASK;
return voltage == VOLTAGE_INFO_0_85V;
}
static int icl_max_source_rate(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
@ -229,7 +307,7 @@ static int icl_max_source_rate(struct intel_dp *intel_dp)
enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port);
if (intel_phy_is_combo(dev_priv, phy) &&
!intel_dp_is_edp(intel_dp))
(is_low_voltage_sku(dev_priv, phy) || !intel_dp_is_edp(intel_dp)))
return 540000;
return 810000;
@ -237,7 +315,23 @@ static int icl_max_source_rate(struct intel_dp *intel_dp)
static int ehl_max_source_rate(struct intel_dp *intel_dp)
{
if (intel_dp_is_edp(intel_dp))
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port);
if (intel_dp_is_edp(intel_dp) || is_low_voltage_sku(dev_priv, phy))
return 540000;
return 810000;
}
static int dg1_max_source_rate(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
if (intel_phy_is_combo(i915, phy) && is_low_voltage_sku(i915, phy))
return 540000;
return 810000;
@ -248,7 +342,8 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp)
{
/* The values must be in increasing order */
static const int icl_rates[] = {
162000, 216000, 270000, 324000, 432000, 540000, 648000, 810000
162000, 216000, 270000, 324000, 432000, 540000, 648000, 810000,
1000000, 1350000,
};
static const int bxt_rates[] = {
162000, 216000, 243000, 270000, 324000, 432000, 540000
@ -275,7 +370,12 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp)
if (DISPLAY_VER(dev_priv) >= 11) {
source_rates = icl_rates;
size = ARRAY_SIZE(icl_rates);
if (IS_JSL_EHL(dev_priv))
if (IS_DG2(dev_priv))
max_rate = dg2_max_source_rate(intel_dp);
else if (IS_ALDERLAKE_P(dev_priv) || IS_ALDERLAKE_S(dev_priv) ||
IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv))
max_rate = dg1_max_source_rate(intel_dp);
else if (IS_JSL_EHL(dev_priv))
max_rate = ehl_max_source_rate(intel_dp);
else
max_rate = icl_max_source_rate(intel_dp);
@ -461,7 +561,9 @@ u32 intel_dp_mode_to_fec_clock(u32 mode_clock)
static int
small_joiner_ram_size_bits(struct drm_i915_private *i915)
{
if (DISPLAY_VER(i915) >= 11)
if (DISPLAY_VER(i915) >= 13)
return 17280 * 8;
else if (DISPLAY_VER(i915) >= 11)
return 7680 * 8;
else
return 6144 * 8;
@ -1044,7 +1146,8 @@ intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
intel_dp->num_common_rates,
intel_dp->compliance.test_link_rate);
if (index >= 0)
limits->min_clock = limits->max_clock = index;
limits->min_rate = limits->max_rate =
intel_dp->compliance.test_link_rate;
limits->min_lane_count = limits->max_lane_count =
intel_dp->compliance.test_lane_count;
}
@ -1058,8 +1161,8 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
const struct link_config_limits *limits)
{
struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
int bpp, clock, lane_count;
int mode_rate, link_clock, link_avail;
int bpp, i, lane_count;
int mode_rate, link_rate, link_avail;
for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
int output_bpp = intel_dp_output_bpp(pipe_config->output_format, bpp);
@ -1067,18 +1170,22 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
output_bpp);
for (clock = limits->min_clock; clock <= limits->max_clock; clock++) {
for (i = 0; i < intel_dp->num_common_rates; i++) {
link_rate = intel_dp->common_rates[i];
if (link_rate < limits->min_rate ||
link_rate > limits->max_rate)
continue;
for (lane_count = limits->min_lane_count;
lane_count <= limits->max_lane_count;
lane_count <<= 1) {
link_clock = intel_dp->common_rates[clock];
link_avail = intel_dp_max_data_rate(link_clock,
link_avail = intel_dp_max_data_rate(link_rate,
lane_count);
if (mode_rate <= link_avail) {
pipe_config->lane_count = lane_count;
pipe_config->pipe_bpp = bpp;
pipe_config->port_clock = link_clock;
pipe_config->port_clock = link_rate;
return 0;
}
@ -1212,7 +1319,7 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
* with DSC enabled for the requested mode.
*/
pipe_config->pipe_bpp = pipe_bpp;
pipe_config->port_clock = intel_dp->common_rates[limits->max_clock];
pipe_config->port_clock = limits->max_rate;
pipe_config->lane_count = limits->max_lane_count;
if (intel_dp_is_edp(intel_dp)) {
@ -1321,8 +1428,8 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
/* No common link rates between source and sink */
drm_WARN_ON(encoder->base.dev, common_len <= 0);
limits.min_clock = 0;
limits.max_clock = common_len - 1;
limits.min_rate = intel_dp->common_rates[0];
limits.max_rate = intel_dp->common_rates[common_len - 1];
limits.min_lane_count = 1;
limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
@ -1340,15 +1447,14 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
* values correspond to the native resolution of the panel.
*/
limits.min_lane_count = limits.max_lane_count;
limits.min_clock = limits.max_clock;
limits.min_rate = limits.max_rate;
}
intel_dp_adjust_compliance_config(intel_dp, pipe_config, &limits);
drm_dbg_kms(&i915->drm, "DP link computation with max lane count %i "
"max rate %d max bpp %d pixel clock %iKHz\n",
limits.max_lane_count,
intel_dp->common_rates[limits.max_clock],
limits.max_lane_count, limits.max_rate,
limits.max_bpp, adjusted_mode->crtc_clock);
if ((adjusted_mode->crtc_clock > i915->max_dotclk_freq ||
@ -1603,46 +1709,6 @@ intel_dp_compute_hdr_metadata_infoframe_sdp(struct intel_dp *intel_dp,
intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_METADATA);
}
static void
intel_dp_drrs_compute_config(struct intel_dp *intel_dp,
struct intel_crtc_state *pipe_config,
int output_bpp, bool constant_n)
{
struct intel_connector *intel_connector = intel_dp->attached_connector;
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
int pixel_clock;
if (pipe_config->vrr.enable)
return;
/*
* DRRS and PSR can't be enable together, so giving preference to PSR
* as it allows more power-savings by complete shutting down display,
* so to guarantee this, intel_dp_drrs_compute_config() must be called
* after intel_psr_compute_config().
*/
if (pipe_config->has_psr)
return;
if (!intel_connector->panel.downclock_mode ||
dev_priv->drrs.type != SEAMLESS_DRRS_SUPPORT)
return;
pipe_config->has_drrs = true;
pixel_clock = intel_connector->panel.downclock_mode->clock;
if (pipe_config->splitter.enable)
pixel_clock /= pipe_config->splitter.link_count;
intel_link_compute_m_n(output_bpp, pipe_config->lane_count, pixel_clock,
pipe_config->port_clock, &pipe_config->dp_m2_n2,
constant_n, pipe_config->fec_enable);
/* FIXME: abstract this better */
if (pipe_config->splitter.enable)
pipe_config->dp_m2_n2.gmch_m *= pipe_config->splitter.link_count;
}
int
intel_dp_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
@ -1665,7 +1731,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
adjusted_mode);
if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
ret = intel_pch_panel_fitting(pipe_config, conn_state);
ret = intel_panel_fitting(pipe_config, conn_state);
if (ret)
return ret;
}
@ -1678,13 +1744,10 @@ intel_dp_compute_config(struct intel_encoder *encoder,
pipe_config->has_audio = intel_conn_state->force_audio == HDMI_AUDIO_ON;
if (intel_dp_is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
intel_panel_fixed_mode(intel_connector->panel.fixed_mode,
adjusted_mode);
if (HAS_GMCH(dev_priv))
ret = intel_gmch_panel_fitting(pipe_config, conn_state);
else
ret = intel_pch_panel_fitting(pipe_config, conn_state);
ret = intel_panel_fitting(pipe_config, conn_state);
if (ret)
return ret;
}
@ -1751,8 +1814,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
intel_vrr_compute_config(pipe_config, conn_state);
intel_psr_compute_config(intel_dp, pipe_config);
intel_dp_drrs_compute_config(intel_dp, pipe_config, output_bpp,
constant_n);
intel_drrs_compute_config(intel_dp, pipe_config, output_bpp,
constant_n);
intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state);
@ -1779,7 +1842,7 @@ void intel_edp_backlight_on(const struct intel_crtc_state *crtc_state,
drm_dbg_kms(&i915->drm, "\n");
intel_panel_enable_backlight(crtc_state, conn_state);
intel_backlight_enable(crtc_state, conn_state);
intel_pps_backlight_on(intel_dp);
}
@ -1795,7 +1858,7 @@ void intel_edp_backlight_off(const struct drm_connector_state *old_conn_state)
drm_dbg_kms(&i915->drm, "\n");
intel_pps_backlight_off(intel_dp);
intel_panel_disable_backlight(old_conn_state);
intel_backlight_disable(old_conn_state);
}
static bool downstream_hpd_needs_d0(struct intel_dp *intel_dp)
@ -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",

View File

@ -26,7 +26,7 @@ struct intel_dp;
struct intel_encoder;
struct link_config_limits {
int min_clock, max_clock;
int min_rate, max_rate;
int min_lane_count, max_lane_count;
int min_bpp, max_bpp;
};
@ -70,17 +70,6 @@ int intel_dp_max_link_rate(struct intel_dp *intel_dp);
int intel_dp_max_lane_count(struct intel_dp *intel_dp);
int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
void intel_edp_drrs_enable(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state);
void intel_edp_drrs_disable(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state);
void intel_edp_drrs_update(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state);
void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits);
void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits);
void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
u8 *link_bw, u8 *rate_select);
bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
@ -88,7 +77,7 @@ bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp);
bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp);
int intel_dp_link_required(int pixel_clock, int bpp);
int intel_dp_max_data_rate(int max_link_clock, int max_lanes);
int intel_dp_max_data_rate(int max_link_rate, int max_lanes);
bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp);
bool intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);

View File

@ -34,9 +34,9 @@
* for some reason.
*/
#include "intel_backlight.h"
#include "intel_display_types.h"
#include "intel_dp_aux_backlight.h"
#include "intel_panel.h"
/* TODO:
* Implement HDR, right now we just implement the bare minimum to bring us back into SDR mode so we
@ -146,7 +146,7 @@ intel_dp_aux_hdr_get_backlight(struct intel_connector *connector, enum pipe pipe
if (!panel->backlight.edp.intel.sdr_uses_aux) {
u32 pwm_level = panel->backlight.pwm_funcs->get(connector, pipe);
return intel_panel_backlight_level_from_pwm(connector, pwm_level);
return intel_backlight_level_from_pwm(connector, pwm_level);
}
/* Assume 100% brightness if backlight controls aren't enabled yet */
@ -187,9 +187,9 @@ intel_dp_aux_hdr_set_backlight(const struct drm_connector_state *conn_state, u32
if (panel->backlight.edp.intel.sdr_uses_aux) {
intel_dp_aux_hdr_set_aux_backlight(conn_state, level);
} else {
const u32 pwm_level = intel_panel_backlight_level_to_pwm(connector, level);
const u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
intel_panel_set_pwm_level(conn_state, pwm_level);
intel_backlight_set_pwm_level(conn_state, pwm_level);
}
}
@ -215,7 +215,7 @@ intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state,
ctrl |= INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE;
intel_dp_aux_hdr_set_aux_backlight(conn_state, level);
} else {
u32 pwm_level = intel_panel_backlight_level_to_pwm(connector, level);
u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
panel->backlight.pwm_funcs->enable(crtc_state, conn_state, pwm_level);
@ -238,7 +238,7 @@ intel_dp_aux_hdr_disable_backlight(const struct drm_connector_state *conn_state,
return;
/* Note we want the actual pwm_level to be 0, regardless of pwm_min */
panel->backlight.pwm_funcs->disable(conn_state, intel_panel_invert_pwm_level(connector, 0));
panel->backlight.pwm_funcs->disable(conn_state, intel_backlight_invert_pwm_level(connector, 0));
}
static int

View File

@ -446,8 +446,6 @@ static
int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port,
void *buf, size_t size)
{
struct intel_dp *dp = &dig_port->dp;
struct intel_hdcp *hdcp = &dp->attached_connector->hdcp;
unsigned int offset;
u8 *byte = buf;
ssize_t ret, bytes_to_write, len;
@ -463,8 +461,6 @@ int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port,
bytes_to_write = size - 1;
byte++;
hdcp->cp_irq_count_cached = atomic_read(&hdcp->cp_irq_count);
while (bytes_to_write) {
len = bytes_to_write > DP_AUX_MAX_PAYLOAD_BYTES ?
DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_write;
@ -482,29 +478,11 @@ int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port,
return size;
}
static int
get_rxinfo_hdcp_1_dev_downstream(struct intel_digital_port *dig_port, bool *hdcp_1_x)
{
u8 rx_info[HDCP_2_2_RXINFO_LEN];
int ret;
ret = drm_dp_dpcd_read(&dig_port->dp.aux,
DP_HDCP_2_2_REG_RXINFO_OFFSET,
(void *)rx_info, HDCP_2_2_RXINFO_LEN);
if (ret != HDCP_2_2_RXINFO_LEN)
return ret >= 0 ? -EIO : ret;
*hdcp_1_x = HDCP_2_2_HDCP1_DEVICE_CONNECTED(rx_info[1]) ? true : false;
return 0;
}
static
ssize_t get_receiver_id_list_size(struct intel_digital_port *dig_port)
ssize_t get_receiver_id_list_rx_info(struct intel_digital_port *dig_port, u32 *dev_cnt, u8 *byte)
{
u8 rx_info[HDCP_2_2_RXINFO_LEN];
u32 dev_cnt;
ssize_t ret;
u8 *rx_info = byte;
ret = drm_dp_dpcd_read(&dig_port->dp.aux,
DP_HDCP_2_2_REG_RXINFO_OFFSET,
@ -512,15 +490,11 @@ ssize_t get_receiver_id_list_size(struct intel_digital_port *dig_port)
if (ret != HDCP_2_2_RXINFO_LEN)
return ret >= 0 ? -EIO : ret;
dev_cnt = (HDCP_2_2_DEV_COUNT_HI(rx_info[0]) << 4 |
*dev_cnt = (HDCP_2_2_DEV_COUNT_HI(rx_info[0]) << 4 |
HDCP_2_2_DEV_COUNT_LO(rx_info[1]));
if (dev_cnt > HDCP_2_2_MAX_DEVICE_COUNT)
dev_cnt = HDCP_2_2_MAX_DEVICE_COUNT;
ret = sizeof(struct hdcp2_rep_send_receiverid_list) -
HDCP_2_2_RECEIVER_IDS_MAX_LEN +
(dev_cnt * HDCP_2_2_RECEIVER_ID_LEN);
if (*dev_cnt > HDCP_2_2_MAX_DEVICE_COUNT)
*dev_cnt = HDCP_2_2_MAX_DEVICE_COUNT;
return ret;
}
@ -530,12 +504,15 @@ int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port,
u8 msg_id, void *buf, size_t size)
{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
struct intel_dp *dp = &dig_port->dp;
struct intel_hdcp *hdcp = &dp->attached_connector->hdcp;
unsigned int offset;
u8 *byte = buf;
ssize_t ret, bytes_to_recv, len;
const struct hdcp2_dp_msg_data *hdcp2_msg_data;
ktime_t msg_end = ktime_set(0, 0);
bool msg_expired;
u32 dev_cnt;
hdcp2_msg_data = get_hdcp2_dp_msg_data(msg_id);
if (!hdcp2_msg_data)
@ -546,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,
};

View File

@ -61,7 +61,7 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
int bpp, slots = -EINVAL;
crtc_state->lane_count = limits->max_lane_count;
crtc_state->port_clock = limits->max_clock;
crtc_state->port_clock = limits->max_rate;
for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
crtc_state->pipe_bpp = bpp;
@ -131,8 +131,8 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
* for MST we always configure max link bw - the spec doesn't
* seem to suggest we should do otherwise.
*/
limits.min_clock =
limits.max_clock = intel_dp_max_link_rate(intel_dp);
limits.min_rate =
limits.max_rate = intel_dp_max_link_rate(intel_dp);
limits.min_lane_count =
limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
@ -396,7 +396,6 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state,
to_intel_connector(old_conn_state->connector);
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
bool last_mst_stream;
u32 val;
intel_dp->active_mst_links--;
last_mst_stream = intel_dp->active_mst_links == 0;
@ -412,12 +411,8 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state,
clear_act_sent(encoder, old_crtc_state);
val = intel_de_read(dev_priv,
TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder));
val &= ~TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
intel_de_write(dev_priv,
TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder),
val);
intel_de_rmw(dev_priv, TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder),
TRANS_DDI_DP_VC_PAYLOAD_ALLOC, 0);
wait_for_act_sent(encoder, old_crtc_state);

View File

@ -309,7 +309,7 @@ int pnv_calc_dpll_params(int refclk, struct dpll *clock)
return clock->dot;
}
static u32 i9xx_dpll_compute_m(struct dpll *dpll)
static u32 i9xx_dpll_compute_m(const struct dpll *dpll)
{
return 5 * (dpll->m1 + 2) + (dpll->m2 + 2);
}
@ -428,7 +428,8 @@ i9xx_select_p2_div(const struct intel_limit *limit,
static bool
i9xx_find_best_dpll(const struct intel_limit *limit,
struct intel_crtc_state *crtc_state,
int target, int refclk, struct dpll *match_clock,
int target, int refclk,
const struct dpll *match_clock,
struct dpll *best_clock)
{
struct drm_device *dev = crtc_state->uapi.crtc->dev;
@ -486,7 +487,8 @@ i9xx_find_best_dpll(const struct intel_limit *limit,
static bool
pnv_find_best_dpll(const struct intel_limit *limit,
struct intel_crtc_state *crtc_state,
int target, int refclk, struct dpll *match_clock,
int target, int refclk,
const struct dpll *match_clock,
struct dpll *best_clock)
{
struct drm_device *dev = crtc_state->uapi.crtc->dev;
@ -542,7 +544,8 @@ pnv_find_best_dpll(const struct intel_limit *limit,
static bool
g4x_find_best_dpll(const struct intel_limit *limit,
struct intel_crtc_state *crtc_state,
int target, int refclk, struct dpll *match_clock,
int target, int refclk,
const struct dpll *match_clock,
struct dpll *best_clock)
{
struct drm_device *dev = crtc_state->uapi.crtc->dev;
@ -636,7 +639,8 @@ static bool vlv_PLL_is_optimal(struct drm_device *dev, int target_freq,
static bool
vlv_find_best_dpll(const struct intel_limit *limit,
struct intel_crtc_state *crtc_state,
int target, int refclk, struct dpll *match_clock,
int target, int refclk,
const struct dpll *match_clock,
struct dpll *best_clock)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
@ -696,7 +700,8 @@ vlv_find_best_dpll(const struct intel_limit *limit,
static bool
chv_find_best_dpll(const struct intel_limit *limit,
struct intel_crtc_state *crtc_state,
int target, int refclk, struct dpll *match_clock,
int target, int refclk,
const struct dpll *match_clock,
struct dpll *best_clock)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
@ -763,47 +768,45 @@ bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state,
NULL, best_clock);
}
static u32 pnv_dpll_compute_fp(struct dpll *dpll)
u32 i9xx_dpll_compute_fp(const struct dpll *dpll)
{
return dpll->n << 16 | dpll->m1 << 8 | dpll->m2;
}
static u32 pnv_dpll_compute_fp(const struct dpll *dpll)
{
return (1 << dpll->n) << 16 | dpll->m2;
}
static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state,
struct dpll *reduced_clock)
static void i9xx_update_pll_dividers(struct intel_crtc_state *crtc_state,
const struct dpll *clock,
const struct dpll *reduced_clock)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 fp, fp2 = 0;
u32 fp, fp2;
if (IS_PINEVIEW(dev_priv)) {
fp = pnv_dpll_compute_fp(&crtc_state->dpll);
if (reduced_clock)
fp2 = pnv_dpll_compute_fp(reduced_clock);
fp = pnv_dpll_compute_fp(clock);
fp2 = pnv_dpll_compute_fp(reduced_clock);
} else {
fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
if (reduced_clock)
fp2 = i9xx_dpll_compute_fp(reduced_clock);
fp = i9xx_dpll_compute_fp(clock);
fp2 = i9xx_dpll_compute_fp(reduced_clock);
}
crtc_state->dpll_hw_state.fp0 = fp;
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
reduced_clock) {
crtc_state->dpll_hw_state.fp1 = fp2;
} else {
crtc_state->dpll_hw_state.fp1 = fp;
}
crtc_state->dpll_hw_state.fp1 = fp2;
}
static void i9xx_compute_dpll(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state,
struct dpll *reduced_clock)
static void i9xx_compute_dpll(struct intel_crtc_state *crtc_state,
const struct dpll *clock,
const struct dpll *reduced_clock)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 dpll;
struct dpll *clock = &crtc_state->dpll;
i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
i9xx_update_pll_dividers(crtc_state, clock, reduced_clock);
dpll = DPLL_VGA_MODE_DIS;
@ -826,13 +829,17 @@ static void i9xx_compute_dpll(struct intel_crtc *crtc,
dpll |= DPLL_SDVO_HIGH_SPEED;
/* compute bitmask from p1 value */
if (IS_PINEVIEW(dev_priv))
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;
}

View File

@ -18,27 +18,20 @@ void intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv);
int vlv_calc_dpll_params(int refclk, struct dpll *clock);
int pnv_calc_dpll_params(int refclk, struct dpll *clock);
int i9xx_calc_dpll_params(int refclk, struct dpll *clock);
void vlv_compute_dpll(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config);
void chv_compute_dpll(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config);
u32 i9xx_dpll_compute_fp(const struct dpll *dpll);
void vlv_compute_dpll(struct intel_crtc_state *crtc_state);
void chv_compute_dpll(struct intel_crtc_state *crtc_state);
int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe,
const struct dpll *dpll);
void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe);
void i9xx_enable_pll(struct intel_crtc *crtc,
const struct intel_crtc_state *crtc_state);
void vlv_enable_pll(struct intel_crtc *crtc,
const struct intel_crtc_state *pipe_config);
void chv_enable_pll(struct intel_crtc *crtc,
const struct intel_crtc_state *pipe_config);
void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe);
void chv_enable_pll(const struct intel_crtc_state *crtc_state);
void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe);
void vlv_enable_pll(const struct intel_crtc_state *crtc_state);
void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe);
void i9xx_enable_pll(const struct intel_crtc_state *crtc_state);
void i9xx_disable_pll(const struct intel_crtc_state *crtc_state);
void vlv_prepare_pll(struct intel_crtc *crtc,
const struct intel_crtc_state *pipe_config);
void chv_prepare_pll(struct intel_crtc *crtc,
const struct intel_crtc_state *pipe_config);
bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state,
struct dpll *best_clock);
int chv_calc_dpll_params(int refclk, struct dpll *pll_clock);

View File

@ -184,34 +184,6 @@ intel_tc_pll_enable_reg(struct drm_i915_private *i915,
return MG_PLL_ENABLE(tc_port);
}
/**
* intel_prepare_shared_dpll - call a dpll's prepare hook
* @crtc_state: CRTC, and its state, which has a shared dpll
*
* This calls the PLL's prepare hook if it has one and if the PLL is not
* already enabled. The prepare hook is platform specific.
*/
void intel_prepare_shared_dpll(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
struct intel_shared_dpll *pll = crtc_state->shared_dpll;
if (drm_WARN_ON(&dev_priv->drm, pll == NULL))
return;
mutex_lock(&dev_priv->dpll.lock);
drm_WARN_ON(&dev_priv->drm, !pll->state.pipe_mask);
if (!pll->active_mask) {
drm_dbg(&dev_priv->drm, "setting up %s\n", pll->info->name);
drm_WARN_ON(&dev_priv->drm, pll->on);
assert_shared_dpll_disabled(dev_priv, pll);
pll->info->funcs->prepare(dev_priv, pll);
}
mutex_unlock(&dev_priv->dpll.lock);
}
/**
* intel_enable_shared_dpll - enable a CRTC's shared DPLL
* @crtc_state: CRTC, and its state, which has a shared DPLL
@ -451,15 +423,6 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
return val & DPLL_VCO_ENABLE;
}
static void ibx_pch_dpll_prepare(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
const enum intel_dpll_id id = pll->info->id;
intel_de_write(dev_priv, PCH_FP0(id), pll->state.hw_state.fp0);
intel_de_write(dev_priv, PCH_FP1(id), pll->state.hw_state.fp1);
}
static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
{
u32 val;
@ -481,6 +444,9 @@ static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
/* PCH refclock must be enabled first */
ibx_assert_pch_refclk_enabled(dev_priv);
intel_de_write(dev_priv, PCH_FP0(id), pll->state.hw_state.fp0);
intel_de_write(dev_priv, PCH_FP1(id), pll->state.hw_state.fp1);
intel_de_write(dev_priv, PCH_DPLL(id), pll->state.hw_state.dpll);
/* Wait for the clocks to stabilize. */
@ -558,7 +524,6 @@ static void ibx_dump_hw_state(struct drm_i915_private *dev_priv,
}
static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = {
.prepare = ibx_pch_dpll_prepare,
.enable = ibx_pch_dpll_enable,
.disable = ibx_pch_dpll_disable,
.get_hw_state = ibx_pch_dpll_get_hw_state,

View File

@ -255,16 +255,6 @@ struct intel_shared_dpll_state {
* struct intel_shared_dpll_funcs - platform specific hooks for managing DPLLs
*/
struct intel_shared_dpll_funcs {
/**
* @prepare:
*
* Optional hook to perform operations prior to enabling the PLL.
* Called from intel_prepare_shared_dpll() function unless the PLL
* is already enabled.
*/
void (*prepare)(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll);
/**
* @enable:
*
@ -404,7 +394,6 @@ int intel_dpll_get_freq(struct drm_i915_private *i915,
bool intel_dpll_get_hw_state(struct drm_i915_private *i915,
struct intel_shared_dpll *pll,
struct intel_dpll_hw_state *hw_state);
void intel_prepare_shared_dpll(const struct intel_crtc_state *crtc_state);
void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state);
void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state);
void intel_shared_dpll_swap_state(struct intel_atomic_state *state);

View 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);
}

View 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__ */

View 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;
}

View 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__ */

View File

@ -47,33 +47,42 @@ static u32 dcs_get_backlight(struct intel_connector *connector, enum pipe unused
{
struct intel_encoder *encoder = intel_attached_encoder(connector);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
struct intel_panel *panel = &connector->panel;
struct mipi_dsi_device *dsi_device;
u8 data = 0;
u8 data[2] = {};
enum port port;
size_t len = panel->backlight.max > U8_MAX ? 2 : 1;
/* FIXME: Need to take care of 16 bit brightness level */
for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
dsi_device = intel_dsi->dsi_hosts[port]->device;
mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
&data, sizeof(data));
&data, len);
break;
}
return data;
return (data[1] << 8) | data[0];
}
static void dcs_set_backlight(const struct drm_connector_state *conn_state, u32 level)
{
struct intel_dsi *intel_dsi = enc_to_intel_dsi(to_intel_encoder(conn_state->best_encoder));
struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;
struct mipi_dsi_device *dsi_device;
u8 data = level;
u8 data[2] = {};
enum port port;
size_t len = panel->backlight.max > U8_MAX ? 2 : 1;
if (len == 1) {
data[0] = level;
} else {
data[0] = level >> 8;
data[1] = level;
}
/* FIXME: Need to take care of 16 bit brightness level */
for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
dsi_device = intel_dsi->dsi_hosts[port]->device;
mipi_dsi_dcs_write(dsi_device, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
&data, sizeof(data));
&data, len);
}
}
@ -147,10 +156,16 @@ static void dcs_enable_backlight(const struct intel_crtc_state *crtc_state,
static int dcs_setup_backlight(struct intel_connector *connector,
enum pipe unused)
{
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_panel *panel = &connector->panel;
panel->backlight.max = PANEL_PWM_MAX_VALUE;
panel->backlight.level = PANEL_PWM_MAX_VALUE;
if (dev_priv->vbt.backlight.brightness_precision_bits > 8)
panel->backlight.max = (1 << dev_priv->vbt.backlight.brightness_precision_bits) - 1;
else
panel->backlight.max = PANEL_PWM_MAX_VALUE;
panel->backlight.level = panel->backlight.max;
return 0;
}

View File

@ -265,7 +265,7 @@ static int intel_dvo_compute_config(struct intel_encoder *encoder,
* of the original mode.
*/
if (fixed_mode)
intel_fixed_panel_mode(fixed_mode, adjusted_mode);
intel_panel_fixed_mode(fixed_mode, adjusted_mode);
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
return -EINVAL;

View File

@ -4,9 +4,11 @@
*/
#include <drm/drm_framebuffer.h>
#include <drm/drm_modeset_helper.h>
#include "intel_display.h"
#include "intel_display_types.h"
#include "intel_dpt.h"
#include "intel_fb.h"
#define check_array_bounds(i915, a, i) drm_WARN_ON(&(i915)->drm, (i) >= ARRAY_SIZE(a))
@ -61,6 +63,12 @@ int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane)
return ccs_plane - fb->format->num_planes / 2;
}
static int gen12_ccs_aux_stride(struct drm_framebuffer *fb, int ccs_plane)
{
return DIV_ROUND_UP(fb->pitches[skl_ccs_to_main_plane(fb, ccs_plane)],
512) * 64;
}
int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane)
{
struct drm_i915_private *i915 = to_i915(fb->dev);
@ -79,6 +87,60 @@ unsigned int intel_tile_size(const struct drm_i915_private *i915)
return DISPLAY_VER(i915) == 2 ? 2048 : 4096;
}
unsigned int
intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
{
struct drm_i915_private *dev_priv = to_i915(fb->dev);
unsigned int cpp = fb->format->cpp[color_plane];
switch (fb->modifier) {
case DRM_FORMAT_MOD_LINEAR:
return intel_tile_size(dev_priv);
case I915_FORMAT_MOD_X_TILED:
if (DISPLAY_VER(dev_priv) == 2)
return 128;
else
return 512;
case I915_FORMAT_MOD_Y_TILED_CCS:
if (is_ccs_plane(fb, color_plane))
return 128;
fallthrough;
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
if (is_ccs_plane(fb, color_plane))
return 64;
fallthrough;
case I915_FORMAT_MOD_Y_TILED:
if (DISPLAY_VER(dev_priv) == 2 || HAS_128_BYTE_Y_TILING(dev_priv))
return 128;
else
return 512;
case I915_FORMAT_MOD_Yf_TILED_CCS:
if (is_ccs_plane(fb, color_plane))
return 128;
fallthrough;
case I915_FORMAT_MOD_Yf_TILED:
switch (cpp) {
case 1:
return 64;
case 2:
case 4:
return 128;
case 8:
case 16:
return 256;
default:
MISSING_CASE(cpp);
return cpp;
}
break;
default:
MISSING_CASE(fb->modifier);
return cpp;
}
}
unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
{
if (is_gen12_ccs_plane(fb, color_plane))
@ -109,6 +171,31 @@ unsigned int intel_tile_row_size(const struct drm_framebuffer *fb, int color_pla
return fb->pitches[color_plane] * tile_height;
}
unsigned int
intel_fb_align_height(const struct drm_framebuffer *fb,
int color_plane, unsigned int height)
{
unsigned int tile_height = intel_tile_height(fb, color_plane);
return ALIGN(height, tile_height);
}
static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
{
switch (fb_modifier) {
case I915_FORMAT_MOD_X_TILED:
return I915_TILING_X;
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_Y_TILED_CCS:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
return I915_TILING_Y;
default:
return I915_TILING_NONE;
}
}
unsigned int intel_cursor_alignment(const struct drm_i915_private *i915)
{
if (IS_I830(i915))
@ -121,6 +208,70 @@ unsigned int intel_cursor_alignment(const struct drm_i915_private *i915)
return 4 * 1024;
}
static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv)
{
if (DISPLAY_VER(dev_priv) >= 9)
return 256 * 1024;
else if (IS_I965G(dev_priv) || IS_I965GM(dev_priv) ||
IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
return 128 * 1024;
else if (DISPLAY_VER(dev_priv) >= 4)
return 4 * 1024;
else
return 0;
}
unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
int color_plane)
{
struct drm_i915_private *dev_priv = to_i915(fb->dev);
if (intel_fb_uses_dpt(fb))
return 512 * 4096;
/* AUX_DIST needs only 4K alignment */
if (is_ccs_plane(fb, color_plane))
return 4096;
if (is_semiplanar_uv_plane(fb, color_plane)) {
/*
* TODO: cross-check wrt. the bspec stride in bytes * 64 bytes
* alignment for linear UV planes on all platforms.
*/
if (DISPLAY_VER(dev_priv) >= 12) {
if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
return intel_linear_alignment(dev_priv);
return intel_tile_row_size(fb, color_plane);
}
return 4096;
}
drm_WARN_ON(&dev_priv->drm, color_plane != 0);
switch (fb->modifier) {
case DRM_FORMAT_MOD_LINEAR:
return intel_linear_alignment(dev_priv);
case I915_FORMAT_MOD_X_TILED:
if (HAS_ASYNC_FLIPS(dev_priv))
return 256 * 1024;
return 0;
case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
return 16 * 1024;
case I915_FORMAT_MOD_Y_TILED_CCS:
case I915_FORMAT_MOD_Yf_TILED_CCS:
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_Yf_TILED:
return 1 * 1024 * 1024;
default:
MISSING_CASE(fb->modifier);
return 0;
}
}
void intel_fb_plane_get_subsampling(int *hsub, int *vsub,
const struct drm_framebuffer *fb,
int color_plane)
@ -918,6 +1069,71 @@ void intel_fb_fill_view(const struct intel_framebuffer *fb, unsigned int rotatio
*view = fb->normal_view;
}
static
u32 intel_fb_max_stride(struct drm_i915_private *dev_priv,
u32 pixel_format, u64 modifier)
{
/*
* Arbitrary limit for gen4+ chosen to match the
* render engine max stride.
*
* The new CCS hash mode makes remapping impossible
*/
if (DISPLAY_VER(dev_priv) < 4 || is_ccs_modifier(modifier) ||
intel_modifier_uses_dpt(dev_priv, modifier))
return intel_plane_fb_max_stride(dev_priv, pixel_format, modifier);
else if (DISPLAY_VER(dev_priv) >= 7)
return 256 * 1024;
else
return 128 * 1024;
}
static u32
intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
{
struct drm_i915_private *dev_priv = to_i915(fb->dev);
u32 tile_width;
if (is_surface_linear(fb, color_plane)) {
u32 max_stride = intel_plane_fb_max_stride(dev_priv,
fb->format->format,
fb->modifier);
/*
* To make remapping with linear generally feasible
* we need the stride to be page aligned.
*/
if (fb->pitches[color_plane] > max_stride &&
!is_ccs_modifier(fb->modifier))
return intel_tile_size(dev_priv);
else
return 64;
}
tile_width = intel_tile_width_bytes(fb, color_plane);
if (is_ccs_modifier(fb->modifier)) {
/*
* Display WA #0531: skl,bxt,kbl,glk
*
* Render decompression and plane width > 3840
* combined with horizontal panning requires the
* plane stride to be a multiple of 4. We'll just
* require the entire fb to accommodate that to avoid
* potential runtime errors at plane configuration time.
*/
if ((DISPLAY_VER(dev_priv) == 9 || IS_GEMINILAKE(dev_priv)) &&
color_plane == 0 && fb->width > 3840)
tile_width *= 4;
/*
* The main surface pitch must be padded to a multiple of four
* tile widths.
*/
else if (DISPLAY_VER(dev_priv) >= 12)
tile_width *= 4;
}
return tile_width;
}
static int intel_plane_check_stride(const struct intel_plane_state *plane_state)
{
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
@ -981,3 +1197,268 @@ int intel_plane_compute_gtt(struct intel_plane_state *plane_state)
return intel_plane_check_stride(plane_state);
}
static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
{
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
drm_framebuffer_cleanup(fb);
if (intel_fb_uses_dpt(fb))
intel_dpt_destroy(intel_fb->dpt_vm);
intel_frontbuffer_put(intel_fb->frontbuffer);
kfree(intel_fb);
}
static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb,
struct drm_file *file,
unsigned int *handle)
{
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct drm_i915_private *i915 = to_i915(obj->base.dev);
if (i915_gem_object_is_userptr(obj)) {
drm_dbg(&i915->drm,
"attempting to use a userptr for a framebuffer, denied\n");
return -EINVAL;
}
return drm_gem_handle_create(file, &obj->base, handle);
}
static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb,
struct drm_file *file,
unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
unsigned int num_clips)
{
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
i915_gem_object_flush_if_display(obj);
intel_frontbuffer_flush(to_intel_frontbuffer(fb), ORIGIN_DIRTYFB);
return 0;
}
static const struct drm_framebuffer_funcs intel_fb_funcs = {
.destroy = intel_user_framebuffer_destroy,
.create_handle = intel_user_framebuffer_create_handle,
.dirty = intel_user_framebuffer_dirty,
};
int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
struct drm_i915_gem_object *obj,
struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
struct drm_framebuffer *fb = &intel_fb->base;
u32 max_stride;
unsigned int tiling, stride;
int ret = -EINVAL;
int i;
intel_fb->frontbuffer = intel_frontbuffer_get(obj);
if (!intel_fb->frontbuffer)
return -ENOMEM;
i915_gem_object_lock(obj, NULL);
tiling = i915_gem_object_get_tiling(obj);
stride = i915_gem_object_get_stride(obj);
i915_gem_object_unlock(obj);
if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) {
/*
* If there's a fence, enforce that
* the fb modifier and tiling mode match.
*/
if (tiling != I915_TILING_NONE &&
tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
drm_dbg_kms(&dev_priv->drm,
"tiling_mode doesn't match fb modifier\n");
goto err;
}
} else {
if (tiling == I915_TILING_X) {
mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED;
} else if (tiling == I915_TILING_Y) {
drm_dbg_kms(&dev_priv->drm,
"No Y tiling for legacy addfb\n");
goto err;
}
}
if (!drm_any_plane_has_format(&dev_priv->drm,
mode_cmd->pixel_format,
mode_cmd->modifier[0])) {
drm_dbg_kms(&dev_priv->drm,
"unsupported pixel format %p4cc / modifier 0x%llx\n",
&mode_cmd->pixel_format, mode_cmd->modifier[0]);
goto err;
}
/*
* gen2/3 display engine uses the fence if present,
* so the tiling mode must match the fb modifier exactly.
*/
if (DISPLAY_VER(dev_priv) < 4 &&
tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
drm_dbg_kms(&dev_priv->drm,
"tiling_mode must match fb modifier exactly on gen2/3\n");
goto err;
}
max_stride = intel_fb_max_stride(dev_priv, mode_cmd->pixel_format,
mode_cmd->modifier[0]);
if (mode_cmd->pitches[0] > max_stride) {
drm_dbg_kms(&dev_priv->drm,
"%s pitch (%u) must be at most %d\n",
mode_cmd->modifier[0] != DRM_FORMAT_MOD_LINEAR ?
"tiled" : "linear",
mode_cmd->pitches[0], max_stride);
goto err;
}
/*
* If there's a fence, enforce that
* the fb pitch and fence stride match.
*/
if (tiling != I915_TILING_NONE && mode_cmd->pitches[0] != stride) {
drm_dbg_kms(&dev_priv->drm,
"pitch (%d) must match tiling stride (%d)\n",
mode_cmd->pitches[0], stride);
goto err;
}
/* FIXME need to adjust LINOFF/TILEOFF accordingly. */
if (mode_cmd->offsets[0] != 0) {
drm_dbg_kms(&dev_priv->drm,
"plane 0 offset (0x%08x) must be 0\n",
mode_cmd->offsets[0]);
goto err;
}
drm_helper_mode_fill_fb_struct(&dev_priv->drm, fb, mode_cmd);
for (i = 0; i < fb->format->num_planes; i++) {
u32 stride_alignment;
if (mode_cmd->handles[i] != mode_cmd->handles[0]) {
drm_dbg_kms(&dev_priv->drm, "bad plane %d handle\n",
i);
goto err;
}
stride_alignment = intel_fb_stride_alignment(fb, i);
if (fb->pitches[i] & (stride_alignment - 1)) {
drm_dbg_kms(&dev_priv->drm,
"plane %d pitch (%d) must be at least %u byte aligned\n",
i, fb->pitches[i], stride_alignment);
goto err;
}
if (is_gen12_ccs_plane(fb, i) && !is_gen12_ccs_cc_plane(fb, i)) {
int ccs_aux_stride = gen12_ccs_aux_stride(fb, i);
if (fb->pitches[i] != ccs_aux_stride) {
drm_dbg_kms(&dev_priv->drm,
"ccs aux plane %d pitch (%d) must be %d\n",
i,
fb->pitches[i], ccs_aux_stride);
goto err;
}
}
/* TODO: Add POT stride remapping support for CCS formats as well. */
if (IS_ALDERLAKE_P(dev_priv) &&
mode_cmd->modifier[i] != DRM_FORMAT_MOD_LINEAR &&
!intel_fb_needs_pot_stride_remap(intel_fb) &&
!is_power_of_2(mode_cmd->pitches[i])) {
drm_dbg_kms(&dev_priv->drm,
"plane %d pitch (%d) must be power of two for tiled buffers\n",
i, mode_cmd->pitches[i]);
goto err;
}
fb->obj[i] = &obj->base;
}
ret = intel_fill_fb_info(dev_priv, intel_fb);
if (ret)
goto err;
if (intel_fb_uses_dpt(fb)) {
struct i915_address_space *vm;
vm = intel_dpt_create(intel_fb);
if (IS_ERR(vm)) {
ret = PTR_ERR(vm);
goto err;
}
intel_fb->dpt_vm = vm;
}
ret = drm_framebuffer_init(&dev_priv->drm, fb, &intel_fb_funcs);
if (ret) {
drm_err(&dev_priv->drm, "framebuffer init failed %d\n", ret);
goto err;
}
return 0;
err:
intel_frontbuffer_put(intel_fb->frontbuffer);
return ret;
}
struct drm_framebuffer *
intel_user_framebuffer_create(struct drm_device *dev,
struct drm_file *filp,
const struct drm_mode_fb_cmd2 *user_mode_cmd)
{
struct drm_framebuffer *fb;
struct drm_i915_gem_object *obj;
struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd;
struct drm_i915_private *i915;
obj = i915_gem_object_lookup(filp, mode_cmd.handles[0]);
if (!obj)
return ERR_PTR(-ENOENT);
/* object is backed with LMEM for discrete */
i915 = to_i915(obj->base.dev);
if (HAS_LMEM(i915) && !i915_gem_object_can_migrate(obj, INTEL_REGION_LMEM)) {
/* object is "remote", not in local memory */
i915_gem_object_put(obj);
return ERR_PTR(-EREMOTE);
}
fb = intel_framebuffer_create(obj, &mode_cmd);
i915_gem_object_put(obj);
return fb;
}
struct drm_framebuffer *
intel_framebuffer_create(struct drm_i915_gem_object *obj,
struct drm_mode_fb_cmd2 *mode_cmd)
{
struct intel_framebuffer *intel_fb;
int ret;
intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
if (!intel_fb)
return ERR_PTR(-ENOMEM);
ret = intel_framebuffer_init(intel_fb, obj, mode_cmd);
if (ret)
goto err;
return &intel_fb->base;
err:
kfree(intel_fb);
return ERR_PTR(ret);
}

View File

@ -8,10 +8,12 @@
#include <linux/types.h>
struct drm_device;
struct drm_file;
struct drm_framebuffer;
struct drm_i915_gem_object;
struct drm_i915_private;
struct drm_mode_fb_cmd2;
struct intel_fb_view;
struct intel_framebuffer;
struct intel_plane_state;
@ -28,10 +30,14 @@ int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane);
int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane);
unsigned int intel_tile_size(const struct drm_i915_private *i915);
unsigned int intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane);
unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane);
unsigned int intel_tile_row_size(const struct drm_framebuffer *fb, int color_plane);
unsigned int intel_fb_align_height(const struct drm_framebuffer *fb,
int color_plane, unsigned int height);
unsigned int intel_cursor_alignment(const struct drm_i915_private *i915);
unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
int color_plane);
void intel_fb_plane_get_subsampling(int *hsub, int *vsub,
const struct drm_framebuffer *fb,
@ -53,4 +59,12 @@ void intel_fb_fill_view(const struct intel_framebuffer *fb, unsigned int rotatio
struct intel_fb_view *view);
int intel_plane_compute_gtt(struct intel_plane_state *plane_state);
int intel_framebuffer_init(struct intel_framebuffer *ifb,
struct drm_i915_gem_object *obj,
struct drm_mode_fb_cmd2 *mode_cmd);
struct drm_framebuffer *
intel_user_framebuffer_create(struct drm_device *dev,
struct drm_file *filp,
const struct drm_mode_fb_cmd2 *user_mode_cmd);
#endif /* __INTEL_FB_H__ */

View File

@ -232,16 +232,16 @@ static void i965_fbc_recompress(struct drm_i915_private *dev_priv)
/* This function forces a CFB recompression through the nuke operation. */
static void snb_fbc_recompress(struct drm_i915_private *dev_priv)
{
struct intel_fbc *fbc = &dev_priv->fbc;
trace_intel_fbc_nuke(fbc->crtc);
intel_de_write(dev_priv, MSG_FBC_REND_STATE, FBC_REND_NUKE);
intel_de_posting_read(dev_priv, MSG_FBC_REND_STATE);
}
static void intel_fbc_recompress(struct drm_i915_private *dev_priv)
{
struct intel_fbc *fbc = &dev_priv->fbc;
trace_intel_fbc_nuke(fbc->crtc);
if (DISPLAY_VER(dev_priv) >= 6)
snb_fbc_recompress(dev_priv);
else if (DISPLAY_VER(dev_priv) >= 4)
@ -280,8 +280,6 @@ static void ilk_fbc_activate(struct drm_i915_private *dev_priv)
params->fence_y_offset);
/* enable it... */
intel_de_write(dev_priv, ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
intel_fbc_recompress(dev_priv);
}
static void ilk_fbc_deactivate(struct drm_i915_private *dev_priv)
@ -308,14 +306,15 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv)
/* Display WA #0529: skl, kbl, bxt. */
if (DISPLAY_VER(dev_priv) == 9) {
u32 val = intel_de_read(dev_priv, CHICKEN_MISC_4);
u32 val = 0;
val &= ~(FBC_STRIDE_OVERRIDE | FBC_STRIDE_MASK);
if (params->override_cfb_stride)
val |= CHICKEN_FBC_STRIDE_OVERRIDE |
CHICKEN_FBC_STRIDE(params->override_cfb_stride);
if (params->gen9_wa_cfb_stride)
val |= FBC_STRIDE_OVERRIDE | params->gen9_wa_cfb_stride;
intel_de_write(dev_priv, CHICKEN_MISC_4, val);
intel_de_rmw(dev_priv, CHICKEN_MISC_4,
CHICKEN_FBC_STRIDE_OVERRIDE |
CHICKEN_FBC_STRIDE_MASK, val);
}
dpfc_ctl = 0;
@ -339,8 +338,6 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv)
dpfc_ctl |= FBC_CTL_FALSE_COLOR;
intel_de_write(dev_priv, ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
intel_fbc_recompress(dev_priv);
}
static bool intel_fbc_hw_is_active(struct drm_i915_private *dev_priv)
@ -402,6 +399,12 @@ bool intel_fbc_is_active(struct drm_i915_private *dev_priv)
return dev_priv->fbc.active;
}
static void intel_fbc_activate(struct drm_i915_private *dev_priv)
{
intel_fbc_hw_activate(dev_priv);
intel_fbc_recompress(dev_priv);
}
static void intel_fbc_deactivate(struct drm_i915_private *dev_priv,
const char *reason)
{
@ -675,11 +678,9 @@ static bool tiling_is_valid(struct drm_i915_private *dev_priv,
{
switch (modifier) {
case DRM_FORMAT_MOD_LINEAR:
if (DISPLAY_VER(dev_priv) >= 9)
return true;
return false;
case I915_FORMAT_MOD_X_TILED:
case I915_FORMAT_MOD_Y_TILED:
return DISPLAY_VER(dev_priv) >= 9;
case I915_FORMAT_MOD_X_TILED:
return true;
default:
return false;
@ -749,7 +750,7 @@ static bool intel_fbc_cfb_size_changed(struct drm_i915_private *dev_priv)
fbc->compressed_fb.size * fbc->limit;
}
static u16 intel_fbc_gen9_wa_cfb_stride(struct drm_i915_private *dev_priv)
static u16 intel_fbc_override_cfb_stride(struct drm_i915_private *dev_priv)
{
struct intel_fbc *fbc = &dev_priv->fbc;
struct intel_fbc_state_cache *cache = &fbc->state_cache;
@ -761,11 +762,11 @@ static u16 intel_fbc_gen9_wa_cfb_stride(struct drm_i915_private *dev_priv)
return 0;
}
static bool intel_fbc_gen9_wa_cfb_stride_changed(struct drm_i915_private *dev_priv)
static bool intel_fbc_override_cfb_stride_changed(struct drm_i915_private *dev_priv)
{
struct intel_fbc *fbc = &dev_priv->fbc;
return fbc->params.gen9_wa_cfb_stride != intel_fbc_gen9_wa_cfb_stride(dev_priv);
return fbc->params.override_cfb_stride != intel_fbc_override_cfb_stride(dev_priv);
}
static bool intel_fbc_can_enable(struct drm_i915_private *dev_priv)
@ -950,7 +951,7 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc,
params->cfb_size = intel_fbc_calculate_cfb_size(dev_priv, cache);
params->gen9_wa_cfb_stride = cache->gen9_wa_cfb_stride;
params->override_cfb_stride = cache->override_cfb_stride;
params->plane_visible = cache->plane.visible;
}
@ -984,7 +985,7 @@ static bool intel_fbc_can_flip_nuke(const struct intel_crtc_state *crtc_state)
if (params->cfb_size != intel_fbc_calculate_cfb_size(dev_priv, cache))
return false;
if (params->gen9_wa_cfb_stride != cache->gen9_wa_cfb_stride)
if (params->override_cfb_stride != cache->override_cfb_stride)
return false;
return true;
@ -1090,7 +1091,7 @@ static void __intel_fbc_post_update(struct intel_crtc *crtc)
return;
if (!fbc->busy_bits)
intel_fbc_hw_activate(dev_priv);
intel_fbc_activate(dev_priv);
else
intel_fbc_deactivate(dev_priv, "frontbuffer write");
}
@ -1129,7 +1130,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
if (!HAS_FBC(dev_priv))
return;
if (origin == ORIGIN_GTT || origin == ORIGIN_FLIP)
if (origin == ORIGIN_FLIP)
return;
mutex_lock(&fbc->lock);
@ -1150,14 +1151,6 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv,
if (!HAS_FBC(dev_priv))
return;
/*
* GTT tracking does not nuke the entire cfb
* so don't clear busy_bits set for some other
* reason.
*/
if (origin == ORIGIN_GTT)
return;
mutex_lock(&fbc->lock);
fbc->busy_bits &= ~frontbuffer_bits;
@ -1246,8 +1239,8 @@ 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

View File

@ -24,7 +24,7 @@ bool intel_fbc_pre_update(struct intel_atomic_state *state,
void intel_fbc_post_update(struct intel_atomic_state *state,
struct intel_crtc *crtc);
void intel_fbc_init(struct drm_i915_private *dev_priv);
void intel_fbc_enable(struct intel_atomic_state *state,
void intel_fbc_update(struct intel_atomic_state *state,
struct intel_crtc *crtc);
void intel_fbc_disable(struct intel_crtc *crtc);
void intel_fbc_global_disable(struct drm_i915_private *dev_priv);

View File

@ -45,6 +45,7 @@
#include "i915_drv.h"
#include "intel_display_types.h"
#include "intel_fb.h"
#include "intel_fbdev.h"
#include "intel_frontbuffer.h"

View File

@ -2,11 +2,13 @@
/*
* Copyright © 2020 Intel Corporation
*/
#include "intel_atomic.h"
#include "intel_ddi.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_fdi.h"
#include "intel_sideband.h"
/* units of 100MHz */
static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
@ -91,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)
{

View File

@ -12,6 +12,8 @@ struct intel_crtc_state;
struct intel_encoder;
#define I915_DISPLAY_CONFIG_RETRY 1
int intel_fdi_link_freq(struct drm_i915_private *i915,
const struct intel_crtc_state *pipe_config);
int ilk_fdi_compute_config(struct intel_crtc *intel_crtc,
struct intel_crtc_state *pipe_config);
void intel_fdi_normal_train(struct intel_crtc *crtc);
@ -21,5 +23,7 @@ void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state);
void intel_fdi_init_hook(struct drm_i915_private *dev_priv);
void hsw_fdi_link_train(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state);
void intel_fdi_pll_freq_update(struct drm_i915_private *i915);
void lpt_fdi_program_mphy(struct drm_i915_private *i915);
#endif

View File

@ -62,6 +62,7 @@
#include "intel_display_types.h"
#include "intel_fbc.h"
#include "intel_frontbuffer.h"
#include "intel_drrs.h"
#include "intel_psr.h"
/**
@ -91,7 +92,7 @@ static void frontbuffer_flush(struct drm_i915_private *i915,
trace_intel_frontbuffer_flush(frontbuffer_bits, origin);
might_sleep();
intel_edp_drrs_flush(i915, frontbuffer_bits);
intel_drrs_flush(i915, frontbuffer_bits);
intel_psr_flush(i915, frontbuffer_bits, origin);
intel_fbc_flush(i915, frontbuffer_bits, origin);
}
@ -180,7 +181,7 @@ void __intel_fb_invalidate(struct intel_frontbuffer *front,
might_sleep();
intel_psr_invalidate(i915, frontbuffer_bits, origin);
intel_edp_drrs_invalidate(i915, frontbuffer_bits);
intel_drrs_invalidate(i915, frontbuffer_bits);
intel_fbc_invalidate(i915, frontbuffer_bits, origin);
}

View File

@ -33,8 +33,7 @@
struct drm_i915_private;
enum fb_op_origin {
ORIGIN_GTT,
ORIGIN_CPU,
ORIGIN_CPU = 0,
ORIGIN_CS,
ORIGIN_FLIP,
ORIGIN_DIRTYFB,

View File

@ -33,21 +33,6 @@ static int intel_conn_to_vcpi(struct intel_connector *connector)
return connector->port ? connector->port->vcpi.vcpi : 0;
}
static bool
intel_streams_type1_capable(struct intel_connector *connector)
{
const struct intel_hdcp_shim *shim = connector->hdcp.shim;
bool capable = false;
if (!shim)
return capable;
if (shim->streams_type1_capable)
shim->streams_type1_capable(connector, &capable);
return capable;
}
/*
* intel_hdcp_required_content_stream selects the most highest common possible HDCP
* content_type for all streams in DP MST topology because security f/w doesn't
@ -86,7 +71,7 @@ intel_hdcp_required_content_stream(struct intel_digital_port *dig_port)
if (conn_dig_port != dig_port)
continue;
if (!enforce_type0 && !intel_streams_type1_capable(connector))
if (!enforce_type0 && !dig_port->hdcp_mst_type1_capable)
enforce_type0 = true;
data->streams[data->k].stream_id = intel_conn_to_vcpi(connector);
@ -112,6 +97,25 @@ intel_hdcp_required_content_stream(struct intel_digital_port *dig_port)
return 0;
}
static int intel_hdcp_prepare_streams(struct intel_connector *connector)
{
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
struct intel_hdcp *hdcp = &connector->hdcp;
int ret;
if (!intel_encoder_is_mst(intel_attached_encoder(connector))) {
data->k = 1;
data->streams[0].stream_type = hdcp->content_type;
} else {
ret = intel_hdcp_required_content_stream(dig_port);
if (ret)
return ret;
}
return 0;
}
static
bool intel_hdcp_is_ksv_valid(u8 *ksv)
{
@ -1632,6 +1636,14 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector)
return -EINVAL;
}
/*
* MST topology is not Type 1 capable if it contains a downstream
* device that is only HDCP 1.x or Legacy HDCP 2.0/2.1 compliant.
*/
dig_port->hdcp_mst_type1_capable =
!HDCP_2_2_HDCP1_DEVICE_CONNECTED(rx_info[1]) &&
!HDCP_2_2_HDCP_2_0_REP_CONNECTED(rx_info[1]);
/* Converting and Storing the seq_num_v to local variable as DWORD */
seq_num_v =
drm_hdcp_be24_to_cpu((const u8 *)msgs.recvid_list.seq_num_v);
@ -1876,6 +1888,14 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
for (i = 0; i < tries && !dig_port->hdcp_auth_status; i++) {
ret = hdcp2_authenticate_sink(connector);
if (!ret) {
ret = intel_hdcp_prepare_streams(connector);
if (ret) {
drm_dbg_kms(&i915->drm,
"Prepare streams failed.(%d)\n",
ret);
break;
}
ret = hdcp2_propagate_stream_management_info(connector);
if (ret) {
drm_dbg_kms(&i915->drm,
@ -1921,9 +1941,7 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
static int _intel_hdcp2_enable(struct intel_connector *connector)
{
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
struct intel_hdcp *hdcp = &connector->hdcp;
int ret;
@ -1931,16 +1949,6 @@ static int _intel_hdcp2_enable(struct intel_connector *connector)
connector->base.name, connector->base.base.id,
hdcp->content_type);
/* Stream which requires encryption */
if (!intel_encoder_is_mst(intel_attached_encoder(connector))) {
data->k = 1;
data->streams[0].stream_type = hdcp->content_type;
} else {
ret = intel_hdcp_required_content_stream(dig_port);
if (ret)
return ret;
}
ret = hdcp2_authenticate_and_encrypt(connector);
if (ret) {
drm_dbg_kms(&i915->drm, "HDCP2 Type%d Enabling Failed. (%d)\n",

View File

@ -2210,7 +2210,7 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
return ret;
if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
ret = intel_pch_panel_fitting(pipe_config, conn_state);
ret = intel_panel_fitting(pipe_config, conn_state);
if (ret)
return ret;
}

View File

@ -40,6 +40,7 @@
#include "i915_drv.h"
#include "intel_atomic.h"
#include "intel_backlight.h"
#include "intel_connector.h"
#include "intel_de.h"
#include "intel_display_types.h"
@ -323,7 +324,7 @@ static void intel_enable_lvds(struct intel_atomic_state *state,
drm_err(&dev_priv->drm,
"timed out waiting for panel to power on\n");
intel_panel_enable_backlight(pipe_config, conn_state);
intel_backlight_enable(pipe_config, conn_state);
}
static void intel_disable_lvds(struct intel_atomic_state *state,
@ -351,7 +352,7 @@ static void gmch_disable_lvds(struct intel_atomic_state *state,
const struct drm_connector_state *old_conn_state)
{
intel_panel_disable_backlight(old_conn_state);
intel_backlight_disable(old_conn_state);
intel_disable_lvds(state, encoder, old_crtc_state, old_conn_state);
}
@ -361,7 +362,7 @@ static void pch_disable_lvds(struct intel_atomic_state *state,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
intel_panel_disable_backlight(old_conn_state);
intel_backlight_disable(old_conn_state);
}
static void pch_post_disable_lvds(struct intel_atomic_state *state,
@ -441,7 +442,7 @@ static int intel_lvds_compute_config(struct intel_encoder *intel_encoder,
* with the panel scaling set up to source from the H/VDisplay
* of the original mode.
*/
intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
intel_panel_fixed_mode(intel_connector->panel.fixed_mode,
adjusted_mode);
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
@ -450,10 +451,7 @@ static int intel_lvds_compute_config(struct intel_encoder *intel_encoder,
if (HAS_PCH_SPLIT(dev_priv))
pipe_config->has_pch_encoder = true;
if (HAS_GMCH(dev_priv))
ret = intel_gmch_panel_fitting(pipe_config, conn_state);
else
ret = intel_pch_panel_fitting(pipe_config, conn_state);
ret = intel_panel_fitting(pipe_config, conn_state);
if (ret)
return ret;
@ -906,7 +904,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
}
intel_encoder->get_hw_state = intel_lvds_get_hw_state;
intel_encoder->get_config = intel_lvds_get_config;
intel_encoder->update_pipe = intel_panel_update_backlight;
intel_encoder->update_pipe = intel_backlight_update;
intel_encoder->shutdown = intel_lvds_shutdown;
intel_connector->get_hw_state = intel_connector_get_hw_state;
@ -999,7 +997,7 @@ 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",

View File

@ -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

View File

@ -8,15 +8,13 @@
#include <linux/types.h>
#include "intel_display.h"
enum drm_connector_status;
struct drm_connector;
struct drm_connector_state;
struct drm_display_mode;
struct drm_i915_private;
struct intel_connector;
struct intel_crtc;
struct intel_crtc_state;
struct intel_encoder;
struct intel_panel;
int intel_panel_init(struct intel_panel *panel,
@ -25,23 +23,11 @@ int intel_panel_init(struct intel_panel *panel,
void intel_panel_fini(struct intel_panel *panel);
enum drm_connector_status
intel_panel_detect(struct drm_connector *connector, bool force);
void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
bool intel_panel_use_ssc(struct drm_i915_private *i915);
void intel_panel_fixed_mode(const struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode);
int intel_pch_panel_fitting(struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
int intel_gmch_panel_fitting(struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state,
u32 level, u32 max);
int intel_panel_setup_backlight(struct drm_connector *connector,
enum pipe pipe);
void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
void intel_panel_update_backlight(struct intel_atomic_state *state,
struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state);
int intel_panel_fitting(struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
struct drm_display_mode *
intel_panel_edid_downclock_mode(struct intel_connector *connector,
const struct drm_display_mode *fixed_mode);
@ -49,22 +35,5 @@ struct drm_display_mode *
intel_panel_edid_fixed_mode(struct intel_connector *connector);
struct drm_display_mode *
intel_panel_vbt_fixed_mode(struct intel_connector *connector);
void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 level);
u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 level);
u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 level);
u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val);
#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
int intel_backlight_device_register(struct intel_connector *connector);
void intel_backlight_device_unregister(struct intel_connector *connector);
#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */
static inline int intel_backlight_device_register(struct intel_connector *connector)
{
return 0;
}
static inline void intel_backlight_device_unregister(struct intel_connector *connector)
{
}
#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
#endif /* __INTEL_PANEL_H__ */

View File

@ -364,41 +364,6 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp)
}
}
static void hsw_psr_setup_aux(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
u32 aux_clock_divider, aux_ctl;
int i;
static const u8 aux_msg[] = {
[0] = DP_AUX_NATIVE_WRITE << 4,
[1] = DP_SET_POWER >> 8,
[2] = DP_SET_POWER & 0xff,
[3] = 1 - 1,
[4] = DP_SET_POWER_D0,
};
u32 psr_aux_mask = EDP_PSR_AUX_CTL_TIME_OUT_MASK |
EDP_PSR_AUX_CTL_MESSAGE_SIZE_MASK |
EDP_PSR_AUX_CTL_PRECHARGE_2US_MASK |
EDP_PSR_AUX_CTL_BIT_CLOCK_2X_MASK;
BUILD_BUG_ON(sizeof(aux_msg) > 20);
for (i = 0; i < sizeof(aux_msg); i += 4)
intel_de_write(dev_priv,
EDP_PSR_AUX_DATA(intel_dp->psr.transcoder, i >> 2),
intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i));
aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0);
/* Start with bits set for DDI_AUX_CTL register */
aux_ctl = intel_dp->get_aux_send_ctl(intel_dp, sizeof(aux_msg),
aux_clock_divider);
/* Select only valid bits for SRD_AUX_CTL */
aux_ctl &= psr_aux_mask;
intel_de_write(dev_priv, EDP_PSR_AUX_CTL(intel_dp->psr.transcoder),
aux_ctl);
}
static void intel_psr_enable_sink(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@ -621,9 +586,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp)
static bool
transcoder_has_psr2(struct drm_i915_private *dev_priv, enum transcoder trans)
{
if (DISPLAY_VER(dev_priv) < 9)
return false;
else if (DISPLAY_VER(dev_priv) >= 12)
if (DISPLAY_VER(dev_priv) >= 12)
return trans == TRANSCODER_A;
else
return trans == TRANSCODER_EDP;
@ -1114,12 +1077,6 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp)
enum transcoder cpu_transcoder = intel_dp->psr.transcoder;
u32 mask;
/* Only HSW and BDW have PSR AUX registers that need to be setup. SKL+
* use hardcoded values PSR AUX transactions
*/
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
hsw_psr_setup_aux(intel_dp);
if (intel_dp->psr.psr2_enabled && DISPLAY_VER(dev_priv) == 9) {
i915_reg_t reg = CHICKEN_TRANS(cpu_transcoder);
u32 chicken = intel_de_read(dev_priv, reg);
@ -1460,23 +1417,16 @@ static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
if (DISPLAY_VER(dev_priv) >= 9)
/*
* Display WA #0884: skl+
* This documented WA for bxt can be safely applied
* broadly so we can force HW tracking to exit PSR
* instead of disabling and re-enabling.
* Workaround tells us to write 0 to CUR_SURFLIVE_A,
* but it makes more sense write to the current active
* pipe.
*/
intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0);
else
/*
* A write to CURSURFLIVE do not cause HW tracking to exit PSR
* on older gens so doing the manual exit instead.
*/
intel_psr_exit(intel_dp);
/*
* Display WA #0884: skl+
* This documented WA for bxt can be safely applied
* broadly so we can force HW tracking to exit PSR
* instead of disabling and re-enabling.
* Workaround tells us to write 0 to CUR_SURFLIVE_A,
* but it makes more sense write to the current active
* pipe.
*/
intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0);
}
void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane,
@ -1487,8 +1437,8 @@ void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane,
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe;
const struct drm_rect *clip;
u32 val, offset;
int ret, x, y;
u32 val;
int x, y;
if (!crtc_state->enable_psr2_sel_fetch)
return;
@ -1508,10 +1458,6 @@ void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane,
/* TODO: consider auxiliary surfaces */
x = plane_state->uapi.src.x1 >> 16;
y = (plane_state->uapi.src.y1 >> 16) + clip->y1;
ret = skl_calc_main_surface_offset(plane_state, &x, &y, &offset);
if (ret)
drm_warn_once(&dev_priv->drm, "skl_calc_main_surface_offset() returned %i\n",
ret);
val = y << 16 | x;
intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_OFFSET(pipe, plane->id),
val);
@ -1748,7 +1694,6 @@ void intel_psr_update(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
struct intel_psr *psr = &intel_dp->psr;
bool enable, psr2_enable;
@ -1765,15 +1710,6 @@ void intel_psr_update(struct intel_dp *intel_dp,
/* Force a PSR exit when enabling CRC to avoid CRC timeouts */
if (crtc_state->crc_enabled && psr->enabled)
psr_force_hw_tracking_exit(intel_dp);
else if (DISPLAY_VER(dev_priv) < 9 && psr->enabled) {
/*
* Activate PSR again after a force exit when enabling
* CRC in older gens
*/
if (!intel_dp->psr.active &&
!intel_dp->psr.busy_frontbuffer_bits)
schedule_work(&intel_dp->psr.work);
}
goto unlock;
}
@ -2186,23 +2122,12 @@ void intel_psr_init(struct intel_dp *intel_dp)
intel_dp->psr.source_support = true;
if (IS_HASWELL(dev_priv))
/*
* HSW don't have PSR registers on the same space as transcoder
* so set this to a value that when subtract to the register
* in transcoder space results in the right offset for HSW
*/
dev_priv->hsw_psr_mmio_adjust = _SRD_CTL_EDP - _HSW_EDP_PSR_BASE;
if (dev_priv->params.enable_psr == -1)
if (DISPLAY_VER(dev_priv) < 9 || !dev_priv->vbt.psr.enable)
if (!dev_priv->vbt.psr.enable)
dev_priv->params.enable_psr = 0;
/* Set link_standby x link_off defaults */
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
/* HSW and BDW require workarounds that we don't implement. */
intel_dp->psr.link_standby = false;
else if (DISPLAY_VER(dev_priv) < 12)
if (DISPLAY_VER(dev_priv) < 12)
/* For new platforms up to TGL let's respect VBT back again */
intel_dp->psr.link_standby = dev_priv->vbt.psr.full_link;

View File

@ -5,6 +5,7 @@
#include <linux/util_macros.h>
#include "intel_ddi_buf_trans.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_snps_phy.h"
@ -50,58 +51,30 @@ void intel_snps_phy_update_psr_power_state(struct drm_i915_private *dev_priv,
SNPS_PHY_TX_REQ_LN_DIS_PWR_STATE_PSR, val);
}
static const u32 dg2_ddi_translations[] = {
/* VS 0, pre-emph 0 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 26),
/* VS 0, pre-emph 1 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 33) |
REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 6),
/* VS 0, pre-emph 2 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 38) |
REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 12),
/* VS 0, pre-emph 3 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 43) |
REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 19),
/* VS 1, pre-emph 0 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 39),
/* VS 1, pre-emph 1 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 44) |
REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 8),
/* VS 1, pre-emph 2 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 47) |
REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 15),
/* VS 2, pre-emph 0 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 52),
/* VS 2, pre-emph 1 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 51) |
REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 10),
/* VS 3, pre-emph 0 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 62),
};
void intel_snps_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
u32 level)
const struct intel_crtc_state *crtc_state,
int level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
const struct intel_ddi_buf_trans *ddi_translations;
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
int n_entries, ln;
n_entries = ARRAY_SIZE(dg2_ddi_translations);
if (level >= n_entries)
ddi_translations = encoder->get_buf_trans(encoder, crtc_state, &n_entries);
if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations))
return;
if (drm_WARN_ON_ONCE(&dev_priv->drm, level < 0 || level >= n_entries))
level = n_entries - 1;
for (ln = 0; ln < 4; ln++)
intel_de_write(dev_priv, SNPS_PHY_TX_EQ(ln, phy),
dg2_ddi_translations[level]);
for (ln = 0; ln < 4; ln++) {
u32 val = 0;
val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, ddi_translations->entries[level].snps.snps_vswing);
val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_PRE, ddi_translations->entries[level].snps.snps_pre_cursor);
val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, ddi_translations->entries[level].snps.snps_post_cursor);
intel_de_write(dev_priv, SNPS_PHY_TX_EQ(ln, phy), val);
}
}
/*
@ -198,11 +171,81 @@ static const struct intel_mpllb_state dg2_dp_hbr3_100 = {
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 1),
};
static const struct intel_mpllb_state *dg2_dp_100_tables[] = {
static const struct intel_mpllb_state dg2_dp_uhbr10_100 = {
.clock = 1000000,
.ref_control =
REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
.mpllb_cp =
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 4) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 21) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
.mpllb_div =
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_CLK_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_MULTIPLIER, 8) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_WORD_DIV2_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_DP2_MODE, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2),
.mpllb_div2 =
REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 2) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 368),
.mpllb_fracn1 =
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 1),
/*
* SSC will be enabled, DP UHBR has a minimum SSC requirement.
*/
.mpllb_sscen =
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_PEAK, 58982),
.mpllb_sscstep =
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 76101),
};
static const struct intel_mpllb_state dg2_dp_uhbr13_100 = {
.clock = 1350000,
.ref_control =
REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
.mpllb_cp =
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 5) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 45) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
.mpllb_div =
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_CLK_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_MULTIPLIER, 8) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_WORD_DIV2_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_DP2_MODE, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 3),
.mpllb_div2 =
REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 2) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 508),
.mpllb_fracn1 =
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 1),
/*
* SSC will be enabled, DP UHBR has a minimum SSC requirement.
*/
.mpllb_sscen =
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_PEAK, 79626),
.mpllb_sscstep =
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 102737),
};
static const struct intel_mpllb_state * const dg2_dp_100_tables[] = {
&dg2_dp_rbr_100,
&dg2_dp_hbr1_100,
&dg2_dp_hbr2_100,
&dg2_dp_hbr3_100,
&dg2_dp_uhbr10_100,
&dg2_dp_uhbr13_100,
NULL,
};
@ -311,11 +354,88 @@ static const struct intel_mpllb_state dg2_dp_hbr3_38_4 = {
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 61440),
};
static const struct intel_mpllb_state *dg2_dp_38_4_tables[] = {
static const struct intel_mpllb_state dg2_dp_uhbr10_38_4 = {
.clock = 1000000,
.ref_control =
REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 1),
.mpllb_cp =
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 5) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 26) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
.mpllb_div =
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_CLK_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_MULTIPLIER, 8) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_WORD_DIV2_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_DP2_MODE, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2),
.mpllb_div2 =
REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 488),
.mpllb_fracn1 =
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 3),
.mpllb_fracn2 =
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 2) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 27306),
/*
* SSC will be enabled, DP UHBR has a minimum SSC requirement.
*/
.mpllb_sscen =
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_PEAK, 76800),
.mpllb_sscstep =
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 129024),
};
static const struct intel_mpllb_state dg2_dp_uhbr13_38_4 = {
.clock = 1350000,
.ref_control =
REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 1),
.mpllb_cp =
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 56) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
.mpllb_div =
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_CLK_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV_MULTIPLIER, 8) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_WORD_DIV2_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_DP2_MODE, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 3),
.mpllb_div2 =
REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 670),
.mpllb_fracn1 =
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 1),
.mpllb_fracn2 =
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 36864),
/*
* SSC will be enabled, DP UHBR has a minimum SSC requirement.
*/
.mpllb_sscen =
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_EN, 1) |
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_PEAK, 103680),
.mpllb_sscstep =
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 174182),
};
static const struct intel_mpllb_state * const dg2_dp_38_4_tables[] = {
&dg2_dp_rbr_38_4,
&dg2_dp_hbr1_38_4,
&dg2_dp_hbr2_38_4,
&dg2_dp_hbr3_38_4,
&dg2_dp_uhbr10_38_4,
&dg2_dp_uhbr13_38_4,
NULL,
};
@ -448,7 +568,7 @@ static const struct intel_mpllb_state dg2_edp_r432 = {
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 65752),
};
static const struct intel_mpllb_state *dg2_edp_tables[] = {
static const struct intel_mpllb_state * const dg2_edp_tables[] = {
&dg2_dp_rbr_100,
&dg2_edp_r216,
&dg2_edp_r243,
@ -611,7 +731,7 @@ static const struct intel_mpllb_state dg2_hdmi_594 = {
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
};
static const struct intel_mpllb_state *dg2_hdmi_tables[] = {
static const struct intel_mpllb_state * const dg2_hdmi_tables[] = {
&dg2_hdmi_25_175,
&dg2_hdmi_27_0,
&dg2_hdmi_74_25,
@ -620,7 +740,7 @@ static const struct intel_mpllb_state *dg2_hdmi_tables[] = {
NULL,
};
static const struct intel_mpllb_state **
static const struct intel_mpllb_state * const *
intel_mpllb_tables_get(struct intel_crtc_state *crtc_state,
struct intel_encoder *encoder)
{
@ -654,7 +774,7 @@ intel_mpllb_tables_get(struct intel_crtc_state *crtc_state,
int intel_mpllb_calc_state(struct intel_crtc_state *crtc_state,
struct intel_encoder *encoder)
{
const struct intel_mpllb_state **tables;
const struct intel_mpllb_state * const *tables;
int i;
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
@ -850,7 +970,7 @@ void intel_mpllb_readout_hw_state(struct intel_encoder *encoder,
int intel_snps_phy_check_hdmi_link_rate(int clock)
{
const struct intel_mpllb_state **tables = dg2_hdmi_tables;
const struct intel_mpllb_state * const *tables = dg2_hdmi_tables;
int i;
for (i = 0; tables[i]; i++) {

View File

@ -30,6 +30,7 @@ int intel_mpllb_calc_port_clock(struct intel_encoder *encoder,
int intel_snps_phy_check_hdmi_link_rate(int clock);
void intel_snps_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
u32 level);
const struct intel_crtc_state *crtc_state,
int level);
#endif /* __INTEL_SNPS_PHY_H__ */

View File

@ -32,6 +32,7 @@
#include "i915_drv.h"
#include "intel_atomic.h"
#include "intel_backlight.h"
#include "intel_connector.h"
#include "intel_crtc.h"
#include "intel_de.h"
@ -278,12 +279,9 @@ static int intel_dsi_compute_config(struct intel_encoder *encoder,
pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
if (fixed_mode) {
intel_fixed_panel_mode(fixed_mode, adjusted_mode);
intel_panel_fixed_mode(fixed_mode, adjusted_mode);
if (HAS_GMCH(dev_priv))
ret = intel_gmch_panel_fitting(pipe_config, conn_state);
else
ret = intel_pch_panel_fitting(pipe_config, conn_state);
ret = intel_panel_fitting(pipe_config, conn_state);
if (ret)
return ret;
}
@ -883,7 +881,7 @@ static void intel_dsi_pre_enable(struct intel_atomic_state *state,
intel_dsi_port_enable(encoder, pipe_config);
}
intel_panel_enable_backlight(pipe_config, conn_state);
intel_backlight_enable(pipe_config, conn_state);
intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
}
@ -913,7 +911,7 @@ static void intel_dsi_disable(struct intel_atomic_state *state,
drm_dbg_kms(&i915->drm, "\n");
intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF);
intel_panel_disable_backlight(old_conn_state);
intel_backlight_disable(old_conn_state);
/*
* According to the spec we should send SHUTDOWN before
@ -1876,7 +1874,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
intel_encoder->post_disable = intel_dsi_post_disable;
intel_encoder->get_hw_state = intel_dsi_get_hw_state;
intel_encoder->get_config = intel_dsi_get_config;
intel_encoder->update_pipe = intel_panel_update_backlight;
intel_encoder->update_pipe = intel_backlight_update;
intel_encoder->shutdown = intel_dsi_shutdown;
intel_connector->get_hw_state = intel_connector_get_hw_state;
@ -1964,7 +1962,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
}
intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
intel_panel_setup_backlight(connector, INVALID_PIPE);
intel_backlight_setup(intel_connector, INVALID_PIPE);
vlv_dsi_add_properties(intel_connector);

View File

@ -352,8 +352,7 @@ struct drm_i915_display_funcs {
struct intel_crtc_state *);
void (*get_initial_plane_config)(struct intel_crtc *,
struct intel_initial_plane_config *);
int (*crtc_compute_clock)(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state);
int (*crtc_compute_clock)(struct intel_crtc_state *crtc_state);
void (*crtc_enable)(struct intel_atomic_state *state,
struct intel_crtc *crtc);
void (*crtc_disable)(struct intel_atomic_state *state,
@ -454,7 +453,7 @@ struct intel_fbc {
} fb;
unsigned int fence_y_offset;
u16 gen9_wa_cfb_stride;
u16 override_cfb_stride;
u16 interval;
s8 fence_id;
bool psr2_active;
@ -481,7 +480,7 @@ struct intel_fbc {
int cfb_size;
unsigned int fence_y_offset;
u16 gen9_wa_cfb_stride;
u16 override_cfb_stride;
u16 interval;
s8 fence_id;
bool plane_visible;
@ -636,22 +635,6 @@ i915_fence_timeout(const struct drm_i915_private *i915)
/* Amount of PSF GV points, BSpec precisely defines this */
#define I915_NUM_PSF_GV_POINTS 3
struct ddi_vbt_port_info {
/* Non-NULL if port present. */
struct intel_bios_encoder_data *devdata;
int max_tmds_clock;
/* This is an index in the HDMI/DVI DDI buffer translation table. */
u8 hdmi_level_shift;
u8 hdmi_level_shift_set:1;
u8 alternate_aux_channel;
u8 alternate_ddc_pin;
int dp_max_link_rate; /* 0 for not limited by VBT */
};
enum psr_lines_to_wait {
PSR_0_LINES_TO_WAIT = 0,
PSR_1_LINE_TO_WAIT,
@ -706,6 +689,7 @@ struct intel_vbt_data {
struct {
u16 pwm_freq_hz;
u16 brightness_precision_bits;
bool present;
bool active_low_pwm;
u8 min_brightness; /* min_brightness/255 of max */
@ -732,7 +716,7 @@ struct intel_vbt_data {
struct list_head display_devices;
struct ddi_vbt_port_info ddi_port_info[I915_MAX_PORTS];
struct intel_bios_encoder_data *ports[I915_MAX_PORTS]; /* Non-NULL if port present. */
struct sdvo_device_mapping sdvo_mappings[2];
};
@ -886,8 +870,6 @@ struct drm_i915_private {
*/
u32 gpio_mmio_base;
u32 hsw_psr_mmio_adjust;
/* MMIO base address for MIPI regs */
u32 mipi_mmio_base;
@ -1016,12 +998,6 @@ struct drm_i915_private {
struct list_head global_obj_list;
/*
* For reading active_pipes holding any crtc lock is
* sufficient, for writing must hold all of them.
*/
u8 active_pipes;
struct i915_wa_list gt_wa_list;
struct i915_frontbuffer_tracking fb_tracking;
@ -1721,6 +1697,8 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define HAS_VRR(i915) (GRAPHICS_VER(i915) >= 12)
#define HAS_ASYNC_FLIPS(i915) (DISPLAY_VER(i915) >= 5)
/* Only valid when HAS_DISPLAY() is true */
#define INTEL_DISPLAY_ENABLED(dev_priv) \
(drm_WARN_ON(&(dev_priv)->drm, !HAS_DISPLAY(dev_priv)), !(dev_priv)->params.disable_display)

View File

@ -359,9 +359,8 @@ void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv,
* @interrupt_mask: mask of interrupt bits to update
* @enabled_irq_mask: mask of interrupt bits to enable
*/
void ilk_update_display_irq(struct drm_i915_private *dev_priv,
u32 interrupt_mask,
u32 enabled_irq_mask)
static void ilk_update_display_irq(struct drm_i915_private *dev_priv,
u32 interrupt_mask, u32 enabled_irq_mask)
{
u32 new_val;
@ -380,6 +379,16 @@ void ilk_update_display_irq(struct drm_i915_private *dev_priv,
}
}
void ilk_enable_display_irq(struct drm_i915_private *i915, u32 bits)
{
ilk_update_display_irq(i915, bits, bits);
}
void ilk_disable_display_irq(struct drm_i915_private *i915, u32 bits)
{
ilk_update_display_irq(i915, bits, 0);
}
/**
* bdw_update_port_irq - update DE port interrupt
* @dev_priv: driver private
@ -419,10 +428,9 @@ static void bdw_update_port_irq(struct drm_i915_private *dev_priv,
* @interrupt_mask: mask of interrupt bits to update
* @enabled_irq_mask: mask of interrupt bits to enable
*/
void bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
enum pipe pipe,
u32 interrupt_mask,
u32 enabled_irq_mask)
static void bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
enum pipe pipe, u32 interrupt_mask,
u32 enabled_irq_mask)
{
u32 new_val;
@ -444,15 +452,27 @@ void bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
}
}
void bdw_enable_pipe_irq(struct drm_i915_private *i915,
enum pipe pipe, u32 bits)
{
bdw_update_pipe_irq(i915, pipe, bits, bits);
}
void bdw_disable_pipe_irq(struct drm_i915_private *i915,
enum pipe pipe, u32 bits)
{
bdw_update_pipe_irq(i915, pipe, bits, 0);
}
/**
* ibx_display_interrupt_update - update SDEIMR
* @dev_priv: driver private
* @interrupt_mask: mask of interrupt bits to update
* @enabled_irq_mask: mask of interrupt bits to enable
*/
void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
u32 interrupt_mask,
u32 enabled_irq_mask)
static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
u32 interrupt_mask,
u32 enabled_irq_mask)
{
u32 sdeimr = intel_uncore_read(&dev_priv->uncore, SDEIMR);
sdeimr &= ~interrupt_mask;
@ -469,6 +489,16 @@ void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
intel_uncore_posting_read(&dev_priv->uncore, SDEIMR);
}
void ibx_enable_display_interrupt(struct drm_i915_private *i915, u32 bits)
{
ibx_display_interrupt_update(i915, bits, bits);
}
void ibx_disable_display_interrupt(struct drm_i915_private *i915, u32 bits)
{
ibx_display_interrupt_update(i915, bits, 0);
}
u32 i915_pipestat_enable_mask(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
@ -2093,22 +2123,6 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
if (de_iir & DE_ERR_INT_IVB)
ivb_err_int_handler(dev_priv);
if (de_iir & DE_EDP_PSR_INT_HSW) {
struct intel_encoder *encoder;
for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
u32 psr_iir = intel_uncore_read(&dev_priv->uncore,
EDP_PSR_IIR);
intel_psr_irq_handler(intel_dp, psr_iir);
intel_uncore_write(&dev_priv->uncore,
EDP_PSR_IIR, psr_iir);
break;
}
}
if (de_iir & DE_AUX_CHANNEL_A_IVB)
dp_aux_irq_handler(dev_priv);

View File

@ -9,9 +9,9 @@
#include <linux/ktime.h>
#include <linux/types.h>
#include "display/intel_display.h"
#include "i915_reg.h"
enum pipe;
struct drm_crtc;
struct drm_device;
struct drm_display_mode;
@ -40,46 +40,15 @@ void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv);
void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv,
u32 mask,
u32 bits);
void ilk_update_display_irq(struct drm_i915_private *dev_priv,
u32 interrupt_mask,
u32 enabled_irq_mask);
static inline void
ilk_enable_display_irq(struct drm_i915_private *dev_priv, u32 bits)
{
ilk_update_display_irq(dev_priv, bits, bits);
}
static inline void
ilk_disable_display_irq(struct drm_i915_private *dev_priv, u32 bits)
{
ilk_update_display_irq(dev_priv, bits, 0);
}
void bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
enum pipe pipe,
u32 interrupt_mask,
u32 enabled_irq_mask);
static inline void bdw_enable_pipe_irq(struct drm_i915_private *dev_priv,
enum pipe pipe, u32 bits)
{
bdw_update_pipe_irq(dev_priv, pipe, bits, bits);
}
static inline void bdw_disable_pipe_irq(struct drm_i915_private *dev_priv,
enum pipe pipe, u32 bits)
{
bdw_update_pipe_irq(dev_priv, pipe, bits, 0);
}
void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
u32 interrupt_mask,
u32 enabled_irq_mask);
static inline void
ibx_enable_display_interrupt(struct drm_i915_private *dev_priv, u32 bits)
{
ibx_display_interrupt_update(dev_priv, bits, bits);
}
static inline void
ibx_disable_display_interrupt(struct drm_i915_private *dev_priv, u32 bits)
{
ibx_display_interrupt_update(dev_priv, bits, 0);
}
void ilk_enable_display_irq(struct drm_i915_private *i915, u32 bits);
void ilk_disable_display_irq(struct drm_i915_private *i915, u32 bits);
void bdw_enable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits);
void bdw_disable_pipe_irq(struct drm_i915_private *i915, enum pipe pipe, u32 bits);
void ibx_enable_display_interrupt(struct drm_i915_private *i915, u32 bits);
void ibx_disable_display_interrupt(struct drm_i915_private *i915, u32 bits);
void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, u32 mask);
void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, u32 mask);

View File

@ -537,8 +537,6 @@ static const struct intel_device_info vlv_info = {
BIT(TRANSCODER_C) | BIT(TRANSCODER_EDP), \
.display.has_ddi = 1, \
.display.has_fpga_dbg = 1, \
.display.has_psr = 1, \
.display.has_psr_hw_tracking = 1, \
.display.has_dp_mst = 1, \
.has_rc6p = 0 /* RC6p removed-by HSW */, \
HSW_PIPE_OFFSETS, \
@ -642,6 +640,8 @@ static const struct intel_device_info chv_info = {
.has_gt_uc = 1, \
.display.has_hdcp = 1, \
.display.has_ipc = 1, \
.display.has_psr = 1, \
.display.has_psr_hw_tracking = 1, \
.dbuf.size = 896 - 4, /* 4 blocks for bypass path allocation */ \
.dbuf.slice_mask = BIT(DBUF_S1)

View File

@ -2237,10 +2237,14 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
#define SNPS_PHY_MPLLB_DIV(phy) _MMIO_SNPS(phy, 0x168004)
#define SNPS_PHY_MPLLB_FORCE_EN REG_BIT(31)
#define SNPS_PHY_MPLLB_DIV_CLK_EN REG_BIT(30)
#define SNPS_PHY_MPLLB_DIV5_CLK_EN REG_BIT(29)
#define SNPS_PHY_MPLLB_V2I REG_GENMASK(27, 26)
#define SNPS_PHY_MPLLB_FREQ_VCO REG_GENMASK(25, 24)
#define SNPS_PHY_MPLLB_DIV_MULTIPLIER REG_GENMASK(23, 16)
#define SNPS_PHY_MPLLB_PMIX_EN REG_BIT(10)
#define SNPS_PHY_MPLLB_DP2_MODE REG_BIT(9)
#define SNPS_PHY_MPLLB_WORD_DIV2_EN REG_BIT(8)
#define SNPS_PHY_MPLLB_TX_CLK_DIV REG_GENMASK(7, 5)
#define SNPS_PHY_MPLLB_FRACN1(phy) _MMIO_SNPS(phy, 0x168008)
@ -4509,11 +4513,9 @@ enum {
* HSW PSR registers are relative to DDIA(_DDI_BUF_CTL_A + 0x800) with just one
* instance of it
*/
#define _HSW_EDP_PSR_BASE 0x64800
#define _SRD_CTL_A 0x60800
#define _SRD_CTL_EDP 0x6f800
#define _PSR_ADJ(tran, reg) (_TRANS2(tran, reg) - dev_priv->hsw_psr_mmio_adjust)
#define EDP_PSR_CTL(tran) _MMIO(_PSR_ADJ(tran, _SRD_CTL_A))
#define EDP_PSR_CTL(tran) _MMIO(_TRANS2(tran, _SRD_CTL_A))
#define EDP_PSR_ENABLE (1 << 31)
#define BDW_PSR_SINGLE_FRAME (1 << 30)
#define EDP_PSR_RESTORE_PSR_ACTIVE_CTX_MASK (1 << 29) /* SW can't modify */
@ -4557,22 +4559,13 @@ enum {
#define EDP_PSR_POST_EXIT(trans) (0x2 << _EDP_PSR_TRANS_SHIFT(trans))
#define EDP_PSR_PRE_ENTRY(trans) (0x1 << _EDP_PSR_TRANS_SHIFT(trans))
#define _SRD_AUX_CTL_A 0x60810
#define _SRD_AUX_CTL_EDP 0x6f810
#define EDP_PSR_AUX_CTL(tran) _MMIO(_PSR_ADJ(tran, _SRD_AUX_CTL_A))
#define EDP_PSR_AUX_CTL_TIME_OUT_MASK (3 << 26)
#define EDP_PSR_AUX_CTL_MESSAGE_SIZE_MASK (0x1f << 20)
#define EDP_PSR_AUX_CTL_PRECHARGE_2US_MASK (0xf << 16)
#define EDP_PSR_AUX_CTL_ERROR_INTERRUPT (1 << 11)
#define EDP_PSR_AUX_CTL_BIT_CLOCK_2X_MASK (0x7ff)
#define _SRD_AUX_DATA_A 0x60814
#define _SRD_AUX_DATA_EDP 0x6f814
#define EDP_PSR_AUX_DATA(tran, i) _MMIO(_PSR_ADJ(tran, _SRD_AUX_DATA_A) + (i) + 4) /* 5 registers */
#define EDP_PSR_AUX_DATA(tran, i) _MMIO(_TRANS2(tran, _SRD_AUX_DATA_A) + (i) + 4) /* 5 registers */
#define _SRD_STATUS_A 0x60840
#define _SRD_STATUS_EDP 0x6f840
#define EDP_PSR_STATUS(tran) _MMIO(_PSR_ADJ(tran, _SRD_STATUS_A))
#define EDP_PSR_STATUS(tran) _MMIO(_TRANS2(tran, _SRD_STATUS_A))
#define EDP_PSR_STATUS_STATE_MASK (7 << 29)
#define EDP_PSR_STATUS_STATE_SHIFT 29
#define EDP_PSR_STATUS_STATE_IDLE (0 << 29)
@ -4599,13 +4592,13 @@ enum {
#define _SRD_PERF_CNT_A 0x60844
#define _SRD_PERF_CNT_EDP 0x6f844
#define EDP_PSR_PERF_CNT(tran) _MMIO(_PSR_ADJ(tran, _SRD_PERF_CNT_A))
#define EDP_PSR_PERF_CNT(tran) _MMIO(_TRANS2(tran, _SRD_PERF_CNT_A))
#define EDP_PSR_PERF_CNT_MASK 0xffffff
/* PSR_MASK on SKL+ */
#define _SRD_DEBUG_A 0x60860
#define _SRD_DEBUG_EDP 0x6f860
#define EDP_PSR_DEBUG(tran) _MMIO(_PSR_ADJ(tran, _SRD_DEBUG_A))
#define EDP_PSR_DEBUG(tran) _MMIO(_TRANS2(tran, _SRD_DEBUG_A))
#define EDP_PSR_DEBUG_MASK_MAX_SLEEP (1 << 28)
#define EDP_PSR_DEBUG_MASK_LPSP (1 << 27)
#define EDP_PSR_DEBUG_MASK_MEMUP (1 << 26)
@ -8176,8 +8169,9 @@ enum {
#define GLK_CL0_PWR_DOWN (1 << 10)
#define CHICKEN_MISC_4 _MMIO(0x4208c)
#define FBC_STRIDE_OVERRIDE (1 << 13)
#define FBC_STRIDE_MASK 0x1FFF
#define CHICKEN_FBC_STRIDE_OVERRIDE REG_BIT(13)
#define CHICKEN_FBC_STRIDE_MASK REG_GENMASK(12, 0)
#define CHICKEN_FBC_STRIDE(x) REG_FIELD_PREP(CHICKEN_FBC_STRIDE_MASK, (x))
#define _CHICKEN_PIPESL_1_A 0x420b0
#define _CHICKEN_PIPESL_1_B 0x420b4
@ -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)

View File

@ -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)

View File

@ -8,7 +8,6 @@
#include <linux/types.h>
#include "display/intel_bw.h"
#include "display/intel_display.h"
#include "display/intel_global_state.h"
@ -19,6 +18,7 @@ struct drm_device;
struct drm_i915_private;
struct i915_request;
struct intel_atomic_state;
struct intel_bw_state;
struct intel_crtc;
struct intel_crtc_state;
struct intel_plane;

View File

@ -8,8 +8,6 @@
#include <linux/types.h>
#include "display/intel_display.h"
#include "intel_wakeref.h"
#include "i915_utils.h"

View File

@ -4,6 +4,7 @@ menu "USB Type-C Alternate Mode drivers"
config TYPEC_DP_ALTMODE
tristate "DisplayPort Alternate Mode driver"
depends on DRM
help
DisplayPort USB Type-C Alternate Mode allows DisplayPort
displays and adapters to be attached to the USB Type-C

View File

@ -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);

View File

@ -47,6 +47,8 @@ static bool use_bgrt = true;
static bool request_mem_succeeded = false;
static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
static struct pci_dev *efifb_pci_dev; /* dev with BAR covering the efifb */
static struct fb_var_screeninfo efifb_defined = {
.activate = FB_ACTIVATE_NOW,
.height = -1,
@ -243,6 +245,9 @@ static inline void efifb_show_boot_graphics(struct fb_info *info) {}
static void efifb_destroy(struct fb_info *info)
{
if (efifb_pci_dev)
pm_runtime_put(&efifb_pci_dev->dev);
if (info->screen_base) {
if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
iounmap(info->screen_base);
@ -333,7 +338,6 @@ ATTRIBUTE_GROUPS(efifb);
static bool pci_dev_disabled; /* FB base matches BAR of a disabled device */
static struct pci_dev *efifb_pci_dev; /* dev with BAR covering the efifb */
static struct resource *bar_resource;
static u64 bar_offset;
@ -569,17 +573,22 @@ static int efifb_probe(struct platform_device *dev)
pr_err("efifb: cannot allocate colormap\n");
goto err_groups;
}
if (efifb_pci_dev)
WARN_ON(pm_runtime_get_sync(&efifb_pci_dev->dev) < 0);
err = register_framebuffer(info);
if (err < 0) {
pr_err("efifb: cannot register framebuffer\n");
goto err_fb_dealoc;
goto err_put_rpm_ref;
}
fb_info(info, "%s frame buffer device\n", info->fix.id);
if (efifb_pci_dev)
pm_runtime_get_sync(&efifb_pci_dev->dev);
return 0;
err_fb_dealoc:
err_put_rpm_ref:
if (efifb_pci_dev)
pm_runtime_put(&efifb_pci_dev->dev);
fb_dealloc_cmap(&info->cmap);
err_groups:
sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
@ -603,8 +612,6 @@ static int efifb_remove(struct platform_device *pdev)
unregister_framebuffer(info);
sysfs_remove_groups(&pdev->dev.kobj, efifb_groups);
framebuffer_release(info);
if (efifb_pci_dev)
pm_runtime_put(&efifb_pci_dev->dev);
return 0;
}

View File

@ -590,6 +590,18 @@ struct drm_display_info {
* @monitor_range: Frequency range supported by monitor range descriptor
*/
struct drm_monitor_range_info monitor_range;
/**
* @mso_stream_count: eDP Multi-SST Operation (MSO) stream count from
* the DisplayID VESA vendor block. 0 for conventional Single-Stream
* Transport (SST), or 2 or 4 MSO streams.
*/
u8 mso_stream_count;
/**
* @mso_pixel_overlap: eDP MSO segment pixel overlap, 0-8 pixels.
*/
u8 mso_pixel_overlap;
};
int drm_display_info_set_bus_formats(struct drm_display_info *info,
@ -1084,6 +1096,14 @@ struct drm_connector_funcs {
*/
void (*atomic_print_state)(struct drm_printer *p,
const struct drm_connector_state *state);
/**
* @oob_hotplug_event:
*
* This will get called when a hotplug-event for a drm-connector
* has been received from a source outside the display driver / device.
*/
void (*oob_hotplug_event)(struct drm_connector *connector);
};
/**
@ -1228,6 +1248,14 @@ struct drm_connector {
struct device *kdev;
/** @attr: sysfs attributes */
struct device_attribute *attr;
/**
* @fwnode: associated fwnode supplied by platform firmware
*
* Drivers can set this to associate a fwnode with a connector, drivers
* are expected to get a reference on the fwnode when setting this.
* drm_connector_cleanup() will call fwnode_handle_put() on this.
*/
struct fwnode_handle *fwnode;
/**
* @head:
@ -1239,6 +1267,14 @@ struct drm_connector {
*/
struct list_head head;
/**
* @global_connector_list_entry:
*
* Connector entry in the global connector-list, used by
* drm_connector_find_by_fwnode().
*/
struct list_head global_connector_list_entry;
/** @base: base KMS object */
struct drm_mode_object base;
@ -1650,6 +1686,7 @@ drm_connector_is_unregistered(struct drm_connector *connector)
DRM_CONNECTOR_UNREGISTERED;
}
void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode);
const char *drm_get_connector_type_name(unsigned int connector_type);
const char *drm_get_connector_status_name(enum drm_connector_status status);
const char *drm_get_subpixel_order_name(enum subpixel_order order);

View File

@ -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;

View File

@ -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)