Commit 53eed4ec authored by David Vrabel's avatar David Vrabel Committed by Linus Torvalds

[PATCH] fbdev: geode updates

Geode framebuffer driver updates:

- Local mode list (taken from modedb.c) containing only relevant modes.
  This also makes the driver work as a module.

- Make it a PCI driver (from James Simmons <jsimmons@infradead.org>).

- A few other minor cosmetic bits and pieces.
Signed-off-by: default avatarDavid Vrabel <dvrabel@arcom.com>
Signed-off-by: default avatarJames Simmons <jsimmons@infradead.org>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: default avatarAdrian Bunk <bunk@stusta.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 4c7ffe0b
...@@ -3,15 +3,13 @@ ...@@ -3,15 +3,13 @@
# #
config FB_GEODE config FB_GEODE
bool "AMD Geode family framebuffer support (EXPERIMENTAL)" bool "AMD Geode family framebuffer support (EXPERIMENTAL)"
default n depends on FB && PCI && EXPERIMENTAL && X86
depends on FB && EXPERIMENTAL && X86
---help--- ---help---
Say 'Y' here to allow you to select framebuffer drivers for Say 'Y' here to allow you to select framebuffer drivers for
the AMD Geode family of processors. the AMD Geode family of processors.
config FB_GEODE_GX1 config FB_GEODE_GX1
tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)" tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)"
default n
depends on FB_GEODE && EXPERIMENTAL depends on FB_GEODE && EXPERIMENTAL
select FB_CFB_FILLRECT select FB_CFB_FILLRECT
select FB_CFB_COPYAREA select FB_CFB_COPYAREA
...@@ -21,9 +19,7 @@ config FB_GEODE_GX1 ...@@ -21,9 +19,7 @@ config FB_GEODE_GX1
Framebuffer driver for the display controller integrated into the Framebuffer driver for the display controller integrated into the
AMD Geode GX1 processor. AMD Geode GX1 processor.
This driver is also available as a module ( = code which can be To compile this driver as a module, choose M here: the module will be
inserted and removed from the running kernel whenever you want). The called gx1fb.
module will be called gx1fb. If you want to compile it as a module,
say M here and read <file:Documentation/modules.txt>.
If unsure, say N. If unsure, say N.
...@@ -29,7 +29,6 @@ struct geodefb_par { ...@@ -29,7 +29,6 @@ struct geodefb_par {
int enable_crt; int enable_crt;
int panel_x; /* dimensions of an attached flat panel, non-zero => enable panel */ int panel_x; /* dimensions of an attached flat panel, non-zero => enable panel */
int panel_y; int panel_y;
struct pci_dev *vid_dev;
void __iomem *dc_regs; void __iomem *dc_regs;
void __iomem *vid_regs; void __iomem *vid_regs;
struct geode_dc_ops *dc_ops; struct geode_dc_ops *dc_ops;
......
...@@ -30,6 +30,62 @@ static char mode_option[32] = "640x480-16@60"; ...@@ -30,6 +30,62 @@ static char mode_option[32] = "640x480-16@60";
static int crt_option = 1; static int crt_option = 1;
static char panel_option[32] = ""; static char panel_option[32] = "";
/* Modes relevant to the GX1 (taken from modedb.c) */
static const struct fb_videomode __initdata gx1_modedb[] = {
/* 640x480-60 VESA */
{ NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 640x480-75 VESA */
{ NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 640x480-85 VESA */
{ NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3,
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 800x600-60 VESA */
{ NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 800x600-75 VESA */
{ NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 800x600-85 VESA */
{ NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 1024x768-60 VESA */
{ NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 1024x768-75 VESA */
{ NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 1024x768-85 VESA */
{ NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 1280x960-60 VESA */
{ NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 1280x960-85 VESA */
{ NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 1280x1024-60 VESA */
{ NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 1280x1024-75 VESA */
{ NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 1280x1024-85 VESA */
{ NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
};
static int gx1_line_delta(int xres, int bpp) static int gx1_line_delta(int xres, int bpp)
{ {
int line_delta = xres * (bpp >> 3); int line_delta = xres * (bpp >> 3);
...@@ -47,8 +103,6 @@ static int gx1fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ...@@ -47,8 +103,6 @@ static int gx1fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{ {
struct geodefb_par *par = info->par; struct geodefb_par *par = info->par;
printk(KERN_DEBUG "%s()\n", __FUNCTION__);
/* Maximum resolution is 1280x1024. */ /* Maximum resolution is 1280x1024. */
if (var->xres > 1280 || var->yres > 1024) if (var->xres > 1280 || var->yres > 1024)
return -EINVAL; return -EINVAL;
...@@ -146,40 +200,48 @@ static int gx1fb_blank(int blank_mode, struct fb_info *info) ...@@ -146,40 +200,48 @@ static int gx1fb_blank(int blank_mode, struct fb_info *info)
return par->vid_ops->blank_display(info, blank_mode); return par->vid_ops->blank_display(info, blank_mode);
} }
static int __init gx1fb_map_video_memory(struct fb_info *info) static int __init gx1fb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
{ {
struct geodefb_par *par = info->par; struct geodefb_par *par = info->par;
unsigned gx_base; unsigned gx_base;
int fb_len; int fb_len;
int ret;
gx_base = gx1_gx_base(); gx_base = gx1_gx_base();
if (!gx_base) if (!gx_base)
return -ENODEV; return -ENODEV;
par->vid_dev = pci_get_device(PCI_VENDOR_ID_CYRIX, ret = pci_enable_device(dev);
PCI_DEVICE_ID_CYRIX_5530_VIDEO, NULL); if (ret < 0)
if (!par->vid_dev) return ret;
return -ENODEV;
par->vid_regs = ioremap(pci_resource_start(par->vid_dev, 1), ret = pci_request_region(dev, 1, "gx1fb (video)");
pci_resource_len(par->vid_dev, 1)); if (ret < 0)
return ret;
par->vid_regs = ioremap(pci_resource_start(dev, 1),
pci_resource_len(dev, 1));
if (!par->vid_regs) if (!par->vid_regs)
return -ENOMEM; return -ENOMEM;
if (!request_mem_region(gx_base + 0x8300, 0x100, "gx1fb (display controller)"))
return -EBUSY;
par->dc_regs = ioremap(gx_base + 0x8300, 0x100); par->dc_regs = ioremap(gx_base + 0x8300, 0x100);
if (!par->dc_regs) if (!par->dc_regs)
return -ENOMEM; return -ENOMEM;
info->fix.smem_start = gx_base + 0x800000; ret = pci_request_region(dev, 0, "gx1fb (frame buffer)");
if (ret < 0 )
return -EBUSY;
if ((fb_len = gx1_frame_buffer_size()) < 0) if ((fb_len = gx1_frame_buffer_size()) < 0)
return -ENOMEM; return -ENOMEM;
info->fix.smem_start = pci_resource_start(dev, 0);
info->fix.smem_len = fb_len; info->fix.smem_len = fb_len;
info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
if (!info->screen_base) if (!info->screen_base)
return -ENOMEM; return -ENOMEM;
printk(KERN_INFO "%s: %d Kibyte of video memory at 0x%lx\n", dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n",
info->fix.id, info->fix.smem_len / 1024, info->fix.smem_start); info->fix.smem_len / 1024, info->fix.smem_start);
return 0; return 0;
} }
...@@ -216,13 +278,13 @@ static struct fb_ops gx1fb_ops = { ...@@ -216,13 +278,13 @@ static struct fb_ops gx1fb_ops = {
.fb_cursor = soft_cursor, .fb_cursor = soft_cursor,
}; };
static struct fb_info * __init gx1fb_init_fbinfo(void) static struct fb_info * __init gx1fb_init_fbinfo(struct device *dev)
{ {
struct fb_info *info;
struct geodefb_par *par; struct geodefb_par *par;
struct fb_info *info;
/* Alloc enough space for the pseudo palette. */ /* Alloc enough space for the pseudo palette. */
info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, NULL); info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, dev);
if (!info) if (!info)
return NULL; return NULL;
...@@ -255,47 +317,37 @@ static struct fb_info * __init gx1fb_init_fbinfo(void) ...@@ -255,47 +317,37 @@ static struct fb_info * __init gx1fb_init_fbinfo(void)
/* CRT and panel options */ /* CRT and panel options */
par->enable_crt = crt_option; par->enable_crt = crt_option;
if (parse_panel_option(info) < 0) if (parse_panel_option(info) < 0)
printk(KERN_WARNING "%s: invalid 'panel' option -- disabling flat panel\n", printk(KERN_WARNING "gx1fb: invalid 'panel' option -- disabling flat panel\n");
info->fix.id);
if (!par->panel_x) if (!par->panel_x)
par->enable_crt = 1; /* fall back to CRT if no panel is specified */ par->enable_crt = 1; /* fall back to CRT if no panel is specified */
return info; return info;
} }
static int __init gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
static struct fb_info *gx1fb_info;
static int __init gx1fb_init(void)
{ {
struct geodefb_par *par;
struct fb_info *info; struct fb_info *info;
struct geodefb_par *par;
int ret; int ret;
#ifndef MODULE info = gx1fb_init_fbinfo(&pdev->dev);
if (fb_get_options("gx1fb", NULL))
return -ENODEV;
#endif
info = gx1fb_init_fbinfo();
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;
gx1fb_info = info;
par = info->par; par = info->par;
/* GX1 display controller and CS5530 video device */ /* GX1 display controller and CS5530 video device */
par->dc_ops = &gx1_dc_ops; par->dc_ops = &gx1_dc_ops;
par->vid_ops = &cs5530_vid_ops; par->vid_ops = &cs5530_vid_ops;
if ((ret = gx1fb_map_video_memory(info)) < 0) { if ((ret = gx1fb_map_video_memory(info, pdev)) < 0) {
printk(KERN_ERR "%s: gx1fb_map_video_memory() failed\n", info->fix.id); dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n");
goto err; goto err;
} }
ret = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16); ret = fb_find_mode(&info->var, info, mode_option,
gx1_modedb, ARRAY_SIZE(gx1_modedb), NULL, 16);
if (ret == 0 || ret == 4) { if (ret == 0 || ret == 4) {
printk(KERN_ERR "%s: could not find valid video mode\n", info->fix.id); dev_err(&pdev->dev, "could not find valid video mode\n");
ret = -EINVAL; ret = -EINVAL;
goto err; goto err;
} }
...@@ -310,39 +362,83 @@ static int __init gx1fb_init(void) ...@@ -310,39 +362,83 @@ static int __init gx1fb_init(void)
ret = -EINVAL; ret = -EINVAL;
goto err; goto err;
} }
pci_set_drvdata(pdev, info);
printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
return 0; return 0;
err: err:
if (info->screen_base) if (info->screen_base) {
iounmap(info->screen_base); iounmap(info->screen_base);
if (par->vid_regs) pci_release_region(pdev, 0);
}
if (par->vid_regs) {
iounmap(par->vid_regs); iounmap(par->vid_regs);
if (par->dc_regs) pci_release_region(pdev, 1);
}
if (par->dc_regs) {
iounmap(par->dc_regs); iounmap(par->dc_regs);
if (par->vid_dev) release_mem_region(gx1_gx_base() + 0x8300, 0x100);
pci_dev_put(par->vid_dev); }
pci_disable_device(pdev);
if (info) if (info)
framebuffer_release(info); framebuffer_release(info);
return ret; return ret;
} }
static void __exit gx1fb_cleanup(void) static void gx1fb_remove(struct pci_dev *pdev)
{ {
struct fb_info *info = gx1fb_info; struct fb_info *info = pci_get_drvdata(pdev);
struct geodefb_par *par = gx1fb_info->par; struct geodefb_par *par = info->par;
unregister_framebuffer(info); unregister_framebuffer(info);
iounmap((void __iomem *)info->screen_base); iounmap((void __iomem *)info->screen_base);
pci_release_region(pdev, 0);
iounmap(par->vid_regs); iounmap(par->vid_regs);
pci_release_region(pdev, 1);
iounmap(par->dc_regs); iounmap(par->dc_regs);
release_mem_region(gx1_gx_base() + 0x8300, 0x100);
pci_dev_put(par->vid_dev); pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
framebuffer_release(info); framebuffer_release(info);
} }
static struct pci_device_id gx1fb_id_table[] = {
{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_VIDEO,
PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
0xff0000, 0 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, gx1fb_id_table);
static struct pci_driver gx1fb_driver = {
.name = "gx1fb",
.id_table = gx1fb_id_table,
.probe = gx1fb_probe,
.remove = gx1fb_remove,
};
static int __init gx1fb_init(void)
{
#ifndef MODULE
if (fb_get_options("gx1fb", NULL))
return -ENODEV;
#endif
return pci_register_driver(&gx1fb_driver);
}
static void __exit gx1fb_cleanup(void)
{
pci_unregister_driver(&gx1fb_driver);
}
module_init(gx1fb_init); module_init(gx1fb_init);
module_exit(gx1fb_cleanup); module_exit(gx1fb_cleanup);
......
...@@ -69,8 +69,6 @@ static const struct cs5530_pll_entry cs5530_pll_table[] = { ...@@ -69,8 +69,6 @@ static const struct cs5530_pll_entry cs5530_pll_table[] = {
{ 4310, 0x2FB1B802, }, /* 232.0000 */ { 4310, 0x2FB1B802, }, /* 232.0000 */
}; };
#define NUM_CS5530_FREQUENCIES sizeof(cs5530_pll_table)/sizeof(struct cs5530_pll_entry)
static void cs5530_set_dclk_frequency(struct fb_info *info) static void cs5530_set_dclk_frequency(struct fb_info *info)
{ {
struct geodefb_par *par = info->par; struct geodefb_par *par = info->par;
...@@ -82,7 +80,7 @@ static void cs5530_set_dclk_frequency(struct fb_info *info) ...@@ -82,7 +80,7 @@ static void cs5530_set_dclk_frequency(struct fb_info *info)
value = cs5530_pll_table[0].pll_value; value = cs5530_pll_table[0].pll_value;
min = cs5530_pll_table[0].pixclock - info->var.pixclock; min = cs5530_pll_table[0].pixclock - info->var.pixclock;
if (min < 0) min = -min; if (min < 0) min = -min;
for (i = 1; i < NUM_CS5530_FREQUENCIES; i++) { for (i = 1; i < ARRAY_SIZE(cs5530_pll_table); i++) {
diff = cs5530_pll_table[i].pixclock - info->var.pixclock; diff = cs5530_pll_table[i].pixclock - info->var.pixclock;
if (diff < 0L) diff = -diff; if (diff < 0L) diff = -diff;
if (diff < min) { if (diff < min) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment