11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  linux/drivers/video/cyber2000fb.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1998-2002 Russell King
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  MIPS and 50xx clock support
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  32 bit support, text color and panning fixes for modes != 8 bit
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2002 Denis Oliver Kropp <dok@directfb.org>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation.
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based on cyberfb.c.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that we now use the new fbcon fix, var and cmap scheme.  We do
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * still have to check which console is the currently displayed one
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * however, especially for the colourmap stuff.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We also use the new hotplug PCI subsystem.  I'm not sure if there
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are any such cards, but I'm erring on the side of caution.  We don't
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * want to go pop just because someone does have one.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that this doesn't work fully in the case of multiple CyberPro
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cards with grabbers.  We currently can only attach to the first
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CyberPro card found.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When we're in truecolour mode, we power down the LUT RAM as a power
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * saving feature.  Also, when we enter any of the powersaving modes
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (except soft blanking) we power down the RAMDACs.  This saves about
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1W, which is roughly 8% of the power consumption of a NetWinder
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (which, incidentally, is about the same saving as a 2.5in hard disk
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * entering standby mode.)
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fb.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
49997302259f386bca8fe1db67c50296ca426c438fRussell King#include <linux/io.h>
50e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#include <linux/i2c.h>
51e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#include <linux/i2c-algo-bit.h>
52e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __arm__
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mach-types.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "cyber2000fb.h"
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct cfb_info {
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fb_info		fb;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct display_switch	*dispsw;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct display		*display;
65532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	unsigned char		__iomem *region;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char		__iomem *regs;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int			id;
6824d6e5cb191189531396870402bf276aacf01598Russell King	u_int			irq;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			func_use_count;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long			ref_ps;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Clock divisors
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int			divisors[4];
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct {
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 red, green, blue;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} palette[NR_PALETTE];
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char			mem_ctl1;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char			mem_ctl2;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char			mclk_mult;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char			mclk_div;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * RAMDAC control register is both of these or'ed together
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char			ramdac_ctrl;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char			ramdac_powerdown;
90eca02b0c1dc1da374216128157747d8ed994e5efRussell King
91eca02b0c1dc1da374216128157747d8ed994e5efRussell King	u32			pseudo_palette[16];
92052a7f5c496b7d2966edea0f576ec39f41703992Russell King
93052a7f5c496b7d2966edea0f576ec39f41703992Russell King	spinlock_t		reg_b0_lock;
94052a7f5c496b7d2966edea0f576ec39f41703992Russell King
95e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#ifdef CONFIG_FB_CYBER2000_DDC
96e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	bool			ddc_registered;
97e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	struct i2c_adapter	ddc_adapter;
98e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	struct i2c_algo_bit_data	ddc_algo;
99e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#endif
100b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
101b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King#ifdef CONFIG_FB_CYBER2000_I2C
102b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	struct i2c_adapter	i2c_adapter;
103b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	struct i2c_algo_bit_data i2c_algo;
104b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King#endif
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *default_font = "Acorn8x8";
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(default_font, charp, 0);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(default_font, "Default font name");
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Our access methods.
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
114532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt#define cyber2000fb_writel(val, reg, cfb)	writel(val, (cfb)->regs + (reg))
115532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt#define cyber2000fb_writew(val, reg, cfb)	writew(val, (cfb)->regs + (reg))
116532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt#define cyber2000fb_writeb(val, reg, cfb)	writeb(val, (cfb)->regs + (reg))
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
118532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt#define cyber2000fb_readb(reg, cfb)		readb((cfb)->regs + (reg))
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000_crtcw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writew((reg & 255) | val << 8, 0x3d4, cfb);
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000_grphw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writew((reg & 255) | val << 8, 0x3ce, cfb);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned int
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000_grphr(unsigned int reg, struct cfb_info *cfb)
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(reg, 0x3ce, cfb);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return cyber2000fb_readb(0x3cf, cfb);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000_attrw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_readb(0x3da, cfb);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(reg, 0x3c0, cfb);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_readb(0x3c1, cfb);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(val, 0x3c0, cfb);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000_seqw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writew((reg & 255) | val << 8, 0x3c4, cfb);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- Hardware specific routines ------------------------- */
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Hardware Cyber2000 Acceleration
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cfb_info *cfb = (struct cfb_info *)info;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long dst, col;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb_fillrect(info, rect);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writew(rect->width - 1, CO_REG_PIXWIDTH, cfb);
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writew(rect->height - 1, CO_REG_PIXHEIGHT, cfb);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	col = rect->color;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cfb->fb.var.bits_per_pixel > 8)
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		col = ((u32 *)cfb->fb.pseudo_palette)[col];
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writel(col, CO_REG_FGCOLOUR, cfb);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dst = rect->dx + rect->dy * cfb->fb.var.xres_virtual;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cfb->fb.var.bits_per_pixel == 24) {
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dst *= 3;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb);
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writew(CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cfb_info *cfb = (struct cfb_info *)info;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int cmd = CO_CMD_L_PATTERN_FGCOL;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long src, dst;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb_copyarea(info, region);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writew(region->width - 1, CO_REG_PIXWIDTH, cfb);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writew(region->height - 1, CO_REG_PIXHEIGHT, cfb);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	src = region->sx + region->sy * cfb->fb.var.xres_virtual;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dst = region->dx + region->dy * cfb->fb.var.xres_virtual;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (region->sx < region->dx) {
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		src += region->width - 1;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dst += region->width - 1;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd |= CO_CMD_L_INC_LEFT;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (region->sy < region->dy) {
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		src += (region->height - 1) * cfb->fb.var.xres_virtual;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dst += (region->height - 1) * cfb->fb.var.xres_virtual;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd |= CO_CMD_L_INC_UP;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cfb->fb.var.bits_per_pixel == 24) {
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		src *= 3;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dst *= 3;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writel(src, CO_REG_SRC1_PTR, cfb);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writew(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writew(CO_CMD_H_FGSRCMAP | CO_CMD_H_BLITTER,
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   CO_REG_CMD_H, cfb);
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000fb_imageblit(struct fb_info *info, const struct fb_image *image)
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
238532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	cfb_imageblit(info, image);
239532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	return;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cyber2000fb_sync(struct fb_info *info)
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cfb_info *cfb = (struct cfb_info *)info;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count = 100000;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT))
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & CO_CTRL_BUSY) {
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!count--) {
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_printf("accel_wait timed out\n");
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(1);
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ===========================================================================
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u32 convert_bitfield(u_int val, struct fb_bitfield *bf)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int mask = (1 << bf->length) - 1;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (val >> (16 - bf->length) & mask) << bf->offset;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Set a single color register. Return != 0 for invalid regno.
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      u_int transp, struct fb_info *info)
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cfb_info *cfb = (struct cfb_info *)info;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fb_var_screeninfo *var = &cfb->fb.var;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pseudo_val;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 1;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cfb->fb.fix.visual) {
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Pseudocolour:
290532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	   8     8
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * pixel --/--+--/-->  red lut  --> red dac
292532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	      |  8
293532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	      +--/--> green lut --> green dac
294532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	      |  8
295532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	      +--/-->  blue lut --> blue dac
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_VISUAL_PSEUDOCOLOR:
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (regno >= NR_PALETTE)
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 1;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		red >>= 8;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		green >>= 8;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		blue >>= 8;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
305532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		cfb->palette[regno].red = red;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->palette[regno].green = green;
307532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		cfb->palette[regno].blue = blue;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_writeb(regno, 0x3c8, cfb);
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_writeb(red, 0x3c9, cfb);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_writeb(green, 0x3c9, cfb);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_writeb(blue, 0x3c9, cfb);
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Direct colour:
317532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	   n     rl
318532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 * pixel --/--+--/-->  red lut  --> red dac
319532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	      |  gl
320532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	      +--/--> green lut --> green dac
321532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	      |  bl
322532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	      +--/-->  blue lut --> blue dac
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * n = bpp, rl = red length, gl = green length, bl = blue length
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_VISUAL_DIRECTCOLOR:
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		red >>= 8;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		green >>= 8;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		blue >>= 8;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (var->green.length == 6 && regno < 64) {
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cfb->palette[regno << 2].green = green;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * The 6 bits of the green component are applied
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * to the high 6 bits of the LUT.
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
338532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt			cyber2000fb_writeb(cfb->palette[regno >> 1].red,
339532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt					   0x3c9, cfb);
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(green, 0x3c9, cfb);
341532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt			cyber2000fb_writeb(cfb->palette[regno >> 1].blue,
342532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt					   0x3c9, cfb);
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			green = cfb->palette[regno << 3].green;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = 0;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (var->green.length >= 5 && regno < 32) {
350532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt			cfb->palette[regno << 3].red = red;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cfb->palette[regno << 3].green = green;
352532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt			cfb->palette[regno << 3].blue = blue;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * The 5 bits of each colour component are
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * applied to the high 5 bits of the LUT.
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(red, 0x3c9, cfb);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(green, 0x3c9, cfb);
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(blue, 0x3c9, cfb);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = 0;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (var->green.length == 4 && regno < 16) {
366532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt			cfb->palette[regno << 4].red = red;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cfb->palette[regno << 4].green = green;
368532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt			cfb->palette[regno << 4].blue = blue;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * The 5 bits of each colour component are
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * applied to the high 5 bits of the LUT.
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(regno << 4, 0x3c8, cfb);
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(red, 0x3c9, cfb);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(green, 0x3c9, cfb);
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(blue, 0x3c9, cfb);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = 0;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Since this is only used for the first 16 colours, we
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * don't have to care about overflowing for regno >= 32
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pseudo_val = regno << var->red.offset |
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     regno << var->green.offset |
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     regno << var->blue.offset;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * True colour:
392532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	   n     rl
393532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 * pixel --/--+--/--> red dac
394532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	      |  gl
395532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	      +--/--> green dac
396532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	      |  bl
397532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	 *	      +--/--> blue dac
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * n = bpp, rl = red length, gl = green length, bl = blue length
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_VISUAL_TRUECOLOR:
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pseudo_val = convert_bitfield(transp ^ 0xffff, &var->transp);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pseudo_val |= convert_bitfield(red, &var->red);
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pseudo_val |= convert_bitfield(green, &var->green);
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pseudo_val |= convert_bitfield(blue, &var->blue);
405e76df4d33973bd9b963d0cce05749b090cc14936Ondrej Zary		ret = 0;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Now set our pseudo palette for the CFB16/24/32 drivers.
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (regno < 16)
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((u32 *)cfb->fb.pseudo_palette)[regno] = pseudo_val;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct par_info {
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Hardware
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char	clock_mult;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char	clock_div;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char	extseqmisc;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char	co_pixfmt;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char	crtc_ofl;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char	crtc[19];
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	width;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	pitch;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	fetch;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Other
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char	ramdac;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u_char crtc_idx[] = {
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x08, 0x09,
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb)
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int i;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int val = cfb->ramdac_ctrl | cfb->ramdac_powerdown;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(0x56, 0x3ce, cfb);
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = cyber2000fb_readb(0x3cf, cfb);
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(i | 4, 0x3cf, cfb);
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(val, 0x3c6, cfb);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(i, 0x3cf, cfb);
45400b4703f03ce04bd7f2f912fd05a243096ab826fOndrej Zary	/* prevent card lock-up observed on x86 with CyberPro 2000 */
45500b4703f03ce04bd7f2f912fd05a243096ab826fOndrej Zary	cyber2000fb_readb(0x3cf, cfb);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int i;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Blank palette
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < NR_PALETTE; i++) {
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_writeb(i, 0x3c8, cfb);
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_writeb(0, 0x3c9, cfb);
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_writeb(0, 0x3c9, cfb);
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_writeb(0, 0x3c9, cfb);
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(0xef, 0x3c2, cfb);
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_crtcw(0x11, 0x0b, cfb);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_attrw(0x11, 0x00, cfb);
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_seqw(0x00, 0x01, cfb);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_seqw(0x01, 0x01, cfb);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_seqw(0x02, 0x0f, cfb);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_seqw(0x03, 0x00, cfb);
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_seqw(0x04, 0x0e, cfb);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_seqw(0x00, 0x03, cfb);
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < sizeof(crtc_idx); i++)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000_crtcw(crtc_idx[i], hw->crtc[i], cfb);
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0x0a; i < 0x10; i++)
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000_crtcw(i, 0, cfb);
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(EXT_CRT_VRTOFL, hw->crtc_ofl, cfb);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0x00, 0x00, cfb);
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0x01, 0x00, cfb);
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0x02, 0x00, cfb);
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0x03, 0x00, cfb);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0x04, 0x00, cfb);
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0x05, 0x60, cfb);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0x06, 0x05, cfb);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0x07, 0x0f, cfb);
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0x08, 0xff, cfb);
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Attribute controller registers */
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 16; i++)
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000_attrw(i, i, cfb);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_attrw(0x10, 0x01, cfb);
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_attrw(0x11, 0x00, cfb);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_attrw(0x12, 0x0f, cfb);
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_attrw(0x13, 0x00, cfb);
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_attrw(0x14, 0x00, cfb);
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* PLL registers */
511e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	spin_lock(&cfb->reg_b0_lock);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb);
513532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb);
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb);
515532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	cyber2000_grphw(EXT_MCLK_DIV, cfb->mclk_div, cfb);
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0x90, 0x01, cfb);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0xb9, 0x80, cfb);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0xb9, 0x00, cfb);
519e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	spin_unlock(&cfb->reg_b0_lock);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->ramdac_ctrl = hw->ramdac;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_write_ramdac_ctrl(cfb);
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(0x20, 0x3c0, cfb);
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(0xff, 0x3c6, cfb);
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0x14, hw->fetch, cfb);
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) |
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      ((hw->pitch >> 4) & 0x30), cfb);
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(EXT_SEQ_MISC, hw->extseqmisc, cfb);
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Set up accelerator registers
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
535532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	cyber2000fb_writew(hw->width, CO_REG_SRC_WIDTH, cfb);
536532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	cyber2000fb_writew(hw->width, CO_REG_DEST_WIDTH, cfb);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(hw->co_pixfmt, CO_REG_PIXFMT, cfb);
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var)
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int base = var->yoffset * var->xres_virtual + var->xoffset;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	base *= var->bits_per_pixel;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Convert to bytes and shift two extra bits because DAC
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can only start on 4 byte aligned data.
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	base >>= 5;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (base >= 1 << 20)
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(0x10, base >> 16 | 0x10, cfb);
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_crtcw(0x0c, base >> 8, cfb);
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_crtcw(0x0d, base, cfb);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct fb_var_screeninfo *var)
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int Htotal, Hblankend, Hsyncend;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
569532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt#define ENCODE_BIT(v, b1, m, b2) ((((v) >> (b1)) & (m)) << (b2))
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[13] = hw->pitch;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[17] = 0xe3;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[14] = 0;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[8]  = 0;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
576532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	Htotal     = var->xres + var->right_margin +
577532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		     var->hsync_len + var->left_margin;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (Htotal > 2080)
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[0] = (Htotal >> 3) - 5;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[1] = (var->xres >> 3) - 1;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[2] = var->xres >> 3;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[4] = (var->xres + var->right_margin) >> 3;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
587532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	Hblankend   = (Htotal - 4 * 8) >> 3;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
58987d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby	hw->crtc[3] = ENCODE_BIT(Hblankend,  0, 0x1f,  0) |
59087d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby		      ENCODE_BIT(1,          0, 0x01,  7);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Hsyncend    = (var->xres + var->right_margin + var->hsync_len) >> 3;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
59487d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby	hw->crtc[5] = ENCODE_BIT(Hsyncend,   0, 0x1f,  0) |
59587d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby		      ENCODE_BIT(Hblankend,  5, 0x01,  7);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Vdispend    = var->yres - 1;
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Vsyncstart  = var->yres + var->lower_margin;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Vsyncend    = var->yres + var->lower_margin + var->vsync_len;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Vtotal      = var->yres + var->lower_margin + var->vsync_len +
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      var->upper_margin - 2;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (Vtotal > 2047)
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Vblankstart = var->yres + 6;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Vblankend   = Vtotal - 10;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[6]  = Vtotal;
61087d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby	hw->crtc[7]  = ENCODE_BIT(Vtotal,     8, 0x01,  0) |
61187d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby			ENCODE_BIT(Vdispend,   8, 0x01,  1) |
61287d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby			ENCODE_BIT(Vsyncstart, 8, 0x01,  2) |
613532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt			ENCODE_BIT(Vblankstart, 8, 0x01,  3) |
61487d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby			ENCODE_BIT(1,          0, 0x01,  4) |
615532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt			ENCODE_BIT(Vtotal,     9, 0x01,  5) |
61687d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby			ENCODE_BIT(Vdispend,   9, 0x01,  6) |
61787d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby			ENCODE_BIT(Vsyncstart, 9, 0x01,  7);
61887d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby	hw->crtc[9]  = ENCODE_BIT(0,          0, 0x1f,  0) |
619532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt			ENCODE_BIT(Vblankstart, 9, 0x01,  5) |
62087d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby			ENCODE_BIT(1,          0, 0x01,  6);
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[10] = Vsyncstart;
62287d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby	hw->crtc[11] = ENCODE_BIT(Vsyncend,   0, 0x0f,  0) |
62387d0613103aa279f8a39a497af09edbb068ef285Jiri Slaby		       ENCODE_BIT(1,          0, 0x01,  7);
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[12] = Vdispend;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[15] = Vblankstart;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[16] = Vblankend;
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc[18] = 0xff;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * overflow - graphics reg 0x11
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->crtc_ofl =
635532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		ENCODE_BIT(Vtotal, 10, 0x01, 0) |
636532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		ENCODE_BIT(Vdispend, 10, 0x01, 1) |
637532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		ENCODE_BIT(Vsyncstart, 10, 0x01, 2) |
638532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		ENCODE_BIT(Vblankstart, 10, 0x01, 3) |
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		EXT_CRT_VRTOFL_LINECOMP10;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* woody: set the interlaced bit... */
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME: what about doublescan? */
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw->crtc_ofl |= EXT_CRT_VRTOFL_INTERLACE;
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The following was discovered by a good monitor, bit twiddling, theorising
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and but mostly luck.  Strangely, it looks like everyone elses' PLL!
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clock registers:
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   fclock = fpll / div2
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   fpll   = fref * mult / div1
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * where:
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   fref = 14.318MHz (69842ps)
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   mult = reg0xb0.7:0
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   div1 = (reg0xb1.5:0 + 1)
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   div2 =  2^(reg0xb1.7:6)
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   fpll should be between 115 and 260 MHz
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  (8696ps and 3846ps)
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb,
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 struct fb_var_screeninfo *var)
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long pll_ps = var->pixclock;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const u_long ref_ps = cfb->ref_ps;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int div2, t_div1, best_div1, best_mult;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int best_diff;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int vco;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Step 1:
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *   find div2 such that 115MHz < fpll < 260MHz
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *   and 0 <= div2 < 4
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (div2 = 0; div2 < 4; div2++) {
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u_long new_pll;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_pll = pll_ps / cfb->divisors[div2];
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (8696 > new_pll && new_pll > 3846) {
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pll_ps = new_pll;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (div2 == 4)
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Step 2:
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  Given pll_ps and ref_ps, find:
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *    pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  where { 1 < best_div1 < 32, 1 < best_mult < 256 }
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *    pll_ps_calc = best_div1 / (ref_ps * best_mult)
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	best_diff = 0x7fffffff;
700fcd3c7796c62f6bf5300ee52a87b8654084c5ae4Russell King	best_mult = 2;
701fcd3c7796c62f6bf5300ee52a87b8654084c5ae4Russell King	best_div1 = 32;
702fcd3c7796c62f6bf5300ee52a87b8654084c5ae4Russell King	for (t_div1 = 2; t_div1 < 32; t_div1 += 1) {
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u_int rr, t_mult, t_pll_ps;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int diff;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Find the multiplier for this divisor
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rr = ref_ps * t_div1;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_mult = (rr + pll_ps / 2) / pll_ps;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Is the multiplier within the correct range?
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (t_mult > 256 || t_mult < 2)
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Calculate the actual clock period from this multiplier
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * and divisor, and estimate the error.
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_pll_ps = (rr + t_mult / 2) / t_mult;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		diff = pll_ps - t_pll_ps;
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (diff < 0)
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			diff = -diff;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (diff < best_diff) {
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			best_diff = diff;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			best_mult = t_mult;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			best_div1 = t_div1;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * If we hit an exact value, there is no point in continuing.
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (diff == 0)
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Step 3:
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  combine values
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->clock_mult = best_mult - 1;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw->clock_div  = div2 << 6 | (best_div1 - 1);
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vco = ref_ps * best_div1 / best_mult;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ref_ps == 40690) && (vco < 5556))
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Set VFSEL when VCO > 180MHz (5.556 ps). */
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw->clock_div |= EXT_DCLK_DIV_VFSEL;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Set the User Defined Part of the Display
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cfb_info *cfb = (struct cfb_info *)info;
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct par_info hw;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mem;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->transp.msb_right	= 0;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->red.msb_right	= 0;
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->green.msb_right	= 0;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->blue.msb_right	= 0;
770532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	var->transp.offset	= 0;
771532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	var->transp.length	= 0;
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (var->bits_per_pixel) {
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 8:	/* PSEUDOCOLOUR, 256 */
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.offset		= 0;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.length		= 8;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->green.offset	= 0;
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->green.length	= 8;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->blue.offset	= 0;
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->blue.length	= 8;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 16:/* DIRECTCOLOUR, 64k or 32k */
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (var->green.length) {
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 6: /* RGB565, 64k */
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->red.offset		= 11;
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->red.length		= 5;
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->green.offset	= 5;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->green.length	= 6;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->blue.offset	= 0;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->blue.length	= 5;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 5: /* RGB555, 32k */
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->red.offset		= 10;
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->red.length		= 5;
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->green.offset	= 5;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->green.length	= 5;
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->blue.offset	= 0;
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->blue.length	= 5;
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 4: /* RGB444, 4k + transparency? */
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->transp.offset	= 12;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->transp.length	= 4;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->red.offset		= 8;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->red.length		= 4;
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->green.offset	= 4;
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->green.length	= 4;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->blue.offset	= 0;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			var->blue.length	= 4;
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 24:/* TRUECOLOUR, 16m */
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.offset		= 16;
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.length		= 8;
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->green.offset	= 8;
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->green.length	= 8;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->blue.offset	= 0;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->blue.length	= 8;
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 32:/* TRUECOLOUR, 16m */
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->transp.offset	= 24;
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->transp.length	= 8;
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.offset		= 16;
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.length		= 8;
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->green.offset	= 8;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->green.length	= 8;
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->blue.offset	= 0;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->blue.length	= 8;
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mem = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8);
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mem > cfb->fb.fix.smem_len)
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->yres_virtual = cfb->fb.fix.smem_len * 8 /
844532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt				    (var->bits_per_pixel * var->xres_virtual);
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->yres > var->yres_virtual)
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->yres = var->yres_virtual;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->xres > var->xres_virtual)
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->xres = var->xres_virtual;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = cyber2000fb_decode_clock(&hw, cfb, var);
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = cyber2000fb_decode_crtc(&hw, cfb, var);
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cyber2000fb_set_par(struct fb_info *info)
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cfb_info *cfb = (struct cfb_info *)info;
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fb_var_screeninfo *var = &cfb->fb.var;
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct par_info hw;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mem;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw.width = var->xres_virtual;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw.ramdac = RAMDAC_VREFEN | RAMDAC_DAC8BIT;
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (var->bits_per_pixel) {
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 8:
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.co_pixfmt		= CO_PIXFMT_8BPP;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.pitch		= hw.width >> 3;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.extseqmisc		= EXT_SEQ_MISC_8;
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 16:
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.co_pixfmt		= CO_PIXFMT_16BPP;
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.pitch		= hw.width >> 2;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (var->green.length) {
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 6: /* RGB565, 64k */
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hw.extseqmisc	= EXT_SEQ_MISC_16_RGB565;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 5: /* RGB555, 32k */
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hw.extseqmisc	= EXT_SEQ_MISC_16_RGB555;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 4: /* RGB444, 4k + transparency? */
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hw.extseqmisc	= EXT_SEQ_MISC_16_RGB444;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			BUG();
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
896c2ec21c5c8f15c079c209f403d582f3134785060Jan Rinze		break;
897c2ec21c5c8f15c079c209f403d582f3134785060Jan Rinze
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 24:/* TRUECOLOUR, 16m */
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.co_pixfmt		= CO_PIXFMT_24BPP;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.width		*= 3;
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.pitch		= hw.width >> 3;
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.ramdac		|= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.extseqmisc		= EXT_SEQ_MISC_24_RGB888;
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 32:/* TRUECOLOUR, 16m */
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.co_pixfmt		= CO_PIXFMT_32BPP;
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.pitch		= hw.width >> 1;
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.ramdac		|= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.extseqmisc		= EXT_SEQ_MISC_32;
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Sigh, this is absolutely disgusting, but caused by
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the way the fbcon developers want to separate out
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the "checking" and the "setting" of the video mode.
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If the mode is not suitable for the hardware here,
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * we can't prevent it being set by returning an error.
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * In theory, since NetWinders contain just one VGA card,
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * we should never end up hitting this problem.
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(cyber2000fb_decode_clock(&hw, cfb, var) != 0);
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(cyber2000fb_decode_crtc(&hw, cfb, var) != 0);
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw.width -= 1;
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw.fetch = hw.pitch;
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(cfb->mem_ctl2 & MEM_CTL2_64BIT))
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hw.fetch <<= 1;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hw.fetch += 1;
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
937532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	cfb->fb.fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Same here - if the size of the video mode exceeds the
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * available RAM, we can't prevent this mode being set.
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * In theory, since NetWinders contain just one VGA card,
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * we should never end up hitting this problem.
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mem = cfb->fb.fix.line_length * var->yres_virtual;
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(mem > cfb->fb.fix.smem_len);
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * 8bpp displays are always pseudo colour.  16bpp and above
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * are direct colour or true colour, depending on whether
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the RAMDAC palettes are bypassed.  (Direct colour has
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * palettes, true colour does not.)
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->bits_per_pixel == 8)
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (hw.ramdac & RAMDAC_BYPASS)
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_set_timing(cfb, &hw);
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_update_start(cfb, var);
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Pan or Wrap the Display
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyber2000fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cfb_info *cfb = (struct cfb_info *)info;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cyber2000fb_update_start(cfb, var))
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.var.xoffset = var->xoffset;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.var.yoffset = var->yoffset;
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->vmode & FB_VMODE_YWRAP) {
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->fb.var.vmode |= FB_VMODE_YWRAP;
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->fb.var.vmode &= ~FB_VMODE_YWRAP;
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    (Un)Blank the display.
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Blank the screen if blank_mode != 0, else unblank. If
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  blank == NULL then the caller blanks by setting the CLUT
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  (Color Look Up Table) to all black. Return 0 if blanking
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  succeeded, != 0 if un-/blanking failed due to e.g. a
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  video mode which doesn't support it. Implements VESA
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  suspend and powerdown modes on hardware that supports
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  disabling hsync/vsync:
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    blank_mode == 2: suspend vsync
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    blank_mode == 3: suspend hsync
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    blank_mode == 4: powerdown
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  wms...Enable VESA DMPS compatible powerdown mode
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  run "setterm -powersave powerdown" to take advantage
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cyber2000fb_blank(int blank, struct fb_info *info)
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cfb_info *cfb = (struct cfb_info *)info;
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int sync = 0;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (blank) {
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_BLANK_POWERDOWN:	/* powerdown - both sync lines down */
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_0;
1017532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		break;
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_BLANK_HSYNC_SUSPEND:	/* hsync off */
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sync = EXT_SYNC_CTL_VS_NORMAL | EXT_SYNC_CTL_HS_0;
1020532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		break;
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_BLANK_VSYNC_SUSPEND:	/* vsync off */
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_NORMAL;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1024532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	case FB_BLANK_NORMAL:		/* soft blank */
1025532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	default:			/* unblank */
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(EXT_SYNC_CTL, sync, cfb);
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (blank <= 1) {
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* turn on ramdacs */
1033532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS |
1034532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt					   RAMDAC_RAMPWRDN);
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_write_ramdac_ctrl(cfb);
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Soft blank/unblank the display.
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (blank) {	/* soft blank */
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < NR_PALETTE; i++) {
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(i, 0x3c8, cfb);
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(0, 0x3c9, cfb);
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(0, 0x3c9, cfb);
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(0, 0x3c9, cfb);
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {	/* unblank */
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < NR_PALETTE; i++) {
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(i, 0x3c8, cfb);
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb);
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb);
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb);
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (blank >= 2) {
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* turn off ramdacs */
1059532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS |
1060532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt					 RAMDAC_RAMPWRDN;
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_write_ramdac_ctrl(cfb);
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct fb_ops cyber2000fb_ops = {
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_check_var	= cyber2000fb_check_var,
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_set_par	= cyber2000fb_set_par,
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_setcolreg	= cyber2000fb_setcolreg,
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_blank	= cyber2000fb_blank,
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_pan_display	= cyber2000fb_pan_display,
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_fillrect	= cyber2000fb_fillrect,
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_copyarea	= cyber2000fb_copyarea,
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_imageblit	= cyber2000fb_imageblit,
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_sync	= cyber2000fb_sync,
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is the only "static" reference to the internal data structures
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of this driver.  It is here solely at the moment to support the other
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CyberPro modules external to this driver.
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1085532237eff1f271302ed923af6d811a699d582bbcKrzysztof Heltstatic struct cfb_info *int_cfb_info;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enable access to the extended registers
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid cyber2000fb_enable_extregs(struct cfb_info *cfb)
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->func_use_count += 1;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cfb->func_use_count == 1) {
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int old;
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		old = cyber2000_grphr(EXT_FUNC_CTL, cfb);
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		old |= EXT_FUNC_CTL_EXTREGENBL;
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000_grphw(EXT_FUNC_CTL, old, cfb);
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1102532237eff1f271302ed923af6d811a699d582bbcKrzysztof HeltEXPORT_SYMBOL(cyber2000fb_enable_extregs);
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable access to the extended registers
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid cyber2000fb_disable_extregs(struct cfb_info *cfb)
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cfb->func_use_count == 1) {
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int old;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		old = cyber2000_grphr(EXT_FUNC_CTL, cfb);
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		old &= ~EXT_FUNC_CTL_EXTREGENBL;
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000_grphw(EXT_FUNC_CTL, old, cfb);
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cfb->func_use_count == 0)
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "disable_extregs: count = 0\n");
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->func_use_count -= 1;
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1122532237eff1f271302ed923af6d811a699d582bbcKrzysztof HeltEXPORT_SYMBOL(cyber2000fb_disable_extregs);
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Attach a capture/tv driver to the core CyberX0X0 driver.
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cyber2000fb_attach(struct cyberpro_info *info, int idx)
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (int_cfb_info != NULL) {
113024d6e5cb191189531396870402bf276aacf01598Russell King		info->dev	      = int_cfb_info->fb.device;
1131b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King#ifdef CONFIG_FB_CYBER2000_I2C
1132b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King		info->i2c	      = &int_cfb_info->i2c_adapter;
1133b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King#else
1134b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King		info->i2c	      = NULL;
1135b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King#endif
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->regs	      = int_cfb_info->regs;
113724d6e5cb191189531396870402bf276aacf01598Russell King		info->irq             = int_cfb_info->irq;
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->fb	      = int_cfb_info->fb.screen_base;
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->fb_size	      = int_cfb_info->fb.fix.smem_len;
1140532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		info->info	      = int_cfb_info;
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1142532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		strlcpy(info->dev_name, int_cfb_info->fb.fix.id,
1143532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt			sizeof(info->dev_name));
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return int_cfb_info != NULL;
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1148532237eff1f271302ed923af6d811a699d582bbcKrzysztof HeltEXPORT_SYMBOL(cyber2000fb_attach);
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Detach a capture/tv driver from the core CyberX0X0 driver.
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid cyber2000fb_detach(int idx)
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(cyber2000fb_detach);
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1158e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#ifdef CONFIG_FB_CYBER2000_DDC
1159e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1160e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#define DDC_REG		0xb0
1161e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#define DDC_SCL_OUT	(1 << 0)
1162e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#define DDC_SDA_OUT	(1 << 4)
1163e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#define DDC_SCL_IN	(1 << 2)
1164e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#define DDC_SDA_IN	(1 << 6)
1165e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1166e5dedf8d561fb309ba37003546025300678da549Ondrej Zarystatic void cyber2000fb_enable_ddc(struct cfb_info *cfb)
1167e5dedf8d561fb309ba37003546025300678da549Ondrej Zary{
1168e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	spin_lock(&cfb->reg_b0_lock);
1169e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cyber2000fb_writew(0x1bf, 0x3ce, cfb);
1170e5dedf8d561fb309ba37003546025300678da549Ondrej Zary}
1171e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1172e5dedf8d561fb309ba37003546025300678da549Ondrej Zarystatic void cyber2000fb_disable_ddc(struct cfb_info *cfb)
1173e5dedf8d561fb309ba37003546025300678da549Ondrej Zary{
1174e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cyber2000fb_writew(0x0bf, 0x3ce, cfb);
1175e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	spin_unlock(&cfb->reg_b0_lock);
1176e5dedf8d561fb309ba37003546025300678da549Ondrej Zary}
1177e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1178e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1179e5dedf8d561fb309ba37003546025300678da549Ondrej Zarystatic void cyber2000fb_ddc_setscl(void *data, int val)
1180e5dedf8d561fb309ba37003546025300678da549Ondrej Zary{
1181e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	struct cfb_info *cfb = data;
1182e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	unsigned char reg;
1183e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1184e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cyber2000fb_enable_ddc(cfb);
1185e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	reg = cyber2000_grphr(DDC_REG, cfb);
1186e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	if (!val)	/* bit is inverted */
1187e5dedf8d561fb309ba37003546025300678da549Ondrej Zary		reg |= DDC_SCL_OUT;
1188e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	else
1189e5dedf8d561fb309ba37003546025300678da549Ondrej Zary		reg &= ~DDC_SCL_OUT;
1190e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cyber2000_grphw(DDC_REG, reg, cfb);
1191e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cyber2000fb_disable_ddc(cfb);
1192e5dedf8d561fb309ba37003546025300678da549Ondrej Zary}
1193e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1194e5dedf8d561fb309ba37003546025300678da549Ondrej Zarystatic void cyber2000fb_ddc_setsda(void *data, int val)
1195e5dedf8d561fb309ba37003546025300678da549Ondrej Zary{
1196e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	struct cfb_info *cfb = data;
1197e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	unsigned char reg;
1198e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1199e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cyber2000fb_enable_ddc(cfb);
1200e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	reg = cyber2000_grphr(DDC_REG, cfb);
1201e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	if (!val)	/* bit is inverted */
1202e5dedf8d561fb309ba37003546025300678da549Ondrej Zary		reg |= DDC_SDA_OUT;
1203e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	else
1204e5dedf8d561fb309ba37003546025300678da549Ondrej Zary		reg &= ~DDC_SDA_OUT;
1205e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cyber2000_grphw(DDC_REG, reg, cfb);
1206e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cyber2000fb_disable_ddc(cfb);
1207e5dedf8d561fb309ba37003546025300678da549Ondrej Zary}
1208e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1209e5dedf8d561fb309ba37003546025300678da549Ondrej Zarystatic int cyber2000fb_ddc_getscl(void *data)
1210e5dedf8d561fb309ba37003546025300678da549Ondrej Zary{
1211e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	struct cfb_info *cfb = data;
1212e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	int retval;
1213e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1214e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cyber2000fb_enable_ddc(cfb);
1215e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SCL_IN);
1216e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cyber2000fb_disable_ddc(cfb);
1217e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1218e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	return retval;
1219e5dedf8d561fb309ba37003546025300678da549Ondrej Zary}
1220e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1221e5dedf8d561fb309ba37003546025300678da549Ondrej Zarystatic int cyber2000fb_ddc_getsda(void *data)
1222e5dedf8d561fb309ba37003546025300678da549Ondrej Zary{
1223e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	struct cfb_info *cfb = data;
1224e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	int retval;
1225e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1226e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cyber2000fb_enable_ddc(cfb);
1227e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SDA_IN);
1228e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cyber2000fb_disable_ddc(cfb);
1229e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1230e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	return retval;
1231e5dedf8d561fb309ba37003546025300678da549Ondrej Zary}
1232e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1233e5dedf8d561fb309ba37003546025300678da549Ondrej Zarystatic int __devinit cyber2000fb_setup_ddc_bus(struct cfb_info *cfb)
1234e5dedf8d561fb309ba37003546025300678da549Ondrej Zary{
1235e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	strlcpy(cfb->ddc_adapter.name, cfb->fb.fix.id,
1236e5dedf8d561fb309ba37003546025300678da549Ondrej Zary		sizeof(cfb->ddc_adapter.name));
1237e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cfb->ddc_adapter.owner		= THIS_MODULE;
1238e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cfb->ddc_adapter.class		= I2C_CLASS_DDC;
1239e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cfb->ddc_adapter.algo_data	= &cfb->ddc_algo;
124024d6e5cb191189531396870402bf276aacf01598Russell King	cfb->ddc_adapter.dev.parent	= cfb->fb.device;
1241e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cfb->ddc_algo.setsda		= cyber2000fb_ddc_setsda;
1242e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cfb->ddc_algo.setscl		= cyber2000fb_ddc_setscl;
1243e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cfb->ddc_algo.getsda		= cyber2000fb_ddc_getsda;
1244e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cfb->ddc_algo.getscl		= cyber2000fb_ddc_getscl;
1245e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cfb->ddc_algo.udelay		= 10;
1246e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cfb->ddc_algo.timeout		= 20;
1247e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	cfb->ddc_algo.data		= cfb;
1248e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1249e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	i2c_set_adapdata(&cfb->ddc_adapter, cfb);
1250e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1251e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	return i2c_bit_add_bus(&cfb->ddc_adapter);
1252e5dedf8d561fb309ba37003546025300678da549Ondrej Zary}
1253e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#endif /* CONFIG_FB_CYBER2000_DDC */
1254e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
1255b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King#ifdef CONFIG_FB_CYBER2000_I2C
1256b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell Kingstatic void cyber2000fb_i2c_setsda(void *data, int state)
1257b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King{
1258b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	struct cfb_info *cfb = data;
1259b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	unsigned int latch2;
1260b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
1261b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	spin_lock(&cfb->reg_b0_lock);
1262b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	latch2 = cyber2000_grphr(EXT_LATCH2, cfb);
1263b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	latch2 &= EXT_LATCH2_I2C_CLKEN;
1264b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	if (state)
1265b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King		latch2 |= EXT_LATCH2_I2C_DATEN;
1266b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	cyber2000_grphw(EXT_LATCH2, latch2, cfb);
1267b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	spin_unlock(&cfb->reg_b0_lock);
1268b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King}
1269b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
1270b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell Kingstatic void cyber2000fb_i2c_setscl(void *data, int state)
1271b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King{
1272b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	struct cfb_info *cfb = data;
1273b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	unsigned int latch2;
1274b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
1275b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	spin_lock(&cfb->reg_b0_lock);
1276b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	latch2 = cyber2000_grphr(EXT_LATCH2, cfb);
1277b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	latch2 &= EXT_LATCH2_I2C_DATEN;
1278b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	if (state)
1279b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King		latch2 |= EXT_LATCH2_I2C_CLKEN;
1280b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	cyber2000_grphw(EXT_LATCH2, latch2, cfb);
1281b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	spin_unlock(&cfb->reg_b0_lock);
1282b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King}
1283b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
1284b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell Kingstatic int cyber2000fb_i2c_getsda(void *data)
1285b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King{
1286b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	struct cfb_info *cfb = data;
1287b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	int ret;
1288b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
1289b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	spin_lock(&cfb->reg_b0_lock);
1290b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_DAT);
1291b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	spin_unlock(&cfb->reg_b0_lock);
1292b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
1293b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	return ret;
1294b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King}
1295b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
1296b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell Kingstatic int cyber2000fb_i2c_getscl(void *data)
1297b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King{
1298b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	struct cfb_info *cfb = data;
1299b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	int ret;
1300b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
1301b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	spin_lock(&cfb->reg_b0_lock);
1302b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_CLK);
1303b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	spin_unlock(&cfb->reg_b0_lock);
1304b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
1305b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	return ret;
1306b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King}
1307b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
1308b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell Kingstatic int __devinit cyber2000fb_i2c_register(struct cfb_info *cfb)
1309b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King{
1310b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	strlcpy(cfb->i2c_adapter.name, cfb->fb.fix.id,
1311b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King		sizeof(cfb->i2c_adapter.name));
1312b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	cfb->i2c_adapter.owner = THIS_MODULE;
1313b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	cfb->i2c_adapter.algo_data = &cfb->i2c_algo;
131424d6e5cb191189531396870402bf276aacf01598Russell King	cfb->i2c_adapter.dev.parent = cfb->fb.device;
1315b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	cfb->i2c_algo.setsda = cyber2000fb_i2c_setsda;
1316b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	cfb->i2c_algo.setscl = cyber2000fb_i2c_setscl;
1317b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	cfb->i2c_algo.getsda = cyber2000fb_i2c_getsda;
1318b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	cfb->i2c_algo.getscl = cyber2000fb_i2c_getscl;
1319b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	cfb->i2c_algo.udelay = 5;
1320b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	cfb->i2c_algo.timeout = msecs_to_jiffies(100);
1321b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	cfb->i2c_algo.data = cfb;
1322b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
1323b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	return i2c_bit_add_bus(&cfb->i2c_adapter);
1324b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King}
1325b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
1326b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell Kingstatic void cyber2000fb_i2c_unregister(struct cfb_info *cfb)
1327b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King{
1328b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	i2c_del_adapter(&cfb->i2c_adapter);
1329b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King}
1330b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King#else
1331b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King#define cyber2000fb_i2c_register(cfb)	(0)
1332b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King#define cyber2000fb_i2c_unregister(cfb)	do { } while (0)
1333b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King#endif
1334b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These parameters give
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 640x480, hsync 31.5kHz, vsync 60Hz
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct fb_videomode __devinitdata cyber2000fb_default_mode = {
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.refresh	= 60,
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 640,
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.yres		= 480,
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 39722,
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 56,
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 16,
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.upper_margin	= 34,
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lower_margin	= 9,
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 88,
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vsync_len	= 2,
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vmode		= FB_VMODE_NONINTERLACED
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char igs_regs[] = {
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_CRT_IRQ,		0,
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_CRT_TEST,		0,
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_SYNC_CTL,		0,
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_SEG_WRITE_PTR,	0,
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_SEG_READ_PTR,	0,
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_BIU_MISC,		EXT_BIU_MISC_LIN_ENABLE |
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				EXT_BIU_MISC_COP_ENABLE |
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				EXT_BIU_MISC_COP_BFC,
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_FUNC_CTL,		0,
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CURS_H_START,		0,
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CURS_H_START + 1,	0,
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CURS_H_PRESET,		0,
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CURS_V_START,		0,
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CURS_V_START + 1,	0,
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CURS_V_PRESET,		0,
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CURS_CTL,		0,
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_ATTRIB_CTL,		EXT_ATTRIB_CTL_EXT,
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_OVERSCAN_RED,	0,
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_OVERSCAN_GREEN,	0,
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_OVERSCAN_BLUE,	0,
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* some of these are questionable when we have a BIOS */
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_MEM_CTL0,		EXT_MEM_CTL0_7CLK |
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				EXT_MEM_CTL0_RAS_1 |
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				EXT_MEM_CTL0_MULTCAS,
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_HIDDEN_CTL1,	0x30,
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_FIFO_CTL,		0x0b,
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_FIFO_CTL + 1,	0x17,
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x76,			0x00,
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXT_HIDDEN_CTL4,	0xc8
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialise the CyberPro hardware.  On the CyberPro5XXXX,
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ensure that we're using the correct PLL (5XXX's may be
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * programmed to use an additional set of PLLs.)
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cyberpro_init_hw(struct cfb_info *cfb)
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < sizeof(igs_regs); i += 2)
1397532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		cyber2000_grphw(igs_regs[i], igs_regs[i + 1], cfb);
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cfb->id == ID_CYBERPRO_5000) {
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned char val;
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_writeb(0xba, 0x3ce, cfb);
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = cyber2000fb_readb(0x3cf, cfb) & 0x80;
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyber2000fb_writeb(val, 0x3cf, cfb);
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1407532237eff1f271302ed923af6d811a699d582bbcKrzysztof Heltstatic struct cfb_info __devinit *cyberpro_alloc_fb_info(unsigned int id,
1408532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt							 char *name)
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cfb_info *cfb;
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1412dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau	cfb = kzalloc(sizeof(struct cfb_info), GFP_KERNEL);
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cfb)
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->id			= id;
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (id == ID_CYBERPRO_5000)
1420532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		cfb->ref_ps	= 40690; /* 24.576 MHz */
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
1422532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		cfb->ref_ps	= 69842; /* 14.31818 MHz (69841?) */
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->divisors[0]	= 1;
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->divisors[1]	= 2;
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->divisors[2]	= 4;
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (id == ID_CYBERPRO_2000)
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->divisors[3] = 8;
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->divisors[3] = 6;
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(cfb->fb.fix.id, name);
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.fix.type	= FB_TYPE_PACKED_PIXELS;
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.fix.type_aux	= 0;
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.fix.xpanstep	= 0;
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.fix.ypanstep	= 1;
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.fix.ywrapstep	= 0;
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (id) {
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ID_IGA_1682:
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->fb.fix.accel = 0;
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ID_CYBERPRO_2000:
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2000;
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ID_CYBERPRO_2010:
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2010;
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ID_CYBERPRO_5000:
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER5000;
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.var.nonstd	= 0;
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.var.activate	= FB_ACTIVATE_NOW;
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.var.height	= -1;
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.var.width	= -1;
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.var.accel_flags	= FB_ACCELF_TEXT;
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.fbops		= &cyber2000fb_ops;
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.flags		= FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1467eca02b0c1dc1da374216128157747d8ed994e5efRussell King	cfb->fb.pseudo_palette	= cfb->pseudo_palette;
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1469052a7f5c496b7d2966edea0f576ec39f41703992Russell King	spin_lock_init(&cfb->reg_b0_lock);
1470052a7f5c496b7d2966edea0f576ec39f41703992Russell King
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0);
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return cfb;
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1476532237eff1f271302ed923af6d811a699d582bbcKrzysztof Heltstatic void cyberpro_free_fb_info(struct cfb_info *cfb)
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cfb) {
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Free the colourmap
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fb_alloc_cmap(&cfb->fb.cmap, 0, 0);
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(cfb);
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parse Cyber2000fb options.  Usage:
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  video=cyber2000:font:fontname
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE
1493532237eff1f271302ed923af6d811a699d582bbcKrzysztof Heltstatic int cyber2000fb_setup(char *options)
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *opt;
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!options || !*options)
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((opt = strsep(&options, ",")) != NULL) {
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!*opt)
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strncmp(opt, "font:", 5) == 0) {
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			static char default_font_storage[40];
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1507532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt			strlcpy(default_font_storage, opt + 5,
1508532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt				sizeof(default_font_storage));
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default_font = default_font_storage;
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "CyberPro20x0: unknown parameter: %s\n", opt);
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif  /*  MODULE  */
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The CyberPro chips can be placed on many different bus types.
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This probe function is common to all bus types.  The bus-specific
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * probe function is expected to have:
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  - enabled access to the linear memory region
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  - memory mapped access to the registers
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  - initialised mem_ctl1 and mem_ctl2 appropriately.
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit cyberpro_common_probe(struct cfb_info *cfb)
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long smem_size;
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int h_sync, v_sync;
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyberpro_init_hw(cfb);
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Get the video RAM size and width from the VGA register.
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This should have been already initialised by the BIOS,
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * but if it's garbage, claim default 1MB VRAM (woody)
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->mem_ctl1 = cyber2000_grphr(EXT_MEM_CTL1, cfb);
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->mem_ctl2 = cyber2000_grphr(EXT_MEM_CTL2, cfb);
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Determine the size of the memory.
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) {
1547532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	case MEM_CTL2_SIZE_4MB:
1548532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		smem_size = 0x00400000;
1549532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		break;
1550532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	case MEM_CTL2_SIZE_2MB:
1551532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		smem_size = 0x00200000;
1552532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		break;
1553532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	case MEM_CTL2_SIZE_1MB:
1554532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		smem_size = 0x00100000;
1555532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		break;
1556532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	default:
1557532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		smem_size = 0x00100000;
1558532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		break;
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.fix.smem_len   = smem_size;
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.fix.mmio_len   = MMIO_SIZE;
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.screen_base    = cfb->region;
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1565e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#ifdef CONFIG_FB_CYBER2000_DDC
1566e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	if (cyber2000fb_setup_ddc_bus(cfb) == 0)
1567e5dedf8d561fb309ba37003546025300678da549Ondrej Zary		cfb->ddc_registered = true;
1568e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#endif
1569e5dedf8d561fb309ba37003546025300678da549Ondrej Zary
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = -EINVAL;
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0,
1572532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt			  &cyber2000fb_default_mode, 8)) {
1573532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		printk(KERN_ERR "%s: no valid mode found\n", cfb->fb.fix.id);
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed;
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.var.yres_virtual = cfb->fb.fix.smem_len * 8 /
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(cfb->fb.var.bits_per_pixel * cfb->fb.var.xres_virtual);
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cfb->fb.var.yres_virtual < cfb->fb.var.yres)
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->fb.var.yres_virtual = cfb->fb.var.yres;
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1583532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt/*	fb_set_var(&cfb->fb.var, -1, &cfb->fb); */
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Calculate the hsync and vsync frequencies.  Note that
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * we split the 1e12 constant up so that we can preserve
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the precision and fit the results into 32-bit registers.
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  (1953125000 * 512 = 1e12)
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	h_sync = 1953125000 / cfb->fb.var.pixclock;
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin +
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 cfb->fb.var.right_margin + cfb->fb.var.hsync_len);
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin +
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 cfb->fb.var.lower_margin + cfb->fb.var.vsync_len);
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "%s: %dKiB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10,
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->fb.var.xres, cfb->fb.var.yres,
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		h_sync / 1000, h_sync % 1000, v_sync);
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1602b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	err = cyber2000fb_i2c_register(cfb);
1603b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	if (err)
1604b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King		goto failed;
1605b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = register_framebuffer(&cfb->fb);
1607b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	if (err)
1608b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King		cyber2000fb_i2c_unregister(cfb);
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed:
1611e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#ifdef CONFIG_FB_CYBER2000_DDC
1612e5dedf8d561fb309ba37003546025300678da549Ondrej Zary	if (err && cfb->ddc_registered)
1613e5dedf8d561fb309ba37003546025300678da549Ondrej Zary		i2c_del_adapter(&cfb->ddc_adapter);
1614e5dedf8d561fb309ba37003546025300678da549Ondrej Zary#endif
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1618b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell Kingstatic void __devexit cyberpro_common_remove(struct cfb_info *cfb)
1619b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King{
1620b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	unregister_framebuffer(&cfb->fb);
1621b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King#ifdef CONFIG_FB_CYBER2000_DDC
1622b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	if (cfb->ddc_registered)
1623b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King		i2c_del_adapter(&cfb->ddc_adapter);
1624b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King#endif
1625b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King	cyber2000fb_i2c_unregister(cfb);
1626b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King}
1627b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cyberpro_common_resume(struct cfb_info *cfb)
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyberpro_init_hw(cfb);
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Reprogram the MEM_CTL1 and MEM_CTL2 registers
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(EXT_MEM_CTL1, cfb->mem_ctl1, cfb);
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000_grphw(EXT_MEM_CTL2, cfb->mem_ctl2, cfb);
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Restore the old video mode and the palette.
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We also need to tell fbcon to redraw the console.
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_set_par(&cfb->fb);
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_ARCH_SHARK
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1647eab184c2362567f2b2e951b7bd0e0d353a7e5091Alexander Schulz#include <mach/framebuffer.h>
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1649532237eff1f271302ed923af6d811a699d582bbcKrzysztof Heltstatic int __devinit cyberpro_vl_probe(void)
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cfb_info *cfb;
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENOMEM;
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1654532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	if (!request_mem_region(FB_START, FB_SIZE, "CyberPro2010"))
1655532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		return err;
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb = cyberpro_alloc_fb_info(ID_CYBERPRO_2010, "CyberPro2010");
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cfb)
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_release;
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
166124d6e5cb191189531396870402bf276aacf01598Russell King	cfb->irq = -1;
1662532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	cfb->region = ioremap(FB_START, FB_SIZE);
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cfb->region)
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_ioremap;
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->regs = cfb->region + MMIO_OFFSET;
166724d6e5cb191189531396870402bf276aacf01598Russell King	cfb->fb.device = NULL;
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.fix.mmio_start = FB_START + MMIO_OFFSET;
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.fix.smem_start = FB_START;
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Bring up the hardware.  This is expected to enable access
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to the linear memory region, and allow access to the memory
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * mapped registers.  Also, mem_ctl1 and mem_ctl2 must be
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * initialised.
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(0x18, 0x46e8, cfb);
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(0x01, 0x102, cfb);
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(0x08, 0x46e8, cfb);
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(EXT_BIU_MISC, 0x3ce, cfb);
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_writeb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf, cfb);
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->mclk_mult = 0xdb;
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->mclk_div  = 0x54;
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = cyberpro_common_probe(cfb);
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed;
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (int_cfb_info == NULL)
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int_cfb_info = cfb;
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed:
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap(cfb->region);
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_ioremap:
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyberpro_free_fb_info(cfb);
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_release:
1700532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt	release_mem_region(FB_START, FB_SIZE);
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_ARCH_SHARK */
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI specific support.
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to wake up the CyberPro, and make sure its in linear memory
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mode.  Unfortunately, this is specific to the platform and card that
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we are running on.
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On x86 and ARM, should we be initialising the CyberPro first via the
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IO registers, and then the MMIO registers to catch all cases?  Can we
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * end up in the situation where the chip is in MMIO mode, but not awake
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on an x86 system?
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cyberpro_pci_enable_mmio(struct cfb_info *cfb)
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char val;
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(__sparc_v9__)
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#error "You lose, consult DaveM."
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#elif defined(__sparc__)
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SPARC does not have an "outb" instruction, so we generate
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * I/O cycles storing into a reserved memory space at
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * physical address 0x3000000
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1732cd0306656c15f355e0e533cc0f08691bb98ca912Al Viro	unsigned char __iomem *iop;
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iop = ioremap(0x3000000, 0x5000);
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (iop == NULL) {
173689b409f77017171c55e79628eefc557126c8fd7fDavid S. Miller		printk(KERN_ERR "iga5000: cannot map I/O\n");
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writeb(0x18, iop + 0x46e8);
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writeb(0x01, iop + 0x102);
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writeb(0x08, iop + 0x46e8);
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writeb(EXT_BIU_MISC, iop + 0x3ce);
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writeb(EXT_BIU_MISC_LIN_ENABLE, iop + 0x3cf);
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1746cd0306656c15f355e0e533cc0f08691bb98ca912Al Viro	iounmap(iop);
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Most other machine types are "normal", so
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * we use the standard IO-based wakeup.
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x18, 0x46e8);
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x01, 0x102);
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x08, 0x46e8);
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(EXT_BIU_MISC, 0x3ce);
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf);
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Allow the CyberPro to accept PCI burst accesses
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1762cd792aa896f281a224870eb5f2ee5b24682910a5Woody Suwalski	if (cfb->id == ID_CYBERPRO_2010) {
1763532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		printk(KERN_INFO "%s: NOT enabling PCI bursts\n",
1764532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt		       cfb->fb.fix.id);
1765cd792aa896f281a224870eb5f2ee5b24682910a5Woody Suwalski	} else {
1766cd792aa896f281a224870eb5f2ee5b24682910a5Woody Suwalski		val = cyber2000_grphr(EXT_BUS_CTL, cfb);
1767cd792aa896f281a224870eb5f2ee5b24682910a5Woody Suwalski		if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) {
1768cd792aa896f281a224870eb5f2ee5b24682910a5Woody Suwalski			printk(KERN_INFO "%s: enabling PCI bursts\n",
1769cd792aa896f281a224870eb5f2ee5b24682910a5Woody Suwalski				cfb->fb.fix.id);
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771cd792aa896f281a224870eb5f2ee5b24682910a5Woody Suwalski			val |= EXT_BUS_CTL_PCIBURST_WRITE;
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1773cd792aa896f281a224870eb5f2ee5b24682910a5Woody Suwalski			if (cfb->id == ID_CYBERPRO_5000)
1774cd792aa896f281a224870eb5f2ee5b24682910a5Woody Suwalski				val |= EXT_BUS_CTL_PCIBURST_READ;
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1776cd792aa896f281a224870eb5f2ee5b24682910a5Woody Suwalski			cyber2000_grphw(EXT_BUS_CTL, val, cfb);
1777cd792aa896f281a224870eb5f2ee5b24682910a5Woody Suwalski		}
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cfb_info *cfb;
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char name[16];
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(name, "CyberPro%4X", id->device);
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = pci_enable_device(dev);
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = -ENOMEM;
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb = cyberpro_alloc_fb_info(id->driver_data, name);
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cfb)
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_release;
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801ed5a35acbb48d512332a53565e6341c65eecfa29Russell King	err = pci_request_regions(dev, cfb->fb.fix.id);
1802ed5a35acbb48d512332a53565e6341c65eecfa29Russell King	if (err)
1803ed5a35acbb48d512332a53565e6341c65eecfa29Russell King		goto failed_regions;
1804ed5a35acbb48d512332a53565e6341c65eecfa29Russell King
180524d6e5cb191189531396870402bf276aacf01598Russell King	cfb->irq = dev->irq;
18063c36aa5ccdf516255ef2eac90dd948da891aa4bdArjan van de Ven	cfb->region = pci_ioremap_bar(dev, 0);
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cfb->region)
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_ioremap;
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->regs = cfb->region + MMIO_OFFSET;
181124d6e5cb191189531396870402bf276aacf01598Russell King	cfb->fb.device = &dev->dev;
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET;
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->fb.fix.smem_start = pci_resource_start(dev, 0);
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Bring up the hardware.  This is expected to enable access
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to the linear memory region, and allow access to the memory
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * mapped registers.  Also, mem_ctl1 and mem_ctl2 must be
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * initialised.
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = cyberpro_pci_enable_mmio(cfb);
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed;
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Use MCLK from BIOS. FIXME: what about hotplug?
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->mclk_mult = cyber2000_grphr(EXT_MCLK_MULT, cfb);
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cfb->mclk_div  = cyber2000_grphr(EXT_MCLK_DIV, cfb);
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __arm__
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MCLK on the NetWinder and the Shark is fixed at 75MHz
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (machine_is_netwinder()) {
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->mclk_mult = 0xdb;
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb->mclk_div  = 0x54;
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = cyberpro_common_probe(cfb);
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed;
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Our driver data
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_set_drvdata(dev, cfb);
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (int_cfb_info == NULL)
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int_cfb_info = cfb;
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed:
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap(cfb->region);
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_ioremap:
1857ed5a35acbb48d512332a53565e6341c65eecfa29Russell King	pci_release_regions(dev);
1858ed5a35acbb48d512332a53565e6341c65eecfa29Russell Kingfailed_regions:
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyberpro_free_fb_info(cfb);
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_release:
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __devexit cyberpro_pci_remove(struct pci_dev *dev)
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cfb_info *cfb = pci_get_drvdata(dev);
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cfb) {
1869b7ca01a9b20e3fdd11745227905e9ad8a99e0123Russell King		cyberpro_common_remove(cfb);
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iounmap(cfb->region);
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyberpro_free_fb_info(cfb);
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Ensure that the driver data is no longer
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * valid.
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_set_drvdata(dev, NULL);
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cfb == int_cfb_info)
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int_cfb_info = NULL;
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_release_regions(dev);
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cyberpro_pci_suspend(struct pci_dev *dev, pm_message_t state)
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Re-initialise the CyberPro hardware
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cyberpro_pci_resume(struct pci_dev *dev)
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cfb_info *cfb = pci_get_drvdata(dev);
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cfb) {
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyberpro_pci_enable_mmio(cfb);
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cyberpro_common_resume(cfb);
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_device_id cyberpro_pci_table[] = {
1906532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt/*	Not yet
1907532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt *	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
1908532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt *		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 },
1909532237eff1f271302ed923af6d811a699d582bbcKrzysztof Helt */
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 },
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2010 },
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000,
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_5000 },
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0, }
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1919532237eff1f271302ed923af6d811a699d582bbcKrzysztof HeltMODULE_DEVICE_TABLE(pci, cyberpro_pci_table);
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver cyberpro_driver = {
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "CyberPro",
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe		= cyberpro_pci_probe,
19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.remove		= __devexit_p(cyberpro_pci_remove),
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.suspend	= cyberpro_pci_suspend,
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.resume		= cyberpro_pci_resume,
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table	= cyberpro_pci_table
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I don't think we can use the "module_init" stuff here because
19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the fbcon stuff may not be initialised yet.  Hence the #ifdef
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * around module_init.
19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Tony: "module_init" is now required
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init cyber2000fb_init(void)
19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = -1, err;
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE
19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *option = NULL;
19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fb_get_options("cyber2000fb", &option))
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cyber2000fb_setup(option);
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_ARCH_SHARK
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = cyberpro_vl_probe();
1952ab8e2eb722f1e5fcbd8181e3e9ef4e95c52124dfRusty Russell	if (!err)
19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = pci_register_driver(&cyberpro_driver);
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!err)
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret ? err : 0;
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1963ab8e2eb722f1e5fcbd8181e3e9ef4e95c52124dfRusty Russellmodule_init(cyber2000fb_init);
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1965ab8e2eb722f1e5fcbd8181e3e9ef4e95c52124dfRusty Russell#ifndef CONFIG_ARCH_SHARK
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cyberpro_exit(void)
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_unregister_driver(&cyberpro_driver);
19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(cyberpro_exit);
1971ab8e2eb722f1e5fcbd8181e3e9ef4e95c52124dfRusty Russell#endif
19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Russell King");
19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");
19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
1976