/*
* Silicon Motion SM7XX frame buffer device
*
* Copyright (C) 2006 Silicon Motion Technology Corp.
* Authors: Ge Wang, gewang@siliconmotion.com
* Boyod boyod.yang@siliconmotion.com.cn
*
* Copyright (C) 2009 Lemote, Inc.
* Author: Wu Zhangjin, wuzhangjin@gmail.com
*
* Copyright (C) 2011 Igalia, S.L.
* Author: Javier M. Mellid <jmunhoz@igalia.com>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
* Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips
*/
#include <linux/io.h>
#include <linux/fb.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/console.h>
#include <linux/screen_info.h>
#ifdef CONFIG_PM
#include <linux/pm.h>
#endif
#include "sm7xx.h"
/*
* Private structure
*/
struct smtcfb_info {
struct pci_dev *pdev;
struct fb_info fb;
u16 chip_id;
u8 chip_rev_id;
void __iomem *lfb; /* linear frame buffer */
void __iomem *dp_regs; /* drawing processor control regs */
void __iomem *vp_regs; /* video processor control regs */
void __iomem *cp_regs; /* capture processor control regs */
void __iomem *mmio; /* memory map IO port */
u_int width;
u_int height;
u_int hz;
u32 colreg[17];
};
void __iomem *smtc_RegBaseAddress; /* Memory Map IO starting address */
static struct fb_var_screeninfo smtcfb_var = {
.xres = 1024,
.yres = 600,
.xres_virtual = 1024,
.yres_virtual = 600,
.bits_per_pixel = 16,
.red = {16, 8, 0},
.green = {8, 8, 0},
.blue = {0, 8, 0},
.activate = FB_ACTIVATE_NOW,
.height = -1,
.width = -1,
.vmode = FB_VMODE_NONINTERLACED,
.nonstd = 0,
.accel_flags = FB_ACCELF_TEXT,
};
static struct fb_fix_screeninfo smtcfb_fix = {
.id = "smXXXfb",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
.line_length = 800 * 3,
.accel = FB_ACCEL_SMI_LYNX,
.type_aux = 0,
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
};
struct vesa_mode {
char index[6];
u16 lfb_width;
u16 lfb_height;
u16 lfb_depth;
};
static struct vesa_mode vesa_mode_table[] = {
{"0x301", 640, 480, 8},
{"0x303", 800, 600, 8},
{"0x305", 1024, 768, 8},
{"0x307", 1280, 1024, 8},
{"0x311", 640, 480, 16},
{"0x314", 800, 600, 16},
{"0x317", 1024, 768, 16},
{"0x31A", 1280, 1024, 16},
{"0x312", 640, 480, 24},
{"0x315", 800, 600, 24},
{"0x318", 1024, 768, 24},
{"0x31B", 1280, 1024, 24},
};
struct screen_info smtc_scr_info;
/* process command line options, get vga parameter */
static int __init sm7xx_vga_setup(char *options)
{
int i;
if (!options || !*options)
return -EINVAL;
smtc_scr_info.lfb_width = 0;
smtc_scr_info.lfb_height = 0;
smtc_scr_info.lfb_depth = 0;
pr_debug("sm7xx_vga_setup = %s\n", options);
for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
if (strstr(options, vesa_mode_table[i].index)) {
smtc_scr_info.lfb_width = vesa_mode_table[i].lfb_width;
smtc_scr_info.lfb_height = vesa_mode_table[i].lfb_height;
smtc_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth;
return 0;
}
}
return -1;
}
__setup("vga=", sm7xx_vga_setup);
static void sm712_setpalette(int regno, unsigned red, unsigned green