aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_bios.c
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2008-11-07 17:24:08 -0500
committerDave Airlie <airlied@linux.ie>2008-12-29 02:47:23 -0500
commit79e539453b34e35f39299a899d263b0a1f1670bd (patch)
tree6d1285f2b78fab399aab75a3557b7d6bc0dbd112 /drivers/gpu/drm/i915/intel_bios.c
parentf453ba0460742ad027ae0c4c7d61e62817b3e7ef (diff)
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs. Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are supported. HDMI, DisplayPort and additional SDVO output support will follow. Support for the mode setting code is controlled by the new 'modeset' module option. A new config option, CONFIG_DRM_I915_KMS controls the default behavior, and whether a PCI ID list is built into the module for use by user level module utilities. Note that if mode setting is enabled, user level drivers that access display registers directly or that don't use the kernel graphics memory manager will likely corrupt kernel graphics memory, disrupt output configuration (possibly leading to hangs and/or blank displays), and prevent panic/oops messages from appearing. So use caution when enabling this code; be sure your user level code supports the new interfaces. A new SysRq key, 'g', provides emergency support for switching back to the kernel's framebuffer console; which is useful for testing. Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_bios.c')
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c193
1 files changed, 193 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
new file mode 100644
index 000000000000..4ca82a025525
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -0,0 +1,193 @@
1/*
2 * Copyright © 2006 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Eric Anholt <eric@anholt.net>
25 *
26 */
27#include "drmP.h"
28#include "drm.h"
29#include "i915_drm.h"
30#include "i915_drv.h"
31#include "intel_bios.h"
32
33
34static void *
35find_section(struct bdb_header *bdb, int section_id)
36{
37 u8 *base = (u8 *)bdb;
38 int index = 0;
39 u16 total, current_size;
40 u8 current_id;
41
42 /* skip to first section */
43 index += bdb->header_size;
44 total = bdb->bdb_size;
45
46 /* walk the sections looking for section_id */
47 while (index < total) {
48 current_id = *(base + index);
49 index++;
50 current_size = *((u16 *)(base + index));
51 index += 2;
52 if (current_id == section_id)
53 return base + index;
54 index += current_size;
55 }
56
57 return NULL;
58}
59
60/* Try to find panel data */
61static void
62parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
63{
64 struct bdb_lvds_options *lvds_options;
65 struct bdb_lvds_lfp_data *lvds_lfp_data;
66 struct bdb_lvds_lfp_data_entry *entry;
67 struct lvds_dvo_timing *dvo_timing;
68 struct drm_display_mode *panel_fixed_mode;
69
70 /* Defaults if we can't find VBT info */
71 dev_priv->lvds_dither = 0;
72 dev_priv->lvds_vbt = 0;
73
74 lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
75 if (!lvds_options)
76 return;
77
78 dev_priv->lvds_dither = lvds_options->pixel_dither;
79 if (lvds_options->panel_type == 0xff)
80 return;
81
82 lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
83 if (!lvds_lfp_data)
84 return;
85
86 dev_priv->lvds_vbt = 1;
87
88 entry = &lvds_lfp_data->data[lvds_options->panel_type];
89 dvo_timing = &entry->dvo_timing;
90
91 panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode),
92 DRM_MEM_DRIVER);
93
94 panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) |
95 dvo_timing->hactive_lo;
96 panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay +
97 ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo);
98 panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start +
99 dvo_timing->hsync_pulse_width;
100 panel_fixed_mode->htotal = panel_fixed_mode->hdisplay +
101 ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo);
102
103 panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) |
104 dvo_timing->vactive_lo;
105 panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay +
106 dvo_timing->vsync_off;
107 panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start +
108 dvo_timing->vsync_pulse_width;
109 panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay +
110 ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo);
111 panel_fixed_mode->clock = dvo_timing->clock * 10;
112 panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
113
114 drm_mode_set_name(panel_fixed_mode);
115
116 dev_priv->vbt_mode = panel_fixed_mode;
117
118 DRM_DEBUG("Found panel mode in BIOS VBT tables:\n");
119 drm_mode_debug_printmodeline(panel_fixed_mode);
120
121 return;
122}
123
124static void
125parse_general_features(struct drm_i915_private *dev_priv,
126 struct bdb_header *bdb)
127{
128 struct bdb_general_features *general;
129
130 /* Set sensible defaults in case we can't find the general block */
131 dev_priv->int_tv_support = 1;
132 dev_priv->int_crt_support = 1;
133
134 general = find_section(bdb, BDB_GENERAL_FEATURES);
135 if (general) {
136 dev_priv->int_tv_support = general->int_tv_support;
137 dev_priv->int_crt_support = general->int_crt_support;
138 }
139}
140
141/**
142 * intel_init_bios - initialize VBIOS settings & find VBT
143 * @dev: DRM device
144 *
145 * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers
146 * to appropriate values.
147 *
148 * VBT existence is a sanity check that is relied on by other i830_bios.c code.
149 * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may
150 * feed an updated VBT back through that, compared to what we'll fetch using
151 * this method of groping around in the BIOS data.
152 *
153 * Returns 0 on success, nonzero on failure.
154 */
155bool
156intel_init_bios(struct drm_device *dev)
157{
158 struct drm_i915_private *dev_priv = dev->dev_private;
159 struct pci_dev *pdev = dev->pdev;
160 struct vbt_header *vbt = NULL;
161 struct bdb_header *bdb;
162 u8 __iomem *bios;
163 size_t size;
164 int i;
165
166 bios = pci_map_rom(pdev, &size);
167 if (!bios)
168 return -1;
169
170 /* Scour memory looking for the VBT signature */
171 for (i = 0; i + 4 < size; i++) {
172 if (!memcmp(bios + i, "$VBT", 4)) {
173 vbt = (struct vbt_header *)(bios + i);
174 break;
175 }
176 }
177
178 if (!vbt) {
179 DRM_ERROR("VBT signature missing\n");
180 pci_unmap_rom(pdev, bios);
181 return -1;
182 }
183
184 bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
185
186 /* Grab useful general definitions */
187 parse_general_features(dev_priv, bdb);
188 parse_panel_data(dev_priv, bdb);
189
190 pci_unmap_rom(pdev, bios);
191
192 return 0;
193}