diff options
Diffstat (limited to 'drivers/video/cg3.c')
-rw-r--r-- | drivers/video/cg3.c | 217 |
1 files changed, 111 insertions, 106 deletions
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 3de6e1b5ab2f..9c8c753ef454 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* cg3.c: CGTHREE frame buffer driver | 1 | /* cg3.c: CGTHREE frame buffer driver |
2 | * | 2 | * |
3 | * Copyright (C) 2003 David S. Miller (davem@redhat.com) | 3 | * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) |
4 | * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) | 4 | * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) |
5 | * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) | 5 | * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) |
6 | * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) | 6 | * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) |
@@ -19,8 +19,9 @@ | |||
19 | #include <linux/mm.h> | 19 | #include <linux/mm.h> |
20 | 20 | ||
21 | #include <asm/io.h> | 21 | #include <asm/io.h> |
22 | #include <asm/sbus.h> | ||
23 | #include <asm/oplib.h> | 22 | #include <asm/oplib.h> |
23 | #include <asm/prom.h> | ||
24 | #include <asm/of_device.h> | ||
24 | #include <asm/fbio.h> | 25 | #include <asm/fbio.h> |
25 | 26 | ||
26 | #include "sbuslib.h" | 27 | #include "sbuslib.h" |
@@ -80,30 +81,30 @@ enum cg3_type { | |||
80 | }; | 81 | }; |
81 | 82 | ||
82 | struct bt_regs { | 83 | struct bt_regs { |
83 | volatile u32 addr; | 84 | u32 addr; |
84 | volatile u32 color_map; | 85 | u32 color_map; |
85 | volatile u32 control; | 86 | u32 control; |
86 | volatile u32 cursor; | 87 | u32 cursor; |
87 | }; | 88 | }; |
88 | 89 | ||
89 | struct cg3_regs { | 90 | struct cg3_regs { |
90 | struct bt_regs cmap; | 91 | struct bt_regs cmap; |
91 | volatile u8 control; | 92 | u8 control; |
92 | volatile u8 status; | 93 | u8 status; |
93 | volatile u8 cursor_start; | 94 | u8 cursor_start; |
94 | volatile u8 cursor_end; | 95 | u8 cursor_end; |
95 | volatile u8 h_blank_start; | 96 | u8 h_blank_start; |
96 | volatile u8 h_blank_end; | 97 | u8 h_blank_end; |
97 | volatile u8 h_sync_start; | 98 | u8 h_sync_start; |
98 | volatile u8 h_sync_end; | 99 | u8 h_sync_end; |
99 | volatile u8 comp_sync_end; | 100 | u8 comp_sync_end; |
100 | volatile u8 v_blank_start_high; | 101 | u8 v_blank_start_high; |
101 | volatile u8 v_blank_start_low; | 102 | u8 v_blank_start_low; |
102 | volatile u8 v_blank_end; | 103 | u8 v_blank_end; |
103 | volatile u8 v_sync_start; | 104 | u8 v_sync_start; |
104 | volatile u8 v_sync_end; | 105 | u8 v_sync_end; |
105 | volatile u8 xfer_holdoff_start; | 106 | u8 xfer_holdoff_start; |
106 | volatile u8 xfer_holdoff_end; | 107 | u8 xfer_holdoff_end; |
107 | }; | 108 | }; |
108 | 109 | ||
109 | /* Offset of interesting structures in the OBIO space */ | 110 | /* Offset of interesting structures in the OBIO space */ |
@@ -120,9 +121,8 @@ struct cg3_par { | |||
120 | #define CG3_FLAG_RDI 0x00000002 | 121 | #define CG3_FLAG_RDI 0x00000002 |
121 | 122 | ||
122 | unsigned long physbase; | 123 | unsigned long physbase; |
124 | unsigned long which_io; | ||
123 | unsigned long fbsize; | 125 | unsigned long fbsize; |
124 | |||
125 | struct sbus_dev *sdev; | ||
126 | }; | 126 | }; |
127 | 127 | ||
128 | /** | 128 | /** |
@@ -235,7 +235,7 @@ static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma) | |||
235 | 235 | ||
236 | return sbusfb_mmap_helper(cg3_mmap_map, | 236 | return sbusfb_mmap_helper(cg3_mmap_map, |
237 | par->physbase, par->fbsize, | 237 | par->physbase, par->fbsize, |
238 | par->sdev->reg_addrs[0].which_io, | 238 | par->which_io, |
239 | vma); | 239 | vma); |
240 | } | 240 | } |
241 | 241 | ||
@@ -252,11 +252,9 @@ static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) | |||
252 | */ | 252 | */ |
253 | 253 | ||
254 | static void | 254 | static void |
255 | cg3_init_fix(struct fb_info *info, int linebytes) | 255 | cg3_init_fix(struct fb_info *info, int linebytes, struct device_node *dp) |
256 | { | 256 | { |
257 | struct cg3_par *par = (struct cg3_par *)info->par; | 257 | strlcpy(info->fix.id, dp->name, sizeof(info->fix.id)); |
258 | |||
259 | strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id)); | ||
260 | 258 | ||
261 | info->fix.type = FB_TYPE_PACKED_PIXELS; | 259 | info->fix.type = FB_TYPE_PACKED_PIXELS; |
262 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | 260 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; |
@@ -267,16 +265,15 @@ cg3_init_fix(struct fb_info *info, int linebytes) | |||
267 | } | 265 | } |
268 | 266 | ||
269 | static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var, | 267 | static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var, |
270 | struct sbus_dev *sdev) | 268 | struct device_node *dp) |
271 | { | 269 | { |
272 | char buffer[40]; | 270 | char *params; |
273 | char *p; | 271 | char *p; |
274 | int ww, hh; | 272 | int ww, hh; |
275 | 273 | ||
276 | *buffer = 0; | 274 | params = of_get_property(dp, "params", NULL); |
277 | prom_getstring(sdev->prom_node, "params", buffer, sizeof(buffer)); | 275 | if (params) { |
278 | if (*buffer) { | 276 | ww = simple_strtoul(params, &p, 10); |
279 | ww = simple_strtoul(buffer, &p, 10); | ||
280 | if (ww && *p == 'x') { | 277 | if (ww && *p == 'x') { |
281 | hh = simple_strtoul(p + 1, &p, 10); | 278 | hh = simple_strtoul(p + 1, &p, 10); |
282 | if (hh && *p == '-') { | 279 | if (hh && *p == '-') { |
@@ -348,11 +345,11 @@ static void cg3_do_default_mode(struct cg3_par *par) | |||
348 | sbus_writeb(p[1], regp); | 345 | sbus_writeb(p[1], regp); |
349 | } | 346 | } |
350 | for (p = cg3_dacvals; *p; p += 2) { | 347 | for (p = cg3_dacvals; *p; p += 2) { |
351 | volatile u8 __iomem *regp; | 348 | u8 __iomem *regp; |
352 | 349 | ||
353 | regp = (volatile u8 __iomem *)&par->regs->cmap.addr; | 350 | regp = (u8 __iomem *)&par->regs->cmap.addr; |
354 | sbus_writeb(p[0], regp); | 351 | sbus_writeb(p[0], regp); |
355 | regp = (volatile u8 __iomem *)&par->regs->cmap.control; | 352 | regp = (u8 __iomem *)&par->regs->cmap.control; |
356 | sbus_writeb(p[1], regp); | 353 | sbus_writeb(p[1], regp); |
357 | } | 354 | } |
358 | } | 355 | } |
@@ -360,129 +357,137 @@ static void cg3_do_default_mode(struct cg3_par *par) | |||
360 | struct all_info { | 357 | struct all_info { |
361 | struct fb_info info; | 358 | struct fb_info info; |
362 | struct cg3_par par; | 359 | struct cg3_par par; |
363 | struct list_head list; | ||
364 | }; | 360 | }; |
365 | static LIST_HEAD(cg3_list); | ||
366 | 361 | ||
367 | static void cg3_init_one(struct sbus_dev *sdev) | 362 | static int __devinit cg3_init_one(struct of_device *op) |
368 | { | 363 | { |
364 | struct device_node *dp = op->node; | ||
369 | struct all_info *all; | 365 | struct all_info *all; |
370 | int linebytes; | 366 | int linebytes, err; |
371 | |||
372 | all = kmalloc(sizeof(*all), GFP_KERNEL); | ||
373 | if (!all) { | ||
374 | printk(KERN_ERR "cg3: Cannot allocate memory.\n"); | ||
375 | return; | ||
376 | } | ||
377 | memset(all, 0, sizeof(*all)); | ||
378 | 367 | ||
379 | INIT_LIST_HEAD(&all->list); | 368 | all = kzalloc(sizeof(*all), GFP_KERNEL); |
369 | if (!all) | ||
370 | return -ENOMEM; | ||
380 | 371 | ||
381 | spin_lock_init(&all->par.lock); | 372 | spin_lock_init(&all->par.lock); |
382 | all->par.sdev = sdev; | ||
383 | 373 | ||
384 | all->par.physbase = sdev->reg_addrs[0].phys_addr; | 374 | all->par.physbase = op->resource[0].start; |
375 | all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; | ||
385 | 376 | ||
386 | sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); | 377 | sbusfb_fill_var(&all->info.var, dp->node, 8); |
387 | all->info.var.red.length = 8; | 378 | all->info.var.red.length = 8; |
388 | all->info.var.green.length = 8; | 379 | all->info.var.green.length = 8; |
389 | all->info.var.blue.length = 8; | 380 | all->info.var.blue.length = 8; |
390 | if (!strcmp(sdev->prom_name, "cgRDI")) | 381 | if (!strcmp(dp->name, "cgRDI")) |
391 | all->par.flags |= CG3_FLAG_RDI; | 382 | all->par.flags |= CG3_FLAG_RDI; |
392 | if (all->par.flags & CG3_FLAG_RDI) | 383 | if (all->par.flags & CG3_FLAG_RDI) |
393 | cg3_rdi_maybe_fixup_var(&all->info.var, sdev); | 384 | cg3_rdi_maybe_fixup_var(&all->info.var, dp); |
394 | 385 | ||
395 | linebytes = prom_getintdefault(sdev->prom_node, "linebytes", | 386 | linebytes = of_getintprop_default(dp, "linebytes", |
396 | all->info.var.xres); | 387 | all->info.var.xres); |
397 | all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); | 388 | all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); |
398 | 389 | ||
399 | all->par.regs = sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET, | 390 | all->par.regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET, |
400 | sizeof(struct cg3_regs), "cg3 regs"); | 391 | sizeof(struct cg3_regs), "cg3 regs"); |
401 | 392 | ||
402 | all->info.flags = FBINFO_DEFAULT; | 393 | all->info.flags = FBINFO_DEFAULT; |
403 | all->info.fbops = &cg3_ops; | 394 | all->info.fbops = &cg3_ops; |
404 | #ifdef CONFIG_SPARC32 | 395 | all->info.screen_base = |
405 | all->info.screen_base = (char __iomem *) | 396 | of_ioremap(&op->resource[0], CG3_RAM_OFFSET, |
406 | prom_getintdefault(sdev->prom_node, "address", 0); | 397 | all->par.fbsize, "cg3 ram"); |
407 | #endif | ||
408 | if (!all->info.screen_base) | ||
409 | all->info.screen_base = | ||
410 | sbus_ioremap(&sdev->resource[0], CG3_RAM_OFFSET, | ||
411 | all->par.fbsize, "cg3 ram"); | ||
412 | all->info.par = &all->par; | 398 | all->info.par = &all->par; |
413 | 399 | ||
414 | cg3_blank(0, &all->info); | 400 | cg3_blank(0, &all->info); |
415 | 401 | ||
416 | if (!prom_getbool(sdev->prom_node, "width")) | 402 | if (!of_find_property(dp, "width", NULL)) |
417 | cg3_do_default_mode(&all->par); | 403 | cg3_do_default_mode(&all->par); |
418 | 404 | ||
419 | if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { | 405 | if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { |
420 | printk(KERN_ERR "cg3: Could not allocate color map.\n"); | 406 | of_iounmap(all->par.regs, sizeof(struct cg3_regs)); |
407 | of_iounmap(all->info.screen_base, all->par.fbsize); | ||
421 | kfree(all); | 408 | kfree(all); |
422 | return; | 409 | return -ENOMEM; |
423 | } | 410 | } |
424 | fb_set_cmap(&all->info.cmap, &all->info); | 411 | fb_set_cmap(&all->info.cmap, &all->info); |
425 | 412 | ||
426 | cg3_init_fix(&all->info, linebytes); | 413 | cg3_init_fix(&all->info, linebytes, dp); |
427 | 414 | ||
428 | if (register_framebuffer(&all->info) < 0) { | 415 | err = register_framebuffer(&all->info); |
429 | printk(KERN_ERR "cg3: Could not register framebuffer.\n"); | 416 | if (err < 0) { |
430 | fb_dealloc_cmap(&all->info.cmap); | 417 | fb_dealloc_cmap(&all->info.cmap); |
418 | of_iounmap(all->par.regs, sizeof(struct cg3_regs)); | ||
419 | of_iounmap(all->info.screen_base, all->par.fbsize); | ||
431 | kfree(all); | 420 | kfree(all); |
432 | return; | 421 | return err; |
433 | } | 422 | } |
434 | 423 | ||
435 | list_add(&all->list, &cg3_list); | 424 | dev_set_drvdata(&op->dev, all); |
425 | |||
426 | printk("%s: cg3 at %lx:%lx\n", | ||
427 | dp->full_name, all->par.which_io, all->par.physbase); | ||
436 | 428 | ||
437 | printk("cg3: %s at %lx:%lx\n", | 429 | return 0; |
438 | sdev->prom_name, | ||
439 | (long) sdev->reg_addrs[0].which_io, | ||
440 | (long) sdev->reg_addrs[0].phys_addr); | ||
441 | } | 430 | } |
442 | 431 | ||
443 | int __init cg3_init(void) | 432 | static int __devinit cg3_probe(struct of_device *dev, const struct of_device_id *match) |
444 | { | 433 | { |
445 | struct sbus_bus *sbus; | 434 | struct of_device *op = to_of_device(&dev->dev); |
446 | struct sbus_dev *sdev; | ||
447 | 435 | ||
448 | if (fb_get_options("cg3fb", NULL)) | 436 | return cg3_init_one(op); |
449 | return -ENODEV; | 437 | } |
450 | 438 | ||
451 | for_all_sbusdev(sdev, sbus) { | 439 | static int __devexit cg3_remove(struct of_device *dev) |
452 | if (!strcmp(sdev->prom_name, "cgthree") || | 440 | { |
453 | !strcmp(sdev->prom_name, "cgRDI")) | 441 | struct all_info *all = dev_get_drvdata(&dev->dev); |
454 | cg3_init_one(sdev); | 442 | |
455 | } | 443 | unregister_framebuffer(&all->info); |
444 | fb_dealloc_cmap(&all->info.cmap); | ||
445 | |||
446 | of_iounmap(all->par.regs, sizeof(struct cg3_regs)); | ||
447 | of_iounmap(all->info.screen_base, all->par.fbsize); | ||
448 | |||
449 | kfree(all); | ||
450 | |||
451 | dev_set_drvdata(&dev->dev, NULL); | ||
456 | 452 | ||
457 | return 0; | 453 | return 0; |
458 | } | 454 | } |
459 | 455 | ||
460 | void __exit cg3_exit(void) | 456 | static struct of_device_id cg3_match[] = { |
461 | { | 457 | { |
462 | struct list_head *pos, *tmp; | 458 | .name = "cgthree", |
459 | }, | ||
460 | { | ||
461 | .name = "cgRDI", | ||
462 | }, | ||
463 | {}, | ||
464 | }; | ||
465 | MODULE_DEVICE_TABLE(of, cg3_match); | ||
463 | 466 | ||
464 | list_for_each_safe(pos, tmp, &cg3_list) { | 467 | static struct of_platform_driver cg3_driver = { |
465 | struct all_info *all = list_entry(pos, typeof(*all), list); | 468 | .name = "cg3", |
469 | .match_table = cg3_match, | ||
470 | .probe = cg3_probe, | ||
471 | .remove = __devexit_p(cg3_remove), | ||
472 | }; | ||
466 | 473 | ||
467 | unregister_framebuffer(&all->info); | 474 | static int __init cg3_init(void) |
468 | fb_dealloc_cmap(&all->info.cmap); | 475 | { |
469 | kfree(all); | 476 | if (fb_get_options("cg3fb", NULL)) |
470 | } | 477 | return -ENODEV; |
478 | |||
479 | return of_register_driver(&cg3_driver, &of_bus_type); | ||
471 | } | 480 | } |
472 | 481 | ||
473 | int __init | 482 | static void __exit cg3_exit(void) |
474 | cg3_setup(char *arg) | ||
475 | { | 483 | { |
476 | /* No cmdline options yet... */ | 484 | of_unregister_driver(&cg3_driver); |
477 | return 0; | ||
478 | } | 485 | } |
479 | 486 | ||
480 | module_init(cg3_init); | 487 | module_init(cg3_init); |
481 | |||
482 | #ifdef MODULE | ||
483 | module_exit(cg3_exit); | 488 | module_exit(cg3_exit); |
484 | #endif | ||
485 | 489 | ||
486 | MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets"); | 490 | MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets"); |
487 | MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); | 491 | MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); |
492 | MODULE_VERSION("2.0"); | ||
488 | MODULE_LICENSE("GPL"); | 493 | MODULE_LICENSE("GPL"); |