diff options
Diffstat (limited to 'drivers/video/p9100.c')
-rw-r--r-- | drivers/video/p9100.c | 251 |
1 files changed, 131 insertions, 120 deletions
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 0d195750535..56ac51d6a7f 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* p9100.c: P9100 frame buffer driver | 1 | /* p9100.c: P9100 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 1999 Derrick J Brashear (shadow@dementia.org) | 4 | * Copyright 1999 Derrick J Brashear (shadow@dementia.org) |
5 | * | 5 | * |
6 | * Driver layout based loosely on tgafb.c, see that file for credits. | 6 | * Driver layout based loosely on tgafb.c, see that file for credits. |
@@ -17,8 +17,8 @@ | |||
17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
18 | 18 | ||
19 | #include <asm/io.h> | 19 | #include <asm/io.h> |
20 | #include <asm/sbus.h> | 20 | #include <asm/prom.h> |
21 | #include <asm/oplib.h> | 21 | #include <asm/of_device.h> |
22 | #include <asm/fbio.h> | 22 | #include <asm/fbio.h> |
23 | 23 | ||
24 | #include "sbuslib.h" | 24 | #include "sbuslib.h" |
@@ -72,60 +72,60 @@ static struct fb_ops p9100_ops = { | |||
72 | 72 | ||
73 | struct p9100_regs { | 73 | struct p9100_regs { |
74 | /* Registers for the system control */ | 74 | /* Registers for the system control */ |
75 | volatile u32 sys_base; | 75 | u32 sys_base; |
76 | volatile u32 sys_config; | 76 | u32 sys_config; |
77 | volatile u32 sys_intr; | 77 | u32 sys_intr; |
78 | volatile u32 sys_int_ena; | 78 | u32 sys_int_ena; |
79 | volatile u32 sys_alt_rd; | 79 | u32 sys_alt_rd; |
80 | volatile u32 sys_alt_wr; | 80 | u32 sys_alt_wr; |
81 | volatile u32 sys_xxx[58]; | 81 | u32 sys_xxx[58]; |
82 | 82 | ||
83 | /* Registers for the video control */ | 83 | /* Registers for the video control */ |
84 | volatile u32 vid_base; | 84 | u32 vid_base; |
85 | volatile u32 vid_hcnt; | 85 | u32 vid_hcnt; |
86 | volatile u32 vid_htotal; | 86 | u32 vid_htotal; |
87 | volatile u32 vid_hsync_rise; | 87 | u32 vid_hsync_rise; |
88 | volatile u32 vid_hblank_rise; | 88 | u32 vid_hblank_rise; |
89 | volatile u32 vid_hblank_fall; | 89 | u32 vid_hblank_fall; |
90 | volatile u32 vid_hcnt_preload; | 90 | u32 vid_hcnt_preload; |
91 | volatile u32 vid_vcnt; | 91 | u32 vid_vcnt; |
92 | volatile u32 vid_vlen; | 92 | u32 vid_vlen; |
93 | volatile u32 vid_vsync_rise; | 93 | u32 vid_vsync_rise; |
94 | volatile u32 vid_vblank_rise; | 94 | u32 vid_vblank_rise; |
95 | volatile u32 vid_vblank_fall; | 95 | u32 vid_vblank_fall; |
96 | volatile u32 vid_vcnt_preload; | 96 | u32 vid_vcnt_preload; |
97 | volatile u32 vid_screenpaint_addr; | 97 | u32 vid_screenpaint_addr; |
98 | volatile u32 vid_screenpaint_timectl1; | 98 | u32 vid_screenpaint_timectl1; |
99 | volatile u32 vid_screenpaint_qsfcnt; | 99 | u32 vid_screenpaint_qsfcnt; |
100 | volatile u32 vid_screenpaint_timectl2; | 100 | u32 vid_screenpaint_timectl2; |
101 | volatile u32 vid_xxx[15]; | 101 | u32 vid_xxx[15]; |
102 | 102 | ||
103 | /* Registers for the video control */ | 103 | /* Registers for the video control */ |
104 | volatile u32 vram_base; | 104 | u32 vram_base; |
105 | volatile u32 vram_memcfg; | 105 | u32 vram_memcfg; |
106 | volatile u32 vram_refresh_pd; | 106 | u32 vram_refresh_pd; |
107 | volatile u32 vram_refresh_cnt; | 107 | u32 vram_refresh_cnt; |
108 | volatile u32 vram_raslo_max; | 108 | u32 vram_raslo_max; |
109 | volatile u32 vram_raslo_cur; | 109 | u32 vram_raslo_cur; |
110 | volatile u32 pwrup_cfg; | 110 | u32 pwrup_cfg; |
111 | volatile u32 vram_xxx[25]; | 111 | u32 vram_xxx[25]; |
112 | 112 | ||
113 | /* Registers for IBM RGB528 Palette */ | 113 | /* Registers for IBM RGB528 Palette */ |
114 | volatile u32 ramdac_cmap_wridx; | 114 | u32 ramdac_cmap_wridx; |
115 | volatile u32 ramdac_palette_data; | 115 | u32 ramdac_palette_data; |
116 | volatile u32 ramdac_pixel_mask; | 116 | u32 ramdac_pixel_mask; |
117 | volatile u32 ramdac_palette_rdaddr; | 117 | u32 ramdac_palette_rdaddr; |
118 | volatile u32 ramdac_idx_lo; | 118 | u32 ramdac_idx_lo; |
119 | volatile u32 ramdac_idx_hi; | 119 | u32 ramdac_idx_hi; |
120 | volatile u32 ramdac_idx_data; | 120 | u32 ramdac_idx_data; |
121 | volatile u32 ramdac_idx_ctl; | 121 | u32 ramdac_idx_ctl; |
122 | volatile u32 ramdac_xxx[1784]; | 122 | u32 ramdac_xxx[1784]; |
123 | }; | 123 | }; |
124 | 124 | ||
125 | struct p9100_cmd_parameng { | 125 | struct p9100_cmd_parameng { |
126 | volatile u32 parameng_status; | 126 | u32 parameng_status; |
127 | volatile u32 parameng_bltcmd; | 127 | u32 parameng_bltcmd; |
128 | volatile u32 parameng_quadcmd; | 128 | u32 parameng_quadcmd; |
129 | }; | 129 | }; |
130 | 130 | ||
131 | struct p9100_par { | 131 | struct p9100_par { |
@@ -136,9 +136,8 @@ struct p9100_par { | |||
136 | #define P9100_FLAG_BLANKED 0x00000001 | 136 | #define P9100_FLAG_BLANKED 0x00000001 |
137 | 137 | ||
138 | unsigned long physbase; | 138 | unsigned long physbase; |
139 | unsigned long which_io; | ||
139 | unsigned long fbsize; | 140 | unsigned long fbsize; |
140 | |||
141 | struct sbus_dev *sdev; | ||
142 | }; | 141 | }; |
143 | 142 | ||
144 | /** | 143 | /** |
@@ -227,8 +226,7 @@ static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma) | |||
227 | 226 | ||
228 | return sbusfb_mmap_helper(p9100_mmap_map, | 227 | return sbusfb_mmap_helper(p9100_mmap_map, |
229 | par->physbase, par->fbsize, | 228 | par->physbase, par->fbsize, |
230 | par->sdev->reg_addrs[0].which_io, | 229 | par->which_io, vma); |
231 | vma); | ||
232 | } | 230 | } |
233 | 231 | ||
234 | static int p9100_ioctl(struct fb_info *info, unsigned int cmd, | 232 | static int p9100_ioctl(struct fb_info *info, unsigned int cmd, |
@@ -245,12 +243,9 @@ static int p9100_ioctl(struct fb_info *info, unsigned int cmd, | |||
245 | * Initialisation | 243 | * Initialisation |
246 | */ | 244 | */ |
247 | 245 | ||
248 | static void | 246 | static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_node *dp) |
249 | p9100_init_fix(struct fb_info *info, int linebytes) | ||
250 | { | 247 | { |
251 | struct p9100_par *par = (struct p9100_par *)info->par; | 248 | strlcpy(info->fix.id, dp->name, sizeof(info->fix.id)); |
252 | |||
253 | strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id)); | ||
254 | 249 | ||
255 | info->fix.type = FB_TYPE_PACKED_PIXELS; | 250 | info->fix.type = FB_TYPE_PACKED_PIXELS; |
256 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | 251 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; |
@@ -263,121 +258,137 @@ p9100_init_fix(struct fb_info *info, int linebytes) | |||
263 | struct all_info { | 258 | struct all_info { |
264 | struct fb_info info; | 259 | struct fb_info info; |
265 | struct p9100_par par; | 260 | struct p9100_par par; |
266 | struct list_head list; | ||
267 | }; | 261 | }; |
268 | static LIST_HEAD(p9100_list); | ||
269 | 262 | ||
270 | static void p9100_init_one(struct sbus_dev *sdev) | 263 | static int __devinit p9100_init_one(struct of_device *op) |
271 | { | 264 | { |
265 | struct device_node *dp = op->node; | ||
272 | struct all_info *all; | 266 | struct all_info *all; |
273 | int linebytes; | 267 | int linebytes, err; |
274 | |||
275 | all = kmalloc(sizeof(*all), GFP_KERNEL); | ||
276 | if (!all) { | ||
277 | printk(KERN_ERR "p9100: Cannot allocate memory.\n"); | ||
278 | return; | ||
279 | } | ||
280 | memset(all, 0, sizeof(*all)); | ||
281 | 268 | ||
282 | INIT_LIST_HEAD(&all->list); | 269 | all = kzalloc(sizeof(*all), GFP_KERNEL); |
270 | if (!all) | ||
271 | return -ENOMEM; | ||
283 | 272 | ||
284 | spin_lock_init(&all->par.lock); | 273 | spin_lock_init(&all->par.lock); |
285 | all->par.sdev = sdev; | ||
286 | 274 | ||
287 | /* This is the framebuffer and the only resource apps can mmap. */ | 275 | /* This is the framebuffer and the only resource apps can mmap. */ |
288 | all->par.physbase = sdev->reg_addrs[2].phys_addr; | 276 | all->par.physbase = op->resource[2].start; |
277 | all->par.which_io = op->resource[2].flags & IORESOURCE_BITS; | ||
289 | 278 | ||
290 | sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); | 279 | sbusfb_fill_var(&all->info.var, dp->node, 8); |
291 | all->info.var.red.length = 8; | 280 | all->info.var.red.length = 8; |
292 | all->info.var.green.length = 8; | 281 | all->info.var.green.length = 8; |
293 | all->info.var.blue.length = 8; | 282 | all->info.var.blue.length = 8; |
294 | 283 | ||
295 | linebytes = prom_getintdefault(sdev->prom_node, "linebytes", | 284 | linebytes = of_getintprop_default(dp, "linebytes", |
296 | all->info.var.xres); | 285 | all->info.var.xres); |
297 | all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); | 286 | all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); |
298 | 287 | ||
299 | all->par.regs = sbus_ioremap(&sdev->resource[0], 0, | 288 | all->par.regs = of_ioremap(&op->resource[0], 0, |
300 | sizeof(struct p9100_regs), "p9100 regs"); | 289 | sizeof(struct p9100_regs), "p9100 regs"); |
290 | if (!all->par.regs) { | ||
291 | kfree(all); | ||
292 | return -ENOMEM; | ||
293 | } | ||
301 | 294 | ||
302 | all->info.flags = FBINFO_DEFAULT; | 295 | all->info.flags = FBINFO_DEFAULT; |
303 | all->info.fbops = &p9100_ops; | 296 | all->info.fbops = &p9100_ops; |
304 | #ifdef CONFIG_SPARC32 | 297 | all->info.screen_base = of_ioremap(&op->resource[2], 0, |
305 | all->info.screen_base = (char __iomem *) | 298 | all->par.fbsize, "p9100 ram"); |
306 | prom_getintdefault(sdev->prom_node, "address", 0); | 299 | if (!all->info.screen_base) { |
307 | #endif | 300 | of_iounmap(all->par.regs, sizeof(struct p9100_regs)); |
308 | if (!all->info.screen_base) | 301 | kfree(all); |
309 | all->info.screen_base = sbus_ioremap(&sdev->resource[2], 0, | 302 | return -ENOMEM; |
310 | all->par.fbsize, "p9100 ram"); | 303 | } |
311 | all->info.par = &all->par; | 304 | all->info.par = &all->par; |
312 | 305 | ||
313 | p9100_blank(0, &all->info); | 306 | p9100_blank(0, &all->info); |
314 | 307 | ||
315 | if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { | 308 | if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { |
316 | printk(KERN_ERR "p9100: Could not allocate color map.\n"); | 309 | of_iounmap(all->par.regs, sizeof(struct p9100_regs)); |
310 | of_iounmap(all->info.screen_base, all->par.fbsize); | ||
317 | kfree(all); | 311 | kfree(all); |
318 | return; | 312 | return -ENOMEM; |
319 | } | 313 | } |
320 | 314 | ||
321 | p9100_init_fix(&all->info, linebytes); | 315 | p9100_init_fix(&all->info, linebytes, dp); |
322 | 316 | ||
323 | if (register_framebuffer(&all->info) < 0) { | 317 | err = register_framebuffer(&all->info); |
324 | printk(KERN_ERR "p9100: Could not register framebuffer.\n"); | 318 | if (err < 0) { |
325 | fb_dealloc_cmap(&all->info.cmap); | 319 | fb_dealloc_cmap(&all->info.cmap); |
320 | of_iounmap(all->par.regs, sizeof(struct p9100_regs)); | ||
321 | of_iounmap(all->info.screen_base, all->par.fbsize); | ||
326 | kfree(all); | 322 | kfree(all); |
327 | return; | 323 | return err; |
328 | } | 324 | } |
329 | fb_set_cmap(&all->info.cmap, &all->info); | 325 | fb_set_cmap(&all->info.cmap, &all->info); |
330 | 326 | ||
331 | list_add(&all->list, &p9100_list); | 327 | dev_set_drvdata(&op->dev, all); |
328 | |||
329 | printk("%s: p9100 at %lx:%lx\n", | ||
330 | dp->full_name, | ||
331 | all->par.which_io, all->par.physbase); | ||
332 | 332 | ||
333 | printk("p9100: %s at %lx:%lx\n", | 333 | return 0; |
334 | sdev->prom_name, | ||
335 | (long) sdev->reg_addrs[0].which_io, | ||
336 | (long) sdev->reg_addrs[0].phys_addr); | ||
337 | } | 334 | } |
338 | 335 | ||
339 | int __init p9100_init(void) | 336 | static int __devinit p9100_probe(struct of_device *dev, const struct of_device_id *match) |
340 | { | 337 | { |
341 | struct sbus_bus *sbus; | 338 | struct of_device *op = to_of_device(&dev->dev); |
342 | struct sbus_dev *sdev; | ||
343 | 339 | ||
344 | if (fb_get_options("p9100fb", NULL)) | 340 | return p9100_init_one(op); |
345 | return -ENODEV; | 341 | } |
346 | 342 | ||
347 | for_all_sbusdev(sdev, sbus) { | 343 | static int __devexit p9100_remove(struct of_device *dev) |
348 | if (!strcmp(sdev->prom_name, "p9100")) | 344 | { |
349 | p9100_init_one(sdev); | 345 | struct all_info *all = dev_get_drvdata(&dev->dev); |
350 | } | 346 | |
347 | unregister_framebuffer(&all->info); | ||
348 | fb_dealloc_cmap(&all->info.cmap); | ||
349 | |||
350 | of_iounmap(all->par.regs, sizeof(struct p9100_regs)); | ||
351 | of_iounmap(all->info.screen_base, all->par.fbsize); | ||
352 | |||
353 | kfree(all); | ||
354 | |||
355 | dev_set_drvdata(&dev->dev, NULL); | ||
351 | 356 | ||
352 | return 0; | 357 | return 0; |
353 | } | 358 | } |
354 | 359 | ||
355 | void __exit p9100_exit(void) | 360 | static struct of_device_id p9100_match[] = { |
356 | { | 361 | { |
357 | struct list_head *pos, *tmp; | 362 | .name = "p9100", |
363 | }, | ||
364 | {}, | ||
365 | }; | ||
366 | MODULE_DEVICE_TABLE(of, p9100_match); | ||
358 | 367 | ||
359 | list_for_each_safe(pos, tmp, &p9100_list) { | 368 | static struct of_platform_driver p9100_driver = { |
360 | struct all_info *all = list_entry(pos, typeof(*all), list); | 369 | .name = "p9100", |
370 | .match_table = p9100_match, | ||
371 | .probe = p9100_probe, | ||
372 | .remove = __devexit_p(p9100_remove), | ||
373 | }; | ||
361 | 374 | ||
362 | unregister_framebuffer(&all->info); | 375 | static int __init p9100_init(void) |
363 | fb_dealloc_cmap(&all->info.cmap); | 376 | { |
364 | kfree(all); | 377 | if (fb_get_options("p9100fb", NULL)) |
365 | } | 378 | return -ENODEV; |
379 | |||
380 | return of_register_driver(&p9100_driver, &of_bus_type); | ||
366 | } | 381 | } |
367 | 382 | ||
368 | int __init | 383 | static void __exit p9100_exit(void) |
369 | p9100_setup(char *arg) | ||
370 | { | 384 | { |
371 | /* No cmdline options yet... */ | 385 | of_unregister_driver(&p9100_driver); |
372 | return 0; | ||
373 | } | 386 | } |
374 | 387 | ||
375 | module_init(p9100_init); | 388 | module_init(p9100_init); |
376 | |||
377 | #ifdef MODULE | ||
378 | module_exit(p9100_exit); | 389 | module_exit(p9100_exit); |
379 | #endif | ||
380 | 390 | ||
381 | MODULE_DESCRIPTION("framebuffer driver for P9100 chipsets"); | 391 | MODULE_DESCRIPTION("framebuffer driver for P9100 chipsets"); |
382 | MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); | 392 | MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); |
393 | MODULE_VERSION("2.0"); | ||
383 | MODULE_LICENSE("GPL"); | 394 | MODULE_LICENSE("GPL"); |