18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *	drivers/video/aty/radeon_base.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *	framebuffer driver for ATI Radeon chipset video boards
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *	Copyright 2003	Ben. Herrenschmidt <benh@kernel.crashing.org>
78c2ecf20Sopenharmony_ci *	Copyright 2000	Ani Joshi <ajoshi@kernel.crashing.org>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *	i2c bits from Luca Tettamanti <kronos@kronoz.cjb.net>
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *	Special thanks to ATI DevRel team for their hardware donations.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci *	...Insert GPL boilerplate here...
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci *	Significant portions of this driver apdated from XFree86 Radeon
168c2ecf20Sopenharmony_ci *	driver which has the following copyright notice:
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *	Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
198c2ecf20Sopenharmony_ci *                     VA Linux Systems Inc., Fremont, California.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci *	All Rights Reserved.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci *	Permission is hereby granted, free of charge, to any person obtaining
248c2ecf20Sopenharmony_ci *	a copy of this software and associated documentation files (the
258c2ecf20Sopenharmony_ci *	"Software"), to deal in the Software without restriction, including
268c2ecf20Sopenharmony_ci *	without limitation on the rights to use, copy, modify, merge,
278c2ecf20Sopenharmony_ci *	publish, distribute, sublicense, and/or sell copies of the Software,
288c2ecf20Sopenharmony_ci *	and to permit persons to whom the Software is furnished to do so,
298c2ecf20Sopenharmony_ci *	subject to the following conditions:
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci *	The above copyright notice and this permission notice (including the
328c2ecf20Sopenharmony_ci *	next paragraph) shall be included in all copies or substantial
338c2ecf20Sopenharmony_ci *	portions of the Software.
348c2ecf20Sopenharmony_ci *
358c2ecf20Sopenharmony_ci *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
368c2ecf20Sopenharmony_ci * 	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
378c2ecf20Sopenharmony_ci *	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
388c2ecf20Sopenharmony_ci *	NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
398c2ecf20Sopenharmony_ci *	THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
408c2ecf20Sopenharmony_ci *	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
418c2ecf20Sopenharmony_ci *	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
428c2ecf20Sopenharmony_ci *	DEALINGS IN THE SOFTWARE.
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci *	XFree86 driver authors:
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci *	   Kevin E. Martin <martin@xfree86.org>
478c2ecf20Sopenharmony_ci *	   Rickard E. Faith <faith@valinux.com>
488c2ecf20Sopenharmony_ci *	   Alan Hourihane <alanh@fairlite.demon.co.uk>
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define RADEON_VERSION	"0.2.0"
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#include "radeonfb.h"
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#include <linux/module.h>
588c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
598c2ecf20Sopenharmony_ci#include <linux/kernel.h>
608c2ecf20Sopenharmony_ci#include <linux/errno.h>
618c2ecf20Sopenharmony_ci#include <linux/string.h>
628c2ecf20Sopenharmony_ci#include <linux/ctype.h>
638c2ecf20Sopenharmony_ci#include <linux/mm.h>
648c2ecf20Sopenharmony_ci#include <linux/slab.h>
658c2ecf20Sopenharmony_ci#include <linux/delay.h>
668c2ecf20Sopenharmony_ci#include <linux/time.h>
678c2ecf20Sopenharmony_ci#include <linux/fb.h>
688c2ecf20Sopenharmony_ci#include <linux/ioport.h>
698c2ecf20Sopenharmony_ci#include <linux/init.h>
708c2ecf20Sopenharmony_ci#include <linux/pci.h>
718c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
728c2ecf20Sopenharmony_ci#include <linux/device.h>
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#include <asm/io.h>
758c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci#include "../macmodes.h"
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci#ifdef CONFIG_BOOTX_TEXT
828c2ecf20Sopenharmony_ci#include <asm/btext.h>
838c2ecf20Sopenharmony_ci#endif
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC */
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci#include <video/radeon.h>
888c2ecf20Sopenharmony_ci#include <linux/radeonfb.h>
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci#include "../edid.h" // MOVE THAT TO include/video
918c2ecf20Sopenharmony_ci#include "ati_ids.h"
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define MAX_MAPPED_VRAM	(2048*2048*4)
948c2ecf20Sopenharmony_ci#define MIN_MAPPED_VRAM	(1024*768*1)
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci#define CHIP_DEF(id, family, flags)					\
978c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_ATI, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (flags) | (CHIP_FAMILY_##family) }
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic const struct pci_device_id radeonfb_pci_table[] = {
1008c2ecf20Sopenharmony_ci        /* Radeon Xpress 200m */
1018c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RS480_5955,   RS480,  CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
1028c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RS482_5975,	RS480,	CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
1038c2ecf20Sopenharmony_ci	/* Mobility M6 */
1048c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RADEON_LY, 	RV100,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1058c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RADEON_LZ,	RV100,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1068c2ecf20Sopenharmony_ci	/* Radeon VE/7000 */
1078c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV100_QY, 	RV100,	CHIP_HAS_CRTC2),
1088c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV100_QZ, 	RV100,	CHIP_HAS_CRTC2),
1098c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RN50,		RV100,	CHIP_HAS_CRTC2),
1108c2ecf20Sopenharmony_ci	/* Radeon IGP320M (U1) */
1118c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RS100_4336,	RS100,	CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
1128c2ecf20Sopenharmony_ci	/* Radeon IGP320 (A3) */
1138c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RS100_4136,	RS100,	CHIP_HAS_CRTC2 | CHIP_IS_IGP),
1148c2ecf20Sopenharmony_ci	/* IGP330M/340M/350M (U2) */
1158c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RS200_4337,	RS200,	CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
1168c2ecf20Sopenharmony_ci	/* IGP330/340/350 (A4) */
1178c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RS200_4137,	RS200,	CHIP_HAS_CRTC2 | CHIP_IS_IGP),
1188c2ecf20Sopenharmony_ci	/* Mobility 7000 IGP */
1198c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RS250_4437,	RS200,	CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
1208c2ecf20Sopenharmony_ci	/* 7000 IGP (A4+) */
1218c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RS250_4237,	RS200,	CHIP_HAS_CRTC2 | CHIP_IS_IGP),
1228c2ecf20Sopenharmony_ci	/* 8500 AIW */
1238c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R200_BB,	R200,	CHIP_HAS_CRTC2),
1248c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R200_BC,	R200,	CHIP_HAS_CRTC2),
1258c2ecf20Sopenharmony_ci	/* 8700/8800 */
1268c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R200_QH,	R200,	CHIP_HAS_CRTC2),
1278c2ecf20Sopenharmony_ci	/* 8500 */
1288c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R200_QL,	R200,	CHIP_HAS_CRTC2),
1298c2ecf20Sopenharmony_ci	/* 9100 */
1308c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R200_QM,	R200,	CHIP_HAS_CRTC2),
1318c2ecf20Sopenharmony_ci	/* Mobility M7 */
1328c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RADEON_LW,	RV200,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1338c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RADEON_LX,	RV200,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1348c2ecf20Sopenharmony_ci	/* 7500 */
1358c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV200_QW,	RV200,	CHIP_HAS_CRTC2),
1368c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV200_QX,	RV200,	CHIP_HAS_CRTC2),
1378c2ecf20Sopenharmony_ci	/* Mobility M9 */
1388c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV250_Ld,	RV250,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1398c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV250_Le,	RV250,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1408c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV250_Lf,	RV250,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1418c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV250_Lg,	RV250,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1428c2ecf20Sopenharmony_ci	/* 9000/Pro */
1438c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV250_If,	RV250,	CHIP_HAS_CRTC2),
1448c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV250_Ig,	RV250,	CHIP_HAS_CRTC2),
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RC410_5A62,   RC410,  CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
1478c2ecf20Sopenharmony_ci	/* Mobility 9100 IGP (U3) */
1488c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RS300_5835,	RS300,	CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
1498c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RS350_7835,	RS300,	CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
1508c2ecf20Sopenharmony_ci	/* 9100 IGP (A5) */
1518c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RS300_5834,	RS300,	CHIP_HAS_CRTC2 | CHIP_IS_IGP),
1528c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RS350_7834,	RS300,	CHIP_HAS_CRTC2 | CHIP_IS_IGP),
1538c2ecf20Sopenharmony_ci	/* Mobility 9200 (M9+) */
1548c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV280_5C61,	RV280,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1558c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV280_5C63,	RV280,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1568c2ecf20Sopenharmony_ci	/* 9200 */
1578c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV280_5960,	RV280,	CHIP_HAS_CRTC2),
1588c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV280_5961,	RV280,	CHIP_HAS_CRTC2),
1598c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV280_5962,	RV280,	CHIP_HAS_CRTC2),
1608c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV280_5964,	RV280,	CHIP_HAS_CRTC2),
1618c2ecf20Sopenharmony_ci	/* 9500 */
1628c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R300_AD,	R300,	CHIP_HAS_CRTC2),
1638c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R300_AE,	R300,	CHIP_HAS_CRTC2),
1648c2ecf20Sopenharmony_ci	/* 9600TX / FireGL Z1 */
1658c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R300_AF,	R300,	CHIP_HAS_CRTC2),
1668c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R300_AG,	R300,	CHIP_HAS_CRTC2),
1678c2ecf20Sopenharmony_ci	/* 9700/9500/Pro/FireGL X1 */
1688c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R300_ND,	R300,	CHIP_HAS_CRTC2),
1698c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R300_NE,	R300,	CHIP_HAS_CRTC2),
1708c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R300_NF,	R300,	CHIP_HAS_CRTC2),
1718c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R300_NG,	R300,	CHIP_HAS_CRTC2),
1728c2ecf20Sopenharmony_ci	/* Mobility M10/M11 */
1738c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV350_NP,	RV350,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1748c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV350_NQ,	RV350,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1758c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV350_NR,	RV350,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1768c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV350_NS,	RV350,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1778c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV350_NT,	RV350,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1788c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV350_NV,	RV350,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1798c2ecf20Sopenharmony_ci	/* 9600/FireGL T2 */
1808c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV350_AP,	RV350,	CHIP_HAS_CRTC2),
1818c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV350_AQ,	RV350,	CHIP_HAS_CRTC2),
1828c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV360_AR,	RV350,	CHIP_HAS_CRTC2),
1838c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV350_AS,	RV350,	CHIP_HAS_CRTC2),
1848c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV350_AT,	RV350,	CHIP_HAS_CRTC2),
1858c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV350_AV,	RV350,	CHIP_HAS_CRTC2),
1868c2ecf20Sopenharmony_ci	/* 9800/Pro/FileGL X2 */
1878c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R350_AH,	R350,	CHIP_HAS_CRTC2),
1888c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R350_AI,	R350,	CHIP_HAS_CRTC2),
1898c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R350_AJ,	R350,	CHIP_HAS_CRTC2),
1908c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R350_AK,	R350,	CHIP_HAS_CRTC2),
1918c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R350_NH,	R350,	CHIP_HAS_CRTC2),
1928c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R350_NI,	R350,	CHIP_HAS_CRTC2),
1938c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R360_NJ,	R350,	CHIP_HAS_CRTC2),
1948c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R350_NK,	R350,	CHIP_HAS_CRTC2),
1958c2ecf20Sopenharmony_ci	/* Newer stuff */
1968c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV380_3E50,	RV380,	CHIP_HAS_CRTC2),
1978c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV380_3E54,	RV380,	CHIP_HAS_CRTC2),
1988c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV380_3150,	RV380,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
1998c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV380_3154,	RV380,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
2008c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV370_5B60,	RV380,	CHIP_HAS_CRTC2),
2018c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV370_5B62,	RV380,	CHIP_HAS_CRTC2),
2028c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV370_5B63,	RV380,	CHIP_HAS_CRTC2),
2038c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV370_5B64,	RV380,	CHIP_HAS_CRTC2),
2048c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV370_5B65,	RV380,	CHIP_HAS_CRTC2),
2058c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV370_5460,	RV380,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
2068c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RV370_5464,	RV380,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
2078c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R420_JH,	R420,	CHIP_HAS_CRTC2),
2088c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R420_JI,	R420,	CHIP_HAS_CRTC2),
2098c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R420_JJ,	R420,	CHIP_HAS_CRTC2),
2108c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R420_JK,	R420,	CHIP_HAS_CRTC2),
2118c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R420_JL,	R420,	CHIP_HAS_CRTC2),
2128c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R420_JM,	R420,	CHIP_HAS_CRTC2),
2138c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R420_JN,	R420,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
2148c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R420_JP,	R420,	CHIP_HAS_CRTC2),
2158c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R423_UH,	R420,	CHIP_HAS_CRTC2),
2168c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R423_UI,	R420,	CHIP_HAS_CRTC2),
2178c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R423_UJ,	R420,	CHIP_HAS_CRTC2),
2188c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R423_UK,	R420,	CHIP_HAS_CRTC2),
2198c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R423_UQ,	R420,	CHIP_HAS_CRTC2),
2208c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R423_UR,	R420,	CHIP_HAS_CRTC2),
2218c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R423_UT,	R420,	CHIP_HAS_CRTC2),
2228c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_R423_5D57,	R420,	CHIP_HAS_CRTC2),
2238c2ecf20Sopenharmony_ci	/* Original Radeon/7200 */
2248c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RADEON_QD,	RADEON,	0),
2258c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RADEON_QE,	RADEON,	0),
2268c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RADEON_QF,	RADEON,	0),
2278c2ecf20Sopenharmony_ci	CHIP_DEF(PCI_CHIP_RADEON_QG,	RADEON,	0),
2288c2ecf20Sopenharmony_ci	{ 0, }
2298c2ecf20Sopenharmony_ci};
2308c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, radeonfb_pci_table);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_citypedef struct {
2348c2ecf20Sopenharmony_ci	u16 reg;
2358c2ecf20Sopenharmony_ci	u32 val;
2368c2ecf20Sopenharmony_ci} reg_val;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci/* these common regs are cleared before mode setting so they do not
2408c2ecf20Sopenharmony_ci * interfere with anything
2418c2ecf20Sopenharmony_ci */
2428c2ecf20Sopenharmony_cistatic reg_val common_regs[] = {
2438c2ecf20Sopenharmony_ci	{ OVR_CLR, 0 },
2448c2ecf20Sopenharmony_ci	{ OVR_WID_LEFT_RIGHT, 0 },
2458c2ecf20Sopenharmony_ci	{ OVR_WID_TOP_BOTTOM, 0 },
2468c2ecf20Sopenharmony_ci	{ OV0_SCALE_CNTL, 0 },
2478c2ecf20Sopenharmony_ci	{ SUBPIC_CNTL, 0 },
2488c2ecf20Sopenharmony_ci	{ VIPH_CONTROL, 0 },
2498c2ecf20Sopenharmony_ci	{ I2C_CNTL_1, 0 },
2508c2ecf20Sopenharmony_ci	{ GEN_INT_CNTL, 0 },
2518c2ecf20Sopenharmony_ci	{ CAP0_TRIG_CNTL, 0 },
2528c2ecf20Sopenharmony_ci	{ CAP1_TRIG_CNTL, 0 },
2538c2ecf20Sopenharmony_ci};
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/*
2568c2ecf20Sopenharmony_ci * globals
2578c2ecf20Sopenharmony_ci */
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic char *mode_option;
2608c2ecf20Sopenharmony_cistatic char *monitor_layout;
2618c2ecf20Sopenharmony_cistatic bool noaccel = 0;
2628c2ecf20Sopenharmony_cistatic int default_dynclk = -2;
2638c2ecf20Sopenharmony_cistatic bool nomodeset = 0;
2648c2ecf20Sopenharmony_cistatic bool ignore_edid = 0;
2658c2ecf20Sopenharmony_cistatic bool mirror = 0;
2668c2ecf20Sopenharmony_cistatic int panel_yres = 0;
2678c2ecf20Sopenharmony_cistatic bool force_dfp = 0;
2688c2ecf20Sopenharmony_cistatic bool force_measure_pll = 0;
2698c2ecf20Sopenharmony_cistatic bool nomtrr = 0;
2708c2ecf20Sopenharmony_cistatic bool force_sleep;
2718c2ecf20Sopenharmony_cistatic bool ignore_devlist;
2728c2ecf20Sopenharmony_cistatic int backlight = IS_BUILTIN(CONFIG_PMAC_BACKLIGHT);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci/* Note about this function: we have some rare cases where we must not schedule,
2758c2ecf20Sopenharmony_ci * this typically happen with our special "wake up early" hook which allows us to
2768c2ecf20Sopenharmony_ci * wake up the graphic chip (and thus get the console back) before everything else
2778c2ecf20Sopenharmony_ci * on some machines that support that mechanism. At this point, interrupts are off
2788c2ecf20Sopenharmony_ci * and scheduling is not permitted
2798c2ecf20Sopenharmony_ci */
2808c2ecf20Sopenharmony_civoid _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	if (rinfo->no_schedule || oops_in_progress)
2838c2ecf20Sopenharmony_ci		mdelay(ms);
2848c2ecf20Sopenharmony_ci	else
2858c2ecf20Sopenharmony_ci		msleep(ms);
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_civoid radeon_pll_errata_after_index_slow(struct radeonfb_info *rinfo)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	/* Called if (rinfo->errata & CHIP_ERRATA_PLL_DUMMYREADS) is set */
2918c2ecf20Sopenharmony_ci	(void)INREG(CLOCK_CNTL_DATA);
2928c2ecf20Sopenharmony_ci	(void)INREG(CRTC_GEN_CNTL);
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_civoid radeon_pll_errata_after_data_slow(struct radeonfb_info *rinfo)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	if (rinfo->errata & CHIP_ERRATA_PLL_DELAY) {
2988c2ecf20Sopenharmony_ci		/* we can't deal with posted writes here ... */
2998c2ecf20Sopenharmony_ci		_radeon_msleep(rinfo, 5);
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci	if (rinfo->errata & CHIP_ERRATA_R300_CG) {
3028c2ecf20Sopenharmony_ci		u32 save, tmp;
3038c2ecf20Sopenharmony_ci		save = INREG(CLOCK_CNTL_INDEX);
3048c2ecf20Sopenharmony_ci		tmp = save & ~(0x3f | PLL_WR_EN);
3058c2ecf20Sopenharmony_ci		OUTREG(CLOCK_CNTL_INDEX, tmp);
3068c2ecf20Sopenharmony_ci		tmp = INREG(CLOCK_CNTL_DATA);
3078c2ecf20Sopenharmony_ci		OUTREG(CLOCK_CNTL_INDEX, save);
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_civoid _OUTREGP(struct radeonfb_info *rinfo, u32 addr, u32 val, u32 mask)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	unsigned long flags;
3148c2ecf20Sopenharmony_ci	unsigned int tmp;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rinfo->reg_lock, flags);
3178c2ecf20Sopenharmony_ci	tmp = INREG(addr);
3188c2ecf20Sopenharmony_ci	tmp &= (mask);
3198c2ecf20Sopenharmony_ci	tmp |= (val);
3208c2ecf20Sopenharmony_ci	OUTREG(addr, tmp);
3218c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rinfo->reg_lock, flags);
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ciu32 __INPLL(struct radeonfb_info *rinfo, u32 addr)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	u32 data;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
3298c2ecf20Sopenharmony_ci	radeon_pll_errata_after_index(rinfo);
3308c2ecf20Sopenharmony_ci	data = INREG(CLOCK_CNTL_DATA);
3318c2ecf20Sopenharmony_ci	radeon_pll_errata_after_data(rinfo);
3328c2ecf20Sopenharmony_ci	return data;
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_civoid __OUTPLL(struct radeonfb_info *rinfo, unsigned int index, u32 val)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	OUTREG8(CLOCK_CNTL_INDEX, (index & 0x0000003f) | 0x00000080);
3388c2ecf20Sopenharmony_ci	radeon_pll_errata_after_index(rinfo);
3398c2ecf20Sopenharmony_ci	OUTREG(CLOCK_CNTL_DATA, val);
3408c2ecf20Sopenharmony_ci	radeon_pll_errata_after_data(rinfo);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_civoid __OUTPLLP(struct radeonfb_info *rinfo, unsigned int index,
3448c2ecf20Sopenharmony_ci			     u32 val, u32 mask)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	unsigned int tmp;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	tmp  = __INPLL(rinfo, index);
3498c2ecf20Sopenharmony_ci	tmp &= (mask);
3508c2ecf20Sopenharmony_ci	tmp |= (val);
3518c2ecf20Sopenharmony_ci	__OUTPLL(rinfo, index, tmp);
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_civoid _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	int i;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	for (i=0; i<2000000; i++) {
3598c2ecf20Sopenharmony_ci		if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
3608c2ecf20Sopenharmony_ci			return;
3618c2ecf20Sopenharmony_ci		udelay(1);
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci	printk(KERN_ERR "radeonfb: FIFO Timeout !\n");
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_civoid radeon_engine_flush(struct radeonfb_info *rinfo)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	int i;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* Initiate flush */
3718c2ecf20Sopenharmony_ci	OUTREGP(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
3728c2ecf20Sopenharmony_ci	        ~RB2D_DC_FLUSH_ALL);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	/* Ensure FIFO is empty, ie, make sure the flush commands
3758c2ecf20Sopenharmony_ci	 * has reached the cache
3768c2ecf20Sopenharmony_ci	 */
3778c2ecf20Sopenharmony_ci	_radeon_fifo_wait(rinfo, 64);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	/* Wait for the flush to complete */
3808c2ecf20Sopenharmony_ci	for (i=0; i < 2000000; i++) {
3818c2ecf20Sopenharmony_ci		if (!(INREG(DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
3828c2ecf20Sopenharmony_ci			return;
3838c2ecf20Sopenharmony_ci		udelay(1);
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci	printk(KERN_ERR "radeonfb: Flush Timeout !\n");
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_civoid _radeon_engine_idle(struct radeonfb_info *rinfo)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	int i;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	/* ensure FIFO is empty before waiting for idle */
3938c2ecf20Sopenharmony_ci	_radeon_fifo_wait(rinfo, 64);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	for (i=0; i<2000000; i++) {
3968c2ecf20Sopenharmony_ci		if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) {
3978c2ecf20Sopenharmony_ci			radeon_engine_flush(rinfo);
3988c2ecf20Sopenharmony_ci			return;
3998c2ecf20Sopenharmony_ci		}
4008c2ecf20Sopenharmony_ci		udelay(1);
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci	printk(KERN_ERR "radeonfb: Idle Timeout !\n");
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	if (!rinfo->bios_seg)
4108c2ecf20Sopenharmony_ci		return;
4118c2ecf20Sopenharmony_ci	pci_unmap_rom(dev, rinfo->bios_seg);
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_cistatic int radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	void __iomem *rom;
4178c2ecf20Sopenharmony_ci	u16 dptr;
4188c2ecf20Sopenharmony_ci	u8 rom_type;
4198c2ecf20Sopenharmony_ci	size_t rom_size;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	/* If this is a primary card, there is a shadow copy of the
4228c2ecf20Sopenharmony_ci	 * ROM somewhere in the first meg. We will just ignore the copy
4238c2ecf20Sopenharmony_ci	 * and use the ROM directly.
4248c2ecf20Sopenharmony_ci	 */
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci    	/* Fix from ATI for problem with Radeon hardware not leaving ROM enabled */
4278c2ecf20Sopenharmony_ci    	unsigned int temp;
4288c2ecf20Sopenharmony_ci	temp = INREG(MPP_TB_CONFIG);
4298c2ecf20Sopenharmony_ci	temp &= 0x00ffffffu;
4308c2ecf20Sopenharmony_ci	temp |= 0x04 << 24;
4318c2ecf20Sopenharmony_ci	OUTREG(MPP_TB_CONFIG, temp);
4328c2ecf20Sopenharmony_ci	temp = INREG(MPP_TB_CONFIG);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	rom = pci_map_rom(dev, &rom_size);
4358c2ecf20Sopenharmony_ci	if (!rom) {
4368c2ecf20Sopenharmony_ci		printk(KERN_ERR "radeonfb (%s): ROM failed to map\n",
4378c2ecf20Sopenharmony_ci		       pci_name(rinfo->pdev));
4388c2ecf20Sopenharmony_ci		return -ENOMEM;
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	rinfo->bios_seg = rom;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	/* Very simple test to make sure it appeared */
4448c2ecf20Sopenharmony_ci	if (BIOS_IN16(0) != 0xaa55) {
4458c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "radeonfb (%s): Invalid ROM signature %x "
4468c2ecf20Sopenharmony_ci			"should be 0xaa55\n",
4478c2ecf20Sopenharmony_ci			pci_name(rinfo->pdev), BIOS_IN16(0));
4488c2ecf20Sopenharmony_ci		goto failed;
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci	/* Look for the PCI data to check the ROM type */
4518c2ecf20Sopenharmony_ci	dptr = BIOS_IN16(0x18);
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* Check the PCI data signature. If it's wrong, we still assume a normal x86 ROM
4548c2ecf20Sopenharmony_ci	 * for now, until I've verified this works everywhere. The goal here is more
4558c2ecf20Sopenharmony_ci	 * to phase out Open Firmware images.
4568c2ecf20Sopenharmony_ci	 *
4578c2ecf20Sopenharmony_ci	 * Currently, we only look at the first PCI data, we could iteratre and deal with
4588c2ecf20Sopenharmony_ci	 * them all, and we should use fb_bios_start relative to start of image and not
4598c2ecf20Sopenharmony_ci	 * relative start of ROM, but so far, I never found a dual-image ATI card
4608c2ecf20Sopenharmony_ci	 *
4618c2ecf20Sopenharmony_ci	 * typedef struct {
4628c2ecf20Sopenharmony_ci	 * 	u32	signature;	+ 0x00
4638c2ecf20Sopenharmony_ci	 * 	u16	vendor;		+ 0x04
4648c2ecf20Sopenharmony_ci	 * 	u16	device;		+ 0x06
4658c2ecf20Sopenharmony_ci	 * 	u16	reserved_1;	+ 0x08
4668c2ecf20Sopenharmony_ci	 * 	u16	dlen;		+ 0x0a
4678c2ecf20Sopenharmony_ci	 * 	u8	drevision;	+ 0x0c
4688c2ecf20Sopenharmony_ci	 * 	u8	class_hi;	+ 0x0d
4698c2ecf20Sopenharmony_ci	 * 	u16	class_lo;	+ 0x0e
4708c2ecf20Sopenharmony_ci	 * 	u16	ilen;		+ 0x10
4718c2ecf20Sopenharmony_ci	 * 	u16	irevision;	+ 0x12
4728c2ecf20Sopenharmony_ci	 * 	u8	type;		+ 0x14
4738c2ecf20Sopenharmony_ci	 * 	u8	indicator;	+ 0x15
4748c2ecf20Sopenharmony_ci	 * 	u16	reserved_2;	+ 0x16
4758c2ecf20Sopenharmony_ci	 * } pci_data_t;
4768c2ecf20Sopenharmony_ci	 */
4778c2ecf20Sopenharmony_ci	if (BIOS_IN32(dptr) !=  (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) {
4788c2ecf20Sopenharmony_ci		printk(KERN_WARNING "radeonfb (%s): PCI DATA signature in ROM"
4798c2ecf20Sopenharmony_ci		       "incorrect: %08x\n", pci_name(rinfo->pdev), BIOS_IN32(dptr));
4808c2ecf20Sopenharmony_ci		goto anyway;
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci	rom_type = BIOS_IN8(dptr + 0x14);
4838c2ecf20Sopenharmony_ci	switch(rom_type) {
4848c2ecf20Sopenharmony_ci	case 0:
4858c2ecf20Sopenharmony_ci		printk(KERN_INFO "radeonfb: Found Intel x86 BIOS ROM Image\n");
4868c2ecf20Sopenharmony_ci		break;
4878c2ecf20Sopenharmony_ci	case 1:
4888c2ecf20Sopenharmony_ci		printk(KERN_INFO "radeonfb: Found Open Firmware ROM Image\n");
4898c2ecf20Sopenharmony_ci		goto failed;
4908c2ecf20Sopenharmony_ci	case 2:
4918c2ecf20Sopenharmony_ci		printk(KERN_INFO "radeonfb: Found HP PA-RISC ROM Image\n");
4928c2ecf20Sopenharmony_ci		goto failed;
4938c2ecf20Sopenharmony_ci	default:
4948c2ecf20Sopenharmony_ci		printk(KERN_INFO "radeonfb: Found unknown type %d ROM Image\n", rom_type);
4958c2ecf20Sopenharmony_ci		goto failed;
4968c2ecf20Sopenharmony_ci	}
4978c2ecf20Sopenharmony_ci anyway:
4988c2ecf20Sopenharmony_ci	/* Locate the flat panel infos, do some sanity checking !!! */
4998c2ecf20Sopenharmony_ci	rinfo->fp_bios_start = BIOS_IN16(0x48);
5008c2ecf20Sopenharmony_ci	return 0;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci failed:
5038c2ecf20Sopenharmony_ci	rinfo->bios_seg = NULL;
5048c2ecf20Sopenharmony_ci	radeon_unmap_ROM(rinfo, dev);
5058c2ecf20Sopenharmony_ci	return -ENXIO;
5068c2ecf20Sopenharmony_ci}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
5098c2ecf20Sopenharmony_cistatic int  radeon_find_mem_vbios(struct radeonfb_info *rinfo)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	/* I simplified this code as we used to miss the signatures in
5128c2ecf20Sopenharmony_ci	 * a lot of case. It's now closer to XFree, we just don't check
5138c2ecf20Sopenharmony_ci	 * for signatures at all... Something better will have to be done
5148c2ecf20Sopenharmony_ci	 * if we end up having conflicts
5158c2ecf20Sopenharmony_ci	 */
5168c2ecf20Sopenharmony_ci        u32  segstart;
5178c2ecf20Sopenharmony_ci	void __iomem *rom_base = NULL;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci        for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
5208c2ecf20Sopenharmony_ci                rom_base = ioremap(segstart, 0x10000);
5218c2ecf20Sopenharmony_ci		if (rom_base == NULL)
5228c2ecf20Sopenharmony_ci			return -ENOMEM;
5238c2ecf20Sopenharmony_ci                if (readb(rom_base) == 0x55 && readb(rom_base + 1) == 0xaa)
5248c2ecf20Sopenharmony_ci	                break;
5258c2ecf20Sopenharmony_ci                iounmap(rom_base);
5268c2ecf20Sopenharmony_ci		rom_base = NULL;
5278c2ecf20Sopenharmony_ci        }
5288c2ecf20Sopenharmony_ci	if (rom_base == NULL)
5298c2ecf20Sopenharmony_ci		return -ENXIO;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	/* Locate the flat panel infos, do some sanity checking !!! */
5328c2ecf20Sopenharmony_ci	rinfo->bios_seg = rom_base;
5338c2ecf20Sopenharmony_ci	rinfo->fp_bios_start = BIOS_IN16(0x48);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	return 0;
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci#endif
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci#if defined(CONFIG_PPC) || defined(CONFIG_SPARC)
5408c2ecf20Sopenharmony_ci/*
5418c2ecf20Sopenharmony_ci * Read XTAL (ref clock), SCLK and MCLK from Open Firmware device
5428c2ecf20Sopenharmony_ci * tree. Hopefully, ATI OF driver is kind enough to fill these
5438c2ecf20Sopenharmony_ci */
5448c2ecf20Sopenharmony_cistatic int radeon_read_xtal_OF(struct radeonfb_info *rinfo)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct device_node *dp = rinfo->of_node;
5478c2ecf20Sopenharmony_ci	const u32 *val;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (dp == NULL)
5508c2ecf20Sopenharmony_ci		return -ENODEV;
5518c2ecf20Sopenharmony_ci	val = of_get_property(dp, "ATY,RefCLK", NULL);
5528c2ecf20Sopenharmony_ci	if (!val || !*val) {
5538c2ecf20Sopenharmony_ci		printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n");
5548c2ecf20Sopenharmony_ci		return -EINVAL;
5558c2ecf20Sopenharmony_ci	}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	rinfo->pll.ref_clk = (*val) / 10;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	val = of_get_property(dp, "ATY,SCLK", NULL);
5608c2ecf20Sopenharmony_ci	if (val && *val)
5618c2ecf20Sopenharmony_ci		rinfo->pll.sclk = (*val) / 10;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	val = of_get_property(dp, "ATY,MCLK", NULL);
5648c2ecf20Sopenharmony_ci	if (val && *val)
5658c2ecf20Sopenharmony_ci		rinfo->pll.mclk = (*val) / 10;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci       	return 0;
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC || CONFIG_SPARC */
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci/*
5728c2ecf20Sopenharmony_ci * Read PLL infos from chip registers
5738c2ecf20Sopenharmony_ci */
5748c2ecf20Sopenharmony_cistatic int radeon_probe_pll_params(struct radeonfb_info *rinfo)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	unsigned char ppll_div_sel;
5778c2ecf20Sopenharmony_ci	unsigned Ns, Nm, M;
5788c2ecf20Sopenharmony_ci	unsigned sclk, mclk, tmp, ref_div;
5798c2ecf20Sopenharmony_ci	int hTotal, vTotal, num, denom, m, n;
5808c2ecf20Sopenharmony_ci	unsigned long long hz, vclk;
5818c2ecf20Sopenharmony_ci	long xtal;
5828c2ecf20Sopenharmony_ci	ktime_t start_time, stop_time;
5838c2ecf20Sopenharmony_ci	u64 total_usecs;
5848c2ecf20Sopenharmony_ci	int i;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	/* Ugh, we cut interrupts, bad bad bad, but we want some precision
5878c2ecf20Sopenharmony_ci	 * here, so... --BenH
5888c2ecf20Sopenharmony_ci	 */
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	/* Flush PCI buffers ? */
5918c2ecf20Sopenharmony_ci	tmp = INREG16(DEVICE_ID);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	local_irq_disable();
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	for(i=0; i<1000000; i++)
5968c2ecf20Sopenharmony_ci		if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0)
5978c2ecf20Sopenharmony_ci			break;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	start_time = ktime_get();
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	for(i=0; i<1000000; i++)
6028c2ecf20Sopenharmony_ci		if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) != 0)
6038c2ecf20Sopenharmony_ci			break;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	for(i=0; i<1000000; i++)
6068c2ecf20Sopenharmony_ci		if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0)
6078c2ecf20Sopenharmony_ci			break;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	stop_time = ktime_get();
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	local_irq_enable();
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	total_usecs = ktime_us_delta(stop_time, start_time);
6148c2ecf20Sopenharmony_ci	if (total_usecs >= 10 * USEC_PER_SEC || total_usecs == 0)
6158c2ecf20Sopenharmony_ci		return -1;
6168c2ecf20Sopenharmony_ci	hz = USEC_PER_SEC/(u32)total_usecs;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	hTotal = ((INREG(CRTC_H_TOTAL_DISP) & 0x1ff) + 1) * 8;
6198c2ecf20Sopenharmony_ci	vTotal = ((INREG(CRTC_V_TOTAL_DISP) & 0x3ff) + 1);
6208c2ecf20Sopenharmony_ci	vclk = (long long)hTotal * (long long)vTotal * hz;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	switch((INPLL(PPLL_REF_DIV) & 0x30000) >> 16) {
6238c2ecf20Sopenharmony_ci	case 0:
6248c2ecf20Sopenharmony_ci	default:
6258c2ecf20Sopenharmony_ci		num = 1;
6268c2ecf20Sopenharmony_ci		denom = 1;
6278c2ecf20Sopenharmony_ci		break;
6288c2ecf20Sopenharmony_ci	case 1:
6298c2ecf20Sopenharmony_ci		n = ((INPLL(M_SPLL_REF_FB_DIV) >> 16) & 0xff);
6308c2ecf20Sopenharmony_ci		m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff);
6318c2ecf20Sopenharmony_ci		num = 2*n;
6328c2ecf20Sopenharmony_ci		denom = 2*m;
6338c2ecf20Sopenharmony_ci		break;
6348c2ecf20Sopenharmony_ci	case 2:
6358c2ecf20Sopenharmony_ci		n = ((INPLL(M_SPLL_REF_FB_DIV) >> 8) & 0xff);
6368c2ecf20Sopenharmony_ci		m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff);
6378c2ecf20Sopenharmony_ci		num = 2*n;
6388c2ecf20Sopenharmony_ci		denom = 2*m;
6398c2ecf20Sopenharmony_ci        break;
6408c2ecf20Sopenharmony_ci	}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3;
6438c2ecf20Sopenharmony_ci	radeon_pll_errata_after_index(rinfo);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	n = (INPLL(PPLL_DIV_0 + ppll_div_sel) & 0x7ff);
6468c2ecf20Sopenharmony_ci	m = (INPLL(PPLL_REF_DIV) & 0x3ff);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	num *= n;
6498c2ecf20Sopenharmony_ci	denom *= m;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	switch ((INPLL(PPLL_DIV_0 + ppll_div_sel) >> 16) & 0x7) {
6528c2ecf20Sopenharmony_ci	case 1:
6538c2ecf20Sopenharmony_ci		denom *= 2;
6548c2ecf20Sopenharmony_ci		break;
6558c2ecf20Sopenharmony_ci	case 2:
6568c2ecf20Sopenharmony_ci		denom *= 4;
6578c2ecf20Sopenharmony_ci		break;
6588c2ecf20Sopenharmony_ci	case 3:
6598c2ecf20Sopenharmony_ci		denom *= 8;
6608c2ecf20Sopenharmony_ci		break;
6618c2ecf20Sopenharmony_ci	case 4:
6628c2ecf20Sopenharmony_ci		denom *= 3;
6638c2ecf20Sopenharmony_ci		break;
6648c2ecf20Sopenharmony_ci	case 6:
6658c2ecf20Sopenharmony_ci		denom *= 6;
6668c2ecf20Sopenharmony_ci		break;
6678c2ecf20Sopenharmony_ci	case 7:
6688c2ecf20Sopenharmony_ci		denom *= 12;
6698c2ecf20Sopenharmony_ci		break;
6708c2ecf20Sopenharmony_ci	}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	vclk *= denom;
6738c2ecf20Sopenharmony_ci	do_div(vclk, 1000 * num);
6748c2ecf20Sopenharmony_ci	xtal = vclk;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	if ((xtal > 26900) && (xtal < 27100))
6778c2ecf20Sopenharmony_ci		xtal = 2700;
6788c2ecf20Sopenharmony_ci	else if ((xtal > 14200) && (xtal < 14400))
6798c2ecf20Sopenharmony_ci		xtal = 1432;
6808c2ecf20Sopenharmony_ci	else if ((xtal > 29400) && (xtal < 29600))
6818c2ecf20Sopenharmony_ci		xtal = 2950;
6828c2ecf20Sopenharmony_ci	else {
6838c2ecf20Sopenharmony_ci		printk(KERN_WARNING "xtal calculation failed: %ld\n", xtal);
6848c2ecf20Sopenharmony_ci		return -1;
6858c2ecf20Sopenharmony_ci	}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	tmp = INPLL(M_SPLL_REF_FB_DIV);
6888c2ecf20Sopenharmony_ci	ref_div = INPLL(PPLL_REF_DIV) & 0x3ff;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	Ns = (tmp & 0xff0000) >> 16;
6918c2ecf20Sopenharmony_ci	Nm = (tmp & 0xff00) >> 8;
6928c2ecf20Sopenharmony_ci	M = (tmp & 0xff);
6938c2ecf20Sopenharmony_ci	sclk = round_div((2 * Ns * xtal), (2 * M));
6948c2ecf20Sopenharmony_ci	mclk = round_div((2 * Nm * xtal), (2 * M));
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	/* we're done, hopefully these are sane values */
6978c2ecf20Sopenharmony_ci	rinfo->pll.ref_clk = xtal;
6988c2ecf20Sopenharmony_ci	rinfo->pll.ref_div = ref_div;
6998c2ecf20Sopenharmony_ci	rinfo->pll.sclk = sclk;
7008c2ecf20Sopenharmony_ci	rinfo->pll.mclk = mclk;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	return 0;
7038c2ecf20Sopenharmony_ci}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci/*
7068c2ecf20Sopenharmony_ci * Retrieve PLL infos by different means (BIOS, Open Firmware, register probing...)
7078c2ecf20Sopenharmony_ci */
7088c2ecf20Sopenharmony_cistatic void radeon_get_pllinfo(struct radeonfb_info *rinfo)
7098c2ecf20Sopenharmony_ci{
7108c2ecf20Sopenharmony_ci	/*
7118c2ecf20Sopenharmony_ci	 * In the case nothing works, these are defaults; they are mostly
7128c2ecf20Sopenharmony_ci	 * incomplete, however.  It does provide ppll_max and _min values
7138c2ecf20Sopenharmony_ci	 * even for most other methods, however.
7148c2ecf20Sopenharmony_ci	 */
7158c2ecf20Sopenharmony_ci	switch (rinfo->chipset) {
7168c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_QW:
7178c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_QX:
7188c2ecf20Sopenharmony_ci		rinfo->pll.ppll_max = 35000;
7198c2ecf20Sopenharmony_ci		rinfo->pll.ppll_min = 12000;
7208c2ecf20Sopenharmony_ci		rinfo->pll.mclk = 23000;
7218c2ecf20Sopenharmony_ci		rinfo->pll.sclk = 23000;
7228c2ecf20Sopenharmony_ci		rinfo->pll.ref_clk = 2700;
7238c2ecf20Sopenharmony_ci		break;
7248c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_QL:
7258c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_QN:
7268c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_QO:
7278c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_Ql:
7288c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_BB:
7298c2ecf20Sopenharmony_ci		rinfo->pll.ppll_max = 35000;
7308c2ecf20Sopenharmony_ci		rinfo->pll.ppll_min = 12000;
7318c2ecf20Sopenharmony_ci		rinfo->pll.mclk = 27500;
7328c2ecf20Sopenharmony_ci		rinfo->pll.sclk = 27500;
7338c2ecf20Sopenharmony_ci		rinfo->pll.ref_clk = 2700;
7348c2ecf20Sopenharmony_ci		break;
7358c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_Id:
7368c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_Ie:
7378c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_If:
7388c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_Ig:
7398c2ecf20Sopenharmony_ci		rinfo->pll.ppll_max = 35000;
7408c2ecf20Sopenharmony_ci		rinfo->pll.ppll_min = 12000;
7418c2ecf20Sopenharmony_ci		rinfo->pll.mclk = 25000;
7428c2ecf20Sopenharmony_ci		rinfo->pll.sclk = 25000;
7438c2ecf20Sopenharmony_ci		rinfo->pll.ref_clk = 2700;
7448c2ecf20Sopenharmony_ci		break;
7458c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_ND:
7468c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_NE:
7478c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_NF:
7488c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_NG:
7498c2ecf20Sopenharmony_ci		rinfo->pll.ppll_max = 40000;
7508c2ecf20Sopenharmony_ci		rinfo->pll.ppll_min = 20000;
7518c2ecf20Sopenharmony_ci		rinfo->pll.mclk = 27000;
7528c2ecf20Sopenharmony_ci		rinfo->pll.sclk = 27000;
7538c2ecf20Sopenharmony_ci		rinfo->pll.ref_clk = 2700;
7548c2ecf20Sopenharmony_ci		break;
7558c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_QD:
7568c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_QE:
7578c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_QF:
7588c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_ATI_RADEON_QG:
7598c2ecf20Sopenharmony_ci	default:
7608c2ecf20Sopenharmony_ci		rinfo->pll.ppll_max = 35000;
7618c2ecf20Sopenharmony_ci		rinfo->pll.ppll_min = 12000;
7628c2ecf20Sopenharmony_ci		rinfo->pll.mclk = 16600;
7638c2ecf20Sopenharmony_ci		rinfo->pll.sclk = 16600;
7648c2ecf20Sopenharmony_ci		rinfo->pll.ref_clk = 2700;
7658c2ecf20Sopenharmony_ci		break;
7668c2ecf20Sopenharmony_ci	}
7678c2ecf20Sopenharmony_ci	rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci#if defined(CONFIG_PPC) || defined(CONFIG_SPARC)
7718c2ecf20Sopenharmony_ci	/*
7728c2ecf20Sopenharmony_ci	 * Retrieve PLL infos from Open Firmware first
7738c2ecf20Sopenharmony_ci	 */
7748c2ecf20Sopenharmony_ci       	if (!force_measure_pll && radeon_read_xtal_OF(rinfo) == 0) {
7758c2ecf20Sopenharmony_ci       		printk(KERN_INFO "radeonfb: Retrieved PLL infos from Open Firmware\n");
7768c2ecf20Sopenharmony_ci		goto found;
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC || CONFIG_SPARC */
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	/*
7818c2ecf20Sopenharmony_ci	 * Check out if we have an X86 which gave us some PLL informations
7828c2ecf20Sopenharmony_ci	 * and if yes, retrieve them
7838c2ecf20Sopenharmony_ci	 */
7848c2ecf20Sopenharmony_ci	if (!force_measure_pll && rinfo->bios_seg) {
7858c2ecf20Sopenharmony_ci		u16 pll_info_block = BIOS_IN16(rinfo->fp_bios_start + 0x30);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci		rinfo->pll.sclk		= BIOS_IN16(pll_info_block + 0x08);
7888c2ecf20Sopenharmony_ci		rinfo->pll.mclk		= BIOS_IN16(pll_info_block + 0x0a);
7898c2ecf20Sopenharmony_ci		rinfo->pll.ref_clk	= BIOS_IN16(pll_info_block + 0x0e);
7908c2ecf20Sopenharmony_ci		rinfo->pll.ref_div	= BIOS_IN16(pll_info_block + 0x10);
7918c2ecf20Sopenharmony_ci		rinfo->pll.ppll_min	= BIOS_IN32(pll_info_block + 0x12);
7928c2ecf20Sopenharmony_ci		rinfo->pll.ppll_max	= BIOS_IN32(pll_info_block + 0x16);
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci		printk(KERN_INFO "radeonfb: Retrieved PLL infos from BIOS\n");
7958c2ecf20Sopenharmony_ci		goto found;
7968c2ecf20Sopenharmony_ci	}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	/*
7998c2ecf20Sopenharmony_ci	 * We didn't get PLL parameters from either OF or BIOS, we try to
8008c2ecf20Sopenharmony_ci	 * probe them
8018c2ecf20Sopenharmony_ci	 */
8028c2ecf20Sopenharmony_ci	if (radeon_probe_pll_params(rinfo) == 0) {
8038c2ecf20Sopenharmony_ci		printk(KERN_INFO "radeonfb: Retrieved PLL infos from registers\n");
8048c2ecf20Sopenharmony_ci		goto found;
8058c2ecf20Sopenharmony_ci	}
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	/*
8088c2ecf20Sopenharmony_ci	 * Fall back to already-set defaults...
8098c2ecf20Sopenharmony_ci	 */
8108c2ecf20Sopenharmony_ci       	printk(KERN_INFO "radeonfb: Used default PLL infos\n");
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_cifound:
8138c2ecf20Sopenharmony_ci	/*
8148c2ecf20Sopenharmony_ci	 * Some methods fail to retrieve SCLK and MCLK values, we apply default
8158c2ecf20Sopenharmony_ci	 * settings in this case (200Mhz). If that really happens often, we
8168c2ecf20Sopenharmony_ci	 * could fetch from registers instead...
8178c2ecf20Sopenharmony_ci	 */
8188c2ecf20Sopenharmony_ci	if (rinfo->pll.mclk == 0)
8198c2ecf20Sopenharmony_ci		rinfo->pll.mclk = 20000;
8208c2ecf20Sopenharmony_ci	if (rinfo->pll.sclk == 0)
8218c2ecf20Sopenharmony_ci		rinfo->pll.sclk = 20000;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	printk("radeonfb: Reference=%d.%02d MHz (RefDiv=%d) Memory=%d.%02d Mhz, System=%d.%02d MHz\n",
8248c2ecf20Sopenharmony_ci	       rinfo->pll.ref_clk / 100, rinfo->pll.ref_clk % 100,
8258c2ecf20Sopenharmony_ci	       rinfo->pll.ref_div,
8268c2ecf20Sopenharmony_ci	       rinfo->pll.mclk / 100, rinfo->pll.mclk % 100,
8278c2ecf20Sopenharmony_ci	       rinfo->pll.sclk / 100, rinfo->pll.sclk % 100);
8288c2ecf20Sopenharmony_ci	printk("radeonfb: PLL min %d max %d\n", rinfo->pll.ppll_min, rinfo->pll.ppll_max);
8298c2ecf20Sopenharmony_ci}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_cistatic int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info)
8328c2ecf20Sopenharmony_ci{
8338c2ecf20Sopenharmony_ci	struct radeonfb_info *rinfo = info->par;
8348c2ecf20Sopenharmony_ci        struct fb_var_screeninfo v;
8358c2ecf20Sopenharmony_ci        int nom, den;
8368c2ecf20Sopenharmony_ci	unsigned int pitch;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	if (radeon_match_mode(rinfo, &v, var))
8398c2ecf20Sopenharmony_ci		return -EINVAL;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci        switch (v.bits_per_pixel) {
8428c2ecf20Sopenharmony_ci		case 0 ... 8:
8438c2ecf20Sopenharmony_ci			v.bits_per_pixel = 8;
8448c2ecf20Sopenharmony_ci			break;
8458c2ecf20Sopenharmony_ci		case 9 ... 16:
8468c2ecf20Sopenharmony_ci			v.bits_per_pixel = 16;
8478c2ecf20Sopenharmony_ci			break;
8488c2ecf20Sopenharmony_ci		case 25 ... 32:
8498c2ecf20Sopenharmony_ci			v.bits_per_pixel = 32;
8508c2ecf20Sopenharmony_ci			break;
8518c2ecf20Sopenharmony_ci		default:
8528c2ecf20Sopenharmony_ci			return -EINVAL;
8538c2ecf20Sopenharmony_ci	}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	switch (var_to_depth(&v)) {
8568c2ecf20Sopenharmony_ci                case 8:
8578c2ecf20Sopenharmony_ci                        nom = den = 1;
8588c2ecf20Sopenharmony_ci                        v.red.offset = v.green.offset = v.blue.offset = 0;
8598c2ecf20Sopenharmony_ci                        v.red.length = v.green.length = v.blue.length = 8;
8608c2ecf20Sopenharmony_ci                        v.transp.offset = v.transp.length = 0;
8618c2ecf20Sopenharmony_ci                        break;
8628c2ecf20Sopenharmony_ci		case 15:
8638c2ecf20Sopenharmony_ci			nom = 2;
8648c2ecf20Sopenharmony_ci			den = 1;
8658c2ecf20Sopenharmony_ci			v.red.offset = 10;
8668c2ecf20Sopenharmony_ci			v.green.offset = 5;
8678c2ecf20Sopenharmony_ci			v.blue.offset = 0;
8688c2ecf20Sopenharmony_ci			v.red.length = v.green.length = v.blue.length = 5;
8698c2ecf20Sopenharmony_ci			v.transp.offset = v.transp.length = 0;
8708c2ecf20Sopenharmony_ci			break;
8718c2ecf20Sopenharmony_ci                case 16:
8728c2ecf20Sopenharmony_ci                        nom = 2;
8738c2ecf20Sopenharmony_ci                        den = 1;
8748c2ecf20Sopenharmony_ci                        v.red.offset = 11;
8758c2ecf20Sopenharmony_ci                        v.green.offset = 5;
8768c2ecf20Sopenharmony_ci                        v.blue.offset = 0;
8778c2ecf20Sopenharmony_ci                        v.red.length = 5;
8788c2ecf20Sopenharmony_ci                        v.green.length = 6;
8798c2ecf20Sopenharmony_ci                        v.blue.length = 5;
8808c2ecf20Sopenharmony_ci                        v.transp.offset = v.transp.length = 0;
8818c2ecf20Sopenharmony_ci                        break;
8828c2ecf20Sopenharmony_ci                case 24:
8838c2ecf20Sopenharmony_ci                        nom = 4;
8848c2ecf20Sopenharmony_ci                        den = 1;
8858c2ecf20Sopenharmony_ci                        v.red.offset = 16;
8868c2ecf20Sopenharmony_ci                        v.green.offset = 8;
8878c2ecf20Sopenharmony_ci                        v.blue.offset = 0;
8888c2ecf20Sopenharmony_ci                        v.red.length = v.blue.length = v.green.length = 8;
8898c2ecf20Sopenharmony_ci                        v.transp.offset = v.transp.length = 0;
8908c2ecf20Sopenharmony_ci                        break;
8918c2ecf20Sopenharmony_ci                case 32:
8928c2ecf20Sopenharmony_ci                        nom = 4;
8938c2ecf20Sopenharmony_ci                        den = 1;
8948c2ecf20Sopenharmony_ci                        v.red.offset = 16;
8958c2ecf20Sopenharmony_ci                        v.green.offset = 8;
8968c2ecf20Sopenharmony_ci                        v.blue.offset = 0;
8978c2ecf20Sopenharmony_ci                        v.red.length = v.blue.length = v.green.length = 8;
8988c2ecf20Sopenharmony_ci                        v.transp.offset = 24;
8998c2ecf20Sopenharmony_ci                        v.transp.length = 8;
9008c2ecf20Sopenharmony_ci                        break;
9018c2ecf20Sopenharmony_ci                default:
9028c2ecf20Sopenharmony_ci                        printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n",
9038c2ecf20Sopenharmony_ci                                var->xres, var->yres, var->bits_per_pixel);
9048c2ecf20Sopenharmony_ci                        return -EINVAL;
9058c2ecf20Sopenharmony_ci        }
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	if (v.yres_virtual < v.yres)
9088c2ecf20Sopenharmony_ci		v.yres_virtual = v.yres;
9098c2ecf20Sopenharmony_ci	if (v.xres_virtual < v.xres)
9108c2ecf20Sopenharmony_ci		v.xres_virtual = v.xres;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	/* XXX I'm adjusting xres_virtual to the pitch, that may help XFree
9148c2ecf20Sopenharmony_ci	 * with some panels, though I don't quite like this solution
9158c2ecf20Sopenharmony_ci	 */
9168c2ecf20Sopenharmony_ci  	if (rinfo->info->flags & FBINFO_HWACCEL_DISABLED) {
9178c2ecf20Sopenharmony_ci		v.xres_virtual = v.xres_virtual & ~7ul;
9188c2ecf20Sopenharmony_ci	} else {
9198c2ecf20Sopenharmony_ci		pitch = ((v.xres_virtual * ((v.bits_per_pixel + 1) / 8) + 0x3f)
9208c2ecf20Sopenharmony_ci 				& ~(0x3f)) >> 6;
9218c2ecf20Sopenharmony_ci		v.xres_virtual = (pitch << 6) / ((v.bits_per_pixel + 1) / 8);
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	if (((v.xres_virtual * v.yres_virtual * nom) / den) > rinfo->mapped_vram)
9258c2ecf20Sopenharmony_ci		return -EINVAL;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	if (v.xres_virtual < v.xres)
9288c2ecf20Sopenharmony_ci		v.xres = v.xres_virtual;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci        if (v.xoffset > v.xres_virtual - v.xres)
9318c2ecf20Sopenharmony_ci                v.xoffset = v.xres_virtual - v.xres - 1;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci        if (v.yoffset > v.yres_virtual - v.yres)
9348c2ecf20Sopenharmony_ci                v.yoffset = v.yres_virtual - v.yres - 1;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci        v.red.msb_right = v.green.msb_right = v.blue.msb_right =
9378c2ecf20Sopenharmony_ci                          v.transp.offset = v.transp.length =
9388c2ecf20Sopenharmony_ci                          v.transp.msb_right = 0;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci        memcpy(var, &v, sizeof(v));
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci        return 0;
9438c2ecf20Sopenharmony_ci}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_cistatic int radeonfb_pan_display (struct fb_var_screeninfo *var,
9478c2ecf20Sopenharmony_ci                                 struct fb_info *info)
9488c2ecf20Sopenharmony_ci{
9498c2ecf20Sopenharmony_ci        struct radeonfb_info *rinfo = info->par;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	if ((var->xoffset + info->var.xres > info->var.xres_virtual)
9528c2ecf20Sopenharmony_ci	    || (var->yoffset + info->var.yres > info->var.yres_virtual))
9538c2ecf20Sopenharmony_ci		return -EINVAL;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci        if (rinfo->asleep)
9568c2ecf20Sopenharmony_ci        	return 0;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	radeon_fifo_wait(2);
9598c2ecf20Sopenharmony_ci	OUTREG(CRTC_OFFSET, (var->yoffset * info->fix.line_length +
9608c2ecf20Sopenharmony_ci			     var->xoffset * info->var.bits_per_pixel / 8) & ~7);
9618c2ecf20Sopenharmony_ci        return 0;
9628c2ecf20Sopenharmony_ci}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_cistatic int radeonfb_ioctl (struct fb_info *info, unsigned int cmd,
9668c2ecf20Sopenharmony_ci                           unsigned long arg)
9678c2ecf20Sopenharmony_ci{
9688c2ecf20Sopenharmony_ci        struct radeonfb_info *rinfo = info->par;
9698c2ecf20Sopenharmony_ci	unsigned int tmp;
9708c2ecf20Sopenharmony_ci	u32 value = 0;
9718c2ecf20Sopenharmony_ci	int rc;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	switch (cmd) {
9748c2ecf20Sopenharmony_ci		/*
9758c2ecf20Sopenharmony_ci		 * TODO:  set mirror accordingly for non-Mobility chipsets with 2 CRTC's
9768c2ecf20Sopenharmony_ci		 *        and do something better using 2nd CRTC instead of just hackish
9778c2ecf20Sopenharmony_ci		 *        routing to second output
9788c2ecf20Sopenharmony_ci		 */
9798c2ecf20Sopenharmony_ci		case FBIO_RADEON_SET_MIRROR:
9808c2ecf20Sopenharmony_ci			if (!rinfo->is_mobility)
9818c2ecf20Sopenharmony_ci				return -EINVAL;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci			rc = get_user(value, (__u32 __user *)arg);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci			if (rc)
9868c2ecf20Sopenharmony_ci				return rc;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci			radeon_fifo_wait(2);
9898c2ecf20Sopenharmony_ci			if (value & 0x01) {
9908c2ecf20Sopenharmony_ci				tmp = INREG(LVDS_GEN_CNTL);
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci				tmp |= (LVDS_ON | LVDS_BLON);
9938c2ecf20Sopenharmony_ci			} else {
9948c2ecf20Sopenharmony_ci				tmp = INREG(LVDS_GEN_CNTL);
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci				tmp &= ~(LVDS_ON | LVDS_BLON);
9978c2ecf20Sopenharmony_ci			}
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci			OUTREG(LVDS_GEN_CNTL, tmp);
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci			if (value & 0x02) {
10028c2ecf20Sopenharmony_ci				tmp = INREG(CRTC_EXT_CNTL);
10038c2ecf20Sopenharmony_ci				tmp |= CRTC_CRT_ON;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci				mirror = 1;
10068c2ecf20Sopenharmony_ci			} else {
10078c2ecf20Sopenharmony_ci				tmp = INREG(CRTC_EXT_CNTL);
10088c2ecf20Sopenharmony_ci				tmp &= ~CRTC_CRT_ON;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci				mirror = 0;
10118c2ecf20Sopenharmony_ci			}
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci			OUTREG(CRTC_EXT_CNTL, tmp);
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci			return 0;
10168c2ecf20Sopenharmony_ci		case FBIO_RADEON_GET_MIRROR:
10178c2ecf20Sopenharmony_ci			if (!rinfo->is_mobility)
10188c2ecf20Sopenharmony_ci				return -EINVAL;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci			tmp = INREG(LVDS_GEN_CNTL);
10218c2ecf20Sopenharmony_ci			if ((LVDS_ON | LVDS_BLON) & tmp)
10228c2ecf20Sopenharmony_ci				value |= 0x01;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci			tmp = INREG(CRTC_EXT_CNTL);
10258c2ecf20Sopenharmony_ci			if (CRTC_CRT_ON & tmp)
10268c2ecf20Sopenharmony_ci				value |= 0x02;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci			return put_user(value, (__u32 __user *)arg);
10298c2ecf20Sopenharmony_ci		default:
10308c2ecf20Sopenharmony_ci			return -EINVAL;
10318c2ecf20Sopenharmony_ci	}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	return -EINVAL;
10348c2ecf20Sopenharmony_ci}
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ciint radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch)
10388c2ecf20Sopenharmony_ci{
10398c2ecf20Sopenharmony_ci        u32 val;
10408c2ecf20Sopenharmony_ci	u32 tmp_pix_clks;
10418c2ecf20Sopenharmony_ci	int unblank = 0;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	if (rinfo->lock_blank)
10448c2ecf20Sopenharmony_ci		return 0;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	radeon_engine_idle();
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	val = INREG(CRTC_EXT_CNTL);
10498c2ecf20Sopenharmony_ci        val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |
10508c2ecf20Sopenharmony_ci                 CRTC_VSYNC_DIS);
10518c2ecf20Sopenharmony_ci        switch (blank) {
10528c2ecf20Sopenharmony_ci	case FB_BLANK_VSYNC_SUSPEND:
10538c2ecf20Sopenharmony_ci		val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS);
10548c2ecf20Sopenharmony_ci		break;
10558c2ecf20Sopenharmony_ci	case FB_BLANK_HSYNC_SUSPEND:
10568c2ecf20Sopenharmony_ci		val |= (CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS);
10578c2ecf20Sopenharmony_ci		break;
10588c2ecf20Sopenharmony_ci	case FB_BLANK_POWERDOWN:
10598c2ecf20Sopenharmony_ci		val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS |
10608c2ecf20Sopenharmony_ci			CRTC_HSYNC_DIS);
10618c2ecf20Sopenharmony_ci		break;
10628c2ecf20Sopenharmony_ci	case FB_BLANK_NORMAL:
10638c2ecf20Sopenharmony_ci		val |= CRTC_DISPLAY_DIS;
10648c2ecf20Sopenharmony_ci		break;
10658c2ecf20Sopenharmony_ci	case FB_BLANK_UNBLANK:
10668c2ecf20Sopenharmony_ci	default:
10678c2ecf20Sopenharmony_ci		unblank = 1;
10688c2ecf20Sopenharmony_ci        }
10698c2ecf20Sopenharmony_ci	OUTREG(CRTC_EXT_CNTL, val);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	switch (rinfo->mon1_type) {
10738c2ecf20Sopenharmony_ci	case MT_DFP:
10748c2ecf20Sopenharmony_ci		if (unblank)
10758c2ecf20Sopenharmony_ci			OUTREGP(FP_GEN_CNTL, (FP_FPON | FP_TMDS_EN),
10768c2ecf20Sopenharmony_ci				~(FP_FPON | FP_TMDS_EN));
10778c2ecf20Sopenharmony_ci		else {
10788c2ecf20Sopenharmony_ci			if (mode_switch || blank == FB_BLANK_NORMAL)
10798c2ecf20Sopenharmony_ci				break;
10808c2ecf20Sopenharmony_ci			OUTREGP(FP_GEN_CNTL, 0, ~(FP_FPON | FP_TMDS_EN));
10818c2ecf20Sopenharmony_ci		}
10828c2ecf20Sopenharmony_ci		break;
10838c2ecf20Sopenharmony_ci	case MT_LCD:
10848c2ecf20Sopenharmony_ci		del_timer_sync(&rinfo->lvds_timer);
10858c2ecf20Sopenharmony_ci		val = INREG(LVDS_GEN_CNTL);
10868c2ecf20Sopenharmony_ci		if (unblank) {
10878c2ecf20Sopenharmony_ci			u32 target_val = (val & ~LVDS_DISPLAY_DIS) | LVDS_BLON | LVDS_ON
10888c2ecf20Sopenharmony_ci				| LVDS_EN | (rinfo->init_state.lvds_gen_cntl
10898c2ecf20Sopenharmony_ci					     & (LVDS_DIGON | LVDS_BL_MOD_EN));
10908c2ecf20Sopenharmony_ci			if ((val ^ target_val) == LVDS_DISPLAY_DIS)
10918c2ecf20Sopenharmony_ci				OUTREG(LVDS_GEN_CNTL, target_val);
10928c2ecf20Sopenharmony_ci			else if ((val ^ target_val) != 0) {
10938c2ecf20Sopenharmony_ci				OUTREG(LVDS_GEN_CNTL, target_val
10948c2ecf20Sopenharmony_ci				       & ~(LVDS_ON | LVDS_BL_MOD_EN));
10958c2ecf20Sopenharmony_ci				rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
10968c2ecf20Sopenharmony_ci				rinfo->init_state.lvds_gen_cntl |=
10978c2ecf20Sopenharmony_ci					target_val & LVDS_STATE_MASK;
10988c2ecf20Sopenharmony_ci				if (mode_switch) {
10998c2ecf20Sopenharmony_ci					radeon_msleep(rinfo->panel_info.pwr_delay);
11008c2ecf20Sopenharmony_ci					OUTREG(LVDS_GEN_CNTL, target_val);
11018c2ecf20Sopenharmony_ci				}
11028c2ecf20Sopenharmony_ci				else {
11038c2ecf20Sopenharmony_ci					rinfo->pending_lvds_gen_cntl = target_val;
11048c2ecf20Sopenharmony_ci					mod_timer(&rinfo->lvds_timer,
11058c2ecf20Sopenharmony_ci					   jiffies +
11068c2ecf20Sopenharmony_ci					   msecs_to_jiffies(rinfo->panel_info.pwr_delay));
11078c2ecf20Sopenharmony_ci				}
11088c2ecf20Sopenharmony_ci			}
11098c2ecf20Sopenharmony_ci		} else {
11108c2ecf20Sopenharmony_ci			val |= LVDS_DISPLAY_DIS;
11118c2ecf20Sopenharmony_ci			OUTREG(LVDS_GEN_CNTL, val);
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci			/* We don't do a full switch-off on a simple mode switch */
11148c2ecf20Sopenharmony_ci			if (mode_switch || blank == FB_BLANK_NORMAL)
11158c2ecf20Sopenharmony_ci				break;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci			/* Asic bug, when turning off LVDS_ON, we have to make sure
11188c2ecf20Sopenharmony_ci			 * RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
11198c2ecf20Sopenharmony_ci			 */
11208c2ecf20Sopenharmony_ci			tmp_pix_clks = INPLL(PIXCLKS_CNTL);
11218c2ecf20Sopenharmony_ci			if (rinfo->is_mobility || rinfo->is_IGP)
11228c2ecf20Sopenharmony_ci				OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
11238c2ecf20Sopenharmony_ci			val &= ~(LVDS_BL_MOD_EN);
11248c2ecf20Sopenharmony_ci			OUTREG(LVDS_GEN_CNTL, val);
11258c2ecf20Sopenharmony_ci			udelay(100);
11268c2ecf20Sopenharmony_ci			val &= ~(LVDS_ON | LVDS_EN);
11278c2ecf20Sopenharmony_ci			OUTREG(LVDS_GEN_CNTL, val);
11288c2ecf20Sopenharmony_ci			val &= ~LVDS_DIGON;
11298c2ecf20Sopenharmony_ci			rinfo->pending_lvds_gen_cntl = val;
11308c2ecf20Sopenharmony_ci			mod_timer(&rinfo->lvds_timer,
11318c2ecf20Sopenharmony_ci				  jiffies +
11328c2ecf20Sopenharmony_ci				  msecs_to_jiffies(rinfo->panel_info.pwr_delay));
11338c2ecf20Sopenharmony_ci			rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
11348c2ecf20Sopenharmony_ci			rinfo->init_state.lvds_gen_cntl |= val & LVDS_STATE_MASK;
11358c2ecf20Sopenharmony_ci			if (rinfo->is_mobility || rinfo->is_IGP)
11368c2ecf20Sopenharmony_ci				OUTPLL(PIXCLKS_CNTL, tmp_pix_clks);
11378c2ecf20Sopenharmony_ci		}
11388c2ecf20Sopenharmony_ci		break;
11398c2ecf20Sopenharmony_ci	case MT_CRT:
11408c2ecf20Sopenharmony_ci		// todo: powerdown DAC
11418c2ecf20Sopenharmony_ci	default:
11428c2ecf20Sopenharmony_ci		break;
11438c2ecf20Sopenharmony_ci	}
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	return 0;
11468c2ecf20Sopenharmony_ci}
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_cistatic int radeonfb_blank (int blank, struct fb_info *info)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci        struct radeonfb_info *rinfo = info->par;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	if (rinfo->asleep)
11538c2ecf20Sopenharmony_ci		return 0;
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	return radeon_screen_blank(rinfo, blank, 0);
11568c2ecf20Sopenharmony_ci}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_cistatic int radeon_setcolreg (unsigned regno, unsigned red, unsigned green,
11598c2ecf20Sopenharmony_ci                             unsigned blue, unsigned transp,
11608c2ecf20Sopenharmony_ci			     struct radeonfb_info *rinfo)
11618c2ecf20Sopenharmony_ci{
11628c2ecf20Sopenharmony_ci	u32 pindex;
11638c2ecf20Sopenharmony_ci	unsigned int i;
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	if (regno > 255)
11678c2ecf20Sopenharmony_ci		return -EINVAL;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	red >>= 8;
11708c2ecf20Sopenharmony_ci	green >>= 8;
11718c2ecf20Sopenharmony_ci	blue >>= 8;
11728c2ecf20Sopenharmony_ci	rinfo->palette[regno].red = red;
11738c2ecf20Sopenharmony_ci	rinfo->palette[regno].green = green;
11748c2ecf20Sopenharmony_ci	rinfo->palette[regno].blue = blue;
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci        /* default */
11778c2ecf20Sopenharmony_ci        pindex = regno;
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci        if (!rinfo->asleep) {
11808c2ecf20Sopenharmony_ci		radeon_fifo_wait(9);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci		if (rinfo->bpp == 16) {
11838c2ecf20Sopenharmony_ci			pindex = regno * 8;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci			if (rinfo->depth == 16 && regno > 63)
11868c2ecf20Sopenharmony_ci				return -EINVAL;
11878c2ecf20Sopenharmony_ci			if (rinfo->depth == 15 && regno > 31)
11888c2ecf20Sopenharmony_ci				return -EINVAL;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci			/* For 565, the green component is mixed one order
11918c2ecf20Sopenharmony_ci			 * below
11928c2ecf20Sopenharmony_ci			 */
11938c2ecf20Sopenharmony_ci			if (rinfo->depth == 16) {
11948c2ecf20Sopenharmony_ci		                OUTREG(PALETTE_INDEX, pindex>>1);
11958c2ecf20Sopenharmony_ci	       	         	OUTREG(PALETTE_DATA,
11968c2ecf20Sopenharmony_ci				       (rinfo->palette[regno>>1].red << 16) |
11978c2ecf20Sopenharmony_ci	                        	(green << 8) |
11988c2ecf20Sopenharmony_ci				       (rinfo->palette[regno>>1].blue));
11998c2ecf20Sopenharmony_ci	                	green = rinfo->palette[regno<<1].green;
12008c2ecf20Sopenharmony_ci	        	}
12018c2ecf20Sopenharmony_ci		}
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci		if (rinfo->depth != 16 || regno < 32) {
12048c2ecf20Sopenharmony_ci			OUTREG(PALETTE_INDEX, pindex);
12058c2ecf20Sopenharmony_ci			OUTREG(PALETTE_DATA, (red << 16) |
12068c2ecf20Sopenharmony_ci			       (green << 8) | blue);
12078c2ecf20Sopenharmony_ci		}
12088c2ecf20Sopenharmony_ci	}
12098c2ecf20Sopenharmony_ci 	if (regno < 16) {
12108c2ecf20Sopenharmony_ci		u32 *pal = rinfo->info->pseudo_palette;
12118c2ecf20Sopenharmony_ci        	switch (rinfo->depth) {
12128c2ecf20Sopenharmony_ci		case 15:
12138c2ecf20Sopenharmony_ci			pal[regno] = (regno << 10) | (regno << 5) | regno;
12148c2ecf20Sopenharmony_ci			break;
12158c2ecf20Sopenharmony_ci		case 16:
12168c2ecf20Sopenharmony_ci			pal[regno] = (regno << 11) | (regno << 5) | regno;
12178c2ecf20Sopenharmony_ci			break;
12188c2ecf20Sopenharmony_ci		case 24:
12198c2ecf20Sopenharmony_ci			pal[regno] = (regno << 16) | (regno << 8) | regno;
12208c2ecf20Sopenharmony_ci			break;
12218c2ecf20Sopenharmony_ci		case 32:
12228c2ecf20Sopenharmony_ci			i = (regno << 8) | regno;
12238c2ecf20Sopenharmony_ci			pal[regno] = (i << 16) | i;
12248c2ecf20Sopenharmony_ci			break;
12258c2ecf20Sopenharmony_ci		}
12268c2ecf20Sopenharmony_ci        }
12278c2ecf20Sopenharmony_ci	return 0;
12288c2ecf20Sopenharmony_ci}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_cistatic int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
12318c2ecf20Sopenharmony_ci			       unsigned blue, unsigned transp,
12328c2ecf20Sopenharmony_ci			       struct fb_info *info)
12338c2ecf20Sopenharmony_ci{
12348c2ecf20Sopenharmony_ci        struct radeonfb_info *rinfo = info->par;
12358c2ecf20Sopenharmony_ci	u32 dac_cntl2, vclk_cntl = 0;
12368c2ecf20Sopenharmony_ci	int rc;
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci        if (!rinfo->asleep) {
12398c2ecf20Sopenharmony_ci		if (rinfo->is_mobility) {
12408c2ecf20Sopenharmony_ci			vclk_cntl = INPLL(VCLK_ECP_CNTL);
12418c2ecf20Sopenharmony_ci			OUTPLL(VCLK_ECP_CNTL,
12428c2ecf20Sopenharmony_ci			       vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
12438c2ecf20Sopenharmony_ci		}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci		/* Make sure we are on first palette */
12468c2ecf20Sopenharmony_ci		if (rinfo->has_CRTC2) {
12478c2ecf20Sopenharmony_ci			dac_cntl2 = INREG(DAC_CNTL2);
12488c2ecf20Sopenharmony_ci			dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;
12498c2ecf20Sopenharmony_ci			OUTREG(DAC_CNTL2, dac_cntl2);
12508c2ecf20Sopenharmony_ci		}
12518c2ecf20Sopenharmony_ci	}
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	rc = radeon_setcolreg (regno, red, green, blue, transp, rinfo);
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	if (!rinfo->asleep && rinfo->is_mobility)
12568c2ecf20Sopenharmony_ci		OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	return rc;
12598c2ecf20Sopenharmony_ci}
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_cistatic int radeonfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
12628c2ecf20Sopenharmony_ci{
12638c2ecf20Sopenharmony_ci        struct radeonfb_info *rinfo = info->par;
12648c2ecf20Sopenharmony_ci	u16 *red, *green, *blue, *transp;
12658c2ecf20Sopenharmony_ci	u32 dac_cntl2, vclk_cntl = 0;
12668c2ecf20Sopenharmony_ci	int i, start, rc = 0;
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci        if (!rinfo->asleep) {
12698c2ecf20Sopenharmony_ci		if (rinfo->is_mobility) {
12708c2ecf20Sopenharmony_ci			vclk_cntl = INPLL(VCLK_ECP_CNTL);
12718c2ecf20Sopenharmony_ci			OUTPLL(VCLK_ECP_CNTL,
12728c2ecf20Sopenharmony_ci			       vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
12738c2ecf20Sopenharmony_ci		}
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci		/* Make sure we are on first palette */
12768c2ecf20Sopenharmony_ci		if (rinfo->has_CRTC2) {
12778c2ecf20Sopenharmony_ci			dac_cntl2 = INREG(DAC_CNTL2);
12788c2ecf20Sopenharmony_ci			dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;
12798c2ecf20Sopenharmony_ci			OUTREG(DAC_CNTL2, dac_cntl2);
12808c2ecf20Sopenharmony_ci		}
12818c2ecf20Sopenharmony_ci	}
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	red = cmap->red;
12848c2ecf20Sopenharmony_ci	green = cmap->green;
12858c2ecf20Sopenharmony_ci	blue = cmap->blue;
12868c2ecf20Sopenharmony_ci	transp = cmap->transp;
12878c2ecf20Sopenharmony_ci	start = cmap->start;
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	for (i = 0; i < cmap->len; i++) {
12908c2ecf20Sopenharmony_ci		u_int hred, hgreen, hblue, htransp = 0xffff;
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci		hred = *red++;
12938c2ecf20Sopenharmony_ci		hgreen = *green++;
12948c2ecf20Sopenharmony_ci		hblue = *blue++;
12958c2ecf20Sopenharmony_ci		if (transp)
12968c2ecf20Sopenharmony_ci			htransp = *transp++;
12978c2ecf20Sopenharmony_ci		rc = radeon_setcolreg (start++, hred, hgreen, hblue, htransp,
12988c2ecf20Sopenharmony_ci				       rinfo);
12998c2ecf20Sopenharmony_ci		if (rc)
13008c2ecf20Sopenharmony_ci			break;
13018c2ecf20Sopenharmony_ci	}
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	if (!rinfo->asleep && rinfo->is_mobility)
13048c2ecf20Sopenharmony_ci		OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	return rc;
13078c2ecf20Sopenharmony_ci}
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_cistatic void radeon_save_state (struct radeonfb_info *rinfo,
13108c2ecf20Sopenharmony_ci			       struct radeon_regs *save)
13118c2ecf20Sopenharmony_ci{
13128c2ecf20Sopenharmony_ci	/* CRTC regs */
13138c2ecf20Sopenharmony_ci	save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
13148c2ecf20Sopenharmony_ci	save->crtc_ext_cntl = INREG(CRTC_EXT_CNTL);
13158c2ecf20Sopenharmony_ci	save->crtc_more_cntl = INREG(CRTC_MORE_CNTL);
13168c2ecf20Sopenharmony_ci	save->dac_cntl = INREG(DAC_CNTL);
13178c2ecf20Sopenharmony_ci        save->crtc_h_total_disp = INREG(CRTC_H_TOTAL_DISP);
13188c2ecf20Sopenharmony_ci        save->crtc_h_sync_strt_wid = INREG(CRTC_H_SYNC_STRT_WID);
13198c2ecf20Sopenharmony_ci        save->crtc_v_total_disp = INREG(CRTC_V_TOTAL_DISP);
13208c2ecf20Sopenharmony_ci        save->crtc_v_sync_strt_wid = INREG(CRTC_V_SYNC_STRT_WID);
13218c2ecf20Sopenharmony_ci	save->crtc_pitch = INREG(CRTC_PITCH);
13228c2ecf20Sopenharmony_ci	save->surface_cntl = INREG(SURFACE_CNTL);
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	/* FP regs */
13258c2ecf20Sopenharmony_ci	save->fp_crtc_h_total_disp = INREG(FP_CRTC_H_TOTAL_DISP);
13268c2ecf20Sopenharmony_ci	save->fp_crtc_v_total_disp = INREG(FP_CRTC_V_TOTAL_DISP);
13278c2ecf20Sopenharmony_ci	save->fp_gen_cntl = INREG(FP_GEN_CNTL);
13288c2ecf20Sopenharmony_ci	save->fp_h_sync_strt_wid = INREG(FP_H_SYNC_STRT_WID);
13298c2ecf20Sopenharmony_ci	save->fp_horz_stretch = INREG(FP_HORZ_STRETCH);
13308c2ecf20Sopenharmony_ci	save->fp_v_sync_strt_wid = INREG(FP_V_SYNC_STRT_WID);
13318c2ecf20Sopenharmony_ci	save->fp_vert_stretch = INREG(FP_VERT_STRETCH);
13328c2ecf20Sopenharmony_ci	save->lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
13338c2ecf20Sopenharmony_ci	save->lvds_pll_cntl = INREG(LVDS_PLL_CNTL);
13348c2ecf20Sopenharmony_ci	save->tmds_crc = INREG(TMDS_CRC);
13358c2ecf20Sopenharmony_ci	save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL);
13368c2ecf20Sopenharmony_ci	save->vclk_ecp_cntl = INPLL(VCLK_ECP_CNTL);
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	/* PLL regs */
13398c2ecf20Sopenharmony_ci	save->clk_cntl_index = INREG(CLOCK_CNTL_INDEX) & ~0x3f;
13408c2ecf20Sopenharmony_ci	radeon_pll_errata_after_index(rinfo);
13418c2ecf20Sopenharmony_ci	save->ppll_div_3 = INPLL(PPLL_DIV_3);
13428c2ecf20Sopenharmony_ci	save->ppll_ref_div = INPLL(PPLL_REF_DIV);
13438c2ecf20Sopenharmony_ci}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_cistatic void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *mode)
13478c2ecf20Sopenharmony_ci{
13488c2ecf20Sopenharmony_ci	int i;
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	radeon_fifo_wait(20);
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	/* Workaround from XFree */
13538c2ecf20Sopenharmony_ci	if (rinfo->is_mobility) {
13548c2ecf20Sopenharmony_ci	        /* A temporal workaround for the occasional blanking on certain laptop
13558c2ecf20Sopenharmony_ci		 * panels. This appears to related to the PLL divider registers
13568c2ecf20Sopenharmony_ci		 * (fail to lock?). It occurs even when all dividers are the same
13578c2ecf20Sopenharmony_ci		 * with their old settings. In this case we really don't need to
13588c2ecf20Sopenharmony_ci		 * fiddle with PLL registers. By doing this we can avoid the blanking
13598c2ecf20Sopenharmony_ci		 * problem with some panels.
13608c2ecf20Sopenharmony_ci	         */
13618c2ecf20Sopenharmony_ci		if ((mode->ppll_ref_div == (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK)) &&
13628c2ecf20Sopenharmony_ci		    (mode->ppll_div_3 == (INPLL(PPLL_DIV_3) &
13638c2ecf20Sopenharmony_ci					  (PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK)))) {
13648c2ecf20Sopenharmony_ci			/* We still have to force a switch to selected PPLL div thanks to
13658c2ecf20Sopenharmony_ci			 * an XFree86 driver bug which will switch it away in some cases
13668c2ecf20Sopenharmony_ci			 * even when using UseFDev */
13678c2ecf20Sopenharmony_ci			OUTREGP(CLOCK_CNTL_INDEX,
13688c2ecf20Sopenharmony_ci				mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
13698c2ecf20Sopenharmony_ci				~PPLL_DIV_SEL_MASK);
13708c2ecf20Sopenharmony_ci			radeon_pll_errata_after_index(rinfo);
13718c2ecf20Sopenharmony_ci			radeon_pll_errata_after_data(rinfo);
13728c2ecf20Sopenharmony_ci            		return;
13738c2ecf20Sopenharmony_ci		}
13748c2ecf20Sopenharmony_ci	}
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	/* Swich VCKL clock input to CPUCLK so it stays fed while PPLL updates*/
13778c2ecf20Sopenharmony_ci	OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_CPUCLK, ~VCLK_SRC_SEL_MASK);
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	/* Reset PPLL & enable atomic update */
13808c2ecf20Sopenharmony_ci	OUTPLLP(PPLL_CNTL,
13818c2ecf20Sopenharmony_ci		PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN,
13828c2ecf20Sopenharmony_ci		~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci	/* Switch to selected PPLL divider */
13858c2ecf20Sopenharmony_ci	OUTREGP(CLOCK_CNTL_INDEX,
13868c2ecf20Sopenharmony_ci		mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
13878c2ecf20Sopenharmony_ci		~PPLL_DIV_SEL_MASK);
13888c2ecf20Sopenharmony_ci	radeon_pll_errata_after_index(rinfo);
13898c2ecf20Sopenharmony_ci	radeon_pll_errata_after_data(rinfo);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	/* Set PPLL ref. div */
13928c2ecf20Sopenharmony_ci	if (IS_R300_VARIANT(rinfo) ||
13938c2ecf20Sopenharmony_ci	    rinfo->family == CHIP_FAMILY_RS300 ||
13948c2ecf20Sopenharmony_ci	    rinfo->family == CHIP_FAMILY_RS400 ||
13958c2ecf20Sopenharmony_ci	    rinfo->family == CHIP_FAMILY_RS480) {
13968c2ecf20Sopenharmony_ci		if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
13978c2ecf20Sopenharmony_ci			/* When restoring console mode, use saved PPLL_REF_DIV
13988c2ecf20Sopenharmony_ci			 * setting.
13998c2ecf20Sopenharmony_ci			 */
14008c2ecf20Sopenharmony_ci			OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, 0);
14018c2ecf20Sopenharmony_ci		} else {
14028c2ecf20Sopenharmony_ci			/* R300 uses ref_div_acc field as real ref divider */
14038c2ecf20Sopenharmony_ci			OUTPLLP(PPLL_REF_DIV,
14048c2ecf20Sopenharmony_ci				(mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
14058c2ecf20Sopenharmony_ci				~R300_PPLL_REF_DIV_ACC_MASK);
14068c2ecf20Sopenharmony_ci		}
14078c2ecf20Sopenharmony_ci	} else
14088c2ecf20Sopenharmony_ci		OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK);
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	/* Set PPLL divider 3 & post divider*/
14118c2ecf20Sopenharmony_ci	OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK);
14128c2ecf20Sopenharmony_ci	OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK);
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	/* Write update */
14158c2ecf20Sopenharmony_ci	while (INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R)
14168c2ecf20Sopenharmony_ci		;
14178c2ecf20Sopenharmony_ci	OUTPLLP(PPLL_REF_DIV, PPLL_ATOMIC_UPDATE_W, ~PPLL_ATOMIC_UPDATE_W);
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	/* Wait read update complete */
14208c2ecf20Sopenharmony_ci	/* FIXME: Certain revisions of R300 can't recover here.  Not sure of
14218c2ecf20Sopenharmony_ci	   the cause yet, but this workaround will mask the problem for now.
14228c2ecf20Sopenharmony_ci	   Other chips usually will pass at the very first test, so the
14238c2ecf20Sopenharmony_ci	   workaround shouldn't have any effect on them. */
14248c2ecf20Sopenharmony_ci	for (i = 0; (i < 10000 && INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); i++)
14258c2ecf20Sopenharmony_ci		;
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	OUTPLL(HTOTAL_CNTL, 0);
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	/* Clear reset & atomic update */
14308c2ecf20Sopenharmony_ci	OUTPLLP(PPLL_CNTL, 0,
14318c2ecf20Sopenharmony_ci		~(PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	/* We may want some locking ... oh well */
14348c2ecf20Sopenharmony_ci       	radeon_msleep(5);
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	/* Switch back VCLK source to PPLL */
14378c2ecf20Sopenharmony_ci	OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_PPLLCLK, ~VCLK_SRC_SEL_MASK);
14388c2ecf20Sopenharmony_ci}
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci/*
14418c2ecf20Sopenharmony_ci * Timer function for delayed LVDS panel power up/down
14428c2ecf20Sopenharmony_ci */
14438c2ecf20Sopenharmony_cistatic void radeon_lvds_timer_func(struct timer_list *t)
14448c2ecf20Sopenharmony_ci{
14458c2ecf20Sopenharmony_ci	struct radeonfb_info *rinfo = from_timer(rinfo, t, lvds_timer);
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	radeon_engine_idle();
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	OUTREG(LVDS_GEN_CNTL, rinfo->pending_lvds_gen_cntl);
14508c2ecf20Sopenharmony_ci}
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci/*
14538c2ecf20Sopenharmony_ci * Apply a video mode. This will apply the whole register set, including
14548c2ecf20Sopenharmony_ci * the PLL registers, to the card
14558c2ecf20Sopenharmony_ci */
14568c2ecf20Sopenharmony_civoid radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
14578c2ecf20Sopenharmony_ci			int regs_only)
14588c2ecf20Sopenharmony_ci{
14598c2ecf20Sopenharmony_ci	int i;
14608c2ecf20Sopenharmony_ci	int primary_mon = PRIMARY_MONITOR(rinfo);
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	if (nomodeset)
14638c2ecf20Sopenharmony_ci		return;
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	if (!regs_only)
14668c2ecf20Sopenharmony_ci		radeon_screen_blank(rinfo, FB_BLANK_NORMAL, 0);
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	radeon_fifo_wait(31);
14698c2ecf20Sopenharmony_ci	for (i=0; i<10; i++)
14708c2ecf20Sopenharmony_ci		OUTREG(common_regs[i].reg, common_regs[i].val);
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	/* Apply surface registers */
14738c2ecf20Sopenharmony_ci	for (i=0; i<8; i++) {
14748c2ecf20Sopenharmony_ci		OUTREG(SURFACE0_LOWER_BOUND + 0x10*i, mode->surf_lower_bound[i]);
14758c2ecf20Sopenharmony_ci		OUTREG(SURFACE0_UPPER_BOUND + 0x10*i, mode->surf_upper_bound[i]);
14768c2ecf20Sopenharmony_ci		OUTREG(SURFACE0_INFO + 0x10*i, mode->surf_info[i]);
14778c2ecf20Sopenharmony_ci	}
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
14808c2ecf20Sopenharmony_ci	OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
14818c2ecf20Sopenharmony_ci		~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));
14828c2ecf20Sopenharmony_ci	OUTREG(CRTC_MORE_CNTL, mode->crtc_more_cntl);
14838c2ecf20Sopenharmony_ci	OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
14848c2ecf20Sopenharmony_ci	OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
14858c2ecf20Sopenharmony_ci	OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
14868c2ecf20Sopenharmony_ci	OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
14878c2ecf20Sopenharmony_ci	OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
14888c2ecf20Sopenharmony_ci	OUTREG(CRTC_OFFSET, 0);
14898c2ecf20Sopenharmony_ci	OUTREG(CRTC_OFFSET_CNTL, 0);
14908c2ecf20Sopenharmony_ci	OUTREG(CRTC_PITCH, mode->crtc_pitch);
14918c2ecf20Sopenharmony_ci	OUTREG(SURFACE_CNTL, mode->surface_cntl);
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci	radeon_write_pll_regs(rinfo, mode);
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
14968c2ecf20Sopenharmony_ci		radeon_fifo_wait(10);
14978c2ecf20Sopenharmony_ci		OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp);
14988c2ecf20Sopenharmony_ci		OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp);
14998c2ecf20Sopenharmony_ci		OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid);
15008c2ecf20Sopenharmony_ci		OUTREG(FP_V_SYNC_STRT_WID, mode->fp_v_sync_strt_wid);
15018c2ecf20Sopenharmony_ci		OUTREG(FP_HORZ_STRETCH, mode->fp_horz_stretch);
15028c2ecf20Sopenharmony_ci		OUTREG(FP_VERT_STRETCH, mode->fp_vert_stretch);
15038c2ecf20Sopenharmony_ci		OUTREG(FP_GEN_CNTL, mode->fp_gen_cntl);
15048c2ecf20Sopenharmony_ci		OUTREG(TMDS_CRC, mode->tmds_crc);
15058c2ecf20Sopenharmony_ci		OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl);
15068c2ecf20Sopenharmony_ci	}
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	if (!regs_only)
15098c2ecf20Sopenharmony_ci		radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 0);
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	radeon_fifo_wait(2);
15128c2ecf20Sopenharmony_ci	OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl);
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	return;
15158c2ecf20Sopenharmony_ci}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci/*
15188c2ecf20Sopenharmony_ci * Calculate the PLL values for a given mode
15198c2ecf20Sopenharmony_ci */
15208c2ecf20Sopenharmony_cistatic void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *regs,
15218c2ecf20Sopenharmony_ci				 unsigned long freq)
15228c2ecf20Sopenharmony_ci{
15238c2ecf20Sopenharmony_ci	static const struct {
15248c2ecf20Sopenharmony_ci		int divider;
15258c2ecf20Sopenharmony_ci		int bitvalue;
15268c2ecf20Sopenharmony_ci	} *post_div,
15278c2ecf20Sopenharmony_ci	  post_divs[] = {
15288c2ecf20Sopenharmony_ci		{ 1,  0 },
15298c2ecf20Sopenharmony_ci		{ 2,  1 },
15308c2ecf20Sopenharmony_ci		{ 4,  2 },
15318c2ecf20Sopenharmony_ci		{ 8,  3 },
15328c2ecf20Sopenharmony_ci		{ 3,  4 },
15338c2ecf20Sopenharmony_ci		{ 16, 5 },
15348c2ecf20Sopenharmony_ci		{ 6,  6 },
15358c2ecf20Sopenharmony_ci		{ 12, 7 },
15368c2ecf20Sopenharmony_ci		{ 0,  0 },
15378c2ecf20Sopenharmony_ci	};
15388c2ecf20Sopenharmony_ci	int fb_div, pll_output_freq = 0;
15398c2ecf20Sopenharmony_ci	int uses_dvo = 0;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	/* Check if the DVO port is enabled and sourced from the primary CRTC. I'm
15428c2ecf20Sopenharmony_ci	 * not sure which model starts having FP2_GEN_CNTL, I assume anything more
15438c2ecf20Sopenharmony_ci	 * recent than an r(v)100...
15448c2ecf20Sopenharmony_ci	 */
15458c2ecf20Sopenharmony_ci#if 1
15468c2ecf20Sopenharmony_ci	/* XXX I had reports of flicker happening with the cinema display
15478c2ecf20Sopenharmony_ci	 * on TMDS1 that seem to be fixed if I also forbit odd dividers in
15488c2ecf20Sopenharmony_ci	 * this case. This could just be a bandwidth calculation issue, I
15498c2ecf20Sopenharmony_ci	 * haven't implemented the bandwidth code yet, but in the meantime,
15508c2ecf20Sopenharmony_ci	 * forcing uses_dvo to 1 fixes it and shouln't have bad side effects,
15518c2ecf20Sopenharmony_ci	 * I haven't seen a case were were absolutely needed an odd PLL
15528c2ecf20Sopenharmony_ci	 * divider. I'll find a better fix once I have more infos on the
15538c2ecf20Sopenharmony_ci	 * real cause of the problem.
15548c2ecf20Sopenharmony_ci	 */
15558c2ecf20Sopenharmony_ci	while (rinfo->has_CRTC2) {
15568c2ecf20Sopenharmony_ci		u32 fp2_gen_cntl = INREG(FP2_GEN_CNTL);
15578c2ecf20Sopenharmony_ci		u32 disp_output_cntl;
15588c2ecf20Sopenharmony_ci		int source;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci		/* FP2 path not enabled */
15618c2ecf20Sopenharmony_ci		if ((fp2_gen_cntl & FP2_ON) == 0)
15628c2ecf20Sopenharmony_ci			break;
15638c2ecf20Sopenharmony_ci		/* Not all chip revs have the same format for this register,
15648c2ecf20Sopenharmony_ci		 * extract the source selection
15658c2ecf20Sopenharmony_ci		 */
15668c2ecf20Sopenharmony_ci		if (rinfo->family == CHIP_FAMILY_R200 || IS_R300_VARIANT(rinfo)) {
15678c2ecf20Sopenharmony_ci			source = (fp2_gen_cntl >> 10) & 0x3;
15688c2ecf20Sopenharmony_ci			/* sourced from transform unit, check for transform unit
15698c2ecf20Sopenharmony_ci			 * own source
15708c2ecf20Sopenharmony_ci			 */
15718c2ecf20Sopenharmony_ci			if (source == 3) {
15728c2ecf20Sopenharmony_ci				disp_output_cntl = INREG(DISP_OUTPUT_CNTL);
15738c2ecf20Sopenharmony_ci				source = (disp_output_cntl >> 12) & 0x3;
15748c2ecf20Sopenharmony_ci			}
15758c2ecf20Sopenharmony_ci		} else
15768c2ecf20Sopenharmony_ci			source = (fp2_gen_cntl >> 13) & 0x1;
15778c2ecf20Sopenharmony_ci		/* sourced from CRTC2 -> exit */
15788c2ecf20Sopenharmony_ci		if (source == 1)
15798c2ecf20Sopenharmony_ci			break;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci		/* so we end up on CRTC1, let's set uses_dvo to 1 now */
15828c2ecf20Sopenharmony_ci		uses_dvo = 1;
15838c2ecf20Sopenharmony_ci		break;
15848c2ecf20Sopenharmony_ci	}
15858c2ecf20Sopenharmony_ci#else
15868c2ecf20Sopenharmony_ci	uses_dvo = 1;
15878c2ecf20Sopenharmony_ci#endif
15888c2ecf20Sopenharmony_ci	if (freq > rinfo->pll.ppll_max)
15898c2ecf20Sopenharmony_ci		freq = rinfo->pll.ppll_max;
15908c2ecf20Sopenharmony_ci	if (freq*12 < rinfo->pll.ppll_min)
15918c2ecf20Sopenharmony_ci		freq = rinfo->pll.ppll_min / 12;
15928c2ecf20Sopenharmony_ci	pr_debug("freq = %lu, PLL min = %u, PLL max = %u\n",
15938c2ecf20Sopenharmony_ci	       freq, rinfo->pll.ppll_min, rinfo->pll.ppll_max);
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
15968c2ecf20Sopenharmony_ci		pll_output_freq = post_div->divider * freq;
15978c2ecf20Sopenharmony_ci		/* If we output to the DVO port (external TMDS), we don't allow an
15988c2ecf20Sopenharmony_ci		 * odd PLL divider as those aren't supported on this path
15998c2ecf20Sopenharmony_ci		 */
16008c2ecf20Sopenharmony_ci		if (uses_dvo && (post_div->divider & 1))
16018c2ecf20Sopenharmony_ci			continue;
16028c2ecf20Sopenharmony_ci		if (pll_output_freq >= rinfo->pll.ppll_min  &&
16038c2ecf20Sopenharmony_ci		    pll_output_freq <= rinfo->pll.ppll_max)
16048c2ecf20Sopenharmony_ci			break;
16058c2ecf20Sopenharmony_ci	}
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	/* If we fall through the bottom, try the "default value"
16088c2ecf20Sopenharmony_ci	   given by the terminal post_div->bitvalue */
16098c2ecf20Sopenharmony_ci	if ( !post_div->divider ) {
16108c2ecf20Sopenharmony_ci		post_div = &post_divs[post_div->bitvalue];
16118c2ecf20Sopenharmony_ci		pll_output_freq = post_div->divider * freq;
16128c2ecf20Sopenharmony_ci	}
16138c2ecf20Sopenharmony_ci	pr_debug("ref_div = %d, ref_clk = %d, output_freq = %d\n",
16148c2ecf20Sopenharmony_ci	       rinfo->pll.ref_div, rinfo->pll.ref_clk,
16158c2ecf20Sopenharmony_ci	       pll_output_freq);
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	/* If we fall through the bottom, try the "default value"
16188c2ecf20Sopenharmony_ci	   given by the terminal post_div->bitvalue */
16198c2ecf20Sopenharmony_ci	if ( !post_div->divider ) {
16208c2ecf20Sopenharmony_ci		post_div = &post_divs[post_div->bitvalue];
16218c2ecf20Sopenharmony_ci		pll_output_freq = post_div->divider * freq;
16228c2ecf20Sopenharmony_ci	}
16238c2ecf20Sopenharmony_ci	pr_debug("ref_div = %d, ref_clk = %d, output_freq = %d\n",
16248c2ecf20Sopenharmony_ci	       rinfo->pll.ref_div, rinfo->pll.ref_clk,
16258c2ecf20Sopenharmony_ci	       pll_output_freq);
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	fb_div = round_div(rinfo->pll.ref_div*pll_output_freq,
16288c2ecf20Sopenharmony_ci				  rinfo->pll.ref_clk);
16298c2ecf20Sopenharmony_ci	regs->ppll_ref_div = rinfo->pll.ref_div;
16308c2ecf20Sopenharmony_ci	regs->ppll_div_3 = fb_div | (post_div->bitvalue << 16);
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	pr_debug("post div = 0x%x\n", post_div->bitvalue);
16338c2ecf20Sopenharmony_ci	pr_debug("fb_div = 0x%x\n", fb_div);
16348c2ecf20Sopenharmony_ci	pr_debug("ppll_div_3 = 0x%x\n", regs->ppll_div_3);
16358c2ecf20Sopenharmony_ci}
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_cistatic int radeonfb_set_par(struct fb_info *info)
16388c2ecf20Sopenharmony_ci{
16398c2ecf20Sopenharmony_ci	struct radeonfb_info *rinfo = info->par;
16408c2ecf20Sopenharmony_ci	struct fb_var_screeninfo *mode = &info->var;
16418c2ecf20Sopenharmony_ci	struct radeon_regs *newmode;
16428c2ecf20Sopenharmony_ci	int hTotal, vTotal, hSyncStart, hSyncEnd,
16438c2ecf20Sopenharmony_ci	    vSyncStart, vSyncEnd;
16448c2ecf20Sopenharmony_ci	u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5};
16458c2ecf20Sopenharmony_ci	u8 hsync_fudge_fp[] = {2, 2, 0, 0, 5, 5};
16468c2ecf20Sopenharmony_ci	u32 sync, h_sync_pol, v_sync_pol, dotClock, pixClock;
16478c2ecf20Sopenharmony_ci	int i, freq;
16488c2ecf20Sopenharmony_ci	int format = 0;
16498c2ecf20Sopenharmony_ci	int nopllcalc = 0;
16508c2ecf20Sopenharmony_ci	int hsync_start, hsync_fudge, hsync_wid, vsync_wid;
16518c2ecf20Sopenharmony_ci	int primary_mon = PRIMARY_MONITOR(rinfo);
16528c2ecf20Sopenharmony_ci	int depth = var_to_depth(mode);
16538c2ecf20Sopenharmony_ci	int use_rmx = 0;
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	newmode = kmalloc(sizeof(struct radeon_regs), GFP_KERNEL);
16568c2ecf20Sopenharmony_ci	if (!newmode)
16578c2ecf20Sopenharmony_ci		return -ENOMEM;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	/* We always want engine to be idle on a mode switch, even
16608c2ecf20Sopenharmony_ci	 * if we won't actually change the mode
16618c2ecf20Sopenharmony_ci	 */
16628c2ecf20Sopenharmony_ci	radeon_engine_idle();
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	hSyncStart = mode->xres + mode->right_margin;
16658c2ecf20Sopenharmony_ci	hSyncEnd = hSyncStart + mode->hsync_len;
16668c2ecf20Sopenharmony_ci	hTotal = hSyncEnd + mode->left_margin;
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	vSyncStart = mode->yres + mode->lower_margin;
16698c2ecf20Sopenharmony_ci	vSyncEnd = vSyncStart + mode->vsync_len;
16708c2ecf20Sopenharmony_ci	vTotal = vSyncEnd + mode->upper_margin;
16718c2ecf20Sopenharmony_ci	pixClock = mode->pixclock;
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	sync = mode->sync;
16748c2ecf20Sopenharmony_ci	h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
16758c2ecf20Sopenharmony_ci	v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	if (primary_mon == MT_DFP || primary_mon == MT_LCD) {
16788c2ecf20Sopenharmony_ci		if (rinfo->panel_info.xres < mode->xres)
16798c2ecf20Sopenharmony_ci			mode->xres = rinfo->panel_info.xres;
16808c2ecf20Sopenharmony_ci		if (rinfo->panel_info.yres < mode->yres)
16818c2ecf20Sopenharmony_ci			mode->yres = rinfo->panel_info.yres;
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci		hTotal = mode->xres + rinfo->panel_info.hblank;
16848c2ecf20Sopenharmony_ci		hSyncStart = mode->xres + rinfo->panel_info.hOver_plus;
16858c2ecf20Sopenharmony_ci		hSyncEnd = hSyncStart + rinfo->panel_info.hSync_width;
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci		vTotal = mode->yres + rinfo->panel_info.vblank;
16888c2ecf20Sopenharmony_ci		vSyncStart = mode->yres + rinfo->panel_info.vOver_plus;
16898c2ecf20Sopenharmony_ci		vSyncEnd = vSyncStart + rinfo->panel_info.vSync_width;
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci		h_sync_pol = !rinfo->panel_info.hAct_high;
16928c2ecf20Sopenharmony_ci		v_sync_pol = !rinfo->panel_info.vAct_high;
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci		pixClock = 100000000 / rinfo->panel_info.clock;
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci		if (rinfo->panel_info.use_bios_dividers) {
16978c2ecf20Sopenharmony_ci			nopllcalc = 1;
16988c2ecf20Sopenharmony_ci			newmode->ppll_div_3 = rinfo->panel_info.fbk_divider |
16998c2ecf20Sopenharmony_ci				(rinfo->panel_info.post_divider << 16);
17008c2ecf20Sopenharmony_ci			newmode->ppll_ref_div = rinfo->panel_info.ref_divider;
17018c2ecf20Sopenharmony_ci		}
17028c2ecf20Sopenharmony_ci	}
17038c2ecf20Sopenharmony_ci	dotClock = 1000000000 / pixClock;
17048c2ecf20Sopenharmony_ci	freq = dotClock / 10; /* x100 */
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	pr_debug("hStart = %d, hEnd = %d, hTotal = %d\n",
17078c2ecf20Sopenharmony_ci		hSyncStart, hSyncEnd, hTotal);
17088c2ecf20Sopenharmony_ci	pr_debug("vStart = %d, vEnd = %d, vTotal = %d\n",
17098c2ecf20Sopenharmony_ci		vSyncStart, vSyncEnd, vTotal);
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	hsync_wid = (hSyncEnd - hSyncStart) / 8;
17128c2ecf20Sopenharmony_ci	vsync_wid = vSyncEnd - vSyncStart;
17138c2ecf20Sopenharmony_ci	if (hsync_wid == 0)
17148c2ecf20Sopenharmony_ci		hsync_wid = 1;
17158c2ecf20Sopenharmony_ci	else if (hsync_wid > 0x3f)	/* max */
17168c2ecf20Sopenharmony_ci		hsync_wid = 0x3f;
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	if (vsync_wid == 0)
17198c2ecf20Sopenharmony_ci		vsync_wid = 1;
17208c2ecf20Sopenharmony_ci	else if (vsync_wid > 0x1f)	/* max */
17218c2ecf20Sopenharmony_ci		vsync_wid = 0x1f;
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	format = radeon_get_dstbpp(depth);
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD))
17268c2ecf20Sopenharmony_ci		hsync_fudge = hsync_fudge_fp[format-1];
17278c2ecf20Sopenharmony_ci	else
17288c2ecf20Sopenharmony_ci		hsync_fudge = hsync_adj_tab[format-1];
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	hsync_start = hSyncStart - 8 + hsync_fudge;
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	newmode->crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN |
17338c2ecf20Sopenharmony_ci				(format << 8);
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	/* Clear auto-center etc... */
17368c2ecf20Sopenharmony_ci	newmode->crtc_more_cntl = rinfo->init_state.crtc_more_cntl;
17378c2ecf20Sopenharmony_ci	newmode->crtc_more_cntl &= 0xfffffff0;
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
17408c2ecf20Sopenharmony_ci		newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN;
17418c2ecf20Sopenharmony_ci		if (mirror)
17428c2ecf20Sopenharmony_ci			newmode->crtc_ext_cntl |= CRTC_CRT_ON;
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci		newmode->crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN |
17458c2ecf20Sopenharmony_ci					   CRTC_INTERLACE_EN);
17468c2ecf20Sopenharmony_ci	} else {
17478c2ecf20Sopenharmony_ci		newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN |
17488c2ecf20Sopenharmony_ci					CRTC_CRT_ON;
17498c2ecf20Sopenharmony_ci	}
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	newmode->dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN |
17528c2ecf20Sopenharmony_ci			   DAC_8BIT_EN;
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci	newmode->crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) |
17558c2ecf20Sopenharmony_ci				     (((mode->xres / 8) - 1) << 16));
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	newmode->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) |
17588c2ecf20Sopenharmony_ci					(hsync_wid << 16) | (h_sync_pol << 23));
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	newmode->crtc_v_total_disp = ((vTotal - 1) & 0xffff) |
17618c2ecf20Sopenharmony_ci				    ((mode->yres - 1) << 16);
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci	newmode->crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) |
17648c2ecf20Sopenharmony_ci					 (vsync_wid << 16) | (v_sync_pol  << 23));
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	if (!(info->flags & FBINFO_HWACCEL_DISABLED)) {
17678c2ecf20Sopenharmony_ci		/* We first calculate the engine pitch */
17688c2ecf20Sopenharmony_ci		rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f)
17698c2ecf20Sopenharmony_ci 				& ~(0x3f)) >> 6;
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci		/* Then, re-multiply it to get the CRTC pitch */
17728c2ecf20Sopenharmony_ci		newmode->crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8);
17738c2ecf20Sopenharmony_ci	} else
17748c2ecf20Sopenharmony_ci		newmode->crtc_pitch = (mode->xres_virtual >> 3);
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	newmode->crtc_pitch |= (newmode->crtc_pitch << 16);
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci	/*
17798c2ecf20Sopenharmony_ci	 * It looks like recent chips have a problem with SURFACE_CNTL,
17808c2ecf20Sopenharmony_ci	 * setting SURF_TRANSLATION_DIS completely disables the
17818c2ecf20Sopenharmony_ci	 * swapper as well, so we leave it unset now.
17828c2ecf20Sopenharmony_ci	 */
17838c2ecf20Sopenharmony_ci	newmode->surface_cntl = 0;
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci#if defined(__BIG_ENDIAN)
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	/* Setup swapping on both apertures, though we currently
17888c2ecf20Sopenharmony_ci	 * only use aperture 0, enabling swapper on aperture 1
17898c2ecf20Sopenharmony_ci	 * won't harm
17908c2ecf20Sopenharmony_ci	 */
17918c2ecf20Sopenharmony_ci	switch (mode->bits_per_pixel) {
17928c2ecf20Sopenharmony_ci		case 16:
17938c2ecf20Sopenharmony_ci			newmode->surface_cntl |= NONSURF_AP0_SWP_16BPP;
17948c2ecf20Sopenharmony_ci			newmode->surface_cntl |= NONSURF_AP1_SWP_16BPP;
17958c2ecf20Sopenharmony_ci			break;
17968c2ecf20Sopenharmony_ci		case 24:
17978c2ecf20Sopenharmony_ci		case 32:
17988c2ecf20Sopenharmony_ci			newmode->surface_cntl |= NONSURF_AP0_SWP_32BPP;
17998c2ecf20Sopenharmony_ci			newmode->surface_cntl |= NONSURF_AP1_SWP_32BPP;
18008c2ecf20Sopenharmony_ci			break;
18018c2ecf20Sopenharmony_ci	}
18028c2ecf20Sopenharmony_ci#endif
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	/* Clear surface registers */
18058c2ecf20Sopenharmony_ci	for (i=0; i<8; i++) {
18068c2ecf20Sopenharmony_ci		newmode->surf_lower_bound[i] = 0;
18078c2ecf20Sopenharmony_ci		newmode->surf_upper_bound[i] = 0x1f;
18088c2ecf20Sopenharmony_ci		newmode->surf_info[i] = 0;
18098c2ecf20Sopenharmony_ci	}
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	pr_debug("h_total_disp = 0x%x\t   hsync_strt_wid = 0x%x\n",
18128c2ecf20Sopenharmony_ci		newmode->crtc_h_total_disp, newmode->crtc_h_sync_strt_wid);
18138c2ecf20Sopenharmony_ci	pr_debug("v_total_disp = 0x%x\t   vsync_strt_wid = 0x%x\n",
18148c2ecf20Sopenharmony_ci		newmode->crtc_v_total_disp, newmode->crtc_v_sync_strt_wid);
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci	rinfo->bpp = mode->bits_per_pixel;
18178c2ecf20Sopenharmony_ci	rinfo->depth = depth;
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	pr_debug("pixclock = %lu\n", (unsigned long)pixClock);
18208c2ecf20Sopenharmony_ci	pr_debug("freq = %lu\n", (unsigned long)freq);
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	/* We use PPLL_DIV_3 */
18238c2ecf20Sopenharmony_ci	newmode->clk_cntl_index = 0x300;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci	/* Calculate PPLL value if necessary */
18268c2ecf20Sopenharmony_ci	if (!nopllcalc)
18278c2ecf20Sopenharmony_ci		radeon_calc_pll_regs(rinfo, newmode, freq);
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci	newmode->vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl;
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
18328c2ecf20Sopenharmony_ci		unsigned int hRatio, vRatio;
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci		if (mode->xres > rinfo->panel_info.xres)
18358c2ecf20Sopenharmony_ci			mode->xres = rinfo->panel_info.xres;
18368c2ecf20Sopenharmony_ci		if (mode->yres > rinfo->panel_info.yres)
18378c2ecf20Sopenharmony_ci			mode->yres = rinfo->panel_info.yres;
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci		newmode->fp_horz_stretch = (((rinfo->panel_info.xres / 8) - 1)
18408c2ecf20Sopenharmony_ci					   << HORZ_PANEL_SHIFT);
18418c2ecf20Sopenharmony_ci		newmode->fp_vert_stretch = ((rinfo->panel_info.yres - 1)
18428c2ecf20Sopenharmony_ci					   << VERT_PANEL_SHIFT);
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci		if (mode->xres != rinfo->panel_info.xres) {
18458c2ecf20Sopenharmony_ci			hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX,
18468c2ecf20Sopenharmony_ci					   rinfo->panel_info.xres);
18478c2ecf20Sopenharmony_ci			newmode->fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) |
18488c2ecf20Sopenharmony_ci						   (newmode->fp_horz_stretch &
18498c2ecf20Sopenharmony_ci						    (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH |
18508c2ecf20Sopenharmony_ci						     HORZ_AUTO_RATIO_INC)));
18518c2ecf20Sopenharmony_ci			newmode->fp_horz_stretch |= (HORZ_STRETCH_BLEND |
18528c2ecf20Sopenharmony_ci						    HORZ_STRETCH_ENABLE);
18538c2ecf20Sopenharmony_ci			use_rmx = 1;
18548c2ecf20Sopenharmony_ci		}
18558c2ecf20Sopenharmony_ci		newmode->fp_horz_stretch &= ~HORZ_AUTO_RATIO;
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci		if (mode->yres != rinfo->panel_info.yres) {
18588c2ecf20Sopenharmony_ci			vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX,
18598c2ecf20Sopenharmony_ci					   rinfo->panel_info.yres);
18608c2ecf20Sopenharmony_ci			newmode->fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) |
18618c2ecf20Sopenharmony_ci						   (newmode->fp_vert_stretch &
18628c2ecf20Sopenharmony_ci						   (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED)));
18638c2ecf20Sopenharmony_ci			newmode->fp_vert_stretch |= (VERT_STRETCH_BLEND |
18648c2ecf20Sopenharmony_ci						    VERT_STRETCH_ENABLE);
18658c2ecf20Sopenharmony_ci			use_rmx = 1;
18668c2ecf20Sopenharmony_ci		}
18678c2ecf20Sopenharmony_ci		newmode->fp_vert_stretch &= ~VERT_AUTO_RATIO_EN;
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci		newmode->fp_gen_cntl = (rinfo->init_state.fp_gen_cntl & (u32)
18708c2ecf20Sopenharmony_ci				       ~(FP_SEL_CRTC2 |
18718c2ecf20Sopenharmony_ci					 FP_RMX_HVSYNC_CONTROL_EN |
18728c2ecf20Sopenharmony_ci					 FP_DFP_SYNC_SEL |
18738c2ecf20Sopenharmony_ci					 FP_CRT_SYNC_SEL |
18748c2ecf20Sopenharmony_ci					 FP_CRTC_LOCK_8DOT |
18758c2ecf20Sopenharmony_ci					 FP_USE_SHADOW_EN |
18768c2ecf20Sopenharmony_ci					 FP_CRTC_USE_SHADOW_VEND |
18778c2ecf20Sopenharmony_ci					 FP_CRT_SYNC_ALT));
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci		newmode->fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR |
18808c2ecf20Sopenharmony_ci					FP_CRTC_DONT_SHADOW_HEND |
18818c2ecf20Sopenharmony_ci					FP_PANEL_FORMAT);
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci		if (IS_R300_VARIANT(rinfo) ||
18848c2ecf20Sopenharmony_ci		    (rinfo->family == CHIP_FAMILY_R200)) {
18858c2ecf20Sopenharmony_ci			newmode->fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK;
18868c2ecf20Sopenharmony_ci			if (use_rmx)
18878c2ecf20Sopenharmony_ci				newmode->fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX;
18888c2ecf20Sopenharmony_ci			else
18898c2ecf20Sopenharmony_ci				newmode->fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1;
18908c2ecf20Sopenharmony_ci		} else
18918c2ecf20Sopenharmony_ci			newmode->fp_gen_cntl |= FP_SEL_CRTC1;
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci		newmode->lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl;
18948c2ecf20Sopenharmony_ci		newmode->lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl;
18958c2ecf20Sopenharmony_ci		newmode->tmds_crc = rinfo->init_state.tmds_crc;
18968c2ecf20Sopenharmony_ci		newmode->tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci		if (primary_mon == MT_LCD) {
18998c2ecf20Sopenharmony_ci			newmode->lvds_gen_cntl |= (LVDS_ON | LVDS_BLON);
19008c2ecf20Sopenharmony_ci			newmode->fp_gen_cntl &= ~(FP_FPON | FP_TMDS_EN);
19018c2ecf20Sopenharmony_ci		} else {
19028c2ecf20Sopenharmony_ci			/* DFP */
19038c2ecf20Sopenharmony_ci			newmode->fp_gen_cntl |= (FP_FPON | FP_TMDS_EN);
19048c2ecf20Sopenharmony_ci			newmode->tmds_transmitter_cntl &= ~(TMDS_PLLRST);
19058c2ecf20Sopenharmony_ci			/* TMDS_PLL_EN bit is reversed on RV (and mobility) chips */
19068c2ecf20Sopenharmony_ci			if (IS_R300_VARIANT(rinfo) ||
19078c2ecf20Sopenharmony_ci			    (rinfo->family == CHIP_FAMILY_R200) || !rinfo->has_CRTC2)
19088c2ecf20Sopenharmony_ci				newmode->tmds_transmitter_cntl &= ~TMDS_PLL_EN;
19098c2ecf20Sopenharmony_ci			else
19108c2ecf20Sopenharmony_ci				newmode->tmds_transmitter_cntl |= TMDS_PLL_EN;
19118c2ecf20Sopenharmony_ci			newmode->crtc_ext_cntl &= ~CRTC_CRT_ON;
19128c2ecf20Sopenharmony_ci		}
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci		newmode->fp_crtc_h_total_disp = (((rinfo->panel_info.hblank / 8) & 0x3ff) |
19158c2ecf20Sopenharmony_ci				(((mode->xres / 8) - 1) << 16));
19168c2ecf20Sopenharmony_ci		newmode->fp_crtc_v_total_disp = (rinfo->panel_info.vblank & 0xffff) |
19178c2ecf20Sopenharmony_ci				((mode->yres - 1) << 16);
19188c2ecf20Sopenharmony_ci		newmode->fp_h_sync_strt_wid = ((rinfo->panel_info.hOver_plus & 0x1fff) |
19198c2ecf20Sopenharmony_ci				(hsync_wid << 16) | (h_sync_pol << 23));
19208c2ecf20Sopenharmony_ci		newmode->fp_v_sync_strt_wid = ((rinfo->panel_info.vOver_plus & 0xfff) |
19218c2ecf20Sopenharmony_ci				(vsync_wid << 16) | (v_sync_pol  << 23));
19228c2ecf20Sopenharmony_ci	}
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	/* do it! */
19258c2ecf20Sopenharmony_ci	if (!rinfo->asleep) {
19268c2ecf20Sopenharmony_ci		memcpy(&rinfo->state, newmode, sizeof(*newmode));
19278c2ecf20Sopenharmony_ci		radeon_write_mode (rinfo, newmode, 0);
19288c2ecf20Sopenharmony_ci		/* (re)initialize the engine */
19298c2ecf20Sopenharmony_ci		if (!(info->flags & FBINFO_HWACCEL_DISABLED))
19308c2ecf20Sopenharmony_ci			radeonfb_engine_init (rinfo);
19318c2ecf20Sopenharmony_ci	}
19328c2ecf20Sopenharmony_ci	/* Update fix */
19338c2ecf20Sopenharmony_ci	if (!(info->flags & FBINFO_HWACCEL_DISABLED))
19348c2ecf20Sopenharmony_ci        	info->fix.line_length = rinfo->pitch*64;
19358c2ecf20Sopenharmony_ci        else
19368c2ecf20Sopenharmony_ci		info->fix.line_length = mode->xres_virtual
19378c2ecf20Sopenharmony_ci			* ((mode->bits_per_pixel + 1) / 8);
19388c2ecf20Sopenharmony_ci        info->fix.visual = rinfo->depth == 8 ? FB_VISUAL_PSEUDOCOLOR
19398c2ecf20Sopenharmony_ci		: FB_VISUAL_DIRECTCOLOR;
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci#ifdef CONFIG_BOOTX_TEXT
19428c2ecf20Sopenharmony_ci	/* Update debug text engine */
19438c2ecf20Sopenharmony_ci	btext_update_display(rinfo->fb_base_phys, mode->xres, mode->yres,
19448c2ecf20Sopenharmony_ci			     rinfo->depth, info->fix.line_length);
19458c2ecf20Sopenharmony_ci#endif
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci	kfree(newmode);
19488c2ecf20Sopenharmony_ci	return 0;
19498c2ecf20Sopenharmony_ci}
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_cistatic const struct fb_ops radeonfb_ops = {
19538c2ecf20Sopenharmony_ci	.owner			= THIS_MODULE,
19548c2ecf20Sopenharmony_ci	.fb_check_var		= radeonfb_check_var,
19558c2ecf20Sopenharmony_ci	.fb_set_par		= radeonfb_set_par,
19568c2ecf20Sopenharmony_ci	.fb_setcolreg		= radeonfb_setcolreg,
19578c2ecf20Sopenharmony_ci	.fb_setcmap		= radeonfb_setcmap,
19588c2ecf20Sopenharmony_ci	.fb_pan_display 	= radeonfb_pan_display,
19598c2ecf20Sopenharmony_ci	.fb_blank		= radeonfb_blank,
19608c2ecf20Sopenharmony_ci	.fb_ioctl		= radeonfb_ioctl,
19618c2ecf20Sopenharmony_ci	.fb_sync		= radeonfb_sync,
19628c2ecf20Sopenharmony_ci	.fb_fillrect		= radeonfb_fillrect,
19638c2ecf20Sopenharmony_ci	.fb_copyarea		= radeonfb_copyarea,
19648c2ecf20Sopenharmony_ci	.fb_imageblit		= radeonfb_imageblit,
19658c2ecf20Sopenharmony_ci};
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_cistatic int radeon_set_fbinfo(struct radeonfb_info *rinfo)
19698c2ecf20Sopenharmony_ci{
19708c2ecf20Sopenharmony_ci	struct fb_info *info = rinfo->info;
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci	info->par = rinfo;
19738c2ecf20Sopenharmony_ci	info->pseudo_palette = rinfo->pseudo_palette;
19748c2ecf20Sopenharmony_ci	info->flags = FBINFO_DEFAULT
19758c2ecf20Sopenharmony_ci		    | FBINFO_HWACCEL_COPYAREA
19768c2ecf20Sopenharmony_ci		    | FBINFO_HWACCEL_FILLRECT
19778c2ecf20Sopenharmony_ci		    | FBINFO_HWACCEL_XPAN
19788c2ecf20Sopenharmony_ci		    | FBINFO_HWACCEL_YPAN;
19798c2ecf20Sopenharmony_ci	info->fbops = &radeonfb_ops;
19808c2ecf20Sopenharmony_ci	info->screen_base = rinfo->fb_base;
19818c2ecf20Sopenharmony_ci	info->screen_size = rinfo->mapped_vram;
19828c2ecf20Sopenharmony_ci	/* Fill fix common fields */
19838c2ecf20Sopenharmony_ci	strlcpy(info->fix.id, rinfo->name, sizeof(info->fix.id));
19848c2ecf20Sopenharmony_ci        info->fix.smem_start = rinfo->fb_base_phys;
19858c2ecf20Sopenharmony_ci        info->fix.smem_len = rinfo->video_ram;
19868c2ecf20Sopenharmony_ci        info->fix.type = FB_TYPE_PACKED_PIXELS;
19878c2ecf20Sopenharmony_ci        info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
19888c2ecf20Sopenharmony_ci        info->fix.xpanstep = 8;
19898c2ecf20Sopenharmony_ci        info->fix.ypanstep = 1;
19908c2ecf20Sopenharmony_ci        info->fix.ywrapstep = 0;
19918c2ecf20Sopenharmony_ci        info->fix.type_aux = 0;
19928c2ecf20Sopenharmony_ci        info->fix.mmio_start = rinfo->mmio_base_phys;
19938c2ecf20Sopenharmony_ci        info->fix.mmio_len = RADEON_REGSIZE;
19948c2ecf20Sopenharmony_ci	info->fix.accel = FB_ACCEL_ATI_RADEON;
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	fb_alloc_cmap(&info->cmap, 256, 0);
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	if (noaccel)
19998c2ecf20Sopenharmony_ci		info->flags |= FBINFO_HWACCEL_DISABLED;
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_ci        return 0;
20028c2ecf20Sopenharmony_ci}
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci/*
20058c2ecf20Sopenharmony_ci * This reconfigure the card's internal memory map. In theory, we'd like
20068c2ecf20Sopenharmony_ci * to setup the card's memory at the same address as it's PCI bus address,
20078c2ecf20Sopenharmony_ci * and the AGP aperture right after that so that system RAM on 32 bits
20088c2ecf20Sopenharmony_ci * machines at least, is directly accessible. However, doing so would
20098c2ecf20Sopenharmony_ci * conflict with the current XFree drivers...
20108c2ecf20Sopenharmony_ci * Ultimately, I hope XFree, GATOS and ATI binary drivers will all agree
20118c2ecf20Sopenharmony_ci * on the proper way to set this up and duplicate this here. In the meantime,
20128c2ecf20Sopenharmony_ci * I put the card's memory at 0 in card space and AGP at some random high
20138c2ecf20Sopenharmony_ci * local (0xe0000000 for now) that will be changed by XFree/DRI anyway
20148c2ecf20Sopenharmony_ci */
20158c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC
20168c2ecf20Sopenharmony_ci#undef SET_MC_FB_FROM_APERTURE
20178c2ecf20Sopenharmony_cistatic void fixup_memory_mappings(struct radeonfb_info *rinfo)
20188c2ecf20Sopenharmony_ci{
20198c2ecf20Sopenharmony_ci	u32 save_crtc_gen_cntl, save_crtc2_gen_cntl = 0;
20208c2ecf20Sopenharmony_ci	u32 save_crtc_ext_cntl;
20218c2ecf20Sopenharmony_ci	u32 aper_base, aper_size;
20228c2ecf20Sopenharmony_ci	u32 agp_base;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	/* First, we disable display to avoid interfering */
20258c2ecf20Sopenharmony_ci	if (rinfo->has_CRTC2) {
20268c2ecf20Sopenharmony_ci		save_crtc2_gen_cntl = INREG(CRTC2_GEN_CNTL);
20278c2ecf20Sopenharmony_ci		OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl | CRTC2_DISP_REQ_EN_B);
20288c2ecf20Sopenharmony_ci	}
20298c2ecf20Sopenharmony_ci	save_crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
20308c2ecf20Sopenharmony_ci	save_crtc_ext_cntl = INREG(CRTC_EXT_CNTL);
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl | CRTC_DISPLAY_DIS);
20338c2ecf20Sopenharmony_ci	OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl | CRTC_DISP_REQ_EN_B);
20348c2ecf20Sopenharmony_ci	mdelay(100);
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci	aper_base = INREG(CNFG_APER_0_BASE);
20378c2ecf20Sopenharmony_ci	aper_size = INREG(CNFG_APER_SIZE);
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci#ifdef SET_MC_FB_FROM_APERTURE
20408c2ecf20Sopenharmony_ci	/* Set framebuffer to be at the same address as set in PCI BAR */
20418c2ecf20Sopenharmony_ci	OUTREG(MC_FB_LOCATION,
20428c2ecf20Sopenharmony_ci		((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16));
20438c2ecf20Sopenharmony_ci	rinfo->fb_local_base = aper_base;
20448c2ecf20Sopenharmony_ci#else
20458c2ecf20Sopenharmony_ci	OUTREG(MC_FB_LOCATION, 0x7fff0000);
20468c2ecf20Sopenharmony_ci	rinfo->fb_local_base = 0;
20478c2ecf20Sopenharmony_ci#endif
20488c2ecf20Sopenharmony_ci	agp_base = aper_base + aper_size;
20498c2ecf20Sopenharmony_ci	if (agp_base & 0xf0000000)
20508c2ecf20Sopenharmony_ci		agp_base = (aper_base | 0x0fffffff) + 1;
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	/* Set AGP to be just after the framebuffer on a 256Mb boundary. This
20538c2ecf20Sopenharmony_ci	 * assumes the FB isn't mapped to 0xf0000000 or above, but this is
20548c2ecf20Sopenharmony_ci	 * always the case on PPCs afaik.
20558c2ecf20Sopenharmony_ci	 */
20568c2ecf20Sopenharmony_ci#ifdef SET_MC_FB_FROM_APERTURE
20578c2ecf20Sopenharmony_ci	OUTREG(MC_AGP_LOCATION, 0xffff0000 | (agp_base >> 16));
20588c2ecf20Sopenharmony_ci#else
20598c2ecf20Sopenharmony_ci	OUTREG(MC_AGP_LOCATION, 0xffffe000);
20608c2ecf20Sopenharmony_ci#endif
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci	/* Fixup the display base addresses & engine offsets while we
20638c2ecf20Sopenharmony_ci	 * are at it as well
20648c2ecf20Sopenharmony_ci	 */
20658c2ecf20Sopenharmony_ci#ifdef SET_MC_FB_FROM_APERTURE
20668c2ecf20Sopenharmony_ci	OUTREG(DISPLAY_BASE_ADDR, aper_base);
20678c2ecf20Sopenharmony_ci	if (rinfo->has_CRTC2)
20688c2ecf20Sopenharmony_ci		OUTREG(CRTC2_DISPLAY_BASE_ADDR, aper_base);
20698c2ecf20Sopenharmony_ci	OUTREG(OV0_BASE_ADDR, aper_base);
20708c2ecf20Sopenharmony_ci#else
20718c2ecf20Sopenharmony_ci	OUTREG(DISPLAY_BASE_ADDR, 0);
20728c2ecf20Sopenharmony_ci	if (rinfo->has_CRTC2)
20738c2ecf20Sopenharmony_ci		OUTREG(CRTC2_DISPLAY_BASE_ADDR, 0);
20748c2ecf20Sopenharmony_ci	OUTREG(OV0_BASE_ADDR, 0);
20758c2ecf20Sopenharmony_ci#endif
20768c2ecf20Sopenharmony_ci	mdelay(100);
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci	/* Restore display settings */
20798c2ecf20Sopenharmony_ci	OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl);
20808c2ecf20Sopenharmony_ci	OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl);
20818c2ecf20Sopenharmony_ci	if (rinfo->has_CRTC2)
20828c2ecf20Sopenharmony_ci		OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl);
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci	pr_debug("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n",
20858c2ecf20Sopenharmony_ci		aper_base,
20868c2ecf20Sopenharmony_ci		((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16),
20878c2ecf20Sopenharmony_ci		0xffff0000 | (agp_base >> 16));
20888c2ecf20Sopenharmony_ci}
20898c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC */
20908c2ecf20Sopenharmony_ci
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_cistatic void radeon_identify_vram(struct radeonfb_info *rinfo)
20938c2ecf20Sopenharmony_ci{
20948c2ecf20Sopenharmony_ci	u32 tmp;
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	/* framebuffer size */
20978c2ecf20Sopenharmony_ci        if ((rinfo->family == CHIP_FAMILY_RS100) ||
20988c2ecf20Sopenharmony_ci            (rinfo->family == CHIP_FAMILY_RS200) ||
20998c2ecf20Sopenharmony_ci            (rinfo->family == CHIP_FAMILY_RS300) ||
21008c2ecf20Sopenharmony_ci            (rinfo->family == CHIP_FAMILY_RC410) ||
21018c2ecf20Sopenharmony_ci            (rinfo->family == CHIP_FAMILY_RS400) ||
21028c2ecf20Sopenharmony_ci	    (rinfo->family == CHIP_FAMILY_RS480) ) {
21038c2ecf20Sopenharmony_ci          u32 tom = INREG(NB_TOM);
21048c2ecf20Sopenharmony_ci          tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci 		radeon_fifo_wait(6);
21078c2ecf20Sopenharmony_ci          OUTREG(MC_FB_LOCATION, tom);
21088c2ecf20Sopenharmony_ci          OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
21098c2ecf20Sopenharmony_ci          OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
21108c2ecf20Sopenharmony_ci          OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16);
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci          /* This is supposed to fix the crtc2 noise problem. */
21138c2ecf20Sopenharmony_ci          OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000);
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci          if ((rinfo->family == CHIP_FAMILY_RS100) ||
21168c2ecf20Sopenharmony_ci              (rinfo->family == CHIP_FAMILY_RS200)) {
21178c2ecf20Sopenharmony_ci             /* This is to workaround the asic bug for RMX, some versions
21188c2ecf20Sopenharmony_ci                of BIOS doesn't have this register initialized correctly.
21198c2ecf20Sopenharmony_ci             */
21208c2ecf20Sopenharmony_ci             OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN,
21218c2ecf20Sopenharmony_ci                     ~CRTC_H_CUTOFF_ACTIVE_EN);
21228c2ecf20Sopenharmony_ci          }
21238c2ecf20Sopenharmony_ci        } else {
21248c2ecf20Sopenharmony_ci          tmp = INREG(CNFG_MEMSIZE);
21258c2ecf20Sopenharmony_ci        }
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	/* mem size is bits [28:0], mask off the rest */
21288c2ecf20Sopenharmony_ci	rinfo->video_ram = tmp & CNFG_MEMSIZE_MASK;
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci	/*
21318c2ecf20Sopenharmony_ci	 * Hack to get around some busted production M6's
21328c2ecf20Sopenharmony_ci	 * reporting no ram
21338c2ecf20Sopenharmony_ci	 */
21348c2ecf20Sopenharmony_ci	if (rinfo->video_ram == 0) {
21358c2ecf20Sopenharmony_ci		switch (rinfo->pdev->device) {
21368c2ecf20Sopenharmony_ci	       	case PCI_CHIP_RADEON_LY:
21378c2ecf20Sopenharmony_ci		case PCI_CHIP_RADEON_LZ:
21388c2ecf20Sopenharmony_ci	       		rinfo->video_ram = 8192 * 1024;
21398c2ecf20Sopenharmony_ci	       		break;
21408c2ecf20Sopenharmony_ci	       	default:
21418c2ecf20Sopenharmony_ci	       		break;
21428c2ecf20Sopenharmony_ci		}
21438c2ecf20Sopenharmony_ci	}
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	/*
21478c2ecf20Sopenharmony_ci	 * Now try to identify VRAM type
21488c2ecf20Sopenharmony_ci	 */
21498c2ecf20Sopenharmony_ci	if (rinfo->is_IGP || (rinfo->family >= CHIP_FAMILY_R300) ||
21508c2ecf20Sopenharmony_ci	    (INREG(MEM_SDRAM_MODE_REG) & (1<<30)))
21518c2ecf20Sopenharmony_ci		rinfo->vram_ddr = 1;
21528c2ecf20Sopenharmony_ci	else
21538c2ecf20Sopenharmony_ci		rinfo->vram_ddr = 0;
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	tmp = INREG(MEM_CNTL);
21568c2ecf20Sopenharmony_ci	if (IS_R300_VARIANT(rinfo)) {
21578c2ecf20Sopenharmony_ci		tmp &=  R300_MEM_NUM_CHANNELS_MASK;
21588c2ecf20Sopenharmony_ci		switch (tmp) {
21598c2ecf20Sopenharmony_ci		case 0:  rinfo->vram_width = 64; break;
21608c2ecf20Sopenharmony_ci		case 1:  rinfo->vram_width = 128; break;
21618c2ecf20Sopenharmony_ci		case 2:  rinfo->vram_width = 256; break;
21628c2ecf20Sopenharmony_ci		default: rinfo->vram_width = 128; break;
21638c2ecf20Sopenharmony_ci		}
21648c2ecf20Sopenharmony_ci	} else if ((rinfo->family == CHIP_FAMILY_RV100) ||
21658c2ecf20Sopenharmony_ci		   (rinfo->family == CHIP_FAMILY_RS100) ||
21668c2ecf20Sopenharmony_ci		   (rinfo->family == CHIP_FAMILY_RS200)){
21678c2ecf20Sopenharmony_ci		if (tmp & RV100_MEM_HALF_MODE)
21688c2ecf20Sopenharmony_ci			rinfo->vram_width = 32;
21698c2ecf20Sopenharmony_ci		else
21708c2ecf20Sopenharmony_ci			rinfo->vram_width = 64;
21718c2ecf20Sopenharmony_ci	} else {
21728c2ecf20Sopenharmony_ci		if (tmp & MEM_NUM_CHANNELS_MASK)
21738c2ecf20Sopenharmony_ci			rinfo->vram_width = 128;
21748c2ecf20Sopenharmony_ci		else
21758c2ecf20Sopenharmony_ci			rinfo->vram_width = 64;
21768c2ecf20Sopenharmony_ci	}
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci	/* This may not be correct, as some cards can have half of channel disabled
21798c2ecf20Sopenharmony_ci	 * ToDo: identify these cases
21808c2ecf20Sopenharmony_ci	 */
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	pr_debug("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n",
21838c2ecf20Sopenharmony_ci	       pci_name(rinfo->pdev),
21848c2ecf20Sopenharmony_ci	       rinfo->video_ram / 1024,
21858c2ecf20Sopenharmony_ci	       rinfo->vram_ddr ? "DDR" : "SDRAM",
21868c2ecf20Sopenharmony_ci	       rinfo->vram_width);
21878c2ecf20Sopenharmony_ci}
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci/*
21908c2ecf20Sopenharmony_ci * Sysfs
21918c2ecf20Sopenharmony_ci */
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_cistatic ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u8 *edid)
21948c2ecf20Sopenharmony_ci{
21958c2ecf20Sopenharmony_ci	return memory_read_from_buffer(buf, count, &off, edid, EDID_LENGTH);
21968c2ecf20Sopenharmony_ci}
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_cistatic ssize_t radeon_show_edid1(struct file *filp, struct kobject *kobj,
22008c2ecf20Sopenharmony_ci				 struct bin_attribute *bin_attr,
22018c2ecf20Sopenharmony_ci				 char *buf, loff_t off, size_t count)
22028c2ecf20Sopenharmony_ci{
22038c2ecf20Sopenharmony_ci	struct device *dev = container_of(kobj, struct device, kobj);
22048c2ecf20Sopenharmony_ci	struct fb_info *info = dev_get_drvdata(dev);
22058c2ecf20Sopenharmony_ci        struct radeonfb_info *rinfo = info->par;
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	return radeon_show_one_edid(buf, off, count, rinfo->mon1_EDID);
22088c2ecf20Sopenharmony_ci}
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_cistatic ssize_t radeon_show_edid2(struct file *filp, struct kobject *kobj,
22128c2ecf20Sopenharmony_ci				 struct bin_attribute *bin_attr,
22138c2ecf20Sopenharmony_ci				 char *buf, loff_t off, size_t count)
22148c2ecf20Sopenharmony_ci{
22158c2ecf20Sopenharmony_ci	struct device *dev = container_of(kobj, struct device, kobj);
22168c2ecf20Sopenharmony_ci	struct fb_info *info = dev_get_drvdata(dev);
22178c2ecf20Sopenharmony_ci        struct radeonfb_info *rinfo = info->par;
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci	return radeon_show_one_edid(buf, off, count, rinfo->mon2_EDID);
22208c2ecf20Sopenharmony_ci}
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_cistatic const struct bin_attribute edid1_attr = {
22238c2ecf20Sopenharmony_ci	.attr   = {
22248c2ecf20Sopenharmony_ci		.name	= "edid1",
22258c2ecf20Sopenharmony_ci		.mode	= 0444,
22268c2ecf20Sopenharmony_ci	},
22278c2ecf20Sopenharmony_ci	.size	= EDID_LENGTH,
22288c2ecf20Sopenharmony_ci	.read	= radeon_show_edid1,
22298c2ecf20Sopenharmony_ci};
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_cistatic const struct bin_attribute edid2_attr = {
22328c2ecf20Sopenharmony_ci	.attr   = {
22338c2ecf20Sopenharmony_ci		.name	= "edid2",
22348c2ecf20Sopenharmony_ci		.mode	= 0444,
22358c2ecf20Sopenharmony_ci	},
22368c2ecf20Sopenharmony_ci	.size	= EDID_LENGTH,
22378c2ecf20Sopenharmony_ci	.read	= radeon_show_edid2,
22388c2ecf20Sopenharmony_ci};
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_cistatic int radeon_kick_out_firmware_fb(struct pci_dev *pdev)
22418c2ecf20Sopenharmony_ci{
22428c2ecf20Sopenharmony_ci	struct apertures_struct *ap;
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	ap = alloc_apertures(1);
22458c2ecf20Sopenharmony_ci	if (!ap)
22468c2ecf20Sopenharmony_ci		return -ENOMEM;
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	ap->ranges[0].base = pci_resource_start(pdev, 0);
22498c2ecf20Sopenharmony_ci	ap->ranges[0].size = pci_resource_len(pdev, 0);
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci	remove_conflicting_framebuffers(ap, KBUILD_MODNAME, false);
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci	kfree(ap);
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	return 0;
22568c2ecf20Sopenharmony_ci}
22578c2ecf20Sopenharmony_ci
22588c2ecf20Sopenharmony_cistatic int radeonfb_pci_register(struct pci_dev *pdev,
22598c2ecf20Sopenharmony_ci				 const struct pci_device_id *ent)
22608c2ecf20Sopenharmony_ci{
22618c2ecf20Sopenharmony_ci	struct fb_info *info;
22628c2ecf20Sopenharmony_ci	struct radeonfb_info *rinfo;
22638c2ecf20Sopenharmony_ci	int ret;
22648c2ecf20Sopenharmony_ci	unsigned char c1, c2;
22658c2ecf20Sopenharmony_ci	int err = 0;
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_ci	pr_debug("radeonfb_pci_register BEGIN\n");
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci	/* Enable device in PCI config */
22708c2ecf20Sopenharmony_ci	ret = pci_enable_device(pdev);
22718c2ecf20Sopenharmony_ci	if (ret < 0) {
22728c2ecf20Sopenharmony_ci		printk(KERN_ERR "radeonfb (%s): Cannot enable PCI device\n",
22738c2ecf20Sopenharmony_ci		       pci_name(pdev));
22748c2ecf20Sopenharmony_ci		goto err_out;
22758c2ecf20Sopenharmony_ci	}
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci	info = framebuffer_alloc(sizeof(struct radeonfb_info), &pdev->dev);
22788c2ecf20Sopenharmony_ci	if (!info) {
22798c2ecf20Sopenharmony_ci		ret = -ENOMEM;
22808c2ecf20Sopenharmony_ci		goto err_disable;
22818c2ecf20Sopenharmony_ci	}
22828c2ecf20Sopenharmony_ci	rinfo = info->par;
22838c2ecf20Sopenharmony_ci	rinfo->info = info;
22848c2ecf20Sopenharmony_ci	rinfo->pdev = pdev;
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci	spin_lock_init(&rinfo->reg_lock);
22878c2ecf20Sopenharmony_ci	timer_setup(&rinfo->lvds_timer, radeon_lvds_timer_func, 0);
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci	c1 = ent->device >> 8;
22908c2ecf20Sopenharmony_ci	c2 = ent->device & 0xff;
22918c2ecf20Sopenharmony_ci	if (isprint(c1) && isprint(c2))
22928c2ecf20Sopenharmony_ci		snprintf(rinfo->name, sizeof(rinfo->name),
22938c2ecf20Sopenharmony_ci			 "ATI Radeon %x \"%c%c\"", ent->device & 0xffff, c1, c2);
22948c2ecf20Sopenharmony_ci	else
22958c2ecf20Sopenharmony_ci		snprintf(rinfo->name, sizeof(rinfo->name),
22968c2ecf20Sopenharmony_ci			 "ATI Radeon %x", ent->device & 0xffff);
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_ci	rinfo->family = ent->driver_data & CHIP_FAMILY_MASK;
22998c2ecf20Sopenharmony_ci	rinfo->chipset = pdev->device;
23008c2ecf20Sopenharmony_ci	rinfo->has_CRTC2 = (ent->driver_data & CHIP_HAS_CRTC2) != 0;
23018c2ecf20Sopenharmony_ci	rinfo->is_mobility = (ent->driver_data & CHIP_IS_MOBILITY) != 0;
23028c2ecf20Sopenharmony_ci	rinfo->is_IGP = (ent->driver_data & CHIP_IS_IGP) != 0;
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci	/* Set base addrs */
23058c2ecf20Sopenharmony_ci	rinfo->fb_base_phys = pci_resource_start (pdev, 0);
23068c2ecf20Sopenharmony_ci	rinfo->mmio_base_phys = pci_resource_start (pdev, 2);
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci	ret = radeon_kick_out_firmware_fb(pdev);
23098c2ecf20Sopenharmony_ci	if (ret)
23108c2ecf20Sopenharmony_ci		goto err_release_fb;
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci	/* request the mem regions */
23138c2ecf20Sopenharmony_ci	ret = pci_request_region(pdev, 0, "radeonfb framebuffer");
23148c2ecf20Sopenharmony_ci	if (ret < 0) {
23158c2ecf20Sopenharmony_ci		printk( KERN_ERR "radeonfb (%s): cannot request region 0.\n",
23168c2ecf20Sopenharmony_ci			pci_name(rinfo->pdev));
23178c2ecf20Sopenharmony_ci		goto err_release_fb;
23188c2ecf20Sopenharmony_ci	}
23198c2ecf20Sopenharmony_ci
23208c2ecf20Sopenharmony_ci	ret = pci_request_region(pdev, 2, "radeonfb mmio");
23218c2ecf20Sopenharmony_ci	if (ret < 0) {
23228c2ecf20Sopenharmony_ci		printk( KERN_ERR "radeonfb (%s): cannot request region 2.\n",
23238c2ecf20Sopenharmony_ci			pci_name(rinfo->pdev));
23248c2ecf20Sopenharmony_ci		goto err_release_pci0;
23258c2ecf20Sopenharmony_ci	}
23268c2ecf20Sopenharmony_ci
23278c2ecf20Sopenharmony_ci	/* map the regions */
23288c2ecf20Sopenharmony_ci	rinfo->mmio_base = ioremap(rinfo->mmio_base_phys, RADEON_REGSIZE);
23298c2ecf20Sopenharmony_ci	if (!rinfo->mmio_base) {
23308c2ecf20Sopenharmony_ci		printk(KERN_ERR "radeonfb (%s): cannot map MMIO\n",
23318c2ecf20Sopenharmony_ci		       pci_name(rinfo->pdev));
23328c2ecf20Sopenharmony_ci		ret = -EIO;
23338c2ecf20Sopenharmony_ci		goto err_release_pci2;
23348c2ecf20Sopenharmony_ci	}
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci	rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci	/*
23398c2ecf20Sopenharmony_ci	 * Check for errata
23408c2ecf20Sopenharmony_ci	 */
23418c2ecf20Sopenharmony_ci	rinfo->errata = 0;
23428c2ecf20Sopenharmony_ci	if (rinfo->family == CHIP_FAMILY_R300 &&
23438c2ecf20Sopenharmony_ci	    (INREG(CNFG_CNTL) & CFG_ATI_REV_ID_MASK)
23448c2ecf20Sopenharmony_ci	    == CFG_ATI_REV_A11)
23458c2ecf20Sopenharmony_ci		rinfo->errata |= CHIP_ERRATA_R300_CG;
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_ci	if (rinfo->family == CHIP_FAMILY_RV200 ||
23488c2ecf20Sopenharmony_ci	    rinfo->family == CHIP_FAMILY_RS200)
23498c2ecf20Sopenharmony_ci		rinfo->errata |= CHIP_ERRATA_PLL_DUMMYREADS;
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_ci	if (rinfo->family == CHIP_FAMILY_RV100 ||
23528c2ecf20Sopenharmony_ci	    rinfo->family == CHIP_FAMILY_RS100 ||
23538c2ecf20Sopenharmony_ci	    rinfo->family == CHIP_FAMILY_RS200)
23548c2ecf20Sopenharmony_ci		rinfo->errata |= CHIP_ERRATA_PLL_DELAY;
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_ci#if defined(CONFIG_PPC) || defined(CONFIG_SPARC)
23578c2ecf20Sopenharmony_ci	/* On PPC, we obtain the OF device-node pointer to the firmware
23588c2ecf20Sopenharmony_ci	 * data for this chip
23598c2ecf20Sopenharmony_ci	 */
23608c2ecf20Sopenharmony_ci	rinfo->of_node = pci_device_to_OF_node(pdev);
23618c2ecf20Sopenharmony_ci	if (rinfo->of_node == NULL)
23628c2ecf20Sopenharmony_ci		printk(KERN_WARNING "radeonfb (%s): Cannot match card to OF node !\n",
23638c2ecf20Sopenharmony_ci		       pci_name(rinfo->pdev));
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC || CONFIG_SPARC */
23668c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC
23678c2ecf20Sopenharmony_ci	/* On PPC, the firmware sets up a memory mapping that tends
23688c2ecf20Sopenharmony_ci	 * to cause lockups when enabling the engine. We reconfigure
23698c2ecf20Sopenharmony_ci	 * the card internal memory mappings properly
23708c2ecf20Sopenharmony_ci	 */
23718c2ecf20Sopenharmony_ci	fixup_memory_mappings(rinfo);
23728c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC */
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci	/* Get VRAM size and type */
23758c2ecf20Sopenharmony_ci	radeon_identify_vram(rinfo);
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_ci	rinfo->mapped_vram = min_t(unsigned long, MAX_MAPPED_VRAM, rinfo->video_ram);
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci	do {
23808c2ecf20Sopenharmony_ci		rinfo->fb_base = ioremap_wc(rinfo->fb_base_phys,
23818c2ecf20Sopenharmony_ci					    rinfo->mapped_vram);
23828c2ecf20Sopenharmony_ci	} while (rinfo->fb_base == NULL &&
23838c2ecf20Sopenharmony_ci		 ((rinfo->mapped_vram /= 2) >= MIN_MAPPED_VRAM));
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci	if (rinfo->fb_base == NULL) {
23868c2ecf20Sopenharmony_ci		printk (KERN_ERR "radeonfb (%s): cannot map FB\n",
23878c2ecf20Sopenharmony_ci			pci_name(rinfo->pdev));
23888c2ecf20Sopenharmony_ci		ret = -EIO;
23898c2ecf20Sopenharmony_ci		goto err_unmap_rom;
23908c2ecf20Sopenharmony_ci	}
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci	pr_debug("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev),
23938c2ecf20Sopenharmony_ci	       rinfo->mapped_vram/1024);
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci	/*
23968c2ecf20Sopenharmony_ci	 * Map the BIOS ROM if any and retrieve PLL parameters from
23978c2ecf20Sopenharmony_ci	 * the BIOS. We skip that on mobility chips as the real panel
23988c2ecf20Sopenharmony_ci	 * values we need aren't in the ROM but in the BIOS image in
23998c2ecf20Sopenharmony_ci	 * memory. This is definitely not the best meacnism though,
24008c2ecf20Sopenharmony_ci	 * we really need the arch code to tell us which is the "primary"
24018c2ecf20Sopenharmony_ci	 * video adapter to use the memory image (or better, the arch
24028c2ecf20Sopenharmony_ci	 * should provide us a copy of the BIOS image to shield us from
24038c2ecf20Sopenharmony_ci	 * archs who would store that elsewhere and/or could initialize
24048c2ecf20Sopenharmony_ci	 * more than one adapter during boot).
24058c2ecf20Sopenharmony_ci	 */
24068c2ecf20Sopenharmony_ci	if (!rinfo->is_mobility)
24078c2ecf20Sopenharmony_ci		radeon_map_ROM(rinfo, pdev);
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci	/*
24108c2ecf20Sopenharmony_ci	 * On x86, the primary display on laptop may have it's BIOS
24118c2ecf20Sopenharmony_ci	 * ROM elsewhere, try to locate it at the legacy memory hole.
24128c2ecf20Sopenharmony_ci	 * We probably need to make sure this is the primary display,
24138c2ecf20Sopenharmony_ci	 * but that is difficult without some arch support.
24148c2ecf20Sopenharmony_ci	 */
24158c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
24168c2ecf20Sopenharmony_ci	if (rinfo->bios_seg == NULL)
24178c2ecf20Sopenharmony_ci		radeon_find_mem_vbios(rinfo);
24188c2ecf20Sopenharmony_ci#endif
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci	/* If both above failed, try the BIOS ROM again for mobility
24218c2ecf20Sopenharmony_ci	 * chips
24228c2ecf20Sopenharmony_ci	 */
24238c2ecf20Sopenharmony_ci	if (rinfo->bios_seg == NULL && rinfo->is_mobility)
24248c2ecf20Sopenharmony_ci		radeon_map_ROM(rinfo, pdev);
24258c2ecf20Sopenharmony_ci
24268c2ecf20Sopenharmony_ci	/* Get informations about the board's PLL */
24278c2ecf20Sopenharmony_ci	radeon_get_pllinfo(rinfo);
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_RADEON_I2C
24308c2ecf20Sopenharmony_ci	/* Register I2C bus */
24318c2ecf20Sopenharmony_ci	radeon_create_i2c_busses(rinfo);
24328c2ecf20Sopenharmony_ci#endif
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	/* set all the vital stuff */
24358c2ecf20Sopenharmony_ci	radeon_set_fbinfo (rinfo);
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci	/* Probe screen types */
24388c2ecf20Sopenharmony_ci	radeon_probe_screens(rinfo, monitor_layout, ignore_edid);
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci	/* Build mode list, check out panel native model */
24418c2ecf20Sopenharmony_ci	radeon_check_modes(rinfo, mode_option);
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_ci	/* Register some sysfs stuff (should be done better) */
24448c2ecf20Sopenharmony_ci	if (rinfo->mon1_EDID)
24458c2ecf20Sopenharmony_ci		err |= sysfs_create_bin_file(&rinfo->pdev->dev.kobj,
24468c2ecf20Sopenharmony_ci						&edid1_attr);
24478c2ecf20Sopenharmony_ci	if (rinfo->mon2_EDID)
24488c2ecf20Sopenharmony_ci		err |= sysfs_create_bin_file(&rinfo->pdev->dev.kobj,
24498c2ecf20Sopenharmony_ci						&edid2_attr);
24508c2ecf20Sopenharmony_ci	if (err)
24518c2ecf20Sopenharmony_ci		pr_warn("%s() Creating sysfs files failed, continuing\n",
24528c2ecf20Sopenharmony_ci			__func__);
24538c2ecf20Sopenharmony_ci
24548c2ecf20Sopenharmony_ci	/* save current mode regs before we switch into the new one
24558c2ecf20Sopenharmony_ci	 * so we can restore this upon __exit
24568c2ecf20Sopenharmony_ci	 */
24578c2ecf20Sopenharmony_ci	radeon_save_state (rinfo, &rinfo->init_state);
24588c2ecf20Sopenharmony_ci	memcpy(&rinfo->state, &rinfo->init_state, sizeof(struct radeon_regs));
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci	/* Setup Power Management capabilities */
24618c2ecf20Sopenharmony_ci	if (default_dynclk < -1) {
24628c2ecf20Sopenharmony_ci		/* -2 is special: means  ON on mobility chips and do not
24638c2ecf20Sopenharmony_ci		 * change on others
24648c2ecf20Sopenharmony_ci		 */
24658c2ecf20Sopenharmony_ci		radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1, ignore_devlist, force_sleep);
24668c2ecf20Sopenharmony_ci	} else
24678c2ecf20Sopenharmony_ci		radeonfb_pm_init(rinfo, default_dynclk, ignore_devlist, force_sleep);
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, info);
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	/* Register with fbdev layer */
24728c2ecf20Sopenharmony_ci	ret = register_framebuffer(info);
24738c2ecf20Sopenharmony_ci	if (ret < 0) {
24748c2ecf20Sopenharmony_ci		printk (KERN_ERR "radeonfb (%s): could not register framebuffer\n",
24758c2ecf20Sopenharmony_ci			pci_name(rinfo->pdev));
24768c2ecf20Sopenharmony_ci		goto err_unmap_fb;
24778c2ecf20Sopenharmony_ci	}
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_ci	if (!nomtrr)
24808c2ecf20Sopenharmony_ci		rinfo->wc_cookie = arch_phys_wc_add(rinfo->fb_base_phys,
24818c2ecf20Sopenharmony_ci						    rinfo->video_ram);
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci	if (backlight)
24848c2ecf20Sopenharmony_ci		radeonfb_bl_init(rinfo);
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci	printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci	if (rinfo->bios_seg)
24898c2ecf20Sopenharmony_ci		radeon_unmap_ROM(rinfo, pdev);
24908c2ecf20Sopenharmony_ci	pr_debug("radeonfb_pci_register END\n");
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_ci	return 0;
24938c2ecf20Sopenharmony_cierr_unmap_fb:
24948c2ecf20Sopenharmony_ci	iounmap(rinfo->fb_base);
24958c2ecf20Sopenharmony_cierr_unmap_rom:
24968c2ecf20Sopenharmony_ci	kfree(rinfo->mon1_EDID);
24978c2ecf20Sopenharmony_ci	kfree(rinfo->mon2_EDID);
24988c2ecf20Sopenharmony_ci	if (rinfo->mon1_modedb)
24998c2ecf20Sopenharmony_ci		fb_destroy_modedb(rinfo->mon1_modedb);
25008c2ecf20Sopenharmony_ci	fb_dealloc_cmap(&info->cmap);
25018c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_RADEON_I2C
25028c2ecf20Sopenharmony_ci	radeon_delete_i2c_busses(rinfo);
25038c2ecf20Sopenharmony_ci#endif
25048c2ecf20Sopenharmony_ci	if (rinfo->bios_seg)
25058c2ecf20Sopenharmony_ci		radeon_unmap_ROM(rinfo, pdev);
25068c2ecf20Sopenharmony_ci	iounmap(rinfo->mmio_base);
25078c2ecf20Sopenharmony_cierr_release_pci2:
25088c2ecf20Sopenharmony_ci	pci_release_region(pdev, 2);
25098c2ecf20Sopenharmony_cierr_release_pci0:
25108c2ecf20Sopenharmony_ci	pci_release_region(pdev, 0);
25118c2ecf20Sopenharmony_cierr_release_fb:
25128c2ecf20Sopenharmony_ci        framebuffer_release(info);
25138c2ecf20Sopenharmony_cierr_disable:
25148c2ecf20Sopenharmony_cierr_out:
25158c2ecf20Sopenharmony_ci	return ret;
25168c2ecf20Sopenharmony_ci}
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_cistatic void radeonfb_pci_unregister(struct pci_dev *pdev)
25218c2ecf20Sopenharmony_ci{
25228c2ecf20Sopenharmony_ci        struct fb_info *info = pci_get_drvdata(pdev);
25238c2ecf20Sopenharmony_ci        struct radeonfb_info *rinfo = info->par;
25248c2ecf20Sopenharmony_ci
25258c2ecf20Sopenharmony_ci        if (!rinfo)
25268c2ecf20Sopenharmony_ci                return;
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci	radeonfb_pm_exit(rinfo);
25298c2ecf20Sopenharmony_ci
25308c2ecf20Sopenharmony_ci	if (rinfo->mon1_EDID)
25318c2ecf20Sopenharmony_ci		sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid1_attr);
25328c2ecf20Sopenharmony_ci	if (rinfo->mon2_EDID)
25338c2ecf20Sopenharmony_ci		sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid2_attr);
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ci	del_timer_sync(&rinfo->lvds_timer);
25368c2ecf20Sopenharmony_ci	arch_phys_wc_del(rinfo->wc_cookie);
25378c2ecf20Sopenharmony_ci        unregister_framebuffer(info);
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci        radeonfb_bl_exit(rinfo);
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci        iounmap(rinfo->mmio_base);
25428c2ecf20Sopenharmony_ci        iounmap(rinfo->fb_base);
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci	pci_release_region(pdev, 2);
25458c2ecf20Sopenharmony_ci	pci_release_region(pdev, 0);
25468c2ecf20Sopenharmony_ci
25478c2ecf20Sopenharmony_ci	kfree(rinfo->mon1_EDID);
25488c2ecf20Sopenharmony_ci	kfree(rinfo->mon2_EDID);
25498c2ecf20Sopenharmony_ci	if (rinfo->mon1_modedb)
25508c2ecf20Sopenharmony_ci		fb_destroy_modedb(rinfo->mon1_modedb);
25518c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_RADEON_I2C
25528c2ecf20Sopenharmony_ci	radeon_delete_i2c_busses(rinfo);
25538c2ecf20Sopenharmony_ci#endif
25548c2ecf20Sopenharmony_ci	fb_dealloc_cmap(&info->cmap);
25558c2ecf20Sopenharmony_ci        framebuffer_release(info);
25568c2ecf20Sopenharmony_ci}
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
25598c2ecf20Sopenharmony_ci#define RADEONFB_PCI_PM_OPS (&radeonfb_pci_pm_ops)
25608c2ecf20Sopenharmony_ci#else
25618c2ecf20Sopenharmony_ci#define RADEONFB_PCI_PM_OPS NULL
25628c2ecf20Sopenharmony_ci#endif
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_cistatic struct pci_driver radeonfb_driver = {
25658c2ecf20Sopenharmony_ci	.name		= "radeonfb",
25668c2ecf20Sopenharmony_ci	.id_table	= radeonfb_pci_table,
25678c2ecf20Sopenharmony_ci	.probe		= radeonfb_pci_register,
25688c2ecf20Sopenharmony_ci	.remove		= radeonfb_pci_unregister,
25698c2ecf20Sopenharmony_ci	.driver.pm	= RADEONFB_PCI_PM_OPS,
25708c2ecf20Sopenharmony_ci};
25718c2ecf20Sopenharmony_ci
25728c2ecf20Sopenharmony_ci#ifndef MODULE
25738c2ecf20Sopenharmony_cistatic int __init radeonfb_setup (char *options)
25748c2ecf20Sopenharmony_ci{
25758c2ecf20Sopenharmony_ci	char *this_opt;
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_ci	if (!options || !*options)
25788c2ecf20Sopenharmony_ci		return 0;
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	while ((this_opt = strsep (&options, ",")) != NULL) {
25818c2ecf20Sopenharmony_ci		if (!*this_opt)
25828c2ecf20Sopenharmony_ci			continue;
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci		if (!strncmp(this_opt, "noaccel", 7)) {
25858c2ecf20Sopenharmony_ci			noaccel = 1;
25868c2ecf20Sopenharmony_ci		} else if (!strncmp(this_opt, "mirror", 6)) {
25878c2ecf20Sopenharmony_ci			mirror = 1;
25888c2ecf20Sopenharmony_ci		} else if (!strncmp(this_opt, "force_dfp", 9)) {
25898c2ecf20Sopenharmony_ci			force_dfp = 1;
25908c2ecf20Sopenharmony_ci		} else if (!strncmp(this_opt, "panel_yres:", 11)) {
25918c2ecf20Sopenharmony_ci			panel_yres = simple_strtoul((this_opt+11), NULL, 0);
25928c2ecf20Sopenharmony_ci		} else if (!strncmp(this_opt, "backlight:", 10)) {
25938c2ecf20Sopenharmony_ci			backlight = simple_strtoul(this_opt+10, NULL, 0);
25948c2ecf20Sopenharmony_ci		} else if (!strncmp(this_opt, "nomtrr", 6)) {
25958c2ecf20Sopenharmony_ci			nomtrr = 1;
25968c2ecf20Sopenharmony_ci		} else if (!strncmp(this_opt, "nomodeset", 9)) {
25978c2ecf20Sopenharmony_ci			nomodeset = 1;
25988c2ecf20Sopenharmony_ci		} else if (!strncmp(this_opt, "force_measure_pll", 17)) {
25998c2ecf20Sopenharmony_ci			force_measure_pll = 1;
26008c2ecf20Sopenharmony_ci		} else if (!strncmp(this_opt, "ignore_edid", 11)) {
26018c2ecf20Sopenharmony_ci			ignore_edid = 1;
26028c2ecf20Sopenharmony_ci#if defined(CONFIG_PM) && defined(CONFIG_X86)
26038c2ecf20Sopenharmony_ci	 	} else if (!strncmp(this_opt, "force_sleep", 11)) {
26048c2ecf20Sopenharmony_ci			force_sleep = 1;
26058c2ecf20Sopenharmony_ci		} else if (!strncmp(this_opt, "ignore_devlist", 14)) {
26068c2ecf20Sopenharmony_ci			ignore_devlist = 1;
26078c2ecf20Sopenharmony_ci#endif
26088c2ecf20Sopenharmony_ci		} else
26098c2ecf20Sopenharmony_ci			mode_option = this_opt;
26108c2ecf20Sopenharmony_ci	}
26118c2ecf20Sopenharmony_ci	return 0;
26128c2ecf20Sopenharmony_ci}
26138c2ecf20Sopenharmony_ci#endif  /*  MODULE  */
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_cistatic int __init radeonfb_init (void)
26168c2ecf20Sopenharmony_ci{
26178c2ecf20Sopenharmony_ci#ifndef MODULE
26188c2ecf20Sopenharmony_ci	char *option = NULL;
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci	if (fb_get_options("radeonfb", &option))
26218c2ecf20Sopenharmony_ci		return -ENODEV;
26228c2ecf20Sopenharmony_ci	radeonfb_setup(option);
26238c2ecf20Sopenharmony_ci#endif
26248c2ecf20Sopenharmony_ci	return pci_register_driver (&radeonfb_driver);
26258c2ecf20Sopenharmony_ci}
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci
26288c2ecf20Sopenharmony_cistatic void __exit radeonfb_exit (void)
26298c2ecf20Sopenharmony_ci{
26308c2ecf20Sopenharmony_ci	pci_unregister_driver (&radeonfb_driver);
26318c2ecf20Sopenharmony_ci}
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_cimodule_init(radeonfb_init);
26348c2ecf20Sopenharmony_cimodule_exit(radeonfb_exit);
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ani Joshi");
26378c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset");
26388c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
26398c2ecf20Sopenharmony_cimodule_param(noaccel, bool, 0);
26408c2ecf20Sopenharmony_cimodule_param(default_dynclk, int, 0);
26418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(default_dynclk, "int: -2=enable on mobility only,-1=do not change,0=off,1=on");
26428c2ecf20Sopenharmony_ciMODULE_PARM_DESC(noaccel, "bool: disable acceleration");
26438c2ecf20Sopenharmony_cimodule_param(nomodeset, bool, 0);
26448c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nomodeset, "bool: disable actual setting of video mode");
26458c2ecf20Sopenharmony_cimodule_param(mirror, bool, 0);
26468c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mirror, "bool: mirror the display to both monitors");
26478c2ecf20Sopenharmony_cimodule_param(force_dfp, bool, 0);
26488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force_dfp, "bool: force display to dfp");
26498c2ecf20Sopenharmony_cimodule_param(ignore_edid, bool, 0);
26508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ignore_edid, "bool: Ignore EDID data when doing DDC probe");
26518c2ecf20Sopenharmony_cimodule_param(monitor_layout, charp, 0);
26528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(monitor_layout, "Specify monitor mapping (like XFree86)");
26538c2ecf20Sopenharmony_cimodule_param(force_measure_pll, bool, 0);
26548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force_measure_pll, "Force measurement of PLL (debug)");
26558c2ecf20Sopenharmony_cimodule_param(nomtrr, bool, 0);
26568c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nomtrr, "bool: disable use of MTRR registers");
26578c2ecf20Sopenharmony_cimodule_param(panel_yres, int, 0);
26588c2ecf20Sopenharmony_ciMODULE_PARM_DESC(panel_yres, "int: set panel yres");
26598c2ecf20Sopenharmony_cimodule_param(mode_option, charp, 0);
26608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
26618c2ecf20Sopenharmony_ci#if defined(CONFIG_PM) && defined(CONFIG_X86)
26628c2ecf20Sopenharmony_cimodule_param(force_sleep, bool, 0);
26638c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force_sleep, "bool: force D2 sleep mode on all hardware");
26648c2ecf20Sopenharmony_cimodule_param(ignore_devlist, bool, 0);
26658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ignore_devlist, "bool: ignore workarounds for bugs in specific laptops");
26668c2ecf20Sopenharmony_ci#endif
2667