sync with OpenBSD -current

This commit is contained in:
purplerain 2024-01-18 08:29:14 +00:00
parent ee68147dcd
commit 1cefe29c7e
Signed by: purplerain
GPG key ID: F42C07F07E2E35B7
1651 changed files with 283292 additions and 68089 deletions

View file

@ -31,13 +31,18 @@
#include <linux/kernel.h>
#include <linux/pwm.h>
#include <drm/drm_edid.h>
#include "i915_reg.h"
#include "intel_backlight.h"
#include "intel_connector.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_drrs.h"
#include "intel_lvds_regs.h"
#include "intel_panel.h"
#include "intel_quirks.h"
#include "intel_vrr.h"
bool intel_panel_use_ssc(struct drm_i915_private *i915)
{
@ -54,6 +59,38 @@ intel_panel_preferred_fixed_mode(struct intel_connector *connector)
struct drm_display_mode, head);
}
static bool is_in_vrr_range(struct intel_connector *connector, int vrefresh)
{
const struct drm_display_info *info = &connector->base.display_info;
return intel_vrr_is_capable(connector) &&
vrefresh >= info->monitor_range.min_vfreq &&
vrefresh <= info->monitor_range.max_vfreq;
}
static bool is_best_fixed_mode(struct intel_connector *connector,
int vrefresh, int fixed_mode_vrefresh,
const struct drm_display_mode *best_mode)
{
/* we want to always return something */
if (!best_mode)
return true;
/*
* With VRR always pick a mode with equal/higher than requested
* vrefresh, which we can then reduce to match the requested
* vrefresh by extending the vblank length.
*/
if (is_in_vrr_range(connector, vrefresh) &&
is_in_vrr_range(connector, fixed_mode_vrefresh) &&
fixed_mode_vrefresh < vrefresh)
return false;
/* pick the fixed_mode that is closest in terms of vrefresh */
return abs(fixed_mode_vrefresh - vrefresh) <
abs(drm_mode_vrefresh(best_mode) - vrefresh);
}
const struct drm_display_mode *
intel_panel_fixed_mode(struct intel_connector *connector,
const struct drm_display_mode *mode)
@ -61,11 +98,11 @@ intel_panel_fixed_mode(struct intel_connector *connector,
const struct drm_display_mode *fixed_mode, *best_mode = NULL;
int vrefresh = drm_mode_vrefresh(mode);
/* pick the fixed_mode that is closest in terms of vrefresh */
list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
if (!best_mode ||
abs(drm_mode_vrefresh(fixed_mode) - vrefresh) <
abs(drm_mode_vrefresh(best_mode) - vrefresh))
int fixed_mode_vrefresh = drm_mode_vrefresh(fixed_mode);
if (is_best_fixed_mode(connector, vrefresh,
fixed_mode_vrefresh, best_mode))
best_mode = fixed_mode;
}
@ -148,12 +185,24 @@ int intel_panel_get_modes(struct intel_connector *connector)
return num_modes;
}
static bool has_drrs_modes(struct intel_connector *connector)
{
const struct drm_display_mode *mode1;
list_for_each_entry(mode1, &connector->panel.fixed_modes, head) {
const struct drm_display_mode *mode2 = mode1;
list_for_each_entry_continue(mode2, &connector->panel.fixed_modes, head) {
if (is_alt_drrs_mode(mode1, mode2))
return true;
}
}
return false;
}
enum drrs_type intel_panel_drrs_type(struct intel_connector *connector)
{
if (list_empty(&connector->panel.fixed_modes) ||
list_is_singular(&connector->panel.fixed_modes))
return DRRS_TYPE_NONE;
return connector->panel.vbt.drrs_type;
}
@ -162,27 +211,46 @@ int intel_panel_compute_config(struct intel_connector *connector,
{
const struct drm_display_mode *fixed_mode =
intel_panel_fixed_mode(connector, adjusted_mode);
int vrefresh, fixed_mode_vrefresh;
bool is_vrr;
if (!fixed_mode)
return 0;
/*
* We don't want to lie too much to the user about the refresh
* rate they're going to get. But we have to allow a bit of latitude
* for Xorg since it likes to automagically cook up modes with slightly
* off refresh rates.
*/
if (abs(drm_mode_vrefresh(adjusted_mode) - drm_mode_vrefresh(fixed_mode)) > 1) {
drm_dbg_kms(connector->base.dev,
"[CONNECTOR:%d:%s] Requested mode vrefresh (%d Hz) does not match fixed mode vrefresh (%d Hz)\n",
connector->base.base.id, connector->base.name,
drm_mode_vrefresh(adjusted_mode), drm_mode_vrefresh(fixed_mode));
vrefresh = drm_mode_vrefresh(adjusted_mode);
fixed_mode_vrefresh = drm_mode_vrefresh(fixed_mode);
return -EINVAL;
/*
* Assume that we shouldn't muck about with the
* timings if they don't land in the VRR range.
*/
is_vrr = is_in_vrr_range(connector, vrefresh) &&
is_in_vrr_range(connector, fixed_mode_vrefresh);
if (!is_vrr) {
/*
* We don't want to lie too much to the user about the refresh
* rate they're going to get. But we have to allow a bit of latitude
* for Xorg since it likes to automagically cook up modes with slightly
* off refresh rates.
*/
if (abs(vrefresh - fixed_mode_vrefresh) > 1) {
drm_dbg_kms(connector->base.dev,
"[CONNECTOR:%d:%s] Requested mode vrefresh (%d Hz) does not match fixed mode vrefresh (%d Hz)\n",
connector->base.base.id, connector->base.name,
vrefresh, fixed_mode_vrefresh);
return -EINVAL;
}
}
drm_mode_copy(adjusted_mode, fixed_mode);
if (is_vrr && fixed_mode_vrefresh != vrefresh)
adjusted_mode->vtotal =
DIV_ROUND_CLOSEST(adjusted_mode->clock * 1000,
adjusted_mode->htotal * vrefresh);
drm_mode_set_crtcinfo(adjusted_mode, 0);
return 0;
@ -496,11 +564,11 @@ static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state,
bits = panel_fitter_scaling(pipe_src_h,
adjusted_mode->crtc_vdisplay);
*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
bits << PFIT_VERT_SCALE_SHIFT);
*pfit_pgm_ratios |= (PFIT_HORIZ_SCALE(bits) |
PFIT_VERT_SCALE(bits));
*pfit_control |= (PFIT_ENABLE |
VERT_INTERP_BILINEAR |
HORIZ_INTERP_BILINEAR);
PFIT_VERT_INTERP_BILINEAR |
PFIT_HORIZ_INTERP_BILINEAR);
}
} else if (scaled_width < scaled_height) { /* letter */
centre_vertically(adjusted_mode,
@ -511,18 +579,19 @@ static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state,
bits = panel_fitter_scaling(pipe_src_w,
adjusted_mode->crtc_hdisplay);
*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
bits << PFIT_VERT_SCALE_SHIFT);
*pfit_pgm_ratios |= (PFIT_HORIZ_SCALE(bits) |
PFIT_VERT_SCALE(bits));
*pfit_control |= (PFIT_ENABLE |
VERT_INTERP_BILINEAR |
HORIZ_INTERP_BILINEAR);
PFIT_VERT_INTERP_BILINEAR |
PFIT_HORIZ_INTERP_BILINEAR);
}
} else {
/* Aspects match, Let hw scale both directions */
*pfit_control |= (PFIT_ENABLE |
VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
VERT_INTERP_BILINEAR |
HORIZ_INTERP_BILINEAR);
PFIT_VERT_AUTO_SCALE |
PFIT_HORIZ_AUTO_SCALE |
PFIT_VERT_INTERP_BILINEAR |
PFIT_HORIZ_INTERP_BILINEAR);
}
}
@ -570,10 +639,10 @@ static int gmch_panel_fitting(struct intel_crtc_state *crtc_state,
if (DISPLAY_VER(dev_priv) >= 4)
pfit_control |= PFIT_SCALING_AUTO;
else
pfit_control |= (VERT_AUTO_SCALE |
VERT_INTERP_BILINEAR |
HORIZ_AUTO_SCALE |
HORIZ_INTERP_BILINEAR);
pfit_control |= (PFIT_VERT_AUTO_SCALE |
PFIT_VERT_INTERP_BILINEAR |
PFIT_HORIZ_AUTO_SCALE |
PFIT_HORIZ_INTERP_BILINEAR);
}
break;
default:
@ -594,7 +663,7 @@ out:
/* Make sure pre-965 set dither correctly for 18bpp panels. */
if (DISPLAY_VER(dev_priv) < 4 && crtc_state->pipe_bpp == 18)
pfit_control |= PANEL_8TO6_DITHER_ENABLE;
pfit_control |= PFIT_PANEL_8TO6_DITHER_ENABLE;
crtc_state->gmch_pfit.control = pfit_control;
crtc_state->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
@ -653,15 +722,22 @@ void intel_panel_init_alloc(struct intel_connector *connector)
struct intel_panel *panel = &connector->panel;
connector->panel.vbt.panel_type = -1;
connector->panel.vbt.backlight.controller = -1;
INIT_LIST_HEAD(&panel->fixed_modes);
}
int intel_panel_init(struct intel_connector *connector)
int intel_panel_init(struct intel_connector *connector,
const struct drm_edid *fixed_edid)
{
struct intel_panel *panel = &connector->panel;
panel->fixed_edid = fixed_edid;
intel_backlight_init_funcs(panel);
if (!has_drrs_modes(connector))
connector->panel.vbt.drrs_type = DRRS_TYPE_NONE;
drm_dbg_kms(connector->base.dev,
"[CONNECTOR:%d:%s] DRRS type: %s\n",
connector->base.base.id, connector->base.name,
@ -675,6 +751,9 @@ void intel_panel_fini(struct intel_connector *connector)
struct intel_panel *panel = &connector->panel;
struct drm_display_mode *fixed_mode, *next;
if (!IS_ERR_OR_NULL(panel->fixed_edid))
drm_edid_free(panel->fixed_edid);
intel_backlight_destroy(panel);
intel_bios_fini_panel(panel);