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 vm_area_struct
*);
35 static int p9100_ioctl(struct fb_info
*, unsigned int, unsigned long);
38 * Frame buffer operations
41 static struct fb_ops p9100_ops
= {
43 .fb_setcolreg
= p9100_setcolreg
,
44 .fb_blank
= p9100_blank
,
45 .fb_fillrect
= cfb_fillrect
,
46 .fb_copyarea
= cfb_copyarea
,
47 .fb_imageblit
= cfb_imageblit
,
48 .fb_mmap
= p9100_mmap
,
49 .fb_ioctl
= p9100_ioctl
,
51 .fb_compat_ioctl
= sbusfb_compat_ioctl
,
55 /* P9100 control registers */
56 #define P9100_SYSCTL_OFF 0x0UL
57 #define P9100_VIDEOCTL_OFF 0x100UL
58 #define P9100_VRAMCTL_OFF 0x180UL
59 #define P9100_RAMDAC_OFF 0x200UL
60 #define P9100_VIDEOCOPROC_OFF 0x400UL
62 /* P9100 command registers */
63 #define P9100_CMD_OFF 0x0UL
65 /* P9100 framebuffer memory */
66 #define P9100_FB_OFF 0x0UL
68 /* 3 bits: 2=8bpp 3=16bpp 5=32bpp 7=24bpp */
69 #define SYS_CONFIG_PIXELSIZE_SHIFT 26
71 #define SCREENPAINT_TIMECTL1_ENABLE_VIDEO 0x20 /* 0 = off, 1 = on */
74 /* Registers for the system control */
75 volatile u32 sys_base
;
76 volatile u32 sys_config
;
77 volatile u32 sys_intr
;
78 volatile u32 sys_int_ena
;
79 volatile u32 sys_alt_rd
;
80 volatile u32 sys_alt_wr
;
81 volatile u32 sys_xxx
[58];
83 /* Registers for the video control */
84 volatile u32 vid_base
;
85 volatile u32 vid_hcnt
;
86 volatile u32 vid_htotal
;
87 volatile u32 vid_hsync_rise
;
88 volatile u32 vid_hblank_rise
;
89 volatile u32 vid_hblank_fall
;
90 volatile u32 vid_hcnt_preload
;
91 volatile u32 vid_vcnt
;
92 volatile u32 vid_vlen
;
93 volatile u32 vid_vsync_rise
;
94 volatile u32 vid_vblank_rise
;
95 volatile u32 vid_vblank_fall
;
96 volatile u32 vid_vcnt_preload
;
97 volatile u32 vid_screenpaint_addr
;
98 volatile u32 vid_screenpaint_timectl1
;
99 volatile u32 vid_screenpaint_qsfcnt
;
100 volatile u32 vid_screenpaint_timectl2
;
101 volatile u32 vid_xxx
[15];
103 /* Registers for the video control */
104 volatile u32 vram_base
;
105 volatile u32 vram_memcfg
;
106 volatile u32 vram_refresh_pd
;
107 volatile u32 vram_refresh_cnt
;
108 volatile u32 vram_raslo_max
;
109 volatile u32 vram_raslo_cur
;
110 volatile u32 pwrup_cfg
;
111 volatile u32 vram_xxx
[25];
113 /* Registers for IBM RGB528 Palette */
114 volatile u32 ramdac_cmap_wridx
;
115 volatile u32 ramdac_palette_data
;
116 volatile u32 ramdac_pixel_mask
;
117 volatile u32 ramdac_palette_rdaddr
;
118 volatile u32 ramdac_idx_lo
;
119 volatile u32 ramdac_idx_hi
;
120 volatile u32 ramdac_idx_data
;
121 volatile u32 ramdac_idx_ctl
;
122 volatile u32 ramdac_xxx
[1784];
125 struct p9100_cmd_parameng
{
126 volatile u32 parameng_status
;
127 volatile u32 parameng_bltcmd
;
128 volatile u32 parameng_quadcmd
;
133 struct p9100_regs __iomem
*regs
;
136 #define P9100_FLAG_BLANKED 0x00000001
138 unsigned long physbase
;
139 unsigned long fbsize
;
141 struct sbus_dev
*sdev
;
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 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 fb_info
*info
, unsigned int cmd
,
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);
291 all
->info
.var
.red
.length
= 8;
292 all
->info
.var
.green
.length
= 8;
293 all
->info
.var
.blue
.length
= 8;
295 linebytes
= prom_getintdefault(sdev
->prom_node
, "linebytes",
297 all
->par
.fbsize
= PAGE_ALIGN(linebytes
* all
->info
.var
.yres
);
299 all
->par
.regs
= sbus_ioremap(&sdev
->resource
[0], 0,
300 sizeof(struct p9100_regs
), "p9100 regs");
302 all
->info
.flags
= FBINFO_DEFAULT
;
303 all
->info
.fbops
= &p9100_ops
;
304 #ifdef CONFIG_SPARC32
305 all
->info
.screen_base
= (char __iomem
*)
306 prom_getintdefault(sdev
->prom_node
, "address", 0);
308 if (!all
->info
.screen_base
)
309 all
->info
.screen_base
= sbus_ioremap(&sdev
->resource
[2], 0,
310 all
->par
.fbsize
, "p9100 ram");
311 all
->info
.par
= &all
->par
;
313 p9100_blank(0, &all
->info
);
315 if (fb_alloc_cmap(&all
->info
.cmap
, 256, 0)) {
316 printk(KERN_ERR
"p9100: Could not allocate color map.\n");
321 p9100_init_fix(&all
->info
, linebytes
);
323 if (register_framebuffer(&all
->info
) < 0) {
324 printk(KERN_ERR
"p9100: Could not register framebuffer.\n");
325 fb_dealloc_cmap(&all
->info
.cmap
);
329 fb_set_cmap(&all
->info
.cmap
, &all
->info
);
331 list_add(&all
->list
, &p9100_list
);
333 printk("p9100: %s at %lx:%lx\n",
335 (long) sdev
->reg_addrs
[0].which_io
,
336 (long) sdev
->reg_addrs
[0].phys_addr
);
339 int __init
p9100_init(void)
341 struct sbus_bus
*sbus
;
342 struct sbus_dev
*sdev
;
344 if (fb_get_options("p9100fb", NULL
))
347 for_all_sbusdev(sdev
, sbus
) {
348 if (!strcmp(sdev
->prom_name
, "p9100"))
349 p9100_init_one(sdev
);
355 void __exit
p9100_exit(void)
357 struct list_head
*pos
, *tmp
;
359 list_for_each_safe(pos
, tmp
, &p9100_list
) {
360 struct all_info
*all
= list_entry(pos
, typeof(*all
), list
);
362 unregister_framebuffer(&all
->info
);
363 fb_dealloc_cmap(&all
->info
.cmap
);
369 p9100_setup(char *arg
)
371 /* No cmdline options yet... */
375 module_init(p9100_init
);
378 module_exit(p9100_exit
);
381 MODULE_DESCRIPTION("framebuffer driver for P9100 chipsets");
382 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
383 MODULE_LICENSE("GPL");