diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c index d42da38..f767164 100644 --- a/arch/x86/boot/video.c +++ b/arch/x86/boot/video.c @@ -27,6 +27,12 @@ static void store_cursor_position(void) boot_params.screen_info.orig_x = oreg.dl; boot_params.screen_info.orig_y = oreg.dh; + + if (oreg.ch & 0x20) + boot_params.screen_info.flags |= VIDEO_FLAGS_NOCURSOR; + + if ((oreg.ch & 0x1f) > (oreg.cl & 0x1f)) + boot_params.screen_info.flags |= VIDEO_FLAGS_NOCURSOR; } static void store_video_mode(void) diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 0c80c68..2d832af 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -146,10 +146,12 @@ static const struct consw *con_driver_map[MAX_NR_CONSOLES]; static int con_open(struct tty_struct *, struct file *); static void vc_init(struct vc_data *vc, unsigned int rows, - unsigned int cols, int do_clear); + unsigned int cols, int do_clear, + int show_cursor); static void gotoxy(struct vc_data *vc, int new_x, int new_y); static void save_cur(struct vc_data *vc); -static void reset_terminal(struct vc_data *vc, int do_clear); +static void reset_terminal(struct vc_data *vc, int do_clear, + int show_cursor); static void con_flush_chars(struct tty_struct *tty); static int set_vesa_blanking(char __user *p); static void set_cursor(struct vc_data *vc); @@ -170,6 +172,7 @@ static int ignore_poke; int do_poke_blanked_console; int console_blanked; +static int boot_cursor_hidden; static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ static int vesa_off_interval; @@ -775,7 +778,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ vc_cons[currcons].d = NULL; return -ENOMEM; } - vc_init(vc, vc->vc_rows, vc->vc_cols, 1); + vc_init(vc, vc->vc_rows, vc->vc_cols, 1, 1); vcs_make_sysfs(currcons); atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, ¶m); } @@ -1595,7 +1598,7 @@ enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, ESpalette }; /* console_sem is held (except via vc_init()) */ -static void reset_terminal(struct vc_data *vc, int do_clear) +static void reset_terminal(struct vc_data *vc, int do_clear, int show_cursor) { vc->vc_top = 0; vc->vc_bottom = vc->vc_rows; @@ -1616,7 +1619,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) vc->vc_decscnm = 0; vc->vc_decom = 0; vc->vc_decawm = 1; - vc->vc_deccm = 1; + vc->vc_deccm = show_cursor; vc->vc_decim = 0; set_kbd(vc, decarm); @@ -1756,7 +1759,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_state = EShash; return; case 'c': - reset_terminal(vc, 1); + reset_terminal(vc, 1, 1); return; case '>': /* Numeric keypad */ clr_kbd(vc, kbdapplic); @@ -2799,7 +2802,7 @@ module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR); module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR); static void vc_init(struct vc_data *vc, unsigned int rows, - unsigned int cols, int do_clear) + unsigned int cols, int do_clear, int show_cursor) { int j, k ; @@ -2821,7 +2824,7 @@ static void vc_init(struct vc_data *vc, unsigned int rows, vc->vc_itcolor = default_italic_color; vc->vc_halfcolor = 0x08; /* grey */ init_waitqueue_head(&vc->paste_wait); - reset_terminal(vc, do_clear); + reset_terminal(vc, do_clear, show_cursor); } /* @@ -2873,7 +2876,8 @@ static int __init con_init(void) visual_init(vc, currcons, 1); vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT); vc_init(vc, vc->vc_rows, vc->vc_cols, - currcons || !vc->vc_sw->con_save_screen); + currcons || !vc->vc_sw->con_save_screen, + !boot_cursor_hidden); } currcons = fg_console = 0; master_display_fg = vc = vc_cons[currcons].d; @@ -4028,6 +4032,12 @@ u16 screen_glyph(struct vc_data *vc, int offset) } EXPORT_SYMBOL_GPL(screen_glyph); +void hide_boot_cursor(bool hide) +{ + boot_cursor_hidden = hide; +} +EXPORT_SYMBOL(hide_boot_cursor); + /* used by vcs - note the word offset */ unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed) { diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 093146b..de7a859 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1548,7 +1548,15 @@ int i915_driver_unload(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); drm_mm_takedown(&dev_priv->vram); i915_gem_lastclose(dev); - + /* + * free the memory space allocated for the child device + * config parsed from VBT + */ + if (dev_priv->child_dev_num && dev_priv->child_dev) { + kfree(dev_priv->child_dev); + dev_priv->child_dev = NULL; + dev_priv->child_dev_num = 0; + } intel_cleanup_overlay(dev); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 835625b..059e93e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -261,7 +261,7 @@ typedef struct drm_i915_private { unsigned int lvds_vbt:1; unsigned int int_crt_support:1; unsigned int lvds_use_ssc:1; - unsigned int edp_support:1; + unsigned int lvds_config:2; int lvds_ssc_freq; struct notifier_block lid_notifier; @@ -543,6 +543,8 @@ typedef struct drm_i915_private { struct timer_list idle_timer; bool busy; u16 orig_clock; + int child_dev_num; + struct child_device_config *child_dev; } drm_i915_private_t; /** driver private structure attached to each drm_gem_object */ diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index cbd9118..886a929 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -355,17 +355,77 @@ parse_driver_features(struct drm_i915_private *dev_priv, if (!driver) return; - if (driver && SUPPORTS_EDP(dev) && - driver->lvds_config == BDB_DRIVER_FEATURE_EDP) { - dev_priv->edp_support = 1; - } else { - dev_priv->edp_support = 0; - } + dev_priv->lvds_config = driver->lvds_config; - if (driver && driver->dual_frequency) + if (driver->dual_frequency) dev_priv->render_reclock_avail = true; } +static void +parse_device_mapping_from_vbt(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, *block_ptr; + + p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); + if (!p_defs) { + DRM_DEBUG("No general definition block is found\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("different child size is found. Invalid.\n"); + return; + } + /* get the block size of general definitions */ + block_ptr = (u16 *)((char *)p_defs - 2); + block_size = *block_ptr; + /* 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("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("Can't allocate memory space for child device\n"); + } + 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; + printk(KERN_DEBUG "initial %p, result %p, size %d\n", + dev_priv->child_dev, child_dev_ptr, sizeof(*p_child) * count); + count++; + memcpy((void *)child_dev_ptr, (void *)p_child, sizeof(*p_child)); + } + return; +} + /** * intel_init_bios - initialize VBIOS settings & find VBT * @dev: DRM device @@ -417,6 +477,7 @@ intel_init_bios(struct drm_device *dev) parse_lfp_panel_data(dev_priv, bdb); parse_sdvo_panel_data(dev_priv, bdb); parse_sdvo_device_mapping(dev_priv, bdb); + parse_device_mapping_from_vbt(dev_priv, bdb); parse_driver_features(dev_priv, bdb); pci_unmap_rom(pdev, bios); diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 0f8e5f6..efef36b 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -161,13 +161,16 @@ struct bdb_general_features { #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_EFP_HDMI DEVICE_TYPE_EFP_DVI_D_HDCP #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 0x1022 #define DEVICE_TYPE_LFP_LVDS_PWR 0x5062 #define DEVICE_TYPE_LFP_LVDS_DUAL 0x5162 #define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2 +#define DEVICE_TYPE_DISPLAYPORT 0x68c6 #define DEVICE_CFG_NONE 0x00 #define DEVICE_CFG_12BIT_DVOB 0x01 @@ -192,6 +195,10 @@ struct bdb_general_features { #define DEVICE_PORT_DVOA 0x00 /* none on 845+ */ #define DEVICE_PORT_DVOB 0x01 #define DEVICE_PORT_DVOC 0x02 +#define DEVICE_PORT_DVOD 0x03 +#define DEVICE_PORT_IDPB 0x07 +#define DEVICE_PORT_IDPC 0x08 +#define DEVICE_PORT_IDPD 0x09 struct child_device_config { u16 handle; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fcab9de..bf8318e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1229,6 +1229,45 @@ intel_dp_hot_plug(struct intel_output *intel_output) intel_dp_check_link_status(intel_output); } +/* + * Enumerate the child dev array parsed from VBT to check whether + * the given DP is present. + * If it is present, return 1. + * If it is not present, return false. + * If no child dev is parsed from VBT, it assumes that the given + * DP is present. + */ +int dp_is_present_in_vbt(struct drm_device *dev, int dp_reg) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct child_device_config *p_child; + int i, dp_port, ret; + + if (!dev_priv->child_dev_num) + return 1; + + if (dp_reg == DP_B) + dp_port = DEVICE_PORT_IDPB; + else if (dp_reg == DP_C) + dp_port = DEVICE_PORT_IDPC; + else + dp_port = DEVICE_PORT_IDPD; + + ret = 0; + for (i = 0; i < dev_priv->child_dev_num; i++) { + p_child = dev_priv->child_dev + i; + /* + * If the device type is not HDMI, continue. + */ + if (p_child->device_type != DEVICE_TYPE_DISPLAYPORT) + continue; + /* Find the DP port */ + if (p_child->dvo_port == dp_port) + ret = 1; + } + return ret; +} + void intel_dp_init(struct drm_device *dev, int output_reg) { @@ -1238,6 +1277,11 @@ intel_dp_init(struct drm_device *dev, int output_reg) struct intel_dp_priv *dp_priv; const char *name = NULL; + if (!dp_is_present_in_vbt(dev, output_reg)) { + DRM_DEBUG("DP is not present, ignoring\n"); + return; + } + intel_output = kcalloc(sizeof(struct intel_output) + sizeof(struct intel_dp_priv), 1, GFP_KERNEL); if (!intel_output) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index c33451a..e8fcce7 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -225,6 +225,45 @@ static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { .destroy = intel_hdmi_enc_destroy, }; +/* + * Enumerate the child dev array parsed from VBT to check whether + * the given HDMI is present. + * If it is present, return 1. + * If it is not present, return false. + * If no child dev is parsed from VBT, it assumes that the given + * HDMI is present. + */ +int hdmi_is_present_in_vbt(struct drm_device *dev, int hdmi_reg) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct child_device_config *p_child; + int i, hdmi_port, ret; + + if (!dev_priv->child_dev_num) + return 1; + + if (hdmi_reg == SDVOB) + hdmi_port = DEVICE_PORT_DVOB; + else if (hdmi_reg == SDVOC) + hdmi_port = DEVICE_PORT_DVOC; + else if (hdmi_reg == HDMIB) + hdmi_port = DEVICE_PORT_DVOB; + else if (hdmi_reg == HDMIC) + hdmi_port = DEVICE_PORT_DVOC; + else if (hdmi_reg == HDMID) + hdmi_port = DEVICE_PORT_DVOD; + + ret = 0; + for (i = 0; i < dev_priv->child_dev_num; i++) { + p_child = dev_priv->child_dev + i; + if (p_child->device_type != DEVICE_TYPE_EFP_HDMI) + continue; + /* Find the HDMI port */ + if (p_child->dvo_port == hdmi_port) + ret = 1; + } + return ret; +} void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) { @@ -233,6 +272,11 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) struct intel_output *intel_output; struct intel_hdmi_priv *hdmi_priv; + if (!hdmi_is_present_in_vbt(dev, sdvox_reg)) { + DRM_DEBUG("HDMI is not present, ignoring\n"); + return; + } + intel_output = kcalloc(sizeof(struct intel_output) + sizeof(struct intel_hdmi_priv), 1, GFP_KERNEL); if (!intel_output) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index b1e3af7..ffd266e 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -913,6 +913,38 @@ static int intel_lid_present(void) } #endif +static int device_is_lvds(u32 device) +{ + return device == DEVICE_TYPE_LFP_LVDS || + device == DEVICE_TYPE_LFP_LVDS_PWR || + device == DEVICE_TYPE_LFP_LVDS_DUAL || + device == DEVICE_TYPE_LFP_LVDS_DUAL_HDCP; +} + +static int intel_lvds_present_in_vbt(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct child_device_config *child; + int i; + + if (!dev_priv->child_dev_num) + return 1; + + if (dev_priv->lvds_config == BDB_DRIVER_FEATURE_NO_LVDS) + return 0; + + for (i = 0; i < dev_priv->child_dev_num; i++) { + child = dev_priv->child_dev + i; + + if (!(device_is_lvds(child->device_type))) + continue; + if (child->addin_offset) + return 1; + } + + return 0; +} + /** * intel_lvds_init - setup LVDS connectors on this device * @dev: drm device @@ -936,20 +968,16 @@ void intel_lvds_init(struct drm_device *dev) if (dmi_check_system(intel_no_lvds)) return; - /* Assume that any device without an ACPI LID device also doesn't - * have an integrated LVDS. We would be better off parsing the BIOS - * to get a reliable indicator, but that code isn't written yet. - * - * In the case of all-in-one desktops using LVDS that we've seen, - * they're using SDVO LVDS. + /* + * Walk the child device config for a valid-looking LVDS entry. */ - if (!intel_lid_present()) + if (!intel_lvds_present_in_vbt(dev)) return; if (IS_IGDNG(dev)) { if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) return; - if (dev_priv->edp_support) { + if (dev_priv->lvds_config == BDB_DRIVER_FEATURE_EDP) { DRM_DEBUG_KMS("disable LVDS for eDP support\n"); return; } diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index da55cca..4381fb6 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -376,6 +376,8 @@ static const char *vgacon_startup(void) u16 saved1, saved2; volatile u16 *p; + printk("Video flags: %x\n", screen_info.flags); + if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) { no_vga: #ifdef CONFIG_DUMMY_CONSOLE @@ -585,6 +587,8 @@ static void vgacon_init(struct vc_data *c, int init) vgacon_uni_pagedir[1]++; if (!vgacon_uni_pagedir[0] && p) con_set_default_unimap(c); + + hide_boot_cursor(screen_info.flags & VIDEO_FLAGS_NOCURSOR); } static void vgacon_deinit(struct vc_data *c) diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h index 1ee2c05..899fbb4 100644 --- a/include/linux/screen_info.h +++ b/include/linux/screen_info.h @@ -14,7 +14,8 @@ struct screen_info { __u16 orig_video_page; /* 0x04 */ __u8 orig_video_mode; /* 0x06 */ __u8 orig_video_cols; /* 0x07 */ - __u16 unused2; /* 0x08 */ + __u8 flags; /* 0x08 */ + __u8 unused2; /* 0x09 */ __u16 orig_video_ega_bx;/* 0x0a */ __u16 unused3; /* 0x0c */ __u8 orig_video_lines; /* 0x0e */ @@ -65,6 +66,8 @@ struct screen_info { #define VIDEO_TYPE_EFI 0x70 /* EFI graphic mode */ +#define VIDEO_FLAGS_NOCURSOR (1 << 0) /* The video mode has no cursor set */ + #ifdef __KERNEL__ extern struct screen_info screen_info; diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index c0c4e11..459bf00 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -130,4 +130,6 @@ struct vt_notifier_param { extern int register_vt_notifier(struct notifier_block *nb); extern int unregister_vt_notifier(struct notifier_block *nb); +extern void hide_boot_cursor(bool hide); + #endif /* _VT_KERN_H */