2 * drivers/video/geode/gx1fb_core.c
3 * -- Geode GX1 framebuffer driver
5 * Copyright (C) 2005 Arcom Control Systems Ltd.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/string.h>
18 #include <linux/tty.h>
19 #include <linux/slab.h>
20 #include <linux/delay.h>
22 #include <linux/init.h>
23 #include <linux/pci.h>
26 #include "display_gx1.h"
27 #include "video_cs5530.h"
29 static char mode_option
[32] = "640x480-16@60";
30 static int crt_option
= 1;
31 static char panel_option
[32] = "";
33 static int gx1_line_delta(int xres
, int bpp
)
35 int line_delta
= xres
* (bpp
>> 3);
37 if (line_delta
> 2048)
39 else if (line_delta
> 1024)
46 static int gx1fb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
48 struct geodefb_par
*par
= info
->par
;
50 printk(KERN_DEBUG
"%s()\n", __FUNCTION__
);
52 /* Maximum resolution is 1280x1024. */
53 if (var
->xres
> 1280 || var
->yres
> 1024)
56 if (par
->panel_x
&& (var
->xres
> par
->panel_x
|| var
->yres
> par
->panel_y
))
59 /* Only 16 bpp and 8 bpp is supported by the hardware. */
60 if (var
->bits_per_pixel
== 16) {
61 var
->red
.offset
= 11; var
->red
.length
= 5;
62 var
->green
.offset
= 5; var
->green
.length
= 6;
63 var
->blue
.offset
= 0; var
->blue
.length
= 5;
64 var
->transp
.offset
= 0; var
->transp
.length
= 0;
65 } else if (var
->bits_per_pixel
== 8) {
66 var
->red
.offset
= 0; var
->red
.length
= 8;
67 var
->green
.offset
= 0; var
->green
.length
= 8;
68 var
->blue
.offset
= 0; var
->blue
.length
= 8;
69 var
->transp
.offset
= 0; var
->transp
.length
= 0;
73 /* Enough video memory? */
74 if (gx1_line_delta(var
->xres
, var
->bits_per_pixel
) * var
->yres
> info
->fix
.smem_len
)
77 /* FIXME: Check timing parameters here? */
82 static int gx1fb_set_par(struct fb_info
*info
)
84 struct geodefb_par
*par
= info
->par
;
86 if (info
->var
.bits_per_pixel
== 16) {
87 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
88 fb_dealloc_cmap(&info
->cmap
);
90 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
91 fb_alloc_cmap(&info
->cmap
, 1<<info
->var
.bits_per_pixel
, 0);
94 info
->fix
.line_length
= gx1_line_delta(info
->var
.xres
, info
->var
.bits_per_pixel
);
96 par
->dc_ops
->set_mode(info
);
101 static inline u_int
chan_to_field(u_int chan
, struct fb_bitfield
*bf
)
104 chan
>>= 16 - bf
->length
;
105 return chan
<< bf
->offset
;
108 static int gx1fb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
109 unsigned blue
, unsigned transp
,
110 struct fb_info
*info
)
112 struct geodefb_par
*par
= info
->par
;
114 if (info
->var
.grayscale
) {
115 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
116 red
= green
= blue
= (red
* 77 + green
* 151 + blue
* 28) >> 8;
119 /* Truecolor has hardware independent palette */
120 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
) {
121 u32
*pal
= info
->pseudo_palette
;
127 v
= chan_to_field(red
, &info
->var
.red
);
128 v
|= chan_to_field(green
, &info
->var
.green
);
129 v
|= chan_to_field(blue
, &info
->var
.blue
);
136 par
->dc_ops
->set_palette_reg(info
, regno
, red
, green
, blue
);
142 static int gx1fb_blank(int blank_mode
, struct fb_info
*info
)
144 struct geodefb_par
*par
= info
->par
;
146 return par
->vid_ops
->blank_display(info
, blank_mode
);
149 static int __init
gx1fb_map_video_memory(struct fb_info
*info
)
151 struct geodefb_par
*par
= info
->par
;
155 gx_base
= gx1_gx_base();
159 par
->vid_dev
= pci_get_device(PCI_VENDOR_ID_CYRIX
,
160 PCI_DEVICE_ID_CYRIX_5530_VIDEO
, NULL
);
164 par
->vid_regs
= ioremap(pci_resource_start(par
->vid_dev
, 1),
165 pci_resource_len(par
->vid_dev
, 1));
169 par
->dc_regs
= ioremap(gx_base
+ 0x8300, 0x100);
173 info
->fix
.smem_start
= gx_base
+ 0x800000;
174 if ((fb_len
= gx1_frame_buffer_size()) < 0)
176 info
->fix
.smem_len
= fb_len
;
177 info
->screen_base
= ioremap(info
->fix
.smem_start
, info
->fix
.smem_len
);
178 if (!info
->screen_base
)
181 printk(KERN_INFO
"%s: %d Kibyte of video memory at 0x%lx\n",
182 info
->fix
.id
, info
->fix
.smem_len
/ 1024, info
->fix
.smem_start
);
187 static int parse_panel_option(struct fb_info
*info
)
189 struct geodefb_par
*par
= info
->par
;
191 if (strcmp(panel_option
, "") != 0) {
194 x
= simple_strtol(panel_option
, &s
, 10);
197 y
= simple_strtol(s
+ 1, NULL
, 10);
206 static struct fb_ops gx1fb_ops
= {
207 .owner
= THIS_MODULE
,
208 .fb_check_var
= gx1fb_check_var
,
209 .fb_set_par
= gx1fb_set_par
,
210 .fb_setcolreg
= gx1fb_setcolreg
,
211 .fb_blank
= gx1fb_blank
,
212 /* No HW acceleration for now. */
213 .fb_fillrect
= cfb_fillrect
,
214 .fb_copyarea
= cfb_copyarea
,
215 .fb_imageblit
= cfb_imageblit
,
216 .fb_cursor
= soft_cursor
,
219 static struct fb_info
* __init
gx1fb_init_fbinfo(void)
221 struct fb_info
*info
;
222 struct geodefb_par
*par
;
224 /* Alloc enough space for the pseudo palette. */
225 info
= framebuffer_alloc(sizeof(struct geodefb_par
) + sizeof(u32
) * 16, NULL
);
231 strcpy(info
->fix
.id
, "GX1");
233 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
234 info
->fix
.type_aux
= 0;
235 info
->fix
.xpanstep
= 0;
236 info
->fix
.ypanstep
= 0;
237 info
->fix
.ywrapstep
= 0;
238 info
->fix
.accel
= FB_ACCEL_NONE
;
240 info
->var
.nonstd
= 0;
241 info
->var
.activate
= FB_ACTIVATE_NOW
;
242 info
->var
.height
= -1;
243 info
->var
.width
= -1;
244 info
->var
.accel_flags
= 0;
245 info
->var
.vmode
= FB_VMODE_NONINTERLACED
;
247 info
->fbops
= &gx1fb_ops
;
248 info
->flags
= FBINFO_DEFAULT
;
251 info
->pseudo_palette
= (void *)par
+ sizeof(struct geodefb_par
);
253 info
->var
.grayscale
= 0;
255 /* CRT and panel options */
256 par
->enable_crt
= crt_option
;
257 if (parse_panel_option(info
) < 0)
258 printk(KERN_WARNING
"%s: invalid 'panel' option -- disabling flat panel\n",
261 par
->enable_crt
= 1; /* fall back to CRT if no panel is specified */
267 static struct fb_info
*gx1fb_info
;
269 static int __init
gx1fb_init(void)
271 struct fb_info
*info
;
272 struct geodefb_par
*par
;
276 if (fb_get_options("gx1fb", NULL
))
280 info
= gx1fb_init_fbinfo();
287 /* GX1 display controller and CS5530 video device */
288 par
->dc_ops
= &gx1_dc_ops
;
289 par
->vid_ops
= &cs5530_vid_ops
;
291 if ((ret
= gx1fb_map_video_memory(info
)) < 0) {
292 printk(KERN_ERR
"%s: gx1fb_map_video_memory() failed\n", info
->fix
.id
);
296 ret
= fb_find_mode(&info
->var
, info
, mode_option
, NULL
, 0, NULL
, 16);
297 if (ret
== 0 || ret
== 4) {
298 printk(KERN_ERR
"%s: could not find valid video mode\n", info
->fix
.id
);
303 /* Clear the frame buffer of garbage. */
304 memset_io(info
->screen_base
, 0, info
->fix
.smem_len
);
306 gx1fb_check_var(&info
->var
, info
);
309 if (register_framebuffer(info
) < 0) {
313 printk(KERN_INFO
"fb%d: %s frame buffer device\n", info
->node
, info
->fix
.id
);
317 if (info
->screen_base
)
318 iounmap(info
->screen_base
);
320 iounmap(par
->vid_regs
);
322 iounmap(par
->dc_regs
);
324 pci_dev_put(par
->vid_dev
);
326 framebuffer_release(info
);
330 static void __exit
gx1fb_cleanup(void)
332 struct fb_info
*info
= gx1fb_info
;
333 struct geodefb_par
*par
= gx1fb_info
->par
;
335 unregister_framebuffer(info
);
337 iounmap((void __iomem
*)info
->screen_base
);
338 iounmap(par
->vid_regs
);
339 iounmap(par
->dc_regs
);
341 pci_dev_put(par
->vid_dev
);
343 framebuffer_release(info
);
346 module_init(gx1fb_init
);
347 module_exit(gx1fb_cleanup
);
349 module_param_string(mode
, mode_option
, sizeof(mode_option
), 0444);
350 MODULE_PARM_DESC(mode
, "video mode (<x>x<y>[-<bpp>][@<refr>])");
352 module_param_named(crt
, crt_option
, int, 0444);
353 MODULE_PARM_DESC(crt
, "enable CRT output. 0 = off, 1 = on (default)");
355 module_param_string(panel
, panel_option
, sizeof(panel_option
), 0444);
356 MODULE_PARM_DESC(panel
, "size of attached flat panel (<x>x<y>)");
358 MODULE_DESCRIPTION("framebuffer driver for the AMD Geode GX1");
359 MODULE_LICENSE("GPL");