1 /* 2 * Copyright (c) 2006 Intel Corporation 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms and conditions of the GNU General Public License, 6 * version 2, as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * this program; if not, write to the Free Software Foundation, Inc., 15 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 16 * 17 * Authors: 18 * Eric Anholt <eric@anholt.net> 19 * 20 */ 21 #include <drm/drmP.h> 22 #include <drm/drm.h> 23 #include "gma_drm.h" 24 #include "psb_drv.h" 25 #include "psb_intel_drv.h" 26 #include "psb_intel_reg.h" 27 #include "intel_bios.h" 28 29 30 static void *find_section(struct bdb_header *bdb, int section_id) 31 { 32 u8 *base = (u8 *)bdb; 33 int index = 0; 34 u16 total, current_size; 35 u8 current_id; 36 37 /* skip to first section */ 38 index += bdb->header_size; 39 total = bdb->bdb_size; 40 41 /* walk the sections looking for section_id */ 42 while (index < total) { 43 current_id = *(base + index); 44 index++; 45 current_size = *((u16 *)(base + index)); 46 index += 2; 47 if (current_id == section_id) 48 return base + index; 49 index += current_size; 50 } 51 52 return NULL; 53 } 54 55 static void fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, 56 struct lvds_dvo_timing *dvo_timing) 57 { 58 panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | 59 dvo_timing->hactive_lo; 60 panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + 61 ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); 62 panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + 63 dvo_timing->hsync_pulse_width; 64 panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + 65 ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); 66 67 panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | 68 dvo_timing->vactive_lo; 69 panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + 70 dvo_timing->vsync_off; 71 panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + 72 dvo_timing->vsync_pulse_width; 73 panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + 74 ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); 75 panel_fixed_mode->clock = dvo_timing->clock * 10; 76 panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; 77 78 /* Some VBTs have bogus h/vtotal values */ 79 if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) 80 panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; 81 if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) 82 panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; 83 84 drm_mode_set_name(panel_fixed_mode); 85 } 86 87 static void parse_backlight_data(struct drm_psb_private *dev_priv, 88 struct bdb_header *bdb) 89 { 90 struct bdb_lvds_backlight *vbt_lvds_bl = NULL; 91 struct bdb_lvds_backlight *lvds_bl; 92 u8 p_type = 0; 93 void *bl_start = NULL; 94 struct bdb_lvds_options *lvds_opts 95 = find_section(bdb, BDB_LVDS_OPTIONS); 96 97 dev_priv->lvds_bl = NULL; 98 99 if (lvds_opts) 100 p_type = lvds_opts->panel_type; 101 else 102 return; 103 104 bl_start = find_section(bdb, BDB_LVDS_BACKLIGHT); 105 vbt_lvds_bl = (struct bdb_lvds_backlight *)(bl_start + 1) + p_type; 106 107 lvds_bl = kzalloc(sizeof(*vbt_lvds_bl), GFP_KERNEL); 108 if (!lvds_bl) { 109 dev_err(dev_priv->dev->dev, "out of memory for backlight data\n"); 110 return; 111 } 112 memcpy(lvds_bl, vbt_lvds_bl, sizeof(*vbt_lvds_bl)); 113 dev_priv->lvds_bl = lvds_bl; 114 } 115 116 /* Try to find integrated panel data */ 117 static void parse_lfp_panel_data(struct drm_psb_private *dev_priv, 118 struct bdb_header *bdb) 119 { 120 struct bdb_lvds_options *lvds_options; 121 struct bdb_lvds_lfp_data *lvds_lfp_data; 122 struct bdb_lvds_lfp_data_entry *entry; 123 struct lvds_dvo_timing *dvo_timing; 124 struct drm_display_mode *panel_fixed_mode; 125 126 /* Defaults if we can't find VBT info */ 127 dev_priv->lvds_dither = 0; 128 dev_priv->lvds_vbt = 0; 129 130 lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); 131 if (!lvds_options) 132 return; 133 134 dev_priv->lvds_dither = lvds_options->pixel_dither; 135 if (lvds_options->panel_type == 0xff) 136 return; 137 138 lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); 139 if (!lvds_lfp_data) 140 return; 141 142 143 entry = &lvds_lfp_data->data[lvds_options->panel_type]; 144 dvo_timing = &entry->dvo_timing; 145 146 panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), 147 GFP_KERNEL); 148 if (panel_fixed_mode == NULL) { 149 dev_err(dev_priv->dev->dev, "out of memory for fixed panel mode\n"); 150 return; 151 } 152 153 dev_priv->lvds_vbt = 1; 154 fill_detail_timing_data(panel_fixed_mode, dvo_timing); 155 156 if (panel_fixed_mode->htotal > 0 && panel_fixed_mode->vtotal > 0) { 157 dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; 158 drm_mode_debug_printmodeline(panel_fixed_mode); 159 } else { 160 dev_dbg(dev_priv->dev->dev, "ignoring invalid LVDS VBT\n"); 161 dev_priv->lvds_vbt = 0; 162 kfree(panel_fixed_mode); 163 } 164 return; 165 } 166 167 /* Try to find sdvo panel data */ 168 static void parse_sdvo_panel_data(struct drm_psb_private *dev_priv, 169 struct bdb_header *bdb) 170 { 171 struct bdb_sdvo_lvds_options *sdvo_lvds_options; 172 struct lvds_dvo_timing *dvo_timing; 173 struct drm_display_mode *panel_fixed_mode; 174 175 dev_priv->sdvo_lvds_vbt_mode = NULL; 176 177 sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); 178 if (!sdvo_lvds_options) 179 return; 180 181 dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS); 182 if (!dvo_timing) 183 return; 184 185 panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); 186 187 if (!panel_fixed_mode) 188 return; 189 190 fill_detail_timing_data(panel_fixed_mode, 191 dvo_timing + sdvo_lvds_options->panel_type); 192 193 dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode; 194 195 return; 196 } 197 198 static void parse_general_features(struct drm_psb_private *dev_priv, 199 struct bdb_header *bdb) 200 { 201 struct bdb_general_features *general; 202 203 /* Set sensible defaults in case we can't find the general block */ 204 dev_priv->int_tv_support = 1; 205 dev_priv->int_crt_support = 1; 206 207 general = find_section(bdb, BDB_GENERAL_FEATURES); 208 if (general) { 209 dev_priv->int_tv_support = general->int_tv_support; 210 dev_priv->int_crt_support = general->int_crt_support; 211 dev_priv->lvds_use_ssc = general->enable_ssc; 212 213 if (dev_priv->lvds_use_ssc) { 214 dev_priv->lvds_ssc_freq 215 = general->ssc_freq ? 100 : 96; 216 } 217 } 218 } 219 220 /** 221 * psb_intel_init_bios - initialize VBIOS settings & find VBT 222 * @dev: DRM device 223 * 224 * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers 225 * to appropriate values. 226 * 227 * VBT existence is a sanity check that is relied on by other i830_bios.c code. 228 * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may 229 * feed an updated VBT back through that, compared to what we'll fetch using 230 * this method of groping around in the BIOS data. 231 * 232 * Returns 0 on success, nonzero on failure. 233 */ 234 bool psb_intel_init_bios(struct drm_device *dev) 235 { 236 struct drm_psb_private *dev_priv = dev->dev_private; 237 struct pci_dev *pdev = dev->pdev; 238 struct vbt_header *vbt = NULL; 239 struct bdb_header *bdb; 240 u8 __iomem *bios; 241 size_t size; 242 int i; 243 244 bios = pci_map_rom(pdev, &size); 245 if (!bios) 246 return -1; 247 248 /* Scour memory looking for the VBT signature */ 249 for (i = 0; i + 4 < size; i++) { 250 if (!memcmp(bios + i, "$VBT", 4)) { 251 vbt = (struct vbt_header *)(bios + i); 252 break; 253 } 254 } 255 256 if (!vbt) { 257 dev_err(dev->dev, "VBT signature missing\n"); 258 pci_unmap_rom(pdev, bios); 259 return -1; 260 } 261 262 bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); 263 264 /* Grab useful general definitions */ 265 parse_general_features(dev_priv, bdb); 266 parse_lfp_panel_data(dev_priv, bdb); 267 parse_sdvo_panel_data(dev_priv, bdb); 268 parse_backlight_data(dev_priv, bdb); 269 270 pci_unmap_rom(pdev, bios); 271 272 return 0; 273 } 274 275 /** 276 * Destroy and free VBT data 277 */ 278 void psb_intel_destroy_bios(struct drm_device *dev) 279 { 280 struct drm_psb_private *dev_priv = dev->dev_private; 281 struct drm_display_mode *sdvo_lvds_vbt_mode = 282 dev_priv->sdvo_lvds_vbt_mode; 283 struct drm_display_mode *lfp_lvds_vbt_mode = 284 dev_priv->lfp_lvds_vbt_mode; 285 struct bdb_lvds_backlight *lvds_bl = 286 dev_priv->lvds_bl; 287 288 /*free sdvo panel mode*/ 289 if (sdvo_lvds_vbt_mode) { 290 dev_priv->sdvo_lvds_vbt_mode = NULL; 291 kfree(sdvo_lvds_vbt_mode); 292 } 293 294 if (lfp_lvds_vbt_mode) { 295 dev_priv->lfp_lvds_vbt_mode = NULL; 296 kfree(lfp_lvds_vbt_mode); 297 } 298 299 if (lvds_bl) { 300 dev_priv->lvds_bl = NULL; 301 kfree(lvds_bl); 302 } 303 } 304