diff options
Diffstat (limited to 'drivers/video/intelfb/intelfbdrv.c')
-rw-r--r-- | drivers/video/intelfb/intelfbdrv.c | 85 |
1 files changed, 69 insertions, 16 deletions
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 995b47c165a7..076fa56be192 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c | |||
@@ -1,11 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * intelfb | 2 | * intelfb |
3 | * | 3 | * |
4 | * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM | 4 | * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/ |
5 | * integrated graphics chips. | 5 | * 945G/945GM integrated graphics chips. |
6 | * | 6 | * |
7 | * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org> | 7 | * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org> |
8 | * 2004 Sylvain Meyer | 8 | * 2004 Sylvain Meyer |
9 | * 2006 David Airlie | ||
9 | * | 10 | * |
10 | * This driver consists of two parts. The first part (intelfbdrv.c) provides | 11 | * This driver consists of two parts. The first part (intelfbdrv.c) provides |
11 | * the basic fbdev interfaces, is derived in part from the radeonfb and | 12 | * the basic fbdev interfaces, is derived in part from the radeonfb and |
@@ -131,6 +132,7 @@ | |||
131 | 132 | ||
132 | #include "intelfb.h" | 133 | #include "intelfb.h" |
133 | #include "intelfbhw.h" | 134 | #include "intelfbhw.h" |
135 | #include "../edid.h" | ||
134 | 136 | ||
135 | static void __devinit get_initial_mode(struct intelfb_info *dinfo); | 137 | static void __devinit get_initial_mode(struct intelfb_info *dinfo); |
136 | static void update_dinfo(struct intelfb_info *dinfo, | 138 | static void update_dinfo(struct intelfb_info *dinfo, |
@@ -182,6 +184,8 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = { | |||
182 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G }, | 184 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G }, |
183 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G }, | 185 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G }, |
184 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM }, | 186 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM }, |
187 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G }, | ||
188 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM }, | ||
185 | { 0, } | 189 | { 0, } |
186 | }; | 190 | }; |
187 | 191 | ||
@@ -261,7 +265,7 @@ MODULE_PARM_DESC(mode, | |||
261 | 265 | ||
262 | #ifndef MODULE | 266 | #ifndef MODULE |
263 | #define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name))) | 267 | #define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name))) |
264 | #define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name), NULL, 0) | 268 | #define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name) + 1, NULL, 0) |
265 | #define OPT_STRVAL(opt, name) (opt + strlen(name)) | 269 | #define OPT_STRVAL(opt, name) (opt + strlen(name)) |
266 | 270 | ||
267 | static __inline__ char * | 271 | static __inline__ char * |
@@ -546,11 +550,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
546 | 550 | ||
547 | /* Set base addresses. */ | 551 | /* Set base addresses. */ |
548 | if ((ent->device == PCI_DEVICE_ID_INTEL_915G) || | 552 | if ((ent->device == PCI_DEVICE_ID_INTEL_915G) || |
549 | (ent->device == PCI_DEVICE_ID_INTEL_915GM)) { | 553 | (ent->device == PCI_DEVICE_ID_INTEL_915GM) || |
554 | (ent->device == PCI_DEVICE_ID_INTEL_945G) || | ||
555 | (ent->device == PCI_DEVICE_ID_INTEL_945GM)) { | ||
550 | aperture_bar = 2; | 556 | aperture_bar = 2; |
551 | mmio_bar = 0; | 557 | mmio_bar = 0; |
552 | /* Disable HW cursor on 915G/M (not implemented yet) */ | ||
553 | hwcursor = 0; | ||
554 | } | 558 | } |
555 | dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar); | 559 | dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar); |
556 | dinfo->aperture.size = pci_resource_len(pdev, aperture_bar); | 560 | dinfo->aperture.size = pci_resource_len(pdev, aperture_bar); |
@@ -584,8 +588,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
584 | /* Get the chipset info. */ | 588 | /* Get the chipset info. */ |
585 | dinfo->pci_chipset = pdev->device; | 589 | dinfo->pci_chipset = pdev->device; |
586 | 590 | ||
587 | if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset, | 591 | if (intelfbhw_get_chipset(pdev, dinfo)) { |
588 | &dinfo->mobile)) { | ||
589 | cleanup(dinfo); | 592 | cleanup(dinfo); |
590 | return -ENODEV; | 593 | return -ENODEV; |
591 | } | 594 | } |
@@ -1029,17 +1032,44 @@ intelfb_init_var(struct intelfb_info *dinfo) | |||
1029 | sizeof(struct fb_var_screeninfo)); | 1032 | sizeof(struct fb_var_screeninfo)); |
1030 | msrc = 5; | 1033 | msrc = 5; |
1031 | } else { | 1034 | } else { |
1035 | const u8 *edid_s = fb_firmware_edid(&dinfo->pdev->dev); | ||
1036 | u8 *edid_d = NULL; | ||
1037 | |||
1038 | if (edid_s) { | ||
1039 | edid_d = kmalloc(EDID_LENGTH, GFP_KERNEL); | ||
1040 | |||
1041 | if (edid_d) { | ||
1042 | memcpy(edid_d, edid_s, EDID_LENGTH); | ||
1043 | fb_edid_to_monspecs(edid_d, | ||
1044 | &dinfo->info->monspecs); | ||
1045 | kfree(edid_d); | ||
1046 | } | ||
1047 | } | ||
1048 | |||
1032 | if (mode) { | 1049 | if (mode) { |
1050 | printk("intelfb: Looking for mode in private " | ||
1051 | "database\n"); | ||
1033 | msrc = fb_find_mode(var, dinfo->info, mode, | 1052 | msrc = fb_find_mode(var, dinfo->info, mode, |
1034 | vesa_modes, VESA_MODEDB_SIZE, | 1053 | dinfo->info->monspecs.modedb, |
1054 | dinfo->info->monspecs.modedb_len, | ||
1035 | NULL, 0); | 1055 | NULL, 0); |
1036 | if (msrc) | 1056 | |
1037 | msrc |= 8; | 1057 | if (msrc && msrc > 1) { |
1058 | printk("intelfb: No mode in private database, " | ||
1059 | "intelfb: looking for mode in global " | ||
1060 | "database "); | ||
1061 | msrc = fb_find_mode(var, dinfo->info, mode, | ||
1062 | NULL, 0, NULL, 0); | ||
1063 | |||
1064 | if (msrc) | ||
1065 | msrc |= 8; | ||
1066 | } | ||
1067 | |||
1038 | } | 1068 | } |
1069 | |||
1039 | if (!msrc) { | 1070 | if (!msrc) { |
1040 | msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE, | 1071 | msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE, |
1041 | vesa_modes, VESA_MODEDB_SIZE, | 1072 | NULL, 0, NULL, 0); |
1042 | NULL, 0); | ||
1043 | } | 1073 | } |
1044 | } | 1074 | } |
1045 | 1075 | ||
@@ -1139,7 +1169,10 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var) | |||
1139 | } | 1169 | } |
1140 | 1170 | ||
1141 | /* Make sure the line length is a aligned correctly. */ | 1171 | /* Make sure the line length is a aligned correctly. */ |
1142 | dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT); | 1172 | if (IS_I9XX(dinfo)) |
1173 | dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT_I9XX); | ||
1174 | else | ||
1175 | dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT); | ||
1143 | 1176 | ||
1144 | if (FIXED_MODE(dinfo)) | 1177 | if (FIXED_MODE(dinfo)) |
1145 | dinfo->pitch = dinfo->initial_pitch; | 1178 | dinfo->pitch = dinfo->initial_pitch; |
@@ -1162,16 +1195,33 @@ intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
1162 | struct fb_var_screeninfo v; | 1195 | struct fb_var_screeninfo v; |
1163 | struct intelfb_info *dinfo; | 1196 | struct intelfb_info *dinfo; |
1164 | static int first = 1; | 1197 | static int first = 1; |
1198 | int i; | ||
1199 | /* Good pitches to allow tiling. Don't care about pitches < 1024. */ | ||
1200 | static const int pitches[] = { | ||
1201 | 128 * 8, | ||
1202 | 128 * 16, | ||
1203 | 128 * 32, | ||
1204 | 128 * 64, | ||
1205 | 0 | ||
1206 | }; | ||
1165 | 1207 | ||
1166 | DBG_MSG("intelfb_check_var: accel_flags is %d\n", var->accel_flags); | 1208 | DBG_MSG("intelfb_check_var: accel_flags is %d\n", var->accel_flags); |
1167 | 1209 | ||
1168 | dinfo = GET_DINFO(info); | 1210 | dinfo = GET_DINFO(info); |
1169 | 1211 | ||
1212 | /* update the pitch */ | ||
1170 | if (intelfbhw_validate_mode(dinfo, var) != 0) | 1213 | if (intelfbhw_validate_mode(dinfo, var) != 0) |
1171 | return -EINVAL; | 1214 | return -EINVAL; |
1172 | 1215 | ||
1173 | v = *var; | 1216 | v = *var; |
1174 | 1217 | ||
1218 | for (i = 0; pitches[i] != 0; i++) { | ||
1219 | if (pitches[i] >= v.xres_virtual) { | ||
1220 | v.xres_virtual = pitches[i]; | ||
1221 | break; | ||
1222 | } | ||
1223 | } | ||
1224 | |||
1175 | /* Check for a supported bpp. */ | 1225 | /* Check for a supported bpp. */ |
1176 | if (v.bits_per_pixel <= 8) { | 1226 | if (v.bits_per_pixel <= 8) { |
1177 | v.bits_per_pixel = 8; | 1227 | v.bits_per_pixel = 8; |
@@ -1467,7 +1517,7 @@ static int | |||
1467 | intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | 1517 | intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) |
1468 | { | 1518 | { |
1469 | struct intelfb_info *dinfo = GET_DINFO(info); | 1519 | struct intelfb_info *dinfo = GET_DINFO(info); |
1470 | 1520 | u32 physical; | |
1471 | #if VERBOSE > 0 | 1521 | #if VERBOSE > 0 |
1472 | DBG_MSG("intelfb_cursor\n"); | 1522 | DBG_MSG("intelfb_cursor\n"); |
1473 | #endif | 1523 | #endif |
@@ -1478,7 +1528,10 @@ intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
1478 | intelfbhw_cursor_hide(dinfo); | 1528 | intelfbhw_cursor_hide(dinfo); |
1479 | 1529 | ||
1480 | /* If XFree killed the cursor - restore it */ | 1530 | /* If XFree killed the cursor - restore it */ |
1481 | if (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.offset << 12) { | 1531 | physical = (dinfo->mobile || IS_I9XX(dinfo)) ? dinfo->cursor.physical : |
1532 | (dinfo->cursor.offset << 12); | ||
1533 | |||
1534 | if (INREG(CURSOR_A_BASEADDR) != physical) { | ||
1482 | u32 fg, bg; | 1535 | u32 fg, bg; |
1483 | 1536 | ||
1484 | DBG_MSG("the cursor was killed - restore it !!\n"); | 1537 | DBG_MSG("the cursor was killed - restore it !!\n"); |