0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #undef DEBUG
0021
0022 #include <linux/module.h>
0023 #include <linux/kernel.h>
0024 #include <linux/errno.h>
0025 #include <linux/string.h>
0026 #include <linux/mm.h>
0027 #include <linux/vmalloc.h>
0028 #include <linux/delay.h>
0029 #include <linux/interrupt.h>
0030 #include <linux/fb.h>
0031 #include <linux/init.h>
0032 #include <linux/nvram.h>
0033 #include <linux/of_address.h>
0034 #include <linux/of_device.h>
0035 #include <linux/of_platform.h>
0036
0037 #include "macmodes.h"
0038 #include "platinumfb.h"
0039
0040 static int default_vmode = VMODE_NVRAM;
0041 static int default_cmode = CMODE_NVRAM;
0042
0043 struct fb_info_platinum {
0044 struct fb_info *info;
0045
0046 int vmode, cmode;
0047 int xres, yres;
0048 int vxres, vyres;
0049 int xoffset, yoffset;
0050
0051 struct {
0052 __u8 red, green, blue;
0053 } palette[256];
0054 u32 pseudo_palette[16];
0055
0056 volatile struct cmap_regs __iomem *cmap_regs;
0057 unsigned long cmap_regs_phys;
0058
0059 volatile struct platinum_regs __iomem *platinum_regs;
0060 unsigned long platinum_regs_phys;
0061
0062 __u8 __iomem *frame_buffer;
0063 volatile __u8 __iomem *base_frame_buffer;
0064 unsigned long frame_buffer_phys;
0065
0066 unsigned long total_vram;
0067 int clktype;
0068 int dactype;
0069
0070 struct resource rsrc_fb, rsrc_reg;
0071 };
0072
0073
0074
0075
0076
0077 static int platinumfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
0078 u_int transp, struct fb_info *info);
0079 static int platinumfb_blank(int blank_mode, struct fb_info *info);
0080 static int platinumfb_set_par (struct fb_info *info);
0081 static int platinumfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info);
0082
0083
0084
0085
0086
0087 static inline int platinum_vram_reqd(int video_mode, int color_mode);
0088 static int read_platinum_sense(struct fb_info_platinum *pinfo);
0089 static void set_platinum_clock(struct fb_info_platinum *pinfo);
0090 static void platinum_set_hardware(struct fb_info_platinum *pinfo);
0091 static int platinum_var_to_par(struct fb_var_screeninfo *var,
0092 struct fb_info_platinum *pinfo,
0093 int check_only);
0094
0095
0096
0097
0098
0099 static const struct fb_ops platinumfb_ops = {
0100 .owner = THIS_MODULE,
0101 .fb_check_var = platinumfb_check_var,
0102 .fb_set_par = platinumfb_set_par,
0103 .fb_setcolreg = platinumfb_setcolreg,
0104 .fb_blank = platinumfb_blank,
0105 .fb_fillrect = cfb_fillrect,
0106 .fb_copyarea = cfb_copyarea,
0107 .fb_imageblit = cfb_imageblit,
0108 };
0109
0110
0111
0112
0113 static int platinumfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info)
0114 {
0115 return platinum_var_to_par(var, info->par, 1);
0116 }
0117
0118
0119
0120
0121 static int platinumfb_set_par (struct fb_info *info)
0122 {
0123 struct fb_info_platinum *pinfo = info->par;
0124 struct platinum_regvals *init;
0125 int err, offset = 0x20;
0126
0127 if((err = platinum_var_to_par(&info->var, pinfo, 0))) {
0128 printk (KERN_ERR "platinumfb_set_par: error calling"
0129 " platinum_var_to_par: %d.\n", err);
0130 return err;
0131 }
0132
0133 platinum_set_hardware(pinfo);
0134
0135 init = platinum_reg_init[pinfo->vmode-1];
0136
0137 if ((pinfo->vmode == VMODE_832_624_75) && (pinfo->cmode > CMODE_8))
0138 offset = 0x10;
0139
0140 info->screen_base = pinfo->frame_buffer + init->fb_offset + offset;
0141 mutex_lock(&info->mm_lock);
0142 info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset;
0143 mutex_unlock(&info->mm_lock);
0144 info->fix.visual = (pinfo->cmode == CMODE_8) ?
0145 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
0146 info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode)
0147 + offset;
0148 printk("line_length: %x\n", info->fix.line_length);
0149 return 0;
0150 }
0151
0152 static int platinumfb_blank(int blank, struct fb_info *fb)
0153 {
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179 return 0;
0180 }
0181
0182 static int platinumfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
0183 u_int transp, struct fb_info *info)
0184 {
0185 struct fb_info_platinum *pinfo = info->par;
0186 volatile struct cmap_regs __iomem *cmap_regs = pinfo->cmap_regs;
0187
0188 if (regno > 255)
0189 return 1;
0190
0191 red >>= 8;
0192 green >>= 8;
0193 blue >>= 8;
0194
0195 pinfo->palette[regno].red = red;
0196 pinfo->palette[regno].green = green;
0197 pinfo->palette[regno].blue = blue;
0198
0199 out_8(&cmap_regs->addr, regno);
0200 out_8(&cmap_regs->lut, red);
0201 out_8(&cmap_regs->lut, green);
0202 out_8(&cmap_regs->lut, blue);
0203
0204 if (regno < 16) {
0205 int i;
0206 u32 *pal = info->pseudo_palette;
0207 switch (pinfo->cmode) {
0208 case CMODE_16:
0209 pal[regno] = (regno << 10) | (regno << 5) | regno;
0210 break;
0211 case CMODE_32:
0212 i = (regno << 8) | regno;
0213 pal[regno] = (i << 16) | i;
0214 break;
0215 }
0216 }
0217
0218 return 0;
0219 }
0220
0221 static inline int platinum_vram_reqd(int video_mode, int color_mode)
0222 {
0223 int baseval = vmode_attrs[video_mode-1].hres * (1<<color_mode);
0224
0225 if ((video_mode == VMODE_832_624_75) && (color_mode > CMODE_8))
0226 baseval += 0x10;
0227 else
0228 baseval += 0x20;
0229
0230 return vmode_attrs[video_mode-1].vres * baseval + 0x1000;
0231 }
0232
0233 #define STORE_D2(a, d) { \
0234 out_8(&cmap_regs->addr, (a+32)); \
0235 out_8(&cmap_regs->d2, (d)); \
0236 }
0237
0238 static void set_platinum_clock(struct fb_info_platinum *pinfo)
0239 {
0240 volatile struct cmap_regs __iomem *cmap_regs = pinfo->cmap_regs;
0241 struct platinum_regvals *init;
0242
0243 init = platinum_reg_init[pinfo->vmode-1];
0244
0245 STORE_D2(6, 0xc6);
0246 out_8(&cmap_regs->addr,3+32);
0247
0248 if (in_8(&cmap_regs->d2) == 2) {
0249 STORE_D2(7, init->clock_params[pinfo->clktype][0]);
0250 STORE_D2(8, init->clock_params[pinfo->clktype][1]);
0251 STORE_D2(3, 3);
0252 } else {
0253 STORE_D2(4, init->clock_params[pinfo->clktype][0]);
0254 STORE_D2(5, init->clock_params[pinfo->clktype][1]);
0255 STORE_D2(3, 2);
0256 }
0257
0258 __delay(5000);
0259 STORE_D2(9, 0xa6);
0260 }
0261
0262
0263
0264
0265 static void platinum_set_hardware(struct fb_info_platinum *pinfo)
0266 {
0267 volatile struct platinum_regs __iomem *platinum_regs = pinfo->platinum_regs;
0268 volatile struct cmap_regs __iomem *cmap_regs = pinfo->cmap_regs;
0269 struct platinum_regvals *init;
0270 int i;
0271 int vmode, cmode;
0272
0273 vmode = pinfo->vmode;
0274 cmode = pinfo->cmode;
0275
0276 init = platinum_reg_init[vmode - 1];
0277
0278
0279 out_be32(&platinum_regs->reg[24].r, 7);
0280
0281 for (i = 0; i < 26; ++i)
0282 out_be32(&platinum_regs->reg[i+32].r, init->regs[i]);
0283
0284 out_be32(&platinum_regs->reg[26+32].r, (pinfo->total_vram == 0x100000 ?
0285 init->offset[cmode] + 4 - cmode :
0286 init->offset[cmode]));
0287 out_be32(&platinum_regs->reg[16].r, (unsigned) pinfo->frame_buffer_phys+init->fb_offset+0x10);
0288 out_be32(&platinum_regs->reg[18].r, init->pitch[cmode]);
0289 out_be32(&platinum_regs->reg[19].r, (pinfo->total_vram == 0x100000 ?
0290 init->mode[cmode+1] :
0291 init->mode[cmode]));
0292 out_be32(&platinum_regs->reg[20].r, (pinfo->total_vram == 0x100000 ? 0x11 : 0x1011));
0293 out_be32(&platinum_regs->reg[21].r, 0x100);
0294 out_be32(&platinum_regs->reg[22].r, 1);
0295 out_be32(&platinum_regs->reg[23].r, 1);
0296 out_be32(&platinum_regs->reg[26].r, 0xc00);
0297 out_be32(&platinum_regs->reg[27].r, 0x235);
0298
0299
0300 STORE_D2(0, (pinfo->total_vram == 0x100000 ?
0301 init->dacula_ctrl[cmode] & 0xf :
0302 init->dacula_ctrl[cmode]));
0303 STORE_D2(1, 4);
0304 STORE_D2(2, 0);
0305
0306 set_platinum_clock(pinfo);
0307
0308 out_be32(&platinum_regs->reg[24].r, 0);
0309 }
0310
0311
0312
0313
0314 static void platinum_init_info(struct fb_info *info,
0315 struct fb_info_platinum *pinfo)
0316 {
0317
0318 info->fbops = &platinumfb_ops;
0319 info->pseudo_palette = pinfo->pseudo_palette;
0320 info->flags = FBINFO_DEFAULT;
0321 info->screen_base = pinfo->frame_buffer + 0x20;
0322
0323 fb_alloc_cmap(&info->cmap, 256, 0);
0324
0325
0326 strcpy(info->fix.id, "platinum");
0327 info->fix.mmio_start = pinfo->platinum_regs_phys;
0328 info->fix.mmio_len = 0x1000;
0329 info->fix.type = FB_TYPE_PACKED_PIXELS;
0330 info->fix.smem_start = pinfo->frame_buffer_phys + 0x20;
0331 info->fix.smem_len = pinfo->total_vram - 0x20;
0332 info->fix.ywrapstep = 0;
0333 info->fix.xpanstep = 0;
0334 info->fix.ypanstep = 0;
0335 info->fix.type_aux = 0;
0336 info->fix.accel = FB_ACCEL_NONE;
0337 }
0338
0339
0340 static int platinum_init_fb(struct fb_info *info)
0341 {
0342 struct fb_info_platinum *pinfo = info->par;
0343 struct fb_var_screeninfo var;
0344 int sense, rc;
0345
0346 sense = read_platinum_sense(pinfo);
0347 printk(KERN_INFO "platinumfb: Monitor sense value = 0x%x, ", sense);
0348
0349 if (IS_REACHABLE(CONFIG_NVRAM) && default_vmode == VMODE_NVRAM)
0350 default_vmode = nvram_read_byte(NV_VMODE);
0351 if (default_vmode <= 0 || default_vmode > VMODE_MAX ||
0352 !platinum_reg_init[default_vmode - 1]) {
0353 default_vmode = mac_map_monitor_sense(sense);
0354 if (!platinum_reg_init[default_vmode - 1])
0355 default_vmode = VMODE_640_480_60;
0356 }
0357
0358 if (IS_REACHABLE(CONFIG_NVRAM) && default_cmode == CMODE_NVRAM)
0359 default_cmode = nvram_read_byte(NV_CMODE);
0360 if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
0361 default_cmode = CMODE_8;
0362
0363
0364
0365 while(default_cmode > CMODE_8 &&
0366 platinum_vram_reqd(default_vmode, default_cmode) > pinfo->total_vram)
0367 default_cmode--;
0368
0369 printk("platinumfb: Using video mode %d and color mode %d.\n", default_vmode, default_cmode);
0370
0371
0372 if (mac_vmode_to_var(default_vmode, default_cmode, &var) < 0) {
0373
0374 printk("mac_vmode_to_var(%d, %d,) failed\n", default_vmode, default_cmode);
0375 try_again:
0376 default_vmode = VMODE_640_480_60;
0377 default_cmode = CMODE_8;
0378 if (mac_vmode_to_var(default_vmode, default_cmode, &var) < 0) {
0379 printk(KERN_ERR "platinumfb: mac_vmode_to_var() failed\n");
0380 return -ENXIO;
0381 }
0382 }
0383
0384
0385 platinum_init_info(info, pinfo);
0386
0387
0388 info->var = var;
0389 var.activate = FB_ACTIVATE_NOW;
0390 rc = fb_set_var(info, &var);
0391 if (rc && (default_vmode != VMODE_640_480_60 || default_cmode != CMODE_8))
0392 goto try_again;
0393
0394
0395 rc = register_framebuffer(info);
0396 if (rc < 0)
0397 return rc;
0398
0399 fb_info(info, "Apple Platinum frame buffer device\n");
0400
0401 return 0;
0402 }
0403
0404
0405
0406
0407
0408
0409 static int read_platinum_sense(struct fb_info_platinum *info)
0410 {
0411 volatile struct platinum_regs __iomem *platinum_regs = info->platinum_regs;
0412 int sense;
0413
0414 out_be32(&platinum_regs->reg[23].r, 7);
0415 __delay(2000);
0416 sense = (~in_be32(&platinum_regs->reg[23].r) & 7) << 8;
0417
0418
0419 out_be32(&platinum_regs->reg[23].r, 3);
0420 __delay(2000);
0421 sense |= (~in_be32(&platinum_regs->reg[23].r) & 3) << 4;
0422 out_be32(&platinum_regs->reg[23].r, 5);
0423 __delay(2000);
0424 sense |= (~in_be32(&platinum_regs->reg[23].r) & 4) << 1;
0425 sense |= (~in_be32(&platinum_regs->reg[23].r) & 1) << 2;
0426 out_be32(&platinum_regs->reg[23].r, 6);
0427 __delay(2000);
0428 sense |= (~in_be32(&platinum_regs->reg[23].r) & 6) >> 1;
0429
0430 out_be32(&platinum_regs->reg[23].r, 7);
0431
0432 return sense;
0433 }
0434
0435
0436
0437
0438
0439 static int platinum_var_to_par(struct fb_var_screeninfo *var,
0440 struct fb_info_platinum *pinfo,
0441 int check_only)
0442 {
0443 int vmode, cmode;
0444
0445 if (mac_var_to_vmode(var, &vmode, &cmode) != 0) {
0446 printk(KERN_ERR "platinum_var_to_par: mac_var_to_vmode unsuccessful.\n");
0447 printk(KERN_ERR "platinum_var_to_par: var->xres = %d\n", var->xres);
0448 printk(KERN_ERR "platinum_var_to_par: var->yres = %d\n", var->yres);
0449 printk(KERN_ERR "platinum_var_to_par: var->xres_virtual = %d\n", var->xres_virtual);
0450 printk(KERN_ERR "platinum_var_to_par: var->yres_virtual = %d\n", var->yres_virtual);
0451 printk(KERN_ERR "platinum_var_to_par: var->bits_per_pixel = %d\n", var->bits_per_pixel);
0452 printk(KERN_ERR "platinum_var_to_par: var->pixclock = %d\n", var->pixclock);
0453 printk(KERN_ERR "platinum_var_to_par: var->vmode = %d\n", var->vmode);
0454 return -EINVAL;
0455 }
0456
0457 if (!platinum_reg_init[vmode-1]) {
0458 printk(KERN_ERR "platinum_var_to_par, vmode %d not valid.\n", vmode);
0459 return -EINVAL;
0460 }
0461
0462 if (platinum_vram_reqd(vmode, cmode) > pinfo->total_vram) {
0463 printk(KERN_ERR "platinum_var_to_par, not enough ram for vmode %d, cmode %d.\n", vmode, cmode);
0464 return -EINVAL;
0465 }
0466
0467 if (mac_vmode_to_var(vmode, cmode, var))
0468 return -EINVAL;
0469
0470 if (check_only)
0471 return 0;
0472
0473 pinfo->vmode = vmode;
0474 pinfo->cmode = cmode;
0475 pinfo->xres = vmode_attrs[vmode-1].hres;
0476 pinfo->yres = vmode_attrs[vmode-1].vres;
0477 pinfo->xoffset = 0;
0478 pinfo->yoffset = 0;
0479 pinfo->vxres = pinfo->xres;
0480 pinfo->vyres = pinfo->yres;
0481
0482 return 0;
0483 }
0484
0485
0486
0487
0488
0489 static int __init platinumfb_setup(char *options)
0490 {
0491 char *this_opt;
0492
0493 if (!options || !*options)
0494 return 0;
0495
0496 while ((this_opt = strsep(&options, ",")) != NULL) {
0497 if (!strncmp(this_opt, "vmode:", 6)) {
0498 int vmode = simple_strtoul(this_opt+6, NULL, 0);
0499 if (vmode > 0 && vmode <= VMODE_MAX)
0500 default_vmode = vmode;
0501 } else if (!strncmp(this_opt, "cmode:", 6)) {
0502 int depth = simple_strtoul(this_opt+6, NULL, 0);
0503 switch (depth) {
0504 case 0:
0505 case 8:
0506 default_cmode = CMODE_8;
0507 break;
0508 case 15:
0509 case 16:
0510 default_cmode = CMODE_16;
0511 break;
0512 case 24:
0513 case 32:
0514 default_cmode = CMODE_32;
0515 break;
0516 }
0517 }
0518 }
0519 return 0;
0520 }
0521
0522 #ifdef __powerpc__
0523 #define invalidate_cache(addr) \
0524 asm volatile("eieio; dcbf 0,%1" \
0525 : "=m" (*(addr)) : "r" (addr) : "memory");
0526 #else
0527 #define invalidate_cache(addr)
0528 #endif
0529
0530 static int platinumfb_probe(struct platform_device* odev)
0531 {
0532 struct device_node *dp = odev->dev.of_node;
0533 struct fb_info *info;
0534 struct fb_info_platinum *pinfo;
0535 volatile __u8 *fbuffer;
0536 int bank0, bank1, bank2, bank3, rc;
0537
0538 dev_info(&odev->dev, "Found Apple Platinum video hardware\n");
0539
0540 info = framebuffer_alloc(sizeof(*pinfo), &odev->dev);
0541 if (!info)
0542 return -ENOMEM;
0543
0544 pinfo = info->par;
0545
0546 if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) ||
0547 of_address_to_resource(dp, 1, &pinfo->rsrc_fb)) {
0548 dev_err(&odev->dev, "Can't get resources\n");
0549 framebuffer_release(info);
0550 return -ENXIO;
0551 }
0552 dev_dbg(&odev->dev, " registers : 0x%llx...0x%llx\n",
0553 (unsigned long long)pinfo->rsrc_reg.start,
0554 (unsigned long long)pinfo->rsrc_reg.end);
0555 dev_dbg(&odev->dev, " framebuffer: 0x%llx...0x%llx\n",
0556 (unsigned long long)pinfo->rsrc_fb.start,
0557 (unsigned long long)pinfo->rsrc_fb.end);
0558
0559
0560
0561
0562 if (!request_mem_region(pinfo->rsrc_fb.start,
0563 resource_size(&pinfo->rsrc_fb),
0564 "platinumfb framebuffer")) {
0565 printk(KERN_ERR "platinumfb: Can't request framebuffer !\n");
0566 framebuffer_release(info);
0567 return -ENXIO;
0568 }
0569
0570
0571 pinfo->frame_buffer_phys = pinfo->rsrc_fb.start;
0572 pinfo->frame_buffer = ioremap_wt(pinfo->rsrc_fb.start, 0x400000);
0573 pinfo->base_frame_buffer = pinfo->frame_buffer;
0574
0575
0576 pinfo->platinum_regs_phys = pinfo->rsrc_reg.start;
0577 pinfo->platinum_regs = ioremap(pinfo->rsrc_reg.start, 0x1000);
0578
0579 pinfo->cmap_regs_phys = 0xf301b000;
0580 request_mem_region(pinfo->cmap_regs_phys, 0x1000, "platinumfb cmap");
0581 pinfo->cmap_regs = ioremap(pinfo->cmap_regs_phys, 0x1000);
0582
0583
0584 out_be32(&pinfo->platinum_regs->reg[16].r, (unsigned)pinfo->frame_buffer_phys);
0585 out_be32(&pinfo->platinum_regs->reg[20].r, 0x1011);
0586 out_be32(&pinfo->platinum_regs->reg[24].r, 0);
0587
0588 fbuffer = pinfo->base_frame_buffer;
0589 fbuffer[0x100000] = 0x34;
0590 fbuffer[0x100008] = 0x0;
0591 invalidate_cache(&fbuffer[0x100000]);
0592 fbuffer[0x200000] = 0x56;
0593 fbuffer[0x200008] = 0x0;
0594 invalidate_cache(&fbuffer[0x200000]);
0595 fbuffer[0x300000] = 0x78;
0596 fbuffer[0x300008] = 0x0;
0597 invalidate_cache(&fbuffer[0x300000]);
0598 bank0 = 1;
0599 bank1 = fbuffer[0x100000] == 0x34;
0600 bank2 = fbuffer[0x200000] == 0x56;
0601 bank3 = fbuffer[0x300000] == 0x78;
0602 pinfo->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
0603 printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n",
0604 (unsigned int) (pinfo->total_vram / 1024 / 1024),
0605 bank3, bank2, bank1, bank0);
0606
0607
0608
0609
0610 out_8(&pinfo->cmap_regs->addr, 0x40);
0611 pinfo->dactype = in_8(&pinfo->cmap_regs->d2);
0612 switch (pinfo->dactype) {
0613 case 0x3c:
0614 pinfo->clktype = 1;
0615 printk(KERN_INFO "platinumfb: DACula type 0x3c\n");
0616 break;
0617 case 0x84:
0618 pinfo->clktype = 0;
0619 printk(KERN_INFO "platinumfb: DACula type 0x84\n");
0620 break;
0621 default:
0622 pinfo->clktype = 0;
0623 printk(KERN_INFO "platinumfb: Unknown DACula type: %x\n", pinfo->dactype);
0624 break;
0625 }
0626 dev_set_drvdata(&odev->dev, info);
0627
0628 rc = platinum_init_fb(info);
0629 if (rc != 0) {
0630 iounmap(pinfo->frame_buffer);
0631 iounmap(pinfo->platinum_regs);
0632 iounmap(pinfo->cmap_regs);
0633 framebuffer_release(info);
0634 }
0635
0636 return rc;
0637 }
0638
0639 static int platinumfb_remove(struct platform_device* odev)
0640 {
0641 struct fb_info *info = dev_get_drvdata(&odev->dev);
0642 struct fb_info_platinum *pinfo = info->par;
0643
0644 unregister_framebuffer (info);
0645
0646
0647 iounmap(pinfo->frame_buffer);
0648 iounmap(pinfo->platinum_regs);
0649 iounmap(pinfo->cmap_regs);
0650
0651 release_mem_region(pinfo->rsrc_fb.start,
0652 resource_size(&pinfo->rsrc_fb));
0653
0654 release_mem_region(pinfo->cmap_regs_phys, 0x1000);
0655
0656 framebuffer_release(info);
0657
0658 return 0;
0659 }
0660
0661 static struct of_device_id platinumfb_match[] =
0662 {
0663 {
0664 .name = "platinum",
0665 },
0666 {},
0667 };
0668
0669 static struct platform_driver platinum_driver =
0670 {
0671 .driver = {
0672 .name = "platinumfb",
0673 .of_match_table = platinumfb_match,
0674 },
0675 .probe = platinumfb_probe,
0676 .remove = platinumfb_remove,
0677 };
0678
0679 static int __init platinumfb_init(void)
0680 {
0681 #ifndef MODULE
0682 char *option = NULL;
0683
0684 if (fb_get_options("platinumfb", &option))
0685 return -ENODEV;
0686 platinumfb_setup(option);
0687 #endif
0688 platform_driver_register(&platinum_driver);
0689
0690 return 0;
0691 }
0692
0693 static void __exit platinumfb_exit(void)
0694 {
0695 platform_driver_unregister(&platinum_driver);
0696 }
0697
0698 MODULE_LICENSE("GPL");
0699 MODULE_DESCRIPTION("framebuffer driver for Apple Platinum video");
0700 module_init(platinumfb_init);
0701
0702 #ifdef MODULE
0703 module_exit(platinumfb_exit);
0704 #endif