#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/console.h>
+#include <linux/suspend.h>
#include <linux/init.h>
#include <linux/pci.h>
-#include <asm/geode.h>
+#include <linux/cs5535.h>
#include "gxfb.h"
static char *mode_option;
static int vram;
+static int vt_switch;
/* Modes relevant to the GX (taken from modedb.c) */
-static const struct fb_videomode gx_modedb[] __initdata = {
+static struct fb_videomode gx_modedb[] __initdata = {
/* 640x480-60 VESA */
{ NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
};
+#ifdef CONFIG_OLPC
+#include <asm/olpc.h>
+
+static struct fb_videomode gx_dcon_modedb[] __initdata = {
+ /* The only mode the DCON has is 1200x900 */
+ { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 }
+};
+
+static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
+{
+ if (olpc_has_dcon()) {
+ *modedb = (struct fb_videomode *) gx_dcon_modedb;
+ *size = ARRAY_SIZE(gx_dcon_modedb);
+ } else {
+ *modedb = (struct fb_videomode *) gx_modedb;
+ *size = ARRAY_SIZE(gx_modedb);
+ }
+}
+
+#else
+static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
+{
+ *modedb = (struct fb_videomode *) gx_modedb;
+ *size = ARRAY_SIZE(gx_modedb);
+}
+#endif
+
static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
if (var->xres > 1600 || var->yres > 1200)
static int gxfb_set_par(struct fb_info *info)
{
- if (info->var.bits_per_pixel > 8) {
+ if (info->var.bits_per_pixel > 8)
info->fix.visual = FB_VISUAL_TRUECOLOR;
- fb_dealloc_cmap(&info->cmap);
- } else {
+ else
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
- fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
- }
info->fix.line_length = gx_line_delta(info->var.xres, info->var.bits_per_pixel);
ret = pci_request_region(dev, 3, "gxfb (video processor)");
if (ret < 0)
return ret;
- par->vid_regs = ioremap(pci_resource_start(dev, 3),
- pci_resource_len(dev, 3));
+ par->vid_regs = pci_ioremap_bar(dev, 3);
if (!par->vid_regs)
return -ENOMEM;
ret = pci_request_region(dev, 2, "gxfb (display controller)");
if (ret < 0)
return ret;
- par->dc_regs = ioremap(pci_resource_start(dev, 2), pci_resource_len(dev, 2));
+ par->dc_regs = pci_ioremap_bar(dev, 2);
if (!par->dc_regs)
return -ENOMEM;
ret = pci_request_region(dev, 1, "gxfb (graphics processor)");
if (ret < 0)
return ret;
- par->gp_regs = ioremap(pci_resource_start(dev, 1),
- pci_resource_len(dev, 1));
+ par->gp_regs = pci_ioremap_bar(dev, 1);
if (!par->gp_regs)
return -ENOMEM;
info->var.grayscale = 0;
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+ framebuffer_release(info);
+ return NULL;
+ }
+
return info;
}
int ret;
unsigned long val;
+ struct fb_videomode *modedb_ptr;
+ unsigned int modedb_size;
+
info = gxfb_init_fbinfo(&pdev->dev);
if (!info)
return -ENOMEM;
else
par->enable_crt = 1;
+ get_modedb(&modedb_ptr, &modedb_size);
ret = fb_find_mode(&info->var, info, mode_option,
- gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16);
+ modedb_ptr, modedb_size, NULL, 16);
if (ret == 0 || ret == 4) {
dev_err(&pdev->dev, "could not find valid video mode\n");
ret = -EINVAL;
gxfb_check_var(&info->var, info);
gxfb_set_par(info);
+ pm_set_vt_switch(vt_switch);
+
if (register_framebuffer(info) < 0) {
ret = -EINVAL;
goto err;
pci_release_region(pdev, 1);
}
- if (info)
+ if (info) {
+ fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
+ }
return ret;
}
iounmap(par->gp_regs);
pci_release_region(pdev, 1);
+ fb_dealloc_cmap(&info->cmap);
pci_set_drvdata(pdev, NULL);
framebuffer_release(info);
module_param(vram, int, 0);
MODULE_PARM_DESC(vram, "video memory size");
+module_param(vt_switch, int, 0);
+MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume");
+
MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX");
MODULE_LICENSE("GPL");