diff options
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 42 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 17 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_bios.c | 102 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_bios.h | 17 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_crt.c | 149 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 26 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_sdvo.c | 137 | ||||
| -rw-r--r-- | include/drm/drmP.h | 24 |
10 files changed, 432 insertions, 89 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9b149fe824c3..c431fa54bbb5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
| @@ -180,7 +180,8 @@ typedef struct drm_i915_private { | |||
| 180 | int backlight_duty_cycle; /* restore backlight to this value */ | 180 | int backlight_duty_cycle; /* restore backlight to this value */ |
| 181 | bool panel_wants_dither; | 181 | bool panel_wants_dither; |
| 182 | struct drm_display_mode *panel_fixed_mode; | 182 | struct drm_display_mode *panel_fixed_mode; |
| 183 | struct drm_display_mode *vbt_mode; /* if any */ | 183 | struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ |
| 184 | struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ | ||
| 184 | 185 | ||
| 185 | /* Feature bits from the VBIOS */ | 186 | /* Feature bits from the VBIOS */ |
| 186 | unsigned int int_tv_support:1; | 187 | unsigned int int_tv_support:1; |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b189b49c7602..717b6a854bcd 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
| @@ -349,7 +349,7 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, | |||
| 349 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; | 349 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; |
| 350 | num_pages = last_data_page - first_data_page + 1; | 350 | num_pages = last_data_page - first_data_page + 1; |
| 351 | 351 | ||
| 352 | user_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); | 352 | user_pages = drm_calloc_large(num_pages, sizeof(struct page *)); |
| 353 | if (user_pages == NULL) | 353 | if (user_pages == NULL) |
| 354 | return -ENOMEM; | 354 | return -ENOMEM; |
| 355 | 355 | ||
| @@ -429,7 +429,7 @@ fail_put_user_pages: | |||
| 429 | SetPageDirty(user_pages[i]); | 429 | SetPageDirty(user_pages[i]); |
| 430 | page_cache_release(user_pages[i]); | 430 | page_cache_release(user_pages[i]); |
| 431 | } | 431 | } |
| 432 | kfree(user_pages); | 432 | drm_free_large(user_pages); |
| 433 | 433 | ||
| 434 | return ret; | 434 | return ret; |
| 435 | } | 435 | } |
| @@ -649,7 +649,7 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, | |||
| 649 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; | 649 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; |
| 650 | num_pages = last_data_page - first_data_page + 1; | 650 | num_pages = last_data_page - first_data_page + 1; |
| 651 | 651 | ||
| 652 | user_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); | 652 | user_pages = drm_calloc_large(num_pages, sizeof(struct page *)); |
| 653 | if (user_pages == NULL) | 653 | if (user_pages == NULL) |
| 654 | return -ENOMEM; | 654 | return -ENOMEM; |
| 655 | 655 | ||
| @@ -719,7 +719,7 @@ out_unlock: | |||
| 719 | out_unpin_pages: | 719 | out_unpin_pages: |
| 720 | for (i = 0; i < pinned_pages; i++) | 720 | for (i = 0; i < pinned_pages; i++) |
| 721 | page_cache_release(user_pages[i]); | 721 | page_cache_release(user_pages[i]); |
| 722 | kfree(user_pages); | 722 | drm_free_large(user_pages); |
| 723 | 723 | ||
| 724 | return ret; | 724 | return ret; |
| 725 | } | 725 | } |
| @@ -824,7 +824,7 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, | |||
| 824 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; | 824 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; |
| 825 | num_pages = last_data_page - first_data_page + 1; | 825 | num_pages = last_data_page - first_data_page + 1; |
| 826 | 826 | ||
| 827 | user_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); | 827 | user_pages = drm_calloc_large(num_pages, sizeof(struct page *)); |
| 828 | if (user_pages == NULL) | 828 | if (user_pages == NULL) |
| 829 | return -ENOMEM; | 829 | return -ENOMEM; |
| 830 | 830 | ||
| @@ -902,7 +902,7 @@ fail_unlock: | |||
| 902 | fail_put_user_pages: | 902 | fail_put_user_pages: |
| 903 | for (i = 0; i < pinned_pages; i++) | 903 | for (i = 0; i < pinned_pages; i++) |
| 904 | page_cache_release(user_pages[i]); | 904 | page_cache_release(user_pages[i]); |
| 905 | kfree(user_pages); | 905 | drm_free_large(user_pages); |
| 906 | 906 | ||
| 907 | return ret; | 907 | return ret; |
| 908 | } | 908 | } |
| @@ -1145,7 +1145,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
| 1145 | mutex_unlock(&dev->struct_mutex); | 1145 | mutex_unlock(&dev->struct_mutex); |
| 1146 | return VM_FAULT_SIGBUS; | 1146 | return VM_FAULT_SIGBUS; |
| 1147 | } | 1147 | } |
| 1148 | list_add(&obj_priv->list, &dev_priv->mm.inactive_list); | 1148 | list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list); |
| 1149 | } | 1149 | } |
| 1150 | 1150 | ||
| 1151 | /* Need a new fence register? */ | 1151 | /* Need a new fence register? */ |
| @@ -1375,7 +1375,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, | |||
| 1375 | mutex_unlock(&dev->struct_mutex); | 1375 | mutex_unlock(&dev->struct_mutex); |
| 1376 | return ret; | 1376 | return ret; |
| 1377 | } | 1377 | } |
| 1378 | list_add(&obj_priv->list, &dev_priv->mm.inactive_list); | 1378 | list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list); |
| 1379 | } | 1379 | } |
| 1380 | 1380 | ||
| 1381 | drm_gem_object_unreference(obj); | 1381 | drm_gem_object_unreference(obj); |
| @@ -1408,9 +1408,7 @@ i915_gem_object_put_pages(struct drm_gem_object *obj) | |||
| 1408 | } | 1408 | } |
| 1409 | obj_priv->dirty = 0; | 1409 | obj_priv->dirty = 0; |
| 1410 | 1410 | ||
| 1411 | drm_free(obj_priv->pages, | 1411 | drm_free_large(obj_priv->pages); |
| 1412 | page_count * sizeof(struct page *), | ||
| 1413 | DRM_MEM_DRIVER); | ||
| 1414 | obj_priv->pages = NULL; | 1412 | obj_priv->pages = NULL; |
| 1415 | } | 1413 | } |
| 1416 | 1414 | ||
| @@ -2024,8 +2022,7 @@ i915_gem_object_get_pages(struct drm_gem_object *obj) | |||
| 2024 | */ | 2022 | */ |
| 2025 | page_count = obj->size / PAGE_SIZE; | 2023 | page_count = obj->size / PAGE_SIZE; |
| 2026 | BUG_ON(obj_priv->pages != NULL); | 2024 | BUG_ON(obj_priv->pages != NULL); |
| 2027 | obj_priv->pages = drm_calloc(page_count, sizeof(struct page *), | 2025 | obj_priv->pages = drm_calloc_large(page_count, sizeof(struct page *)); |
| 2028 | DRM_MEM_DRIVER); | ||
| 2029 | if (obj_priv->pages == NULL) { | 2026 | if (obj_priv->pages == NULL) { |
| 2030 | DRM_ERROR("Faled to allocate page list\n"); | 2027 | DRM_ERROR("Faled to allocate page list\n"); |
| 2031 | obj_priv->pages_refcount--; | 2028 | obj_priv->pages_refcount--; |
| @@ -3111,7 +3108,7 @@ i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object *exec_list, | |||
| 3111 | reloc_count += exec_list[i].relocation_count; | 3108 | reloc_count += exec_list[i].relocation_count; |
| 3112 | } | 3109 | } |
| 3113 | 3110 | ||
| 3114 | *relocs = drm_calloc(reloc_count, sizeof(**relocs), DRM_MEM_DRIVER); | 3111 | *relocs = drm_calloc_large(reloc_count, sizeof(**relocs)); |
| 3115 | if (*relocs == NULL) | 3112 | if (*relocs == NULL) |
| 3116 | return -ENOMEM; | 3113 | return -ENOMEM; |
| 3117 | 3114 | ||
| @@ -3125,8 +3122,7 @@ i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object *exec_list, | |||
| 3125 | exec_list[i].relocation_count * | 3122 | exec_list[i].relocation_count * |
| 3126 | sizeof(**relocs)); | 3123 | sizeof(**relocs)); |
| 3127 | if (ret != 0) { | 3124 | if (ret != 0) { |
| 3128 | drm_free(*relocs, reloc_count * sizeof(**relocs), | 3125 | drm_free_large(*relocs); |
| 3129 | DRM_MEM_DRIVER); | ||
| 3130 | *relocs = NULL; | 3126 | *relocs = NULL; |
| 3131 | return -EFAULT; | 3127 | return -EFAULT; |
| 3132 | } | 3128 | } |
| @@ -3165,7 +3161,7 @@ i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object *exec_list, | |||
| 3165 | } | 3161 | } |
| 3166 | 3162 | ||
| 3167 | err: | 3163 | err: |
| 3168 | drm_free(relocs, reloc_count * sizeof(*relocs), DRM_MEM_DRIVER); | 3164 | drm_free_large(relocs); |
| 3169 | 3165 | ||
| 3170 | return ret; | 3166 | return ret; |
| 3171 | } | 3167 | } |
| @@ -3198,10 +3194,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | |||
| 3198 | return -EINVAL; | 3194 | return -EINVAL; |
| 3199 | } | 3195 | } |
| 3200 | /* Copy in the exec list from userland */ | 3196 | /* Copy in the exec list from userland */ |
| 3201 | exec_list = drm_calloc(sizeof(*exec_list), args->buffer_count, | 3197 | exec_list = drm_calloc_large(sizeof(*exec_list), args->buffer_count); |
| 3202 | DRM_MEM_DRIVER); | 3198 | object_list = drm_calloc_large(sizeof(*object_list), args->buffer_count); |
| 3203 | object_list = drm_calloc(sizeof(*object_list), args->buffer_count, | ||
| 3204 | DRM_MEM_DRIVER); | ||
| 3205 | if (exec_list == NULL || object_list == NULL) { | 3199 | if (exec_list == NULL || object_list == NULL) { |
| 3206 | DRM_ERROR("Failed to allocate exec or object list " | 3200 | DRM_ERROR("Failed to allocate exec or object list " |
| 3207 | "for %d buffers\n", | 3201 | "for %d buffers\n", |
| @@ -3462,10 +3456,8 @@ err: | |||
| 3462 | } | 3456 | } |
| 3463 | 3457 | ||
| 3464 | pre_mutex_err: | 3458 | pre_mutex_err: |
| 3465 | drm_free(object_list, sizeof(*object_list) * args->buffer_count, | 3459 | drm_free_large(object_list); |
| 3466 | DRM_MEM_DRIVER); | 3460 | drm_free_large(exec_list); |
| 3467 | drm_free(exec_list, sizeof(*exec_list) * args->buffer_count, | ||
| 3468 | DRM_MEM_DRIVER); | ||
| 3469 | drm_free(cliprects, sizeof(*cliprects) * args->num_cliprects, | 3461 | drm_free(cliprects, sizeof(*cliprects) * args->num_cliprects, |
| 3470 | DRM_MEM_DRIVER); | 3462 | DRM_MEM_DRIVER); |
| 3471 | 3463 | ||
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 15da44cf21b1..9668cc0d7f4e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
| @@ -1410,9 +1410,25 @@ | |||
| 1410 | 1410 | ||
| 1411 | /* Cursor A & B regs */ | 1411 | /* Cursor A & B regs */ |
| 1412 | #define CURACNTR 0x70080 | 1412 | #define CURACNTR 0x70080 |
| 1413 | /* Old style CUR*CNTR flags (desktop 8xx) */ | ||
| 1414 | #define CURSOR_ENABLE 0x80000000 | ||
| 1415 | #define CURSOR_GAMMA_ENABLE 0x40000000 | ||
| 1416 | #define CURSOR_STRIDE_MASK 0x30000000 | ||
| 1417 | #define CURSOR_FORMAT_SHIFT 24 | ||
| 1418 | #define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT) | ||
| 1419 | #define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT) | ||
| 1420 | #define CURSOR_FORMAT_3C (0x01 << CURSOR_FORMAT_SHIFT) | ||
| 1421 | #define CURSOR_FORMAT_4C (0x02 << CURSOR_FORMAT_SHIFT) | ||
| 1422 | #define CURSOR_FORMAT_ARGB (0x04 << CURSOR_FORMAT_SHIFT) | ||
| 1423 | #define CURSOR_FORMAT_XRGB (0x05 << CURSOR_FORMAT_SHIFT) | ||
| 1424 | /* New style CUR*CNTR flags */ | ||
| 1425 | #define CURSOR_MODE 0x27 | ||
| 1413 | #define CURSOR_MODE_DISABLE 0x00 | 1426 | #define CURSOR_MODE_DISABLE 0x00 |
| 1414 | #define CURSOR_MODE_64_32B_AX 0x07 | 1427 | #define CURSOR_MODE_64_32B_AX 0x07 |
| 1415 | #define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) | 1428 | #define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) |
| 1429 | #define MCURSOR_PIPE_SELECT (1 << 28) | ||
| 1430 | #define MCURSOR_PIPE_A 0x00 | ||
| 1431 | #define MCURSOR_PIPE_B (1 << 28) | ||
| 1416 | #define MCURSOR_GAMMA_ENABLE (1 << 26) | 1432 | #define MCURSOR_GAMMA_ENABLE (1 << 26) |
| 1417 | #define CURABASE 0x70084 | 1433 | #define CURABASE 0x70084 |
| 1418 | #define CURAPOS 0x70088 | 1434 | #define CURAPOS 0x70088 |
| @@ -1420,6 +1436,7 @@ | |||
| 1420 | #define CURSOR_POS_SIGN 0x8000 | 1436 | #define CURSOR_POS_SIGN 0x8000 |
| 1421 | #define CURSOR_X_SHIFT 0 | 1437 | #define CURSOR_X_SHIFT 0 |
| 1422 | #define CURSOR_Y_SHIFT 16 | 1438 | #define CURSOR_Y_SHIFT 16 |
| 1439 | #define CURSIZE 0x700a0 | ||
| 1423 | #define CURBCNTR 0x700c0 | 1440 | #define CURBCNTR 0x700c0 |
| 1424 | #define CURBBASE 0x700c4 | 1441 | #define CURBBASE 0x700c4 |
| 1425 | #define CURBPOS 0x700c8 | 1442 | #define CURBPOS 0x700c8 |
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index fc28e2bbd542..9d78cff33b24 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c | |||
| @@ -57,9 +57,43 @@ find_section(struct bdb_header *bdb, int section_id) | |||
| 57 | return NULL; | 57 | return NULL; |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | /* Try to find panel data */ | ||
| 61 | static void | 60 | static void |
| 62 | parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb) | 61 | fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, |
| 62 | struct lvds_dvo_timing *dvo_timing) | ||
| 63 | { | ||
| 64 | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | | ||
| 65 | dvo_timing->hactive_lo; | ||
| 66 | panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + | ||
| 67 | ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); | ||
| 68 | panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + | ||
| 69 | dvo_timing->hsync_pulse_width; | ||
| 70 | panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + | ||
| 71 | ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); | ||
| 72 | |||
| 73 | panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | | ||
| 74 | dvo_timing->vactive_lo; | ||
| 75 | panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + | ||
| 76 | dvo_timing->vsync_off; | ||
| 77 | panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + | ||
| 78 | dvo_timing->vsync_pulse_width; | ||
| 79 | panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + | ||
| 80 | ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); | ||
| 81 | panel_fixed_mode->clock = dvo_timing->clock * 10; | ||
| 82 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; | ||
| 83 | |||
| 84 | /* Some VBTs have bogus h/vtotal values */ | ||
| 85 | if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) | ||
| 86 | panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; | ||
| 87 | if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) | ||
| 88 | panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; | ||
| 89 | |||
| 90 | drm_mode_set_name(panel_fixed_mode); | ||
| 91 | } | ||
| 92 | |||
| 93 | /* Try to find integrated panel data */ | ||
| 94 | static void | ||
| 95 | parse_lfp_panel_data(struct drm_i915_private *dev_priv, | ||
| 96 | struct bdb_header *bdb) | ||
| 63 | { | 97 | { |
| 64 | struct bdb_lvds_options *lvds_options; | 98 | struct bdb_lvds_options *lvds_options; |
| 65 | struct bdb_lvds_lfp_data *lvds_lfp_data; | 99 | struct bdb_lvds_lfp_data *lvds_lfp_data; |
| @@ -91,38 +125,45 @@ parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb) | |||
| 91 | panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), | 125 | panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), |
| 92 | DRM_MEM_DRIVER); | 126 | DRM_MEM_DRIVER); |
| 93 | 127 | ||
| 94 | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | | 128 | fill_detail_timing_data(panel_fixed_mode, dvo_timing); |
| 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 | 129 | ||
| 103 | panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | | 130 | dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; |
| 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 | 131 | ||
| 114 | /* Some VBTs have bogus h/vtotal values */ | 132 | DRM_DEBUG("Found panel mode in BIOS VBT tables:\n"); |
| 115 | if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) | 133 | drm_mode_debug_printmodeline(panel_fixed_mode); |
| 116 | panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; | ||
| 117 | if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) | ||
| 118 | panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; | ||
| 119 | 134 | ||
| 120 | drm_mode_set_name(panel_fixed_mode); | 135 | return; |
| 136 | } | ||
| 137 | |||
| 138 | /* Try to find sdvo panel data */ | ||
| 139 | static void | ||
| 140 | parse_sdvo_panel_data(struct drm_i915_private *dev_priv, | ||
| 141 | struct bdb_header *bdb) | ||
| 142 | { | ||
| 143 | struct bdb_sdvo_lvds_options *sdvo_lvds_options; | ||
| 144 | struct lvds_dvo_timing *dvo_timing; | ||
| 145 | struct drm_display_mode *panel_fixed_mode; | ||
| 121 | 146 | ||
| 122 | dev_priv->vbt_mode = panel_fixed_mode; | 147 | dev_priv->sdvo_lvds_vbt_mode = NULL; |
| 123 | 148 | ||
| 124 | DRM_DEBUG("Found panel mode in BIOS VBT tables:\n"); | 149 | sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); |
| 125 | drm_mode_debug_printmodeline(panel_fixed_mode); | 150 | if (!sdvo_lvds_options) |
| 151 | return; | ||
| 152 | |||
| 153 | dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS); | ||
| 154 | if (!dvo_timing) | ||
| 155 | return; | ||
| 156 | |||
| 157 | panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), | ||
| 158 | DRM_MEM_DRIVER); | ||
| 159 | |||
| 160 | if (!panel_fixed_mode) | ||
| 161 | return; | ||
| 162 | |||
| 163 | fill_detail_timing_data(panel_fixed_mode, | ||
| 164 | dvo_timing + sdvo_lvds_options->panel_type); | ||
| 165 | |||
| 166 | dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode; | ||
| 126 | 167 | ||
| 127 | return; | 168 | return; |
| 128 | } | 169 | } |
| @@ -199,7 +240,8 @@ intel_init_bios(struct drm_device *dev) | |||
| 199 | 240 | ||
| 200 | /* Grab useful general definitions */ | 241 | /* Grab useful general definitions */ |
| 201 | parse_general_features(dev_priv, bdb); | 242 | parse_general_features(dev_priv, bdb); |
| 202 | parse_panel_data(dev_priv, bdb); | 243 | parse_lfp_panel_data(dev_priv, bdb); |
| 244 | parse_sdvo_panel_data(dev_priv, bdb); | ||
| 203 | 245 | ||
| 204 | pci_unmap_rom(pdev, bios); | 246 | pci_unmap_rom(pdev, bios); |
| 205 | 247 | ||
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index de621aad85b5..8ca2cde15804 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h | |||
| @@ -279,6 +279,23 @@ struct vch_bdb_22 { | |||
| 279 | struct vch_panel_data panels[16]; | 279 | struct vch_panel_data panels[16]; |
| 280 | } __attribute__((packed)); | 280 | } __attribute__((packed)); |
| 281 | 281 | ||
| 282 | struct bdb_sdvo_lvds_options { | ||
| 283 | u8 panel_backlight; | ||
| 284 | u8 h40_set_panel_type; | ||
| 285 | u8 panel_type; | ||
| 286 | u8 ssc_clk_freq; | ||
| 287 | u16 als_low_trip; | ||
| 288 | u16 als_high_trip; | ||
| 289 | u8 sclalarcoeff_tab_row_num; | ||
| 290 | u8 sclalarcoeff_tab_row_size; | ||
| 291 | u8 coefficient[8]; | ||
| 292 | u8 panel_misc_bits_1; | ||
| 293 | u8 panel_misc_bits_2; | ||
| 294 | u8 panel_misc_bits_3; | ||
| 295 | u8 panel_misc_bits_4; | ||
| 296 | } __attribute__((packed)); | ||
| 297 | |||
| 298 | |||
| 282 | bool intel_init_bios(struct drm_device *dev); | 299 | bool intel_init_bios(struct drm_device *dev); |
| 283 | 300 | ||
| 284 | /* | 301 | /* |
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 19148c3df637..640f5158effc 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c | |||
| @@ -198,9 +198,142 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) | |||
| 198 | return intel_ddc_probe(intel_output); | 198 | return intel_ddc_probe(intel_output); |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | static enum drm_connector_status | ||
| 202 | intel_crt_load_detect(struct drm_crtc *crtc, struct intel_output *intel_output) | ||
| 203 | { | ||
| 204 | struct drm_encoder *encoder = &intel_output->enc; | ||
| 205 | struct drm_device *dev = encoder->dev; | ||
| 206 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 207 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 208 | uint32_t pipe = intel_crtc->pipe; | ||
| 209 | uint32_t save_bclrpat; | ||
| 210 | uint32_t save_vtotal; | ||
| 211 | uint32_t vtotal, vactive; | ||
| 212 | uint32_t vsample; | ||
| 213 | uint32_t vblank, vblank_start, vblank_end; | ||
| 214 | uint32_t dsl; | ||
| 215 | uint32_t bclrpat_reg; | ||
| 216 | uint32_t vtotal_reg; | ||
| 217 | uint32_t vblank_reg; | ||
| 218 | uint32_t vsync_reg; | ||
| 219 | uint32_t pipeconf_reg; | ||
| 220 | uint32_t pipe_dsl_reg; | ||
| 221 | uint8_t st00; | ||
| 222 | enum drm_connector_status status; | ||
| 223 | |||
| 224 | if (pipe == 0) { | ||
| 225 | bclrpat_reg = BCLRPAT_A; | ||
| 226 | vtotal_reg = VTOTAL_A; | ||
| 227 | vblank_reg = VBLANK_A; | ||
| 228 | vsync_reg = VSYNC_A; | ||
| 229 | pipeconf_reg = PIPEACONF; | ||
| 230 | pipe_dsl_reg = PIPEADSL; | ||
| 231 | } else { | ||
| 232 | bclrpat_reg = BCLRPAT_B; | ||
| 233 | vtotal_reg = VTOTAL_B; | ||
| 234 | vblank_reg = VBLANK_B; | ||
| 235 | vsync_reg = VSYNC_B; | ||
| 236 | pipeconf_reg = PIPEBCONF; | ||
| 237 | pipe_dsl_reg = PIPEBDSL; | ||
| 238 | } | ||
| 239 | |||
| 240 | save_bclrpat = I915_READ(bclrpat_reg); | ||
| 241 | save_vtotal = I915_READ(vtotal_reg); | ||
| 242 | vblank = I915_READ(vblank_reg); | ||
| 243 | |||
| 244 | vtotal = ((save_vtotal >> 16) & 0xfff) + 1; | ||
| 245 | vactive = (save_vtotal & 0x7ff) + 1; | ||
| 246 | |||
| 247 | vblank_start = (vblank & 0xfff) + 1; | ||
| 248 | vblank_end = ((vblank >> 16) & 0xfff) + 1; | ||
| 249 | |||
| 250 | /* Set the border color to purple. */ | ||
| 251 | I915_WRITE(bclrpat_reg, 0x500050); | ||
| 252 | |||
| 253 | if (IS_I9XX(dev)) { | ||
| 254 | uint32_t pipeconf = I915_READ(pipeconf_reg); | ||
| 255 | I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); | ||
| 256 | /* Wait for next Vblank to substitue | ||
| 257 | * border color for Color info */ | ||
| 258 | intel_wait_for_vblank(dev); | ||
| 259 | st00 = I915_READ8(VGA_MSR_WRITE); | ||
| 260 | status = ((st00 & (1 << 4)) != 0) ? | ||
| 261 | connector_status_connected : | ||
| 262 | connector_status_disconnected; | ||
| 263 | |||
| 264 | I915_WRITE(pipeconf_reg, pipeconf); | ||
| 265 | } else { | ||
| 266 | bool restore_vblank = false; | ||
| 267 | int count, detect; | ||
| 268 | |||
| 269 | /* | ||
| 270 | * If there isn't any border, add some. | ||
| 271 | * Yes, this will flicker | ||
| 272 | */ | ||
| 273 | if (vblank_start <= vactive && vblank_end >= vtotal) { | ||
| 274 | uint32_t vsync = I915_READ(vsync_reg); | ||
| 275 | uint32_t vsync_start = (vsync & 0xffff) + 1; | ||
| 276 | |||
| 277 | vblank_start = vsync_start; | ||
| 278 | I915_WRITE(vblank_reg, | ||
| 279 | (vblank_start - 1) | | ||
| 280 | ((vblank_end - 1) << 16)); | ||
| 281 | restore_vblank = true; | ||
| 282 | } | ||
| 283 | /* sample in the vertical border, selecting the larger one */ | ||
| 284 | if (vblank_start - vactive >= vtotal - vblank_end) | ||
| 285 | vsample = (vblank_start + vactive) >> 1; | ||
| 286 | else | ||
| 287 | vsample = (vtotal + vblank_end) >> 1; | ||
| 288 | |||
| 289 | /* | ||
| 290 | * Wait for the border to be displayed | ||
| 291 | */ | ||
| 292 | while (I915_READ(pipe_dsl_reg) >= vactive) | ||
| 293 | ; | ||
| 294 | while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample) | ||
| 295 | ; | ||
| 296 | /* | ||
| 297 | * Watch ST00 for an entire scanline | ||
| 298 | */ | ||
| 299 | detect = 0; | ||
| 300 | count = 0; | ||
| 301 | do { | ||
| 302 | count++; | ||
| 303 | /* Read the ST00 VGA status register */ | ||
| 304 | st00 = I915_READ8(VGA_MSR_WRITE); | ||
| 305 | if (st00 & (1 << 4)) | ||
| 306 | detect++; | ||
| 307 | } while ((I915_READ(pipe_dsl_reg) == dsl)); | ||
| 308 | |||
| 309 | /* restore vblank if necessary */ | ||
| 310 | if (restore_vblank) | ||
| 311 | I915_WRITE(vblank_reg, vblank); | ||
| 312 | /* | ||
| 313 | * If more than 3/4 of the scanline detected a monitor, | ||
| 314 | * then it is assumed to be present. This works even on i830, | ||
| 315 | * where there isn't any way to force the border color across | ||
| 316 | * the screen | ||
| 317 | */ | ||
| 318 | status = detect * 4 > count * 3 ? | ||
| 319 | connector_status_connected : | ||
| 320 | connector_status_disconnected; | ||
| 321 | } | ||
| 322 | |||
| 323 | /* Restore previous settings */ | ||
| 324 | I915_WRITE(bclrpat_reg, save_bclrpat); | ||
| 325 | |||
| 326 | return status; | ||
| 327 | } | ||
| 328 | |||
| 201 | static enum drm_connector_status intel_crt_detect(struct drm_connector *connector) | 329 | static enum drm_connector_status intel_crt_detect(struct drm_connector *connector) |
| 202 | { | 330 | { |
| 203 | struct drm_device *dev = connector->dev; | 331 | struct drm_device *dev = connector->dev; |
| 332 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 333 | struct drm_encoder *encoder = &intel_output->enc; | ||
| 334 | struct drm_crtc *crtc; | ||
| 335 | int dpms_mode; | ||
| 336 | enum drm_connector_status status; | ||
| 204 | 337 | ||
| 205 | if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { | 338 | if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { |
| 206 | if (intel_crt_detect_hotplug(connector)) | 339 | if (intel_crt_detect_hotplug(connector)) |
| @@ -212,8 +345,20 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connecto | |||
| 212 | if (intel_crt_detect_ddc(connector)) | 345 | if (intel_crt_detect_ddc(connector)) |
| 213 | return connector_status_connected; | 346 | return connector_status_connected; |
| 214 | 347 | ||
| 215 | /* TODO use load detect */ | 348 | /* for pre-945g platforms use load detect */ |
| 216 | return connector_status_unknown; | 349 | if (encoder->crtc && encoder->crtc->enabled) { |
| 350 | status = intel_crt_load_detect(encoder->crtc, intel_output); | ||
| 351 | } else { | ||
| 352 | crtc = intel_get_load_detect_pipe(intel_output, | ||
| 353 | NULL, &dpms_mode); | ||
| 354 | if (crtc) { | ||
| 355 | status = intel_crt_load_detect(crtc, intel_output); | ||
| 356 | intel_release_load_detect_pipe(intel_output, dpms_mode); | ||
| 357 | } else | ||
| 358 | status = connector_status_unknown; | ||
| 359 | } | ||
| 360 | |||
| 361 | return status; | ||
| 217 | } | 362 | } |
| 218 | 363 | ||
| 219 | static void intel_crt_destroy(struct drm_connector *connector) | 364 | static void intel_crt_destroy(struct drm_connector *connector) |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3387cf32f385..c9d6f10ba92e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
| @@ -1357,7 +1357,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, | |||
| 1357 | int pipe = intel_crtc->pipe; | 1357 | int pipe = intel_crtc->pipe; |
| 1358 | uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; | 1358 | uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; |
| 1359 | uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; | 1359 | uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; |
| 1360 | uint32_t temp; | 1360 | uint32_t temp = I915_READ(control); |
| 1361 | size_t addr; | 1361 | size_t addr; |
| 1362 | int ret; | 1362 | int ret; |
| 1363 | 1363 | ||
| @@ -1366,7 +1366,12 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, | |||
| 1366 | /* if we want to turn off the cursor ignore width and height */ | 1366 | /* if we want to turn off the cursor ignore width and height */ |
| 1367 | if (!handle) { | 1367 | if (!handle) { |
| 1368 | DRM_DEBUG("cursor off\n"); | 1368 | DRM_DEBUG("cursor off\n"); |
| 1369 | temp = CURSOR_MODE_DISABLE; | 1369 | if (IS_MOBILE(dev) || IS_I9XX(dev)) { |
| 1370 | temp &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); | ||
| 1371 | temp |= CURSOR_MODE_DISABLE; | ||
| 1372 | } else { | ||
| 1373 | temp &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE); | ||
| 1374 | } | ||
| 1370 | addr = 0; | 1375 | addr = 0; |
| 1371 | bo = NULL; | 1376 | bo = NULL; |
| 1372 | mutex_lock(&dev->struct_mutex); | 1377 | mutex_lock(&dev->struct_mutex); |
| @@ -1409,10 +1414,19 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, | |||
| 1409 | addr = obj_priv->phys_obj->handle->busaddr; | 1414 | addr = obj_priv->phys_obj->handle->busaddr; |
| 1410 | } | 1415 | } |
| 1411 | 1416 | ||
| 1412 | temp = 0; | 1417 | if (!IS_I9XX(dev)) |
| 1413 | /* set the pipe for the cursor */ | 1418 | I915_WRITE(CURSIZE, (height << 12) | width); |
| 1414 | temp |= (pipe << 28); | 1419 | |
| 1415 | temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; | 1420 | /* Hooray for CUR*CNTR differences */ |
| 1421 | if (IS_MOBILE(dev) || IS_I9XX(dev)) { | ||
| 1422 | temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT); | ||
| 1423 | temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; | ||
| 1424 | temp |= (pipe << 28); /* Connect to correct pipe */ | ||
| 1425 | } else { | ||
| 1426 | temp &= ~(CURSOR_FORMAT_MASK); | ||
| 1427 | temp |= CURSOR_ENABLE; | ||
| 1428 | temp |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE; | ||
| 1429 | } | ||
| 1416 | 1430 | ||
| 1417 | finish: | 1431 | finish: |
| 1418 | I915_WRITE(control, temp); | 1432 | I915_WRITE(control, temp); |
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 439a86514993..53731f0ffcb5 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
| @@ -511,10 +511,10 @@ void intel_lvds_init(struct drm_device *dev) | |||
| 511 | } | 511 | } |
| 512 | 512 | ||
| 513 | /* Failed to get EDID, what about VBT? */ | 513 | /* Failed to get EDID, what about VBT? */ |
| 514 | if (dev_priv->vbt_mode) { | 514 | if (dev_priv->lfp_lvds_vbt_mode) { |
| 515 | mutex_lock(&dev->mode_config.mutex); | 515 | mutex_lock(&dev->mode_config.mutex); |
| 516 | dev_priv->panel_fixed_mode = | 516 | dev_priv->panel_fixed_mode = |
| 517 | drm_mode_duplicate(dev, dev_priv->vbt_mode); | 517 | drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); |
| 518 | mutex_unlock(&dev->mode_config.mutex); | 518 | mutex_unlock(&dev->mode_config.mutex); |
| 519 | if (dev_priv->panel_fixed_mode) { | 519 | if (dev_priv->panel_fixed_mode) { |
| 520 | dev_priv->panel_fixed_mode->type |= | 520 | dev_priv->panel_fixed_mode->type |= |
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 9913651c1e17..f3ef6bfd8ffc 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
| @@ -69,6 +69,10 @@ struct intel_sdvo_priv { | |||
| 69 | * This is set if we treat the device as HDMI, instead of DVI. | 69 | * This is set if we treat the device as HDMI, instead of DVI. |
| 70 | */ | 70 | */ |
| 71 | bool is_hdmi; | 71 | bool is_hdmi; |
| 72 | /** | ||
| 73 | * This is set if we detect output of sdvo device as LVDS. | ||
| 74 | */ | ||
| 75 | bool is_lvds; | ||
| 72 | 76 | ||
| 73 | /** | 77 | /** |
| 74 | * Returned SDTV resolutions allowed for the current format, if the | 78 | * Returned SDTV resolutions allowed for the current format, if the |
| @@ -1398,10 +1402,8 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect | |||
| 1398 | static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) | 1402 | static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) |
| 1399 | { | 1403 | { |
| 1400 | struct intel_output *intel_output = to_intel_output(connector); | 1404 | struct intel_output *intel_output = to_intel_output(connector); |
| 1401 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
| 1402 | 1405 | ||
| 1403 | /* set the bus switch and get the modes */ | 1406 | /* set the bus switch and get the modes */ |
| 1404 | intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus); | ||
| 1405 | intel_ddc_get_modes(intel_output); | 1407 | intel_ddc_get_modes(intel_output); |
| 1406 | 1408 | ||
| 1407 | #if 0 | 1409 | #if 0 |
| @@ -1543,6 +1545,37 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) | |||
| 1543 | } | 1545 | } |
| 1544 | } | 1546 | } |
| 1545 | 1547 | ||
| 1548 | static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) | ||
| 1549 | { | ||
| 1550 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 1551 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
| 1552 | struct drm_i915_private *dev_priv = connector->dev->dev_private; | ||
| 1553 | |||
| 1554 | /* | ||
| 1555 | * Attempt to get the mode list from DDC. | ||
| 1556 | * Assume that the preferred modes are | ||
| 1557 | * arranged in priority order. | ||
| 1558 | */ | ||
| 1559 | /* set the bus switch and get the modes */ | ||
| 1560 | intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus); | ||
| 1561 | intel_ddc_get_modes(intel_output); | ||
| 1562 | if (list_empty(&connector->probed_modes) == false) | ||
| 1563 | return; | ||
| 1564 | |||
| 1565 | /* Fetch modes from VBT */ | ||
| 1566 | if (dev_priv->sdvo_lvds_vbt_mode != NULL) { | ||
| 1567 | struct drm_display_mode *newmode; | ||
| 1568 | newmode = drm_mode_duplicate(connector->dev, | ||
| 1569 | dev_priv->sdvo_lvds_vbt_mode); | ||
| 1570 | if (newmode != NULL) { | ||
| 1571 | /* Guarantee the mode is preferred */ | ||
| 1572 | newmode->type = (DRM_MODE_TYPE_PREFERRED | | ||
| 1573 | DRM_MODE_TYPE_DRIVER); | ||
| 1574 | drm_mode_probed_add(connector, newmode); | ||
| 1575 | } | ||
| 1576 | } | ||
| 1577 | } | ||
| 1578 | |||
| 1546 | static int intel_sdvo_get_modes(struct drm_connector *connector) | 1579 | static int intel_sdvo_get_modes(struct drm_connector *connector) |
| 1547 | { | 1580 | { |
| 1548 | struct intel_output *output = to_intel_output(connector); | 1581 | struct intel_output *output = to_intel_output(connector); |
| @@ -1550,6 +1583,8 @@ static int intel_sdvo_get_modes(struct drm_connector *connector) | |||
| 1550 | 1583 | ||
| 1551 | if (sdvo_priv->is_tv) | 1584 | if (sdvo_priv->is_tv) |
| 1552 | intel_sdvo_get_tv_modes(connector); | 1585 | intel_sdvo_get_tv_modes(connector); |
| 1586 | else if (sdvo_priv->is_lvds == true) | ||
| 1587 | intel_sdvo_get_lvds_modes(connector); | ||
| 1553 | else | 1588 | else |
| 1554 | intel_sdvo_get_ddc_modes(connector); | 1589 | intel_sdvo_get_ddc_modes(connector); |
| 1555 | 1590 | ||
| @@ -1564,6 +1599,9 @@ static void intel_sdvo_destroy(struct drm_connector *connector) | |||
| 1564 | 1599 | ||
| 1565 | if (intel_output->i2c_bus) | 1600 | if (intel_output->i2c_bus) |
| 1566 | intel_i2c_destroy(intel_output->i2c_bus); | 1601 | intel_i2c_destroy(intel_output->i2c_bus); |
| 1602 | if (intel_output->ddc_bus) | ||
| 1603 | intel_i2c_destroy(intel_output->ddc_bus); | ||
| 1604 | |||
| 1567 | drm_sysfs_connector_remove(connector); | 1605 | drm_sysfs_connector_remove(connector); |
| 1568 | drm_connector_cleanup(connector); | 1606 | drm_connector_cleanup(connector); |
| 1569 | kfree(intel_output); | 1607 | kfree(intel_output); |
| @@ -1660,12 +1698,56 @@ intel_sdvo_get_digital_encoding_mode(struct intel_output *output) | |||
| 1660 | return true; | 1698 | return true; |
| 1661 | } | 1699 | } |
| 1662 | 1700 | ||
| 1701 | static struct intel_output * | ||
| 1702 | intel_sdvo_chan_to_intel_output(struct intel_i2c_chan *chan) | ||
| 1703 | { | ||
| 1704 | struct drm_device *dev = chan->drm_dev; | ||
| 1705 | struct drm_connector *connector; | ||
| 1706 | struct intel_output *intel_output = NULL; | ||
| 1707 | |||
| 1708 | list_for_each_entry(connector, | ||
| 1709 | &dev->mode_config.connector_list, head) { | ||
| 1710 | if (to_intel_output(connector)->ddc_bus == chan) { | ||
| 1711 | intel_output = to_intel_output(connector); | ||
| 1712 | break; | ||
| 1713 | } | ||
| 1714 | } | ||
| 1715 | return intel_output; | ||
| 1716 | } | ||
| 1717 | |||
| 1718 | static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, | ||
| 1719 | struct i2c_msg msgs[], int num) | ||
| 1720 | { | ||
| 1721 | struct intel_output *intel_output; | ||
| 1722 | struct intel_sdvo_priv *sdvo_priv; | ||
| 1723 | struct i2c_algo_bit_data *algo_data; | ||
| 1724 | struct i2c_algorithm *algo; | ||
| 1725 | |||
| 1726 | algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data; | ||
| 1727 | intel_output = | ||
| 1728 | intel_sdvo_chan_to_intel_output( | ||
| 1729 | (struct intel_i2c_chan *)(algo_data->data)); | ||
| 1730 | if (intel_output == NULL) | ||
| 1731 | return -EINVAL; | ||
| 1732 | |||
| 1733 | sdvo_priv = intel_output->dev_priv; | ||
| 1734 | algo = (struct i2c_algorithm *)intel_output->i2c_bus->adapter.algo; | ||
| 1735 | |||
| 1736 | intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus); | ||
| 1737 | return algo->master_xfer(i2c_adap, msgs, num); | ||
| 1738 | } | ||
| 1739 | |||
| 1740 | static struct i2c_algorithm intel_sdvo_i2c_bit_algo = { | ||
| 1741 | .master_xfer = intel_sdvo_master_xfer, | ||
| 1742 | }; | ||
| 1743 | |||
| 1663 | bool intel_sdvo_init(struct drm_device *dev, int output_device) | 1744 | bool intel_sdvo_init(struct drm_device *dev, int output_device) |
| 1664 | { | 1745 | { |
| 1665 | struct drm_connector *connector; | 1746 | struct drm_connector *connector; |
| 1666 | struct intel_output *intel_output; | 1747 | struct intel_output *intel_output; |
| 1667 | struct intel_sdvo_priv *sdvo_priv; | 1748 | struct intel_sdvo_priv *sdvo_priv; |
| 1668 | struct intel_i2c_chan *i2cbus = NULL; | 1749 | struct intel_i2c_chan *i2cbus = NULL; |
| 1750 | struct intel_i2c_chan *ddcbus = NULL; | ||
| 1669 | int connector_type; | 1751 | int connector_type; |
| 1670 | u8 ch[0x40]; | 1752 | u8 ch[0x40]; |
| 1671 | int i; | 1753 | int i; |
| @@ -1676,17 +1758,9 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
| 1676 | return false; | 1758 | return false; |
| 1677 | } | 1759 | } |
| 1678 | 1760 | ||
| 1679 | connector = &intel_output->base; | ||
| 1680 | |||
| 1681 | drm_connector_init(dev, connector, &intel_sdvo_connector_funcs, | ||
| 1682 | DRM_MODE_CONNECTOR_Unknown); | ||
| 1683 | drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); | ||
| 1684 | sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); | 1761 | sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); |
| 1685 | intel_output->type = INTEL_OUTPUT_SDVO; | 1762 | intel_output->type = INTEL_OUTPUT_SDVO; |
| 1686 | 1763 | ||
| 1687 | connector->interlace_allowed = 0; | ||
| 1688 | connector->doublescan_allowed = 0; | ||
| 1689 | |||
| 1690 | /* setup the DDC bus. */ | 1764 | /* setup the DDC bus. */ |
| 1691 | if (output_device == SDVOB) | 1765 | if (output_device == SDVOB) |
| 1692 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB"); | 1766 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB"); |
| @@ -1694,7 +1768,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
| 1694 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); | 1768 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); |
| 1695 | 1769 | ||
| 1696 | if (!i2cbus) | 1770 | if (!i2cbus) |
| 1697 | goto err_connector; | 1771 | goto err_inteloutput; |
| 1698 | 1772 | ||
| 1699 | sdvo_priv->i2c_bus = i2cbus; | 1773 | sdvo_priv->i2c_bus = i2cbus; |
| 1700 | 1774 | ||
| @@ -1710,7 +1784,6 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
| 1710 | intel_output->i2c_bus = i2cbus; | 1784 | intel_output->i2c_bus = i2cbus; |
| 1711 | intel_output->dev_priv = sdvo_priv; | 1785 | intel_output->dev_priv = sdvo_priv; |
| 1712 | 1786 | ||
| 1713 | |||
| 1714 | /* Read the regs to test if we can talk to the device */ | 1787 | /* Read the regs to test if we can talk to the device */ |
| 1715 | for (i = 0; i < 0x40; i++) { | 1788 | for (i = 0; i < 0x40; i++) { |
| 1716 | if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) { | 1789 | if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) { |
| @@ -1720,6 +1793,22 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
| 1720 | } | 1793 | } |
| 1721 | } | 1794 | } |
| 1722 | 1795 | ||
| 1796 | /* setup the DDC bus. */ | ||
| 1797 | if (output_device == SDVOB) | ||
| 1798 | ddcbus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS"); | ||
| 1799 | else | ||
| 1800 | ddcbus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS"); | ||
| 1801 | |||
| 1802 | if (ddcbus == NULL) | ||
| 1803 | goto err_i2c; | ||
| 1804 | |||
| 1805 | intel_sdvo_i2c_bit_algo.functionality = | ||
| 1806 | intel_output->i2c_bus->adapter.algo->functionality; | ||
| 1807 | ddcbus->adapter.algo = &intel_sdvo_i2c_bit_algo; | ||
| 1808 | intel_output->ddc_bus = ddcbus; | ||
| 1809 | |||
| 1810 | /* In defaut case sdvo lvds is false */ | ||
| 1811 | sdvo_priv->is_lvds = false; | ||
| 1723 | intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps); | 1812 | intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps); |
| 1724 | 1813 | ||
| 1725 | if (sdvo_priv->caps.output_flags & | 1814 | if (sdvo_priv->caps.output_flags & |
| @@ -1729,7 +1818,6 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
| 1729 | else | 1818 | else |
| 1730 | sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1; | 1819 | sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1; |
| 1731 | 1820 | ||
| 1732 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
| 1733 | encoder_type = DRM_MODE_ENCODER_TMDS; | 1821 | encoder_type = DRM_MODE_ENCODER_TMDS; |
| 1734 | connector_type = DRM_MODE_CONNECTOR_DVID; | 1822 | connector_type = DRM_MODE_CONNECTOR_DVID; |
| 1735 | 1823 | ||
| @@ -1747,7 +1835,6 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
| 1747 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_SVID0) | 1835 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_SVID0) |
| 1748 | { | 1836 | { |
| 1749 | sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0; | 1837 | sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0; |
| 1750 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
| 1751 | encoder_type = DRM_MODE_ENCODER_TVDAC; | 1838 | encoder_type = DRM_MODE_ENCODER_TVDAC; |
| 1752 | connector_type = DRM_MODE_CONNECTOR_SVIDEO; | 1839 | connector_type = DRM_MODE_CONNECTOR_SVIDEO; |
| 1753 | sdvo_priv->is_tv = true; | 1840 | sdvo_priv->is_tv = true; |
| @@ -1756,30 +1843,28 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
| 1756 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) | 1843 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) |
| 1757 | { | 1844 | { |
| 1758 | sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0; | 1845 | sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0; |
| 1759 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
| 1760 | encoder_type = DRM_MODE_ENCODER_DAC; | 1846 | encoder_type = DRM_MODE_ENCODER_DAC; |
| 1761 | connector_type = DRM_MODE_CONNECTOR_VGA; | 1847 | connector_type = DRM_MODE_CONNECTOR_VGA; |
| 1762 | } | 1848 | } |
| 1763 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) | 1849 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) |
| 1764 | { | 1850 | { |
| 1765 | sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1; | 1851 | sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1; |
| 1766 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
| 1767 | encoder_type = DRM_MODE_ENCODER_DAC; | 1852 | encoder_type = DRM_MODE_ENCODER_DAC; |
| 1768 | connector_type = DRM_MODE_CONNECTOR_VGA; | 1853 | connector_type = DRM_MODE_CONNECTOR_VGA; |
| 1769 | } | 1854 | } |
| 1770 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS0) | 1855 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS0) |
| 1771 | { | 1856 | { |
| 1772 | sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0; | 1857 | sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0; |
| 1773 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
| 1774 | encoder_type = DRM_MODE_ENCODER_LVDS; | 1858 | encoder_type = DRM_MODE_ENCODER_LVDS; |
| 1775 | connector_type = DRM_MODE_CONNECTOR_LVDS; | 1859 | connector_type = DRM_MODE_CONNECTOR_LVDS; |
| 1860 | sdvo_priv->is_lvds = true; | ||
| 1776 | } | 1861 | } |
| 1777 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS1) | 1862 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS1) |
| 1778 | { | 1863 | { |
| 1779 | sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1; | 1864 | sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1; |
| 1780 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
| 1781 | encoder_type = DRM_MODE_ENCODER_LVDS; | 1865 | encoder_type = DRM_MODE_ENCODER_LVDS; |
| 1782 | connector_type = DRM_MODE_CONNECTOR_LVDS; | 1866 | connector_type = DRM_MODE_CONNECTOR_LVDS; |
| 1867 | sdvo_priv->is_lvds = true; | ||
| 1783 | } | 1868 | } |
| 1784 | else | 1869 | else |
| 1785 | { | 1870 | { |
| @@ -1795,9 +1880,16 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
| 1795 | goto err_i2c; | 1880 | goto err_i2c; |
| 1796 | } | 1881 | } |
| 1797 | 1882 | ||
| 1883 | connector = &intel_output->base; | ||
| 1884 | drm_connector_init(dev, connector, &intel_sdvo_connector_funcs, | ||
| 1885 | connector_type); | ||
| 1886 | drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); | ||
| 1887 | connector->interlace_allowed = 0; | ||
| 1888 | connector->doublescan_allowed = 0; | ||
| 1889 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
| 1890 | |||
| 1798 | drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type); | 1891 | drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type); |
| 1799 | drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs); | 1892 | drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs); |
| 1800 | connector->connector_type = connector_type; | ||
| 1801 | 1893 | ||
| 1802 | drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); | 1894 | drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); |
| 1803 | drm_sysfs_connector_add(connector); | 1895 | drm_sysfs_connector_add(connector); |
| @@ -1829,14 +1921,13 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
| 1829 | sdvo_priv->caps.output_flags & | 1921 | sdvo_priv->caps.output_flags & |
| 1830 | (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); | 1922 | (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); |
| 1831 | 1923 | ||
| 1832 | intel_output->ddc_bus = i2cbus; | ||
| 1833 | |||
| 1834 | return true; | 1924 | return true; |
| 1835 | 1925 | ||
| 1836 | err_i2c: | 1926 | err_i2c: |
| 1927 | if (ddcbus != NULL) | ||
| 1928 | intel_i2c_destroy(intel_output->ddc_bus); | ||
| 1837 | intel_i2c_destroy(intel_output->i2c_bus); | 1929 | intel_i2c_destroy(intel_output->i2c_bus); |
| 1838 | err_connector: | 1930 | err_inteloutput: |
| 1839 | drm_connector_cleanup(connector); | ||
| 1840 | kfree(intel_output); | 1931 | kfree(intel_output); |
| 1841 | 1932 | ||
| 1842 | return false; | 1933 | return false; |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index c8c422151431..b84d8ae35e6f 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
| @@ -1519,6 +1519,30 @@ static __inline__ void *drm_calloc(size_t nmemb, size_t size, int area) | |||
| 1519 | { | 1519 | { |
| 1520 | return kcalloc(nmemb, size, GFP_KERNEL); | 1520 | return kcalloc(nmemb, size, GFP_KERNEL); |
| 1521 | } | 1521 | } |
| 1522 | |||
| 1523 | static __inline__ void *drm_calloc_large(size_t nmemb, size_t size) | ||
| 1524 | { | ||
| 1525 | u8 *addr; | ||
| 1526 | |||
| 1527 | if (size <= PAGE_SIZE) | ||
| 1528 | return kcalloc(nmemb, size, GFP_KERNEL); | ||
| 1529 | |||
| 1530 | addr = vmalloc(nmemb * size); | ||
| 1531 | if (!addr) | ||
| 1532 | return NULL; | ||
| 1533 | |||
| 1534 | memset(addr, 0, nmemb * size); | ||
| 1535 | |||
| 1536 | return addr; | ||
| 1537 | } | ||
| 1538 | |||
| 1539 | static __inline void drm_free_large(void *ptr) | ||
| 1540 | { | ||
| 1541 | if (!is_vmalloc_addr(ptr)) | ||
| 1542 | return kfree(ptr); | ||
| 1543 | |||
| 1544 | vfree(ptr); | ||
| 1545 | } | ||
| 1522 | #else | 1546 | #else |
| 1523 | extern void *drm_alloc(size_t size, int area); | 1547 | extern void *drm_alloc(size_t size, int area); |
| 1524 | extern void drm_free(void *pt, size_t size, int area); | 1548 | extern void drm_free(void *pt, size_t size, int area); |
