forked from KolibriOS/kolibrios
parse vbios
git-svn-id: svn://kolibrios.org@2327 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
e5d0784a42
commit
8ffe856896
@ -766,3 +766,8 @@ const struct intel_gtt *intel_gtt_get(void)
|
|||||||
return &intel_private.base;
|
return &intel_private.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
phys_addr_t get_bus_addr(void)
|
||||||
|
{
|
||||||
|
return intel_private.gma_bus_addr;
|
||||||
|
};
|
||||||
|
@ -81,6 +81,68 @@ static int i915_init_phys_hws(struct drm_device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int i915_load_modeset_init(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = intel_parse_bios(dev);
|
||||||
|
if (ret)
|
||||||
|
DRM_INFO("failed to find VBIOS tables\n");
|
||||||
|
|
||||||
|
// intel_register_dsm_handler();
|
||||||
|
|
||||||
|
/* IIR "flip pending" bit means done if this bit is set */
|
||||||
|
if (IS_GEN3(dev) && (I915_READ(ECOSKPD) & ECO_FLIP_DONE))
|
||||||
|
dev_priv->flip_pending_is_done = true;
|
||||||
|
|
||||||
|
intel_modeset_init(dev);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
ret = i915_load_gem_init(dev);
|
||||||
|
if (ret)
|
||||||
|
goto cleanup_vga_switcheroo;
|
||||||
|
|
||||||
|
intel_modeset_gem_init(dev);
|
||||||
|
|
||||||
|
ret = drm_irq_install(dev);
|
||||||
|
if (ret)
|
||||||
|
goto cleanup_gem;
|
||||||
|
|
||||||
|
/* Always safe in the mode setting case. */
|
||||||
|
/* FIXME: do pre/post-mode set stuff in core KMS code */
|
||||||
|
dev->vblank_disable_allowed = 1;
|
||||||
|
|
||||||
|
ret = intel_fbdev_init(dev);
|
||||||
|
if (ret)
|
||||||
|
goto cleanup_irq;
|
||||||
|
|
||||||
|
drm_kms_helper_poll_init(dev);
|
||||||
|
|
||||||
|
/* We're off and running w/KMS */
|
||||||
|
dev_priv->mm.suspended = 0;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cleanup_irq:
|
||||||
|
// drm_irq_uninstall(dev);
|
||||||
|
cleanup_gem:
|
||||||
|
// mutex_lock(&dev->struct_mutex);
|
||||||
|
// i915_gem_cleanup_ringbuffer(dev);
|
||||||
|
// mutex_unlock(&dev->struct_mutex);
|
||||||
|
cleanup_vga_switcheroo:
|
||||||
|
// vga_switcheroo_unregister_client(dev->pdev);
|
||||||
|
cleanup_vga_client:
|
||||||
|
// vga_client_register(dev->pdev, NULL, NULL, NULL);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void i915_pineview_get_mem_freq(struct drm_device *dev)
|
static void i915_pineview_get_mem_freq(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
@ -333,7 +395,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||||||
// intel_setup_mchbar(dev);
|
// intel_setup_mchbar(dev);
|
||||||
intel_setup_gmbus(dev);
|
intel_setup_gmbus(dev);
|
||||||
|
|
||||||
// intel_opregion_setup(dev);
|
intel_opregion_setup(dev);
|
||||||
|
|
||||||
/* Make sure the bios did its job and set up vital registers */
|
/* Make sure the bios did its job and set up vital registers */
|
||||||
// intel_setup_bios(dev);
|
// intel_setup_bios(dev);
|
||||||
@ -384,14 +446,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||||||
|
|
||||||
intel_detect_pch(dev);
|
intel_detect_pch(dev);
|
||||||
|
|
||||||
|
ret = i915_load_modeset_init(dev);
|
||||||
// if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
if (ret < 0) {
|
||||||
// ret = i915_load_modeset_init(dev);
|
DRM_ERROR("failed to init modeset\n");
|
||||||
// if (ret < 0) {
|
goto out_gem_unload;
|
||||||
// DRM_ERROR("failed to init modeset\n");
|
}
|
||||||
// goto out_gem_unload;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
/* Must be done after probing outputs */
|
/* Must be done after probing outputs */
|
||||||
// intel_opregion_init(dev);
|
// intel_opregion_init(dev);
|
||||||
|
@ -40,6 +40,12 @@
|
|||||||
#include "i915_drv.h"
|
#include "i915_drv.h"
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
|
|
||||||
|
unsigned int i915_lvds_downclock = 0;
|
||||||
|
int i915_vbt_sdvo_panel_type = -1;
|
||||||
|
unsigned int i915_panel_use_ssc = 1;
|
||||||
|
unsigned int i915_powersave = 1;
|
||||||
|
unsigned int i915_enable_fbc = 1;
|
||||||
|
|
||||||
#define PCI_VENDOR_ID_INTEL 0x8086
|
#define PCI_VENDOR_ID_INTEL 0x8086
|
||||||
|
|
||||||
#define INTEL_VGA_DEVICE(id, info) { \
|
#define INTEL_VGA_DEVICE(id, info) { \
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
#define _I915_DRV_H_
|
#define _I915_DRV_H_
|
||||||
|
|
||||||
#include "i915_reg.h"
|
#include "i915_reg.h"
|
||||||
//#include "intel_bios.h"
|
#include "intel_bios.h"
|
||||||
#include "intel_ringbuffer.h"
|
#include "intel_ringbuffer.h"
|
||||||
//#include <linux/io-mapping.h>
|
//#include <linux/io-mapping.h>
|
||||||
//#include <linux/i2c.h>
|
//#include <linux/i2c.h>
|
||||||
@ -43,6 +43,9 @@
|
|||||||
/* General customization:
|
/* General customization:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define I915_TILING_NONE 0
|
||||||
|
|
||||||
|
|
||||||
#define DRIVER_AUTHOR "Tungsten Graphics, Inc."
|
#define DRIVER_AUTHOR "Tungsten Graphics, Inc."
|
||||||
|
|
||||||
#define DRIVER_NAME "i915"
|
#define DRIVER_NAME "i915"
|
||||||
@ -332,7 +335,7 @@ typedef struct drm_i915_private {
|
|||||||
int cfb_y;
|
int cfb_y;
|
||||||
// struct intel_fbc_work *fbc_work;
|
// struct intel_fbc_work *fbc_work;
|
||||||
|
|
||||||
// struct intel_opregion opregion;
|
struct intel_opregion opregion;
|
||||||
|
|
||||||
/* overlay */
|
/* overlay */
|
||||||
// struct intel_overlay *overlay;
|
// struct intel_overlay *overlay;
|
||||||
@ -360,7 +363,7 @@ typedef struct drm_i915_private {
|
|||||||
bool initialized;
|
bool initialized;
|
||||||
bool support;
|
bool support;
|
||||||
int bpp;
|
int bpp;
|
||||||
// struct edp_power_seq pps;
|
struct edp_power_seq pps;
|
||||||
} edp;
|
} edp;
|
||||||
bool no_aux_handshake;
|
bool no_aux_handshake;
|
||||||
|
|
||||||
@ -380,7 +383,7 @@ typedef struct drm_i915_private {
|
|||||||
// struct workqueue_struct *wq;
|
// struct workqueue_struct *wq;
|
||||||
|
|
||||||
/* Display functions */
|
/* Display functions */
|
||||||
// struct drm_i915_display_funcs display;
|
struct drm_i915_display_funcs display;
|
||||||
|
|
||||||
/* PCH chipset type */
|
/* PCH chipset type */
|
||||||
enum intel_pch pch_type;
|
enum intel_pch pch_type;
|
||||||
@ -660,7 +663,7 @@ typedef struct drm_i915_private {
|
|||||||
size_t object_memory;
|
size_t object_memory;
|
||||||
u32 object_count;
|
u32 object_count;
|
||||||
} mm;
|
} mm;
|
||||||
// struct sdvo_device_mapping sdvo_mappings[2];
|
struct sdvo_device_mapping sdvo_mappings[2];
|
||||||
/* indicate whether the LVDS_BORDER should be enabled or not */
|
/* indicate whether the LVDS_BORDER should be enabled or not */
|
||||||
unsigned int lvds_border_bits;
|
unsigned int lvds_border_bits;
|
||||||
/* Panel fitter placement and size for Ironlake+ */
|
/* Panel fitter placement and size for Ironlake+ */
|
||||||
@ -682,9 +685,9 @@ typedef struct drm_i915_private {
|
|||||||
bool busy;
|
bool busy;
|
||||||
u16 orig_clock;
|
u16 orig_clock;
|
||||||
int child_dev_num;
|
int child_dev_num;
|
||||||
// struct child_device_config *child_dev;
|
struct child_device_config *child_dev;
|
||||||
// struct drm_connector *int_lvds_connector;
|
struct drm_connector *int_lvds_connector;
|
||||||
// struct drm_connector *int_edp_connector;
|
struct drm_connector *int_edp_connector;
|
||||||
|
|
||||||
bool mchbar_need_disable;
|
bool mchbar_need_disable;
|
||||||
|
|
||||||
@ -732,6 +735,152 @@ enum i915_cache_level {
|
|||||||
I915_CACHE_LLC_MLC, /* gen6+ */
|
I915_CACHE_LLC_MLC, /* gen6+ */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct drm_i915_gem_object {
|
||||||
|
struct drm_gem_object base;
|
||||||
|
|
||||||
|
/** Current space allocated to this object in the GTT, if any. */
|
||||||
|
struct drm_mm_node *gtt_space;
|
||||||
|
struct list_head gtt_list;
|
||||||
|
|
||||||
|
/** This object's place on the active/flushing/inactive lists */
|
||||||
|
struct list_head ring_list;
|
||||||
|
struct list_head mm_list;
|
||||||
|
/** This object's place on GPU write list */
|
||||||
|
struct list_head gpu_write_list;
|
||||||
|
/** This object's place in the batchbuffer or on the eviction list */
|
||||||
|
struct list_head exec_list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is set if the object is on the active or flushing lists
|
||||||
|
* (has pending rendering), and is not set if it's on inactive (ready
|
||||||
|
* to be unbound).
|
||||||
|
*/
|
||||||
|
unsigned int active : 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is set if the object has been written to since last bound
|
||||||
|
* to the GTT
|
||||||
|
*/
|
||||||
|
unsigned int dirty : 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is set if the object has been written to since the last
|
||||||
|
* GPU flush.
|
||||||
|
*/
|
||||||
|
unsigned int pending_gpu_write : 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fence register bits (if any) for this object. Will be set
|
||||||
|
* as needed when mapped into the GTT.
|
||||||
|
* Protected by dev->struct_mutex.
|
||||||
|
*
|
||||||
|
* Size: 4 bits for 16 fences + sign (for FENCE_REG_NONE)
|
||||||
|
*/
|
||||||
|
signed int fence_reg : 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advice: are the backing pages purgeable?
|
||||||
|
*/
|
||||||
|
unsigned int madv : 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current tiling mode for the object.
|
||||||
|
*/
|
||||||
|
unsigned int tiling_mode : 2;
|
||||||
|
unsigned int tiling_changed : 1;
|
||||||
|
|
||||||
|
/** How many users have pinned this object in GTT space. The following
|
||||||
|
* users can each hold at most one reference: pwrite/pread, pin_ioctl
|
||||||
|
* (via user_pin_count), execbuffer (objects are not allowed multiple
|
||||||
|
* times for the same batchbuffer), and the framebuffer code. When
|
||||||
|
* switching/pageflipping, the framebuffer code has at most two buffers
|
||||||
|
* pinned per crtc.
|
||||||
|
*
|
||||||
|
* In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
|
||||||
|
* bits with absolutely no headroom. So use 4 bits. */
|
||||||
|
unsigned int pin_count : 4;
|
||||||
|
#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the object at the current location in the gtt mappable and
|
||||||
|
* fenceable? Used to avoid costly recalculations.
|
||||||
|
*/
|
||||||
|
unsigned int map_and_fenceable : 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the current gtt mapping needs to be mappable (and isn't just
|
||||||
|
* mappable by accident). Track pin and fault separate for a more
|
||||||
|
* accurate mappable working set.
|
||||||
|
*/
|
||||||
|
unsigned int fault_mappable : 1;
|
||||||
|
unsigned int pin_mappable : 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is the GPU currently using a fence to access this buffer,
|
||||||
|
*/
|
||||||
|
unsigned int pending_fenced_gpu_access:1;
|
||||||
|
unsigned int fenced_gpu_access:1;
|
||||||
|
|
||||||
|
unsigned int cache_level:2;
|
||||||
|
|
||||||
|
struct page **pages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DMAR support
|
||||||
|
*/
|
||||||
|
struct scatterlist *sg_list;
|
||||||
|
int num_sg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for performing relocations during execbuffer insertion.
|
||||||
|
*/
|
||||||
|
struct hlist_node exec_node;
|
||||||
|
unsigned long exec_handle;
|
||||||
|
struct drm_i915_gem_exec_object2 *exec_entry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current offset of the object in GTT space.
|
||||||
|
*
|
||||||
|
* This is the same as gtt_space->start
|
||||||
|
*/
|
||||||
|
uint32_t gtt_offset;
|
||||||
|
|
||||||
|
/** Breadcrumb of last rendering to the buffer. */
|
||||||
|
uint32_t last_rendering_seqno;
|
||||||
|
struct intel_ring_buffer *ring;
|
||||||
|
|
||||||
|
/** Breadcrumb of last fenced GPU access to the buffer. */
|
||||||
|
uint32_t last_fenced_seqno;
|
||||||
|
struct intel_ring_buffer *last_fenced_ring;
|
||||||
|
|
||||||
|
/** Current tiling stride for the object, if it's tiled. */
|
||||||
|
uint32_t stride;
|
||||||
|
|
||||||
|
/** Record of address bit 17 of each page at last unbind. */
|
||||||
|
unsigned long *bit_17;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If present, while GEM_DOMAIN_CPU is in the read domain this array
|
||||||
|
* flags which individual pages are valid.
|
||||||
|
*/
|
||||||
|
uint8_t *page_cpu_valid;
|
||||||
|
|
||||||
|
/** User space pin count and filp owning the pin */
|
||||||
|
uint32_t user_pin_count;
|
||||||
|
struct drm_file *pin_filp;
|
||||||
|
|
||||||
|
/** for phy allocated objects */
|
||||||
|
struct drm_i915_gem_phys_object *phys_obj;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of crtcs where this object is currently the fb, but
|
||||||
|
* will be page flipped away on the next vblank. When it
|
||||||
|
* reaches 0, dev_priv->pending_flip_queue will be woken up.
|
||||||
|
*/
|
||||||
|
atomic_t pending_flip;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
|
#define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
|
||||||
|
|
||||||
|
712
drivers/video/drm/i915/intel_bios.c
Normal file
712
drivers/video/drm/i915/intel_bios.c
Normal file
@ -0,0 +1,712 @@
|
|||||||
|
/*
|
||||||
|
* 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 <drm/drm_dp_helper.h>
|
||||||
|
#include "drmP.h"
|
||||||
|
#include "drm.h"
|
||||||
|
//#include "i915_drm.h"
|
||||||
|
#include "i915_drv.h"
|
||||||
|
#include "intel_bios.h"
|
||||||
|
|
||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
#define SLAVE_ADDR1 0x70
|
||||||
|
#define SLAVE_ADDR2 0x72
|
||||||
|
|
||||||
|
static int panel_type;
|
||||||
|
|
||||||
|
static void *
|
||||||
|
find_section(struct bdb_header *bdb, int section_id)
|
||||||
|
{
|
||||||
|
u8 *base = (u8 *)bdb;
|
||||||
|
int index = 0;
|
||||||
|
u16 total, current_size;
|
||||||
|
u8 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 = *((u16 *)(base + index));
|
||||||
|
index += 2;
|
||||||
|
if (current_id == section_id)
|
||||||
|
return base + index;
|
||||||
|
index += current_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u16
|
||||||
|
get_blocksize(void *p)
|
||||||
|
{
|
||||||
|
u16 *block_ptr, block_size;
|
||||||
|
|
||||||
|
block_ptr = (u16 *)((char *)p - 2);
|
||||||
|
block_size = *block_ptr;
|
||||||
|
return block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
|
||||||
|
const struct lvds_dvo_timing *dvo_timing)
|
||||||
|
{
|
||||||
|
panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) |
|
||||||
|
dvo_timing->hactive_lo;
|
||||||
|
panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay +
|
||||||
|
((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo);
|
||||||
|
panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start +
|
||||||
|
dvo_timing->hsync_pulse_width;
|
||||||
|
panel_fixed_mode->htotal = panel_fixed_mode->hdisplay +
|
||||||
|
((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo);
|
||||||
|
|
||||||
|
panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) |
|
||||||
|
dvo_timing->vactive_lo;
|
||||||
|
panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay +
|
||||||
|
dvo_timing->vsync_off;
|
||||||
|
panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start +
|
||||||
|
dvo_timing->vsync_pulse_width;
|
||||||
|
panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay +
|
||||||
|
((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo);
|
||||||
|
panel_fixed_mode->clock = dvo_timing->clock * 10;
|
||||||
|
panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
|
||||||
|
|
||||||
|
if (dvo_timing->hsync_positive)
|
||||||
|
panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC;
|
||||||
|
else
|
||||||
|
panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC;
|
||||||
|
|
||||||
|
if (dvo_timing->vsync_positive)
|
||||||
|
panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC;
|
||||||
|
else
|
||||||
|
panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC;
|
||||||
|
|
||||||
|
/* Some VBTs have bogus h/vtotal values */
|
||||||
|
if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal)
|
||||||
|
panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1;
|
||||||
|
if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal)
|
||||||
|
panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1;
|
||||||
|
|
||||||
|
drm_mode_set_name(panel_fixed_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
lvds_dvo_timing_equal_size(const struct lvds_dvo_timing *a,
|
||||||
|
const struct lvds_dvo_timing *b)
|
||||||
|
{
|
||||||
|
if (a->hactive_hi != b->hactive_hi ||
|
||||||
|
a->hactive_lo != b->hactive_lo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (a->hsync_off_hi != b->hsync_off_hi ||
|
||||||
|
a->hsync_off_lo != b->hsync_off_lo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (a->hsync_pulse_width != b->hsync_pulse_width)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (a->hblank_hi != b->hblank_hi ||
|
||||||
|
a->hblank_lo != b->hblank_lo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (a->vactive_hi != b->vactive_hi ||
|
||||||
|
a->vactive_lo != b->vactive_lo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (a->vsync_off != b->vsync_off)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (a->vsync_pulse_width != b->vsync_pulse_width)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (a->vblank_hi != b->vblank_hi ||
|
||||||
|
a->vblank_lo != b->vblank_lo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct lvds_dvo_timing *
|
||||||
|
get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data,
|
||||||
|
const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs,
|
||||||
|
int index)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* the size of fp_timing varies on the different platform.
|
||||||
|
* So calculate the DVO timing relative offset in LVDS data
|
||||||
|
* entry to get the DVO timing entry
|
||||||
|
*/
|
||||||
|
|
||||||
|
int lfp_data_size =
|
||||||
|
lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset -
|
||||||
|
lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset;
|
||||||
|
int dvo_timing_offset =
|
||||||
|
lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset -
|
||||||
|
lvds_lfp_data_ptrs->ptr[0].fp_timing_offset;
|
||||||
|
char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index;
|
||||||
|
|
||||||
|
return (struct lvds_dvo_timing *)(entry + dvo_timing_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to find integrated panel data */
|
||||||
|
static void
|
||||||
|
parse_lfp_panel_data(struct drm_i915_private *dev_priv,
|
||||||
|
struct bdb_header *bdb)
|
||||||
|
{
|
||||||
|
const struct bdb_lvds_options *lvds_options;
|
||||||
|
const struct bdb_lvds_lfp_data *lvds_lfp_data;
|
||||||
|
const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
|
||||||
|
const struct lvds_dvo_timing *panel_dvo_timing;
|
||||||
|
struct drm_display_mode *panel_fixed_mode;
|
||||||
|
int i, downclock;
|
||||||
|
|
||||||
|
lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
|
||||||
|
if (!lvds_options)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dev_priv->lvds_dither = lvds_options->pixel_dither;
|
||||||
|
if (lvds_options->panel_type == 0xff)
|
||||||
|
return;
|
||||||
|
|
||||||
|
panel_type = lvds_options->panel_type;
|
||||||
|
|
||||||
|
lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
|
||||||
|
if (!lvds_lfp_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS);
|
||||||
|
if (!lvds_lfp_data_ptrs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dev_priv->lvds_vbt = 1;
|
||||||
|
|
||||||
|
panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
|
||||||
|
lvds_lfp_data_ptrs,
|
||||||
|
lvds_options->panel_type);
|
||||||
|
|
||||||
|
panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
|
||||||
|
if (!panel_fixed_mode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing);
|
||||||
|
|
||||||
|
dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n");
|
||||||
|
drm_mode_debug_printmodeline(panel_fixed_mode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iterate over the LVDS panel timing info to find the lowest clock
|
||||||
|
* for the native resolution.
|
||||||
|
*/
|
||||||
|
downclock = panel_dvo_timing->clock;
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
const struct lvds_dvo_timing *dvo_timing;
|
||||||
|
|
||||||
|
dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
|
||||||
|
lvds_lfp_data_ptrs,
|
||||||
|
i);
|
||||||
|
if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) &&
|
||||||
|
dvo_timing->clock < downclock)
|
||||||
|
downclock = dvo_timing->clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) {
|
||||||
|
dev_priv->lvds_downclock_avail = 1;
|
||||||
|
dev_priv->lvds_downclock = downclock * 10;
|
||||||
|
DRM_DEBUG_KMS("LVDS downclock is found in VBT. "
|
||||||
|
"Normal Clock %dKHz, downclock %dKHz\n",
|
||||||
|
panel_fixed_mode->clock, 10*downclock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to find sdvo panel data */
|
||||||
|
static void
|
||||||
|
parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
|
||||||
|
struct bdb_header *bdb)
|
||||||
|
{
|
||||||
|
struct lvds_dvo_timing *dvo_timing;
|
||||||
|
struct drm_display_mode *panel_fixed_mode;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
index = i915_vbt_sdvo_panel_type;
|
||||||
|
if (index == -1) {
|
||||||
|
struct bdb_sdvo_lvds_options *sdvo_lvds_options;
|
||||||
|
|
||||||
|
sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS);
|
||||||
|
if (!sdvo_lvds_options)
|
||||||
|
return;
|
||||||
|
|
||||||
|
index = sdvo_lvds_options->panel_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS);
|
||||||
|
if (!dvo_timing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
|
||||||
|
if (!panel_fixed_mode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fill_detail_timing_data(panel_fixed_mode, dvo_timing + index);
|
||||||
|
|
||||||
|
dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n");
|
||||||
|
drm_mode_debug_printmodeline(panel_fixed_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int intel_bios_ssc_frequency(struct drm_device *dev,
|
||||||
|
bool alternate)
|
||||||
|
{
|
||||||
|
switch (INTEL_INFO(dev)->gen) {
|
||||||
|
case 2:
|
||||||
|
return alternate ? 66 : 48;
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
return alternate ? 100 : 96;
|
||||||
|
default:
|
||||||
|
return alternate ? 100 : 120;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_general_features(struct drm_i915_private *dev_priv,
|
||||||
|
struct bdb_header *bdb)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = dev_priv->dev;
|
||||||
|
struct bdb_general_features *general;
|
||||||
|
|
||||||
|
general = find_section(bdb, BDB_GENERAL_FEATURES);
|
||||||
|
if (general) {
|
||||||
|
dev_priv->int_tv_support = general->int_tv_support;
|
||||||
|
dev_priv->int_crt_support = general->int_crt_support;
|
||||||
|
dev_priv->lvds_use_ssc = general->enable_ssc;
|
||||||
|
dev_priv->lvds_ssc_freq =
|
||||||
|
intel_bios_ssc_frequency(dev, general->ssc_freq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_general_definitions(struct drm_i915_private *dev_priv,
|
||||||
|
struct bdb_header *bdb)
|
||||||
|
{
|
||||||
|
struct bdb_general_definitions *general;
|
||||||
|
|
||||||
|
general = find_section(bdb, BDB_GENERAL_DEFINITIONS);
|
||||||
|
if (general) {
|
||||||
|
u16 block_size = get_blocksize(general);
|
||||||
|
if (block_size >= sizeof(*general)) {
|
||||||
|
int bus_pin = general->crt_ddc_gmbus_pin;
|
||||||
|
DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
|
||||||
|
if (bus_pin >= 1 && bus_pin <= 6)
|
||||||
|
dev_priv->crt_ddc_pin = bus_pin;
|
||||||
|
} else {
|
||||||
|
DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
|
||||||
|
block_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
|
||||||
|
struct bdb_header *bdb)
|
||||||
|
{
|
||||||
|
struct sdvo_device_mapping *p_mapping;
|
||||||
|
struct bdb_general_definitions *p_defs;
|
||||||
|
struct child_device_config *p_child;
|
||||||
|
int i, child_device_num, count;
|
||||||
|
u16 block_size;
|
||||||
|
|
||||||
|
p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
|
||||||
|
if (!p_defs) {
|
||||||
|
DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* judge whether the size of child device meets the requirements.
|
||||||
|
* If the child device size obtained from general definition block
|
||||||
|
* is different with sizeof(struct child_device_config), skip the
|
||||||
|
* parsing of sdvo device info
|
||||||
|
*/
|
||||||
|
if (p_defs->child_dev_size != sizeof(*p_child)) {
|
||||||
|
/* different child dev size . Ignore it */
|
||||||
|
DRM_DEBUG_KMS("different child size is found. Invalid.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* get the block size of general definitions */
|
||||||
|
block_size = get_blocksize(p_defs);
|
||||||
|
/* get the number of child device */
|
||||||
|
child_device_num = (block_size - sizeof(*p_defs)) /
|
||||||
|
sizeof(*p_child);
|
||||||
|
count = 0;
|
||||||
|
for (i = 0; i < child_device_num; i++) {
|
||||||
|
p_child = &(p_defs->devices[i]);
|
||||||
|
if (!p_child->device_type) {
|
||||||
|
/* skip the device block if device type is invalid */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (p_child->slave_addr != SLAVE_ADDR1 &&
|
||||||
|
p_child->slave_addr != SLAVE_ADDR2) {
|
||||||
|
/*
|
||||||
|
* If the slave address is neither 0x70 nor 0x72,
|
||||||
|
* it is not a SDVO device. Skip it.
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (p_child->dvo_port != DEVICE_PORT_DVOB &&
|
||||||
|
p_child->dvo_port != DEVICE_PORT_DVOC) {
|
||||||
|
/* skip the incorrect SDVO port */
|
||||||
|
DRM_DEBUG_KMS("Incorrect SDVO port. Skip it \n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on"
|
||||||
|
" %s port\n",
|
||||||
|
p_child->slave_addr,
|
||||||
|
(p_child->dvo_port == DEVICE_PORT_DVOB) ?
|
||||||
|
"SDVOB" : "SDVOC");
|
||||||
|
p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]);
|
||||||
|
if (!p_mapping->initialized) {
|
||||||
|
p_mapping->dvo_port = p_child->dvo_port;
|
||||||
|
p_mapping->slave_addr = p_child->slave_addr;
|
||||||
|
p_mapping->dvo_wiring = p_child->dvo_wiring;
|
||||||
|
p_mapping->ddc_pin = p_child->ddc_pin;
|
||||||
|
p_mapping->i2c_pin = p_child->i2c_pin;
|
||||||
|
p_mapping->i2c_speed = p_child->i2c_speed;
|
||||||
|
p_mapping->initialized = 1;
|
||||||
|
DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d, i2c_speed=%d\n",
|
||||||
|
p_mapping->dvo_port,
|
||||||
|
p_mapping->slave_addr,
|
||||||
|
p_mapping->dvo_wiring,
|
||||||
|
p_mapping->ddc_pin,
|
||||||
|
p_mapping->i2c_pin,
|
||||||
|
p_mapping->i2c_speed);
|
||||||
|
} else {
|
||||||
|
DRM_DEBUG_KMS("Maybe one SDVO port is shared by "
|
||||||
|
"two SDVO device.\n");
|
||||||
|
}
|
||||||
|
if (p_child->slave2_addr) {
|
||||||
|
/* Maybe this is a SDVO device with multiple inputs */
|
||||||
|
/* And the mapping info is not added */
|
||||||
|
DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this"
|
||||||
|
" is a SDVO device with multiple inputs.\n");
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!count) {
|
||||||
|
/* No SDVO device info is found */
|
||||||
|
DRM_DEBUG_KMS("No SDVO device info is found in VBT\n");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_driver_features(struct drm_i915_private *dev_priv,
|
||||||
|
struct bdb_header *bdb)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = dev_priv->dev;
|
||||||
|
struct bdb_driver_features *driver;
|
||||||
|
|
||||||
|
driver = find_section(bdb, BDB_DRIVER_FEATURES);
|
||||||
|
if (!driver)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (SUPPORTS_EDP(dev) &&
|
||||||
|
driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
|
||||||
|
dev_priv->edp.support = 1;
|
||||||
|
|
||||||
|
if (driver->dual_frequency)
|
||||||
|
dev_priv->render_reclock_avail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
|
||||||
|
{
|
||||||
|
struct bdb_edp *edp;
|
||||||
|
struct edp_power_seq *edp_pps;
|
||||||
|
struct edp_link_params *edp_link_params;
|
||||||
|
|
||||||
|
edp = find_section(bdb, BDB_EDP);
|
||||||
|
if (!edp) {
|
||||||
|
if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) {
|
||||||
|
DRM_DEBUG_KMS("No eDP BDB found but eDP panel "
|
||||||
|
"supported, assume %dbpp panel color "
|
||||||
|
"depth.\n",
|
||||||
|
dev_priv->edp.bpp);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ((edp->color_depth >> (panel_type * 2)) & 3) {
|
||||||
|
case EDP_18BPP:
|
||||||
|
dev_priv->edp.bpp = 18;
|
||||||
|
break;
|
||||||
|
case EDP_24BPP:
|
||||||
|
dev_priv->edp.bpp = 24;
|
||||||
|
break;
|
||||||
|
case EDP_30BPP:
|
||||||
|
dev_priv->edp.bpp = 30;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the eDP sequencing and link info */
|
||||||
|
edp_pps = &edp->power_seqs[panel_type];
|
||||||
|
edp_link_params = &edp->link_params[panel_type];
|
||||||
|
|
||||||
|
dev_priv->edp.pps = *edp_pps;
|
||||||
|
|
||||||
|
dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
|
||||||
|
DP_LINK_BW_1_62;
|
||||||
|
switch (edp_link_params->lanes) {
|
||||||
|
case 0:
|
||||||
|
dev_priv->edp.lanes = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
dev_priv->edp.lanes = 2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
default:
|
||||||
|
dev_priv->edp.lanes = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (edp_link_params->preemphasis) {
|
||||||
|
case 0:
|
||||||
|
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (edp_link_params->vswing) {
|
||||||
|
case 0:
|
||||||
|
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_device_mapping(struct drm_i915_private *dev_priv,
|
||||||
|
struct bdb_header *bdb)
|
||||||
|
{
|
||||||
|
struct bdb_general_definitions *p_defs;
|
||||||
|
struct child_device_config *p_child, *child_dev_ptr;
|
||||||
|
int i, child_device_num, count;
|
||||||
|
u16 block_size;
|
||||||
|
|
||||||
|
p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
|
||||||
|
if (!p_defs) {
|
||||||
|
DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* judge whether the size of child device meets the requirements.
|
||||||
|
* If the child device size obtained from general definition block
|
||||||
|
* is different with sizeof(struct child_device_config), skip the
|
||||||
|
* parsing of sdvo device info
|
||||||
|
*/
|
||||||
|
if (p_defs->child_dev_size != sizeof(*p_child)) {
|
||||||
|
/* different child dev size . Ignore it */
|
||||||
|
DRM_DEBUG_KMS("different child size is found. Invalid.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* get the block size of general definitions */
|
||||||
|
block_size = get_blocksize(p_defs);
|
||||||
|
/* get the number of child device */
|
||||||
|
child_device_num = (block_size - sizeof(*p_defs)) /
|
||||||
|
sizeof(*p_child);
|
||||||
|
count = 0;
|
||||||
|
/* get the number of child device that is present */
|
||||||
|
for (i = 0; i < child_device_num; i++) {
|
||||||
|
p_child = &(p_defs->devices[i]);
|
||||||
|
if (!p_child->device_type) {
|
||||||
|
/* skip the device block if device type is invalid */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if (!count) {
|
||||||
|
DRM_DEBUG_KMS("no child dev is parsed from VBT \n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dev_priv->child_dev = kzalloc(sizeof(*p_child) * count, GFP_KERNEL);
|
||||||
|
if (!dev_priv->child_dev) {
|
||||||
|
DRM_DEBUG_KMS("No memory space for child device\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_priv->child_dev_num = count;
|
||||||
|
count = 0;
|
||||||
|
for (i = 0; i < child_device_num; i++) {
|
||||||
|
p_child = &(p_defs->devices[i]);
|
||||||
|
if (!p_child->device_type) {
|
||||||
|
/* skip the device block if device type is invalid */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
child_dev_ptr = dev_priv->child_dev + count;
|
||||||
|
count++;
|
||||||
|
memcpy((void *)child_dev_ptr, (void *)p_child,
|
||||||
|
sizeof(*p_child));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_vbt_defaults(struct drm_i915_private *dev_priv)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = dev_priv->dev;
|
||||||
|
|
||||||
|
dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC;
|
||||||
|
|
||||||
|
/* LFP panel data */
|
||||||
|
dev_priv->lvds_dither = 1;
|
||||||
|
dev_priv->lvds_vbt = 0;
|
||||||
|
|
||||||
|
/* SDVO panel data */
|
||||||
|
dev_priv->sdvo_lvds_vbt_mode = NULL;
|
||||||
|
|
||||||
|
/* general features */
|
||||||
|
dev_priv->int_tv_support = 1;
|
||||||
|
dev_priv->int_crt_support = 1;
|
||||||
|
|
||||||
|
/* Default to using SSC */
|
||||||
|
dev_priv->lvds_use_ssc = 1;
|
||||||
|
dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1);
|
||||||
|
DRM_DEBUG("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq);
|
||||||
|
|
||||||
|
/* eDP data */
|
||||||
|
dev_priv->edp.bpp = 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* intel_parse_bios - find VBT and initialize settings from the BIOS
|
||||||
|
* @dev: DRM device
|
||||||
|
*
|
||||||
|
* Loads the Video BIOS and checks that the VBT exists. Sets scratch registers
|
||||||
|
* to appropriate values.
|
||||||
|
*
|
||||||
|
* Returns 0 on success, nonzero on failure.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
intel_parse_bios(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
struct pci_dev *pdev = dev->pdev;
|
||||||
|
struct bdb_header *bdb = NULL;
|
||||||
|
u8 __iomem *bios = NULL;
|
||||||
|
|
||||||
|
ENTER();
|
||||||
|
|
||||||
|
init_vbt_defaults(dev_priv);
|
||||||
|
|
||||||
|
/* XXX Should this validation be moved to intel_opregion.c? */
|
||||||
|
if (dev_priv->opregion.vbt) {
|
||||||
|
struct vbt_header *vbt = dev_priv->opregion.vbt;
|
||||||
|
if (memcmp(vbt->signature, "$VBT", 4) == 0) {
|
||||||
|
DRM_DEBUG_DRIVER("Using VBT from OpRegion: %20s\n",
|
||||||
|
vbt->signature);
|
||||||
|
bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
|
||||||
|
} else
|
||||||
|
dev_priv->opregion.vbt = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bdb == NULL) {
|
||||||
|
struct vbt_header *vbt = NULL;
|
||||||
|
size_t size;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
bios = pci_map_rom(pdev, &size);
|
||||||
|
if (!bios)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Scour memory looking for the VBT signature */
|
||||||
|
for (i = 0; i + 4 < size; i++) {
|
||||||
|
if (!memcmp(bios + i, "$VBT", 4)) {
|
||||||
|
vbt = (struct vbt_header *)(bios + i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vbt) {
|
||||||
|
DRM_ERROR("VBT signature missing\n");
|
||||||
|
pci_unmap_rom(pdev, bios);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grab useful general definitions */
|
||||||
|
parse_general_features(dev_priv, bdb);
|
||||||
|
parse_general_definitions(dev_priv, bdb);
|
||||||
|
parse_lfp_panel_data(dev_priv, bdb);
|
||||||
|
parse_sdvo_panel_data(dev_priv, bdb);
|
||||||
|
parse_sdvo_device_mapping(dev_priv, bdb);
|
||||||
|
parse_device_mapping(dev_priv, bdb);
|
||||||
|
parse_driver_features(dev_priv, bdb);
|
||||||
|
parse_edp(dev_priv, bdb);
|
||||||
|
|
||||||
|
if (bios)
|
||||||
|
pci_unmap_rom(pdev, bios);
|
||||||
|
|
||||||
|
LEAVE();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure that vital registers have been initialised, even if the BIOS
|
||||||
|
* is absent or just failing to do its job.
|
||||||
|
*/
|
||||||
|
void intel_setup_bios(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
/* Set the Panel Power On/Off timings if uninitialized. */
|
||||||
|
if ((I915_READ(PP_ON_DELAYS) == 0) && (I915_READ(PP_OFF_DELAYS) == 0)) {
|
||||||
|
/* Set T2 to 40ms and T5 to 200ms */
|
||||||
|
I915_WRITE(PP_ON_DELAYS, 0x019007d0);
|
||||||
|
|
||||||
|
/* Set T3 to 35ms and Tx to 200ms */
|
||||||
|
I915_WRITE(PP_OFF_DELAYS, 0x015e07d0);
|
||||||
|
}
|
||||||
|
}
|
611
drivers/video/drm/i915/intel_bios.h
Normal file
611
drivers/video/drm/i915/intel_bios.h
Normal file
@ -0,0 +1,611 @@
|
|||||||
|
/*
|
||||||
|
* 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 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* strictly speaking, this is a "skip" block, but it has interesting info */
|
||||||
|
struct vbios_data {
|
||||||
|
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; /* popup memory size */
|
||||||
|
u8 resize_pci_bios;
|
||||||
|
u8 rsvd5; /* is crt already on ddc2 */
|
||||||
|
} __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_EDP 27
|
||||||
|
#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 */
|
||||||
|
u8 panel_fitting:2;
|
||||||
|
u8 flexaim:1;
|
||||||
|
u8 msg_enable:1;
|
||||||
|
u8 clear_screen:3;
|
||||||
|
u8 color_flip:1;
|
||||||
|
|
||||||
|
/* bits 2 */
|
||||||
|
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 */
|
||||||
|
|
||||||
|
/* bits 3 */
|
||||||
|
u8 disable_smooth_vision:1;
|
||||||
|
u8 single_dvi:1;
|
||||||
|
u8 rsvd9:6; /* finish byte */
|
||||||
|
|
||||||
|
/* bits 4 */
|
||||||
|
u8 legacy_monitor_detect;
|
||||||
|
|
||||||
|
/* bits 5 */
|
||||||
|
u8 int_crt_support:1;
|
||||||
|
u8 int_tv_support:1;
|
||||||
|
u8 rsvd11:6; /* finish byte */
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* pre-915 */
|
||||||
|
#define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */
|
||||||
|
#define GPIO_PIN_ADD_I2C 0x05 /* "ADDCARD I2C GPIO pins" */
|
||||||
|
#define GPIO_PIN_ADD_DDC 0x04 /* "ADDCARD DDC GPIO pins" */
|
||||||
|
#define GPIO_PIN_ADD_DDC_I2C 0x06 /* "ADDCARD DDC/I2C GPIO pins" */
|
||||||
|
|
||||||
|
/* Pre 915 */
|
||||||
|
#define DEVICE_TYPE_NONE 0x00
|
||||||
|
#define DEVICE_TYPE_CRT 0x01
|
||||||
|
#define DEVICE_TYPE_TV 0x09
|
||||||
|
#define DEVICE_TYPE_EFP 0x12
|
||||||
|
#define DEVICE_TYPE_LFP 0x22
|
||||||
|
/* On 915+ */
|
||||||
|
#define DEVICE_TYPE_CRT_DPMS 0x6001
|
||||||
|
#define DEVICE_TYPE_CRT_DPMS_HOTPLUG 0x4001
|
||||||
|
#define DEVICE_TYPE_TV_COMPOSITE 0x0209
|
||||||
|
#define DEVICE_TYPE_TV_MACROVISION 0x0289
|
||||||
|
#define DEVICE_TYPE_TV_RF_COMPOSITE 0x020c
|
||||||
|
#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE 0x0609
|
||||||
|
#define DEVICE_TYPE_TV_SCART 0x0209
|
||||||
|
#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009
|
||||||
|
#define DEVICE_TYPE_EFP_HOTPLUG_PWR 0x6012
|
||||||
|
#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052
|
||||||
|
#define DEVICE_TYPE_EFP_DVI_I 0x6053
|
||||||
|
#define DEVICE_TYPE_EFP_DVI_D_DUAL 0x6152
|
||||||
|
#define DEVICE_TYPE_EFP_DVI_D_HDCP 0x60d2
|
||||||
|
#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR 0x6062
|
||||||
|
#define DEVICE_TYPE_OPENLDI_DUALPIX 0x6162
|
||||||
|
#define DEVICE_TYPE_LFP_PANELLINK 0x5012
|
||||||
|
#define DEVICE_TYPE_LFP_CMOS_PWR 0x5042
|
||||||
|
#define DEVICE_TYPE_LFP_LVDS_PWR 0x5062
|
||||||
|
#define DEVICE_TYPE_LFP_LVDS_DUAL 0x5162
|
||||||
|
#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2
|
||||||
|
|
||||||
|
#define DEVICE_CFG_NONE 0x00
|
||||||
|
#define DEVICE_CFG_12BIT_DVOB 0x01
|
||||||
|
#define DEVICE_CFG_12BIT_DVOC 0x02
|
||||||
|
#define DEVICE_CFG_24BIT_DVOBC 0x09
|
||||||
|
#define DEVICE_CFG_24BIT_DVOCB 0x0a
|
||||||
|
#define DEVICE_CFG_DUAL_DVOB 0x11
|
||||||
|
#define DEVICE_CFG_DUAL_DVOC 0x12
|
||||||
|
#define DEVICE_CFG_DUAL_DVOBC 0x13
|
||||||
|
#define DEVICE_CFG_DUAL_LINK_DVOBC 0x19
|
||||||
|
#define DEVICE_CFG_DUAL_LINK_DVOCB 0x1a
|
||||||
|
|
||||||
|
#define DEVICE_WIRE_NONE 0x00
|
||||||
|
#define DEVICE_WIRE_DVOB 0x01
|
||||||
|
#define DEVICE_WIRE_DVOC 0x02
|
||||||
|
#define DEVICE_WIRE_DVOBC 0x03
|
||||||
|
#define DEVICE_WIRE_DVOBB 0x05
|
||||||
|
#define DEVICE_WIRE_DVOCC 0x06
|
||||||
|
#define DEVICE_WIRE_DVOB_MASTER 0x0d
|
||||||
|
#define DEVICE_WIRE_DVOC_MASTER 0x0e
|
||||||
|
|
||||||
|
#define DEVICE_PORT_DVOA 0x00 /* none on 845+ */
|
||||||
|
#define DEVICE_PORT_DVOB 0x01
|
||||||
|
#define DEVICE_PORT_DVOC 0x02
|
||||||
|
|
||||||
|
struct child_device_config {
|
||||||
|
u16 handle;
|
||||||
|
u16 device_type;
|
||||||
|
u8 i2c_speed;
|
||||||
|
u8 rsvd[9];
|
||||||
|
u16 addin_offset;
|
||||||
|
u8 dvo_port; /* See Device_PORT_* above */
|
||||||
|
u8 i2c_pin;
|
||||||
|
u8 slave_addr;
|
||||||
|
u8 ddc_pin;
|
||||||
|
u16 edid_ptr;
|
||||||
|
u8 dvo_cfg; /* See DEVICE_CFG_* above */
|
||||||
|
u8 dvo2_port;
|
||||||
|
u8 i2c2_pin;
|
||||||
|
u8 slave2_addr;
|
||||||
|
u8 ddc2_pin;
|
||||||
|
u8 capabilities;
|
||||||
|
u8 dvo_wiring;/* See DEVICE_WIRE_* above */
|
||||||
|
u8 dvo2_wiring;
|
||||||
|
u16 extended_type;
|
||||||
|
u8 dvo_function;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct bdb_general_definitions {
|
||||||
|
/* DDC GPIO */
|
||||||
|
u8 crt_ddc_gmbus_pin;
|
||||||
|
|
||||||
|
/* DPMS bits */
|
||||||
|
u8 dpms_acpi:1;
|
||||||
|
u8 skip_boot_crt_detect:1;
|
||||||
|
u8 dpms_aim:1;
|
||||||
|
u8 rsvd1:5; /* finish byte */
|
||||||
|
|
||||||
|
/* boot device bits */
|
||||||
|
u8 boot_display[2];
|
||||||
|
u8 child_dev_size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device info:
|
||||||
|
* If TV is present, it'll be at devices[0].
|
||||||
|
* LVDS will be next, either devices[0] or [1], if present.
|
||||||
|
* On some platforms the number of device is 6. But could be as few as
|
||||||
|
* 4 if both TV and LVDS are missing.
|
||||||
|
* And the device num is related with the size of general definition
|
||||||
|
* block. It is obtained by using the following formula:
|
||||||
|
* number = (block_size - sizeof(bdb_general_definitions))/
|
||||||
|
* sizeof(child_device_config);
|
||||||
|
*/
|
||||||
|
struct child_device_config devices[0];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct bdb_lvds_options {
|
||||||
|
u8 panel_type;
|
||||||
|
u8 rsvd1;
|
||||||
|
/* LVDS capabilities, stored in a dword */
|
||||||
|
u8 pfit_mode:2;
|
||||||
|
u8 pfit_text_mode_enhanced:1;
|
||||||
|
u8 pfit_gfx_mode_enhanced:1;
|
||||||
|
u8 pfit_ratio_auto:1;
|
||||||
|
u8 pixel_dither:1;
|
||||||
|
u8 lvds_edid:1;
|
||||||
|
u8 rsvd2:1;
|
||||||
|
u8 rsvd4;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* LFP pointer table contains entries to the struct below */
|
||||||
|
struct bdb_lvds_lfp_data_ptr {
|
||||||
|
u16 fp_timing_offset; /* offsets are from start of bdb */
|
||||||
|
u8 fp_table_size;
|
||||||
|
u16 dvo_timing_offset;
|
||||||
|
u8 dvo_table_size;
|
||||||
|
u16 panel_pnp_id_offset;
|
||||||
|
u8 pnp_table_size;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct bdb_lvds_lfp_data_ptrs {
|
||||||
|
u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */
|
||||||
|
struct bdb_lvds_lfp_data_ptr ptr[16];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* LFP data has 3 blocks per entry */
|
||||||
|
struct lvds_fp_timing {
|
||||||
|
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_dvo_timing {
|
||||||
|
u16 clock; /**< In 10khz */
|
||||||
|
u8 hactive_lo;
|
||||||
|
u8 hblank_lo;
|
||||||
|
u8 hblank_hi:4;
|
||||||
|
u8 hactive_hi:4;
|
||||||
|
u8 vactive_lo;
|
||||||
|
u8 vblank_lo;
|
||||||
|
u8 vblank_hi:4;
|
||||||
|
u8 vactive_hi:4;
|
||||||
|
u8 hsync_off_lo;
|
||||||
|
u8 hsync_pulse_width;
|
||||||
|
u8 vsync_pulse_width:4;
|
||||||
|
u8 vsync_off:4;
|
||||||
|
u8 rsvd0:6;
|
||||||
|
u8 hsync_off_hi:2;
|
||||||
|
u8 h_image;
|
||||||
|
u8 v_image;
|
||||||
|
u8 max_hv;
|
||||||
|
u8 h_border;
|
||||||
|
u8 v_border;
|
||||||
|
u8 rsvd1:3;
|
||||||
|
u8 digital:2;
|
||||||
|
u8 vsync_positive:1;
|
||||||
|
u8 hsync_positive:1;
|
||||||
|
u8 rsvd2:1;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct lvds_pnp_id {
|
||||||
|
u16 mfg_name;
|
||||||
|
u16 product_code;
|
||||||
|
u32 serial;
|
||||||
|
u8 mfg_week;
|
||||||
|
u8 mfg_year;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct bdb_lvds_lfp_data_entry {
|
||||||
|
struct lvds_fp_timing fp_timing;
|
||||||
|
struct lvds_dvo_timing dvo_timing;
|
||||||
|
struct lvds_pnp_id pnp_id;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct bdb_lvds_lfp_data {
|
||||||
|
struct bdb_lvds_lfp_data_entry data[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));
|
||||||
|
|
||||||
|
struct bdb_sdvo_lvds_options {
|
||||||
|
u8 panel_backlight;
|
||||||
|
u8 h40_set_panel_type;
|
||||||
|
u8 panel_type;
|
||||||
|
u8 ssc_clk_freq;
|
||||||
|
u16 als_low_trip;
|
||||||
|
u16 als_high_trip;
|
||||||
|
u8 sclalarcoeff_tab_row_num;
|
||||||
|
u8 sclalarcoeff_tab_row_size;
|
||||||
|
u8 coefficient[8];
|
||||||
|
u8 panel_misc_bits_1;
|
||||||
|
u8 panel_misc_bits_2;
|
||||||
|
u8 panel_misc_bits_3;
|
||||||
|
u8 panel_misc_bits_4;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
|
||||||
|
#define BDB_DRIVER_FEATURE_NO_LVDS 0
|
||||||
|
#define BDB_DRIVER_FEATURE_INT_LVDS 1
|
||||||
|
#define BDB_DRIVER_FEATURE_SDVO_LVDS 2
|
||||||
|
#define BDB_DRIVER_FEATURE_EDP 3
|
||||||
|
|
||||||
|
struct bdb_driver_features {
|
||||||
|
u8 boot_dev_algorithm:1;
|
||||||
|
u8 block_display_switch:1;
|
||||||
|
u8 allow_display_switch:1;
|
||||||
|
u8 hotplug_dvo:1;
|
||||||
|
u8 dual_view_zoom:1;
|
||||||
|
u8 int15h_hook:1;
|
||||||
|
u8 sprite_in_clone:1;
|
||||||
|
u8 primary_lfp_id:1;
|
||||||
|
|
||||||
|
u16 boot_mode_x;
|
||||||
|
u16 boot_mode_y;
|
||||||
|
u8 boot_mode_bpp;
|
||||||
|
u8 boot_mode_refresh;
|
||||||
|
|
||||||
|
u16 enable_lfp_primary:1;
|
||||||
|
u16 selective_mode_pruning:1;
|
||||||
|
u16 dual_frequency:1;
|
||||||
|
u16 render_clock_freq:1; /* 0: high freq; 1: low freq */
|
||||||
|
u16 nt_clone_support:1;
|
||||||
|
u16 power_scheme_ui:1; /* 0: CUI; 1: 3rd party */
|
||||||
|
u16 sprite_display_assign:1; /* 0: secondary; 1: primary */
|
||||||
|
u16 cui_aspect_scaling:1;
|
||||||
|
u16 preserve_aspect_ratio:1;
|
||||||
|
u16 sdvo_device_power_down:1;
|
||||||
|
u16 crt_hotplug:1;
|
||||||
|
u16 lvds_config:2;
|
||||||
|
u16 tv_hotplug:1;
|
||||||
|
u16 hdmi_config:2;
|
||||||
|
|
||||||
|
u8 static_display:1;
|
||||||
|
u8 reserved2:7;
|
||||||
|
u16 legacy_crt_max_x;
|
||||||
|
u16 legacy_crt_max_y;
|
||||||
|
u8 legacy_crt_max_refresh;
|
||||||
|
|
||||||
|
u8 hdmi_termination;
|
||||||
|
u8 custom_vbt_version;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define EDP_18BPP 0
|
||||||
|
#define EDP_24BPP 1
|
||||||
|
#define EDP_30BPP 2
|
||||||
|
#define EDP_RATE_1_62 0
|
||||||
|
#define EDP_RATE_2_7 1
|
||||||
|
#define EDP_LANE_1 0
|
||||||
|
#define EDP_LANE_2 1
|
||||||
|
#define EDP_LANE_4 3
|
||||||
|
#define EDP_PREEMPHASIS_NONE 0
|
||||||
|
#define EDP_PREEMPHASIS_3_5dB 1
|
||||||
|
#define EDP_PREEMPHASIS_6dB 2
|
||||||
|
#define EDP_PREEMPHASIS_9_5dB 3
|
||||||
|
#define EDP_VSWING_0_4V 0
|
||||||
|
#define EDP_VSWING_0_6V 1
|
||||||
|
#define EDP_VSWING_0_8V 2
|
||||||
|
#define EDP_VSWING_1_2V 3
|
||||||
|
|
||||||
|
struct edp_power_seq {
|
||||||
|
u16 t3;
|
||||||
|
u16 t7;
|
||||||
|
u16 t9;
|
||||||
|
u16 t10;
|
||||||
|
u16 t12;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct edp_link_params {
|
||||||
|
u8 rate:4;
|
||||||
|
u8 lanes:4;
|
||||||
|
u8 preemphasis:4;
|
||||||
|
u8 vswing:4;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct bdb_edp {
|
||||||
|
struct edp_power_seq power_seqs[16];
|
||||||
|
u32 color_depth;
|
||||||
|
u32 sdrrs_msa_timing_delay;
|
||||||
|
struct edp_link_params link_params[16];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
void intel_setup_bios(struct drm_device *dev);
|
||||||
|
bool intel_parse_bios(struct drm_device *dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver<->VBIOS interaction occurs through scratch bits in
|
||||||
|
* GR18 & SWF*.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* GR18 bits are set on display switch and hotkey events */
|
||||||
|
#define GR18_DRIVER_SWITCH_EN (1<<7) /* 0: VBIOS control, 1: driver control */
|
||||||
|
#define GR18_HOTKEY_MASK 0x78 /* See also SWF4 15:0 */
|
||||||
|
#define GR18_HK_NONE (0x0<<3)
|
||||||
|
#define GR18_HK_LFP_STRETCH (0x1<<3)
|
||||||
|
#define GR18_HK_TOGGLE_DISP (0x2<<3)
|
||||||
|
#define GR18_HK_DISP_SWITCH (0x4<<3) /* see SWF14 15:0 for what to enable */
|
||||||
|
#define GR18_HK_POPUP_DISABLED (0x6<<3)
|
||||||
|
#define GR18_HK_POPUP_ENABLED (0x7<<3)
|
||||||
|
#define GR18_HK_PFIT (0x8<<3)
|
||||||
|
#define GR18_HK_APM_CHANGE (0xa<<3)
|
||||||
|
#define GR18_HK_MULTIPLE (0xc<<3)
|
||||||
|
#define GR18_USER_INT_EN (1<<2)
|
||||||
|
#define GR18_A0000_FLUSH_EN (1<<1)
|
||||||
|
#define GR18_SMM_EN (1<<0)
|
||||||
|
|
||||||
|
/* Set by driver, cleared by VBIOS */
|
||||||
|
#define SWF00_YRES_SHIFT 16
|
||||||
|
#define SWF00_XRES_SHIFT 0
|
||||||
|
#define SWF00_RES_MASK 0xffff
|
||||||
|
|
||||||
|
/* Set by VBIOS at boot time and driver at runtime */
|
||||||
|
#define SWF01_TV2_FORMAT_SHIFT 8
|
||||||
|
#define SWF01_TV1_FORMAT_SHIFT 0
|
||||||
|
#define SWF01_TV_FORMAT_MASK 0xffff
|
||||||
|
|
||||||
|
#define SWF10_VBIOS_BLC_I2C_EN (1<<29)
|
||||||
|
#define SWF10_GTT_OVERRIDE_EN (1<<28)
|
||||||
|
#define SWF10_LFP_DPMS_OVR (1<<27) /* override DPMS on display switch */
|
||||||
|
#define SWF10_ACTIVE_TOGGLE_LIST_MASK (7<<24)
|
||||||
|
#define SWF10_OLD_TOGGLE 0x0
|
||||||
|
#define SWF10_TOGGLE_LIST_1 0x1
|
||||||
|
#define SWF10_TOGGLE_LIST_2 0x2
|
||||||
|
#define SWF10_TOGGLE_LIST_3 0x3
|
||||||
|
#define SWF10_TOGGLE_LIST_4 0x4
|
||||||
|
#define SWF10_PANNING_EN (1<<23)
|
||||||
|
#define SWF10_DRIVER_LOADED (1<<22)
|
||||||
|
#define SWF10_EXTENDED_DESKTOP (1<<21)
|
||||||
|
#define SWF10_EXCLUSIVE_MODE (1<<20)
|
||||||
|
#define SWF10_OVERLAY_EN (1<<19)
|
||||||
|
#define SWF10_PLANEB_HOLDOFF (1<<18)
|
||||||
|
#define SWF10_PLANEA_HOLDOFF (1<<17)
|
||||||
|
#define SWF10_VGA_HOLDOFF (1<<16)
|
||||||
|
#define SWF10_ACTIVE_DISP_MASK 0xffff
|
||||||
|
#define SWF10_PIPEB_LFP2 (1<<15)
|
||||||
|
#define SWF10_PIPEB_EFP2 (1<<14)
|
||||||
|
#define SWF10_PIPEB_TV2 (1<<13)
|
||||||
|
#define SWF10_PIPEB_CRT2 (1<<12)
|
||||||
|
#define SWF10_PIPEB_LFP (1<<11)
|
||||||
|
#define SWF10_PIPEB_EFP (1<<10)
|
||||||
|
#define SWF10_PIPEB_TV (1<<9)
|
||||||
|
#define SWF10_PIPEB_CRT (1<<8)
|
||||||
|
#define SWF10_PIPEA_LFP2 (1<<7)
|
||||||
|
#define SWF10_PIPEA_EFP2 (1<<6)
|
||||||
|
#define SWF10_PIPEA_TV2 (1<<5)
|
||||||
|
#define SWF10_PIPEA_CRT2 (1<<4)
|
||||||
|
#define SWF10_PIPEA_LFP (1<<3)
|
||||||
|
#define SWF10_PIPEA_EFP (1<<2)
|
||||||
|
#define SWF10_PIPEA_TV (1<<1)
|
||||||
|
#define SWF10_PIPEA_CRT (1<<0)
|
||||||
|
|
||||||
|
#define SWF11_MEMORY_SIZE_SHIFT 16
|
||||||
|
#define SWF11_SV_TEST_EN (1<<15)
|
||||||
|
#define SWF11_IS_AGP (1<<14)
|
||||||
|
#define SWF11_DISPLAY_HOLDOFF (1<<13)
|
||||||
|
#define SWF11_DPMS_REDUCED (1<<12)
|
||||||
|
#define SWF11_IS_VBE_MODE (1<<11)
|
||||||
|
#define SWF11_PIPEB_ACCESS (1<<10) /* 0 here means pipe a */
|
||||||
|
#define SWF11_DPMS_MASK 0x07
|
||||||
|
#define SWF11_DPMS_OFF (1<<2)
|
||||||
|
#define SWF11_DPMS_SUSPEND (1<<1)
|
||||||
|
#define SWF11_DPMS_STANDBY (1<<0)
|
||||||
|
#define SWF11_DPMS_ON 0
|
||||||
|
|
||||||
|
#define SWF14_GFX_PFIT_EN (1<<31)
|
||||||
|
#define SWF14_TEXT_PFIT_EN (1<<30)
|
||||||
|
#define SWF14_LID_STATUS_CLOSED (1<<29) /* 0 here means open */
|
||||||
|
#define SWF14_POPUP_EN (1<<28)
|
||||||
|
#define SWF14_DISPLAY_HOLDOFF (1<<27)
|
||||||
|
#define SWF14_DISP_DETECT_EN (1<<26)
|
||||||
|
#define SWF14_DOCKING_STATUS_DOCKED (1<<25) /* 0 here means undocked */
|
||||||
|
#define SWF14_DRIVER_STATUS (1<<24)
|
||||||
|
#define SWF14_OS_TYPE_WIN9X (1<<23)
|
||||||
|
#define SWF14_OS_TYPE_WINNT (1<<22)
|
||||||
|
/* 21:19 rsvd */
|
||||||
|
#define SWF14_PM_TYPE_MASK 0x00070000
|
||||||
|
#define SWF14_PM_ACPI_VIDEO (0x4 << 16)
|
||||||
|
#define SWF14_PM_ACPI (0x3 << 16)
|
||||||
|
#define SWF14_PM_APM_12 (0x2 << 16)
|
||||||
|
#define SWF14_PM_APM_11 (0x1 << 16)
|
||||||
|
#define SWF14_HK_REQUEST_MASK 0x0000ffff /* see GR18 6:3 for event type */
|
||||||
|
/* if GR18 indicates a display switch */
|
||||||
|
#define SWF14_DS_PIPEB_LFP2_EN (1<<15)
|
||||||
|
#define SWF14_DS_PIPEB_EFP2_EN (1<<14)
|
||||||
|
#define SWF14_DS_PIPEB_TV2_EN (1<<13)
|
||||||
|
#define SWF14_DS_PIPEB_CRT2_EN (1<<12)
|
||||||
|
#define SWF14_DS_PIPEB_LFP_EN (1<<11)
|
||||||
|
#define SWF14_DS_PIPEB_EFP_EN (1<<10)
|
||||||
|
#define SWF14_DS_PIPEB_TV_EN (1<<9)
|
||||||
|
#define SWF14_DS_PIPEB_CRT_EN (1<<8)
|
||||||
|
#define SWF14_DS_PIPEA_LFP2_EN (1<<7)
|
||||||
|
#define SWF14_DS_PIPEA_EFP2_EN (1<<6)
|
||||||
|
#define SWF14_DS_PIPEA_TV2_EN (1<<5)
|
||||||
|
#define SWF14_DS_PIPEA_CRT2_EN (1<<4)
|
||||||
|
#define SWF14_DS_PIPEA_LFP_EN (1<<3)
|
||||||
|
#define SWF14_DS_PIPEA_EFP_EN (1<<2)
|
||||||
|
#define SWF14_DS_PIPEA_TV_EN (1<<1)
|
||||||
|
#define SWF14_DS_PIPEA_CRT_EN (1<<0)
|
||||||
|
/* if GR18 indicates a panel fitting request */
|
||||||
|
#define SWF14_PFIT_EN (1<<0) /* 0 means disable */
|
||||||
|
/* if GR18 indicates an APM change request */
|
||||||
|
#define SWF14_APM_HIBERNATE 0x4
|
||||||
|
#define SWF14_APM_SUSPEND 0x3
|
||||||
|
#define SWF14_APM_STANDBY 0x1
|
||||||
|
#define SWF14_APM_RESTORE 0x0
|
||||||
|
|
||||||
|
/* Add the device class for LFP, TV, HDMI */
|
||||||
|
#define DEVICE_TYPE_INT_LFP 0x1022
|
||||||
|
#define DEVICE_TYPE_INT_TV 0x1009
|
||||||
|
#define DEVICE_TYPE_HDMI 0x60D2
|
||||||
|
#define DEVICE_TYPE_DP 0x68C6
|
||||||
|
#define DEVICE_TYPE_eDP 0x78C6
|
||||||
|
|
||||||
|
/* define the DVO port for HDMI output type */
|
||||||
|
#define DVO_B 1
|
||||||
|
#define DVO_C 2
|
||||||
|
#define DVO_D 3
|
||||||
|
|
||||||
|
/* define the PORT for DP output type */
|
||||||
|
#define PORT_IDPB 7
|
||||||
|
#define PORT_IDPC 8
|
||||||
|
#define PORT_IDPD 9
|
||||||
|
|
||||||
|
#endif /* _I830_BIOS_H_ */
|
6425
drivers/video/drm/i915/intel_display.c
Normal file
6425
drivers/video/drm/i915/intel_display.c
Normal file
File diff suppressed because it is too large
Load Diff
300
drivers/video/drm/i915/intel_dp.c
Normal file
300
drivers/video/drm/i915/intel_dp.c
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2008 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:
|
||||||
|
* Keith Packard <keithp@keithp.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
//#include <linux/slab.h>
|
||||||
|
#include "drmP.h"
|
||||||
|
#include "drm.h"
|
||||||
|
#include "drm_crtc.h"
|
||||||
|
#include "drm_crtc_helper.h"
|
||||||
|
#include "intel_drv.h"
|
||||||
|
//#include "i915_drm.h"
|
||||||
|
#include "i915_drv.h"
|
||||||
|
#include "drm_dp_helper.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define DP_LINK_STATUS_SIZE 6
|
||||||
|
#define DP_LINK_CHECK_TIMEOUT (10 * 1000)
|
||||||
|
|
||||||
|
#define DP_LINK_CONFIGURATION_SIZE 9
|
||||||
|
|
||||||
|
struct intel_dp {
|
||||||
|
struct intel_encoder base;
|
||||||
|
uint32_t output_reg;
|
||||||
|
uint32_t DP;
|
||||||
|
uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE];
|
||||||
|
bool has_audio;
|
||||||
|
int force_audio;
|
||||||
|
uint32_t color_range;
|
||||||
|
int dpms_mode;
|
||||||
|
uint8_t link_bw;
|
||||||
|
uint8_t lane_count;
|
||||||
|
uint8_t dpcd[8];
|
||||||
|
struct i2c_adapter adapter;
|
||||||
|
struct i2c_algo_dp_aux_data algo;
|
||||||
|
bool is_pch_edp;
|
||||||
|
uint8_t train_set[4];
|
||||||
|
uint8_t link_status[DP_LINK_STATUS_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is_edp - is the given port attached to an eDP panel (either CPU or PCH)
|
||||||
|
* @intel_dp: DP struct
|
||||||
|
*
|
||||||
|
* If a CPU or PCH DP output is attached to an eDP panel, this function
|
||||||
|
* will return true, and false otherwise.
|
||||||
|
*/
|
||||||
|
static bool is_edp(struct intel_dp *intel_dp)
|
||||||
|
{
|
||||||
|
return intel_dp->base.type == INTEL_OUTPUT_EDP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is_pch_edp - is the port on the PCH and attached to an eDP panel?
|
||||||
|
* @intel_dp: DP struct
|
||||||
|
*
|
||||||
|
* Returns true if the given DP struct corresponds to a PCH DP port attached
|
||||||
|
* to an eDP panel, false otherwise. Helpful for determining whether we
|
||||||
|
* may need FDI resources for a given DP output or not.
|
||||||
|
*/
|
||||||
|
static bool is_pch_edp(struct intel_dp *intel_dp)
|
||||||
|
{
|
||||||
|
return intel_dp->is_pch_edp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
|
||||||
|
{
|
||||||
|
return container_of(encoder, struct intel_dp, base.base);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* intel_encoder_is_pch_edp - is the given encoder a PCH attached eDP?
|
||||||
|
* @encoder: DRM encoder
|
||||||
|
*
|
||||||
|
* Return true if @encoder corresponds to a PCH attached eDP panel. Needed
|
||||||
|
* by intel_display.c.
|
||||||
|
*/
|
||||||
|
bool intel_encoder_is_pch_edp(struct drm_encoder *encoder)
|
||||||
|
{
|
||||||
|
struct intel_dp *intel_dp;
|
||||||
|
|
||||||
|
if (!encoder)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
intel_dp = enc_to_intel_dp(encoder);
|
||||||
|
|
||||||
|
return is_pch_edp(intel_dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
intel_edp_link_config (struct intel_encoder *intel_encoder,
|
||||||
|
int *lane_num, int *link_bw)
|
||||||
|
{
|
||||||
|
struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base);
|
||||||
|
|
||||||
|
*lane_num = intel_dp->lane_count;
|
||||||
|
if (intel_dp->link_bw == DP_LINK_BW_1_62)
|
||||||
|
*link_bw = 162000;
|
||||||
|
else if (intel_dp->link_bw == DP_LINK_BW_2_7)
|
||||||
|
*link_bw = 270000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct intel_dp_m_n {
|
||||||
|
uint32_t tu;
|
||||||
|
uint32_t gmch_m;
|
||||||
|
uint32_t gmch_n;
|
||||||
|
uint32_t link_m;
|
||||||
|
uint32_t link_n;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
intel_reduce_ratio(uint32_t *num, uint32_t *den)
|
||||||
|
{
|
||||||
|
while (*num > 0xffffff || *den > 0xffffff) {
|
||||||
|
*num >>= 1;
|
||||||
|
*den >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
intel_dp_compute_m_n(int bpp,
|
||||||
|
int nlanes,
|
||||||
|
int pixel_clock,
|
||||||
|
int link_clock,
|
||||||
|
struct intel_dp_m_n *m_n)
|
||||||
|
{
|
||||||
|
m_n->tu = 64;
|
||||||
|
m_n->gmch_m = (pixel_clock * bpp) >> 3;
|
||||||
|
m_n->gmch_n = link_clock * nlanes;
|
||||||
|
intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
|
||||||
|
m_n->link_m = pixel_clock;
|
||||||
|
m_n->link_n = link_clock;
|
||||||
|
intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
||||||
|
struct drm_display_mode *adjusted_mode)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = crtc->dev;
|
||||||
|
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||||
|
struct drm_encoder *encoder;
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||||
|
int lane_count = 4;
|
||||||
|
struct intel_dp_m_n m_n;
|
||||||
|
int pipe = intel_crtc->pipe;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the lane count in the intel_encoder private
|
||||||
|
*/
|
||||||
|
list_for_each_entry(encoder, &mode_config->encoder_list, head) {
|
||||||
|
struct intel_dp *intel_dp;
|
||||||
|
|
||||||
|
if (encoder->crtc != crtc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
intel_dp = enc_to_intel_dp(encoder);
|
||||||
|
if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) {
|
||||||
|
lane_count = intel_dp->lane_count;
|
||||||
|
break;
|
||||||
|
} else if (is_edp(intel_dp)) {
|
||||||
|
lane_count = dev_priv->edp.lanes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the GMCH and Link ratios. The '3' here is
|
||||||
|
* the number of bytes_per_pixel post-LUT, which we always
|
||||||
|
* set up for 8-bits of R/G/B, or 3 bytes total.
|
||||||
|
*/
|
||||||
|
intel_dp_compute_m_n(intel_crtc->bpp, lane_count,
|
||||||
|
mode->clock, adjusted_mode->clock, &m_n);
|
||||||
|
|
||||||
|
if (HAS_PCH_SPLIT(dev)) {
|
||||||
|
I915_WRITE(TRANSDATA_M1(pipe),
|
||||||
|
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
|
||||||
|
m_n.gmch_m);
|
||||||
|
I915_WRITE(TRANSDATA_N1(pipe), m_n.gmch_n);
|
||||||
|
I915_WRITE(TRANSDPLINK_M1(pipe), m_n.link_m);
|
||||||
|
I915_WRITE(TRANSDPLINK_N1(pipe), m_n.link_n);
|
||||||
|
} else {
|
||||||
|
I915_WRITE(PIPE_GMCH_DATA_M(pipe),
|
||||||
|
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
|
||||||
|
m_n.gmch_m);
|
||||||
|
I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n.gmch_n);
|
||||||
|
I915_WRITE(PIPE_DP_LINK_M(pipe), m_n.link_m);
|
||||||
|
I915_WRITE(PIPE_DP_LINK_N(pipe), m_n.link_n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Return which DP Port should be selected for Transcoder DP control */
|
||||||
|
int
|
||||||
|
intel_trans_dp_port_sel (struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = crtc->dev;
|
||||||
|
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||||
|
struct drm_encoder *encoder;
|
||||||
|
|
||||||
|
list_for_each_entry(encoder, &mode_config->encoder_list, head) {
|
||||||
|
struct intel_dp *intel_dp;
|
||||||
|
|
||||||
|
if (encoder->crtc != crtc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
intel_dp = enc_to_intel_dp(encoder);
|
||||||
|
if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT)
|
||||||
|
return intel_dp->output_reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
@ -289,7 +289,7 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
|
|||||||
GPIOF,
|
GPIOF,
|
||||||
};
|
};
|
||||||
struct intel_gpio *gpio;
|
struct intel_gpio *gpio;
|
||||||
ENTER();
|
|
||||||
if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin])
|
if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin])
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -317,7 +317,7 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
|
|||||||
|
|
||||||
if (i2c_bit_add_bus(&gpio->adapter))
|
if (i2c_bit_add_bus(&gpio->adapter))
|
||||||
goto out_free;
|
goto out_free;
|
||||||
LEAVE();
|
|
||||||
return &gpio->adapter;
|
return &gpio->adapter;
|
||||||
|
|
||||||
out_free:
|
out_free:
|
||||||
@ -502,7 +502,7 @@ int intel_setup_gmbus(struct drm_device *dev)
|
|||||||
};
|
};
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
ENTER();
|
|
||||||
dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
|
dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (dev_priv->gmbus == NULL)
|
if (dev_priv->gmbus == NULL)
|
||||||
@ -534,7 +534,7 @@ int intel_setup_gmbus(struct drm_device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
intel_i2c_reset(dev_priv->dev);
|
intel_i2c_reset(dev_priv->dev);
|
||||||
LEAVE();
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
209
drivers/video/drm/i915/intel_opregion.c
Normal file
209
drivers/video/drm/i915/intel_opregion.c
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008 Intel Corporation <hong.liu@intel.com>
|
||||||
|
* Copyright 2008 Red Hat <mjg@redhat.com>
|
||||||
|
*
|
||||||
|
* 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, sub license, 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
|
||||||
|
* NON-INFRINGEMENT. IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#include <linux/acpi.h>
|
||||||
|
//#include <linux/acpi_io.h>
|
||||||
|
//#include <acpi/video.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include "drmP.h"
|
||||||
|
//#include "i915_drm.h"
|
||||||
|
#include "i915_drv.h"
|
||||||
|
#include "intel_drv.h"
|
||||||
|
|
||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
#define PCI_ASLE 0xe4
|
||||||
|
#define PCI_ASLS 0xfc
|
||||||
|
|
||||||
|
#define OPREGION_HEADER_OFFSET 0
|
||||||
|
#define OPREGION_ACPI_OFFSET 0x100
|
||||||
|
#define ACPI_CLID 0x01ac /* current lid state indicator */
|
||||||
|
#define ACPI_CDCK 0x01b0 /* current docking state indicator */
|
||||||
|
#define OPREGION_SWSCI_OFFSET 0x200
|
||||||
|
#define OPREGION_ASLE_OFFSET 0x300
|
||||||
|
#define OPREGION_VBT_OFFSET 0x400
|
||||||
|
|
||||||
|
#define OPREGION_SIGNATURE "IntelGraphicsMem"
|
||||||
|
#define MBOX_ACPI (1<<0)
|
||||||
|
#define MBOX_SWSCI (1<<1)
|
||||||
|
#define MBOX_ASLE (1<<2)
|
||||||
|
|
||||||
|
struct opregion_header {
|
||||||
|
u8 signature[16];
|
||||||
|
u32 size;
|
||||||
|
u32 opregion_ver;
|
||||||
|
u8 bios_ver[32];
|
||||||
|
u8 vbios_ver[16];
|
||||||
|
u8 driver_ver[16];
|
||||||
|
u32 mboxes;
|
||||||
|
u8 reserved[164];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* OpRegion mailbox #1: public ACPI methods */
|
||||||
|
struct opregion_acpi {
|
||||||
|
u32 drdy; /* driver readiness */
|
||||||
|
u32 csts; /* notification status */
|
||||||
|
u32 cevt; /* current event */
|
||||||
|
u8 rsvd1[20];
|
||||||
|
u32 didl[8]; /* supported display devices ID list */
|
||||||
|
u32 cpdl[8]; /* currently presented display list */
|
||||||
|
u32 cadl[8]; /* currently active display list */
|
||||||
|
u32 nadl[8]; /* next active devices list */
|
||||||
|
u32 aslp; /* ASL sleep time-out */
|
||||||
|
u32 tidx; /* toggle table index */
|
||||||
|
u32 chpd; /* current hotplug enable indicator */
|
||||||
|
u32 clid; /* current lid state*/
|
||||||
|
u32 cdck; /* current docking state */
|
||||||
|
u32 sxsw; /* Sx state resume */
|
||||||
|
u32 evts; /* ASL supported events */
|
||||||
|
u32 cnot; /* current OS notification */
|
||||||
|
u32 nrdy; /* driver status */
|
||||||
|
u8 rsvd2[60];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* OpRegion mailbox #2: SWSCI */
|
||||||
|
struct opregion_swsci {
|
||||||
|
u32 scic; /* SWSCI command|status|data */
|
||||||
|
u32 parm; /* command parameters */
|
||||||
|
u32 dslp; /* driver sleep time-out */
|
||||||
|
u8 rsvd[244];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* OpRegion mailbox #3: ASLE */
|
||||||
|
struct opregion_asle {
|
||||||
|
u32 ardy; /* driver readiness */
|
||||||
|
u32 aslc; /* ASLE interrupt command */
|
||||||
|
u32 tche; /* technology enabled indicator */
|
||||||
|
u32 alsi; /* current ALS illuminance reading */
|
||||||
|
u32 bclp; /* backlight brightness to set */
|
||||||
|
u32 pfit; /* panel fitting state */
|
||||||
|
u32 cblv; /* current brightness level */
|
||||||
|
u16 bclm[20]; /* backlight level duty cycle mapping table */
|
||||||
|
u32 cpfm; /* current panel fitting mode */
|
||||||
|
u32 epfm; /* enabled panel fitting modes */
|
||||||
|
u8 plut[74]; /* panel LUT and identifier */
|
||||||
|
u32 pfmb; /* PWM freq and min brightness */
|
||||||
|
u8 rsvd[102];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* ASLE irq request bits */
|
||||||
|
#define ASLE_SET_ALS_ILLUM (1 << 0)
|
||||||
|
#define ASLE_SET_BACKLIGHT (1 << 1)
|
||||||
|
#define ASLE_SET_PFIT (1 << 2)
|
||||||
|
#define ASLE_SET_PWM_FREQ (1 << 3)
|
||||||
|
#define ASLE_REQ_MSK 0xf
|
||||||
|
|
||||||
|
/* response bits of ASLE irq request */
|
||||||
|
#define ASLE_ALS_ILLUM_FAILED (1<<10)
|
||||||
|
#define ASLE_BACKLIGHT_FAILED (1<<12)
|
||||||
|
#define ASLE_PFIT_FAILED (1<<14)
|
||||||
|
#define ASLE_PWM_FREQ_FAILED (1<<16)
|
||||||
|
|
||||||
|
/* ASLE backlight brightness to set */
|
||||||
|
#define ASLE_BCLP_VALID (1<<31)
|
||||||
|
#define ASLE_BCLP_MSK (~(1<<31))
|
||||||
|
|
||||||
|
/* ASLE panel fitting request */
|
||||||
|
#define ASLE_PFIT_VALID (1<<31)
|
||||||
|
#define ASLE_PFIT_CENTER (1<<0)
|
||||||
|
#define ASLE_PFIT_STRETCH_TEXT (1<<1)
|
||||||
|
#define ASLE_PFIT_STRETCH_GFX (1<<2)
|
||||||
|
|
||||||
|
/* PWM frequency and minimum brightness */
|
||||||
|
#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
|
||||||
|
#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
|
||||||
|
#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
|
||||||
|
#define ASLE_PFMB_PWM_VALID (1<<31)
|
||||||
|
|
||||||
|
#define ASLE_CBLV_VALID (1<<31)
|
||||||
|
|
||||||
|
#define ACPI_OTHER_OUTPUT (0<<8)
|
||||||
|
#define ACPI_VGA_OUTPUT (1<<8)
|
||||||
|
#define ACPI_TV_OUTPUT (2<<8)
|
||||||
|
#define ACPI_DIGITAL_OUTPUT (3<<8)
|
||||||
|
#define ACPI_LVDS_OUTPUT (4<<8)
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int pci_read_config_dword(struct pci_dev *dev, int where,
|
||||||
|
u32 *val)
|
||||||
|
{
|
||||||
|
*val = PciRead32(dev->busnr, dev->devfn, where);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int intel_opregion_setup(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
struct intel_opregion *opregion = &dev_priv->opregion;
|
||||||
|
void *base;
|
||||||
|
u32 asls, mboxes;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
|
||||||
|
DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls);
|
||||||
|
if (asls == 0) {
|
||||||
|
DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n");
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
base = ioremap(asls, OPREGION_SIZE);
|
||||||
|
if (!base)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (memcmp(base, OPREGION_SIGNATURE, 16)) {
|
||||||
|
DRM_DEBUG_DRIVER("opregion signature mismatch\n");
|
||||||
|
err = -EINVAL;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
opregion->header = base;
|
||||||
|
opregion->vbt = base + OPREGION_VBT_OFFSET;
|
||||||
|
|
||||||
|
opregion->lid_state = base + ACPI_CLID;
|
||||||
|
|
||||||
|
mboxes = opregion->header->mboxes;
|
||||||
|
if (mboxes & MBOX_ACPI) {
|
||||||
|
DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
|
||||||
|
opregion->acpi = base + OPREGION_ACPI_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mboxes & MBOX_SWSCI) {
|
||||||
|
DRM_DEBUG_DRIVER("SWSCI supported\n");
|
||||||
|
opregion->swsci = base + OPREGION_SWSCI_OFFSET;
|
||||||
|
}
|
||||||
|
if (mboxes & MBOX_ASLE) {
|
||||||
|
DRM_DEBUG_DRIVER("ASLE supported\n");
|
||||||
|
opregion->asle = base + OPREGION_ASLE_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
iounmap(base);
|
||||||
|
return err;
|
||||||
|
}
|
@ -663,3 +663,184 @@ void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
|
|||||||
IO_COND(addr, /* nothing */, iounmap(addr));
|
IO_COND(addr, /* nothing */, iounmap(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct pci_bus_region {
|
||||||
|
resource_size_t start;
|
||||||
|
resource_size_t end;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
|
||||||
|
struct resource *res)
|
||||||
|
{
|
||||||
|
region->start = res->start;
|
||||||
|
region->end = res->end;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int pci_read_config_dword(struct pci_dev *dev, int where,
|
||||||
|
u32 *val)
|
||||||
|
{
|
||||||
|
*val = PciRead32(dev->busnr, dev->devfn, where);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int pci_write_config_dword(struct pci_dev *dev, int where,
|
||||||
|
u32 val)
|
||||||
|
{
|
||||||
|
PciWrite32(dev->busnr, dev->devfn, where, val);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pci_enable_rom(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
struct resource *res = pdev->resource + PCI_ROM_RESOURCE;
|
||||||
|
struct pci_bus_region region;
|
||||||
|
u32 rom_addr;
|
||||||
|
|
||||||
|
if (!res->flags)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pcibios_resource_to_bus(pdev, ®ion, res);
|
||||||
|
pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
|
||||||
|
rom_addr &= ~PCI_ROM_ADDRESS_MASK;
|
||||||
|
rom_addr |= region.start | PCI_ROM_ADDRESS_ENABLE;
|
||||||
|
pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pci_disable_rom(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
u32 rom_addr;
|
||||||
|
pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
|
||||||
|
rom_addr &= ~PCI_ROM_ADDRESS_ENABLE;
|
||||||
|
pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_get_rom_size - obtain the actual size of the ROM image
|
||||||
|
* @pdev: target PCI device
|
||||||
|
* @rom: kernel virtual pointer to image of ROM
|
||||||
|
* @size: size of PCI window
|
||||||
|
* return: size of actual ROM image
|
||||||
|
*
|
||||||
|
* Determine the actual length of the ROM image.
|
||||||
|
* The PCI window size could be much larger than the
|
||||||
|
* actual image size.
|
||||||
|
*/
|
||||||
|
size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size)
|
||||||
|
{
|
||||||
|
void __iomem *image;
|
||||||
|
int last_image;
|
||||||
|
|
||||||
|
image = rom;
|
||||||
|
do {
|
||||||
|
void __iomem *pds;
|
||||||
|
/* Standard PCI ROMs start out with these bytes 55 AA */
|
||||||
|
if (readb(image) != 0x55) {
|
||||||
|
dev_err(&pdev->dev, "Invalid ROM contents\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (readb(image + 1) != 0xAA)
|
||||||
|
break;
|
||||||
|
/* get the PCI data structure and check its signature */
|
||||||
|
pds = image + readw(image + 24);
|
||||||
|
if (readb(pds) != 'P')
|
||||||
|
break;
|
||||||
|
if (readb(pds + 1) != 'C')
|
||||||
|
break;
|
||||||
|
if (readb(pds + 2) != 'I')
|
||||||
|
break;
|
||||||
|
if (readb(pds + 3) != 'R')
|
||||||
|
break;
|
||||||
|
last_image = readb(pds + 21) & 0x80;
|
||||||
|
/* this length is reliable */
|
||||||
|
image += readw(pds + 16) * 512;
|
||||||
|
} while (!last_image);
|
||||||
|
|
||||||
|
/* never return a size larger than the PCI resource window */
|
||||||
|
/* there are known ROMs that get the size wrong */
|
||||||
|
return min((size_t)(image - rom), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_map_rom - map a PCI ROM to kernel space
|
||||||
|
* @pdev: pointer to pci device struct
|
||||||
|
* @size: pointer to receive size of pci window over ROM
|
||||||
|
*
|
||||||
|
* Return: kernel virtual pointer to image of ROM
|
||||||
|
*
|
||||||
|
* Map a PCI ROM into kernel space. If ROM is boot video ROM,
|
||||||
|
* the shadow BIOS copy will be returned instead of the
|
||||||
|
* actual ROM.
|
||||||
|
*/
|
||||||
|
void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
|
||||||
|
{
|
||||||
|
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
|
||||||
|
loff_t start;
|
||||||
|
void __iomem *rom;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy
|
||||||
|
* memory map if the VGA enable bit of the Bridge Control register is
|
||||||
|
* set for embedded VGA.
|
||||||
|
*/
|
||||||
|
if (res->flags & IORESOURCE_ROM_SHADOW) {
|
||||||
|
/* primary video rom always starts here */
|
||||||
|
start = (loff_t)0xC0000;
|
||||||
|
*size = 0x20000; /* cover C000:0 through E000:0 */
|
||||||
|
} else {
|
||||||
|
if (res->flags &
|
||||||
|
(IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) {
|
||||||
|
*size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
|
||||||
|
return (void __iomem *)(unsigned long)
|
||||||
|
pci_resource_start(pdev, PCI_ROM_RESOURCE);
|
||||||
|
} else {
|
||||||
|
/* assign the ROM an address if it doesn't have one */
|
||||||
|
// if (res->parent == NULL &&
|
||||||
|
// pci_assign_resource(pdev,PCI_ROM_RESOURCE))
|
||||||
|
return NULL;
|
||||||
|
// start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
|
||||||
|
// *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
|
||||||
|
// if (*size == 0)
|
||||||
|
// return NULL;
|
||||||
|
|
||||||
|
/* Enable ROM space decodes */
|
||||||
|
// if (pci_enable_rom(pdev))
|
||||||
|
// return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rom = ioremap(start, *size);
|
||||||
|
if (!rom) {
|
||||||
|
/* restore enable if ioremap fails */
|
||||||
|
if (!(res->flags & (IORESOURCE_ROM_ENABLE |
|
||||||
|
IORESOURCE_ROM_SHADOW |
|
||||||
|
IORESOURCE_ROM_COPY)))
|
||||||
|
pci_disable_rom(pdev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to find the true size of the ROM since sometimes the PCI window
|
||||||
|
* size is much larger than the actual size of the ROM.
|
||||||
|
* True size is important if the ROM is going to be copied.
|
||||||
|
*/
|
||||||
|
*size = pci_get_rom_size(pdev, rom, *size);
|
||||||
|
return rom;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
|
||||||
|
{
|
||||||
|
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
|
||||||
|
|
||||||
|
if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY))
|
||||||
|
return;
|
||||||
|
|
||||||
|
iounmap(rom);
|
||||||
|
|
||||||
|
/* Disable again before continuing, leave enabled if pci=rom */
|
||||||
|
if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW)))
|
||||||
|
pci_disable_rom(pdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user