1 /* p9100.c: P9100 frame buffer driver
3 * Copyright (C) 2003 David S. Miller (davem@redhat.com)
4 * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
6 * Driver layout based loosely on tgafb.c, see that file for credits.
9 #include <linux/module.h>
10 #include <linux/kernel.h>
11 #include <linux/errno.h>
12 #include <linux/string.h>
13 #include <linux/slab.h>
14 #include <linux/delay.h>
15 #include <linux/init.h>
21 #include <asm/oplib.h>
30 static int p9100_setcolreg(unsigned, unsigned, unsigned, unsigned,
31 unsigned, struct fb_info
*);
32 static int p9100_blank(int, struct fb_info
*);
34 static int p9100_mmap(struct fb_info
*, struct file
*, struct vm_area_struct
*);
35 static int p9100_ioctl(struct inode
*, struct file
*, unsigned int,
36 unsigned long, struct fb_info
*);
39 * Frame buffer operations
42 static struct fb_ops p9100_ops
= {
44 .fb_setcolreg
= p9100_setcolreg
,
45 .fb_blank
= p9100_blank
,
46 .fb_fillrect
= cfb_fillrect
,
47 .fb_copyarea
= cfb_copyarea
,
48 .fb_imageblit
= cfb_imageblit
,
49 .fb_mmap
= p9100_mmap
,
50 .fb_ioctl
= p9100_ioctl
,
51 .fb_cursor
= soft_cursor
,
54 /* P9100 control registers */
55 #define P9100_SYSCTL_OFF 0x0UL
56 #define P9100_VIDEOCTL_OFF 0x100UL
57 #define P9100_VRAMCTL_OFF 0x180UL
58 #define P9100_RAMDAC_OFF 0x200UL
59 #define P9100_VIDEOCOPROC_OFF 0x400UL
61 /* P9100 command registers */
62 #define P9100_CMD_OFF 0x0UL
64 /* P9100 framebuffer memory */
65 #define P9100_FB_OFF 0x0UL
67 /* 3 bits: 2=8bpp 3=16bpp 5=32bpp 7=24bpp */
68 #define SYS_CONFIG_PIXELSIZE_SHIFT 26
70 #define SCREENPAINT_TIMECTL1_ENABLE_VIDEO 0x20 /* 0 = off, 1 = on */
73 /* Registers for the system control */
74 volatile u32 sys_base
;
75 volatile u32 sys_config
;
76 volatile u32 sys_intr
;
77 volatile u32 sys_int_ena
;
78 volatile u32 sys_alt_rd
;
79 volatile u32 sys_alt_wr
;
80 volatile u32 sys_xxx
[58];
82 /* Registers for the video control */
83 volatile u32 vid_base
;
84 volatile u32 vid_hcnt
;
85 volatile u32 vid_htotal
;
86 volatile u32 vid_hsync_rise
;
87 volatile u32 vid_hblank_rise
;
88 volatile u32 vid_hblank_fall
;
89 volatile u32 vid_hcnt_preload
;
90 volatile u32 vid_vcnt
;
91 volatile u32 vid_vlen
;
92 volatile u32 vid_vsync_rise
;
93 volatile u32 vid_vblank_rise
;
94 volatile u32 vid_vblank_fall
;
95 volatile u32 vid_vcnt_preload
;
96 volatile u32 vid_screenpaint_addr
;
97 volatile u32 vid_screenpaint_timectl1
;
98 volatile u32 vid_screenpaint_qsfcnt
;
99 volatile u32 vid_screenpaint_timectl2
;
100 volatile u32 vid_xxx
[15];
102 /* Registers for the video control */
103 volatile u32 vram_base
;
104 volatile u32 vram_memcfg
;
105 volatile u32 vram_refresh_pd
;
106 volatile u32 vram_refresh_cnt
;
107 volatile u32 vram_raslo_max
;
108 volatile u32 vram_raslo_cur
;
109 volatile u32 pwrup_cfg
;
110 volatile u32 vram_xxx
[25];
112 /* Registers for IBM RGB528 Palette */
113 volatile u32 ramdac_cmap_wridx
;
114 volatile u32 ramdac_palette_data
;
115 volatile u32 ramdac_pixel_mask
;
116 volatile u32 ramdac_palette_rdaddr
;
117 volatile u32 ramdac_idx_lo
;
118 volatile u32 ramdac_idx_hi
;
119 volatile u32 ramdac_idx_data
;
120 volatile u32 ramdac_idx_ctl
;
121 volatile u32 ramdac_xxx
[1784];
124 struct p9100_cmd_parameng
{
125 volatile u32 parameng_status
;
126 volatile u32 parameng_bltcmd
;
127 volatile u32 parameng_quadcmd
;
132 struct p9100_regs __iomem
*regs
;
135 #define P9100_FLAG_BLANKED 0x00000001
137 unsigned long physbase
;
138 unsigned long fbsize
;
140 struct sbus_dev
*sdev
;
141 struct list_head list
;
145 * p9100_setcolreg - Optional function. Sets a color register.
146 * @regno: boolean, 0 copy local, 1 get_user() function
147 * @red: frame buffer colormap structure
148 * @green: The green value which can be up to 16 bits wide
149 * @blue: The blue value which can be up to 16 bits wide.
150 * @transp: If supported the alpha value which can be up to 16 bits wide.
151 * @info: frame buffer info structure
153 static int p9100_setcolreg(unsigned regno
,
154 unsigned red
, unsigned green
, unsigned blue
,
155 unsigned transp
, struct fb_info
*info
)
157 struct p9100_par
*par
= (struct p9100_par
*) info
->par
;
158 struct p9100_regs __iomem
*regs
= par
->regs
;
168 spin_lock_irqsave(&par
->lock
, flags
);
170 sbus_writel((regno
<< 16), ®s
->ramdac_cmap_wridx
);
171 sbus_writel((red
<< 16), ®s
->ramdac_palette_data
);
172 sbus_writel((green
<< 16), ®s
->ramdac_palette_data
);
173 sbus_writel((blue
<< 16), ®s
->ramdac_palette_data
);
175 spin_unlock_irqrestore(&par
->lock
, flags
);
181 * p9100_blank - Optional function. Blanks the display.
182 * @blank_mode: the blank mode we want.
183 * @info: frame buffer structure that represents a single frame buffer
186 p9100_blank(int blank
, struct fb_info
*info
)
188 struct p9100_par
*par
= (struct p9100_par
*) info
->par
;
189 struct p9100_regs __iomem
*regs
= par
->regs
;
193 spin_lock_irqsave(&par
->lock
, flags
);
196 case FB_BLANK_UNBLANK
: /* Unblanking */
197 val
= sbus_readl(®s
->vid_screenpaint_timectl1
);
198 val
|= SCREENPAINT_TIMECTL1_ENABLE_VIDEO
;
199 sbus_writel(val
, ®s
->vid_screenpaint_timectl1
);
200 par
->flags
&= ~P9100_FLAG_BLANKED
;
203 case FB_BLANK_NORMAL
: /* Normal blanking */
204 case FB_BLANK_VSYNC_SUSPEND
: /* VESA blank (vsync off) */
205 case FB_BLANK_HSYNC_SUSPEND
: /* VESA blank (hsync off) */
206 case FB_BLANK_POWERDOWN
: /* Poweroff */
207 val
= sbus_readl(®s
->vid_screenpaint_timectl1
);
208 val
&= ~SCREENPAINT_TIMECTL1_ENABLE_VIDEO
;
209 sbus_writel(val
, ®s
->vid_screenpaint_timectl1
);
210 par
->flags
|= P9100_FLAG_BLANKED
;
214 spin_unlock_irqrestore(&par
->lock
, flags
);
219 static struct sbus_mmap_map p9100_mmap_map
[] = {
220 { CG3_MMAP_OFFSET
, 0, SBUS_MMAP_FBSIZE(1) },
224 static int p9100_mmap(struct fb_info
*info
, struct file
*file
, struct vm_area_struct
*vma
)
226 struct p9100_par
*par
= (struct p9100_par
*)info
->par
;
228 return sbusfb_mmap_helper(p9100_mmap_map
,
229 par
->physbase
, par
->fbsize
,
230 par
->sdev
->reg_addrs
[0].which_io
,
234 static int p9100_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
,
235 unsigned long arg
, struct fb_info
*info
)
237 struct p9100_par
*par
= (struct p9100_par
*) info
->par
;
239 /* Make it look like a cg3. */
240 return sbusfb_ioctl_helper(cmd
, arg
, info
,
241 FBTYPE_SUN3COLOR
, 8, par
->fbsize
);
249 p9100_init_fix(struct fb_info
*info
, int linebytes
)
251 struct p9100_par
*par
= (struct p9100_par
*)info
->par
;
253 strlcpy(info
->fix
.id
, par
->sdev
->prom_name
, sizeof(info
->fix
.id
));
255 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
256 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
258 info
->fix
.line_length
= linebytes
;
260 info
->fix
.accel
= FB_ACCEL_SUN_CGTHREE
;
265 struct p9100_par par
;
266 struct list_head list
;
268 static LIST_HEAD(p9100_list
);
270 static void p9100_init_one(struct sbus_dev
*sdev
)
272 struct all_info
*all
;
275 all
= kmalloc(sizeof(*all
), GFP_KERNEL
);
277 printk(KERN_ERR
"p9100: Cannot allocate memory.\n");
280 memset(all
, 0, sizeof(*all
));
282 INIT_LIST_HEAD(&all
->list
);
284 spin_lock_init(&all
->par
.lock
);
285 all
->par
.sdev
= sdev
;
287 /* This is the framebuffer and the only resource apps can mmap. */
288 all
->par
.physbase
= sdev
->reg_addrs
[2].phys_addr
;
290 sbusfb_fill_var(&all
->info
.var
, sdev
->prom_node
, 8);
292 linebytes
= prom_getintdefault(sdev
->prom_node
, "linebytes",
294 all
->par
.fbsize
= PAGE_ALIGN(linebytes
* all
->info
.var
.yres
);
296 all
->par
.regs
= sbus_ioremap(&sdev
->resource
[0], 0,
297 sizeof(struct p9100_regs
), "p9100 regs");
299 all
->info
.flags
= FBINFO_DEFAULT
;
300 all
->info
.fbops
= &p9100_ops
;
301 #ifdef CONFIG_SPARC32
302 all
->info
.screen_base
= (char __iomem
*)
303 prom_getintdefault(sdev
->prom_node
, "address", 0);
305 if (!all
->info
.screen_base
)
306 all
->info
.screen_base
= sbus_ioremap(&sdev
->resource
[2], 0,
307 all
->par
.fbsize
, "p9100 ram");
308 all
->info
.par
= &all
->par
;
310 p9100_blank(0, &all
->info
);
312 if (fb_alloc_cmap(&all
->info
.cmap
, 256, 0)) {
313 printk(KERN_ERR
"p9100: Could not allocate color map.\n");
318 p9100_init_fix(&all
->info
, linebytes
);
320 if (register_framebuffer(&all
->info
) < 0) {
321 printk(KERN_ERR
"p9100: Could not register framebuffer.\n");
322 fb_dealloc_cmap(&all
->info
.cmap
);
327 list_add(&all
->list
, &p9100_list
);
329 printk("p9100: %s at %lx:%lx\n",
331 (long) sdev
->reg_addrs
[0].which_io
,
332 (long) sdev
->reg_addrs
[0].phys_addr
);
335 int __init
p9100_init(void)
337 struct sbus_bus
*sbus
;
338 struct sbus_dev
*sdev
;
340 if (fb_get_options("p9100fb", NULL
))
343 for_all_sbusdev(sdev
, sbus
) {
344 if (!strcmp(sdev
->prom_name
, "p9100"))
345 p9100_init_one(sdev
);
351 void __exit
p9100_exit(void)
353 struct list_head
*pos
, *tmp
;
355 list_for_each_safe(pos
, tmp
, &p9100_list
) {
356 struct all_info
*all
= list_entry(pos
, typeof(*all
), list
);
358 unregister_framebuffer(&all
->info
);
359 fb_dealloc_cmap(&all
->info
.cmap
);
365 p9100_setup(char *arg
)
367 /* No cmdline options yet... */
371 module_init(p9100_init
);
374 module_exit(p9100_exit
);
377 MODULE_DESCRIPTION("framebuffer driver for P9100 chipsets");
378 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
379 MODULE_LICENSE("GPL");