diff options
| -rw-r--r-- | linux-core/Makefile.kernel | 2 | ||||
| -rw-r--r-- | linux-core/intel_bios.c | 244 | ||||
| -rw-r--r-- | linux-core/intel_bios.h | 187 | ||||
| -rw-r--r-- | shared-core/i915_drv.h | 6 | ||||
| -rw-r--r-- | shared-core/i915_init.c | 7 | 
5 files changed, 445 insertions, 1 deletions
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 6480d51a..f77f8642 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -22,7 +22,7 @@ mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o  i810-objs   := i810_drv.o i810_dma.o  i915-objs   := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \  		i915_buffer.o i915_execbuf.o \ -	        intel_display.o intel_crt.o intel_lvds.o \ +	        intel_display.o intel_crt.o intel_lvds.o intel_bios.o \  		intel_sdvo.o intel_modes.o intel_i2c.o i915_init.o intel_fb.o \  		intel_tv.o i915_compat.o intel_dvo.o dvo_ch7xxx.o \  		dvo_ch7017.o dvo_ivch.o dvo_tfp410.o dvo_sil164.o diff --git a/linux-core/intel_bios.c b/linux-core/intel_bios.c new file mode 100644 index 00000000..7f8e8513 --- /dev/null +++ b/linux-core/intel_bios.c @@ -0,0 +1,244 @@ +/* + * 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> + * + */ +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" +#include "intel_bios.h" + +#define VBT_OFFSET 0x1a + +/** + * intel_find_vbt - find the VBT + * @dev: DRM device + * + * Loads the Video BIOS and checks that the VBT exists. + * + * VBT existence is a sanity check that is relied on by other i830_bios.c code. + * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may + * feed an updated VBT back through that, compared to what we'll fetch using + * this method of groping around in the BIOS data. + * + * Returns 0 on success, nonzero on failure. + */ +bool +intel_find_bios(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct pci_dev *pdev = dev->pdev; +	void __iomem *bios; +	size_t size; + +	bios = pci_map_rom(pdev, &size); +	if (!bios) +		return NULL; + +	dev_priv->vbt = (struct vbt_header *)((u8 *)bios + VBT_OFFSET); +	dev_priv->bdb = (struct bdb_header *)((u8 *)bios + VBT_OFFSET +  +					      dev_priv->vbt->bdb_offset); +	 +	if (memcmp(dev_priv->vbt->signature, "$VBT", 4) != 0) { +		DRM_ERROR("Bad VBT signature\n"); +		pci_unmap_rom(pdev, bios); +		return NULL; +	} + +	return bios; +} + +#if 0 +/** + * Returns the BIOS's fixed panel mode. + * + * Note that many BIOSes will have the appropriate tables for a panel even when + * a panel is not attached.  Additionally, many BIOSes adjust table sizes or + * offsets, such that this parsing fails.  Thus, almost any other method for + * detecting the panel mode is preferable. + */ +struct drm_display_mode * +i830_bios_get_panel_mode(struct drm_device *dev, bool *wants_dither) +{ +    I830Ptr pI830 = I830PTR(pScrn); +    struct vbt_header *vbt; +    struct bdb_header *bdb; +    int vbt_off, bdb_off, bdb_block_off, block_size; +    int panel_type = -1; +    unsigned char *bios; + +    bios = i830_bios_get (pScrn); + +    if (bios == NULL) +	return NULL; + +    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); + +    if (memcmp(bdb->signature, "BIOS_DATA_BLOCK ", 16) != 0) { +	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad BDB signature\n"); +	xfree(bios); +	return NULL; +    } + +    *wants_dither = FALSE; +    for (bdb_block_off = bdb->header_size; bdb_block_off < bdb->bdb_size; +	 bdb_block_off += block_size) +    { +	int start = bdb_off + bdb_block_off; +	int id; +	struct lvds_bdb_1 *lvds1; +	struct lvds_bdb_2 *lvds2; +	struct lvds_bdb_2_fp_params *fpparam; +	struct lvds_bdb_2_fp_edid_dtd *fptiming; +	DisplayModePtr fixed_mode; +	CARD8 *timing_ptr; + +	id = INTEL_BIOS_8(start); +	block_size = INTEL_BIOS_16(start + 1) + 3; +	switch (id) { +	case 40: +	    lvds1 = (struct lvds_bdb_1 *)(bios + start); +	    panel_type = lvds1->panel_type; +	    if (lvds1->caps & LVDS_CAP_DITHER) +		*wants_dither = TRUE; +	    break; +	case 41: +	    if (panel_type == -1) +		break; + +	    lvds2 = (struct lvds_bdb_2 *)(bios + start); +	    fpparam = (struct lvds_bdb_2_fp_params *)(bios + +		bdb_off + lvds2->panels[panel_type].fp_params_offset); +	    fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(bios + +		bdb_off + lvds2->panels[panel_type].fp_edid_dtd_offset); +	    timing_ptr = bios + bdb_off + +	        lvds2->panels[panel_type].fp_edid_dtd_offset; + +	    if (fpparam->terminator != 0xffff) { +		/* Apparently the offsets are wrong for some BIOSes, so we +		 * try the other offsets if we find a bad terminator. +		 */ +		fpparam = (struct lvds_bdb_2_fp_params *)(bios + +		    bdb_off + lvds2->panels[panel_type].fp_params_offset + 8); +		fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(bios + +		    bdb_off + lvds2->panels[panel_type].fp_edid_dtd_offset + 8); +		timing_ptr = bios + bdb_off + +	            lvds2->panels[panel_type].fp_edid_dtd_offset + 8; + +		if (fpparam->terminator != 0xffff) +		    continue; +	    } + +	    fixed_mode = xnfalloc(sizeof(DisplayModeRec)); +	    memset(fixed_mode, 0, sizeof(*fixed_mode)); + +	    /* Since lvds_bdb_2_fp_edid_dtd is just an EDID detailed timing +	     * block, pull the contents out using EDID macros. +	     */ +	    fixed_mode->HDisplay   = _H_ACTIVE(timing_ptr); +	    fixed_mode->VDisplay   = _V_ACTIVE(timing_ptr); +	    fixed_mode->HSyncStart = fixed_mode->HDisplay + +		_H_SYNC_OFF(timing_ptr); +	    fixed_mode->HSyncEnd   = fixed_mode->HSyncStart + +		_H_SYNC_WIDTH(timing_ptr); +	    fixed_mode->HTotal     = fixed_mode->HDisplay + +	        _H_BLANK(timing_ptr); +	    fixed_mode->VSyncStart = fixed_mode->VDisplay + +		_V_SYNC_OFF(timing_ptr); +	    fixed_mode->VSyncEnd   = fixed_mode->VSyncStart + +		_V_SYNC_WIDTH(timing_ptr); +	    fixed_mode->VTotal     = fixed_mode->VDisplay + +	        _V_BLANK(timing_ptr); +	    fixed_mode->Clock      = _PIXEL_CLOCK(timing_ptr) / 1000; +	    fixed_mode->type       = M_T_PREFERRED; + +	    xf86SetModeDefaultName(fixed_mode); + +	    if (pI830->debug_modes) { +		xf86DrvMsg(pScrn->scrnIndex, X_INFO, +			   "Found panel mode in BIOS VBT tables:\n"); +		xf86PrintModeline(pScrn->scrnIndex, fixed_mode); +	    } + +	    xfree(bios); +	    return fixed_mode; +	} +    } + +    xfree(bios); +    return NULL; +} + +unsigned char * +i830_bios_get_aim_data_block (ScrnInfoPtr pScrn, int aim, int data_block) +{ +    unsigned char   *bios; +    int		    bdb_off; +    int		    vbt_off; +    int		    aim_off; +    struct vbt_header *vbt; +    struct aimdb_header *aimdb; +    struct aimdb_block *aimdb_block; + +    bios = i830_bios_get (pScrn); +    if (!bios) +	return NULL; + +    vbt_off = INTEL_BIOS_16(0x1a); +    vbt = (struct vbt_header *)(bios + vbt_off); + +    aim_off = vbt->aim_offset[aim]; +    if (!aim_off) +    { +	free (bios); +	return NULL; +    } +    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "aim_off %d\n", aim_off); +    aimdb = (struct aimdb_header *) (bios + vbt_off + aim_off); +    bdb_off = aimdb->aimdb_header_size; +    while (bdb_off < aimdb->aimdb_size) +    { +	aimdb_block = (struct aimdb_block *) (bios + vbt_off + aim_off + bdb_off); +	if (aimdb_block->aimdb_id == data_block) +	{ +	    unsigned char   *aim = malloc (aimdb_block->aimdb_size + sizeof (struct aimdb_block)); +	    if (!aim) +	    { +		free (bios); +		return NULL; +	    } +	    memcpy (aim, aimdb_block, aimdb_block->aimdb_size + sizeof (struct aimdb_block)); +	    free (bios); +	    return aim; +	} +	bdb_off += aimdb_block->aimdb_size + sizeof (struct aimdb_block); +    } +    free (bios); +    return NULL; +} +#endif diff --git a/linux-core/intel_bios.h b/linux-core/intel_bios.h new file mode 100644 index 00000000..b17856de --- /dev/null +++ b/linux-core/intel_bios.h @@ -0,0 +1,187 @@ +/* + * 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> + * + */ + +#ifndef _I830_BIOS_H_ +#define _I830_BIOS_H_ + +#include "drmP.h" + +struct vbt_header { +	u8 signature[20];		/**< Always starts with 'VBT$' */ +	u16 version;			/**< decimal */ +	u16 header_size;		/**< in bytes */ +	u16 vbt_size;			/**< in bytes */ +	u8 vbt_checksum; +	u8 reserved0; +	u32 bdb_offset;			/**< from beginning of VBT */ +	u32 aim_offset[4];		/**< from beginning of VBT */ +} __attribute__((packed)); + +struct bdb_header { +	u8 signature[16];		/**< Always 'BIOS_DATA_BLOCK' */ +	u16 version;			/**< decimal */ +	u16 header_size;		/**< in bytes */ +	u16 bdb_size;			/**< in bytes */ +	u8 type; /* 0 == desktop, 1 == mobile */ +	u8 relstage; +	u8 chipset; +	u8 lvds_present:1; +	u8 tv_present:1; +	u8 rsvd2:6; /* finish byte */ +	u8 rsvd3[4]; +	u8 signon[155]; +	u8 copyright[61]; +	u16 code_segment; +	u8 dos_boot_mode; +	u8 bandwidth_percent; +	u8 rsvd4; +	u8 resize_pci_bios; +	u8 rsvd5; +	u8 rsvd6[3]; +	u8 panel_fitting:2; +	u8 flexaim:1; +	u8 msg_enable:1; +	u8 clear_screen:1; +	u8 color_flip:1; +	u8 rsvd7:2; /* finish byte */ +	u8 download_ext_vbt:1; +	u8 enable_ssc:1; +	u8 ssc_freq:1; +	u8 enable_lfp_on_override:1; +	u8 disable_ssc_ddt:1; +	u8 rsvd8:3; /* finish byte */ +	u8 disable_smooth_vision:1; +	u8 single_dvi:1; +	u8 rsvd9:6; /* finish byte */ +	u8 legacy_monitor_detect:1; +	u8 rsvd10:7; /* finish byte */ +	u8 int_crt_support:1; +	u8 int_tv_support:1; +	u8 rsvd11:6; /* finish byte */ +} __attribute__((packed)); + +#define LVDS_CAP_EDID			(1 << 6) +#define LVDS_CAP_DITHER			(1 << 5) +#define LVDS_CAP_PFIT_AUTO_RATIO	(1 << 4) +#define LVDS_CAP_PFIT_GRAPHICS_MODE	(1 << 3) +#define LVDS_CAP_PFIT_TEXT_MODE		(1 << 2) +#define LVDS_CAP_PFIT_GRAPHICS		(1 << 1) +#define LVDS_CAP_PFIT_TEXT		(1 << 0) +struct lvds_bdb_1 { +	u8 id;				/**< 40 */ +	u16 size; +	u8 panel_type; +	u8 reserved0; +	u16 caps; +} __attribute__((packed)); + +struct lvds_bdb_2_fp_params { +	u16 x_res; +	u16 y_res; +	u32 lvds_reg; +	u32 lvds_reg_val; +	u32 pp_on_reg; +	u32 pp_on_reg_val; +	u32 pp_off_reg; +	u32 pp_off_reg_val; +	u32 pp_cycle_reg; +	u32 pp_cycle_reg_val; +	u32 pfit_reg; +	u32 pfit_reg_val; +	u16 terminator; +} __attribute__((packed)); + +struct lvds_bdb_2_fp_edid_dtd { +	u16 dclk;		/**< In 10khz */ +	u8 hactive; +	u8 hblank; +	u8 high_h;		/**< 7:4 = hactive 11:8, 3:0 = hblank 11:8 */ +	u8 vactive; +	u8 vblank; +	u8 high_v;		/**< 7:4 = vactive 11:8, 3:0 = vblank 11:8 */ +	u8 hsync_off; +	u8 hsync_pulse_width; +	u8 vsync_off; +	u8 high_hsync_off;	/**< 7:6 = hsync off 9:8 */ +	u8 h_image; +	u8 v_image; +	u8 max_hv; +	u8 h_border; +	u8 v_border; +	u8 flags; +#define FP_EDID_FLAG_VSYNC_POSITIVE	(1 << 2) +#define FP_EDID_FLAG_HSYNC_POSITIVE	(1 << 1) +} __attribute__((packed)); + +struct lvds_bdb_2_entry { +	u16 fp_params_offset;		/**< From beginning of BDB */ +	u8 fp_params_size; +	u16 fp_edid_dtd_offset; +	u8 fp_edid_dtd_size; +	u16 fp_edid_pid_offset; +	u8 fp_edid_pid_size; +} __attribute__((packed)); + +struct lvds_bdb_2 { +	u8 id;			/**< 41 */ +	u16 size; +	u8 table_size;	/* not sure on this one */ +	struct lvds_bdb_2_entry panels[16]; +} __attribute__((packed)); + +struct aimdb_header { +	char signature[16]; +	char oem_device[20]; +	u16 aimdb_version; +	u16 aimdb_header_size; +	u16 aimdb_size; +} __attribute__((packed)); + +struct aimdb_block { +	u8 aimdb_id; +	u16 aimdb_size; +} __attribute__((packed)); + +struct vch_panel_data { +	u16 fp_timing_offset; +	u8 fp_timing_size; +	u16 dvo_timing_offset; +	u8 dvo_timing_size; +	u16 text_fitting_offset; +	u8 text_fitting_size; +	u16 graphics_fitting_offset; +	u8 graphics_fitting_size; +} __attribute__((packed)); + +struct vch_bdb_22 { +	struct aimdb_block aimdb_block; +	struct vch_panel_data panels[16]; +} __attribute__((packed)); + +bool intel_find_bios(struct drm_device *dev); + +#endif /* _I830_BIOS_H_ */ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index a7040f5b..2e7b6bd2 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -33,6 +33,8 @@  /* General customization:   */ +#include "intel_bios.h" +  #define DRIVER_AUTHOR		"Tungsten Graphics, Inc."  #define DRIVER_NAME		"i915" @@ -171,6 +173,10 @@ struct drm_i915_private {  	struct drm_buffer_object *sarea_bo;  	struct drm_bo_kmap_obj sarea_kmap; +	/* BIOS data */ +	struct vbt_header *vbt; +	struct bdb_header *bdb; +  	/* Register state */  	u8 saveLBB;  	u32 saveDSPACNTR; diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 53574eb7..8824b959 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -12,6 +12,7 @@  #include "drm_sarea.h"  #include "i915_drm.h"  #include "i915_drv.h" +#include "intel_bios.h"  /**   * i915_probe_agp - get AGP bootup configuration @@ -259,6 +260,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)  		  DRM_DEBUG("Error\n");  		} +		ret = intel_find_bios(dev); +		if (ret) { +			DRM_ERROR("failed to find VBT\n"); +			return -ENODEV; +		} +  		intel_modeset_init(dev);  		drm_initial_config(dev, false);  | 
