From 205b06b85ecfbc62e39bb581e1e2e5e0f545ed47 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 28 Feb 2011 14:44:24 -0600 Subject: [PATCH] [drm/i915] - Implement direct support for 24 bit LVDS pixel format LVDS digital data can be formatted as 18 bits/pixel or one of two 24 bits/pixel possibilities. All are incompatible with one another, so the GPU's LVDS output has to be configured to match the format expected by the display device. In many (most) cases this is generally not a problem because the LVDS device is integral to the processor board (e.g. a laptop) and thus the video BIOS already sets this up correctly as part of the boot process. Then the i915 drm simply works with what has been already set up. But there are cases where the LVDS-driven display and the GPU are discrete components - this can happen in embedded environments where the processor board is a COTS device with its own BIOS and the display is added to it later. In that situation the video BIOS on the processor board can't know anything about the LVDS display which leads to problems if the pixel format is not 18 bit (usually 18 bit is the default). This patch implements a new kernel option for the i915 kernel module: "lvds_24bit". The default value of zero preserves the previous "don't change anything" behavior. If it is set to "1" or "2" then 24 bit format is enabled - the choice between "1" and "2" selects the particular 24 bit format. If it is set to "3" then 24 format is specifically disabled, which should be an extremely rare case but is included for completeness. There was a similar patch back in 2008 to support 24 bit LVDS with the user-mode xorg intel driver, using a new driver option in the xorg.conf file. However that patch was a casualty of the move to kernel mode switching. This patch implements the same sort of solution, just now it's in the kernel drm driver for i915 driven GPUs. Signed-Off-By: Mike Isely --- drivers/gpu/drm/i915/i915_drv.c | 4 +++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_reg.h | 7 ++++++ drivers/gpu/drm/i915/intel_display.c | 38 ++++++++++++++++++++++++++++++--- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index da769bc..c89f71c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -49,6 +49,10 @@ module_param_named(powersave, i915_powersave, int, 0600); unsigned int i915_lvds_downclock = 0; module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); +unsigned int i915_lvds_24bit = 0; +module_param_named(lvds_24bit, i915_lvds_24bit, int, 0600); +MODULE_PARM_DESC(lvds_24bit, "LVDS 24 bit pixel format: 0=leave untouched (default), 1=24 bit '2.0' format, 2=24 bit '2.1' format, 3=force older 18 bit format"); + static struct drm_driver driver; extern int intel_agp_enabled; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d2896eb..526cef2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -886,6 +886,7 @@ extern int i915_max_ioctl; extern unsigned int i915_fbpercrtc; extern unsigned int i915_powersave; extern unsigned int i915_lvds_downclock; +extern unsigned int i915_lvds_24bit; extern int i915_suspend(struct drm_device *dev, pm_message_t state); extern int i915_resume(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0a1b276..ffe7f45 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1320,6 +1320,13 @@ #define LVDS_PIPEB_SELECT (1 << 30) /* LVDS dithering flag on 965/g4x platform */ #define LVDS_ENABLE_DITHER (1 << 25) +/* + * Selects between .0 and .1 formats: + * + * 0 = 1x18.0, 2x18.0, 1x24.0 or 2x24.0 + * 1 = 1x24.1 or 2x24.1 + */ +#define LVDS_DATA_FORMAT_DOT_ONE (1 << 24) /* Enable border for unscaled (or aspect-scaled) display */ #define LVDS_BORDER_ENABLE (1 << 15) /* diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3abd904..7f5742c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4029,10 +4029,40 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, else temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); - /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) - * appropriately here, but we need to look more thoroughly into how - * panels behave in the two modes. - */ + /* Control the output pixel format. */ + switch (i915_lvds_24bit) { + default: + case 0: + /* 0 means don't mess with 18 vs 24 bit LVDS pixel + * format. Instead we trust whatever the video + * BIOS should have done to set up the panel. + * This is normally the safest choice since most + * LVDS-connected panels are integral to the + * system and thus the video BIOS knows how to set + * it up appropriately. */ + break; + case 1: + /* Enable 24 bit pixel mode using the "2.0" format */ + temp |= LVDS_A3_POWER_UP; + temp &= ~LVDS_DATA_FORMAT_DOT_ONE; + break; + case 2: + /* Enable 24 bit pixel mode using the "2.1" + * format; this choice is equivalent to the + * LVDS24BitMode option in the old pre-KMS user + * space driver. */ + temp |= LVDS_A3_POWER_UP; + temp |= LVDS_DATA_FORMAT_DOT_ONE; + break; + case 3: + /* Enable 18 bit pixel mode - this should be a + very rare case since this is usually the + power-up mode if the video BIOS didn't set + things up. But it's here for completeness. */ + temp &= ~LVDS_A3_POWER_UP; + temp &= ~LVDS_DATA_FORMAT_DOT_ONE; + break; + } /* set the dithering flag on non-PCH LVDS as needed */ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { if (dev_priv->lvds_dither) -- 1.5.6.5