mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 09:50:04 +00:00
![Ville Syrjälä](/assets/img/avatar_default.png)
VBT appears to have two (or possibly three) ways to indicate the panel rotation. The first is in the MIPI config block, but that apparenly usually (maybe always?) indicates 0 degrees despite the actual panel orientation. The second way to indicate this is in the general features block, which can just indicate whether 180 degress rotation is used. The third might be a separate rotation data block, but that is not at all documented so who knows what it may contain. Let's try the first two. We first try the DSI specicic VBT information, and it it doesn't look trustworthy (ie. indicates 0 degrees) we fall back to the 180 degree thing. Just to avoid too many changes in one go we shall also keep the hardware readout path for now. If this works for more than just my VLV FFRD the question becomes how many of the panel orientation quirks are now redundant? v2: Move the code into intel_dsi.c (Jani) Cc: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20181022142015.4026-1-ville.syrjala@linux.intel.com Tested-by: Hans de Goede <hdegoede@redhat.com>
128 lines
3 KiB
C
128 lines
3 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Copyright © 2018 Intel Corporation
|
|
*/
|
|
|
|
#include <drm/drm_mipi_dsi.h>
|
|
#include "intel_dsi.h"
|
|
|
|
int intel_dsi_bitrate(const struct intel_dsi *intel_dsi)
|
|
{
|
|
int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
|
|
|
|
if (WARN_ON(bpp < 0))
|
|
bpp = 16;
|
|
|
|
return intel_dsi->pclk * bpp / intel_dsi->lane_count;
|
|
}
|
|
|
|
int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi)
|
|
{
|
|
switch (intel_dsi->escape_clk_div) {
|
|
default:
|
|
case 0:
|
|
return 50;
|
|
case 1:
|
|
return 100;
|
|
case 2:
|
|
return 200;
|
|
}
|
|
}
|
|
|
|
int intel_dsi_get_modes(struct drm_connector *connector)
|
|
{
|
|
struct intel_connector *intel_connector = to_intel_connector(connector);
|
|
struct drm_display_mode *mode;
|
|
|
|
DRM_DEBUG_KMS("\n");
|
|
|
|
if (!intel_connector->panel.fixed_mode) {
|
|
DRM_DEBUG_KMS("no fixed mode\n");
|
|
return 0;
|
|
}
|
|
|
|
mode = drm_mode_duplicate(connector->dev,
|
|
intel_connector->panel.fixed_mode);
|
|
if (!mode) {
|
|
DRM_DEBUG_KMS("drm_mode_duplicate failed\n");
|
|
return 0;
|
|
}
|
|
|
|
drm_mode_probed_add(connector, mode);
|
|
return 1;
|
|
}
|
|
|
|
enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector,
|
|
struct drm_display_mode *mode)
|
|
{
|
|
struct intel_connector *intel_connector = to_intel_connector(connector);
|
|
const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
|
|
int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
|
|
|
|
DRM_DEBUG_KMS("\n");
|
|
|
|
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
|
return MODE_NO_DBLESCAN;
|
|
|
|
if (fixed_mode) {
|
|
if (mode->hdisplay > fixed_mode->hdisplay)
|
|
return MODE_PANEL;
|
|
if (mode->vdisplay > fixed_mode->vdisplay)
|
|
return MODE_PANEL;
|
|
if (fixed_mode->clock > max_dotclk)
|
|
return MODE_CLOCK_HIGH;
|
|
}
|
|
|
|
return MODE_OK;
|
|
}
|
|
|
|
struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi,
|
|
const struct mipi_dsi_host_ops *funcs,
|
|
enum port port)
|
|
{
|
|
struct intel_dsi_host *host;
|
|
struct mipi_dsi_device *device;
|
|
|
|
host = kzalloc(sizeof(*host), GFP_KERNEL);
|
|
if (!host)
|
|
return NULL;
|
|
|
|
host->base.ops = funcs;
|
|
host->intel_dsi = intel_dsi;
|
|
host->port = port;
|
|
|
|
/*
|
|
* We should call mipi_dsi_host_register(&host->base) here, but we don't
|
|
* have a host->dev, and we don't have OF stuff either. So just use the
|
|
* dsi framework as a library and hope for the best. Create the dsi
|
|
* devices by ourselves here too. Need to be careful though, because we
|
|
* don't initialize any of the driver model devices here.
|
|
*/
|
|
device = kzalloc(sizeof(*device), GFP_KERNEL);
|
|
if (!device) {
|
|
kfree(host);
|
|
return NULL;
|
|
}
|
|
|
|
device->host = &host->base;
|
|
host->device = device;
|
|
|
|
return host;
|
|
}
|
|
|
|
enum drm_panel_orientation
|
|
intel_dsi_get_panel_orientation(struct intel_connector *connector)
|
|
{
|
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
|
enum drm_panel_orientation orientation;
|
|
|
|
orientation = dev_priv->vbt.dsi.orientation;
|
|
if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
|
|
return orientation;
|
|
|
|
orientation = dev_priv->vbt.orientation;
|
|
if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
|
|
return orientation;
|
|
|
|
return DRM_MODE_PANEL_ORIENTATION_NORMAL;
|
|
}
|