summaryrefslogtreecommitdiff
path: root/src/i830_lvds.c
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2009-09-30 16:29:53 -0700
committerEric Anholt <eric@anholt.net>2009-10-06 16:22:31 -0700
commitb9b159c49854d8d9d2207946bb583537bb0d48d6 (patch)
tree6f8ca392a1d5141dbee24b506ebf2b836f74d673 /src/i830_lvds.c
parentd26f4c493721dbb2e2cbf4efcf8d37228d1b1f3b (diff)
Remove UMS support.
At this point, the only remaining feature regressions should be the lack of overlay support (about to land), and the need to update the XVMC code to work in the presence of KMS. Acked-by: Keith Packard <keithp@keithp.com> (in principle) Acked-by: Carl Worth <cworth@cworth.org> (in principle)
Diffstat (limited to 'src/i830_lvds.c')
-rw-r--r--src/i830_lvds.c1627
1 files changed, 0 insertions, 1627 deletions
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
deleted file mode 100644
index 806a965d..00000000
--- a/src/i830_lvds.c
+++ /dev/null
@@ -1,1627 +0,0 @@
-/*
- * Copyright © 2006 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Eric Anholt <eric@anholt.net>
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "xf86.h"
-#include "i830.h"
-#include "i830_bios.h"
-#include "i830_display.h"
-#include "X11/Xatom.h"
-
-/*
- * Three panel fitting modes:
- * CENTER - center image on screen, don't scale
- * FULL_ASPECT - scale image to fit screen, but preserve aspect ratio
- * FULL - scale image to fit screen without regard to aspect ratio
- */
-enum pfit_mode {
- CENTER = 0,
- FULL_ASPECT,
- FULL,
-};
-
-struct i830_lvds_priv {
- /* The panel is in DPMS off */
- Bool dpmsoff;
-
- /* restore backlight to this value */
- int backlight_duty_cycle;
-
- void (*set_backlight)(xf86OutputPtr output, int level);
- int (*get_backlight)(xf86OutputPtr output);
- int backlight_max;
- enum pfit_mode fitting_mode;
- uint32_t pfit_control;
- uint32_t pfit_pgm_ratios;
-};
-
-#define BACKLIGHT_CLASS "/sys/class/backlight"
-
-/*
- * List of available kernel interfaces in priority order
- */
-static char *backlight_interfaces[] = {
- "asus-laptop",
- "eeepc",
- "thinkpad_screen",
- "acpi_video1",
- "acpi_video0",
- "fujitsu-laptop",
- "sony",
- "samsung",
- NULL,
-};
-
-/*
- * Must be long enough for BACKLIGHT_CLASS + '/' + longest in above table +
- * '/' + "max_backlight"
- */
-#define BACKLIGHT_PATH_LEN 80
-/* Enough for 8 digits of backlight + '\n' + '\0' */
-#define BACKLIGHT_VALUE_LEN 10
-
-static int backlight_index;
-
-enum lid_status {
- LID_UNKNOWN = -1,
- LID_OPEN,
- LID_CLOSE,
-};
-
-#define ACPI_BUTTON "/proc/acpi/button/"
-#define ACPI_LID "/proc/acpi/button/lid/"
-
-static Bool
-i830_kernel_backlight_available(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- struct stat buf;
- char path[BACKLIGHT_PATH_LEN];
- int i;
-
- for (i = 0; backlight_interfaces[i] != NULL; i++) {
- sprintf(path, "%s/%s", BACKLIGHT_CLASS, backlight_interfaces[i]);
- if (!stat(path, &buf)) {
- backlight_index = i;
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "found backlight control "
- "method %s\n", path);
- return 1;
- }
- }
-
- return 0;
-}
-
-/* Try to figure out which backlight control method to use */
-static void
-i830_set_lvds_backlight_method(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- uint32_t blc_pwm_ctl, blc_pwm_ctl2;
- enum backlight_control method = BCM_NATIVE; /* Default to native */
-
- if (i830_kernel_backlight_available(output)) {
- method = BCM_KERNEL;
- } else if (IS_I965GM(pI830) || IS_GM45(pI830)) {
- blc_pwm_ctl2 = INREG(BLC_PWM_CTL2);
- if (blc_pwm_ctl2 & BLM_LEGACY_MODE2)
- method = BCM_COMBO;
- } else {
- blc_pwm_ctl = INREG(BLC_PWM_CTL);
- if (blc_pwm_ctl & BLM_LEGACY_MODE)
- method = BCM_COMBO;
- }
-
- pI830->backlight_control_method = method;
-}
-
-/*
- * Native methods
- */
-static void
-i830_lvds_set_backlight_native(xf86OutputPtr output, int level)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- uint32_t blc_pwm_ctl;
-
- blc_pwm_ctl = INREG(BLC_PWM_CTL);
- blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
- OUTREG(BLC_PWM_CTL, blc_pwm_ctl | (level << BACKLIGHT_DUTY_CYCLE_SHIFT));
-}
-
-static int
-i830_lvds_get_backlight_native(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- uint32_t blc_pwm_ctl;
-
- blc_pwm_ctl = INREG(BLC_PWM_CTL);
- blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
- return blc_pwm_ctl;
-}
-
-static int
-i830_lvds_get_backlight_max_native(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- uint32_t pwm_ctl = INREG(BLC_PWM_CTL);
- int val;
-
- if (IS_I965GM(pI830) || IS_GM45(pI830)) {
- val = ((pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK2) >>
- BACKLIGHT_MODULATION_FREQ_SHIFT2);
- } else {
- val = ((pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >>
- BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
- }
-
- return val;
-}
-
-/*
- * Legacy methods
- */
-static void
-i830_lvds_set_backlight_legacy(xf86OutputPtr output, int level)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
-
- pci_device_cfg_write_u8(pI830->PciInfo, level,
- LEGACY_BACKLIGHT_BRIGHTNESS);
-}
-
-static int
-i830_lvds_get_backlight_legacy(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- uint8_t lbb;
-
- pci_device_cfg_read_u8(pI830->PciInfo, &lbb, LEGACY_BACKLIGHT_BRIGHTNESS);
-
- return lbb;
-}
-
-/*
- * Combo methods
- */
-static void
-i830_lvds_set_backlight_combo(xf86OutputPtr output, int level)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- uint32_t blc_pwm_ctl;
- uint8_t lbb;
-
- pci_device_cfg_read_u8(pI830->PciInfo, &lbb, LEGACY_BACKLIGHT_BRIGHTNESS);
- /*
- * If LBB is zero and we're shooting for a non-zero brightness level,
- * we have to increase LBB by at least 1.
- */
- if (!lbb && level) {
- pci_device_cfg_write_u8(pI830->PciInfo, 1,
- LEGACY_BACKLIGHT_BRIGHTNESS);
- }
-
- /*
- * Don't set the lowest bit in combo configs since it can act as a flag for
- * max brightness.
- */
- level <<= 1;
-
- blc_pwm_ctl = INREG(BLC_PWM_CTL);
- blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
- OUTREG(BLC_PWM_CTL, blc_pwm_ctl | (level << BACKLIGHT_DUTY_CYCLE_SHIFT));
-}
-
-static int
-i830_lvds_get_backlight_combo(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- uint32_t blc_pwm_ctl;
-
- blc_pwm_ctl = INREG(BLC_PWM_CTL);
- blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
-
- /* Since we don't use the low bit when using combo, the value is halved */
-
- return blc_pwm_ctl >> 1;
-}
-
-static int
-i830_lvds_get_backlight_max_combo(xf86OutputPtr output)
-{
- /* Since we don't set the low bit when using combo, the range is halved */
- return i830_lvds_get_backlight_max_native(output) >> 1;
-}
-
-/*
- * Kernel methods
- */
-static void
-i830_lvds_set_backlight_kernel(xf86OutputPtr output, int level)
-{
- ScrnInfoPtr pScrn = output->scrn;
- char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
- int fd, len, ret;
-
- len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level);
- if (len > BACKLIGHT_VALUE_LEN) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "backlight value too large: %d\n",
- level);
- return;
- }
-
- sprintf(path, "%s/%s/brightness", BACKLIGHT_CLASS,
- backlight_interfaces[backlight_index]);
- fd = open(path, O_RDWR);
- if (fd == -1) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "failed to open %s for backlight "
- "control: %s\n", path, strerror(errno));
- return;
- }
-
- ret = write(fd, val, len);
- if (ret == -1) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "write to %s for backlight "
- "control failed: %s\n", path, strerror(errno));
- }
-
- close(fd);
-}
-
-static int
-i830_lvds_get_backlight_kernel(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
- int fd;
-
- sprintf(path, "%s/%s/actual_brightness", BACKLIGHT_CLASS,
- backlight_interfaces[backlight_index]);
- fd = open(path, O_RDONLY);
- if (fd == -1) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "failed to open %s for backlight "
- "control: %s\n", path, strerror(errno));
- return 0;
- }
-
- memset(val, 0, sizeof(val));
- if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1)
- goto out_err;
-
- close(fd);
- return atoi(val);
-
-out_err:
- close(fd);
- return 0;
-}
-
-static int
-i830_lvds_get_backlight_max_kernel(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
- int fd, max = 0;
-
- sprintf(path, "%s/%s/max_brightness", BACKLIGHT_CLASS,
- backlight_interfaces[backlight_index]);
- fd = open(path, O_RDONLY);
- if (fd == -1) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "failed to open %s for backlight "
- "control: %s\n", path, strerror(errno));
- return 0;
- }
-
- if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1)
- goto out_err;
-
- close(fd);
-
- max = atoi(val);
-
- return max;
-
-out_err:
- close(fd);
- return 0;
-}
-
-/**
- * Get lid state from ACPI button driver
- */
-static int
-i830_lvds_acpi_lid_open(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- int fd;
- DIR *button_dir;
- DIR *lid_dir;
- struct dirent *lid_dent;
- char *state_name;
- char state[64];
- enum lid_status ret = LID_UNKNOWN;
-
- if (pI830->quirk_flag & QUIRK_BROKEN_ACPI_LID)
- goto out;
-
- button_dir = opendir(ACPI_BUTTON);
- /* If acpi button driver is not loaded, bypass ACPI check method */
- if (button_dir == NULL)
- goto out;
- closedir(button_dir);
-
- lid_dir = opendir(ACPI_LID);
-
- /* no acpi lid object found */
- if (lid_dir == NULL)
- goto out;
-
- while (1) {
- lid_dent = readdir(lid_dir);
- if (lid_dent == NULL) {
- /* no LID object */
- closedir(lid_dir);
- goto out;
- }
- if (strcmp(lid_dent->d_name, ".") &&
- strcmp(lid_dent->d_name, "..")) {
- break;
- }
- }
- state_name = malloc(strlen(ACPI_LID) + strlen(lid_dent->d_name) + 7);
- memset(state_name, 0, sizeof(state_name));
- strcat(state_name, ACPI_LID);
- strcat(state_name, lid_dent->d_name);
- strcat(state_name, "/state");
-
- closedir(lid_dir);
-
- if ((fd = open(state_name, O_RDONLY)) == -1) {
- free(state_name);
- goto out;
- }
- free(state_name);
- if (read(fd, state, 64) == -1) {
- close(fd);
- goto out;
- }
- close(fd);
- if (strstr(state, "open"))
- ret = LID_OPEN;
- else if (strstr(state, "closed"))
- ret = LID_CLOSE;
- else /* "unsupported" */
- ret = LID_UNKNOWN;
-
-out:
- if (pI830->debug_modes && (ret != LID_UNKNOWN))
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "LID switch detect %s with ACPI button\n",
- ret ? "closed" : "open");
-
- return ret;
-}
-
-/**
- * Get LID switch close state from SWF
- */
-static Bool
-i830_lvds_swf_lid_close(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- uint32_t swf14 = INREG(SWF14);
- Bool ret;
-
- if (swf14 & SWF14_LID_SWITCH_EN)
- ret = TRUE;
- else
- ret = FALSE;
-
- if (pI830->debug_modes)
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "LID switch detect %s with SWF14 0x%8x\n",
- ret ? "closed" : "open", swf14);
-
- return ret;
-}
-
-/**
- * Sets the power state for the panel.
- */
-static void
-i830SetLVDSPanelPower(xf86OutputPtr output, Bool on)
-{
- I830OutputPrivatePtr intel_output = output->driver_private;
- struct i830_lvds_priv *dev_priv = intel_output->dev_priv;
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- uint32_t pp_status;
-
- if (on) {
- /* if we're going from on->on, be aware to current level. */
- if ((INREG(PP_CONTROL) & POWER_TARGET_ON) && !dev_priv->dpmsoff)
- dev_priv->backlight_duty_cycle = dev_priv->get_backlight(output);
-
- /*
- * If we're going from off->on we may need to turn on the backlight.
- * We should use the saved value whenever possible, but on some
- * machines 0 is a valid backlight value (due to an external backlight
- * controller for example), so on them, when turning LVDS back on,
- * they'll always re-maximize the brightness.
- */
- if (!(INREG(PP_CONTROL) & POWER_TARGET_ON) &&
- dev_priv->backlight_duty_cycle == 0 &&
- pI830->backlight_control_method < BCM_KERNEL)
- dev_priv->backlight_duty_cycle = dev_priv->backlight_max;
-
- OUTREG(PP_CONTROL, INREG(PP_CONTROL) | POWER_TARGET_ON);
- do {
- pp_status = INREG(PP_STATUS);
- } while ((pp_status & PP_ON) == 0);
-
- dev_priv->set_backlight(output, dev_priv->backlight_duty_cycle);
- dev_priv->dpmsoff = FALSE;
- } else {
- /*
- * Only save the current backlight value if we're going from
- * on to off.
- */
- if ((INREG(PP_CONTROL) & POWER_TARGET_ON) && !dev_priv->dpmsoff)
- dev_priv->backlight_duty_cycle = dev_priv->get_backlight(output);
- dev_priv->set_backlight(output, 0);
-
- OUTREG(PP_CONTROL, INREG(PP_CONTROL) & ~POWER_TARGET_ON);
- do {
- pp_status = INREG(PP_STATUS);
- } while (pp_status & PP_ON);
-
- dev_priv->dpmsoff = TRUE;
- }
-}
-
-static void
-i830_lvds_dpms (xf86OutputPtr output, int mode)
-{
- if (mode == DPMSModeOn)
- i830SetLVDSPanelPower(output, TRUE);
- else
- i830SetLVDSPanelPower(output, FALSE);
-
- /* XXX: We never power down the LVDS pairs. */
-}
-
-static void
-i830_lvds_save (xf86OutputPtr output)
-{
- I830OutputPrivatePtr intel_output = output->driver_private;
- struct i830_lvds_priv *dev_priv = intel_output->dev_priv;
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
-
- if (IS_I965GM(pI830) || IS_GM45(pI830))
- pI830->saveBLC_PWM_CTL2 = INREG(BLC_PWM_CTL2);
- pI830->savePP_ON = INREG(PP_ON_DELAYS);
- pI830->savePP_OFF = INREG(PP_OFF_DELAYS);
- pI830->savePP_CONTROL = INREG(PP_CONTROL);
- pI830->savePP_DIVISOR = INREG(PP_DIVISOR);
- pI830->saveBLC_PWM_CTL = INREG(BLC_PWM_CTL);
- if ((INREG(PP_CONTROL) & POWER_TARGET_ON) && !dev_priv->dpmsoff)
- dev_priv->backlight_duty_cycle = dev_priv->get_backlight(output);
-}
-
-static void
-i830_lvds_restore(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
-
- if (IS_I965GM(pI830) || IS_GM45(pI830))
- OUTREG(BLC_PWM_CTL2, pI830->saveBLC_PWM_CTL2);
- OUTREG(BLC_PWM_CTL, pI830->saveBLC_PWM_CTL);
- OUTREG(PP_ON_DELAYS, pI830->savePP_ON);
- OUTREG(PP_OFF_DELAYS, pI830->savePP_OFF);
- OUTREG(PP_DIVISOR, pI830->savePP_DIVISOR);
- OUTREG(PP_CONTROL, pI830->savePP_CONTROL);
- if (pI830->savePP_CONTROL & POWER_TARGET_ON)
- i830SetLVDSPanelPower(output, TRUE);
- else
- i830SetLVDSPanelPower(output, FALSE);
-}
-
-static int
-i830_lvds_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- DisplayModePtr pFixedMode = pI830->lvds_fixed_mode;
-
- if (pFixedMode)
- {
- if (pMode->HDisplay > pFixedMode->HDisplay)
- return MODE_PANEL;
- if (pMode->VDisplay > pFixedMode->VDisplay)
- return MODE_PANEL;
- }
-
- return MODE_OK;
-}
-
-static Bool
-i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
- DisplayModePtr adjusted_mode)
-{
- I830OutputPrivatePtr intel_output = output->driver_private;
- struct i830_lvds_priv *dev_priv = intel_output->dev_priv;
- ScrnInfoPtr pScrn = output->scrn;
- xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
- I830CrtcPrivatePtr intel_crtc = output->crtc->driver_private;
- I830Ptr pI830 = I830PTR(pScrn);
- uint32_t pfit_control = 0, pfit_pgm_ratios = 0;
- float panel_ratio, desired_ratio, vert_scale, horiz_scale;
- float horiz_ratio, vert_ratio;
- int left_border = 0, right_border = 0, top_border = 0, bottom_border = 0;
- int i;
- uint32_t hsync_width, vsync_width;
- uint32_t hblank_width, vblank_width;
- uint32_t hsync_pos, vsync_pos;
- Bool border = 0;
-
- for (i = 0; i < xf86_config->num_output; i++) {
- xf86OutputPtr other_output = xf86_config->output[i];
-
- if (other_output != output && other_output->crtc == output->crtc) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Can't enable LVDS and another output on the same "
- "pipe\n");
- return FALSE;
- }
- }
-
- if (intel_crtc->pipe == 0) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Can't support LVDS on pipe A\n");
- return FALSE;
- }
-
- /* If we don't have a panel mode there's not much we can do */
- if (pI830->lvds_fixed_mode == NULL)
- return TRUE;
-
- /* If we have timings from the BIOS for the panel, put them in
- * to the adjusted mode. The CRTC will be set up for this mode,
- * with the panel scaling set up to source from the H/VDisplay
- * of the original mode.
- */
- adjusted_mode->HDisplay = pI830->lvds_fixed_mode->HDisplay;
- adjusted_mode->HSyncStart = pI830->lvds_fixed_mode->HSyncStart;
- adjusted_mode->HSyncEnd = pI830->lvds_fixed_mode->HSyncEnd;
- adjusted_mode->HTotal = pI830->lvds_fixed_mode->HTotal;
- adjusted_mode->VDisplay = pI830->lvds_fixed_mode->VDisplay;
- adjusted_mode->VSyncStart = pI830->lvds_fixed_mode->VSyncStart;
- adjusted_mode->VSyncEnd = pI830->lvds_fixed_mode->VSyncEnd;
- adjusted_mode->VTotal = pI830->lvds_fixed_mode->VTotal;
- adjusted_mode->Clock = pI830->lvds_fixed_mode->Clock;
- xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V);
-
- /* Make sure pre-965s set dither correctly */
- if (!IS_I965G(pI830) && pI830->lvds_dither)
- pfit_control |= PANEL_8TO6_DITHER_ENABLE;
-
- /* Native modes don't need fitting */
- if (adjusted_mode->HDisplay == mode->HDisplay &&
- adjusted_mode->VDisplay == mode->VDisplay) {
- pfit_pgm_ratios = 0;
- border = 0;
- goto out;
- }
-
- /* 965+ wants fuzzy fitting */
- if (IS_I965G(pI830))
- pfit_control |= (intel_crtc->pipe << PFIT_PIPE_SHIFT) |
- PFIT_FILTER_FUZZY;
-
- hsync_width = adjusted_mode->CrtcHSyncEnd - adjusted_mode->CrtcHSyncStart;
- vsync_width = adjusted_mode->CrtcVSyncEnd - adjusted_mode->CrtcVSyncStart;
- hblank_width = adjusted_mode->CrtcHBlankEnd -
- adjusted_mode->CrtcHBlankStart;
- vblank_width = adjusted_mode->CrtcVBlankEnd -
- adjusted_mode->CrtcVBlankStart;
- /*
- * Deal with panel fitting options. Figure out how to stretch the image
- * based on its aspect ratio & the current panel fitting mode.
- */
- panel_ratio = (float)adjusted_mode->HDisplay /
- (float)adjusted_mode->VDisplay;
- desired_ratio = (float)mode->HDisplay /
- (float)mode->VDisplay;
-
- /*
- * Enable automatic panel scaling for non-native modes so that they fill
- * the screen. Should be enabled before the pipe is enabled, according to
- * register description and PRM.
- */
- /* Change the value here to see the borders for debugging */
- OUTREG(BCLRPAT_A, 0);
- OUTREG(BCLRPAT_B, 0);
- switch (dev_priv->fitting_mode) {
- case CENTER:
- /*
- * For centered modes, we have to calculate border widths & heights and
- * modify the values programmed into the CRTC. Also need to make sure
- * LVDS borders are enabled (see i830_display.c).
- */
- left_border =
- (pI830->lvds_fixed_mode->HDisplay - mode->HDisplay) / 2;
- right_border = left_border;
- if (mode->HDisplay & 1)
- right_border++;
- top_border =
- (pI830->lvds_fixed_mode->VDisplay - mode->VDisplay) / 2;
- bottom_border = top_border;
- if (mode->VDisplay & 1)
- bottom_border++;
-
- /* Set active & border values */
- adjusted_mode->CrtcHDisplay = mode->HDisplay;
- /* keep the horizontal border be even */
- if (right_border & 1)
- right_border++;
- /* use the border directly instead of border minus one */
- adjusted_mode->CrtcHBlankStart = mode->HDisplay + right_border;
- /* keep the blank width constant */
- adjusted_mode->CrtcHBlankEnd = adjusted_mode->CrtcHBlankStart +
- hblank_width;
- /* get the hsync start position relative to hblank start */
- hsync_pos = (hblank_width - hsync_width) / 2;
- /* keep the hsync width constant and hsync start be even */
- if (hsync_pos & 1)
- hsync_pos++;
- adjusted_mode->CrtcHSyncStart = adjusted_mode->CrtcHBlankStart +
- hsync_pos;
- adjusted_mode->CrtcHSyncEnd = adjusted_mode->CrtcHSyncStart +
- hsync_width;
- adjusted_mode->CrtcVDisplay = mode->VDisplay;
- /* use the border instead of border minus one */
- adjusted_mode->CrtcVBlankStart = mode->VDisplay + bottom_border;
- adjusted_mode->CrtcVBlankEnd = adjusted_mode->CrtcVBlankStart +
- vblank_width;
- /* get the vsync start position relative to vblank start */
- vsync_pos = (vblank_width - vsync_width) / 2;
- adjusted_mode->CrtcVSyncStart = adjusted_mode->CrtcVBlankStart +
- vsync_pos;
- adjusted_mode->CrtcVSyncEnd = adjusted_mode->CrtcVSyncStart +
- vsync_width;
- border = 1;
- break;
- case FULL_ASPECT:
- /* Scale but preserve aspect ratio */
- pfit_control |= PFIT_ENABLE;
- if (IS_I965G(pI830)) {
- /*
- * 965+ is easy, it does everything in hw
- */
- if (panel_ratio > desired_ratio)
- pfit_control |= PFIT_SCALING_PILLAR;
- else if (panel_ratio < desired_ratio)
- pfit_control |= PFIT_SCALING_LETTER;
- else
- pfit_control |= PFIT_SCALING_AUTO;
- } else {
- /*
- * For earlier chips we have to calculate the scaling ratio
- * by hand and program it into the PFIT_PGM_RATIOS reg.
- */
- uint32_t horiz_bits, vert_bits, bits = 12;
-
- horiz_ratio = ((float)mode->HDisplay) /
- ((float)adjusted_mode->HDisplay);
- vert_ratio = ((float)mode->VDisplay) /
- ((float)adjusted_mode->VDisplay);
-
- horiz_scale = ((float)adjusted_mode->HDisplay) /
- ((float)mode->HDisplay);
- vert_scale = ((float)adjusted_mode->VDisplay) /
- ((float)mode->VDisplay);
-
- /* Retain aspect ratio */
- if (panel_ratio > desired_ratio) { /* Pillar */
- unsigned long scaled_width = (float)mode->HDisplay * vert_scale;
-
- horiz_ratio = vert_ratio;
- pfit_control |= VERT_AUTO_SCALE | VERT_INTERP_BILINEAR |
- HORIZ_INTERP_BILINEAR;
-
- /* Pillar will have left/right borders */
- left_border = (pI830->lvds_fixed_mode->HDisplay -
- scaled_width) / 2;
- right_border = left_border;
- if (mode->HDisplay & 1) /* odd resolutions */
- right_border++;
-
- /* keep the border be even */
- if (right_border & 1)
- right_border++;
- adjusted_mode->CrtcHDisplay = scaled_width;
- adjusted_mode->CrtcHBlankStart = scaled_width + right_border;
- adjusted_mode->CrtcHBlankEnd = adjusted_mode->CrtcHBlankStart +
- hblank_width;
- /* get the hsync start position relative to hblank start */
- hsync_pos = (hblank_width - hsync_width) / 2;
- /* keep the hsync start be even */
- if (hsync_pos & 1)
- hsync_pos++;
- adjusted_mode->CrtcHSyncStart = adjusted_mode->CrtcHBlankStart +
- hsync_pos;
- adjusted_mode->CrtcHSyncEnd = adjusted_mode->CrtcHSyncStart +
- hsync_width;
- border = 1;
- } else if (panel_ratio < desired_ratio) { /* Letter */
- unsigned long scaled_height = (float)mode->VDisplay *
- horiz_scale;
-
- vert_ratio = horiz_ratio;
- pfit_control |= HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR |
- HORIZ_INTERP_BILINEAR;
-
- /* Letterbox will have top/bottom borders */
- top_border = (pI830->lvds_fixed_mode->VDisplay -
- scaled_height) / 2;
- bottom_border = top_border;
- if (mode->VDisplay & 1)
- bottom_border++;
-
- adjusted_mode->CrtcVDisplay = scaled_height;
- /* use the border instead of border minus one */
- adjusted_mode->CrtcVBlankStart = scaled_height +
- bottom_border;
- /* keep the Vblank width constant */
- adjusted_mode->CrtcVBlankEnd = adjusted_mode->CrtcVBlankStart +
- vblank_width;
- /* get the vsync start position relative to vblank start */
- vsync_pos = (vblank_width - vsync_width) / 2;
- adjusted_mode->CrtcVSyncStart = adjusted_mode->CrtcVBlankStart +
- vsync_pos;
- adjusted_mode->CrtcVSyncEnd = adjusted_mode->CrtcVBlankStart +
- vsync_width;
- border = 1;
- } else { /* Aspects match, let hw scale both directions */
- pfit_control |= VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
- VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR;
- }
-
- horiz_bits = 0.5 + (1 << bits) * horiz_ratio;
- vert_bits = 0.5 + (1 << bits) * vert_ratio;
-
- pfit_pgm_ratios = (((vert_bits << PFIT_VERT_SCALE_SHIFT) &
- PFIT_VERT_SCALE_MASK) |
- ((horiz_bits << PFIT_HORIZ_SCALE_SHIFT) &
- PFIT_HORIZ_SCALE_MASK));
- }
- break;
- case FULL:
- /*
- * Full scaling, even if it changes the aspect ratio. Fortunately
- * this is all done for us in hw.
- */
- pfit_control |= PFIT_ENABLE;
- if (IS_I965G(pI830))
- pfit_control |= PFIT_SCALING_AUTO;
- else
- pfit_control |= VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
- VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR;
- break;
- default:
- /* shouldn't happen */
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "error: bad fitting mode\n");
- break;
- }
-
-out:
- dev_priv->pfit_control = pfit_control;
- dev_priv->pfit_pgm_ratios = pfit_pgm_ratios;
-
- if (border)
- intel_output->lvds_bits |= LVDS_BORDER_ENABLE;
- else
- intel_output->lvds_bits &= ~LVDS_BORDER_ENABLE;
- /* XXX: It would be nice to support lower refresh rates on the
- * panels to reduce power consumption, and perhaps match the
- * user's requested refresh rate.
- */
-
- return TRUE;
-}
-
-static void
-i830_lvds_prepare(xf86OutputPtr output)
-{
- i830_lvds_dpms(output, DPMSModeOff);
-}
-
-static void
-i830_lvds_mode_set(xf86OutputPtr output, DisplayModePtr mode,
- DisplayModePtr adjusted_mode)
-{
- I830OutputPrivatePtr intel_output = output->driver_private;
- struct i830_lvds_priv *dev_priv = intel_output->dev_priv;
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
-
- /*
- * PFIT must be enabled/disabled while LVDS is on but pipes are still off
- */
- OUTREG(PFIT_PGM_RATIOS, dev_priv->pfit_pgm_ratios);
- OUTREG(PFIT_CONTROL, dev_priv->pfit_control);
-}
-
-/**
- * Detect the LVDS connection.
- */
-static xf86OutputStatus
-i830_lvds_detect(xf86OutputPtr output)
-{
- /* Fallback to origin, mark LVDS always connected.
- * From wider tests, we have seen both broken cases with
- * ACPI lid and SWF bit. So disable them for now until we
- * get a reliable way for LVDS detect.
- */
- return XF86OutputStatusConnected;
-
- enum lid_status lid;
-
- lid = i830_lvds_acpi_lid_open(output);
- if (lid == LID_OPEN)
- return XF86OutputStatusConnected;
- else if (lid == LID_CLOSE)
- return XF86OutputStatusDisconnected;
-
- if (i830_lvds_swf_lid_close(output))
- return XF86OutputStatusDisconnected;
-
- return XF86OutputStatusConnected;
-}
-
-static void fill_detailed_block(struct detailed_monitor_section *det_mon,
- DisplayModePtr mode)
-{
- struct detailed_timings *timing = &det_mon->section.d_timings;
- det_mon->type = DT;
- timing->clock = mode->Clock * 1000;
- timing->h_active = mode->HDisplay;
- timing->h_blanking = mode->HTotal - mode->HDisplay;
- timing->v_active = mode->VDisplay;
- timing->v_blanking = mode->VTotal - mode->VDisplay;
- timing->h_sync_off = mode->HSyncStart - mode->HDisplay;
- timing->h_sync_width = mode->HSyncEnd - mode->HSyncStart;
- timing->v_sync_off = mode->VSyncStart - mode->VDisplay;
- timing->v_sync_width = mode->VSyncEnd - mode->VSyncStart;
-
- if (mode->Flags & V_PVSYNC)
- timing->misc |= 0x02;
-
- if (mode->Flags & V_PHSYNC)
- timing->misc |= 0x01;
-}
-
-/* X Server pre-1.5 compatibility */
-#ifndef DS_VENDOR
-#define DS_VENDOR 0x101
-#endif
-
-/**
- * Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
- */
-static DisplayModePtr
-i830_lvds_get_modes(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- I830OutputPrivatePtr intel_output = output->driver_private;
- xf86MonPtr edid_mon;
- DisplayModePtr modes;
-
- edid_mon = xf86OutputGetEDID (output, intel_output->pDDCBus);
-
- /* Our LVDS scaler can hit any size, so mark the EDID data as
- * supporting continuous timings
- */
- if (edid_mon) {
- int i, j = -1;
- edid_mon->features.msc |= 0x1;
-
- /* Either find a DS_RANGES block, or replace a DS_VENDOR block,
- * smashing it into a DS_RANGES block with wide open refresh to
- * match all default modes
- */
- for (i = 0; i < sizeof (edid_mon->det_mon) / sizeof (edid_mon->det_mon[0]); i++)
- {
- if (edid_mon->det_mon[i].type >= DS_VENDOR && j == -1)
- j = i;
- if (edid_mon->det_mon[i].type == DS_RANGES) {
- j = i;
- break;
- }
- }
- if (j != -1) {
- struct monitor_ranges *ranges = &edid_mon->det_mon[j].section.ranges;
- edid_mon->det_mon[j].type = DS_RANGES;
- ranges->min_v = 0;
- ranges->max_v = 200;
- ranges->min_h = 0;
- ranges->max_h = 200;
- }
- }
- xf86OutputSetEDID (output, edid_mon);
-
- modes = xf86OutputGetEDIDModes (output);
- if (modes != NULL)
- return modes;
-
- if (!output->MonInfo)
- {
- edid_mon = xcalloc (1, sizeof (xf86Monitor));
- if (edid_mon)
- {
- struct detailed_monitor_section *det_mon = edid_mon->det_mon;
- /*support DPM, instead of DPMS*/
- edid_mon->features.dpms |= 0x1;
- /*defaultly support RGB color display*/
- edid_mon->features.display_type |= 0x1;
- /*defaultly display support continuous-freqencey*/
- edid_mon->features.msc |= 0x1;
- /*defaultly the EDID version is 1.4 */
- edid_mon->ver.version = 1;
- edid_mon->ver.revision = 4;
-
- if (pI830->lvds_fixed_mode != NULL) {
- /* now we construct new EDID monitor,
- * so filled one detailed timing block
- */
- fill_detailed_block(det_mon, pI830->lvds_fixed_mode);
- /* the filed timing block should be set preferred*/
- edid_mon->features.msc |= 0x2;
- det_mon = det_mon + 1;
- }
-
- /* Set wide sync ranges so we get all modes
- * handed to valid_mode for checking
- */
- det_mon->type = DS_RANGES;
- det_mon->section.ranges.min_v = 0;
- det_mon->section.ranges.max_v = 200;
- det_mon->section.ranges.min_h = 0;
- det_mon->section.ranges.max_h = 200;
- output->MonInfo = edid_mon;
- }
- }
-
- if (pI830->lvds_fixed_mode != NULL)
- return xf86DuplicateMode(pI830->lvds_fixed_mode);
-
- return NULL;
-}
-
-static void
-i830_lvds_destroy (xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- I830OutputPrivatePtr intel_output = output->driver_private;
-
- xf86DeleteMode (&pI830->lvds_fixed_mode, pI830->lvds_fixed_mode);
- if (intel_output)
- xfree (intel_output);
-}
-
-#ifdef RANDR_12_INTERFACE
-#define BACKLIGHT_NAME "BACKLIGHT"
-static Atom backlight_atom;
-
-/*
- * Backlight control lets the user select how the driver should manage
- * backlight changes: using the legacy interface, the native interface,
- * or not at all.
- */
-#define BACKLIGHT_CONTROL_NAME "BACKLIGHT_CONTROL"
-#define NUM_BACKLIGHT_CONTROL_METHODS 4
-static char *backlight_control_names[] = {
- "native",
- "legacy",
- "combination",
- "kernel",
-};
-static Atom backlight_control_atom;
-static Atom backlight_control_name_atoms[NUM_BACKLIGHT_CONTROL_METHODS];
-
-#define PANEL_FITTING_NAME "PANEL_FITTING"
-#define NUM_PANEL_FITTING_TYPES 3
-static char *panel_fitting_names[] = {
- "center",
- "full_aspect",
- "full",
-};
-static Atom panel_fitting_atom;
-static Atom panel_fitting_name_atoms[NUM_PANEL_FITTING_TYPES];
-
-
-static int
-i830_backlight_control_lookup(const char *name)
-{
- int i;
-
- for (i = 0; i < NUM_BACKLIGHT_CONTROL_METHODS; i++)
- if (!strcmp(name, backlight_control_names[i]))
- return i;
-
- return -1;
-}
-
-static Bool
-i830_lvds_set_backlight_control(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- I830OutputPrivatePtr intel_output = output->driver_private;
- struct i830_lvds_priv *dev_priv = intel_output->dev_priv;
-
- switch (pI830->backlight_control_method) {
- case BCM_NATIVE:
- dev_priv->set_backlight = i830_lvds_set_backlight_native;
- dev_priv->get_backlight = i830_lvds_get_backlight_native;
- dev_priv->backlight_max =
- i830_lvds_get_backlight_max_native(output);
- break;
- case BCM_LEGACY:
- dev_priv->set_backlight = i830_lvds_set_backlight_legacy;
- dev_priv->get_backlight = i830_lvds_get_backlight_legacy;
- dev_priv->backlight_max = 0xff;
- break;
- case BCM_COMBO:
- dev_priv->set_backlight = i830_lvds_set_backlight_combo;
- dev_priv->get_backlight = i830_lvds_get_backlight_combo;
- dev_priv->backlight_max =
- i830_lvds_get_backlight_max_combo(output);
- break;
- case BCM_KERNEL:
- dev_priv->set_backlight = i830_lvds_set_backlight_kernel;
- dev_priv->get_backlight = i830_lvds_get_backlight_kernel;
- dev_priv->backlight_max =
- i830_lvds_get_backlight_max_kernel(output);
- break;
- default:
- /*
- * Should be impossible to get here unless the caller set a bogus
- * backlight_control_method
- */
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "error: bad backlight control "
- "method\n");
- break;
- }
-
- return Success;
-}
-
-static int
-i830_panel_fitting_lookup(const char *name)
-{
- int i;
-
- for (i = 0; i < NUM_PANEL_FITTING_TYPES; i++)
- if (!strcmp(name, panel_fitting_names[i]))
- return i;
-
- return -1;
-}
-#endif /* RANDR_12_INTERFACE */
-
-static void
-i830_lvds_create_resources(xf86OutputPtr output)
-{
-#ifdef RANDR_12_INTERFACE
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- I830OutputPrivatePtr intel_output = output->driver_private;
- struct i830_lvds_priv *dev_priv = intel_output->dev_priv;
- INT32 backlight_range[2];
- int data, err, i;
-
- /* Set up the backlight property, which takes effect immediately
- * and accepts values only within the backlight_range.
- *
- * XXX: Currently, RandR doesn't verify that properties set are
- * within the backlight_range.
- */
- backlight_atom = MakeAtom(BACKLIGHT_NAME, sizeof(BACKLIGHT_NAME) - 1,
- TRUE);
-
- backlight_range[0] = 0;
- backlight_range[1] = dev_priv->backlight_max;
- err = RRConfigureOutputProperty(output->randr_output, backlight_atom,
- FALSE, TRUE, FALSE, 2, backlight_range);
- if (err != 0) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "RRConfigureOutputProperty error, %d\n", err);
- }
- /* Set the current value of the backlight property */
- data = dev_priv->backlight_duty_cycle;
- err = RRChangeOutputProperty(output->randr_output, backlight_atom,
- XA_INTEGER, 32, PropModeReplace, 1, &data,
- FALSE, TRUE);
- if (err != 0) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "RRChangeOutputProperty error, %d\n", err);
- }
-
- /*
- * Now setup the control selection property
- */
- backlight_control_atom = MakeAtom(BACKLIGHT_CONTROL_NAME,
- sizeof(BACKLIGHT_CONTROL_NAME) - 1, TRUE);
- for (i = 0; i < NUM_BACKLIGHT_CONTROL_METHODS; i++) {
- backlight_control_name_atoms[i] =
- MakeAtom(backlight_control_names[i],
- strlen(backlight_control_names[i]), TRUE);
- }
- err = RRConfigureOutputProperty(output->randr_output,
- backlight_control_atom, TRUE, FALSE, FALSE,
- NUM_BACKLIGHT_CONTROL_METHODS,
- (INT32 *)backlight_control_name_atoms);
- if (err != 0) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "RRConfigureOutputProperty error, %d\n", err);
- }
- err = RRChangeOutputProperty(output->randr_output, backlight_control_atom,
- XA_ATOM, 32, PropModeReplace, 1,
- &backlight_control_name_atoms[pI830->backlight_control_method],
- FALSE, TRUE);
- if (err != 0) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "failed to set backlight control, %d\n", err);
- }
-
- /*
- * Panel fitting control
- */
-
- /* Disable panel fitting setting on untested pre-915 chips */
- if (!IS_I9XX(pI830) && !(pI830->quirk_flag & QUIRK_PFIT_SAFE))
- return;
-
- panel_fitting_atom = MakeAtom(PANEL_FITTING_NAME,
- sizeof(PANEL_FITTING_NAME) - 1, TRUE);
- for (i = 0; i < NUM_PANEL_FITTING_TYPES; i++) {
- panel_fitting_name_atoms[i] = MakeAtom(panel_fitting_names[i],
- strlen(panel_fitting_names[i]),
- TRUE);
- }
- err = RRConfigureOutputProperty(output->randr_output,
- panel_fitting_atom, TRUE, FALSE, FALSE,
- NUM_PANEL_FITTING_TYPES,
- (INT32 *)panel_fitting_name_atoms);
- if (err != 0) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "RRConfigureOutputProperty error, %d\n", err);
- }
- err = RRChangeOutputProperty(output->randr_output, panel_fitting_atom,
- XA_ATOM, 32, PropModeReplace, 1,
- &panel_fitting_name_atoms[dev_priv->fitting_mode],
- FALSE, TRUE);
- if (err != 0) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "failed to set panel fitting mode, %d\n", err);
- }
-#endif /* RANDR_12_INTERFACE */
-}
-
-#ifdef RANDR_12_INTERFACE
-static Bool
-i830_lvds_set_property(xf86OutputPtr output, Atom property,
- RRPropertyValuePtr value)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- I830OutputPrivatePtr intel_output = output->driver_private;
- struct i830_lvds_priv *dev_priv = intel_output->dev_priv;
-
- if (property == backlight_atom) {
- INT32 val;
-
- if (value->type != XA_INTEGER || value->format != 32 ||
- value->size != 1)
- {
- return FALSE;
- }
-
- val = *(INT32 *)value->data;
- if (val < 0 || val > dev_priv->backlight_max)
- return FALSE;
-
- if (val != dev_priv->backlight_duty_cycle) {
- dev_priv->set_backlight(output, val);
- dev_priv->backlight_duty_cycle = val;
- }
- return TRUE;
- } else if (property == backlight_control_atom) {
- INT32 backlight_range[2];
- Atom atom;
- const char *name;
- int ret, data;
-
- if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
- return FALSE;
-
- memcpy(&atom, value->data, 4);
- name = NameForAtom(atom);
-
- ret = i830_backlight_control_lookup(name);
- if (ret < 0)
- return FALSE;
-
- pI830->backlight_control_method = ret;
- i830_lvds_set_backlight_control(output);
-
- /*
- * Update the backlight atom since the range and value may have changed
- */
- backlight_range[0] = 0;
- backlight_range[1] = dev_priv->backlight_max;
- ret = RRConfigureOutputProperty(output->randr_output, backlight_atom,
- FALSE, TRUE, FALSE, 2, backlight_range);
- if (ret != 0) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "RRConfigureOutputProperty error, %d\n", ret);
- }
- /* Set the current value of the backlight property */
- if ((INREG(PP_CONTROL) & POWER_TARGET_ON) && !dev_priv->dpmsoff)
- data = dev_priv->get_backlight(output);
- else
- data = dev_priv->backlight_duty_cycle;
- ret = RRChangeOutputProperty(output->randr_output, backlight_atom,
- XA_INTEGER, 32, PropModeReplace, 1, &data,
- FALSE, TRUE);
- if (ret != 0) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "RRChangeOutputProperty error, %d\n", ret);
- }
- return TRUE;
- } else if (property == panel_fitting_atom) {
- Atom atom;
- const char *name;
- int ret;
-
- if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
- return FALSE;
-
- memcpy(&atom, value->data, 4);
- name = NameForAtom(atom);
-
- ret = i830_panel_fitting_lookup(name);
- if (ret < 0)
- return FALSE;
-
- if (dev_priv->fitting_mode == ret)
- return TRUE;
-
- dev_priv->fitting_mode = ret;
-
- if (output->crtc) {
- xf86CrtcPtr crtc = output->crtc;
- if (crtc->enabled) {
- if (!xf86CrtcSetMode(crtc, &crtc->desiredMode,
- crtc->desiredRotation,
- crtc->desiredX, crtc->desiredY)) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Failed to set mode after panel fitting change!\n");
- return FALSE;
- }
- }
- }
- return TRUE;
- }
-
- return TRUE;
-}
-#endif /* RANDR_12_INTERFACE */
-
-#ifdef RANDR_13_INTERFACE
-static Bool
-i830_lvds_get_property(xf86OutputPtr output, Atom property)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- I830OutputPrivatePtr intel_output = output->driver_private;
- struct i830_lvds_priv *dev_priv = intel_output->dev_priv;
- int ret;
-
- /*
- * Only need to update properties that might change out from under
- * us. The others will be cached by the randr core code.
- */
- if (property == backlight_atom) {
- int val;
- if ((INREG(PP_CONTROL) & POWER_TARGET_ON) && !dev_priv->dpmsoff) {
- val = dev_priv->get_backlight(output);
- dev_priv->backlight_duty_cycle = val;
- } else
- val = dev_priv->backlight_duty_cycle;
- ret = RRChangeOutputProperty(output->randr_output, backlight_atom,
- XA_INTEGER, 32, PropModeReplace, 1, &val,
- FALSE, TRUE);
- if (ret != Success)
- return FALSE;
- }
-
- return TRUE;
-}
-#endif /* RANDR_13_INTERFACE */
-
-#ifdef RANDR_GET_CRTC_INTERFACE
-static xf86CrtcPtr
-i830_lvds_get_crtc(xf86OutputPtr output)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- int pipe = !!(INREG(LVDS) & LVDS_PIPEB_SELECT);
-
- return i830_pipe_to_crtc(pScrn, pipe);
-}
-#endif
-
-static const xf86OutputFuncsRec i830_lvds_output_funcs = {
- .create_resources = i830_lvds_create_resources,
- .dpms = i830_lvds_dpms,
- .save = i830_lvds_save,
- .restore = i830_lvds_restore,
- .mode_valid = i830_lvds_mode_valid,
- .mode_fixup = i830_lvds_mode_fixup,
- .prepare = i830_lvds_prepare,
- .mode_set = i830_lvds_mode_set,
- .commit = i830_output_commit,
- .detect = i830_lvds_detect,
- .get_modes = i830_lvds_get_modes,
-#ifdef RANDR_12_INTERFACE
- .set_property = i830_lvds_set_property,
-#endif
-#ifdef RANDR_13_INTERFACE
- .get_property = i830_lvds_get_property,
-#endif
- .destroy = i830_lvds_destroy,
-#ifdef RANDR_GET_CRTC_INTERFACE
- .get_crtc = i830_lvds_get_crtc,
-#endif
-};
-
-void
-i830_lvds_init(ScrnInfoPtr pScrn)
-{
- I830Ptr pI830 = I830PTR(pScrn);
- xf86OutputPtr output;
- I830OutputPrivatePtr intel_output;
- DisplayModePtr modes, scan;
- DisplayModePtr lvds_ddc_mode = NULL;
- struct i830_lvds_priv *dev_priv;
-
- if (!pI830->integrated_lvds) {
- if (pI830->debug_modes)
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Skipping LVDS from driver feature BDB's LVDS config info.\n");
- return;
- }
-
- if (pI830->quirk_flag & QUIRK_IGNORE_LVDS)
- return;
-
- output = xf86OutputCreate (pScrn, &i830_lvds_output_funcs, "LVDS");
- if (!output)
- return;
- intel_output = xnfcalloc (sizeof (I830OutputPrivateRec) +
- sizeof (struct i830_lvds_priv), 1);
- if (!intel_output)
- {
- xf86OutputDestroy (output);
- return;
- }
- intel_output->type = I830_OUTPUT_LVDS;
- intel_output->pipe_mask = (1 << 1);
- intel_output->clone_mask = (1 << I830_OUTPUT_LVDS);
-
- output->driver_private = intel_output;
- output->subpixel_order = SubPixelHorizontalRGB;
- output->interlaceAllowed = FALSE;
- output->doubleScanAllowed = FALSE;
-
- dev_priv = (struct i830_lvds_priv *) (intel_output + 1);
- intel_output->dev_priv = dev_priv;
-
- /*
- * Mode detection algorithms for LFP:
- * 1) if EDID present, use it, done
- * 2) if VBT present, use it, done
- * 3) if current mode is programmed, use it, done
- * 4) check for Mac mini & other quirks
- * 4) fail, assume no LFP
- */
-
- /* Set up the LVDS DDC channel. Most panels won't support it, but it can
- * be useful if available.
- */
- I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOC, "LVDSDDC_C");
-
- if (pI830->skip_panel_detect) {
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Skipping any attempt to determine panel fixed mode.\n");
- goto found_mode;
- }
-
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Attempting to determine panel fixed mode.\n");
-
- /* Attempt to get the fixed panel mode from DDC. Assume that the preferred
- * mode is the right one.
- */
- modes = i830_ddc_get_modes(output);
- for (scan = modes; scan != NULL; scan = scan->next) {
- if (scan->type & M_T_PREFERRED)
- break;
- }
- if (scan != NULL) {
- /* Pull our chosen mode out and make it the fixed mode */
- if (modes == scan)
- modes = modes->next;
- if (scan->prev != NULL)
- scan->prev = scan->next;
- if (scan->next != NULL)
- scan->next = scan->prev;
- lvds_ddc_mode = scan;
- }
- /* Delete the mode list */
- while (modes != NULL)
- xf86DeleteMode(&modes, modes);
-
- if (lvds_ddc_mode) {
- pI830->lvds_fixed_mode = lvds_ddc_mode;
- goto found_mode;
- }
-
- /* Get the LVDS fixed mode out of the BIOS. We should support LVDS with
- * the BIOS being unavailable or broken, but lack the configuration options
- * for now.
- */
- if (pI830->lvds_fixed_mode)
- goto found_mode;
-
- /* If we *still* don't have a mode, try checking if the panel is already
- * turned on. If so, assume that whatever is currently programmed is the
- * correct mode.
- */
- if (!pI830->lvds_fixed_mode) {
- uint32_t lvds = INREG(LVDS);
- int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
- xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
- xf86CrtcPtr crtc = xf86_config->crtc[pipe];
-
- if (lvds & LVDS_PORT_EN) {
- pI830->lvds_fixed_mode = i830_crtc_mode_get(pScrn, crtc);
- if (pI830->lvds_fixed_mode != NULL) {
- pI830->lvds_fixed_mode->type |= M_T_PREFERRED;
- goto found_mode;
- }
- }
- }
-
- if (!pI830->lvds_fixed_mode)
- goto disable_exit;
-
-found_mode:
-
- /* Blacklist machines with BIOSes that list an LVDS panel without actually
- * having one.
- */
- if (pI830->quirk_flag & QUIRK_IGNORE_MACMINI_LVDS) {
- /* It's a Mac Mini or Macbook Pro.
- *
- * Apple hardware is out to get us. The macbook pro has a real
- * LVDS panel, but the mac mini does not, and they have the same
- * device IDs. We'll distinguish by panel size, on the assumption
- * that Apple isn't about to make any machines with an 800x600
- * display.
- */
-
- if (pI830->lvds_fixed_mode != NULL &&
- pI830->lvds_fixed_mode->HDisplay == 800 &&
- pI830->lvds_fixed_mode->VDisplay == 600)
- {
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Suspected Mac Mini, ignoring the LVDS\n");
- goto disable_exit;
- }
- }
-
- i830_set_lvds_backlight_method(output);
-
- switch (pI830->backlight_control_method) {
- case BCM_NATIVE:
- dev_priv->set_backlight = i830_lvds_set_backlight_native;
- dev_priv->get_backlight = i830_lvds_get_backlight_native;
- dev_priv->backlight_max = i830_lvds_get_backlight_max_native(output);
- break;
- case BCM_LEGACY:
- dev_priv->set_backlight = i830_lvds_set_backlight_legacy;
- dev_priv->get_backlight = i830_lvds_get_backlight_legacy;
- dev_priv->backlight_max = 0xff;
- break;
- case BCM_COMBO:
- dev_priv->set_backlight = i830_lvds_set_backlight_combo;
- dev_priv->get_backlight = i830_lvds_get_backlight_combo;
- dev_priv->backlight_max = i830_lvds_get_backlight_max_combo(output);
- break;
- case BCM_KERNEL:
- dev_priv->set_backlight = i830_lvds_set_backlight_kernel;
- dev_priv->get_backlight = i830_lvds_get_backlight_kernel;
- dev_priv->backlight_max = i830_lvds_get_backlight_max_kernel(output);
- break;
- default:
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "bad backlight control method\n");
- break;
- }
-
- dev_priv->backlight_duty_cycle = dev_priv->get_backlight(output);
-
- /*
- * Avoid munging the aspect ratio by default.
- */
- dev_priv->fitting_mode = FULL_ASPECT;
-
- return;
-
-disable_exit:
- xf86DestroyI2CBusRec(intel_output->pDDCBus, TRUE, TRUE);
- xf86OutputDestroy(output);
-}