/*
* linux/drivers/video/mbx/mbxfb.c
*
* Copyright (C) 2006-2007 8D Technologies inc
* Raphael Assenat <raph@8d.com>
* - Added video overlay support
* - Various improvements
*
* Copyright (C) 2006 Compulab, Ltd.
* Mike Rapoport <mike@compulab.co.il>
* - Creation of driver
*
* Based on pxafb.c
*
* 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.
*
* Intel 2700G (Marathon) Graphics Accelerator Frame Buffer Driver
*
*/
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <video/mbxfb.h>
#include "regs.h"
#include "reg_bits.h"
static unsigned long virt_base_2700;
#define write_reg(val, reg) do { writel((val), (reg)); } while(0)
/* Without this delay, the graphics appears somehow scaled and
* there is a lot of jitter in scanlines. This delay is probably
* needed only after setting some specific register(s) somewhere,
* not all over the place... */
#define write_reg_dly(val, reg) do { writel((val), reg); udelay(1000); } while(0)
#define MIN_XRES 16
#define MIN_YRES 16
#define MAX_XRES 2048
#define MAX_YRES 2048
#define MAX_PALETTES 16
/* FIXME: take care of different chip revisions with different sizes
of ODFB */
#define MEMORY_OFFSET 0x60000
struct mbxfb_info {
struct device *dev;
struct resource *fb_res;
struct resource *fb_req;
struct resource *reg_res;
struct resource *reg_req;
void __iomem *fb_virt_addr;
unsigned long fb_phys_addr;
void __iomem *reg_virt_addr;
unsigned long reg_phys_addr;
int (*platform_probe) (struct fb_info * fb);
int (*platform_remove) (struct fb_info * fb);
u32 pseudo_palette[MAX_PALETTES];
#ifdef CONFIG_FB_MBX_DEBUG
void *debugfs_data;
#endif
};
static struct fb_var_screeninfo mbxfb_default __devinitdata = {
.xres = 640,
.yres = 480,
.xres_virtual = 640,
.yres_virtual = 480,
.bits_per_pixel = 16,
.red = {11, 5, 0},
.green = {5, 6, 0},
.blue = {0, 5, 0},
.activate = FB_ACTIVATE_TEST,
.height = -1,
.width = -1,
.pixclock = 40000,
.left_margin = 48,
.right_margin = 16,
.upper_margin = 33,
.lower_margin = 10,
.hsync_len = 96,
.vsync_len = 2,
.vmode = FB_VMODE_NONINTERLACED,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
};
static struct fb_fix_screeninfo mbxfb_fix __devinitdata = {
.id = "MBX",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
.accel = FB_ACCEL_NONE,
};
struct pixclock_div {
u8 m;
u8 n;
u8 p;
};
static unsigned int mbxfb_get_pixclock(unsigned int pixclock_ps,
struct pixclock_div *div)
{
u8 m, n, p;
unsigned int err = 0;
unsigned int min_err = ~0x0;
unsigned int clk;
unsigned int best_clk = 0;
unsigned int ref_clk = 13000; /* FIXME: take from platform data */
unsigned int pixclock;
/* convert pixclock to KHz */
pixclock = PICOS2KHZ(pixclock_ps);
/* PLL output freq = (ref_clk * M) / (N * 2^P)
*
* M: 1 to 63
* N: 1 to 7
* P: 0 to 7
*/
/* RAPH: When N==1, the resulting pixel clock appears to
* get divided by 2. Preventing N=1 by starting the following
* loop at 2 prevents this. Is this a bug with my chip
* revision or something I dont understand? */
for (m = 1; m < 64; m++) {
for (n = 2; n < 8; n++) {
for (p = 0; p < 8; p++) {
clk = (ref_clk * m) / (n * (1 << p));
err = (clk > pixclock) ? (clk - pixclock) :