brintos

brintos / linux-shallow public Read only

0
0
Text · 108.8 KiB · a6dd1cd Raw
4024 lines · c
1/*2 *  ATI Frame Buffer Device Driver Core3 *4 *	Copyright (C) 2004  Alex Kern <alex.kern@gmx.de>5 *	Copyright (C) 1997-2001  Geert Uytterhoeven6 *	Copyright (C) 1998  Bernd Harries7 *	Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)8 *9 *  This driver supports the following ATI graphics chips:10 *    - ATI Mach6411 *12 *  To do: add support for13 *    - ATI Rage128 (from aty128fb.c)14 *    - ATI Radeon (from radeonfb.c)15 *16 *  This driver is partly based on the PowerMac console driver:17 *18 *	Copyright (C) 1996 Paul Mackerras19 *20 *  and on the PowerMac ATI/mach64 display driver:21 *22 *	Copyright (C) 1997 Michael AK Tesch23 *24 *	      with work by Jon Howell25 *			   Harry AC Eaton26 *			   Anthony Tong <atong@uiuc.edu>27 *28 *  Generic LCD support written by Daniel Mantione, ported from 2.4.20 by Alex Kern29 *  Many Thanks to Ville Syrjälä for patches and fixing nasting 16 bit color bug.30 *31 *  This file is subject to the terms and conditions of the GNU General Public32 *  License. See the file COPYING in the main directory of this archive for33 *  more details.34 *35 *  Many thanks to Nitya from ATI devrel for support and patience !36 */37 38/******************************************************************************39 40  TODO:41 42    - cursor support on all cards and all ramdacs.43    - cursor parameters controlable via ioctl()s.44    - guess PLL and MCLK based on the original PLL register values initialized45      by Open Firmware (if they are initialized). BIOS is done46 47    (Anyone with Mac to help with this?)48 49******************************************************************************/50 51#include <linux/aperture.h>52#include <linux/compat.h>53#include <linux/module.h>54#include <linux/moduleparam.h>55#include <linux/kernel.h>56#include <linux/errno.h>57#include <linux/string.h>58#include <linux/mm.h>59#include <linux/slab.h>60#include <linux/vmalloc.h>61#include <linux/delay.h>62#include <linux/compiler.h>63#include <linux/console.h>64#include <linux/fb.h>65#include <linux/init.h>66#include <linux/pci.h>67#include <linux/interrupt.h>68#include <linux/spinlock.h>69#include <linux/wait.h>70#include <linux/backlight.h>71#include <linux/reboot.h>72#include <linux/dmi.h>73 74#include <asm/io.h>75#include <linux/uaccess.h>76 77#include <video/mach64.h>78#include "atyfb.h"79#include "ati_ids.h"80 81#ifdef __powerpc__82#include <asm/machdep.h>83#include "../macmodes.h"84#endif85#ifdef __sparc__86#include <asm/fbio.h>87#include <asm/oplib.h>88#include <asm/prom.h>89#endif90 91#ifdef CONFIG_ADB_PMU92#include <linux/adb.h>93#include <linux/pmu.h>94#endif95#ifdef CONFIG_BOOTX_TEXT96#include <asm/btext.h>97#endif98#ifdef CONFIG_PMAC_BACKLIGHT99#include <asm/backlight.h>100#endif101 102/*103 * Debug flags.104 */105#undef DEBUG106/*#define DEBUG*/107 108/* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */109/*  - must be large enough to catch all GUI-Regs   */110/*  - must be aligned to a PAGE boundary           */111#define GUI_RESERVE	(1 * PAGE_SIZE)112 113/* FIXME: remove the FAIL definition */114#define FAIL(msg) do { \115	if (!(var->activate & FB_ACTIVATE_TEST)) \116		printk(KERN_CRIT "atyfb: " msg "\n"); \117	return -EINVAL; \118} while (0)119#define FAIL_MAX(msg, x, _max_) do { \120	if (x > _max_) { \121		if (!(var->activate & FB_ACTIVATE_TEST)) \122			printk(KERN_CRIT "atyfb: " msg " %x(%x)\n", x, _max_); \123		return -EINVAL; \124	} \125} while (0)126#ifdef DEBUG127#define DPRINTK(fmt, args...)	printk(KERN_DEBUG "atyfb: " fmt, ## args)128#else129#define DPRINTK(fmt, args...)	no_printk(fmt, ##args)130#endif131 132#define PRINTKI(fmt, args...)	printk(KERN_INFO "atyfb: " fmt, ## args)133#define PRINTKE(fmt, args...)	printk(KERN_ERR "atyfb: " fmt, ## args)134 135#if defined(CONFIG_PMAC_BACKLIGHT) || defined(CONFIG_FB_ATY_GENERIC_LCD) || \136defined(CONFIG_FB_ATY_BACKLIGHT) || defined (CONFIG_PPC_PMAC)137static const u32 lt_lcd_regs[] = {138	CNFG_PANEL_LG,139	LCD_GEN_CNTL_LG,140	DSTN_CONTROL_LG,141	HFB_PITCH_ADDR_LG,142	HORZ_STRETCHING_LG,143	VERT_STRETCHING_LG,144	0, /* EXT_VERT_STRETCH */145	LT_GIO_LG,146	POWER_MANAGEMENT_LG147};148 149void aty_st_lcd(int index, u32 val, const struct atyfb_par *par)150{151	if (M64_HAS(LT_LCD_REGS)) {152		aty_st_le32(lt_lcd_regs[index], val, par);153	} else {154		unsigned long temp;155 156		/* write addr byte */157		temp = aty_ld_le32(LCD_INDEX, par);158		aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);159		/* write the register value */160		aty_st_le32(LCD_DATA, val, par);161	}162}163 164u32 aty_ld_lcd(int index, const struct atyfb_par *par)165{166	if (M64_HAS(LT_LCD_REGS)) {167		return aty_ld_le32(lt_lcd_regs[index], par);168	} else {169		unsigned long temp;170 171		/* write addr byte */172		temp = aty_ld_le32(LCD_INDEX, par);173		aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);174		/* read the register value */175		return aty_ld_le32(LCD_DATA, par);176	}177}178#else /* defined(CONFIG_PMAC_BACKLIGHT) || defined(CONFIG_FB_ATY_BACKLIGHT) ||179	 defined(CONFIG_FB_ATY_GENERIC_LCD) || defined(CONFIG_PPC_PMAC) */180void aty_st_lcd(int index, u32 val, const struct atyfb_par *par)181{ }182 183u32 aty_ld_lcd(int index, const struct atyfb_par *par)184{185	return 0;186}187#endif /* defined(CONFIG_PMAC_BACKLIGHT) || defined(CONFIG_FB_ATY_BACKLIGHT) ||188	  defined (CONFIG_FB_ATY_GENERIC_LCD) || defined(CONFIG_PPC_PMAC) */189 190#ifdef CONFIG_FB_ATY_GENERIC_LCD191/*192 * ATIReduceRatio --193 *194 * Reduce a fraction by factoring out the largest common divider of the195 * fraction's numerator and denominator.196 */197static void ATIReduceRatio(int *Numerator, int *Denominator)198{199	int Multiplier, Divider, Remainder;200 201	Multiplier = *Numerator;202	Divider = *Denominator;203 204	while ((Remainder = Multiplier % Divider)) {205		Multiplier = Divider;206		Divider = Remainder;207	}208 209	*Numerator /= Divider;210	*Denominator /= Divider;211}212#endif213/*214 * The Hardware parameters for each card215 */216 217struct pci_mmap_map {218	unsigned long voff;219	unsigned long poff;220	unsigned long size;221	unsigned long prot_flag;222	unsigned long prot_mask;223};224 225static const struct fb_fix_screeninfo atyfb_fix = {226	.id		= "ATY Mach64",227	.type		= FB_TYPE_PACKED_PIXELS,228	.visual		= FB_VISUAL_PSEUDOCOLOR,229	.xpanstep	= 8,230	.ypanstep	= 1,231};232 233/*234 * Frame buffer device API235 */236 237static int atyfb_open(struct fb_info *info, int user);238static int atyfb_release(struct fb_info *info, int user);239static int atyfb_check_var(struct fb_var_screeninfo *var,240			   struct fb_info *info);241static int atyfb_set_par(struct fb_info *info);242static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,243			   u_int transp, struct fb_info *info);244static int atyfb_pan_display(struct fb_var_screeninfo *var,245			     struct fb_info *info);246static int atyfb_blank(int blank, struct fb_info *info);247static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg);248#ifdef CONFIG_COMPAT249static int atyfb_compat_ioctl(struct fb_info *info, u_int cmd, u_long arg)250{251	return atyfb_ioctl(info, cmd, (u_long)compat_ptr(arg));252}253#endif254 255#ifdef __sparc__256static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma);257#endif258static int atyfb_sync(struct fb_info *info);259 260/*261 * Internal routines262 */263 264static int aty_init(struct fb_info *info);265 266static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc);267 268static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc);269static int aty_var_to_crtc(const struct fb_info *info,270			   const struct fb_var_screeninfo *var,271			   struct crtc *crtc);272static int aty_crtc_to_var(const struct crtc *crtc,273			   struct fb_var_screeninfo *var);274static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info);275#ifdef CONFIG_PPC276static int read_aty_sense(const struct atyfb_par *par);277#endif278 279static DEFINE_MUTEX(reboot_lock);280static struct fb_info *reboot_info;281 282/*283 * Interface used by the world284 */285 286static struct fb_var_screeninfo default_var = {287	/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */288	640, 480, 640, 480, 0, 0, 8, 0,289	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},290	0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,291	0, FB_VMODE_NONINTERLACED292};293 294static const struct fb_videomode defmode = {295	/* 640x480 @ 60 Hz, 31.5 kHz hsync */296	NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,297	0, FB_VMODE_NONINTERLACED298};299 300static struct fb_ops atyfb_ops = {301	.owner		= THIS_MODULE,302	.fb_open	= atyfb_open,303	.fb_release	= atyfb_release,304	__FB_DEFAULT_IOMEM_OPS_RDWR,305	.fb_check_var	= atyfb_check_var,306	.fb_set_par	= atyfb_set_par,307	.fb_setcolreg	= atyfb_setcolreg,308	.fb_pan_display	= atyfb_pan_display,309	.fb_blank	= atyfb_blank,310	.fb_ioctl	= atyfb_ioctl,311#ifdef CONFIG_COMPAT312	.fb_compat_ioctl = atyfb_compat_ioctl,313#endif314	.fb_fillrect	= atyfb_fillrect,315	.fb_copyarea	= atyfb_copyarea,316	.fb_imageblit	= atyfb_imageblit,317#ifdef __sparc__318	.fb_mmap	= atyfb_mmap,319#else320	__FB_DEFAULT_IOMEM_OPS_MMAP,321#endif322	.fb_sync	= atyfb_sync,323};324 325static bool noaccel;326static bool nomtrr;327static int vram;328static int pll;329static int mclk;330static int xclk;331static int comp_sync = -1;332static char *mode;333static int backlight = IS_BUILTIN(CONFIG_PMAC_BACKLIGHT);334 335#ifdef CONFIG_PPC336static int default_vmode = VMODE_CHOOSE;337static int default_cmode = CMODE_CHOOSE;338 339module_param_named(vmode, default_vmode, int, 0);340MODULE_PARM_DESC(vmode, "int: video mode for mac");341module_param_named(cmode, default_cmode, int, 0);342MODULE_PARM_DESC(cmode, "int: color mode for mac");343#endif344 345#ifdef CONFIG_ATARI346static unsigned int mach64_count = 0;347static unsigned long phys_vmembase[FB_MAX] = { 0, };348static unsigned long phys_size[FB_MAX] = { 0, };349static unsigned long phys_guiregbase[FB_MAX] = { 0, };350#endif351 352/* top -> down is an evolution of mach64 chipset, any corrections? */353#define ATI_CHIP_88800GX   (M64F_GX)354#define ATI_CHIP_88800CX   (M64F_GX)355 356#define ATI_CHIP_264CT     (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO)357#define ATI_CHIP_264ET     (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO)358 359#define ATI_CHIP_264VT     (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO)360#define ATI_CHIP_264GT     (M64F_GT | M64F_INTEGRATED               | M64F_MAGIC_FIFO | M64F_EXTRA_BRIGHT)361 362#define ATI_CHIP_264VTB    (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP)363#define ATI_CHIP_264VT3    (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL)364#define ATI_CHIP_264VT4    (M64F_VT | M64F_INTEGRATED               | M64F_GTB_DSP)365 366/* FIXME what is this chip? */367#define ATI_CHIP_264LT     (M64F_GT | M64F_INTEGRATED               | M64F_GTB_DSP)368 369/* make sets shorter */370#define ATI_MODERN_SET     (M64F_GT | M64F_INTEGRATED               | M64F_GTB_DSP | M64F_EXTRA_BRIGHT)371 372#define ATI_CHIP_264GTB    (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL)373/*#define ATI_CHIP_264GTDVD  ?*/374#define ATI_CHIP_264LTG    (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL)375 376#define ATI_CHIP_264GT2C   (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE)377#define ATI_CHIP_264GTPRO  (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)378#define ATI_CHIP_264LTPRO  (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)379 380#define ATI_CHIP_264XL     (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM)381#define ATI_CHIP_MOBILITY  (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM | M64F_MOBIL_BUS)382 383static struct {384	u16 pci_id;385	const char *name;386	int pll, mclk, xclk, ecp_max;387	u32 features;388} aty_chips[] = {389#ifdef CONFIG_FB_ATY_GX390	/* Mach64 GX */391	{ PCI_CHIP_MACH64GX, "ATI888GX00 (Mach64 GX)", 135, 50, 50, 0, ATI_CHIP_88800GX },392	{ PCI_CHIP_MACH64CX, "ATI888CX00 (Mach64 CX)", 135, 50, 50, 0, ATI_CHIP_88800CX },393#endif /* CONFIG_FB_ATY_GX */394 395#ifdef CONFIG_FB_ATY_CT396	{ PCI_CHIP_MACH64CT, "ATI264CT (Mach64 CT)", 135, 60, 60, 0, ATI_CHIP_264CT },397	{ PCI_CHIP_MACH64ET, "ATI264ET (Mach64 ET)", 135, 60, 60, 0, ATI_CHIP_264ET },398 399	/* FIXME what is this chip? */400	{ PCI_CHIP_MACH64LT, "ATI264LT (Mach64 LT)", 135, 63, 63, 0, ATI_CHIP_264LT },401 402	{ PCI_CHIP_MACH64VT, "ATI264VT (Mach64 VT)", 170, 67, 67, 80, ATI_CHIP_264VT },403	{ PCI_CHIP_MACH64GT, "3D RAGE (Mach64 GT)", 135, 63, 63, 80, ATI_CHIP_264GT },404 405	{ PCI_CHIP_MACH64VU, "ATI264VT3 (Mach64 VU)", 200, 67, 67, 80, ATI_CHIP_264VT3 },406	{ PCI_CHIP_MACH64GU, "3D RAGE II+ (Mach64 GU)", 200, 67, 67, 100, ATI_CHIP_264GTB },407 408	{ PCI_CHIP_MACH64LG, "3D RAGE LT (Mach64 LG)", 230, 63, 63, 100, ATI_CHIP_264LTG | M64F_LT_LCD_REGS | M64F_G3_PB_1024x768 },409 410	{ PCI_CHIP_MACH64VV, "ATI264VT4 (Mach64 VV)", 230, 83, 83, 100, ATI_CHIP_264VT4 },411 412	{ PCI_CHIP_MACH64GV, "3D RAGE IIC (Mach64 GV, PCI)", 230, 83, 83, 100, ATI_CHIP_264GT2C },413	{ PCI_CHIP_MACH64GW, "3D RAGE IIC (Mach64 GW, AGP)", 230, 83, 83, 100, ATI_CHIP_264GT2C },414	{ PCI_CHIP_MACH64GY, "3D RAGE IIC (Mach64 GY, PCI)", 230, 83, 83, 100, ATI_CHIP_264GT2C },415	{ PCI_CHIP_MACH64GZ, "3D RAGE IIC (Mach64 GZ, AGP)", 230, 83, 83, 100, ATI_CHIP_264GT2C },416 417	{ PCI_CHIP_MACH64GB, "3D RAGE PRO (Mach64 GB, BGA, AGP)", 230, 100, 100, 125, ATI_CHIP_264GTPRO },418	{ PCI_CHIP_MACH64GD, "3D RAGE PRO (Mach64 GD, BGA, AGP 1x)", 230, 100, 100, 125, ATI_CHIP_264GTPRO },419	{ PCI_CHIP_MACH64GI, "3D RAGE PRO (Mach64 GI, BGA, PCI)", 230, 100, 100, 125, ATI_CHIP_264GTPRO | M64F_MAGIC_VRAM_SIZE },420	{ PCI_CHIP_MACH64GP, "3D RAGE PRO (Mach64 GP, PQFP, PCI)", 230, 100, 100, 125, ATI_CHIP_264GTPRO },421	{ PCI_CHIP_MACH64GQ, "3D RAGE PRO (Mach64 GQ, PQFP, PCI, limited 3D)", 230, 100, 100, 125, ATI_CHIP_264GTPRO },422 423	{ PCI_CHIP_MACH64LB, "3D RAGE LT PRO (Mach64 LB, AGP)", 236, 75, 100, 135, ATI_CHIP_264LTPRO },424	{ PCI_CHIP_MACH64LD, "3D RAGE LT PRO (Mach64 LD, AGP)", 230, 100, 100, 135, ATI_CHIP_264LTPRO },425	{ PCI_CHIP_MACH64LI, "3D RAGE LT PRO (Mach64 LI, PCI)", 230, 100, 100, 135, ATI_CHIP_264LTPRO | M64F_G3_PB_1_1 | M64F_G3_PB_1024x768 },426	{ PCI_CHIP_MACH64LP, "3D RAGE LT PRO (Mach64 LP, PCI)", 230, 100, 100, 135, ATI_CHIP_264LTPRO | M64F_G3_PB_1024x768 },427	{ PCI_CHIP_MACH64LQ, "3D RAGE LT PRO (Mach64 LQ, PCI)", 230, 100, 100, 135, ATI_CHIP_264LTPRO },428 429	{ PCI_CHIP_MACH64GM, "3D RAGE XL (Mach64 GM, AGP 2x)", 230, 83, 63, 135, ATI_CHIP_264XL },430	{ PCI_CHIP_MACH64GN, "3D RAGE XC (Mach64 GN, AGP 2x)", 230, 83, 63, 135, ATI_CHIP_264XL },431	{ PCI_CHIP_MACH64GO, "3D RAGE XL (Mach64 GO, PCI-66)", 230, 83, 63, 135, ATI_CHIP_264XL },432	{ PCI_CHIP_MACH64GL, "3D RAGE XC (Mach64 GL, PCI-66)", 230, 83, 63, 135, ATI_CHIP_264XL },433	{ PCI_CHIP_MACH64GR, "3D RAGE XL (Mach64 GR, PCI-33)", 230, 83, 63, 135, ATI_CHIP_264XL | M64F_SDRAM_MAGIC_PLL },434	{ PCI_CHIP_MACH64GS, "3D RAGE XC (Mach64 GS, PCI-33)", 230, 83, 63, 135, ATI_CHIP_264XL },435 436	{ PCI_CHIP_MACH64LM, "3D RAGE Mobility P/M (Mach64 LM, AGP 2x)", 230, 83, 125, 135, ATI_CHIP_MOBILITY },437	{ PCI_CHIP_MACH64LN, "3D RAGE Mobility L (Mach64 LN, AGP 2x)", 230, 83, 125, 135, ATI_CHIP_MOBILITY },438	{ PCI_CHIP_MACH64LR, "3D RAGE Mobility P/M (Mach64 LR, PCI)", 230, 83, 125, 135, ATI_CHIP_MOBILITY },439	{ PCI_CHIP_MACH64LS, "3D RAGE Mobility L (Mach64 LS, PCI)", 230, 83, 125, 135, ATI_CHIP_MOBILITY },440#endif /* CONFIG_FB_ATY_CT */441};442 443/*444 * Last page of 8 MB (4 MB on ISA) aperture is MMIO,445 * unless the auxiliary register aperture is used.446 */447static void aty_fudge_framebuffer_len(struct fb_info *info)448{449	struct atyfb_par *par = (struct atyfb_par *) info->par;450 451	if (!par->aux_start &&452	    (info->fix.smem_len == 0x800000 ||453	     (par->bus_type == ISA && info->fix.smem_len == 0x400000)))454		info->fix.smem_len -= GUI_RESERVE;455}456 457static int correct_chipset(struct atyfb_par *par)458{459	u8 rev;460	u16 type;461	u32 chip_id;462	const char *name;463	int i;464 465	for (i = (int)ARRAY_SIZE(aty_chips) - 1; i >= 0; i--)466		if (par->pci_id == aty_chips[i].pci_id)467			break;468 469	if (i < 0)470		return -ENODEV;471 472	name = aty_chips[i].name;473	par->pll_limits.pll_max = aty_chips[i].pll;474	par->pll_limits.mclk = aty_chips[i].mclk;475	par->pll_limits.xclk = aty_chips[i].xclk;476	par->pll_limits.ecp_max = aty_chips[i].ecp_max;477	par->features = aty_chips[i].features;478 479	chip_id = aty_ld_le32(CNFG_CHIP_ID, par);480	type = chip_id & CFG_CHIP_TYPE;481	rev = (chip_id & CFG_CHIP_REV) >> 24;482 483	switch (par->pci_id) {484#ifdef CONFIG_FB_ATY_GX485	case PCI_CHIP_MACH64GX:486		if (type != 0x00d7)487			return -ENODEV;488		break;489	case PCI_CHIP_MACH64CX:490		if (type != 0x0057)491			return -ENODEV;492		break;493#endif494#ifdef CONFIG_FB_ATY_CT495	case PCI_CHIP_MACH64VT:496		switch (rev & 0x07) {497		case 0x00:498			switch (rev & 0xc0) {499			case 0x00:500				name = "ATI264VT (A3) (Mach64 VT)";501				par->pll_limits.pll_max = 170;502				par->pll_limits.mclk = 67;503				par->pll_limits.xclk = 67;504				par->pll_limits.ecp_max = 80;505				par->features = ATI_CHIP_264VT;506				break;507			case 0x40:508				name = "ATI264VT2 (A4) (Mach64 VT)";509				par->pll_limits.pll_max = 200;510				par->pll_limits.mclk = 67;511				par->pll_limits.xclk = 67;512				par->pll_limits.ecp_max = 80;513				par->features = ATI_CHIP_264VT | M64F_MAGIC_POSTDIV;514				break;515			}516			break;517		case 0x01:518			name = "ATI264VT3 (B1) (Mach64 VT)";519			par->pll_limits.pll_max = 200;520			par->pll_limits.mclk = 67;521			par->pll_limits.xclk = 67;522			par->pll_limits.ecp_max = 80;523			par->features = ATI_CHIP_264VTB;524			break;525		case 0x02:526			name = "ATI264VT3 (B2) (Mach64 VT)";527			par->pll_limits.pll_max = 200;528			par->pll_limits.mclk = 67;529			par->pll_limits.xclk = 67;530			par->pll_limits.ecp_max = 80;531			par->features = ATI_CHIP_264VT3;532			break;533		}534		break;535	case PCI_CHIP_MACH64GT:536		switch (rev & 0x07) {537		case 0x01:538			name = "3D RAGE II (Mach64 GT)";539			par->pll_limits.pll_max = 170;540			par->pll_limits.mclk = 67;541			par->pll_limits.xclk = 67;542			par->pll_limits.ecp_max = 80;543			par->features = ATI_CHIP_264GTB;544			break;545		case 0x02:546			name = "3D RAGE II+ (Mach64 GT)";547			par->pll_limits.pll_max = 200;548			par->pll_limits.mclk = 67;549			par->pll_limits.xclk = 67;550			par->pll_limits.ecp_max = 100;551			par->features = ATI_CHIP_264GTB;552			break;553		}554		break;555#endif556	}557 558	PRINTKI("%s [0x%04x rev 0x%02x]\n", name, type, rev);559	return 0;560}561 562static char ram_dram[] __maybe_unused = "DRAM";563static char ram_resv[] __maybe_unused = "RESV";564#ifdef CONFIG_FB_ATY_GX565static char ram_vram[] = "VRAM";566#endif /* CONFIG_FB_ATY_GX */567#ifdef CONFIG_FB_ATY_CT568static char ram_edo[] = "EDO";569static char ram_sdram[] = "SDRAM (1:1)";570static char ram_sgram[] = "SGRAM (1:1)";571static char ram_sdram32[] = "SDRAM (2:1) (32-bit)";572static char ram_wram[] = "WRAM";573static char ram_off[] = "OFF";574#endif /* CONFIG_FB_ATY_CT */575 576 577#ifdef CONFIG_FB_ATY_GX578static char *aty_gx_ram[8] = {579	ram_dram, ram_vram, ram_vram, ram_dram,580	ram_dram, ram_vram, ram_vram, ram_resv581};582#endif /* CONFIG_FB_ATY_GX */583 584#ifdef CONFIG_FB_ATY_CT585static char *aty_ct_ram[8] = {586	ram_off, ram_dram, ram_edo, ram_edo,587	ram_sdram, ram_sgram, ram_wram, ram_resv588};589static char *aty_xl_ram[8] = {590	ram_off, ram_dram, ram_edo, ram_edo,591	ram_sdram, ram_sgram, ram_sdram32, ram_resv592};593#endif /* CONFIG_FB_ATY_CT */594 595static u32 atyfb_get_pixclock(struct fb_var_screeninfo *var,596			      struct atyfb_par *par)597{598	u32 pixclock = var->pixclock;599#ifdef CONFIG_FB_ATY_GENERIC_LCD600	u32 lcd_on_off;601	par->pll.ct.xres = 0;602	if (par->lcd_table != 0) {603		lcd_on_off = aty_ld_lcd(LCD_GEN_CNTL, par);604		if (lcd_on_off & LCD_ON) {605			par->pll.ct.xres = var->xres;606			pixclock = par->lcd_pixclock;607		}608	}609#endif610	return pixclock;611}612 613#if defined(CONFIG_PPC)614 615/*616 * Apple monitor sense617 */618 619static int read_aty_sense(const struct atyfb_par *par)620{621	int sense, i;622 623	aty_st_le32(GP_IO, 0x31003100, par); /* drive outputs high */624	__delay(200);625	aty_st_le32(GP_IO, 0, par); /* turn off outputs */626	__delay(2000);627	i = aty_ld_le32(GP_IO, par); /* get primary sense value */628	sense = ((i & 0x3000) >> 3) | (i & 0x100);629 630	/* drive each sense line low in turn and collect the other 2 */631	aty_st_le32(GP_IO, 0x20000000, par); /* drive A low */632	__delay(2000);633	i = aty_ld_le32(GP_IO, par);634	sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4);635	aty_st_le32(GP_IO, 0x20002000, par); /* drive A high again */636	__delay(200);637 638	aty_st_le32(GP_IO, 0x10000000, par); /* drive B low */639	__delay(2000);640	i = aty_ld_le32(GP_IO, par);641	sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6);642	aty_st_le32(GP_IO, 0x10001000, par); /* drive B high again */643	__delay(200);644 645	aty_st_le32(GP_IO, 0x01000000, par); /* drive C low */646	__delay(2000);647	sense |= (aty_ld_le32(GP_IO, par) & 0x3000) >> 12;648	aty_st_le32(GP_IO, 0, par); /* turn off outputs */649	return sense;650}651 652#endif /* defined(CONFIG_PPC) */653 654/* ------------------------------------------------------------------------- */655 656/*657 * CRTC programming658 */659 660static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc)661{662#ifdef CONFIG_FB_ATY_GENERIC_LCD663	if (par->lcd_table != 0) {664		if (!M64_HAS(LT_LCD_REGS)) {665			crtc->lcd_index = aty_ld_le32(LCD_INDEX, par);666			aty_st_le32(LCD_INDEX, crtc->lcd_index, par);667		}668		crtc->lcd_config_panel = aty_ld_lcd(CNFG_PANEL, par);669		crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par);670 671 672		/* switch to non shadow registers */673		aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl &674			   ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par);675 676		/* save stretching */677		crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par);678		crtc->vert_stretching = aty_ld_lcd(VERT_STRETCHING, par);679		if (!M64_HAS(LT_LCD_REGS))680			crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par);681	}682#endif683	crtc->h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);684	crtc->h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);685	crtc->v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);686	crtc->v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);687	crtc->vline_crnt_vline = aty_ld_le32(CRTC_VLINE_CRNT_VLINE, par);688	crtc->off_pitch = aty_ld_le32(CRTC_OFF_PITCH, par);689	crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);690 691#ifdef CONFIG_FB_ATY_GENERIC_LCD692	if (par->lcd_table != 0) {693		/* switch to shadow registers */694		aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) |695			   SHADOW_EN | SHADOW_RW_EN, par);696 697		crtc->shadow_h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);698		crtc->shadow_h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);699		crtc->shadow_v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);700		crtc->shadow_v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);701 702		aty_st_le32(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);703	}704#endif /* CONFIG_FB_ATY_GENERIC_LCD */705}706 707static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc)708{709#ifdef CONFIG_FB_ATY_GENERIC_LCD710	if (par->lcd_table != 0) {711		/* stop CRTC */712		aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl &713			    ~(CRTC_EXT_DISP_EN | CRTC_EN), par);714 715		/* update non-shadow registers first */716		aty_st_lcd(CNFG_PANEL, crtc->lcd_config_panel, par);717		aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl &718			   ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par);719 720		/* temporarily disable stretching */721		aty_st_lcd(HORZ_STRETCHING, crtc->horz_stretching &722			   ~(HORZ_STRETCH_MODE | HORZ_STRETCH_EN), par);723		aty_st_lcd(VERT_STRETCHING, crtc->vert_stretching &724			   ~(VERT_STRETCH_RATIO1 | VERT_STRETCH_RATIO2 |725			     VERT_STRETCH_USE0 | VERT_STRETCH_EN), par);726	}727#endif728	/* turn off CRT */729	aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~CRTC_EN, par);730 731	DPRINTK("setting up CRTC\n");732	DPRINTK("set primary CRT to %ix%i %c%c composite %c\n",733		((((crtc->h_tot_disp >> 16) & 0xff) + 1) << 3),734		(((crtc->v_tot_disp >> 16) & 0x7ff) + 1),735		(crtc->h_sync_strt_wid & 0x200000) ? 'N' : 'P',736		(crtc->v_sync_strt_wid & 0x200000) ? 'N' : 'P',737		(crtc->gen_cntl & CRTC_CSYNC_EN) ? 'P' : 'N');738 739	DPRINTK("CRTC_H_TOTAL_DISP: %x\n", crtc->h_tot_disp);740	DPRINTK("CRTC_H_SYNC_STRT_WID: %x\n", crtc->h_sync_strt_wid);741	DPRINTK("CRTC_V_TOTAL_DISP: %x\n", crtc->v_tot_disp);742	DPRINTK("CRTC_V_SYNC_STRT_WID: %x\n", crtc->v_sync_strt_wid);743	DPRINTK("CRTC_OFF_PITCH: %x\n", crtc->off_pitch);744	DPRINTK("CRTC_VLINE_CRNT_VLINE: %x\n", crtc->vline_crnt_vline);745	DPRINTK("CRTC_GEN_CNTL: %x\n", crtc->gen_cntl);746 747	aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, par);748	aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, par);749	aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, par);750	aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, par);751	aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, par);752	aty_st_le32(CRTC_VLINE_CRNT_VLINE, crtc->vline_crnt_vline, par);753 754	aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, par);755#if 0756	FIXME757	if (par->accel_flags & FB_ACCELF_TEXT)758		aty_init_engine(par, info);759#endif760#ifdef CONFIG_FB_ATY_GENERIC_LCD761	/* after setting the CRTC registers we should set the LCD registers. */762	if (par->lcd_table != 0) {763		/* switch to shadow registers */764		aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) |765			   SHADOW_EN | SHADOW_RW_EN, par);766 767		DPRINTK("set shadow CRT to %ix%i %c%c\n",768			((((crtc->shadow_h_tot_disp >> 16) & 0xff) + 1) << 3),769			(((crtc->shadow_v_tot_disp >> 16) & 0x7ff) + 1),770			(crtc->shadow_h_sync_strt_wid & 0x200000) ? 'N' : 'P',771			(crtc->shadow_v_sync_strt_wid & 0x200000) ? 'N' : 'P');772 773		DPRINTK("SHADOW CRTC_H_TOTAL_DISP: %x\n",774			crtc->shadow_h_tot_disp);775		DPRINTK("SHADOW CRTC_H_SYNC_STRT_WID: %x\n",776			crtc->shadow_h_sync_strt_wid);777		DPRINTK("SHADOW CRTC_V_TOTAL_DISP: %x\n",778			crtc->shadow_v_tot_disp);779		DPRINTK("SHADOW CRTC_V_SYNC_STRT_WID: %x\n",780			crtc->shadow_v_sync_strt_wid);781 782		aty_st_le32(CRTC_H_TOTAL_DISP, crtc->shadow_h_tot_disp, par);783		aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->shadow_h_sync_strt_wid, par);784		aty_st_le32(CRTC_V_TOTAL_DISP, crtc->shadow_v_tot_disp, par);785		aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->shadow_v_sync_strt_wid, par);786 787		/* restore CRTC selection & shadow state and enable stretching */788		DPRINTK("LCD_GEN_CNTL: %x\n", crtc->lcd_gen_cntl);789		DPRINTK("HORZ_STRETCHING: %x\n", crtc->horz_stretching);790		DPRINTK("VERT_STRETCHING: %x\n", crtc->vert_stretching);791		if (!M64_HAS(LT_LCD_REGS))792			DPRINTK("EXT_VERT_STRETCH: %x\n", crtc->ext_vert_stretch);793 794		aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);795		aty_st_lcd(HORZ_STRETCHING, crtc->horz_stretching, par);796		aty_st_lcd(VERT_STRETCHING, crtc->vert_stretching, par);797		if (!M64_HAS(LT_LCD_REGS)) {798			aty_st_lcd(EXT_VERT_STRETCH, crtc->ext_vert_stretch, par);799			aty_ld_le32(LCD_INDEX, par);800			aty_st_le32(LCD_INDEX, crtc->lcd_index, par);801		}802	}803#endif /* CONFIG_FB_ATY_GENERIC_LCD */804}805 806static u32 calc_line_length(struct atyfb_par *par, u32 vxres, u32 bpp)807{808	u32 line_length = vxres * bpp / 8;809 810	if (par->ram_type == SGRAM ||811	    (!M64_HAS(XL_MEM) && par->ram_type == WRAM))812		line_length = (line_length + 63) & ~63;813 814	return line_length;815}816 817static int aty_var_to_crtc(const struct fb_info *info,818			   const struct fb_var_screeninfo *var,819			   struct crtc *crtc)820{821	struct atyfb_par *par = (struct atyfb_par *) info->par;822	u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;823	u32 sync, vmode;824	u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol;825	u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync;826	u32 pix_width, dp_pix_width, dp_chain_mask;827	u32 line_length;828 829	/* input */830	xres = (var->xres + 7) & ~7;831	yres = var->yres;832	vxres = (var->xres_virtual + 7) & ~7;833	vyres = var->yres_virtual;834	xoffset = (var->xoffset + 7) & ~7;835	yoffset = var->yoffset;836	bpp = var->bits_per_pixel;837	if (bpp == 16)838		bpp = (var->green.length == 5) ? 15 : 16;839	sync = var->sync;840	vmode = var->vmode;841 842	/* convert (and round up) and validate */843	if (vxres < xres + xoffset)844		vxres = xres + xoffset;845	h_disp = xres;846 847	if (vyres < yres + yoffset)848		vyres = yres + yoffset;849	v_disp = yres;850 851	if (bpp <= 8) {852		bpp = 8;853		pix_width = CRTC_PIX_WIDTH_8BPP;854		dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP |855			BYTE_ORDER_LSB_TO_MSB;856		dp_chain_mask = DP_CHAIN_8BPP;857	} else if (bpp <= 15) {858		bpp = 16;859		pix_width = CRTC_PIX_WIDTH_15BPP;860		dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP |861			BYTE_ORDER_LSB_TO_MSB;862		dp_chain_mask = DP_CHAIN_15BPP;863	} else if (bpp <= 16) {864		bpp = 16;865		pix_width = CRTC_PIX_WIDTH_16BPP;866		dp_pix_width = HOST_16BPP | SRC_16BPP | DST_16BPP |867			BYTE_ORDER_LSB_TO_MSB;868		dp_chain_mask = DP_CHAIN_16BPP;869	} else if (bpp <= 24 && M64_HAS(INTEGRATED)) {870		bpp = 24;871		pix_width = CRTC_PIX_WIDTH_24BPP;872		dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP |873			BYTE_ORDER_LSB_TO_MSB;874		dp_chain_mask = DP_CHAIN_24BPP;875	} else if (bpp <= 32) {876		bpp = 32;877		pix_width = CRTC_PIX_WIDTH_32BPP;878		dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP |879			BYTE_ORDER_LSB_TO_MSB;880		dp_chain_mask = DP_CHAIN_32BPP;881	} else882		FAIL("invalid bpp");883 884	line_length = calc_line_length(par, vxres, bpp);885 886	if (vyres * line_length > info->fix.smem_len)887		FAIL("not enough video RAM");888 889	h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;890	v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;891 892	if ((xres > 1920) || (yres > 1200)) {893		FAIL("MACH64 chips are designed for max 1920x1200\n"894		     "select another resolution.");895	}896	h_sync_strt = h_disp + var->right_margin;897	h_sync_end = h_sync_strt + var->hsync_len;898	h_sync_dly  = var->right_margin & 7;899	h_total = h_sync_end + h_sync_dly + var->left_margin;900 901	v_sync_strt = v_disp + var->lower_margin;902	v_sync_end = v_sync_strt + var->vsync_len;903	v_total = v_sync_end + var->upper_margin;904 905#ifdef CONFIG_FB_ATY_GENERIC_LCD906	if (par->lcd_table != 0) {907		if (!M64_HAS(LT_LCD_REGS)) {908			u32 lcd_index = aty_ld_le32(LCD_INDEX, par);909			crtc->lcd_index = lcd_index &910				~(LCD_INDEX_MASK | LCD_DISPLAY_DIS |911				  LCD_SRC_SEL | CRTC2_DISPLAY_DIS);912			aty_st_le32(LCD_INDEX, lcd_index, par);913		}914 915		if (!M64_HAS(MOBIL_BUS))916			crtc->lcd_index |= CRTC2_DISPLAY_DIS;917 918		crtc->lcd_config_panel = aty_ld_lcd(CNFG_PANEL, par) | 0x4000;919		crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par) & ~CRTC_RW_SELECT;920 921		crtc->lcd_gen_cntl &=922			~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | TVCLK_PM_EN |923			/*VCLK_DAC_PM_EN | USE_SHADOWED_VEND |*/924			USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN);925		crtc->lcd_gen_cntl |= DONT_SHADOW_VPAR | LOCK_8DOT;926 927		if ((crtc->lcd_gen_cntl & LCD_ON) &&928		    ((xres > par->lcd_width) || (yres > par->lcd_height))) {929			/*930			 * We cannot display the mode on the LCD. If the CRT is931			 * enabled we can turn off the LCD.932			 * If the CRT is off, it isn't a good idea to switch it933			 * on; we don't know if one is connected. So it's better934			 * to fail then.935			 */936			if (crtc->lcd_gen_cntl & CRT_ON) {937				if (!(var->activate & FB_ACTIVATE_TEST))938					PRINTKI("Disable LCD panel, because video mode does not fit.\n");939				crtc->lcd_gen_cntl &= ~LCD_ON;940				/*aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);*/941			} else {942				if (!(var->activate & FB_ACTIVATE_TEST))943					PRINTKE("Video mode exceeds size of LCD panel.\nConnect this computer to a conventional monitor if you really need this mode.\n");944				return -EINVAL;945			}946		}947	}948 949	if ((par->lcd_table != 0) && (crtc->lcd_gen_cntl & LCD_ON)) {950		int VScan = 1;951		/* bpp -> bytespp, 1,4 -> 0; 8 -> 2; 15,16 -> 1; 24 -> 6; 32 -> 5952		const u8 DFP_h_sync_dly_LT[] = { 0, 2, 1, 6, 5 };953		const u8 ADD_to_strt_wid_and_dly_LT_DAC[] = { 0, 5, 6, 9, 9, 12, 12 };  */954 955		vmode &= ~(FB_VMODE_DOUBLE | FB_VMODE_INTERLACED);956 957		/*958		 * This is horror! When we simulate, say 640x480 on an 800x600959		 * LCD monitor, the CRTC should be programmed 800x600 values for960		 * the non visible part, but 640x480 for the visible part.961		 * This code has been tested on a laptop with it's 1400x1050 LCD962		 * monitor and a conventional monitor both switched on.963		 * Tested modes: 1280x1024, 1152x864, 1024x768, 800x600,964		 * works with little glitches also with DOUBLESCAN modes965		 */966		if (yres < par->lcd_height) {967			VScan = par->lcd_height / yres;968			if (VScan > 1) {969				VScan = 2;970				vmode |= FB_VMODE_DOUBLE;971			}972		}973 974		h_sync_strt = h_disp + par->lcd_right_margin;975		h_sync_end = h_sync_strt + par->lcd_hsync_len;976		h_sync_dly = /*DFP_h_sync_dly[ ( bpp + 1 ) / 3 ]; */par->lcd_hsync_dly;977		h_total = h_disp + par->lcd_hblank_len;978 979		v_sync_strt = v_disp + par->lcd_lower_margin / VScan;980		v_sync_end = v_sync_strt + par->lcd_vsync_len / VScan;981		v_total = v_disp + par->lcd_vblank_len / VScan;982	}983#endif /* CONFIG_FB_ATY_GENERIC_LCD */984 985	h_disp = (h_disp >> 3) - 1;986	h_sync_strt = (h_sync_strt >> 3) - 1;987	h_sync_end = (h_sync_end >> 3) - 1;988	h_total = (h_total >> 3) - 1;989	h_sync_wid = h_sync_end - h_sync_strt;990 991	FAIL_MAX("h_disp too large", h_disp, 0xff);992	FAIL_MAX("h_sync_strt too large", h_sync_strt, 0x1ff);993	/*FAIL_MAX("h_sync_wid too large", h_sync_wid, 0x1f);*/994	if (h_sync_wid > 0x1f)995		h_sync_wid = 0x1f;996	FAIL_MAX("h_total too large", h_total, 0x1ff);997 998	if (vmode & FB_VMODE_DOUBLE) {999		v_disp <<= 1;1000		v_sync_strt <<= 1;1001		v_sync_end <<= 1;1002		v_total <<= 1;1003	}1004 1005	v_disp--;1006	v_sync_strt--;1007	v_sync_end--;1008	v_total--;1009	v_sync_wid = v_sync_end - v_sync_strt;1010 1011	FAIL_MAX("v_disp too large", v_disp, 0x7ff);1012	FAIL_MAX("v_sync_stsrt too large", v_sync_strt, 0x7ff);1013	/*FAIL_MAX("v_sync_wid too large", v_sync_wid, 0x1f);*/1014	if (v_sync_wid > 0x1f)1015		v_sync_wid = 0x1f;1016	FAIL_MAX("v_total too large", v_total, 0x7ff);1017 1018	c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0;1019 1020	/* output */1021	crtc->vxres = vxres;1022	crtc->vyres = vyres;1023	crtc->xoffset = xoffset;1024	crtc->yoffset = yoffset;1025	crtc->bpp = bpp;1026	crtc->off_pitch =1027		((yoffset * line_length + xoffset * bpp / 8) / 8) |1028		((line_length / bpp) << 22);1029	crtc->vline_crnt_vline = 0;1030 1031	crtc->h_tot_disp = h_total | (h_disp << 16);1032	crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly << 8) |1033		((h_sync_strt & 0x100) << 4) | (h_sync_wid << 16) |1034		(h_sync_pol << 21);1035	crtc->v_tot_disp = v_total | (v_disp << 16);1036	crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid << 16) |1037		(v_sync_pol << 21);1038 1039	/* crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_PRESERVED_MASK; */1040	crtc->gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | pix_width | c_sync;1041	crtc->gen_cntl |= CRTC_VGA_LINEAR;1042 1043	/* Enable doublescan mode if requested */1044	if (vmode & FB_VMODE_DOUBLE)1045		crtc->gen_cntl |= CRTC_DBL_SCAN_EN;1046	/* Enable interlaced mode if requested */1047	if (vmode & FB_VMODE_INTERLACED)1048		crtc->gen_cntl |= CRTC_INTERLACE_EN;1049#ifdef CONFIG_FB_ATY_GENERIC_LCD1050	if (par->lcd_table != 0) {1051		u32 vdisplay = yres;1052		if (vmode & FB_VMODE_DOUBLE)1053			vdisplay <<= 1;1054		crtc->gen_cntl &= ~(CRTC2_EN | CRTC2_PIX_WIDTH);1055		crtc->lcd_gen_cntl &= ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 |1056					/*TVCLK_PM_EN | VCLK_DAC_PM_EN |*/1057					USE_SHADOWED_VEND |1058					USE_SHADOWED_ROWCUR |1059					SHADOW_EN | SHADOW_RW_EN);1060		crtc->lcd_gen_cntl |= DONT_SHADOW_VPAR/* | LOCK_8DOT*/;1061 1062		/* MOBILITY M1 tested, FIXME: LT */1063		crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par);1064		if (!M64_HAS(LT_LCD_REGS))1065			crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par) &1066				~(AUTO_VERT_RATIO | VERT_STRETCH_MODE | VERT_STRETCH_RATIO3);1067 1068		crtc->horz_stretching &= ~(HORZ_STRETCH_RATIO |1069					   HORZ_STRETCH_LOOP | AUTO_HORZ_RATIO |1070					   HORZ_STRETCH_MODE | HORZ_STRETCH_EN);1071		if (xres < par->lcd_width && crtc->lcd_gen_cntl & LCD_ON) {1072			do {1073				/*1074				 * The horizontal blender misbehaves when1075				 * HDisplay is less than a certain threshold1076				 * (440 for a 1024-wide panel).  It doesn't1077				 * stretch such modes enough.  Use pixel1078				 * replication instead of blending to stretch1079				 * modes that can be made to exactly fit the1080				 * panel width.  The undocumented "NoLCDBlend"1081				 * option allows the pixel-replicated mode to1082				 * be slightly wider or narrower than the1083				 * panel width.  It also causes a mode that is1084				 * exactly half as wide as the panel to be1085				 * pixel-replicated, rather than blended.1086				 */1087				int HDisplay  = xres & ~7;1088				int nStretch  = par->lcd_width / HDisplay;1089				int Remainder = par->lcd_width % HDisplay;1090 1091				if ((!Remainder && ((nStretch > 2))) ||1092				    (((HDisplay * 16) / par->lcd_width) < 7)) {1093					static const char StretchLoops[] = { 10, 12, 13, 15, 16 };1094					int horz_stretch_loop = -1, BestRemainder;1095					int Numerator = HDisplay, Denominator = par->lcd_width;1096					int Index = 5;1097					ATIReduceRatio(&Numerator, &Denominator);1098 1099					BestRemainder = (Numerator * 16) / Denominator;1100					while (--Index >= 0) {1101						Remainder = ((Denominator - Numerator) * StretchLoops[Index]) %1102							Denominator;1103						if (Remainder < BestRemainder) {1104							horz_stretch_loop = Index;1105							if (!(BestRemainder = Remainder))1106								break;1107						}1108					}1109 1110					if ((horz_stretch_loop >= 0) && !BestRemainder) {1111						int horz_stretch_ratio = 0, Accumulator = 0;1112						int reuse_previous = 1;1113 1114						Index = StretchLoops[horz_stretch_loop];1115 1116						while (--Index >= 0) {1117							if (Accumulator > 0)1118								horz_stretch_ratio |= reuse_previous;1119							else1120								Accumulator += Denominator;1121							Accumulator -= Numerator;1122							reuse_previous <<= 1;1123						}1124 1125						crtc->horz_stretching |= (HORZ_STRETCH_EN |1126							((horz_stretch_loop & HORZ_STRETCH_LOOP) << 16) |1127							(horz_stretch_ratio & HORZ_STRETCH_RATIO));1128						break;      /* Out of the do { ... } while (0) */1129					}1130				}1131 1132				crtc->horz_stretching |= (HORZ_STRETCH_MODE | HORZ_STRETCH_EN |1133					(((HDisplay * (HORZ_STRETCH_BLEND + 1)) / par->lcd_width) & HORZ_STRETCH_BLEND));1134			} while (0);1135		}1136 1137		if (vdisplay < par->lcd_height && crtc->lcd_gen_cntl & LCD_ON) {1138			crtc->vert_stretching = (VERT_STRETCH_USE0 | VERT_STRETCH_EN |1139				(((vdisplay * (VERT_STRETCH_RATIO0 + 1)) / par->lcd_height) & VERT_STRETCH_RATIO0));1140 1141			if (!M64_HAS(LT_LCD_REGS) &&1142			    xres <= (M64_HAS(MOBIL_BUS) ? 1024 : 800))1143				crtc->ext_vert_stretch |= VERT_STRETCH_MODE;1144		} else {1145			/*1146			 * Don't use vertical blending if the mode is too wide1147			 * or not vertically stretched.1148			 */1149			crtc->vert_stretching = 0;1150		}1151		/* copy to shadow crtc */1152		crtc->shadow_h_tot_disp = crtc->h_tot_disp;1153		crtc->shadow_h_sync_strt_wid = crtc->h_sync_strt_wid;1154		crtc->shadow_v_tot_disp = crtc->v_tot_disp;1155		crtc->shadow_v_sync_strt_wid = crtc->v_sync_strt_wid;1156	}1157#endif /* CONFIG_FB_ATY_GENERIC_LCD */1158 1159	if (M64_HAS(MAGIC_FIFO)) {1160		/* FIXME: display FIFO low watermark values */1161		crtc->gen_cntl |= (aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_FIFO_LWM);1162	}1163	crtc->dp_pix_width = dp_pix_width;1164	crtc->dp_chain_mask = dp_chain_mask;1165 1166	return 0;1167}1168 1169static int aty_crtc_to_var(const struct crtc *crtc,1170			   struct fb_var_screeninfo *var)1171{1172	u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync;1173	u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;1174	u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;1175	u32 pix_width;1176	u32 double_scan, interlace;1177 1178	/* input */1179	h_total = crtc->h_tot_disp & 0x1ff;1180	h_disp = (crtc->h_tot_disp >> 16) & 0xff;1181	h_sync_strt = (crtc->h_sync_strt_wid & 0xff) | ((crtc->h_sync_strt_wid >> 4) & 0x100);1182	h_sync_dly = (crtc->h_sync_strt_wid >> 8) & 0x7;1183	h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x1f;1184	h_sync_pol = (crtc->h_sync_strt_wid >> 21) & 0x1;1185	v_total = crtc->v_tot_disp & 0x7ff;1186	v_disp = (crtc->v_tot_disp >> 16) & 0x7ff;1187	v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;1188	v_sync_wid = (crtc->v_sync_strt_wid >> 16) & 0x1f;1189	v_sync_pol = (crtc->v_sync_strt_wid >> 21) & 0x1;1190	c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0;1191	pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;1192	double_scan = crtc->gen_cntl & CRTC_DBL_SCAN_EN;1193	interlace = crtc->gen_cntl & CRTC_INTERLACE_EN;1194 1195	/* convert */1196	xres = (h_disp + 1) * 8;1197	yres = v_disp + 1;1198	left = (h_total - h_sync_strt - h_sync_wid) * 8 - h_sync_dly;1199	right = (h_sync_strt - h_disp) * 8 + h_sync_dly;1200	hslen = h_sync_wid * 8;1201	upper = v_total - v_sync_strt - v_sync_wid;1202	lower = v_sync_strt - v_disp;1203	vslen = v_sync_wid;1204	sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |1205		(v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |1206		(c_sync ? FB_SYNC_COMP_HIGH_ACT : 0);1207 1208	switch (pix_width) {1209	case CRTC_PIX_WIDTH_8BPP:1210		bpp = 8;1211		var->red.offset = 0;1212		var->red.length = 8;1213		var->green.offset = 0;1214		var->green.length = 8;1215		var->blue.offset = 0;1216		var->blue.length = 8;1217		var->transp.offset = 0;1218		var->transp.length = 0;1219		break;1220	case CRTC_PIX_WIDTH_15BPP:	/* RGB 555 */1221		bpp = 16;1222		var->red.offset = 10;1223		var->red.length = 5;1224		var->green.offset = 5;1225		var->green.length = 5;1226		var->blue.offset = 0;1227		var->blue.length = 5;1228		var->transp.offset = 0;1229		var->transp.length = 0;1230		break;1231	case CRTC_PIX_WIDTH_16BPP:	/* RGB 565 */1232		bpp = 16;1233		var->red.offset = 11;1234		var->red.length = 5;1235		var->green.offset = 5;1236		var->green.length = 6;1237		var->blue.offset = 0;1238		var->blue.length = 5;1239		var->transp.offset = 0;1240		var->transp.length = 0;1241		break;1242	case CRTC_PIX_WIDTH_24BPP:	/* RGB 888 */1243		bpp = 24;1244		var->red.offset = 16;1245		var->red.length = 8;1246		var->green.offset = 8;1247		var->green.length = 8;1248		var->blue.offset = 0;1249		var->blue.length = 8;1250		var->transp.offset = 0;1251		var->transp.length = 0;1252		break;1253	case CRTC_PIX_WIDTH_32BPP:	/* ARGB 8888 */1254		bpp = 32;1255		var->red.offset = 16;1256		var->red.length = 8;1257		var->green.offset = 8;1258		var->green.length = 8;1259		var->blue.offset = 0;1260		var->blue.length = 8;1261		var->transp.offset = 24;1262		var->transp.length = 8;1263		break;1264	default:1265		PRINTKE("Invalid pixel width\n");1266		return -EINVAL;1267	}1268 1269	/* output */1270	var->xres = xres;1271	var->yres = yres;1272	var->xres_virtual = crtc->vxres;1273	var->yres_virtual = crtc->vyres;1274	var->bits_per_pixel = bpp;1275	var->left_margin = left;1276	var->right_margin = right;1277	var->upper_margin = upper;1278	var->lower_margin = lower;1279	var->hsync_len = hslen;1280	var->vsync_len = vslen;1281	var->sync = sync;1282	var->vmode = FB_VMODE_NONINTERLACED;1283	/*1284	 * In double scan mode, the vertical parameters are doubled,1285	 * so we need to halve them to get the right values.1286	 * In interlaced mode the values are already correct,1287	 * so no correction is necessary.1288	 */1289	if (interlace)1290		var->vmode = FB_VMODE_INTERLACED;1291 1292	if (double_scan) {1293		var->vmode = FB_VMODE_DOUBLE;1294		var->yres >>= 1;1295		var->upper_margin >>= 1;1296		var->lower_margin >>= 1;1297		var->vsync_len >>= 1;1298	}1299 1300	return 0;1301}1302 1303/* ------------------------------------------------------------------------- */1304 1305static int atyfb_set_par(struct fb_info *info)1306{1307	struct atyfb_par *par = (struct atyfb_par *) info->par;1308	struct fb_var_screeninfo *var = &info->var;1309	u32 tmp, pixclock;1310	int err;1311#ifdef DEBUG1312	struct fb_var_screeninfo debug;1313	u32 pixclock_in_ps;1314#endif1315	if (par->asleep)1316		return 0;1317 1318	err = aty_var_to_crtc(info, var, &par->crtc);1319	if (err)1320		return err;1321 1322	pixclock = atyfb_get_pixclock(var, par);1323 1324	if (pixclock == 0) {1325		PRINTKE("Invalid pixclock\n");1326		return -EINVAL;1327	} else {1328		err = par->pll_ops->var_to_pll(info, pixclock,1329					       var->bits_per_pixel, &par->pll);1330		if (err)1331			return err;1332	}1333 1334	par->accel_flags = var->accel_flags; /* hack */1335 1336	if (var->accel_flags) {1337		atyfb_ops.fb_sync = atyfb_sync;1338		info->flags &= ~FBINFO_HWACCEL_DISABLED;1339	} else {1340		atyfb_ops.fb_sync = NULL;1341		info->flags |= FBINFO_HWACCEL_DISABLED;1342	}1343 1344	if (par->blitter_may_be_busy)1345		wait_for_idle(par);1346 1347	aty_set_crtc(par, &par->crtc);1348	par->dac_ops->set_dac(info, &par->pll,1349			      var->bits_per_pixel, par->accel_flags);1350	par->pll_ops->set_pll(info, &par->pll);1351 1352#ifdef DEBUG1353	if (par->pll_ops && par->pll_ops->pll_to_var)1354		pixclock_in_ps = par->pll_ops->pll_to_var(info, &par->pll);1355	else1356		pixclock_in_ps = 0;1357 1358	if (0 == pixclock_in_ps) {1359		PRINTKE("ALERT ops->pll_to_var get 0\n");1360		pixclock_in_ps = pixclock;1361	}1362 1363	memset(&debug, 0, sizeof(debug));1364	if (!aty_crtc_to_var(&par->crtc, &debug)) {1365		u32 hSync, vRefresh;1366		u32 h_disp, h_sync_strt, h_sync_end, h_total;1367		u32 v_disp, v_sync_strt, v_sync_end, v_total;1368 1369		h_disp = debug.xres;1370		h_sync_strt = h_disp + debug.right_margin;1371		h_sync_end = h_sync_strt + debug.hsync_len;1372		h_total = h_sync_end + debug.left_margin;1373		v_disp = debug.yres;1374		v_sync_strt = v_disp + debug.lower_margin;1375		v_sync_end = v_sync_strt + debug.vsync_len;1376		v_total = v_sync_end + debug.upper_margin;1377 1378		hSync = 1000000000 / (pixclock_in_ps * h_total);1379		vRefresh = (hSync * 1000) / v_total;1380		if (par->crtc.gen_cntl & CRTC_INTERLACE_EN)1381			vRefresh *= 2;1382		if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN)1383			vRefresh /= 2;1384 1385		DPRINTK("atyfb_set_par\n");1386		DPRINTK(" Set Visible Mode to %ix%i-%i\n",1387			var->xres, var->yres, var->bits_per_pixel);1388		DPRINTK(" Virtual resolution %ix%i, "1389			"pixclock_in_ps %i (calculated %i)\n",1390			var->xres_virtual, var->yres_virtual,1391			pixclock, pixclock_in_ps);1392		DPRINTK(" Dot clock:           %i MHz\n",1393			1000000 / pixclock_in_ps);1394		DPRINTK(" Horizontal sync:     %i kHz\n", hSync);1395		DPRINTK(" Vertical refresh:    %i Hz\n", vRefresh);1396		DPRINTK(" x  style: %i.%03i %i %i %i %i   %i %i %i %i\n",1397			1000000 / pixclock_in_ps, 1000000 % pixclock_in_ps,1398			h_disp, h_sync_strt, h_sync_end, h_total,1399			v_disp, v_sync_strt, v_sync_end, v_total);1400		DPRINTK(" fb style: %i  %i %i %i %i %i %i %i %i\n",1401			pixclock_in_ps,1402			debug.left_margin, h_disp, debug.right_margin, debug.hsync_len,1403			debug.upper_margin, v_disp, debug.lower_margin, debug.vsync_len);1404	}1405#endif /* DEBUG */1406 1407	if (!M64_HAS(INTEGRATED)) {1408		/* Don't forget MEM_CNTL */1409		tmp = aty_ld_le32(MEM_CNTL, par) & 0xf0ffffff;1410		switch (var->bits_per_pixel) {1411		case 8:1412			tmp |= 0x02000000;1413			break;1414		case 16:1415			tmp |= 0x03000000;1416			break;1417		case 32:1418			tmp |= 0x06000000;1419			break;1420		}1421		aty_st_le32(MEM_CNTL, tmp, par);1422	} else {1423		tmp = aty_ld_le32(MEM_CNTL, par) & 0xf00fffff;1424		if (!M64_HAS(MAGIC_POSTDIV))1425			tmp |= par->mem_refresh_rate << 20;1426		switch (var->bits_per_pixel) {1427		case 8:1428		case 24:1429			tmp |= 0x00000000;1430			break;1431		case 16:1432			tmp |= 0x04000000;1433			break;1434		case 32:1435			tmp |= 0x08000000;1436			break;1437		}1438		if (M64_HAS(CT_BUS)) {1439			aty_st_le32(DAC_CNTL, 0x87010184, par);1440			aty_st_le32(BUS_CNTL, 0x680000f9, par);1441		} else if (M64_HAS(VT_BUS)) {1442			aty_st_le32(DAC_CNTL, 0x87010184, par);1443			aty_st_le32(BUS_CNTL, 0x680000f9, par);1444		} else if (M64_HAS(MOBIL_BUS)) {1445			aty_st_le32(DAC_CNTL, 0x80010102, par);1446			aty_st_le32(BUS_CNTL, 0x7b33a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par);1447		} else {1448			/* GT */1449			aty_st_le32(DAC_CNTL, 0x86010102, par);1450			aty_st_le32(BUS_CNTL, 0x7b23a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par);1451			aty_st_le32(EXT_MEM_CNTL, aty_ld_le32(EXT_MEM_CNTL, par) | 0x5000001, par);1452		}1453		aty_st_le32(MEM_CNTL, tmp, par);1454	}1455	aty_st_8(DAC_MASK, 0xff, par);1456 1457	info->fix.line_length = calc_line_length(par, var->xres_virtual,1458						 var->bits_per_pixel);1459 1460	info->fix.visual = var->bits_per_pixel <= 8 ?1461		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;1462 1463	/* Initialize the graphics engine */1464	if (par->accel_flags & FB_ACCELF_TEXT)1465		aty_init_engine(par, info);1466 1467#ifdef CONFIG_BOOTX_TEXT1468	btext_update_display(info->fix.smem_start,1469		(((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8,1470		((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1,1471		var->bits_per_pixel,1472		par->crtc.vxres * var->bits_per_pixel / 8);1473#endif /* CONFIG_BOOTX_TEXT */1474#ifdef DEBUG1475{1476	/* dump non shadow CRTC, pll, LCD registers */1477	int i; u32 base;1478 1479	/* CRTC registers */1480	base = 0x2000;1481	printk("debug atyfb: Mach64 non-shadow register values:");1482	for (i = 0; i < 256; i = i+4) {1483		if (i % 16 == 0) {1484			pr_cont("\n");1485			printk("debug atyfb: 0x%04X: ", base + i);1486		}1487		pr_cont(" %08X", aty_ld_le32(i, par));1488	}1489	pr_cont("\n\n");1490 1491#ifdef CONFIG_FB_ATY_CT1492	/* PLL registers */1493	base = 0x00;1494	printk("debug atyfb: Mach64 PLL register values:");1495	for (i = 0; i < 64; i++) {1496		if (i % 16 == 0) {1497			pr_cont("\n");1498			printk("debug atyfb: 0x%02X: ", base + i);1499		}1500		if (i % 4 == 0)1501			pr_cont(" ");1502		pr_cont("%02X", aty_ld_pll_ct(i, par));1503	}1504	pr_cont("\n\n");1505#endif	/* CONFIG_FB_ATY_CT */1506 1507#ifdef CONFIG_FB_ATY_GENERIC_LCD1508	if (par->lcd_table != 0) {1509		/* LCD registers */1510		base = 0x00;1511		printk("debug atyfb: LCD register values:");1512		if (M64_HAS(LT_LCD_REGS)) {1513			for (i = 0; i <= POWER_MANAGEMENT; i++) {1514				if (i == EXT_VERT_STRETCH)1515					continue;1516				pr_cont("\ndebug atyfb: 0x%04X: ",1517				       lt_lcd_regs[i]);1518				pr_cont(" %08X", aty_ld_lcd(i, par));1519			}1520		} else {1521			for (i = 0; i < 64; i++) {1522				if (i % 4 == 0)1523					pr_cont("\ndebug atyfb: 0x%02X: ",1524					       base + i);1525				pr_cont(" %08X", aty_ld_lcd(i, par));1526			}1527		}1528		pr_cont("\n\n");1529	}1530#endif /* CONFIG_FB_ATY_GENERIC_LCD */1531}1532#endif /* DEBUG */1533	return 0;1534}1535 1536static int atyfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)1537{1538	struct atyfb_par *par = (struct atyfb_par *) info->par;1539	int err;1540	struct crtc crtc;1541	union aty_pll pll;1542	u32 pixclock;1543 1544	memcpy(&pll, &par->pll, sizeof(pll));1545 1546	err = aty_var_to_crtc(info, var, &crtc);1547	if (err)1548		return err;1549 1550	pixclock = atyfb_get_pixclock(var, par);1551 1552	if (pixclock == 0) {1553		if (!(var->activate & FB_ACTIVATE_TEST))1554			PRINTKE("Invalid pixclock\n");1555		return -EINVAL;1556	} else {1557		err = par->pll_ops->var_to_pll(info, pixclock,1558					       var->bits_per_pixel, &pll);1559		if (err)1560			return err;1561	}1562 1563	if (var->accel_flags & FB_ACCELF_TEXT)1564		info->var.accel_flags = FB_ACCELF_TEXT;1565	else1566		info->var.accel_flags = 0;1567 1568	aty_crtc_to_var(&crtc, var);1569	var->pixclock = par->pll_ops->pll_to_var(info, &pll);1570	return 0;1571}1572 1573static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info)1574{1575	u32 xoffset = info->var.xoffset;1576	u32 yoffset = info->var.yoffset;1577	u32 line_length = info->fix.line_length;1578	u32 bpp = info->var.bits_per_pixel;1579 1580	par->crtc.off_pitch =1581		((yoffset * line_length + xoffset * bpp / 8) / 8) |1582		((line_length / bpp) << 22);1583}1584 1585 1586/*1587 * Open/Release the frame buffer device1588 */1589 1590static int atyfb_open(struct fb_info *info, int user)1591{1592	struct atyfb_par *par = (struct atyfb_par *) info->par;1593 1594	if (user) {1595		par->open++;1596#ifdef __sparc__1597		par->mmaped = 0;1598#endif1599	}1600	return 0;1601}1602 1603static irqreturn_t aty_irq(int irq, void *dev_id)1604{1605	struct atyfb_par *par = dev_id;1606	int handled = 0;1607	u32 int_cntl;1608 1609	spin_lock(&par->int_lock);1610 1611	int_cntl = aty_ld_le32(CRTC_INT_CNTL, par);1612 1613	if (int_cntl & CRTC_VBLANK_INT) {1614		/* clear interrupt */1615		aty_st_le32(CRTC_INT_CNTL, (int_cntl & CRTC_INT_EN_MASK) |1616			    CRTC_VBLANK_INT_AK, par);1617		par->vblank.count++;1618		if (par->vblank.pan_display) {1619			par->vblank.pan_display = 0;1620			aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);1621		}1622		wake_up_interruptible(&par->vblank.wait);1623		handled = 1;1624	}1625 1626	spin_unlock(&par->int_lock);1627 1628	return IRQ_RETVAL(handled);1629}1630 1631static int aty_enable_irq(struct atyfb_par *par, int reenable)1632{1633	u32 int_cntl;1634 1635	if (!test_and_set_bit(0, &par->irq_flags)) {1636		if (request_irq(par->irq, aty_irq, IRQF_SHARED, "atyfb", par)) {1637			clear_bit(0, &par->irq_flags);1638			return -EINVAL;1639		}1640		spin_lock_irq(&par->int_lock);1641		int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;1642		/* clear interrupt */1643		aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_AK, par);1644		/* enable interrupt */1645		aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_EN, par);1646		spin_unlock_irq(&par->int_lock);1647	} else if (reenable) {1648		spin_lock_irq(&par->int_lock);1649		int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;1650		if (!(int_cntl & CRTC_VBLANK_INT_EN)) {1651			printk("atyfb: someone disabled IRQ [%08x]\n",1652			       int_cntl);1653			/* re-enable interrupt */1654			aty_st_le32(CRTC_INT_CNTL, int_cntl |1655				    CRTC_VBLANK_INT_EN, par);1656		}1657		spin_unlock_irq(&par->int_lock);1658	}1659 1660	return 0;1661}1662 1663static int aty_disable_irq(struct atyfb_par *par)1664{1665	u32 int_cntl;1666 1667	if (test_and_clear_bit(0, &par->irq_flags)) {1668		if (par->vblank.pan_display) {1669			par->vblank.pan_display = 0;1670			aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);1671		}1672		spin_lock_irq(&par->int_lock);1673		int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;1674		/* disable interrupt */1675		aty_st_le32(CRTC_INT_CNTL, int_cntl & ~CRTC_VBLANK_INT_EN, par);1676		spin_unlock_irq(&par->int_lock);1677		free_irq(par->irq, par);1678	}1679 1680	return 0;1681}1682 1683static int atyfb_release(struct fb_info *info, int user)1684{1685	struct atyfb_par *par = (struct atyfb_par *) info->par;1686#ifdef __sparc__1687	int was_mmaped;1688#endif1689 1690	if (!user)1691		return 0;1692 1693	par->open--;1694	mdelay(1);1695	wait_for_idle(par);1696 1697	if (par->open)1698		return 0;1699 1700#ifdef __sparc__1701	was_mmaped = par->mmaped;1702 1703	par->mmaped = 0;1704 1705	if (was_mmaped) {1706		struct fb_var_screeninfo var;1707 1708		/*1709		 * Now reset the default display config, we have1710		 * no idea what the program(s) which mmap'd the1711		 * chip did to the configuration, nor whether it1712		 * restored it correctly.1713		 */1714		var = default_var;1715		if (noaccel)1716			var.accel_flags &= ~FB_ACCELF_TEXT;1717		else1718			var.accel_flags |= FB_ACCELF_TEXT;1719		if (var.yres == var.yres_virtual) {1720			u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2));1721			var.yres_virtual =1722				((videoram * 8) / var.bits_per_pixel) /1723				var.xres_virtual;1724			if (var.yres_virtual < var.yres)1725				var.yres_virtual = var.yres;1726		}1727	}1728#endif1729	aty_disable_irq(par);1730 1731	return 0;1732}1733 1734/*1735 * Pan or Wrap the Display1736 *1737 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag1738 */1739 1740static int atyfb_pan_display(struct fb_var_screeninfo *var,1741			     struct fb_info *info)1742{1743	struct atyfb_par *par = (struct atyfb_par *) info->par;1744	u32 xres, yres, xoffset, yoffset;1745 1746	xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8;1747	yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1;1748	if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN)1749		yres >>= 1;1750	xoffset = (var->xoffset + 7) & ~7;1751	yoffset = var->yoffset;1752	if (xoffset + xres > par->crtc.vxres ||1753	    yoffset + yres > par->crtc.vyres)1754		return -EINVAL;1755	info->var.xoffset = xoffset;1756	info->var.yoffset = yoffset;1757	if (par->asleep)1758		return 0;1759 1760	set_off_pitch(par, info);1761	if ((var->activate & FB_ACTIVATE_VBL) && !aty_enable_irq(par, 0)) {1762		par->vblank.pan_display = 1;1763	} else {1764		par->vblank.pan_display = 0;1765		aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);1766	}1767 1768	return 0;1769}1770 1771static int aty_waitforvblank(struct atyfb_par *par, u32 crtc)1772{1773	struct aty_interrupt *vbl;1774	unsigned int count;1775	int ret;1776 1777	switch (crtc) {1778	case 0:1779		vbl = &par->vblank;1780		break;1781	default:1782		return -ENODEV;1783	}1784 1785	ret = aty_enable_irq(par, 0);1786	if (ret)1787		return ret;1788 1789	count = vbl->count;1790	ret = wait_event_interruptible_timeout(vbl->wait,1791					       count != vbl->count, HZ/10);1792	if (ret < 0)1793		return ret;1794	if (ret == 0) {1795		aty_enable_irq(par, 1);1796		return -ETIMEDOUT;1797	}1798 1799	return 0;1800}1801 1802 1803#ifdef DEBUG1804#define ATYIO_CLKR		0x41545900	/* ATY\00 */1805#define ATYIO_CLKW		0x41545901	/* ATY\01 */1806 1807struct atyclk {1808	u32 ref_clk_per;1809	u8 pll_ref_div;1810	u8 mclk_fb_div;1811	u8 mclk_post_div;	/* 1,2,3,4,8 */1812	u8 mclk_fb_mult;	/* 2 or 4 */1813	u8 xclk_post_div;	/* 1,2,3,4,8 */1814	u8 vclk_fb_div;1815	u8 vclk_post_div;	/* 1,2,3,4,6,8,12 */1816	u32 dsp_xclks_per_row;	/* 0-16383 */1817	u32 dsp_loop_latency;	/* 0-15 */1818	u32 dsp_precision;	/* 0-7 */1819	u32 dsp_on;		/* 0-2047 */1820	u32 dsp_off;		/* 0-2047 */1821};1822 1823#define ATYIO_FEATR		0x41545902	/* ATY\02 */1824#define ATYIO_FEATW		0x41545903	/* ATY\03 */1825#endif1826 1827static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)1828{1829	struct atyfb_par *par = (struct atyfb_par *) info->par;1830#ifdef __sparc__1831	struct fbtype fbtyp;1832#endif1833 1834	switch (cmd) {1835#ifdef __sparc__1836	case FBIOGTYPE:1837		fbtyp.fb_type = FBTYPE_PCI_GENERIC;1838		fbtyp.fb_width = par->crtc.vxres;1839		fbtyp.fb_height = par->crtc.vyres;1840		fbtyp.fb_depth = info->var.bits_per_pixel;1841		fbtyp.fb_cmsize = info->cmap.len;1842		fbtyp.fb_size = info->fix.smem_len;1843		if (copy_to_user((struct fbtype __user *) arg, &fbtyp,1844				 sizeof(fbtyp)))1845			return -EFAULT;1846		break;1847#endif /* __sparc__ */1848 1849	case FBIO_WAITFORVSYNC:1850		{1851			u32 crtc;1852 1853			if (get_user(crtc, (__u32 __user *) arg))1854				return -EFAULT;1855 1856			return aty_waitforvblank(par, crtc);1857		}1858 1859#if defined(DEBUG) && defined(CONFIG_FB_ATY_CT)1860	case ATYIO_CLKR:1861		if (M64_HAS(INTEGRATED)) {1862			struct atyclk clk = { 0 };1863			union aty_pll *pll = &par->pll;1864			u32 dsp_config = pll->ct.dsp_config;1865			u32 dsp_on_off = pll->ct.dsp_on_off;1866			clk.ref_clk_per = par->ref_clk_per;1867			clk.pll_ref_div = pll->ct.pll_ref_div;1868			clk.mclk_fb_div = pll->ct.mclk_fb_div;1869			clk.mclk_post_div = pll->ct.mclk_post_div_real;1870			clk.mclk_fb_mult = pll->ct.mclk_fb_mult;1871			clk.xclk_post_div = pll->ct.xclk_post_div_real;1872			clk.vclk_fb_div = pll->ct.vclk_fb_div;1873			clk.vclk_post_div = pll->ct.vclk_post_div_real;1874			clk.dsp_xclks_per_row = dsp_config & 0x3fff;1875			clk.dsp_loop_latency = (dsp_config >> 16) & 0xf;1876			clk.dsp_precision = (dsp_config >> 20) & 7;1877			clk.dsp_off = dsp_on_off & 0x7ff;1878			clk.dsp_on = (dsp_on_off >> 16) & 0x7ff;1879			if (copy_to_user((struct atyclk __user *) arg, &clk,1880					 sizeof(clk)))1881				return -EFAULT;1882		} else1883			return -EINVAL;1884		break;1885	case ATYIO_CLKW:1886		if (M64_HAS(INTEGRATED)) {1887			struct atyclk clk;1888			union aty_pll *pll = &par->pll;1889			if (copy_from_user(&clk, (struct atyclk __user *) arg,1890					   sizeof(clk)))1891				return -EFAULT;1892			par->ref_clk_per = clk.ref_clk_per;1893			pll->ct.pll_ref_div = clk.pll_ref_div;1894			pll->ct.mclk_fb_div = clk.mclk_fb_div;1895			pll->ct.mclk_post_div_real = clk.mclk_post_div;1896			pll->ct.mclk_fb_mult = clk.mclk_fb_mult;1897			pll->ct.xclk_post_div_real = clk.xclk_post_div;1898			pll->ct.vclk_fb_div = clk.vclk_fb_div;1899			pll->ct.vclk_post_div_real = clk.vclk_post_div;1900			pll->ct.dsp_config = (clk.dsp_xclks_per_row & 0x3fff) |1901				((clk.dsp_loop_latency & 0xf) << 16) |1902				((clk.dsp_precision & 7) << 20);1903			pll->ct.dsp_on_off = (clk.dsp_off & 0x7ff) |1904				((clk.dsp_on & 0x7ff) << 16);1905			/*aty_calc_pll_ct(info, &pll->ct);*/1906			aty_set_pll_ct(info, pll);1907		} else1908			return -EINVAL;1909		break;1910	case ATYIO_FEATR:1911		if (get_user(par->features, (u32 __user *) arg))1912			return -EFAULT;1913		break;1914	case ATYIO_FEATW:1915		if (put_user(par->features, (u32 __user *) arg))1916			return -EFAULT;1917		break;1918#endif /* DEBUG && CONFIG_FB_ATY_CT */1919	default:1920		return -EINVAL;1921	}1922	return 0;1923}1924 1925static int atyfb_sync(struct fb_info *info)1926{1927	struct atyfb_par *par = (struct atyfb_par *) info->par;1928 1929	if (par->blitter_may_be_busy)1930		wait_for_idle(par);1931	return 0;1932}1933 1934#ifdef __sparc__1935static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma)1936{1937	struct atyfb_par *par = (struct atyfb_par *) info->par;1938	unsigned int size, page, map_size = 0;1939	unsigned long map_offset = 0;1940	unsigned long off;1941	int i;1942 1943	if (!par->mmap_map)1944		return -ENXIO;1945 1946	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))1947		return -EINVAL;1948 1949	off = vma->vm_pgoff << PAGE_SHIFT;1950	size = vma->vm_end - vma->vm_start;1951 1952	/* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */1953 1954	if (((vma->vm_pgoff == 0) && (size == info->fix.smem_len)) ||1955	    ((off == info->fix.smem_len) && (size == PAGE_SIZE)))1956		off += 0x8000000000000000UL;1957 1958	vma->vm_pgoff = off >> PAGE_SHIFT;	/* propagate off changes */1959 1960	/* Each page, see which map applies */1961	for (page = 0; page < size;) {1962		map_size = 0;1963		for (i = 0; par->mmap_map[i].size; i++) {1964			unsigned long start = par->mmap_map[i].voff;1965			unsigned long end = start + par->mmap_map[i].size;1966			unsigned long offset = off + page;1967 1968			if (start > offset)1969				continue;1970			if (offset >= end)1971				continue;1972 1973			map_size = par->mmap_map[i].size - (offset - start);1974			map_offset = par->mmap_map[i].poff + (offset - start);1975			break;1976		}1977		if (!map_size) {1978			page += PAGE_SIZE;1979			continue;1980		}1981		if (page + map_size > size)1982			map_size = size - page;1983 1984		pgprot_val(vma->vm_page_prot) &= ~(par->mmap_map[i].prot_mask);1985		pgprot_val(vma->vm_page_prot) |= par->mmap_map[i].prot_flag;1986 1987		if (remap_pfn_range(vma, vma->vm_start + page,1988			map_offset >> PAGE_SHIFT, map_size, vma->vm_page_prot))1989			return -EAGAIN;1990 1991		page += map_size;1992	}1993 1994	if (!map_size)1995		return -EINVAL;1996 1997	if (!par->mmaped)1998		par->mmaped = 1;1999	return 0;2000}2001#endif /* __sparc__ */2002 2003 2004 2005#if defined(CONFIG_PCI)2006 2007#ifdef CONFIG_PPC_PMAC2008/* Power management routines. Those are used for PowerBook sleep.2009 */2010static int aty_power_mgmt(int sleep, struct atyfb_par *par)2011{2012	u32 pm;2013	int timeout;2014 2015	pm = aty_ld_lcd(POWER_MANAGEMENT, par);2016	pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;2017	aty_st_lcd(POWER_MANAGEMENT, pm, par);2018	pm = aty_ld_lcd(POWER_MANAGEMENT, par);2019 2020	timeout = 2000;2021	if (sleep) {2022		/* Sleep */2023		pm &= ~PWR_MGT_ON;2024		aty_st_lcd(POWER_MANAGEMENT, pm, par);2025		pm = aty_ld_lcd(POWER_MANAGEMENT, par);2026		udelay(10);2027		pm &= ~(PWR_BLON | AUTO_PWR_UP);2028		pm |= SUSPEND_NOW;2029		aty_st_lcd(POWER_MANAGEMENT, pm, par);2030		pm = aty_ld_lcd(POWER_MANAGEMENT, par);2031		udelay(10);2032		pm |= PWR_MGT_ON;2033		aty_st_lcd(POWER_MANAGEMENT, pm, par);2034		do {2035			pm = aty_ld_lcd(POWER_MANAGEMENT, par);2036			mdelay(1);2037			if ((--timeout) == 0)2038				break;2039		} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);2040	} else {2041		/* Wakeup */2042		pm &= ~PWR_MGT_ON;2043		aty_st_lcd(POWER_MANAGEMENT, pm, par);2044		pm = aty_ld_lcd(POWER_MANAGEMENT, par);2045		udelay(10);2046		pm &= ~SUSPEND_NOW;2047		pm |= (PWR_BLON | AUTO_PWR_UP);2048		aty_st_lcd(POWER_MANAGEMENT, pm, par);2049		pm = aty_ld_lcd(POWER_MANAGEMENT, par);2050		udelay(10);2051		pm |= PWR_MGT_ON;2052		aty_st_lcd(POWER_MANAGEMENT, pm, par);2053		do {2054			pm = aty_ld_lcd(POWER_MANAGEMENT, par);2055			mdelay(1);2056			if ((--timeout) == 0)2057				break;2058		} while ((pm & PWR_MGT_STATUS_MASK) != 0);2059	}2060	mdelay(500);2061 2062	return timeout ? 0 : -EIO;2063}2064#endif /* CONFIG_PPC_PMAC */2065 2066static int atyfb_pci_suspend_late(struct device *dev, pm_message_t state)2067{2068	struct pci_dev *pdev = to_pci_dev(dev);2069	struct fb_info *info = pci_get_drvdata(pdev);2070	struct atyfb_par *par = (struct atyfb_par *) info->par;2071 2072	if (state.event == pdev->dev.power.power_state.event)2073		return 0;2074 2075	console_lock();2076 2077	fb_set_suspend(info, 1);2078 2079	/* Idle & reset engine */2080	wait_for_idle(par);2081	aty_reset_engine(par);2082 2083	/* Blank display and LCD */2084	atyfb_blank(FB_BLANK_POWERDOWN, info);2085 2086	par->asleep = 1;2087	par->lock_blank = 1;2088 2089	/*2090	 * Because we may change PCI D state ourselves, we need to2091	 * first save the config space content so the core can2092	 * restore it properly on resume.2093	 */2094 2095#ifdef CONFIG_PPC_PMAC2096	/* Set chip to "suspend" mode */2097	if (machine_is(powermac) && aty_power_mgmt(1, par)) {2098		par->asleep = 0;2099		par->lock_blank = 0;2100		atyfb_blank(FB_BLANK_UNBLANK, info);2101		fb_set_suspend(info, 0);2102		console_unlock();2103		return -EIO;2104	}2105#endif2106 2107	console_unlock();2108 2109	pdev->dev.power.power_state = state;2110 2111	return 0;2112}2113 2114static int __maybe_unused atyfb_pci_suspend(struct device *dev)2115{2116	return atyfb_pci_suspend_late(dev, PMSG_SUSPEND);2117}2118 2119static int __maybe_unused atyfb_pci_hibernate(struct device *dev)2120{2121	return atyfb_pci_suspend_late(dev, PMSG_HIBERNATE);2122}2123 2124static int __maybe_unused atyfb_pci_freeze(struct device *dev)2125{2126	return atyfb_pci_suspend_late(dev, PMSG_FREEZE);2127}2128 2129static void aty_resume_chip(struct fb_info *info)2130{2131	struct atyfb_par *par = info->par;2132 2133	aty_st_le32(MEM_CNTL, par->mem_cntl, par);2134 2135	if (par->pll_ops->resume_pll)2136		par->pll_ops->resume_pll(info, &par->pll);2137 2138	if (par->aux_start)2139		aty_st_le32(BUS_CNTL,2140			aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par);2141}2142 2143static int __maybe_unused atyfb_pci_resume(struct device *dev)2144{2145	struct pci_dev *pdev = to_pci_dev(dev);2146	struct fb_info *info = pci_get_drvdata(pdev);2147	struct atyfb_par *par = (struct atyfb_par *) info->par;2148 2149	if (pdev->dev.power.power_state.event == PM_EVENT_ON)2150		return 0;2151 2152	console_lock();2153 2154	/*2155	 * PCI state will have been restored by the core, so2156	 * we should be in D0 now with our config space fully2157	 * restored2158	 */2159 2160#ifdef CONFIG_PPC_PMAC2161	if (machine_is(powermac) &&2162	    pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)2163		aty_power_mgmt(0, par);2164#endif2165 2166	aty_resume_chip(info);2167 2168	par->asleep = 0;2169 2170	/* Restore display */2171	atyfb_set_par(info);2172 2173	/* Refresh */2174	fb_set_suspend(info, 0);2175 2176	/* Unblank */2177	par->lock_blank = 0;2178	atyfb_blank(FB_BLANK_UNBLANK, info);2179 2180	console_unlock();2181 2182	pdev->dev.power.power_state = PMSG_ON;2183 2184	return 0;2185}2186 2187static const struct dev_pm_ops atyfb_pci_pm_ops = {2188#ifdef CONFIG_PM_SLEEP2189	.suspend	= atyfb_pci_suspend,2190	.resume		= atyfb_pci_resume,2191	.freeze		= atyfb_pci_freeze,2192	.thaw		= atyfb_pci_resume,2193	.poweroff	= atyfb_pci_hibernate,2194	.restore	= atyfb_pci_resume,2195#endif /* CONFIG_PM_SLEEP */2196};2197 2198#endif /*  defined(CONFIG_PCI) */2199 2200/* Backlight */2201#ifdef CONFIG_FB_ATY_BACKLIGHT2202#define MAX_LEVEL 0xFF2203 2204static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)2205{2206	struct fb_info *info = pci_get_drvdata(par->pdev);2207	int atylevel;2208 2209	/* Get and convert the value */2210	/* No locking of bl_curve since we read a single value */2211	atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;2212 2213	if (atylevel < 0)2214		atylevel = 0;2215	else if (atylevel > MAX_LEVEL)2216		atylevel = MAX_LEVEL;2217 2218	return atylevel;2219}2220 2221static int aty_bl_update_status(struct backlight_device *bd)2222{2223	struct atyfb_par *par = bl_get_data(bd);2224	unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);2225	int level = backlight_get_brightness(bd);2226 2227	reg |= (BLMOD_EN | BIASMOD_EN);2228	if (level > 0) {2229		reg &= ~BIAS_MOD_LEVEL_MASK;2230		reg |= (aty_bl_get_level_brightness(par, level) << BIAS_MOD_LEVEL_SHIFT);2231	} else {2232		reg &= ~BIAS_MOD_LEVEL_MASK;2233		reg |= (aty_bl_get_level_brightness(par, 0) << BIAS_MOD_LEVEL_SHIFT);2234	}2235	aty_st_lcd(LCD_MISC_CNTL, reg, par);2236 2237	return 0;2238}2239 2240static const struct backlight_ops aty_bl_data = {2241	.update_status	= aty_bl_update_status,2242};2243 2244static void aty_bl_init(struct atyfb_par *par)2245{2246	struct backlight_properties props;2247	struct fb_info *info = pci_get_drvdata(par->pdev);2248	struct backlight_device *bd;2249	char name[12];2250 2251#ifdef CONFIG_PMAC_BACKLIGHT2252	if (!pmac_has_backlight_type("ati"))2253		return;2254#endif2255 2256	snprintf(name, sizeof(name), "atybl%d", info->node);2257 2258	memset(&props, 0, sizeof(struct backlight_properties));2259	props.type = BACKLIGHT_RAW;2260	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;2261	bd = backlight_device_register(name, info->device, par, &aty_bl_data,2262				       &props);2263	if (IS_ERR(bd)) {2264		info->bl_dev = NULL;2265		printk(KERN_WARNING "aty: Backlight registration failed\n");2266		goto error;2267	}2268 2269	info->bl_dev = bd;2270	fb_bl_default_curve(info, 0,2271			    0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL,2272			    0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL);2273 2274	bd->props.brightness = bd->props.max_brightness;2275	bd->props.power = FB_BLANK_UNBLANK;2276	backlight_update_status(bd);2277 2278	printk("aty: Backlight initialized (%s)\n", name);2279 2280	return;2281 2282error:2283	return;2284}2285 2286#ifdef CONFIG_PCI2287static void aty_bl_exit(struct backlight_device *bd)2288{2289	backlight_device_unregister(bd);2290	printk("aty: Backlight unloaded\n");2291}2292#endif /* CONFIG_PCI */2293 2294#endif /* CONFIG_FB_ATY_BACKLIGHT */2295 2296static void aty_calc_mem_refresh(struct atyfb_par *par, int xclk)2297{2298	static const int ragepro_tbl[] = {2299		44, 50, 55, 66, 75, 80, 1002300	};2301	static const int ragexl_tbl[] = {2302		50, 66, 75, 83, 90, 95, 100, 105,2303		110, 115, 120, 125, 133, 143, 1662304	};2305	const int *refresh_tbl;2306	int i, size;2307 2308	if (M64_HAS(XL_MEM)) {2309		refresh_tbl = ragexl_tbl;2310		size = ARRAY_SIZE(ragexl_tbl);2311	} else {2312		refresh_tbl = ragepro_tbl;2313		size = ARRAY_SIZE(ragepro_tbl);2314	}2315 2316	for (i = 0; i < size; i++) {2317		if (xclk < refresh_tbl[i])2318			break;2319	}2320	par->mem_refresh_rate = i;2321}2322 2323/*2324 * Initialisation2325 */2326 2327static struct fb_info *fb_list = NULL;2328 2329#if defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD)2330static int atyfb_get_timings_from_lcd(struct atyfb_par *par,2331				      struct fb_var_screeninfo *var)2332{2333	int ret = -EINVAL;2334 2335	if (par->lcd_table != 0 && (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {2336		*var = default_var;2337		var->xres = var->xres_virtual = par->lcd_hdisp;2338		var->right_margin = par->lcd_right_margin;2339		var->left_margin = par->lcd_hblank_len -2340			(par->lcd_right_margin + par->lcd_hsync_dly +2341			 par->lcd_hsync_len);2342		var->hsync_len = par->lcd_hsync_len + par->lcd_hsync_dly;2343		var->yres = var->yres_virtual = par->lcd_vdisp;2344		var->lower_margin = par->lcd_lower_margin;2345		var->upper_margin = par->lcd_vblank_len -2346			(par->lcd_lower_margin + par->lcd_vsync_len);2347		var->vsync_len = par->lcd_vsync_len;2348		var->pixclock = par->lcd_pixclock;2349		ret = 0;2350	}2351 2352	return ret;2353}2354#endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */2355 2356static int aty_init(struct fb_info *info)2357{2358	struct atyfb_par *par = (struct atyfb_par *) info->par;2359	const char *ramname = NULL, *xtal;2360	int gtb_memsize, has_var = 0;2361	struct fb_var_screeninfo var;2362	int ret;2363#ifdef CONFIG_ATARI2364	u8 dac_type;2365#endif2366 2367	init_waitqueue_head(&par->vblank.wait);2368	spin_lock_init(&par->int_lock);2369 2370#ifdef CONFIG_FB_ATY_GX2371	if (!M64_HAS(INTEGRATED)) {2372		u32 stat0;2373		u8 dac_subtype, clk_type;2374		stat0 = aty_ld_le32(CNFG_STAT0, par);2375		par->bus_type = (stat0 >> 0) & 0x07;2376		par->ram_type = (stat0 >> 3) & 0x07;2377		ramname = aty_gx_ram[par->ram_type];2378		/* FIXME: clockchip/RAMDAC probing? */2379#ifdef CONFIG_ATARI2380		clk_type = CLK_ATI18818_1;2381		dac_type = (stat0 >> 9) & 0x07;2382		if (dac_type == 0x07)2383			dac_subtype = DAC_ATT20C408;2384		else2385			dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, par) & 0xF0) | dac_type;2386#else2387		dac_subtype = DAC_IBMRGB514;2388		clk_type = CLK_IBMRGB514;2389#endif2390		switch (dac_subtype) {2391		case DAC_IBMRGB514:2392			par->dac_ops = &aty_dac_ibm514;2393			break;2394#ifdef CONFIG_ATARI2395		case DAC_ATI68860_B:2396		case DAC_ATI68860_C:2397			par->dac_ops = &aty_dac_ati68860b;2398			break;2399		case DAC_ATT20C408:2400		case DAC_ATT21C498:2401			par->dac_ops = &aty_dac_att21c498;2402			break;2403#endif2404		default:2405			PRINTKI("aty_init: DAC type not implemented yet!\n");2406			par->dac_ops = &aty_dac_unsupported;2407			break;2408		}2409		switch (clk_type) {2410#ifdef CONFIG_ATARI2411		case CLK_ATI18818_1:2412			par->pll_ops = &aty_pll_ati18818_1;2413			break;2414#else2415		case CLK_IBMRGB514:2416			par->pll_ops = &aty_pll_ibm514;2417			break;2418#endif2419		default:2420			PRINTKI("aty_init: CLK type not implemented yet!");2421			par->pll_ops = &aty_pll_unsupported;2422			break;2423		}2424	}2425#endif /* CONFIG_FB_ATY_GX */2426#ifdef CONFIG_FB_ATY_CT2427	if (M64_HAS(INTEGRATED)) {2428		par->dac_ops = &aty_dac_ct;2429		par->pll_ops = &aty_pll_ct;2430		par->bus_type = PCI;2431		par->ram_type = (aty_ld_le32(CNFG_STAT0, par) & 0x07);2432		if (M64_HAS(XL_MEM))2433			ramname = aty_xl_ram[par->ram_type];2434		else2435			ramname = aty_ct_ram[par->ram_type];2436		/* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */2437		if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM)2438			par->pll_limits.mclk = 63;2439		/* Mobility + 32bit memory interface need halved XCLK. */2440		if (M64_HAS(MOBIL_BUS) && par->ram_type == SDRAM32)2441			par->pll_limits.xclk = (par->pll_limits.xclk + 1) >> 1;2442	}2443#endif2444#ifdef CONFIG_PPC_PMAC2445	/*2446	 * The Apple iBook1 uses non-standard memory frequencies.2447	 * We detect it and set the frequency manually.2448	 */2449	if (of_machine_is_compatible("PowerBook2,1")) {2450		par->pll_limits.mclk = 70;2451		par->pll_limits.xclk = 53;2452	}2453#endif2454 2455	/* Allow command line to override clocks. */2456	if (pll)2457		par->pll_limits.pll_max = pll;2458	if (mclk)2459		par->pll_limits.mclk = mclk;2460	if (xclk)2461		par->pll_limits.xclk = xclk;2462 2463	aty_calc_mem_refresh(par, par->pll_limits.xclk);2464	par->pll_per = 1000000/par->pll_limits.pll_max;2465	par->mclk_per = 1000000/par->pll_limits.mclk;2466	par->xclk_per = 1000000/par->pll_limits.xclk;2467 2468	par->ref_clk_per = 1000000000000ULL / 14318180;2469	xtal = "14.31818";2470 2471#ifdef CONFIG_FB_ATY_CT2472	if (M64_HAS(GTB_DSP)) {2473		u8 pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);2474 2475		if (pll_ref_div) {2476			int diff1, diff2;2477			diff1 = 510 * 14 / pll_ref_div - par->pll_limits.pll_max;2478			diff2 = 510 * 29 / pll_ref_div - par->pll_limits.pll_max;2479			if (diff1 < 0)2480				diff1 = -diff1;2481			if (diff2 < 0)2482				diff2 = -diff2;2483			if (diff2 < diff1) {2484				par->ref_clk_per = 1000000000000ULL / 29498928;2485				xtal = "29.498928";2486			}2487		}2488	}2489#endif /* CONFIG_FB_ATY_CT */2490 2491	/* save previous video mode */2492	aty_get_crtc(par, &par->saved_crtc);2493	if (par->pll_ops->get_pll)2494		par->pll_ops->get_pll(info, &par->saved_pll);2495 2496	par->mem_cntl = aty_ld_le32(MEM_CNTL, par);2497	gtb_memsize = M64_HAS(GTB_DSP);2498	if (gtb_memsize)2499		/* 0xF used instead of MEM_SIZE_ALIAS */2500		switch (par->mem_cntl & 0xF) {2501		case MEM_SIZE_512K:2502			info->fix.smem_len = 0x80000;2503			break;2504		case MEM_SIZE_1M:2505			info->fix.smem_len = 0x100000;2506			break;2507		case MEM_SIZE_2M_GTB:2508			info->fix.smem_len = 0x200000;2509			break;2510		case MEM_SIZE_4M_GTB:2511			info->fix.smem_len = 0x400000;2512			break;2513		case MEM_SIZE_6M_GTB:2514			info->fix.smem_len = 0x600000;2515			break;2516		case MEM_SIZE_8M_GTB:2517			info->fix.smem_len = 0x800000;2518			break;2519		default:2520			info->fix.smem_len = 0x80000;2521	} else2522		switch (par->mem_cntl & MEM_SIZE_ALIAS) {2523		case MEM_SIZE_512K:2524			info->fix.smem_len = 0x80000;2525			break;2526		case MEM_SIZE_1M:2527			info->fix.smem_len = 0x100000;2528			break;2529		case MEM_SIZE_2M:2530			info->fix.smem_len = 0x200000;2531			break;2532		case MEM_SIZE_4M:2533			info->fix.smem_len = 0x400000;2534			break;2535		case MEM_SIZE_6M:2536			info->fix.smem_len = 0x600000;2537			break;2538		case MEM_SIZE_8M:2539			info->fix.smem_len = 0x800000;2540			break;2541		default:2542			info->fix.smem_len = 0x80000;2543		}2544 2545	if (M64_HAS(MAGIC_VRAM_SIZE)) {2546		if (aty_ld_le32(CNFG_STAT1, par) & 0x40000000)2547			info->fix.smem_len += 0x400000;2548	}2549 2550	if (vram) {2551		info->fix.smem_len = vram * 1024;2552		par->mem_cntl &= ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);2553		if (info->fix.smem_len <= 0x80000)2554			par->mem_cntl |= MEM_SIZE_512K;2555		else if (info->fix.smem_len <= 0x100000)2556			par->mem_cntl |= MEM_SIZE_1M;2557		else if (info->fix.smem_len <= 0x200000)2558			par->mem_cntl |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;2559		else if (info->fix.smem_len <= 0x400000)2560			par->mem_cntl |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;2561		else if (info->fix.smem_len <= 0x600000)2562			par->mem_cntl |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;2563		else2564			par->mem_cntl |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;2565		aty_st_le32(MEM_CNTL, par->mem_cntl, par);2566	}2567 2568	/*2569	 * Reg Block 0 (CT-compatible block) is at mmio_start2570	 * Reg Block 1 (multimedia extensions) is at mmio_start - 0x4002571	 */2572	if (M64_HAS(GX)) {2573		info->fix.mmio_len = 0x400;2574		info->fix.accel = FB_ACCEL_ATI_MACH64GX;2575	} else if (M64_HAS(CT)) {2576		info->fix.mmio_len = 0x400;2577		info->fix.accel = FB_ACCEL_ATI_MACH64CT;2578	} else if (M64_HAS(VT)) {2579		info->fix.mmio_start -= 0x400;2580		info->fix.mmio_len = 0x800;2581		info->fix.accel = FB_ACCEL_ATI_MACH64VT;2582	} else {/* GT */2583		info->fix.mmio_start -= 0x400;2584		info->fix.mmio_len = 0x800;2585		info->fix.accel = FB_ACCEL_ATI_MACH64GT;2586	}2587 2588	PRINTKI("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK, %d MHz XCLK\n",2589		info->fix.smem_len == 0x80000 ? 512 : (info->fix.smem_len>>20),2590		info->fix.smem_len == 0x80000 ? 'K' : 'M', ramname, xtal,2591		par->pll_limits.pll_max, par->pll_limits.mclk,2592		par->pll_limits.xclk);2593 2594#if defined(DEBUG) && defined(CONFIG_FB_ATY_CT)2595	if (M64_HAS(INTEGRATED)) {2596		int i;2597		printk("debug atyfb: BUS_CNTL DAC_CNTL MEM_CNTL "2598		       "EXT_MEM_CNTL CRTC_GEN_CNTL DSP_CONFIG "2599		       "DSP_ON_OFF CLOCK_CNTL\n"2600		       "debug atyfb: %08x %08x %08x "2601		       "%08x     %08x      %08x   "2602		       "%08x   %08x\n"2603		       "debug atyfb: PLL",2604		       aty_ld_le32(BUS_CNTL, par),2605		       aty_ld_le32(DAC_CNTL, par),2606		       aty_ld_le32(MEM_CNTL, par),2607		       aty_ld_le32(EXT_MEM_CNTL, par),2608		       aty_ld_le32(CRTC_GEN_CNTL, par),2609		       aty_ld_le32(DSP_CONFIG, par),2610		       aty_ld_le32(DSP_ON_OFF, par),2611		       aty_ld_le32(CLOCK_CNTL, par));2612		for (i = 0; i < 40; i++)2613			pr_cont(" %02x", aty_ld_pll_ct(i, par));2614		pr_cont("\n");2615	}2616#endif2617	if (par->pll_ops->init_pll)2618		par->pll_ops->init_pll(info, &par->pll);2619	if (par->pll_ops->resume_pll)2620		par->pll_ops->resume_pll(info, &par->pll);2621 2622	aty_fudge_framebuffer_len(info);2623 2624	/*2625	 * Disable register access through the linear aperture2626	 * if the auxiliary aperture is used so we can access2627	 * the full 8 MB of video RAM on 8 MB boards.2628	 */2629	if (par->aux_start)2630		aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) |2631			    BUS_APER_REG_DIS, par);2632 2633	if (!nomtrr)2634		/*2635		 * Only the ioremap_wc()'d area will get WC here2636		 * since ioremap_uc() was used on the entire PCI BAR.2637		 */2638		par->wc_cookie = arch_phys_wc_add(par->res_start,2639						  par->res_size);2640 2641	info->fbops = &atyfb_ops;2642	info->pseudo_palette = par->pseudo_palette;2643	info->flags = FBINFO_HWACCEL_IMAGEBLIT |2644		      FBINFO_HWACCEL_FILLRECT  |2645		      FBINFO_HWACCEL_COPYAREA  |2646		      FBINFO_HWACCEL_YPAN      |2647		      FBINFO_READS_FAST;2648 2649#ifdef CONFIG_PMAC_BACKLIGHT2650	if (M64_HAS(G3_PB_1_1) && of_machine_is_compatible("PowerBook1,1")) {2651		/*2652		 * these bits let the 101 powerbook2653		 * wake up from sleep -- paulus2654		 */2655		aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par) |2656			   USE_F32KHZ | TRISTATE_MEM_EN, par);2657	} else2658#endif2659 2660	memset(&var, 0, sizeof(var));2661#ifdef CONFIG_PPC2662	if (machine_is(powermac)) {2663		/*2664		 * FIXME: The NVRAM stuff should be put in a Mac-specific file,2665		 *        as it applies to all Mac video cards2666		 */2667		if (mode) {2668			if (mac_find_mode(&var, info, mode, 8))2669				has_var = 1;2670		} else {2671			if (default_vmode == VMODE_CHOOSE) {2672				int sense;2673				if (M64_HAS(G3_PB_1024x768))2674					/* G3 PowerBook with 1024x768 LCD */2675					default_vmode = VMODE_1024_768_60;2676				else if (of_machine_is_compatible("iMac"))2677					default_vmode = VMODE_1024_768_75;2678				else if (of_machine_is_compatible("PowerBook2,1"))2679					/* iBook with 800x600 LCD */2680					default_vmode = VMODE_800_600_60;2681				else2682					default_vmode = VMODE_640_480_67;2683				sense = read_aty_sense(par);2684				PRINTKI("monitor sense=%x, mode %d\n",2685					sense,  mac_map_monitor_sense(sense));2686			}2687			if (default_vmode <= 0 || default_vmode > VMODE_MAX)2688				default_vmode = VMODE_640_480_60;2689			if (default_cmode < CMODE_8 || default_cmode > CMODE_32)2690				default_cmode = CMODE_8;2691			if (!mac_vmode_to_var(default_vmode, default_cmode,2692					      &var))2693				has_var = 1;2694		}2695	}2696 2697#endif /* !CONFIG_PPC */2698 2699#if defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD)2700	if (!atyfb_get_timings_from_lcd(par, &var))2701		has_var = 1;2702#endif2703 2704	if (mode && fb_find_mode(&var, info, mode, NULL, 0, &defmode, 8))2705		has_var = 1;2706 2707	if (!has_var)2708		var = default_var;2709 2710	if (noaccel)2711		var.accel_flags &= ~FB_ACCELF_TEXT;2712	else2713		var.accel_flags |= FB_ACCELF_TEXT;2714 2715	if (comp_sync != -1) {2716		if (!comp_sync)2717			var.sync &= ~FB_SYNC_COMP_HIGH_ACT;2718		else2719			var.sync |= FB_SYNC_COMP_HIGH_ACT;2720	}2721 2722	if (var.yres == var.yres_virtual) {2723		u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2));2724		var.yres_virtual = ((videoram * 8) / var.bits_per_pixel) / var.xres_virtual;2725		if (var.yres_virtual < var.yres)2726			var.yres_virtual = var.yres;2727	}2728 2729	ret = atyfb_check_var(&var, info);2730	if (ret) {2731		PRINTKE("can't set default video mode\n");2732		goto aty_init_exit;2733	}2734 2735#ifdef CONFIG_FB_ATY_CT2736	if (!noaccel && M64_HAS(INTEGRATED))2737		aty_init_cursor(info, &atyfb_ops);2738#endif /* CONFIG_FB_ATY_CT */2739	info->var = var;2740 2741	ret = fb_alloc_cmap(&info->cmap, 256, 0);2742	if (ret < 0)2743		goto aty_init_exit;2744 2745	ret = register_framebuffer(info);2746	if (ret < 0) {2747		fb_dealloc_cmap(&info->cmap);2748		goto aty_init_exit;2749	}2750 2751	if (M64_HAS(MOBIL_BUS) && backlight) {2752#ifdef CONFIG_FB_ATY_BACKLIGHT2753		aty_bl_init(par);2754#endif2755	}2756 2757	fb_list = info;2758 2759	PRINTKI("fb%d: %s frame buffer device on %s\n",2760		info->node, info->fix.id, par->bus_type == ISA ? "ISA" : "PCI");2761	return 0;2762 2763aty_init_exit:2764	/* restore video mode */2765	aty_set_crtc(par, &par->saved_crtc);2766	par->pll_ops->set_pll(info, &par->saved_pll);2767	arch_phys_wc_del(par->wc_cookie);2768 2769	return ret;2770}2771 2772#if defined(CONFIG_ATARI) && !defined(MODULE)2773static int store_video_par(char *video_str, unsigned char m64_num)2774{2775	char *p;2776	unsigned long vmembase, size, guiregbase;2777 2778	PRINTKI("store_video_par() '%s' \n", video_str);2779 2780	if (!(p = strsep(&video_str, ";")) || !*p)2781		goto mach64_invalid;2782	vmembase = simple_strtoul(p, NULL, 0);2783	if (!(p = strsep(&video_str, ";")) || !*p)2784		goto mach64_invalid;2785	size = simple_strtoul(p, NULL, 0);2786	if (!(p = strsep(&video_str, ";")) || !*p)2787		goto mach64_invalid;2788	guiregbase = simple_strtoul(p, NULL, 0);2789 2790	phys_vmembase[m64_num] = vmembase;2791	phys_size[m64_num] = size;2792	phys_guiregbase[m64_num] = guiregbase;2793	PRINTKI("stored them all: $%08lX $%08lX $%08lX \n", vmembase, size,2794		guiregbase);2795	return 0;2796 2797 mach64_invalid:2798	phys_vmembase[m64_num] = 0;2799	return -1;2800}2801#endif /* CONFIG_ATARI && !MODULE */2802 2803/*2804 * Blank the display.2805 */2806 2807static int atyfb_blank(int blank, struct fb_info *info)2808{2809	struct atyfb_par *par = (struct atyfb_par *) info->par;2810	u32 gen_cntl;2811 2812	if (par->lock_blank || par->asleep)2813		return 0;2814 2815#ifdef CONFIG_FB_ATY_GENERIC_LCD2816	if (par->lcd_table && blank > FB_BLANK_NORMAL &&2817	    (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {2818		u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);2819		pm &= ~PWR_BLON;2820		aty_st_lcd(POWER_MANAGEMENT, pm, par);2821	}2822#endif2823 2824	gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);2825	gen_cntl &= ~0x400004c;2826	switch (blank) {2827	case FB_BLANK_UNBLANK:2828		break;2829	case FB_BLANK_NORMAL:2830		gen_cntl |= 0x4000040;2831		break;2832	case FB_BLANK_VSYNC_SUSPEND:2833		gen_cntl |= 0x4000048;2834		break;2835	case FB_BLANK_HSYNC_SUSPEND:2836		gen_cntl |= 0x4000044;2837		break;2838	case FB_BLANK_POWERDOWN:2839		gen_cntl |= 0x400004c;2840		break;2841	}2842	aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);2843 2844#ifdef CONFIG_FB_ATY_GENERIC_LCD2845	if (par->lcd_table && blank <= FB_BLANK_NORMAL &&2846	    (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {2847		u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);2848		pm |= PWR_BLON;2849		aty_st_lcd(POWER_MANAGEMENT, pm, par);2850	}2851#endif2852 2853	return 0;2854}2855 2856static void aty_st_pal(u_int regno, u_int red, u_int green, u_int blue,2857		       const struct atyfb_par *par)2858{2859	aty_st_8(DAC_W_INDEX, regno, par);2860	aty_st_8(DAC_DATA, red, par);2861	aty_st_8(DAC_DATA, green, par);2862	aty_st_8(DAC_DATA, blue, par);2863}2864 2865/*2866 * Set a single color register. The values supplied are already2867 * rounded down to the hardware's capabilities (according to the2868 * entries in the var structure). Return != 0 for invalid regno.2869 * !! 4 & 8 =  PSEUDO, > 8 = DIRECTCOLOR2870 */2871 2872static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,2873			   u_int transp, struct fb_info *info)2874{2875	struct atyfb_par *par = (struct atyfb_par *) info->par;2876	int i, depth;2877	u32 *pal = info->pseudo_palette;2878 2879	depth = info->var.bits_per_pixel;2880	if (depth == 16)2881		depth = (info->var.green.length == 5) ? 15 : 16;2882 2883	if (par->asleep)2884		return 0;2885 2886	if (regno > 255 ||2887	    (depth == 16 && regno > 63) ||2888	    (depth == 15 && regno > 31))2889		return 1;2890 2891	red >>= 8;2892	green >>= 8;2893	blue >>= 8;2894 2895	par->palette[regno].red = red;2896	par->palette[regno].green = green;2897	par->palette[regno].blue = blue;2898 2899	if (regno < 16) {2900		switch (depth) {2901		case 15:2902			pal[regno] = (regno << 10) | (regno << 5) | regno;2903			break;2904		case 16:2905			pal[regno] = (regno << 11) | (regno << 5) | regno;2906			break;2907		case 24:2908			pal[regno] = (regno << 16) | (regno << 8) | regno;2909			break;2910		case 32:2911			i = (regno << 8) | regno;2912			pal[regno] = (i << 16) | i;2913			break;2914		}2915	}2916 2917	i = aty_ld_8(DAC_CNTL, par) & 0xfc;2918	if (M64_HAS(EXTRA_BRIGHT))2919		i |= 0x2; /* DAC_CNTL | 0x2 turns off the extra brightness for gt */2920	aty_st_8(DAC_CNTL, i, par);2921	aty_st_8(DAC_MASK, 0xff, par);2922 2923	if (M64_HAS(INTEGRATED)) {2924		if (depth == 16) {2925			if (regno < 32)2926				aty_st_pal(regno << 3, red,2927					   par->palette[regno << 1].green,2928					   blue, par);2929			red = par->palette[regno >> 1].red;2930			blue = par->palette[regno >> 1].blue;2931			regno <<= 2;2932		} else if (depth == 15) {2933			regno <<= 3;2934			for (i = 0; i < 8; i++)2935				aty_st_pal(regno + i, red, green, blue, par);2936		}2937	}2938	aty_st_pal(regno, red, green, blue, par);2939 2940	return 0;2941}2942 2943#ifdef CONFIG_PCI2944 2945#ifdef __sparc__2946 2947static int atyfb_setup_sparc(struct pci_dev *pdev, struct fb_info *info,2948			     unsigned long addr)2949{2950	struct atyfb_par *par = info->par;2951	struct device_node *dp;2952	u32 mem, chip_id;2953	int i, j, ret;2954 2955	/*2956	 * Map memory-mapped registers.2957	 */2958	par->ati_regbase = (void *)addr + 0x7ffc00UL;2959	info->fix.mmio_start = addr + 0x7ffc00UL;2960 2961	/*2962	 * Map in big-endian aperture.2963	 */2964	info->screen_base = (char *) (addr + 0x800000UL);2965	info->fix.smem_start = addr + 0x800000UL;2966 2967	/*2968	 * Figure mmap addresses from PCI config space.2969	 * Split Framebuffer in big- and little-endian halfs.2970	 */2971	for (i = 0; i < 6 && pdev->resource[i].start; i++)2972		/* nothing */ ;2973	j = i + 4;2974 2975	par->mmap_map = kcalloc(j, sizeof(*par->mmap_map), GFP_ATOMIC);2976	if (!par->mmap_map) {2977		PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n");2978		return -ENOMEM;2979	}2980 2981	for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {2982		struct resource *rp = &pdev->resource[i];2983		int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);2984		unsigned long base;2985		u32 size, pbase;2986 2987		base = rp->start;2988 2989		io = (rp->flags & IORESOURCE_IO);2990 2991		size = rp->end - base + 1;2992 2993		pci_read_config_dword(pdev, breg, &pbase);2994 2995		if (io)2996			size &= ~1;2997 2998		/*2999		 * Map the framebuffer a second time, this time without3000		 * the braindead _PAGE_IE setting. This is used by the3001		 * fixed Xserver, but we need to maintain the old mapping3002		 * to stay compatible with older ones...3003		 */3004		if (base == addr) {3005			par->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK;3006			par->mmap_map[j].poff = base & PAGE_MASK;3007			par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;3008			par->mmap_map[j].prot_mask = _PAGE_CACHE;3009			par->mmap_map[j].prot_flag = _PAGE_E;3010			j++;3011		}3012 3013		/*3014		 * Here comes the old framebuffer mapping with _PAGE_IE3015		 * set for the big endian half of the framebuffer...3016		 */3017		if (base == addr) {3018			par->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK;3019			par->mmap_map[j].poff = (base + 0x800000) & PAGE_MASK;3020			par->mmap_map[j].size = 0x800000;3021			par->mmap_map[j].prot_mask = _PAGE_CACHE;3022			par->mmap_map[j].prot_flag = _PAGE_E | _PAGE_IE;3023			size -= 0x800000;3024			j++;3025		}3026 3027		par->mmap_map[j].voff = pbase & PAGE_MASK;3028		par->mmap_map[j].poff = base & PAGE_MASK;3029		par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;3030		par->mmap_map[j].prot_mask = _PAGE_CACHE;3031		par->mmap_map[j].prot_flag = _PAGE_E;3032		j++;3033	}3034 3035	ret = correct_chipset(par);3036	if (ret)3037		return ret;3038 3039	if (IS_XL(pdev->device)) {3040		/*3041		 * Fix PROMs idea of MEM_CNTL settings...3042		 */3043		mem = aty_ld_le32(MEM_CNTL, par);3044		chip_id = aty_ld_le32(CNFG_CHIP_ID, par);3045		if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && !((chip_id >> 24) & 1)) {3046			switch (mem & 0x0f) {3047			case 3:3048				mem = (mem & ~(0x0f)) | 2;3049				break;3050			case 7:3051				mem = (mem & ~(0x0f)) | 3;3052				break;3053			case 9:3054				mem = (mem & ~(0x0f)) | 4;3055				break;3056			case 11:3057				mem = (mem & ~(0x0f)) | 5;3058				break;3059			default:3060				break;3061			}3062			if ((aty_ld_le32(CNFG_STAT0, par) & 7) >= SDRAM)3063				mem &= ~(0x00700000);3064		}3065		mem &= ~(0xcf80e000);	/* Turn off all undocumented bits. */3066		aty_st_le32(MEM_CNTL, mem, par);3067	}3068 3069	dp = pci_device_to_OF_node(pdev);3070	if (dp == of_console_device) {3071		struct fb_var_screeninfo *var = &default_var;3072		unsigned int N, P, Q, M, T, R;3073		struct crtc crtc;3074		u8 pll_regs[16];3075		u8 clock_cntl;3076 3077		crtc.vxres = of_getintprop_default(dp, "width", 1024);3078		crtc.vyres = of_getintprop_default(dp, "height", 768);3079		var->bits_per_pixel = of_getintprop_default(dp, "depth", 8);3080		var->xoffset = var->yoffset = 0;3081		crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);3082		crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);3083		crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);3084		crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);3085		crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);3086		aty_crtc_to_var(&crtc, var);3087 3088		/*3089		 * Read the PLL to figure actual Refresh Rate.3090		 */3091		clock_cntl = aty_ld_8(CLOCK_CNTL, par);3092		/* DPRINTK("CLOCK_CNTL %02x\n", clock_cntl); */3093		for (i = 0; i < 16; i++)3094			pll_regs[i] = aty_ld_pll_ct(i, par);3095 3096		/*3097		 * PLL Reference Divider M:3098		 */3099		M = pll_regs[PLL_REF_DIV];3100 3101		/*3102		 * PLL Feedback Divider N (Dependent on CLOCK_CNTL):3103		 */3104		N = pll_regs[VCLK0_FB_DIV + (clock_cntl & 3)];3105 3106		/*3107		 * PLL Post Divider P (Dependent on CLOCK_CNTL):3108		 */3109		P = aty_postdividers[((pll_regs[VCLK_POST_DIV] >> ((clock_cntl & 3) << 1)) & 3) |3110		                     ((pll_regs[PLL_EXT_CNTL] >> (2 + (clock_cntl & 3))) & 4)];3111 3112		/*3113		 * PLL Divider Q:3114		 */3115		Q = N / P;3116 3117		/*3118		 * Target Frequency:3119		 *3120		 *      T * M3121		 * Q = -------3122		 *      2 * R3123		 *3124		 * where R is XTALIN (= 14318 or 29498 kHz).3125		 */3126		if (IS_XL(pdev->device))3127			R = 29498;3128		else3129			R = 14318;3130 3131		T = 2 * Q * R / M;3132 3133		default_var.pixclock = 1000000000 / T;3134	}3135 3136	return 0;3137}3138 3139#else /* __sparc__ */3140 3141#ifdef __i386__3142#ifdef CONFIG_FB_ATY_GENERIC_LCD3143static void aty_init_lcd(struct atyfb_par *par, u32 bios_base)3144{3145	u32 driv_inf_tab, sig;3146	u16 lcd_ofs;3147 3148	/*3149	 * To support an LCD panel, we should know it's dimensions and3150	 *  it's desired pixel clock.3151	 * There are two ways to do it:3152	 *  - Check the startup video mode and calculate the panel3153	 *    size from it. This is unreliable.3154	 *  - Read it from the driver information table in the video BIOS.3155	 */3156	/* Address of driver information table is at offset 0x78. */3157	driv_inf_tab = bios_base + *((u16 *)(bios_base+0x78));3158 3159	/* Check for the driver information table signature. */3160	sig = *(u32 *)driv_inf_tab;3161	if ((sig == 0x54504c24) || /* Rage LT pro */3162	    (sig == 0x544d5224) || /* Rage mobility */3163	    (sig == 0x54435824) || /* Rage XC */3164	    (sig == 0x544c5824)) { /* Rage XL */3165		PRINTKI("BIOS contains driver information table.\n");3166		lcd_ofs = *(u16 *)(driv_inf_tab + 10);3167		par->lcd_table = 0;3168		if (lcd_ofs != 0)3169			par->lcd_table = bios_base + lcd_ofs;3170	}3171 3172	if (par->lcd_table != 0) {3173		char model[24];3174		char strbuf[16];3175		char refresh_rates_buf[100];3176		int id, tech, f, i, m, default_refresh_rate;3177		char *txtcolour;3178		char *txtmonitor;3179		char *txtdual;3180		char *txtformat;3181		u16 width, height, panel_type, refresh_rates;3182		u16 *lcdmodeptr;3183		u32 format;3184		u8 lcd_refresh_rates[16] = { 50, 56, 60, 67, 70, 72, 75, 76, 85,3185					     90, 100, 120, 140, 150, 160, 200 };3186		/*3187		 * The most important information is the panel size at3188		 * offset 25 and 27, but there's some other nice information3189		 * which we print to the screen.3190		 */3191		id = *(u8 *)par->lcd_table;3192		strscpy(model, (char *)par->lcd_table+1, sizeof(model));3193 3194		width = par->lcd_width = *(u16 *)(par->lcd_table+25);3195		height = par->lcd_height = *(u16 *)(par->lcd_table+27);3196		panel_type = *(u16 *)(par->lcd_table+29);3197		if (panel_type & 1)3198			txtcolour = "colour";3199		else3200			txtcolour = "monochrome";3201		if (panel_type & 2)3202			txtdual = "dual (split) ";3203		else3204			txtdual = "";3205		tech = (panel_type >> 2) & 63;3206		switch (tech) {3207		case 0:3208			txtmonitor = "passive matrix";3209			break;3210		case 1:3211			txtmonitor = "active matrix";3212			break;3213		case 2:3214			txtmonitor = "active addressed STN";3215			break;3216		case 3:3217			txtmonitor = "EL";3218			break;3219		case 4:3220			txtmonitor = "plasma";3221			break;3222		default:3223			txtmonitor = "unknown";3224		}3225		format = *(u32 *)(par->lcd_table+57);3226		if (tech == 0 || tech == 2) {3227			switch (format & 7) {3228			case 0:3229				txtformat = "12 bit interface";3230				break;3231			case 1:3232				txtformat = "16 bit interface";3233				break;3234			case 2:3235				txtformat = "24 bit interface";3236				break;3237			default:3238				txtformat = "unknown format";3239			}3240		} else {3241			switch (format & 7) {3242			case 0:3243				txtformat = "8 colours";3244				break;3245			case 1:3246				txtformat = "512 colours";3247				break;3248			case 2:3249				txtformat = "4096 colours";3250				break;3251			case 4:3252				txtformat = "262144 colours (LT mode)";3253				break;3254			case 5:3255				txtformat = "16777216 colours";3256				break;3257			case 6:3258				txtformat = "262144 colours (FDPI-2 mode)";3259				break;3260			default:3261				txtformat = "unknown format";3262			}3263		}3264		PRINTKI("%s%s %s monitor detected: %s\n",3265			txtdual, txtcolour, txtmonitor, model);3266		PRINTKI("       id=%d, %dx%d pixels, %s\n",3267			id, width, height, txtformat);3268		refresh_rates_buf[0] = 0;3269		refresh_rates = *(u16 *)(par->lcd_table+62);3270		m = 1;3271		f = 0;3272		for (i = 0; i < 16; i++) {3273			if (refresh_rates & m) {3274				if (f == 0) {3275					sprintf(strbuf, "%d",3276						lcd_refresh_rates[i]);3277					f++;3278				} else {3279					sprintf(strbuf, ",%d",3280						lcd_refresh_rates[i]);3281				}3282				strcat(refresh_rates_buf, strbuf);3283			}3284			m = m << 1;3285		}3286		default_refresh_rate = (*(u8 *)(par->lcd_table+61) & 0xf0) >> 4;3287		PRINTKI("       supports refresh rates [%s], default %d Hz\n",3288			refresh_rates_buf, lcd_refresh_rates[default_refresh_rate]);3289		par->lcd_refreshrate = lcd_refresh_rates[default_refresh_rate];3290		/*3291		 * We now need to determine the crtc parameters for the3292		 * LCD monitor. This is tricky, because they are not stored3293		 * individually in the BIOS. Instead, the BIOS contains a3294		 * table of display modes that work for this monitor.3295		 *3296		 * The idea is that we search for a mode of the same dimensions3297		 * as the dimensions of the LCD monitor. Say our LCD monitor3298		 * is 800x600 pixels, we search for a 800x600 monitor.3299		 * The CRTC parameters we find here are the ones that we need3300		 * to use to simulate other resolutions on the LCD screen.3301		 */3302		lcdmodeptr = (u16 *)(par->lcd_table + 64);3303		while (*lcdmodeptr != 0) {3304			u32 modeptr;3305			u16 mwidth, mheight, lcd_hsync_start, lcd_vsync_start;3306			modeptr = bios_base + *lcdmodeptr;3307 3308			mwidth = *((u16 *)(modeptr+0));3309			mheight = *((u16 *)(modeptr+2));3310 3311			if (mwidth == width && mheight == height) {3312				par->lcd_pixclock = 100000000 / *((u16 *)(modeptr+9));3313				par->lcd_htotal = *((u16 *)(modeptr+17)) & 511;3314				par->lcd_hdisp = *((u16 *)(modeptr+19)) & 511;3315				lcd_hsync_start = *((u16 *)(modeptr+21)) & 511;3316				par->lcd_hsync_dly = (*((u16 *)(modeptr+21)) >> 9) & 7;3317				par->lcd_hsync_len = *((u8 *)(modeptr+23)) & 63;3318 3319				par->lcd_vtotal = *((u16 *)(modeptr+24)) & 2047;3320				par->lcd_vdisp = *((u16 *)(modeptr+26)) & 2047;3321				lcd_vsync_start = *((u16 *)(modeptr+28)) & 2047;3322				par->lcd_vsync_len = (*((u16 *)(modeptr+28)) >> 11) & 31;3323 3324				par->lcd_htotal = (par->lcd_htotal + 1) * 8;3325				par->lcd_hdisp = (par->lcd_hdisp + 1) * 8;3326				lcd_hsync_start = (lcd_hsync_start + 1) * 8;3327				par->lcd_hsync_len = par->lcd_hsync_len * 8;3328 3329				par->lcd_vtotal++;3330				par->lcd_vdisp++;3331				lcd_vsync_start++;3332 3333				par->lcd_right_margin = lcd_hsync_start - par->lcd_hdisp;3334				par->lcd_lower_margin = lcd_vsync_start - par->lcd_vdisp;3335				par->lcd_hblank_len = par->lcd_htotal - par->lcd_hdisp;3336				par->lcd_vblank_len = par->lcd_vtotal - par->lcd_vdisp;3337				break;3338			}3339 3340			lcdmodeptr++;3341		}3342		if (*lcdmodeptr == 0) {3343			PRINTKE("LCD monitor CRTC parameters not found!!!\n");3344			/* To do: Switch to CRT if possible. */3345		} else {3346			PRINTKI("       LCD CRTC parameters: %d.%d  %d %d %d %d  %d %d %d %d\n",3347				1000000 / par->lcd_pixclock, 1000000 % par->lcd_pixclock,3348				par->lcd_hdisp,3349				par->lcd_hdisp + par->lcd_right_margin,3350				par->lcd_hdisp + par->lcd_right_margin3351					+ par->lcd_hsync_dly + par->lcd_hsync_len,3352				par->lcd_htotal,3353				par->lcd_vdisp,3354				par->lcd_vdisp + par->lcd_lower_margin,3355				par->lcd_vdisp + par->lcd_lower_margin + par->lcd_vsync_len,3356				par->lcd_vtotal);3357			PRINTKI("                          : %d %d %d %d %d %d %d %d %d\n",3358				par->lcd_pixclock,3359				par->lcd_hblank_len - (par->lcd_right_margin +3360					par->lcd_hsync_dly + par->lcd_hsync_len),3361				par->lcd_hdisp,3362				par->lcd_right_margin,3363				par->lcd_hsync_len,3364				par->lcd_vblank_len - (par->lcd_lower_margin + par->lcd_vsync_len),3365				par->lcd_vdisp,3366				par->lcd_lower_margin,3367				par->lcd_vsync_len);3368		}3369	}3370}3371#endif /* CONFIG_FB_ATY_GENERIC_LCD */3372 3373static int init_from_bios(struct atyfb_par *par)3374{3375	u32 bios_base, rom_addr;3376	int ret;3377 3378	rom_addr = 0xc0000 + ((aty_ld_le32(SCRATCH_REG1, par) & 0x7f) << 11);3379	bios_base = (unsigned long)ioremap(rom_addr, 0x10000);3380 3381	/* The BIOS starts with 0xaa55. */3382	if (*((u16 *)bios_base) == 0xaa55) {3383 3384		u8 *bios_ptr;3385		u16 rom_table_offset, freq_table_offset;3386		PLL_BLOCK_MACH64 pll_block;3387 3388		PRINTKI("Mach64 BIOS is located at %x, mapped at %x.\n", rom_addr, bios_base);3389 3390		/* check for frequncy table */3391		bios_ptr = (u8*)bios_base;3392		rom_table_offset = (u16)(bios_ptr[0x48] | (bios_ptr[0x49] << 8));3393		freq_table_offset = bios_ptr[rom_table_offset + 16] | (bios_ptr[rom_table_offset + 17] << 8);3394		memcpy(&pll_block, bios_ptr + freq_table_offset, sizeof(PLL_BLOCK_MACH64));3395 3396		PRINTKI("BIOS frequency table:\n");3397		PRINTKI("PCLK_min_freq %d, PCLK_max_freq %d, ref_freq %d, ref_divider %d\n",3398			pll_block.PCLK_min_freq, pll_block.PCLK_max_freq,3399			pll_block.ref_freq, pll_block.ref_divider);3400		PRINTKI("MCLK_pwd %d, MCLK_max_freq %d, XCLK_max_freq %d, SCLK_freq %d\n",3401			pll_block.MCLK_pwd, pll_block.MCLK_max_freq,3402			pll_block.XCLK_max_freq, pll_block.SCLK_freq);3403 3404		par->pll_limits.pll_min = pll_block.PCLK_min_freq/100;3405		par->pll_limits.pll_max = pll_block.PCLK_max_freq/100;3406		par->pll_limits.ref_clk = pll_block.ref_freq/100;3407		par->pll_limits.ref_div = pll_block.ref_divider;3408		par->pll_limits.sclk = pll_block.SCLK_freq/100;3409		par->pll_limits.mclk = pll_block.MCLK_max_freq/100;3410		par->pll_limits.mclk_pm = pll_block.MCLK_pwd/100;3411		par->pll_limits.xclk = pll_block.XCLK_max_freq/100;3412#ifdef CONFIG_FB_ATY_GENERIC_LCD3413		aty_init_lcd(par, bios_base);3414#endif3415		ret = 0;3416	} else {3417		PRINTKE("no BIOS frequency table found, use parameters\n");3418		ret = -ENXIO;3419	}3420	iounmap((void __iomem *)bios_base);3421 3422	return ret;3423}3424#endif /* __i386__ */3425 3426static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info,3427			       unsigned long addr)3428{3429	struct atyfb_par *par = info->par;3430	u16 tmp;3431	unsigned long raddr;3432	struct resource *rrp;3433	int ret = 0;3434 3435	raddr = addr + 0x7ff000UL;3436	rrp = &pdev->resource[2];3437	if ((rrp->flags & IORESOURCE_MEM) &&3438	    request_mem_region(rrp->start, resource_size(rrp), "atyfb")) {3439		par->aux_start = rrp->start;3440		par->aux_size = resource_size(rrp);3441		raddr = rrp->start;3442		PRINTKI("using auxiliary register aperture\n");3443	}3444 3445	info->fix.mmio_start = raddr;3446#if defined(__i386__) || defined(__ia64__)3447	/*3448	 * By using strong UC we force the MTRR to never have an3449	 * effect on the MMIO region on both non-PAT and PAT systems.3450	 */3451	par->ati_regbase = ioremap_uc(info->fix.mmio_start, 0x1000);3452#else3453	par->ati_regbase = ioremap(info->fix.mmio_start, 0x1000);3454#endif3455	if (par->ati_regbase == NULL)3456		return -ENOMEM;3457 3458	info->fix.mmio_start += par->aux_start ? 0x400 : 0xc00;3459	par->ati_regbase += par->aux_start ? 0x400 : 0xc00;3460 3461	/*3462	 * Enable memory-space accesses using config-space3463	 * command register.3464	 */3465	pci_read_config_word(pdev, PCI_COMMAND, &tmp);3466	if (!(tmp & PCI_COMMAND_MEMORY)) {3467		tmp |= PCI_COMMAND_MEMORY;3468		pci_write_config_word(pdev, PCI_COMMAND, tmp);3469	}3470#ifdef __BIG_ENDIAN3471	/* Use the big-endian aperture */3472	addr += 0x800000;3473#endif3474 3475	/* Map in frame buffer */3476	info->fix.smem_start = addr;3477 3478	/*3479	 * The framebuffer is not always 8 MiB, that's just the size of the3480	 * PCI BAR. We temporarily abuse smem_len here to store the size3481	 * of the BAR. aty_init() will later correct it to match the actual3482	 * framebuffer size.3483	 *3484	 * On devices that don't have the auxiliary register aperture, the3485	 * registers are housed at the top end of the framebuffer PCI BAR.3486	 * aty_fudge_framebuffer_len() is used to reduce smem_len to not3487	 * overlap with the registers.3488	 */3489	info->fix.smem_len = 0x800000;3490 3491	aty_fudge_framebuffer_len(info);3492 3493	info->screen_base = ioremap_wc(info->fix.smem_start,3494				       info->fix.smem_len);3495	if (info->screen_base == NULL) {3496		ret = -ENOMEM;3497		goto atyfb_setup_generic_fail;3498	}3499 3500	ret = correct_chipset(par);3501	if (ret)3502		goto atyfb_setup_generic_fail;3503#ifdef __i386__3504	ret = init_from_bios(par);3505	if (ret)3506		goto atyfb_setup_generic_fail;3507#endif3508	/* according to ATI, we should use clock 3 for acelerated mode */3509	par->clk_wr_offset = 3;3510 3511	return 0;3512 3513atyfb_setup_generic_fail:3514	iounmap(par->ati_regbase);3515	par->ati_regbase = NULL;3516	if (info->screen_base) {3517		iounmap(info->screen_base);3518		info->screen_base = NULL;3519	}3520	return ret;3521}3522 3523#endif /* !__sparc__ */3524 3525static int atyfb_pci_probe(struct pci_dev *pdev,3526			   const struct pci_device_id *ent)3527{3528	unsigned long addr, res_start, res_size;3529	struct fb_info *info;3530	struct resource *rp;3531	struct atyfb_par *par;3532	int rc;3533 3534	rc = aperture_remove_conflicting_pci_devices(pdev, "atyfb");3535	if (rc)3536		return rc;3537 3538	/* Enable device in PCI config */3539	if (pci_enable_device(pdev)) {3540		PRINTKE("Cannot enable PCI device\n");3541		return -ENXIO;3542	}3543 3544	/* Find which resource to use */3545	rp = &pdev->resource[0];3546	if (rp->flags & IORESOURCE_IO)3547		rp = &pdev->resource[1];3548	addr = rp->start;3549	if (!addr)3550		return -ENXIO;3551 3552	/* Reserve space */3553	res_start = rp->start;3554	res_size = resource_size(rp);3555	if (!request_mem_region(res_start, res_size, "atyfb"))3556		return -EBUSY;3557 3558	/* Allocate framebuffer */3559	info = framebuffer_alloc(sizeof(struct atyfb_par), &pdev->dev);3560	if (!info)3561		return -ENOMEM;3562 3563	par = info->par;3564	par->bus_type = PCI;3565	info->fix = atyfb_fix;3566	info->device = &pdev->dev;3567	par->pci_id = pdev->device;3568	par->res_start = res_start;3569	par->res_size = res_size;3570	par->irq = pdev->irq;3571	par->pdev = pdev;3572 3573	/* Setup "info" structure */3574#ifdef __sparc__3575	rc = atyfb_setup_sparc(pdev, info, addr);3576#else3577	rc = atyfb_setup_generic(pdev, info, addr);3578#endif3579	if (rc)3580		goto err_release_mem;3581 3582	pci_set_drvdata(pdev, info);3583 3584	/* Init chip & register framebuffer */3585	rc = aty_init(info);3586	if (rc)3587		goto err_release_io;3588 3589#ifdef __sparc__3590	/*3591	 * Add /dev/fb mmap values.3592	 */3593	par->mmap_map[0].voff = 0x8000000000000000UL;3594	par->mmap_map[0].poff = (unsigned long) info->screen_base & PAGE_MASK;3595	par->mmap_map[0].size = info->fix.smem_len;3596	par->mmap_map[0].prot_mask = _PAGE_CACHE;3597	par->mmap_map[0].prot_flag = _PAGE_E;3598	par->mmap_map[1].voff = par->mmap_map[0].voff + info->fix.smem_len;3599	par->mmap_map[1].poff = (long)par->ati_regbase & PAGE_MASK;3600	par->mmap_map[1].size = PAGE_SIZE;3601	par->mmap_map[1].prot_mask = _PAGE_CACHE;3602	par->mmap_map[1].prot_flag = _PAGE_E;3603#endif /* __sparc__ */3604 3605	mutex_lock(&reboot_lock);3606	if (!reboot_info)3607		reboot_info = info;3608	mutex_unlock(&reboot_lock);3609 3610	return 0;3611 3612err_release_io:3613#ifdef __sparc__3614	kfree(par->mmap_map);3615#else3616	if (par->ati_regbase)3617		iounmap(par->ati_regbase);3618	if (info->screen_base)3619		iounmap(info->screen_base);3620#endif3621err_release_mem:3622	if (par->aux_start)3623		release_mem_region(par->aux_start, par->aux_size);3624 3625	release_mem_region(par->res_start, par->res_size);3626	framebuffer_release(info);3627 3628	return rc;3629}3630 3631#endif /* CONFIG_PCI */3632 3633#ifdef CONFIG_ATARI3634 3635static int __init atyfb_atari_probe(void)3636{3637	struct atyfb_par *par;3638	struct fb_info *info;3639	int m64_num;3640	u32 clock_r;3641	int num_found = 0;3642 3643	for (m64_num = 0; m64_num < mach64_count; m64_num++) {3644		if (!phys_vmembase[m64_num] || !phys_size[m64_num] ||3645		    !phys_guiregbase[m64_num]) {3646			PRINTKI("phys_*[%d] parameters not set => "3647				"returning early. \n", m64_num);3648			continue;3649		}3650 3651		info = framebuffer_alloc(sizeof(struct atyfb_par), NULL);3652		if (!info)3653			return -ENOMEM;3654 3655		par = info->par;3656 3657		info->fix = atyfb_fix;3658 3659		par->irq = (unsigned int) -1; /* something invalid */3660 3661		/*3662		 * Map the video memory (physical address given)3663		 * to somewhere in the kernel address space.3664		 */3665		info->screen_base = ioremap_wc(phys_vmembase[m64_num],3666					       phys_size[m64_num]);3667		info->fix.smem_start = (unsigned long)info->screen_base; /* Fake! */3668		par->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000) +3669						0xFC00ul;3670		info->fix.mmio_start = (unsigned long)par->ati_regbase; /* Fake! */3671 3672		aty_st_le32(CLOCK_CNTL, 0x12345678, par);3673		clock_r = aty_ld_le32(CLOCK_CNTL, par);3674 3675		switch (clock_r & 0x003F) {3676		case 0x12:3677			par->clk_wr_offset = 3; /*  */3678			break;3679		case 0x34:3680			par->clk_wr_offset = 2; /* Medusa ST-IO ISA Adapter etc. */3681			break;3682		case 0x16:3683			par->clk_wr_offset = 1; /*  */3684			break;3685		case 0x38:3686			par->clk_wr_offset = 0; /* Panther 1 ISA Adapter (Gerald) */3687			break;3688		}3689 3690		/* Fake pci_id for correct_chipset() */3691		switch (aty_ld_le32(CNFG_CHIP_ID, par) & CFG_CHIP_TYPE) {3692		case 0x00d7:3693			par->pci_id = PCI_CHIP_MACH64GX;3694			break;3695		case 0x0057:3696			par->pci_id = PCI_CHIP_MACH64CX;3697			break;3698		default:3699			break;3700		}3701 3702		if (correct_chipset(par) || aty_init(info)) {3703			iounmap(info->screen_base);3704			iounmap(par->ati_regbase);3705			framebuffer_release(info);3706		} else {3707			num_found++;3708		}3709	}3710 3711	return num_found ? 0 : -ENXIO;3712}3713 3714#endif /* CONFIG_ATARI */3715 3716#ifdef CONFIG_PCI3717 3718static void atyfb_remove(struct fb_info *info)3719{3720	struct atyfb_par *par = (struct atyfb_par *) info->par;3721 3722	/* restore video mode */3723	aty_set_crtc(par, &par->saved_crtc);3724	par->pll_ops->set_pll(info, &par->saved_pll);3725 3726#ifdef CONFIG_FB_ATY_BACKLIGHT3727	if (M64_HAS(MOBIL_BUS))3728		aty_bl_exit(info->bl_dev);3729#endif3730 3731	unregister_framebuffer(info);3732 3733	arch_phys_wc_del(par->wc_cookie);3734 3735#ifndef __sparc__3736	if (par->ati_regbase)3737		iounmap(par->ati_regbase);3738	if (info->screen_base)3739		iounmap(info->screen_base);3740#ifdef __BIG_ENDIAN3741	if (info->sprite.addr)3742		iounmap(info->sprite.addr);3743#endif3744#endif3745#ifdef __sparc__3746	kfree(par->mmap_map);3747#endif3748	if (par->aux_start)3749		release_mem_region(par->aux_start, par->aux_size);3750 3751	if (par->res_start)3752		release_mem_region(par->res_start, par->res_size);3753 3754	framebuffer_release(info);3755}3756 3757 3758static void atyfb_pci_remove(struct pci_dev *pdev)3759{3760	struct fb_info *info = pci_get_drvdata(pdev);3761 3762	mutex_lock(&reboot_lock);3763	if (reboot_info == info)3764		reboot_info = NULL;3765	mutex_unlock(&reboot_lock);3766 3767	atyfb_remove(info);3768}3769 3770static const struct pci_device_id atyfb_pci_tbl[] = {3771#ifdef CONFIG_FB_ATY_GX3772	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GX) },3773	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64CX) },3774#endif /* CONFIG_FB_ATY_GX */3775 3776#ifdef CONFIG_FB_ATY_CT3777	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64CT) },3778	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64ET) },3779 3780	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LT) },3781 3782	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VT) },3783	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GT) },3784 3785	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VU) },3786	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GU) },3787 3788	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LG) },3789 3790	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VV) },3791 3792	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GV) },3793	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GW) },3794	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GY) },3795	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GZ) },3796 3797	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GB) },3798	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GD) },3799	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GI) },3800	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GP) },3801	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GQ) },3802 3803	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LB) },3804	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LD) },3805	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LI) },3806	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LP) },3807	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LQ) },3808 3809	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GM) },3810	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GN) },3811	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GO) },3812	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GL) },3813	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GR) },3814	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GS) },3815 3816	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LM) },3817	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LN) },3818	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LR) },3819	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LS) },3820#endif /* CONFIG_FB_ATY_CT */3821	{ }3822};3823 3824MODULE_DEVICE_TABLE(pci, atyfb_pci_tbl);3825 3826static struct pci_driver atyfb_driver = {3827	.name		= "atyfb",3828	.id_table	= atyfb_pci_tbl,3829	.probe		= atyfb_pci_probe,3830	.remove		= atyfb_pci_remove,3831	.driver.pm	= &atyfb_pci_pm_ops,3832};3833 3834#endif /* CONFIG_PCI */3835 3836#ifndef MODULE3837static int __init atyfb_setup(char *options)3838{3839	char *this_opt;3840 3841	if (!options || !*options)3842		return 0;3843 3844	while ((this_opt = strsep(&options, ",")) != NULL) {3845		if (!strncmp(this_opt, "noaccel", 7)) {3846			noaccel = true;3847		} else if (!strncmp(this_opt, "nomtrr", 6)) {3848			nomtrr = true;3849		} else if (!strncmp(this_opt, "vram:", 5))3850			vram = simple_strtoul(this_opt + 5, NULL, 0);3851		else if (!strncmp(this_opt, "pll:", 4))3852			pll = simple_strtoul(this_opt + 4, NULL, 0);3853		else if (!strncmp(this_opt, "mclk:", 5))3854			mclk = simple_strtoul(this_opt + 5, NULL, 0);3855		else if (!strncmp(this_opt, "xclk:", 5))3856			xclk = simple_strtoul(this_opt+5, NULL, 0);3857		else if (!strncmp(this_opt, "comp_sync:", 10))3858			comp_sync = simple_strtoul(this_opt+10, NULL, 0);3859		else if (!strncmp(this_opt, "backlight:", 10))3860			backlight = simple_strtoul(this_opt+10, NULL, 0);3861#ifdef CONFIG_PPC3862		else if (!strncmp(this_opt, "vmode:", 6)) {3863			unsigned int vmode =3864			    simple_strtoul(this_opt + 6, NULL, 0);3865			if (vmode > 0 && vmode <= VMODE_MAX)3866				default_vmode = vmode;3867		} else if (!strncmp(this_opt, "cmode:", 6)) {3868			unsigned int cmode =3869			    simple_strtoul(this_opt + 6, NULL, 0);3870			switch (cmode) {3871			case 0:3872			case 8:3873				default_cmode = CMODE_8;3874				break;3875			case 15:3876			case 16:3877				default_cmode = CMODE_16;3878				break;3879			case 24:3880			case 32:3881				default_cmode = CMODE_32;3882				break;3883			}3884		}3885#endif3886#ifdef CONFIG_ATARI3887		/*3888		 * Why do we need this silly Mach64 argument?3889		 * We are already here because of mach64= so its redundant.3890		 */3891		else if (MACH_IS_ATARI3892			 && (!strncmp(this_opt, "Mach64:", 7))) {3893			static unsigned char m64_num;3894			static char mach64_str[80];3895			strscpy(mach64_str, this_opt + 7, sizeof(mach64_str));3896			if (!store_video_par(mach64_str, m64_num)) {3897				m64_num++;3898				mach64_count = m64_num;3899			}3900		}3901#endif3902		else3903			mode = this_opt;3904	}3905	return 0;3906}3907#endif  /*  MODULE  */3908 3909static int atyfb_reboot_notify(struct notifier_block *nb,3910			       unsigned long code, void *unused)3911{3912	struct atyfb_par *par;3913 3914	if (code != SYS_RESTART)3915		return NOTIFY_DONE;3916 3917	mutex_lock(&reboot_lock);3918 3919	if (!reboot_info)3920		goto out;3921 3922	lock_fb_info(reboot_info);3923 3924	par = reboot_info->par;3925 3926	/*3927	 * HP OmniBook 500's BIOS doesn't like the state of the3928	 * hardware after atyfb has been used. Restore the hardware3929	 * to the original state to allow successful reboots.3930	 */3931	aty_set_crtc(par, &par->saved_crtc);3932	par->pll_ops->set_pll(reboot_info, &par->saved_pll);3933 3934	unlock_fb_info(reboot_info);3935 out:3936	mutex_unlock(&reboot_lock);3937 3938	return NOTIFY_DONE;3939}3940 3941static struct notifier_block atyfb_reboot_notifier = {3942	.notifier_call = atyfb_reboot_notify,3943};3944 3945static const struct dmi_system_id atyfb_reboot_ids[] __initconst = {3946	{3947		.ident = "HP OmniBook 500",3948		.matches = {3949			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),3950			DMI_MATCH(DMI_PRODUCT_NAME, "HP OmniBook PC"),3951			DMI_MATCH(DMI_PRODUCT_VERSION, "HP OmniBook 500 FA"),3952		},3953	},3954 3955	{ }3956};3957static bool registered_notifier = false;3958 3959static int __init atyfb_init(void)3960{3961	int err1 = 1, err2 = 1;3962#ifndef MODULE3963	char *option = NULL;3964#endif3965 3966	if (fb_modesetting_disabled("atyfb"))3967		return -ENODEV;3968 3969#ifndef MODULE3970	if (fb_get_options("atyfb", &option))3971		return -ENODEV;3972	atyfb_setup(option);3973#endif3974 3975#ifdef CONFIG_PCI3976	err1 = pci_register_driver(&atyfb_driver);3977#endif3978#ifdef CONFIG_ATARI3979	err2 = atyfb_atari_probe();3980#endif3981 3982	if (err1 && err2)3983		return -ENODEV;3984 3985	if (dmi_check_system(atyfb_reboot_ids)) {3986		register_reboot_notifier(&atyfb_reboot_notifier);3987		registered_notifier = true;3988	}3989 3990	return 0;3991}3992 3993static void __exit atyfb_exit(void)3994{3995	if (registered_notifier)3996		unregister_reboot_notifier(&atyfb_reboot_notifier);3997 3998#ifdef CONFIG_PCI3999	pci_unregister_driver(&atyfb_driver);4000#endif4001}4002 4003module_init(atyfb_init);4004module_exit(atyfb_exit);4005 4006MODULE_DESCRIPTION("FBDev driver for ATI Mach64 cards");4007MODULE_LICENSE("GPL");4008module_param(noaccel, bool, 0);4009MODULE_PARM_DESC(noaccel, "bool: disable acceleration");4010module_param(vram, int, 0);4011MODULE_PARM_DESC(vram, "int: override size of video ram");4012module_param(pll, int, 0);4013MODULE_PARM_DESC(pll, "int: override video clock");4014module_param(mclk, int, 0);4015MODULE_PARM_DESC(mclk, "int: override memory clock");4016module_param(xclk, int, 0);4017MODULE_PARM_DESC(xclk, "int: override accelerated engine clock");4018module_param(comp_sync, int, 0);4019MODULE_PARM_DESC(comp_sync, "Set composite sync signal to low (0) or high (1)");4020module_param(mode, charp, 0);4021MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");4022module_param(nomtrr, bool, 0);4023MODULE_PARM_DESC(nomtrr, "bool: disable use of MTRR registers");4024