22,7 → 22,11 |
* |
* Authors: |
* Eric Anholt <eric@anholt.net> |
* Thomas Richter <thor@math.tu-berlin.de> |
* |
* Minor modifications (Dithering enable): |
* Thomas Richter <thor@math.tu-berlin.de> |
* |
*/ |
|
#include "dvo.h" |
59,6 → 63,8 |
# define VR01_DVO_BYPASS_ENABLE (1 << 1) |
/** Enables the DVO clock */ |
# define VR01_DVO_ENABLE (1 << 0) |
/** Enable dithering for 18bpp panels. Not documented. */ |
# define VR01_DITHER_ENABLE (1 << 4) |
|
/* |
* LCD Interface Format |
74,6 → 80,8 |
# define VR10_INTERFACE_2X18 (2 << 2) |
/** Enables 2x24-bit LVDS output */ |
# define VR10_INTERFACE_2X24 (3 << 2) |
/** Mask that defines the depth of the pipeline */ |
# define VR10_INTERFACE_DEPTH_MASK (3 << 2) |
|
/* |
* VR20 LCD Horizontal Display Size |
83,7 → 91,7 |
/* |
* LCD Vertical Display Size |
*/ |
#define VR21 0x20 |
#define VR21 0x21 |
|
/* |
* Panel power down status |
148,16 → 156,33 |
# define VR8F_POWER_MASK (0x3c) |
# define VR8F_POWER_POS (2) |
|
/* Some Bios implementations do not restore the DVO state upon |
* resume from standby. Thus, this driver has to handle it |
* instead. The following list contains all registers that |
* require saving. |
*/ |
static const uint16_t backup_addresses[] = { |
0x11, 0x12, |
0x18, 0x19, 0x1a, 0x1f, |
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, |
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, |
0x8e, 0x8f, |
0x10 /* this must come last */ |
}; |
|
|
struct ivch_priv { |
bool quiet; |
|
uint16_t width, height; |
|
/* Register backup */ |
|
uint16_t reg_backup[ARRAY_SIZE(backup_addresses)]; |
}; |
|
|
static void ivch_dump_regs(struct intel_dvo_device *dvo); |
|
/** |
* Reads a register on the ivch. |
* |
239,6 → 264,7 |
{ |
struct ivch_priv *priv; |
uint16_t temp; |
int i; |
|
priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL); |
if (priv == NULL) |
266,6 → 292,14 |
ivch_read(dvo, VR20, &priv->width); |
ivch_read(dvo, VR21, &priv->height); |
|
/* Make a backup of the registers to be able to restore them |
* upon suspend. |
*/ |
for (i = 0; i < ARRAY_SIZE(backup_addresses); i++) |
ivch_read(dvo, backup_addresses[i], priv->reg_backup + i); |
|
ivch_dump_regs(dvo); |
|
return true; |
|
out: |
287,6 → 321,23 |
return MODE_OK; |
} |
|
/* Restore the DVO registers after a resume |
* from RAM. Registers have been saved during |
* the initialization. |
*/ |
static void ivch_reset(struct intel_dvo_device *dvo) |
{ |
struct ivch_priv *priv = dvo->dev_priv; |
int i; |
|
DRM_DEBUG_KMS("Resetting the IVCH registers\n"); |
|
ivch_write(dvo, VR10, 0x0000); |
|
for (i = 0; i < ARRAY_SIZE(backup_addresses); i++) |
ivch_write(dvo, backup_addresses[i], priv->reg_backup[i]); |
} |
|
/** Sets the power state of the panel connected to the ivch */ |
static void ivch_dpms(struct intel_dvo_device *dvo, bool enable) |
{ |
293,6 → 344,8 |
int i; |
uint16_t vr01, vr30, backlight; |
|
ivch_reset(dvo); |
|
/* Set the new power state of the panel. */ |
if (!ivch_read(dvo, VR01, &vr01)) |
return; |
301,6 → 354,7 |
backlight = 1; |
else |
backlight = 0; |
|
ivch_write(dvo, VR80, backlight); |
|
if (enable) |
327,6 → 381,8 |
{ |
uint16_t vr01; |
|
ivch_reset(dvo); |
|
/* Set the new power state of the panel. */ |
if (!ivch_read(dvo, VR01, &vr01)) |
return false; |
338,26 → 394,36 |
} |
|
static void ivch_mode_set(struct intel_dvo_device *dvo, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
const struct drm_display_mode *mode, |
const struct drm_display_mode *adjusted_mode) |
{ |
struct ivch_priv *priv = dvo->dev_priv; |
uint16_t vr40 = 0; |
uint16_t vr01; |
uint16_t vr01 = 0; |
uint16_t vr10; |
|
vr01 = 0; |
ivch_reset(dvo); |
|
vr10 = priv->reg_backup[ARRAY_SIZE(backup_addresses) - 1]; |
|
/* Enable dithering for 18 bpp pipelines */ |
vr10 &= VR10_INTERFACE_DEPTH_MASK; |
if (vr10 == VR10_INTERFACE_2X18 || vr10 == VR10_INTERFACE_1X18) |
vr01 = VR01_DITHER_ENABLE; |
|
vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE | |
VR40_HORIZONTAL_INTERP_ENABLE); |
|
if (mode->hdisplay != adjusted_mode->hdisplay || |
mode->vdisplay != adjusted_mode->vdisplay) { |
if (mode->hdisplay != adjusted_mode->crtc_hdisplay || |
mode->vdisplay != adjusted_mode->crtc_vdisplay) { |
uint16_t x_ratio, y_ratio; |
|
vr01 |= VR01_PANEL_FIT_ENABLE; |
vr40 |= VR40_CLOCK_GATING_ENABLE; |
x_ratio = (((mode->hdisplay - 1) << 16) / |
(adjusted_mode->hdisplay - 1)) >> 2; |
(adjusted_mode->crtc_hdisplay - 1)) >> 2; |
y_ratio = (((mode->vdisplay - 1) << 16) / |
(adjusted_mode->vdisplay - 1)) >> 2; |
(adjusted_mode->crtc_vdisplay - 1)) >> 2; |
ivch_write(dvo, VR42, x_ratio); |
ivch_write(dvo, VR41, y_ratio); |
} else { |
368,8 → 434,6 |
|
ivch_write(dvo, VR01, vr01); |
ivch_write(dvo, VR40, vr40); |
|
ivch_dump_regs(dvo); |
} |
|
static void ivch_dump_regs(struct intel_dvo_device *dvo) |
380,6 → 444,8 |
DRM_DEBUG_KMS("VR00: 0x%04x\n", val); |
ivch_read(dvo, VR01, &val); |
DRM_DEBUG_KMS("VR01: 0x%04x\n", val); |
ivch_read(dvo, VR10, &val); |
DRM_DEBUG_KMS("VR10: 0x%04x\n", val); |
ivch_read(dvo, VR30, &val); |
DRM_DEBUG_KMS("VR30: 0x%04x\n", val); |
ivch_read(dvo, VR40, &val); |