summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@jbarnes-t61.(none)>2008-07-10 12:55:12 -0700
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-07-10 12:55:12 -0700
commite00d9435609bcff1afb71aa6638a6b42a64f5178 (patch)
tree4e64382957eb97f9321fd7bbf4a10da7743c088f /src
parent7332132a79e5b5c208d43e93dfe0c8b12eb1728d (diff)
Improve VBIOS feature detection, add SSC support
Improve the VBIOS feature detection and use it to find whether the platform supports spread spectrum clocking. Use the specified reference clock, but disable SSC if multiple heads are active, since it can cause problems in cloned configurations. Reviewed by Nanhai Zou.
Diffstat (limited to 'src')
-rw-r--r--src/i830.h4
-rw-r--r--src/i830_bios.c90
-rw-r--r--src/i830_bios.h93
-rw-r--r--src/i830_display.c18
-rw-r--r--src/i830_lvds.c3
5 files changed, 203 insertions, 5 deletions
diff --git a/src/i830.h b/src/i830.h
index 570db13e..68690f7b 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -554,6 +554,10 @@ typedef struct _I830Rec {
OptionInfoPtr Options;
Bool lvds_24_bit_mode;
+ Bool lvds_use_ssc;
+ int lvds_ssc_freq; /* in MHz */
+
+ Bool tv_present; /* TV connector present (from VBIOS) */
Bool StolenOnly;
diff --git a/src/i830_bios.c b/src/i830_bios.c
index 57ee2782..a8193fc5 100644
--- a/src/i830_bios.c
+++ b/src/i830_bios.c
@@ -70,6 +70,32 @@ i830DumpBIOSToFile(ScrnInfoPtr pScrn, unsigned char *bios)
fclose(f);
}
+static void *
+find_section(struct bdb_header *bdb, int section_id)
+{
+ unsigned char *base = (unsigned char *)bdb;
+ int index = 0;
+ uint16_t total, current_size;
+ unsigned char current_id;
+
+ /* skip to first section */
+ index += bdb->header_size;
+ total = bdb->bdb_size;
+
+ /* walk the sections looking for section_id */
+ while (index < total) {
+ current_id = *(base + index);
+ index++;
+ current_size = *((uint16_t *)(base + index));
+ index += 2;
+ if (current_id == section_id)
+ return base + index;
+ index += current_size;
+ }
+
+ return NULL;
+}
+
/**
* Loads the Video BIOS and checks that the VBT exists.
*
@@ -127,6 +153,70 @@ i830_bios_get (ScrnInfoPtr pScrn)
return bios;
}
+void
+i830_bios_get_ssc(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ struct vbt_header *vbt;
+ struct bdb_header *bdb;
+ struct bdb_general_features *bdb_features;
+ int vbt_off, bdb_off;
+ unsigned char *bios;
+
+ bios = i830_bios_get(pScrn);
+
+ if (bios == NULL)
+ return;
+
+ vbt_off = INTEL_BIOS_16(0x1a);
+ vbt = (struct vbt_header *)(bios + vbt_off);
+ bdb_off = vbt_off + vbt->bdb_offset;
+ bdb = (struct bdb_header *)(bios + bdb_off);
+
+ bdb_features = find_section(bdb, BDB_GENERAL_FEATURES);
+ if (!bdb_features)
+ return;
+
+ pI830->lvds_use_ssc = bdb_features->enable_ssc;
+ if (pI830->lvds_use_ssc) {
+ if (IS_I855(pI830))
+ pI830->lvds_ssc_freq = bdb_features->ssc_freq ? 66 : 48;
+ else
+ pI830->lvds_ssc_freq = bdb_features->ssc_freq ? 100 : 96;
+ }
+
+ xfree(bios);
+}
+
+void
+i830_bios_get_tv(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ struct vbt_header *vbt;
+ struct bdb_header *bdb;
+ struct bdb_general_features *bdb_features;
+ int vbt_off, bdb_off;
+ unsigned char *bios;
+
+ bios = i830_bios_get(pScrn);
+
+ if (bios == NULL)
+ return;
+
+ vbt_off = INTEL_BIOS_16(0x1a);
+ vbt = (struct vbt_header *)(bios + vbt_off);
+ bdb_off = vbt_off + vbt->bdb_offset;
+ bdb = (struct bdb_header *)(bios + bdb_off);
+
+ bdb_features = find_section(bdb, BDB_GENERAL_FEATURES);
+ if (!bdb_features)
+ return;
+
+ pI830->tv_present = bdb_features->int_tv_support;
+
+ xfree(bios);
+}
+
/**
* Returns the BIOS's fixed panel mode.
*
diff --git a/src/i830_bios.h b/src/i830_bios.h
index 95230f5a..c1ba50d7 100644
--- a/src/i830_bios.h
+++ b/src/i830_bios.h
@@ -49,6 +49,97 @@ struct bdb_header {
uint16_t bdb_size; /**< in bytes */
} __attribute__((packed));
+/*
+ * There are several types of BIOS data blocks (BDBs), each block has
+ * an ID and size in the first 3 bytes (ID in first, size in next 2).
+ * Known types are listed below.
+ */
+#define BDB_GENERAL_FEATURES 1
+#define BDB_GENERAL_DEFINITIONS 2
+#define BDB_OLD_TOGGLE_LIST 3
+#define BDB_MODE_SUPPORT_LIST 4
+#define BDB_GENERIC_MODE_TABLE 5
+#define BDB_EXT_MMIO_REGS 6
+#define BDB_SWF_IO 7
+#define BDB_SWF_MMIO 8
+#define BDB_DOT_CLOCK_TABLE 9
+#define BDB_MODE_REMOVAL_TABLE 10
+#define BDB_CHILD_DEVICE_TABLE 11
+#define BDB_DRIVER_FEATURES 12
+#define BDB_DRIVER_PERSISTENCE 13
+#define BDB_EXT_TABLE_PTRS 14
+#define BDB_DOT_CLOCK_OVERRIDE 15
+#define BDB_DISPLAY_SELECT 16
+/* 17 rsvd */
+#define BDB_DRIVER_ROTATION 18
+#define BDB_DISPLAY_REMOVE 19
+#define BDB_OEM_CUSTOM 20
+#define BDB_EFP_LIST 21 /* workarounds for VGA hsync/vsync */
+#define BDB_SDVO_LVDS_OPTIONS 22
+#define BDB_SDVO_PANEL_DTDS 23
+#define BDB_SDVO_LVDS_PNP_IDS 24
+#define BDB_SDVO_LVDS_POWER_SEQ 25
+#define BDB_TV_OPTIONS 26
+#define BDB_LVDS_OPTIONS 40
+#define BDB_LVDS_LFP_DATA_PTRS 41
+#define BDB_LVDS_LFP_DATA 42
+#define BDB_LVDS_BACKLIGHT 43
+#define BDB_LVDS_POWER 44
+#define BDB_SKIP 254 /* VBIOS private block, ignore */
+
+struct bdb_general_features {
+ /* bits 1 */
+ unsigned char panel_fitting:2;
+ unsigned char flexaim:1;
+ unsigned char msg_enable:1;
+ unsigned char clear_screen:3;
+ unsigned char color_flip:1;
+
+ /* bits 2 */
+ unsigned char download_ext_vbt:1;
+ unsigned char enable_ssc:1;
+ unsigned char ssc_freq:1;
+ unsigned char enable_lfp_on_override:1;
+ unsigned char disable_ssc_ddt:1;
+ unsigned char rsvd8:3; /* finish byte */
+
+ /* bits 3 */
+ unsigned char disable_smooth_vision:1;
+ unsigned char single_dvi:1;
+ unsigned char rsvd9:6; /* finish byte */
+
+ /* bits 4 */
+ unsigned char legacy_monitor_detect;
+
+ /* bits 5 */
+ unsigned char int_crt_support:1;
+ unsigned char int_tv_support:1;
+ unsigned char rsvd11:6; /* finish byte */
+} __attribute__((packed));
+
+struct bdb_general_definitions {
+ /* DDC GPIO */
+ unsigned char crt_ddc_gmbus_pin;
+
+ /* DPMS bits */
+ unsigned char dpms_acpi:1;
+ unsigned char skip_boot_crt_detect:1;
+ unsigned char dpms_aim:1;
+ unsigned char rsvd1:5; /* finish byte */
+
+ /* boot device bits */
+ unsigned char boot_display[2];
+ unsigned char child_dev_size;
+
+ /* device info */
+ unsigned char tv_or_lvds_info[33];
+ unsigned char dev1[33];
+ unsigned char dev2[33];
+ unsigned char dev3[33];
+ unsigned char dev4[33];
+ /* may be another device block here on some platforms */
+};
+
#define LVDS_CAP_EDID (1 << 6)
#define LVDS_CAP_DITHER (1 << 5)
#define LVDS_CAP_PFIT_AUTO_RATIO (1 << 4)
@@ -150,6 +241,8 @@ struct vch_bdb_22 {
unsigned char *
i830_bios_get (ScrnInfoPtr pScrn);
+void i830_bios_get_ssc(ScrnInfoPtr pScrn);
+void i830_bios_get_tv(ScrnInfoPtr pScrn);
DisplayModePtr i830_bios_get_panel_mode(ScrnInfoPtr pScrn, Bool *wants_dither);
unsigned char *
diff --git a/src/i830_display.c b/src/i830_display.c
index 306fed49..3967b69b 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -1128,7 +1128,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS;
int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE;
int pipestat_reg = (pipe == 0) ? PIPEASTAT : PIPEBSTAT;
- int i;
+ int i, num_outputs = 0;
int refclk;
intel_clock_t clock;
uint32_t dpll = 0, fp = 0, dspcntr, pipeconf, lvds_bits = 0;
@@ -1168,9 +1168,19 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
is_crt = TRUE;
break;
}
+
+ num_outputs++;
}
- if (IS_I9XX(pI830)) {
+ if (num_outputs > 1)
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "clone detected, disabling SSC\n");
+
+ /* Don't use SSC when cloned */
+ if (pI830->lvds_use_ssc && num_outputs < 2) {
+ refclk = pI830->lvds_ssc_freq * 1000;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "using SSC reference clock of %d MHz\n", refclk / 1000);
+ } else if (IS_I9XX(pI830)) {
refclk = 96000;
} else {
refclk = 48000;
@@ -1246,10 +1256,8 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
dpll |= 3;
}
-#if 0
- else if (is_lvds)
+ else if (is_lvds && pI830->lvds_use_ssc && num_outputs < 2)
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
-#endif
else
dpll |= PLL_REF_INPUT_DREFCLK;
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index d1bbb3a6..c7f24342 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -1341,6 +1341,9 @@ i830_lvds_init(ScrnInfoPtr pScrn)
goto disable_exit;
}
+ /* Update pI830 w/SSC info, if any */
+ i830_bios_get_ssc(pScrn);
+
skip_panel_fixed_mode_setup:
/* Blacklist machines with BIOSes that list an LVDS panel without actually