816 lines · c
1/*2 * linux/drivers/video/kyro/fbdev.c3 *4 * Copyright (C) 2002 STMicroelectronics5 * Copyright (C) 2003, 2004 Paul Mundt6 *7 * This file is subject to the terms and conditions of the GNU General Public8 * License. See the file COPYING in the main directory of this archive9 * for more details.10 */11 12#include <linux/aperture.h>13#include <linux/module.h>14#include <linux/types.h>15#include <linux/kernel.h>16#include <linux/mm.h>17#include <linux/errno.h>18#include <linux/string.h>19#include <linux/delay.h>20#include <linux/fb.h>21#include <linux/ioctl.h>22#include <linux/init.h>23#include <linux/pci.h>24#include <asm/io.h>25#include <linux/uaccess.h>26 27#include <video/kyro.h>28 29#include "STG4000Reg.h"30#include "STG4000Interface.h"31 32/*33 * PCI Definitions34 */35#define PCI_VENDOR_ID_ST 0x104a36#define PCI_DEVICE_ID_STG4000 0x001037 38#define KHZ2PICOS(a) (1000000000UL/(a))39 40/****************************************************************************/41static struct fb_fix_screeninfo kyro_fix = {42 .id = "ST Kyro",43 .type = FB_TYPE_PACKED_PIXELS,44 .visual = FB_VISUAL_TRUECOLOR,45 .accel = FB_ACCEL_NONE,46};47 48static const struct fb_var_screeninfo kyro_var = {49 /* 640x480, 16bpp @ 60 Hz */50 .xres = 640,51 .yres = 480,52 .xres_virtual = 640,53 .yres_virtual = 480,54 .bits_per_pixel = 16,55 .red = { 11, 5, 0 },56 .green = { 5, 6, 0 },57 .blue = { 0, 5, 0 },58 .activate = FB_ACTIVATE_NOW,59 .height = -1,60 .width = -1,61 .pixclock = KHZ2PICOS(25175),62 .left_margin = 48,63 .right_margin = 16,64 .upper_margin = 33,65 .lower_margin = 10,66 .hsync_len = 96,67 .vsync_len = 2,68 .vmode = FB_VMODE_NONINTERLACED,69};70 71typedef struct {72 STG4000REG __iomem *pSTGReg; /* Virtual address of PCI register region */73 u32 ulNextFreeVidMem; /* Offset from start of vid mem to next free region */74 u32 ulOverlayOffset; /* Offset from start of vid mem to overlay */75 u32 ulOverlayStride; /* Interleaved YUV and 422 mode Y stride */76 u32 ulOverlayUVStride; /* 422 mode U & V stride */77} device_info_t;78 79/* global graphics card info structure (one per card) */80static device_info_t deviceInfo;81 82static char *mode_option = NULL;83static int nopan = 0;84static int nowrap = 1;85static int nomtrr = 0;86 87/* PCI driver prototypes */88static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent);89static void kyrofb_remove(struct pci_dev *pdev);90 91static struct fb_videomode kyro_modedb[] = {92 {93 /* 640x350 @ 85Hz */94 NULL, 85, 640, 350, KHZ2PICOS(31500),95 96, 32, 60, 32, 64, 3,96 FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED97 }, {98 /* 640x400 @ 85Hz */99 NULL, 85, 640, 400, KHZ2PICOS(31500),100 96, 32, 41, 1, 64, 3,101 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED102 }, {103 /* 720x400 @ 85Hz */104 NULL, 85, 720, 400, KHZ2PICOS(35500),105 108, 36, 42, 1, 72, 3,106 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED107 }, {108 /* 640x480 @ 60Hz */109 NULL, 60, 640, 480, KHZ2PICOS(25175),110 48, 16, 33, 10, 96, 2,111 0, FB_VMODE_NONINTERLACED112 }, {113 /* 640x480 @ 72Hz */114 NULL, 72, 640, 480, KHZ2PICOS(31500),115 128, 24, 28, 9, 40, 3,116 0, FB_VMODE_NONINTERLACED117 }, {118 /* 640x480 @ 75Hz */119 NULL, 75, 640, 480, KHZ2PICOS(31500),120 120, 16, 16, 1, 64, 3,121 0, FB_VMODE_NONINTERLACED122 }, {123 /* 640x480 @ 85Hz */124 NULL, 85, 640, 480, KHZ2PICOS(36000),125 80, 56, 25, 1, 56, 3,126 0, FB_VMODE_NONINTERLACED127 }, {128 /* 800x600 @ 56Hz */129 NULL, 56, 800, 600, KHZ2PICOS(36000),130 128, 24, 22, 1, 72, 2,131 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED132 }, {133 /* 800x600 @ 60Hz */134 NULL, 60, 800, 600, KHZ2PICOS(40000),135 88, 40, 23, 1, 128, 4,136 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED137 }, {138 /* 800x600 @ 72Hz */139 NULL, 72, 800, 600, KHZ2PICOS(50000),140 64, 56, 23, 37, 120, 6,141 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED142 }, {143 /* 800x600 @ 75Hz */144 NULL, 75, 800, 600, KHZ2PICOS(49500),145 160, 16, 21, 1, 80, 3,146 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED147 }, {148 /* 800x600 @ 85Hz */149 NULL, 85, 800, 600, KHZ2PICOS(56250),150 152, 32, 27, 1, 64, 3,151 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED152 }, {153 /* 1024x768 @ 60Hz */154 NULL, 60, 1024, 768, KHZ2PICOS(65000),155 160, 24, 29, 3, 136, 6,156 0, FB_VMODE_NONINTERLACED157 }, {158 /* 1024x768 @ 70Hz */159 NULL, 70, 1024, 768, KHZ2PICOS(75000),160 144, 24, 29, 3, 136, 6,161 0, FB_VMODE_NONINTERLACED162 }, {163 /* 1024x768 @ 75Hz */164 NULL, 75, 1024, 768, KHZ2PICOS(78750),165 176, 16, 28, 1, 96, 3,166 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED167 }, {168 /* 1024x768 @ 85Hz */169 NULL, 85, 1024, 768, KHZ2PICOS(94500),170 208, 48, 36, 1, 96, 3,171 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED172 }, {173 /* 1152x864 @ 75Hz */174 NULL, 75, 1152, 864, KHZ2PICOS(108000),175 256, 64, 32, 1, 128, 3,176 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED177 }, {178 /* 1280x960 @ 60Hz */179 NULL, 60, 1280, 960, KHZ2PICOS(108000),180 312, 96, 36, 1, 112, 3,181 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED182 }, {183 /* 1280x960 @ 85Hz */184 NULL, 85, 1280, 960, KHZ2PICOS(148500),185 224, 64, 47, 1, 160, 3,186 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED187 }, {188 /* 1280x1024 @ 60Hz */189 NULL, 60, 1280, 1024, KHZ2PICOS(108000),190 248, 48, 38, 1, 112, 3,191 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED192 }, {193 /* 1280x1024 @ 75Hz */194 NULL, 75, 1280, 1024, KHZ2PICOS(135000),195 248, 16, 38, 1, 144, 3,196 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED197 }, {198 /* 1280x1024 @ 85Hz */199 NULL, 85, 1280, 1024, KHZ2PICOS(157500),200 224, 64, 44, 1, 160, 3,201 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED202 }, {203 /* 1600x1200 @ 60Hz */204 NULL, 60, 1600, 1200, KHZ2PICOS(162000),205 304, 64, 46, 1, 192, 3,206 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED207 }, {208 /* 1600x1200 @ 65Hz */209 NULL, 65, 1600, 1200, KHZ2PICOS(175500),210 304, 64, 46, 1, 192, 3,211 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED212 }, {213 /* 1600x1200 @ 70Hz */214 NULL, 70, 1600, 1200, KHZ2PICOS(189000),215 304, 64, 46, 1, 192, 3,216 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED217 }, {218 /* 1600x1200 @ 75Hz */219 NULL, 75, 1600, 1200, KHZ2PICOS(202500),220 304, 64, 46, 1, 192, 3,221 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED222 }, {223 /* 1600x1200 @ 85Hz */224 NULL, 85, 1600, 1200, KHZ2PICOS(229500),225 304, 64, 46, 1, 192, 3,226 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED227 }, {228 /* 1792x1344 @ 60Hz */229 NULL, 60, 1792, 1344, KHZ2PICOS(204750),230 328, 128, 46, 1, 200, 3,231 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED232 }, {233 /* 1792x1344 @ 75Hz */234 NULL, 75, 1792, 1344, KHZ2PICOS(261000),235 352, 96, 69, 1, 216, 3,236 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED237 }, {238 /* 1856x1392 @ 60Hz */239 NULL, 60, 1856, 1392, KHZ2PICOS(218250),240 352, 96, 43, 1, 224, 3,241 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED242 }, {243 /* 1856x1392 @ 75Hz */244 NULL, 75, 1856, 1392, KHZ2PICOS(288000),245 352, 128, 104, 1, 224, 3,246 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED247 }, {248 /* 1920x1440 @ 60Hz */249 NULL, 60, 1920, 1440, KHZ2PICOS(234000),250 344, 128, 56, 1, 208, 3,251 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED252 }, {253 /* 1920x1440 @ 75Hz */254 NULL, 75, 1920, 1440, KHZ2PICOS(297000),255 352, 144, 56, 1, 224, 3,256 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED257 },258};259#define NUM_TOTAL_MODES ARRAY_SIZE(kyro_modedb)260 261/*262 * This needs to be kept ordered corresponding to kyro_modedb.263 */264enum {265 VMODE_640_350_85,266 VMODE_640_400_85,267 VMODE_720_400_85,268 VMODE_640_480_60,269 VMODE_640_480_72,270 VMODE_640_480_75,271 VMODE_640_480_85,272 VMODE_800_600_56,273 VMODE_800_600_60,274 VMODE_800_600_72,275 VMODE_800_600_75,276 VMODE_800_600_85,277 VMODE_1024_768_60,278 VMODE_1024_768_70,279 VMODE_1024_768_75,280 VMODE_1024_768_85,281 VMODE_1152_864_75,282 VMODE_1280_960_60,283 VMODE_1280_960_85,284 VMODE_1280_1024_60,285 VMODE_1280_1024_75,286 VMODE_1280_1024_85,287 VMODE_1600_1200_60,288 VMODE_1600_1200_65,289 VMODE_1600_1200_70,290 VMODE_1600_1200_75,291 VMODE_1600_1200_85,292 VMODE_1792_1344_60,293 VMODE_1792_1344_75,294 VMODE_1856_1392_60,295 VMODE_1856_1392_75,296 VMODE_1920_1440_60,297 VMODE_1920_1440_75,298};299 300/* Accessors */301static int kyro_dev_video_mode_set(struct fb_info *info)302{303 struct kyrofb_info *par = info->par;304 305 /* Turn off display */306 StopVTG(deviceInfo.pSTGReg);307 DisableRamdacOutput(deviceInfo.pSTGReg);308 309 /* Bring us out of VGA and into Hi-Res mode, if not already. */310 DisableVGA(deviceInfo.pSTGReg);311 312 if (InitialiseRamdac(deviceInfo.pSTGReg,313 info->var.bits_per_pixel,314 info->var.xres, info->var.yres,315 par->HSP, par->VSP, &par->PIXCLK) < 0)316 return -EINVAL;317 318 SetupVTG(deviceInfo.pSTGReg, par);319 320 ResetOverlayRegisters(deviceInfo.pSTGReg);321 322 /* Turn on display in new mode */323 EnableRamdacOutput(deviceInfo.pSTGReg);324 StartVTG(deviceInfo.pSTGReg);325 326 deviceInfo.ulNextFreeVidMem = info->var.xres * info->var.yres *327 info->var.bits_per_pixel;328 deviceInfo.ulOverlayOffset = 0;329 330 return 0;331}332 333static int kyro_dev_overlay_create(u32 ulWidth,334 u32 ulHeight, int bLinear)335{336 u32 offset;337 u32 stride, uvStride;338 339 if (deviceInfo.ulOverlayOffset != 0)340 /*341 * Can only create one overlay without resetting the card or342 * changing display mode343 */344 return -EINVAL;345 346 ResetOverlayRegisters(deviceInfo.pSTGReg);347 348 /* Overlays are addressed in multiples of 16bytes or 32bytes, so make349 * sure the start offset is on an appropriate boundary.350 */351 offset = deviceInfo.ulNextFreeVidMem;352 if ((offset & 0x1f) != 0) {353 offset = (offset + 32L) & 0xffffffE0L;354 }355 356 if (CreateOverlaySurface(deviceInfo.pSTGReg, ulWidth, ulHeight,357 bLinear, offset, &stride, &uvStride) < 0)358 return -EINVAL;359 360 deviceInfo.ulOverlayOffset = offset;361 deviceInfo.ulOverlayStride = stride;362 deviceInfo.ulOverlayUVStride = uvStride;363 deviceInfo.ulNextFreeVidMem = offset + (ulHeight * stride) + (ulHeight * 2 * uvStride);364 365 SetOverlayBlendMode(deviceInfo.pSTGReg, GLOBAL_ALPHA, 0xf, 0x0);366 367 return 0;368}369 370static int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 ulWidth, u32 ulHeight)371{372 if (deviceInfo.ulOverlayOffset == 0)373 /* probably haven't called CreateOverlay yet */374 return -EINVAL;375 376 if (ulWidth == 0 || ulWidth == 0xffffffff ||377 ulHeight == 0 || ulHeight == 0xffffffff ||378 (x < 2 && ulWidth + 2 == 0))379 return -EINVAL;380 381 /* Stop Ramdac Output */382 DisableRamdacOutput(deviceInfo.pSTGReg);383 384 SetOverlayViewPort(deviceInfo.pSTGReg,385 x, y, x + ulWidth - 1, y + ulHeight - 1);386 387 EnableOverlayPlane(deviceInfo.pSTGReg);388 /* Start Ramdac Output */389 EnableRamdacOutput(deviceInfo.pSTGReg);390 391 return 0;392}393 394static inline unsigned long get_line_length(int x, int bpp)395{396 return (unsigned long)((((x*bpp)+31)&~31) >> 3);397}398 399static int kyrofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)400{401 struct kyrofb_info *par = info->par;402 403 if (!var->pixclock)404 return -EINVAL;405 406 if (var->bits_per_pixel != 16 && var->bits_per_pixel != 32) {407 printk(KERN_WARNING "kyrofb: depth not supported: %u\n", var->bits_per_pixel);408 return -EINVAL;409 }410 411 switch (var->bits_per_pixel) {412 case 16:413 var->red.offset = 11;414 var->red.length = 5;415 var->green.offset = 5;416 var->green.length = 6;417 var->blue.length = 5;418 break;419 case 32:420 var->transp.offset = 24;421 var->red.offset = 16;422 var->green.offset = 8;423 var->blue.offset = 0;424 425 var->red.length = 8;426 var->green.length = 8;427 var->blue.length = 8;428 var->transp.length = 8;429 break;430 }431 432 /* Height/Width of picture in mm */433 var->height = var->width = -1;434 435 /* Timing information. All values are in picoseconds */436 437 /* par->PIXCLK is in 100Hz units. Convert to picoseconds -438 * ensuring we do not exceed 32 bit precision439 */440 /*441 * XXX: Enabling this really screws over the pixclock value when we442 * read it back with fbset. As such, leaving this commented out appears443 * to do the right thing (at least for now) .. bearing in mind that we444 * have infact already done the KHZ2PICOS conversion in both the modedb445 * and kyro_var. -- PFM.446 */447// var->pixclock = 1000000000 / (par->PIXCLK / 10);448 449 /* the header file claims we should use picoseconds450 * - nobody else does though, the all use pixels and lines451 * of h and v sizes. Both options here.452 */453 454 /*455 * If we're being called by __fb_try_mode(), then we don't want to456 * override any of the var settings that we've already parsed457 * from our modedb. -- PFM.458 */459 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)460 return 0;461 462 var->left_margin = par->HBP;463 var->hsync_len = par->HST;464 var->right_margin = par->HFP;465 466 var->upper_margin = par->VBP;467 var->vsync_len = par->VST;468 var->lower_margin = par->VFP;469 470 if (par->HSP == 1)471 var->sync |= FB_SYNC_HOR_HIGH_ACT;472 if (par->VSP == 1)473 var->sync |= FB_SYNC_VERT_HIGH_ACT;474 475 return 0;476}477 478static int kyrofb_set_par(struct fb_info *info)479{480 struct kyrofb_info *par = info->par;481 unsigned long lineclock;482 unsigned long frameclock;483 484 /* Actual resolution */485 par->XRES = info->var.xres;486 par->YRES = info->var.yres;487 488 /* pixel depth */489 par->PIXDEPTH = info->var.bits_per_pixel;490 491 /* Refresh rate */492 /* time for a line in ns */493 lineclock = (info->var.pixclock * (info->var.xres +494 info->var.right_margin +495 info->var.hsync_len +496 info->var.left_margin)) / 1000;497 498 if (!lineclock)499 return -EINVAL;500 501 /* time for a frame in ns (precision in 32bpp) */502 frameclock = lineclock * (info->var.yres +503 info->var.lower_margin +504 info->var.vsync_len +505 info->var.upper_margin);506 507 /* Calculate refresh rate and horrizontal clocks */508 par->VFREQ = (1000000000 + (frameclock / 2)) / frameclock;509 par->HCLK = (1000000000 + (lineclock / 2)) / lineclock;510 par->PIXCLK = ((1000000000 + (info->var.pixclock / 2))511 / info->var.pixclock) * 10;512 513 /* calculate horizontal timings */514 par->HFP = info->var.right_margin;515 par->HST = info->var.hsync_len;516 par->HBP = info->var.left_margin;517 par->HTot = par->XRES + par->HBP + par->HST + par->HFP;518 519 /* calculate vertical timings */520 par->VFP = info->var.lower_margin;521 par->VST = info->var.vsync_len;522 par->VBP = info->var.upper_margin;523 par->VTot = par->YRES + par->VBP + par->VST + par->VFP;524 525 par->HSP = (info->var.sync & FB_SYNC_HOR_HIGH_ACT) ? 1 : 0;526 par->VSP = (info->var.sync & FB_SYNC_VERT_HIGH_ACT) ? 1 : 0;527 528 kyro_dev_video_mode_set(info);529 530 /* length of a line in bytes */531 info->fix.line_length = get_line_length(par->XRES, par->PIXDEPTH);532 info->fix.visual = FB_VISUAL_TRUECOLOR;533 534 return 0;535}536 537static int kyrofb_setcolreg(u_int regno, u_int red, u_int green,538 u_int blue, u_int transp, struct fb_info *info)539{540 struct kyrofb_info *par = info->par;541 542 if (regno > 255)543 return 1; /* Invalid register */544 545 if (regno < 16) {546 switch (info->var.bits_per_pixel) {547 case 16:548 par->palette[regno] =549 (red & 0xf800) |550 ((green & 0xfc00) >> 5) |551 ((blue & 0xf800) >> 11);552 break;553 case 32:554 red >>= 8; green >>= 8; blue >>= 8; transp >>= 8;555 par->palette[regno] =556 (transp << 24) | (red << 16) | (green << 8) | blue;557 break;558 }559 }560 561 return 0;562}563 564#ifndef MODULE565static int __init kyrofb_setup(char *options)566{567 char *this_opt;568 569 if (!options || !*options)570 return 0;571 572 while ((this_opt = strsep(&options, ","))) {573 if (!*this_opt)574 continue;575 if (strcmp(this_opt, "nopan") == 0) {576 nopan = 1;577 } else if (strcmp(this_opt, "nowrap") == 0) {578 nowrap = 1;579 } else if (strcmp(this_opt, "nomtrr") == 0) {580 nomtrr = 1;581 } else {582 mode_option = this_opt;583 }584 }585 586 return 0;587}588#endif589 590static int kyrofb_ioctl(struct fb_info *info,591 unsigned int cmd, unsigned long arg)592{593 overlay_create ol_create;594 overlay_viewport_set ol_viewport_set;595 void __user *argp = (void __user *)arg;596 597 switch (cmd) {598 case KYRO_IOCTL_OVERLAY_CREATE:599 if (copy_from_user(&ol_create, argp, sizeof(overlay_create)))600 return -EFAULT;601 602 if (kyro_dev_overlay_create(ol_create.ulWidth,603 ol_create.ulHeight, 0) < 0) {604 printk(KERN_ERR "Kyro FB: failed to create overlay surface.\n");605 606 return -EINVAL;607 }608 break;609 case KYRO_IOCTL_OVERLAY_VIEWPORT_SET:610 if (copy_from_user(&ol_viewport_set, argp,611 sizeof(overlay_viewport_set)))612 return -EFAULT;613 614 if (kyro_dev_overlay_viewport_set(ol_viewport_set.xOrgin,615 ol_viewport_set.yOrgin,616 ol_viewport_set.xSize,617 ol_viewport_set.ySize) != 0)618 {619 printk(KERN_ERR "Kyro FB: failed to create overlay viewport.\n");620 return -EINVAL;621 }622 break;623 case KYRO_IOCTL_SET_VIDEO_MODE:624 {625 printk(KERN_ERR "Kyro FB: KYRO_IOCTL_SET_VIDEO_MODE is"626 "obsolete, use the appropriate fb_ioctl()"627 "command instead.\n");628 return -EINVAL;629 }630 case KYRO_IOCTL_UVSTRIDE:631 if (copy_to_user(argp, &deviceInfo.ulOverlayUVStride, sizeof(deviceInfo.ulOverlayUVStride)))632 return -EFAULT;633 break;634 case KYRO_IOCTL_STRIDE:635 if (copy_to_user(argp, &deviceInfo.ulOverlayStride, sizeof(deviceInfo.ulOverlayStride)))636 return -EFAULT;637 break;638 case KYRO_IOCTL_OVERLAY_OFFSET:639 if (copy_to_user(argp, &deviceInfo.ulOverlayOffset, sizeof(deviceInfo.ulOverlayOffset)))640 return -EFAULT;641 break;642 }643 644 return 0;645}646 647static const struct pci_device_id kyrofb_pci_tbl[] = {648 { PCI_VENDOR_ID_ST, PCI_DEVICE_ID_STG4000,649 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },650 { 0, }651};652 653MODULE_DEVICE_TABLE(pci, kyrofb_pci_tbl);654 655static struct pci_driver kyrofb_pci_driver = {656 .name = "kyrofb",657 .id_table = kyrofb_pci_tbl,658 .probe = kyrofb_probe,659 .remove = kyrofb_remove,660};661 662static const struct fb_ops kyrofb_ops = {663 .owner = THIS_MODULE,664 FB_DEFAULT_IOMEM_OPS,665 .fb_check_var = kyrofb_check_var,666 .fb_set_par = kyrofb_set_par,667 .fb_setcolreg = kyrofb_setcolreg,668 .fb_ioctl = kyrofb_ioctl,669};670 671static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)672{673 struct fb_info *info;674 struct kyrofb_info *currentpar;675 unsigned long size;676 int err;677 678 err = aperture_remove_conflicting_pci_devices(pdev, "kyrofb");679 if (err)680 return err;681 682 if ((err = pci_enable_device(pdev))) {683 printk(KERN_WARNING "kyrofb: Can't enable pdev: %d\n", err);684 return err;685 }686 687 info = framebuffer_alloc(sizeof(struct kyrofb_info), &pdev->dev);688 if (!info)689 return -ENOMEM;690 691 currentpar = info->par;692 693 kyro_fix.smem_start = pci_resource_start(pdev, 0);694 kyro_fix.smem_len = pci_resource_len(pdev, 0);695 kyro_fix.mmio_start = pci_resource_start(pdev, 1);696 kyro_fix.mmio_len = pci_resource_len(pdev, 1);697 698 currentpar->regbase = deviceInfo.pSTGReg =699 ioremap(kyro_fix.mmio_start, kyro_fix.mmio_len);700 if (!currentpar->regbase)701 goto out_free_fb;702 703 info->screen_base = pci_ioremap_wc_bar(pdev, 0);704 if (!info->screen_base)705 goto out_unmap_regs;706 707 if (!nomtrr)708 currentpar->wc_cookie = arch_phys_wc_add(kyro_fix.smem_start,709 kyro_fix.smem_len);710 711 kyro_fix.ypanstep = nopan ? 0 : 1;712 kyro_fix.ywrapstep = nowrap ? 0 : 1;713 714 info->fbops = &kyrofb_ops;715 info->fix = kyro_fix;716 info->pseudo_palette = currentpar->palette;717 718 SetCoreClockPLL(deviceInfo.pSTGReg, pdev);719 720 deviceInfo.ulNextFreeVidMem = 0;721 deviceInfo.ulOverlayOffset = 0;722 723 /* This should give a reasonable default video mode */724 if (!fb_find_mode(&info->var, info, mode_option, kyro_modedb,725 NUM_TOTAL_MODES, &kyro_modedb[VMODE_1024_768_75], 32))726 info->var = kyro_var;727 728 fb_alloc_cmap(&info->cmap, 256, 0);729 730 kyrofb_set_par(info);731 kyrofb_check_var(&info->var, info);732 733 size = get_line_length(info->var.xres_virtual,734 info->var.bits_per_pixel);735 size *= info->var.yres_virtual;736 737 fb_memset_io(info->screen_base, 0, size);738 739 if (register_framebuffer(info) < 0)740 goto out_unmap;741 742 fb_info(info, "%s frame buffer device, at %dx%d@%d using %ldk/%ldk of VRAM\n",743 info->fix.id,744 info->var.xres, info->var.yres, info->var.bits_per_pixel,745 size >> 10, (unsigned long)info->fix.smem_len >> 10);746 747 pci_set_drvdata(pdev, info);748 749 return 0;750 751out_unmap:752 iounmap(info->screen_base);753out_unmap_regs:754 iounmap(currentpar->regbase);755out_free_fb:756 framebuffer_release(info);757 758 return -EINVAL;759}760 761static void kyrofb_remove(struct pci_dev *pdev)762{763 struct fb_info *info = pci_get_drvdata(pdev);764 struct kyrofb_info *par = info->par;765 766 /* Reset the board */767 StopVTG(deviceInfo.pSTGReg);768 DisableRamdacOutput(deviceInfo.pSTGReg);769 770 /* Sync up the PLL */771 SetCoreClockPLL(deviceInfo.pSTGReg, pdev);772 773 deviceInfo.ulNextFreeVidMem = 0;774 deviceInfo.ulOverlayOffset = 0;775 776 iounmap(info->screen_base);777 iounmap(par->regbase);778 779 arch_phys_wc_del(par->wc_cookie);780 781 unregister_framebuffer(info);782 framebuffer_release(info);783}784 785static int __init kyrofb_init(void)786{787#ifndef MODULE788 char *option = NULL;789#endif790 791 if (fb_modesetting_disabled("kyrofb"))792 return -ENODEV;793 794#ifndef MODULE795 if (fb_get_options("kyrofb", &option))796 return -ENODEV;797 kyrofb_setup(option);798#endif799 return pci_register_driver(&kyrofb_pci_driver);800}801 802static void __exit kyrofb_exit(void)803{804 pci_unregister_driver(&kyrofb_pci_driver);805}806 807module_init(kyrofb_init);808 809#ifdef MODULE810module_exit(kyrofb_exit);811#endif812 813MODULE_AUTHOR("STMicroelectronics; Paul Mundt <lethal@linux-sh.org>");814MODULE_DESCRIPTION("STG4000/Kyro/PowerVR 3 driver");815MODULE_LICENSE("GPL");816