1f910b411SAlan Cox /* 2f910b411SAlan Cox * Copyright (c) 2006 Intel Corporation 3f910b411SAlan Cox * 4f910b411SAlan Cox * This program is free software; you can redistribute it and/or modify it 5f910b411SAlan Cox * under the terms and conditions of the GNU General Public License, 6f910b411SAlan Cox * version 2, as published by the Free Software Foundation. 7f910b411SAlan Cox * 8f910b411SAlan Cox * This program is distributed in the hope it will be useful, but WITHOUT 9f910b411SAlan Cox * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10f910b411SAlan Cox * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11f910b411SAlan Cox * more details. 12f910b411SAlan Cox * 13f910b411SAlan Cox * You should have received a copy of the GNU General Public License along with 14f910b411SAlan Cox * this program; if not, write to the Free Software Foundation, Inc., 15f910b411SAlan Cox * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 16f910b411SAlan Cox * 17f910b411SAlan Cox * Authors: 18f910b411SAlan Cox * Eric Anholt <eric@anholt.net> 19f910b411SAlan Cox * 20f910b411SAlan Cox */ 21f910b411SAlan Cox #include <drm/drmP.h> 22f910b411SAlan Cox #include <drm/drm.h> 23838fa588SAlan Cox #include "gma_drm.h" 24f910b411SAlan Cox #include "psb_drv.h" 25f910b411SAlan Cox #include "psb_intel_drv.h" 26f910b411SAlan Cox #include "psb_intel_reg.h" 27f910b411SAlan Cox #include "intel_bios.h" 28f910b411SAlan Cox 291fb28e9eSAlan Cox #define SLAVE_ADDR1 0x70 301fb28e9eSAlan Cox #define SLAVE_ADDR2 0x72 31f910b411SAlan Cox 32f910b411SAlan Cox static void *find_section(struct bdb_header *bdb, int section_id) 33f910b411SAlan Cox { 34f910b411SAlan Cox u8 *base = (u8 *)bdb; 35f910b411SAlan Cox int index = 0; 36f910b411SAlan Cox u16 total, current_size; 37f910b411SAlan Cox u8 current_id; 38f910b411SAlan Cox 39f910b411SAlan Cox /* skip to first section */ 40f910b411SAlan Cox index += bdb->header_size; 41f910b411SAlan Cox total = bdb->bdb_size; 42f910b411SAlan Cox 43f910b411SAlan Cox /* walk the sections looking for section_id */ 44f910b411SAlan Cox while (index < total) { 45f910b411SAlan Cox current_id = *(base + index); 46f910b411SAlan Cox index++; 47f910b411SAlan Cox current_size = *((u16 *)(base + index)); 48f910b411SAlan Cox index += 2; 49f910b411SAlan Cox if (current_id == section_id) 50f910b411SAlan Cox return base + index; 51f910b411SAlan Cox index += current_size; 52f910b411SAlan Cox } 53f910b411SAlan Cox 54f910b411SAlan Cox return NULL; 55f910b411SAlan Cox } 56f910b411SAlan Cox 571fb28e9eSAlan Cox static u16 581fb28e9eSAlan Cox get_blocksize(void *p) 591fb28e9eSAlan Cox { 601fb28e9eSAlan Cox u16 *block_ptr, block_size; 611fb28e9eSAlan Cox 621fb28e9eSAlan Cox block_ptr = (u16 *)((char *)p - 2); 631fb28e9eSAlan Cox block_size = *block_ptr; 641fb28e9eSAlan Cox return block_size; 651fb28e9eSAlan Cox } 661fb28e9eSAlan Cox 67f910b411SAlan Cox static void fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, 68f910b411SAlan Cox struct lvds_dvo_timing *dvo_timing) 69f910b411SAlan Cox { 70f910b411SAlan Cox panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | 71f910b411SAlan Cox dvo_timing->hactive_lo; 72f910b411SAlan Cox panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + 73f910b411SAlan Cox ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); 74f910b411SAlan Cox panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + 75f910b411SAlan Cox dvo_timing->hsync_pulse_width; 76f910b411SAlan Cox panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + 77f910b411SAlan Cox ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); 78f910b411SAlan Cox 79f910b411SAlan Cox panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | 80f910b411SAlan Cox dvo_timing->vactive_lo; 81f910b411SAlan Cox panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + 82f910b411SAlan Cox dvo_timing->vsync_off; 83f910b411SAlan Cox panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + 84f910b411SAlan Cox dvo_timing->vsync_pulse_width; 85f910b411SAlan Cox panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + 86f910b411SAlan Cox ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); 87f910b411SAlan Cox panel_fixed_mode->clock = dvo_timing->clock * 10; 88f910b411SAlan Cox panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; 89f910b411SAlan Cox 901fb28e9eSAlan Cox if (dvo_timing->hsync_positive) 911fb28e9eSAlan Cox panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC; 921fb28e9eSAlan Cox else 931fb28e9eSAlan Cox panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC; 941fb28e9eSAlan Cox 951fb28e9eSAlan Cox if (dvo_timing->vsync_positive) 961fb28e9eSAlan Cox panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC; 971fb28e9eSAlan Cox else 981fb28e9eSAlan Cox panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; 991fb28e9eSAlan Cox 100f910b411SAlan Cox /* Some VBTs have bogus h/vtotal values */ 101f910b411SAlan Cox if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) 102f910b411SAlan Cox panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; 103f910b411SAlan Cox if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) 104f910b411SAlan Cox panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; 105f910b411SAlan Cox 106f910b411SAlan Cox drm_mode_set_name(panel_fixed_mode); 107f910b411SAlan Cox } 108f910b411SAlan Cox 109f910b411SAlan Cox static void parse_backlight_data(struct drm_psb_private *dev_priv, 110f910b411SAlan Cox struct bdb_header *bdb) 111f910b411SAlan Cox { 112f910b411SAlan Cox struct bdb_lvds_backlight *vbt_lvds_bl = NULL; 113f910b411SAlan Cox struct bdb_lvds_backlight *lvds_bl; 114f910b411SAlan Cox u8 p_type = 0; 115f910b411SAlan Cox void *bl_start = NULL; 116f910b411SAlan Cox struct bdb_lvds_options *lvds_opts 117f910b411SAlan Cox = find_section(bdb, BDB_LVDS_OPTIONS); 118f910b411SAlan Cox 119f910b411SAlan Cox dev_priv->lvds_bl = NULL; 120f910b411SAlan Cox 121f910b411SAlan Cox if (lvds_opts) 122f910b411SAlan Cox p_type = lvds_opts->panel_type; 123f910b411SAlan Cox else 124f910b411SAlan Cox return; 125f910b411SAlan Cox 126f910b411SAlan Cox bl_start = find_section(bdb, BDB_LVDS_BACKLIGHT); 127f910b411SAlan Cox vbt_lvds_bl = (struct bdb_lvds_backlight *)(bl_start + 1) + p_type; 128f910b411SAlan Cox 129f910b411SAlan Cox lvds_bl = kzalloc(sizeof(*vbt_lvds_bl), GFP_KERNEL); 130f910b411SAlan Cox if (!lvds_bl) { 131f910b411SAlan Cox dev_err(dev_priv->dev->dev, "out of memory for backlight data\n"); 132f910b411SAlan Cox return; 133f910b411SAlan Cox } 134f910b411SAlan Cox memcpy(lvds_bl, vbt_lvds_bl, sizeof(*vbt_lvds_bl)); 135f910b411SAlan Cox dev_priv->lvds_bl = lvds_bl; 136f910b411SAlan Cox } 137f910b411SAlan Cox 138f910b411SAlan Cox /* Try to find integrated panel data */ 139f910b411SAlan Cox static void parse_lfp_panel_data(struct drm_psb_private *dev_priv, 140f910b411SAlan Cox struct bdb_header *bdb) 141f910b411SAlan Cox { 142f910b411SAlan Cox struct bdb_lvds_options *lvds_options; 143f910b411SAlan Cox struct bdb_lvds_lfp_data *lvds_lfp_data; 144f910b411SAlan Cox struct bdb_lvds_lfp_data_entry *entry; 145f910b411SAlan Cox struct lvds_dvo_timing *dvo_timing; 146f910b411SAlan Cox struct drm_display_mode *panel_fixed_mode; 147f910b411SAlan Cox 148f910b411SAlan Cox /* Defaults if we can't find VBT info */ 149f910b411SAlan Cox dev_priv->lvds_dither = 0; 150f910b411SAlan Cox dev_priv->lvds_vbt = 0; 151f910b411SAlan Cox 152f910b411SAlan Cox lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); 153f910b411SAlan Cox if (!lvds_options) 154f910b411SAlan Cox return; 155f910b411SAlan Cox 156f910b411SAlan Cox dev_priv->lvds_dither = lvds_options->pixel_dither; 157f910b411SAlan Cox if (lvds_options->panel_type == 0xff) 158f910b411SAlan Cox return; 159f910b411SAlan Cox 160f910b411SAlan Cox lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); 161f910b411SAlan Cox if (!lvds_lfp_data) 162f910b411SAlan Cox return; 163f910b411SAlan Cox 164f910b411SAlan Cox 165f910b411SAlan Cox entry = &lvds_lfp_data->data[lvds_options->panel_type]; 166f910b411SAlan Cox dvo_timing = &entry->dvo_timing; 167f910b411SAlan Cox 168f910b411SAlan Cox panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), 169f910b411SAlan Cox GFP_KERNEL); 170f910b411SAlan Cox if (panel_fixed_mode == NULL) { 171f910b411SAlan Cox dev_err(dev_priv->dev->dev, "out of memory for fixed panel mode\n"); 172f910b411SAlan Cox return; 173f910b411SAlan Cox } 174f910b411SAlan Cox 175f910b411SAlan Cox dev_priv->lvds_vbt = 1; 176f910b411SAlan Cox fill_detail_timing_data(panel_fixed_mode, dvo_timing); 177f910b411SAlan Cox 178f910b411SAlan Cox if (panel_fixed_mode->htotal > 0 && panel_fixed_mode->vtotal > 0) { 179f910b411SAlan Cox dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; 180f910b411SAlan Cox drm_mode_debug_printmodeline(panel_fixed_mode); 181f910b411SAlan Cox } else { 182f910b411SAlan Cox dev_dbg(dev_priv->dev->dev, "ignoring invalid LVDS VBT\n"); 183f910b411SAlan Cox dev_priv->lvds_vbt = 0; 184f910b411SAlan Cox kfree(panel_fixed_mode); 185f910b411SAlan Cox } 186f910b411SAlan Cox return; 187f910b411SAlan Cox } 188f910b411SAlan Cox 189f910b411SAlan Cox /* Try to find sdvo panel data */ 190f910b411SAlan Cox static void parse_sdvo_panel_data(struct drm_psb_private *dev_priv, 191f910b411SAlan Cox struct bdb_header *bdb) 192f910b411SAlan Cox { 193f910b411SAlan Cox struct bdb_sdvo_lvds_options *sdvo_lvds_options; 194f910b411SAlan Cox struct lvds_dvo_timing *dvo_timing; 195f910b411SAlan Cox struct drm_display_mode *panel_fixed_mode; 196f910b411SAlan Cox 197f910b411SAlan Cox dev_priv->sdvo_lvds_vbt_mode = NULL; 198f910b411SAlan Cox 199f910b411SAlan Cox sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); 200f910b411SAlan Cox if (!sdvo_lvds_options) 201f910b411SAlan Cox return; 202f910b411SAlan Cox 203f910b411SAlan Cox dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS); 204f910b411SAlan Cox if (!dvo_timing) 205f910b411SAlan Cox return; 206f910b411SAlan Cox 207f910b411SAlan Cox panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); 208f910b411SAlan Cox 209f910b411SAlan Cox if (!panel_fixed_mode) 210f910b411SAlan Cox return; 211f910b411SAlan Cox 212f910b411SAlan Cox fill_detail_timing_data(panel_fixed_mode, 213f910b411SAlan Cox dvo_timing + sdvo_lvds_options->panel_type); 214f910b411SAlan Cox 215f910b411SAlan Cox dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode; 216f910b411SAlan Cox 217f910b411SAlan Cox return; 218f910b411SAlan Cox } 219f910b411SAlan Cox 220f910b411SAlan Cox static void parse_general_features(struct drm_psb_private *dev_priv, 221f910b411SAlan Cox struct bdb_header *bdb) 222f910b411SAlan Cox { 223f910b411SAlan Cox struct bdb_general_features *general; 224f910b411SAlan Cox 225f910b411SAlan Cox /* Set sensible defaults in case we can't find the general block */ 226f910b411SAlan Cox dev_priv->int_tv_support = 1; 227f910b411SAlan Cox dev_priv->int_crt_support = 1; 228f910b411SAlan Cox 229f910b411SAlan Cox general = find_section(bdb, BDB_GENERAL_FEATURES); 230f910b411SAlan Cox if (general) { 231f910b411SAlan Cox dev_priv->int_tv_support = general->int_tv_support; 232f910b411SAlan Cox dev_priv->int_crt_support = general->int_crt_support; 233f910b411SAlan Cox dev_priv->lvds_use_ssc = general->enable_ssc; 234f910b411SAlan Cox 235f910b411SAlan Cox if (dev_priv->lvds_use_ssc) { 236f910b411SAlan Cox dev_priv->lvds_ssc_freq 237f910b411SAlan Cox = general->ssc_freq ? 100 : 96; 238f910b411SAlan Cox } 239f910b411SAlan Cox } 240f910b411SAlan Cox } 241f910b411SAlan Cox 242642c52fcSAlan Cox static void 2431fb28e9eSAlan Cox parse_sdvo_device_mapping(struct drm_psb_private *dev_priv, 2441fb28e9eSAlan Cox struct bdb_header *bdb) 2451fb28e9eSAlan Cox { 2461fb28e9eSAlan Cox struct sdvo_device_mapping *p_mapping; 2471fb28e9eSAlan Cox struct bdb_general_definitions *p_defs; 2481fb28e9eSAlan Cox struct child_device_config *p_child; 2491fb28e9eSAlan Cox int i, child_device_num, count; 2501fb28e9eSAlan Cox u16 block_size; 2511fb28e9eSAlan Cox 2521fb28e9eSAlan Cox p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); 2531fb28e9eSAlan Cox if (!p_defs) { 2541fb28e9eSAlan Cox DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n"); 2551fb28e9eSAlan Cox return; 2561fb28e9eSAlan Cox } 2571fb28e9eSAlan Cox /* judge whether the size of child device meets the requirements. 2581fb28e9eSAlan Cox * If the child device size obtained from general definition block 2591fb28e9eSAlan Cox * is different with sizeof(struct child_device_config), skip the 2601fb28e9eSAlan Cox * parsing of sdvo device info 2611fb28e9eSAlan Cox */ 2621fb28e9eSAlan Cox if (p_defs->child_dev_size != sizeof(*p_child)) { 2631fb28e9eSAlan Cox /* different child dev size . Ignore it */ 2641fb28e9eSAlan Cox DRM_DEBUG_KMS("different child size is found. Invalid.\n"); 2651fb28e9eSAlan Cox return; 2661fb28e9eSAlan Cox } 2671fb28e9eSAlan Cox /* get the block size of general definitions */ 2681fb28e9eSAlan Cox block_size = get_blocksize(p_defs); 2691fb28e9eSAlan Cox /* get the number of child device */ 2701fb28e9eSAlan Cox child_device_num = (block_size - sizeof(*p_defs)) / 2711fb28e9eSAlan Cox sizeof(*p_child); 2721fb28e9eSAlan Cox count = 0; 2731fb28e9eSAlan Cox for (i = 0; i < child_device_num; i++) { 2741fb28e9eSAlan Cox p_child = &(p_defs->devices[i]); 2751fb28e9eSAlan Cox if (!p_child->device_type) { 2761fb28e9eSAlan Cox /* skip the device block if device type is invalid */ 2771fb28e9eSAlan Cox continue; 2781fb28e9eSAlan Cox } 2791fb28e9eSAlan Cox if (p_child->slave_addr != SLAVE_ADDR1 && 2801fb28e9eSAlan Cox p_child->slave_addr != SLAVE_ADDR2) { 2811fb28e9eSAlan Cox /* 2821fb28e9eSAlan Cox * If the slave address is neither 0x70 nor 0x72, 2831fb28e9eSAlan Cox * it is not a SDVO device. Skip it. 2841fb28e9eSAlan Cox */ 2851fb28e9eSAlan Cox continue; 2861fb28e9eSAlan Cox } 2871fb28e9eSAlan Cox if (p_child->dvo_port != DEVICE_PORT_DVOB && 2881fb28e9eSAlan Cox p_child->dvo_port != DEVICE_PORT_DVOC) { 2891fb28e9eSAlan Cox /* skip the incorrect SDVO port */ 2901fb28e9eSAlan Cox DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n"); 2911fb28e9eSAlan Cox continue; 2921fb28e9eSAlan Cox } 2931fb28e9eSAlan Cox DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on" 2941fb28e9eSAlan Cox " %s port\n", 2951fb28e9eSAlan Cox p_child->slave_addr, 2961fb28e9eSAlan Cox (p_child->dvo_port == DEVICE_PORT_DVOB) ? 2971fb28e9eSAlan Cox "SDVOB" : "SDVOC"); 2981fb28e9eSAlan Cox p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]); 2991fb28e9eSAlan Cox if (!p_mapping->initialized) { 3001fb28e9eSAlan Cox p_mapping->dvo_port = p_child->dvo_port; 3011fb28e9eSAlan Cox p_mapping->slave_addr = p_child->slave_addr; 3021fb28e9eSAlan Cox p_mapping->dvo_wiring = p_child->dvo_wiring; 3031fb28e9eSAlan Cox p_mapping->ddc_pin = p_child->ddc_pin; 3041fb28e9eSAlan Cox p_mapping->i2c_pin = p_child->i2c_pin; 3051fb28e9eSAlan Cox p_mapping->initialized = 1; 3061fb28e9eSAlan Cox DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n", 3071fb28e9eSAlan Cox p_mapping->dvo_port, 3081fb28e9eSAlan Cox p_mapping->slave_addr, 3091fb28e9eSAlan Cox p_mapping->dvo_wiring, 3101fb28e9eSAlan Cox p_mapping->ddc_pin, 3111fb28e9eSAlan Cox p_mapping->i2c_pin); 3121fb28e9eSAlan Cox } else { 3131fb28e9eSAlan Cox DRM_DEBUG_KMS("Maybe one SDVO port is shared by " 3141fb28e9eSAlan Cox "two SDVO device.\n"); 3151fb28e9eSAlan Cox } 3161fb28e9eSAlan Cox if (p_child->slave2_addr) { 3171fb28e9eSAlan Cox /* Maybe this is a SDVO device with multiple inputs */ 3181fb28e9eSAlan Cox /* And the mapping info is not added */ 3191fb28e9eSAlan Cox DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this" 3201fb28e9eSAlan Cox " is a SDVO device with multiple inputs.\n"); 3211fb28e9eSAlan Cox } 3221fb28e9eSAlan Cox count++; 3231fb28e9eSAlan Cox } 3241fb28e9eSAlan Cox 3251fb28e9eSAlan Cox if (!count) { 3261fb28e9eSAlan Cox /* No SDVO device info is found */ 3271fb28e9eSAlan Cox DRM_DEBUG_KMS("No SDVO device info is found in VBT\n"); 3281fb28e9eSAlan Cox } 3291fb28e9eSAlan Cox return; 3301fb28e9eSAlan Cox } 3311fb28e9eSAlan Cox 3321fb28e9eSAlan Cox 3331fb28e9eSAlan Cox static void 334642c52fcSAlan Cox parse_driver_features(struct drm_psb_private *dev_priv, 335642c52fcSAlan Cox struct bdb_header *bdb) 336642c52fcSAlan Cox { 337642c52fcSAlan Cox struct bdb_driver_features *driver; 338642c52fcSAlan Cox 339642c52fcSAlan Cox driver = find_section(bdb, BDB_DRIVER_FEATURES); 340642c52fcSAlan Cox if (!driver) 341642c52fcSAlan Cox return; 342642c52fcSAlan Cox 343642c52fcSAlan Cox /* This bit means to use 96Mhz for DPLL_A or not */ 344642c52fcSAlan Cox if (driver->primary_lfp_id) 345642c52fcSAlan Cox dev_priv->dplla_96mhz = true; 346642c52fcSAlan Cox else 347642c52fcSAlan Cox dev_priv->dplla_96mhz = false; 348642c52fcSAlan Cox } 349642c52fcSAlan Cox 3501fb28e9eSAlan Cox static void 3511fb28e9eSAlan Cox parse_device_mapping(struct drm_psb_private *dev_priv, 3521fb28e9eSAlan Cox struct bdb_header *bdb) 3531fb28e9eSAlan Cox { 3541fb28e9eSAlan Cox struct bdb_general_definitions *p_defs; 3551fb28e9eSAlan Cox struct child_device_config *p_child, *child_dev_ptr; 3561fb28e9eSAlan Cox int i, child_device_num, count; 3571fb28e9eSAlan Cox u16 block_size; 3581fb28e9eSAlan Cox 3591fb28e9eSAlan Cox p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); 3601fb28e9eSAlan Cox if (!p_defs) { 3611fb28e9eSAlan Cox DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); 3621fb28e9eSAlan Cox return; 3631fb28e9eSAlan Cox } 3641fb28e9eSAlan Cox /* judge whether the size of child device meets the requirements. 3651fb28e9eSAlan Cox * If the child device size obtained from general definition block 3661fb28e9eSAlan Cox * is different with sizeof(struct child_device_config), skip the 3671fb28e9eSAlan Cox * parsing of sdvo device info 3681fb28e9eSAlan Cox */ 3691fb28e9eSAlan Cox if (p_defs->child_dev_size != sizeof(*p_child)) { 3701fb28e9eSAlan Cox /* different child dev size . Ignore it */ 3711fb28e9eSAlan Cox DRM_DEBUG_KMS("different child size is found. Invalid.\n"); 3721fb28e9eSAlan Cox return; 3731fb28e9eSAlan Cox } 3741fb28e9eSAlan Cox /* get the block size of general definitions */ 3751fb28e9eSAlan Cox block_size = get_blocksize(p_defs); 3761fb28e9eSAlan Cox /* get the number of child device */ 3771fb28e9eSAlan Cox child_device_num = (block_size - sizeof(*p_defs)) / 3781fb28e9eSAlan Cox sizeof(*p_child); 3791fb28e9eSAlan Cox count = 0; 3801fb28e9eSAlan Cox /* get the number of child devices that are present */ 3811fb28e9eSAlan Cox for (i = 0; i < child_device_num; i++) { 3821fb28e9eSAlan Cox p_child = &(p_defs->devices[i]); 3831fb28e9eSAlan Cox if (!p_child->device_type) { 3841fb28e9eSAlan Cox /* skip the device block if device type is invalid */ 3851fb28e9eSAlan Cox continue; 3861fb28e9eSAlan Cox } 3871fb28e9eSAlan Cox count++; 3881fb28e9eSAlan Cox } 3891fb28e9eSAlan Cox if (!count) { 3901fb28e9eSAlan Cox DRM_DEBUG_KMS("no child dev is parsed from VBT\n"); 3911fb28e9eSAlan Cox return; 3921fb28e9eSAlan Cox } 3931fb28e9eSAlan Cox dev_priv->child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL); 3941fb28e9eSAlan Cox if (!dev_priv->child_dev) { 3951fb28e9eSAlan Cox DRM_DEBUG_KMS("No memory space for child devices\n"); 3961fb28e9eSAlan Cox return; 3971fb28e9eSAlan Cox } 3981fb28e9eSAlan Cox 3991fb28e9eSAlan Cox dev_priv->child_dev_num = count; 4001fb28e9eSAlan Cox count = 0; 4011fb28e9eSAlan Cox for (i = 0; i < child_device_num; i++) { 4021fb28e9eSAlan Cox p_child = &(p_defs->devices[i]); 4031fb28e9eSAlan Cox if (!p_child->device_type) { 4041fb28e9eSAlan Cox /* skip the device block if device type is invalid */ 4051fb28e9eSAlan Cox continue; 4061fb28e9eSAlan Cox } 4071fb28e9eSAlan Cox child_dev_ptr = dev_priv->child_dev + count; 4081fb28e9eSAlan Cox count++; 4091fb28e9eSAlan Cox memcpy((void *)child_dev_ptr, (void *)p_child, 4101fb28e9eSAlan Cox sizeof(*p_child)); 4111fb28e9eSAlan Cox } 4121fb28e9eSAlan Cox return; 4131fb28e9eSAlan Cox } 4141fb28e9eSAlan Cox 4151fb28e9eSAlan Cox 416f910b411SAlan Cox /** 417f910b411SAlan Cox * psb_intel_init_bios - initialize VBIOS settings & find VBT 418f910b411SAlan Cox * @dev: DRM device 419f910b411SAlan Cox * 420f910b411SAlan Cox * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers 421f910b411SAlan Cox * to appropriate values. 422f910b411SAlan Cox * 423f910b411SAlan Cox * VBT existence is a sanity check that is relied on by other i830_bios.c code. 424f910b411SAlan Cox * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may 425f910b411SAlan Cox * feed an updated VBT back through that, compared to what we'll fetch using 426f910b411SAlan Cox * this method of groping around in the BIOS data. 427f910b411SAlan Cox * 428f910b411SAlan Cox * Returns 0 on success, nonzero on failure. 429f910b411SAlan Cox */ 4300317c6ceSDan Carpenter int psb_intel_init_bios(struct drm_device *dev) 431f910b411SAlan Cox { 432f910b411SAlan Cox struct drm_psb_private *dev_priv = dev->dev_private; 433f910b411SAlan Cox struct pci_dev *pdev = dev->pdev; 434f910b411SAlan Cox struct vbt_header *vbt = NULL; 4351fb28e9eSAlan Cox struct bdb_header *bdb = NULL; 4361fb28e9eSAlan Cox u8 __iomem *bios = NULL; 437f910b411SAlan Cox size_t size; 438f910b411SAlan Cox int i; 439f910b411SAlan Cox 4401fb28e9eSAlan Cox /* XXX Should this validation be moved to intel_opregion.c? */ 4411fb28e9eSAlan Cox if (dev_priv->opregion.vbt) { 4421fb28e9eSAlan Cox struct vbt_header *vbt = dev_priv->opregion.vbt; 4431fb28e9eSAlan Cox if (memcmp(vbt->signature, "$VBT", 4) == 0) { 4441fb28e9eSAlan Cox DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n", 4451fb28e9eSAlan Cox vbt->signature); 4461fb28e9eSAlan Cox bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset); 4471fb28e9eSAlan Cox } else 4481fb28e9eSAlan Cox dev_priv->opregion.vbt = NULL; 4491fb28e9eSAlan Cox } 4501fb28e9eSAlan Cox 4511fb28e9eSAlan Cox if (bdb == NULL) { 452f910b411SAlan Cox bios = pci_map_rom(pdev, &size); 453f910b411SAlan Cox if (!bios) 454f910b411SAlan Cox return -1; 455f910b411SAlan Cox 456f910b411SAlan Cox /* Scour memory looking for the VBT signature */ 457f910b411SAlan Cox for (i = 0; i + 4 < size; i++) { 458f910b411SAlan Cox if (!memcmp(bios + i, "$VBT", 4)) { 459f910b411SAlan Cox vbt = (struct vbt_header *)(bios + i); 460f910b411SAlan Cox break; 461f910b411SAlan Cox } 462f910b411SAlan Cox } 463f910b411SAlan Cox 464f910b411SAlan Cox if (!vbt) { 465f910b411SAlan Cox dev_err(dev->dev, "VBT signature missing\n"); 466f910b411SAlan Cox pci_unmap_rom(pdev, bios); 467f910b411SAlan Cox return -1; 468f910b411SAlan Cox } 469f910b411SAlan Cox bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); 4701fb28e9eSAlan Cox } 471f910b411SAlan Cox 4721fb28e9eSAlan Cox /* Grab useful general dxefinitions */ 473f910b411SAlan Cox parse_general_features(dev_priv, bdb); 474642c52fcSAlan Cox parse_driver_features(dev_priv, bdb); 475f910b411SAlan Cox parse_lfp_panel_data(dev_priv, bdb); 476f910b411SAlan Cox parse_sdvo_panel_data(dev_priv, bdb); 4771fb28e9eSAlan Cox parse_sdvo_device_mapping(dev_priv, bdb); 4781fb28e9eSAlan Cox parse_device_mapping(dev_priv, bdb); 479f910b411SAlan Cox parse_backlight_data(dev_priv, bdb); 480f910b411SAlan Cox 4811fb28e9eSAlan Cox if (bios) 482f910b411SAlan Cox pci_unmap_rom(pdev, bios); 483f910b411SAlan Cox 484f910b411SAlan Cox return 0; 485f910b411SAlan Cox } 486f910b411SAlan Cox 487f910b411SAlan Cox /** 488f910b411SAlan Cox * Destroy and free VBT data 489f910b411SAlan Cox */ 490f910b411SAlan Cox void psb_intel_destroy_bios(struct drm_device *dev) 491f910b411SAlan Cox { 492f910b411SAlan Cox struct drm_psb_private *dev_priv = dev->dev_private; 493f910b411SAlan Cox 4944ab2c7f1SAlan Cox kfree(dev_priv->sdvo_lvds_vbt_mode); 4954ab2c7f1SAlan Cox kfree(dev_priv->lfp_lvds_vbt_mode); 4964ab2c7f1SAlan Cox kfree(dev_priv->lvds_bl); 497f910b411SAlan Cox } 498