162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * drivers/video/aty/radeon_base.c 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * framebuffer driver for ATI Radeon chipset video boards 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright 2003 Ben. Herrenschmidt <benh@kernel.crashing.org> 762306a36Sopenharmony_ci * Copyright 2000 Ani Joshi <ajoshi@kernel.crashing.org> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * i2c bits from Luca Tettamanti <kronos@kronoz.cjb.net> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Special thanks to ATI DevRel team for their hardware donations. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * ...Insert GPL boilerplate here... 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Significant portions of this driver apdated from XFree86 Radeon 1662306a36Sopenharmony_ci * driver which has the following copyright notice: 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and 1962306a36Sopenharmony_ci * VA Linux Systems Inc., Fremont, California. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * All Rights Reserved. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining 2462306a36Sopenharmony_ci * a copy of this software and associated documentation files (the 2562306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 2662306a36Sopenharmony_ci * without limitation on the rights to use, copy, modify, merge, 2762306a36Sopenharmony_ci * publish, distribute, sublicense, and/or sell copies of the Software, 2862306a36Sopenharmony_ci * and to permit persons to whom the Software is furnished to do so, 2962306a36Sopenharmony_ci * subject to the following conditions: 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 3262306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial 3362306a36Sopenharmony_ci * portions of the Software. 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 3662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 3762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 3862306a36Sopenharmony_ci * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR 3962306a36Sopenharmony_ci * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 4062306a36Sopenharmony_ci * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 4162306a36Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 4262306a36Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * XFree86 driver authors: 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * Kevin E. Martin <martin@xfree86.org> 4762306a36Sopenharmony_ci * Rickard E. Faith <faith@valinux.com> 4862306a36Sopenharmony_ci * Alan Hourihane <alanh@fairlite.demon.co.uk> 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define RADEON_VERSION "0.2.0" 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#include "radeonfb.h" 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#include <linux/aperture.h> 5862306a36Sopenharmony_ci#include <linux/module.h> 5962306a36Sopenharmony_ci#include <linux/moduleparam.h> 6062306a36Sopenharmony_ci#include <linux/kernel.h> 6162306a36Sopenharmony_ci#include <linux/errno.h> 6262306a36Sopenharmony_ci#include <linux/string.h> 6362306a36Sopenharmony_ci#include <linux/ctype.h> 6462306a36Sopenharmony_ci#include <linux/mm.h> 6562306a36Sopenharmony_ci#include <linux/slab.h> 6662306a36Sopenharmony_ci#include <linux/delay.h> 6762306a36Sopenharmony_ci#include <linux/time.h> 6862306a36Sopenharmony_ci#include <linux/fb.h> 6962306a36Sopenharmony_ci#include <linux/ioport.h> 7062306a36Sopenharmony_ci#include <linux/init.h> 7162306a36Sopenharmony_ci#include <linux/pci.h> 7262306a36Sopenharmony_ci#include <linux/vmalloc.h> 7362306a36Sopenharmony_ci#include <linux/device.h> 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#include <asm/io.h> 7662306a36Sopenharmony_ci#include <linux/uaccess.h> 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#ifdef CONFIG_PPC 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#include "../macmodes.h" 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#ifdef CONFIG_BOOTX_TEXT 8362306a36Sopenharmony_ci#include <asm/btext.h> 8462306a36Sopenharmony_ci#endif 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#endif /* CONFIG_PPC */ 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#include <video/radeon.h> 8962306a36Sopenharmony_ci#include <linux/radeonfb.h> 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#include "../edid.h" // MOVE THAT TO include/video 9262306a36Sopenharmony_ci#include "ati_ids.h" 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define MAX_MAPPED_VRAM (2048*2048*4) 9562306a36Sopenharmony_ci#define MIN_MAPPED_VRAM (1024*768*1) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define CHIP_DEF(id, family, flags) \ 9862306a36Sopenharmony_ci { PCI_VENDOR_ID_ATI, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (flags) | (CHIP_FAMILY_##family) } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic const struct pci_device_id radeonfb_pci_table[] = { 10162306a36Sopenharmony_ci /* Radeon Xpress 200m */ 10262306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RS480_5955, RS480, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), 10362306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RS482_5975, RS480, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), 10462306a36Sopenharmony_ci /* Mobility M6 */ 10562306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RADEON_LY, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 10662306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RADEON_LZ, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 10762306a36Sopenharmony_ci /* Radeon VE/7000 */ 10862306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV100_QY, RV100, CHIP_HAS_CRTC2), 10962306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV100_QZ, RV100, CHIP_HAS_CRTC2), 11062306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RN50, RV100, CHIP_HAS_CRTC2), 11162306a36Sopenharmony_ci /* Radeon IGP320M (U1) */ 11262306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RS100_4336, RS100, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), 11362306a36Sopenharmony_ci /* Radeon IGP320 (A3) */ 11462306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RS100_4136, RS100, CHIP_HAS_CRTC2 | CHIP_IS_IGP), 11562306a36Sopenharmony_ci /* IGP330M/340M/350M (U2) */ 11662306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RS200_4337, RS200, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), 11762306a36Sopenharmony_ci /* IGP330/340/350 (A4) */ 11862306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RS200_4137, RS200, CHIP_HAS_CRTC2 | CHIP_IS_IGP), 11962306a36Sopenharmony_ci /* Mobility 7000 IGP */ 12062306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RS250_4437, RS200, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), 12162306a36Sopenharmony_ci /* 7000 IGP (A4+) */ 12262306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RS250_4237, RS200, CHIP_HAS_CRTC2 | CHIP_IS_IGP), 12362306a36Sopenharmony_ci /* 8500 AIW */ 12462306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R200_BB, R200, CHIP_HAS_CRTC2), 12562306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R200_BC, R200, CHIP_HAS_CRTC2), 12662306a36Sopenharmony_ci /* 8700/8800 */ 12762306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R200_QH, R200, CHIP_HAS_CRTC2), 12862306a36Sopenharmony_ci /* 8500 */ 12962306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R200_QL, R200, CHIP_HAS_CRTC2), 13062306a36Sopenharmony_ci /* 9100 */ 13162306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R200_QM, R200, CHIP_HAS_CRTC2), 13262306a36Sopenharmony_ci /* Mobility M7 */ 13362306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RADEON_LW, RV200, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 13462306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RADEON_LX, RV200, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 13562306a36Sopenharmony_ci /* 7500 */ 13662306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV200_QW, RV200, CHIP_HAS_CRTC2), 13762306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV200_QX, RV200, CHIP_HAS_CRTC2), 13862306a36Sopenharmony_ci /* Mobility M9 */ 13962306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV250_Ld, RV250, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 14062306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV250_Le, RV250, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 14162306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV250_Lf, RV250, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 14262306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV250_Lg, RV250, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 14362306a36Sopenharmony_ci /* 9000/Pro */ 14462306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV250_If, RV250, CHIP_HAS_CRTC2), 14562306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV250_Ig, RV250, CHIP_HAS_CRTC2), 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RC410_5A62, RC410, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), 14862306a36Sopenharmony_ci /* Mobility 9100 IGP (U3) */ 14962306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RS300_5835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), 15062306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RS350_7835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), 15162306a36Sopenharmony_ci /* 9100 IGP (A5) */ 15262306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RS300_5834, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP), 15362306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RS350_7834, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP), 15462306a36Sopenharmony_ci /* Mobility 9200 (M9+) */ 15562306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV280_5C61, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 15662306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV280_5C63, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 15762306a36Sopenharmony_ci /* 9200 */ 15862306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV280_5960, RV280, CHIP_HAS_CRTC2), 15962306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV280_5961, RV280, CHIP_HAS_CRTC2), 16062306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV280_5962, RV280, CHIP_HAS_CRTC2), 16162306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV280_5964, RV280, CHIP_HAS_CRTC2), 16262306a36Sopenharmony_ci /* 9500 */ 16362306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R300_AD, R300, CHIP_HAS_CRTC2), 16462306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R300_AE, R300, CHIP_HAS_CRTC2), 16562306a36Sopenharmony_ci /* 9600TX / FireGL Z1 */ 16662306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R300_AF, R300, CHIP_HAS_CRTC2), 16762306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R300_AG, R300, CHIP_HAS_CRTC2), 16862306a36Sopenharmony_ci /* 9700/9500/Pro/FireGL X1 */ 16962306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R300_ND, R300, CHIP_HAS_CRTC2), 17062306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R300_NE, R300, CHIP_HAS_CRTC2), 17162306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R300_NF, R300, CHIP_HAS_CRTC2), 17262306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R300_NG, R300, CHIP_HAS_CRTC2), 17362306a36Sopenharmony_ci /* Mobility M10/M11 */ 17462306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV350_NP, RV350, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 17562306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV350_NQ, RV350, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 17662306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV350_NR, RV350, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 17762306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV350_NS, RV350, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 17862306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV350_NT, RV350, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 17962306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV350_NV, RV350, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 18062306a36Sopenharmony_ci /* 9600/FireGL T2 */ 18162306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV350_AP, RV350, CHIP_HAS_CRTC2), 18262306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV350_AQ, RV350, CHIP_HAS_CRTC2), 18362306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV360_AR, RV350, CHIP_HAS_CRTC2), 18462306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV350_AS, RV350, CHIP_HAS_CRTC2), 18562306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV350_AT, RV350, CHIP_HAS_CRTC2), 18662306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV350_AV, RV350, CHIP_HAS_CRTC2), 18762306a36Sopenharmony_ci /* 9800/Pro/FileGL X2 */ 18862306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R350_AH, R350, CHIP_HAS_CRTC2), 18962306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R350_AI, R350, CHIP_HAS_CRTC2), 19062306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R350_AJ, R350, CHIP_HAS_CRTC2), 19162306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R350_AK, R350, CHIP_HAS_CRTC2), 19262306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R350_NH, R350, CHIP_HAS_CRTC2), 19362306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R350_NI, R350, CHIP_HAS_CRTC2), 19462306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R360_NJ, R350, CHIP_HAS_CRTC2), 19562306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R350_NK, R350, CHIP_HAS_CRTC2), 19662306a36Sopenharmony_ci /* Newer stuff */ 19762306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV380_3E50, RV380, CHIP_HAS_CRTC2), 19862306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV380_3E54, RV380, CHIP_HAS_CRTC2), 19962306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV380_3150, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 20062306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV380_3154, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 20162306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV370_5B60, RV380, CHIP_HAS_CRTC2), 20262306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV370_5B62, RV380, CHIP_HAS_CRTC2), 20362306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV370_5B63, RV380, CHIP_HAS_CRTC2), 20462306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV370_5B64, RV380, CHIP_HAS_CRTC2), 20562306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV370_5B65, RV380, CHIP_HAS_CRTC2), 20662306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV370_5460, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 20762306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RV370_5464, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 20862306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R420_JH, R420, CHIP_HAS_CRTC2), 20962306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R420_JI, R420, CHIP_HAS_CRTC2), 21062306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R420_JJ, R420, CHIP_HAS_CRTC2), 21162306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R420_JK, R420, CHIP_HAS_CRTC2), 21262306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R420_JL, R420, CHIP_HAS_CRTC2), 21362306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R420_JM, R420, CHIP_HAS_CRTC2), 21462306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R420_JN, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), 21562306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R420_JP, R420, CHIP_HAS_CRTC2), 21662306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R423_UH, R420, CHIP_HAS_CRTC2), 21762306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R423_UI, R420, CHIP_HAS_CRTC2), 21862306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R423_UJ, R420, CHIP_HAS_CRTC2), 21962306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R423_UK, R420, CHIP_HAS_CRTC2), 22062306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R423_UQ, R420, CHIP_HAS_CRTC2), 22162306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R423_UR, R420, CHIP_HAS_CRTC2), 22262306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R423_UT, R420, CHIP_HAS_CRTC2), 22362306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_R423_5D57, R420, CHIP_HAS_CRTC2), 22462306a36Sopenharmony_ci /* Original Radeon/7200 */ 22562306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RADEON_QD, RADEON, 0), 22662306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RADEON_QE, RADEON, 0), 22762306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RADEON_QF, RADEON, 0), 22862306a36Sopenharmony_ci CHIP_DEF(PCI_CHIP_RADEON_QG, RADEON, 0), 22962306a36Sopenharmony_ci { 0, } 23062306a36Sopenharmony_ci}; 23162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, radeonfb_pci_table); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_citypedef struct { 23562306a36Sopenharmony_ci u16 reg; 23662306a36Sopenharmony_ci u32 val; 23762306a36Sopenharmony_ci} reg_val; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/* these common regs are cleared before mode setting so they do not 24162306a36Sopenharmony_ci * interfere with anything 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_cistatic reg_val common_regs[] = { 24462306a36Sopenharmony_ci { OVR_CLR, 0 }, 24562306a36Sopenharmony_ci { OVR_WID_LEFT_RIGHT, 0 }, 24662306a36Sopenharmony_ci { OVR_WID_TOP_BOTTOM, 0 }, 24762306a36Sopenharmony_ci { OV0_SCALE_CNTL, 0 }, 24862306a36Sopenharmony_ci { SUBPIC_CNTL, 0 }, 24962306a36Sopenharmony_ci { VIPH_CONTROL, 0 }, 25062306a36Sopenharmony_ci { I2C_CNTL_1, 0 }, 25162306a36Sopenharmony_ci { GEN_INT_CNTL, 0 }, 25262306a36Sopenharmony_ci { CAP0_TRIG_CNTL, 0 }, 25362306a36Sopenharmony_ci { CAP1_TRIG_CNTL, 0 }, 25462306a36Sopenharmony_ci}; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/* 25762306a36Sopenharmony_ci * globals 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic char *mode_option; 26162306a36Sopenharmony_cistatic char *monitor_layout; 26262306a36Sopenharmony_cistatic bool noaccel = 0; 26362306a36Sopenharmony_cistatic int default_dynclk = -2; 26462306a36Sopenharmony_cistatic bool nomodeset = 0; 26562306a36Sopenharmony_cistatic bool ignore_edid = 0; 26662306a36Sopenharmony_cistatic bool mirror = 0; 26762306a36Sopenharmony_cistatic int panel_yres = 0; 26862306a36Sopenharmony_cistatic bool force_dfp = 0; 26962306a36Sopenharmony_cistatic bool force_measure_pll = 0; 27062306a36Sopenharmony_cistatic bool nomtrr = 0; 27162306a36Sopenharmony_cistatic bool force_sleep; 27262306a36Sopenharmony_cistatic bool ignore_devlist; 27362306a36Sopenharmony_cistatic int backlight = IS_BUILTIN(CONFIG_PMAC_BACKLIGHT); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/* Note about this function: we have some rare cases where we must not schedule, 27662306a36Sopenharmony_ci * this typically happen with our special "wake up early" hook which allows us to 27762306a36Sopenharmony_ci * wake up the graphic chip (and thus get the console back) before everything else 27862306a36Sopenharmony_ci * on some machines that support that mechanism. At this point, interrupts are off 27962306a36Sopenharmony_ci * and scheduling is not permitted 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_civoid _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci if (rinfo->no_schedule || oops_in_progress) 28462306a36Sopenharmony_ci mdelay(ms); 28562306a36Sopenharmony_ci else 28662306a36Sopenharmony_ci msleep(ms); 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_civoid radeon_pll_errata_after_index_slow(struct radeonfb_info *rinfo) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci /* Called if (rinfo->errata & CHIP_ERRATA_PLL_DUMMYREADS) is set */ 29262306a36Sopenharmony_ci (void)INREG(CLOCK_CNTL_DATA); 29362306a36Sopenharmony_ci (void)INREG(CRTC_GEN_CNTL); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_civoid radeon_pll_errata_after_data_slow(struct radeonfb_info *rinfo) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci if (rinfo->errata & CHIP_ERRATA_PLL_DELAY) { 29962306a36Sopenharmony_ci /* we can't deal with posted writes here ... */ 30062306a36Sopenharmony_ci _radeon_msleep(rinfo, 5); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci if (rinfo->errata & CHIP_ERRATA_R300_CG) { 30362306a36Sopenharmony_ci u32 save, tmp; 30462306a36Sopenharmony_ci save = INREG(CLOCK_CNTL_INDEX); 30562306a36Sopenharmony_ci tmp = save & ~(0x3f | PLL_WR_EN); 30662306a36Sopenharmony_ci OUTREG(CLOCK_CNTL_INDEX, tmp); 30762306a36Sopenharmony_ci tmp = INREG(CLOCK_CNTL_DATA); 30862306a36Sopenharmony_ci OUTREG(CLOCK_CNTL_INDEX, save); 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_civoid _OUTREGP(struct radeonfb_info *rinfo, u32 addr, u32 val, u32 mask) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci unsigned long flags; 31562306a36Sopenharmony_ci unsigned int tmp; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci spin_lock_irqsave(&rinfo->reg_lock, flags); 31862306a36Sopenharmony_ci tmp = INREG(addr); 31962306a36Sopenharmony_ci tmp &= (mask); 32062306a36Sopenharmony_ci tmp |= (val); 32162306a36Sopenharmony_ci OUTREG(addr, tmp); 32262306a36Sopenharmony_ci spin_unlock_irqrestore(&rinfo->reg_lock, flags); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ciu32 __INPLL(struct radeonfb_info *rinfo, u32 addr) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci u32 data; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f); 33062306a36Sopenharmony_ci radeon_pll_errata_after_index(rinfo); 33162306a36Sopenharmony_ci data = INREG(CLOCK_CNTL_DATA); 33262306a36Sopenharmony_ci radeon_pll_errata_after_data(rinfo); 33362306a36Sopenharmony_ci return data; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_civoid __OUTPLL(struct radeonfb_info *rinfo, unsigned int index, u32 val) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci OUTREG8(CLOCK_CNTL_INDEX, (index & 0x0000003f) | 0x00000080); 33962306a36Sopenharmony_ci radeon_pll_errata_after_index(rinfo); 34062306a36Sopenharmony_ci OUTREG(CLOCK_CNTL_DATA, val); 34162306a36Sopenharmony_ci radeon_pll_errata_after_data(rinfo); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_civoid __OUTPLLP(struct radeonfb_info *rinfo, unsigned int index, 34562306a36Sopenharmony_ci u32 val, u32 mask) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci unsigned int tmp; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci tmp = __INPLL(rinfo, index); 35062306a36Sopenharmony_ci tmp &= (mask); 35162306a36Sopenharmony_ci tmp |= (val); 35262306a36Sopenharmony_ci __OUTPLL(rinfo, index, tmp); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_civoid _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci int i; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci for (i=0; i<2000000; i++) { 36062306a36Sopenharmony_ci if ((INREG(RBBM_STATUS) & 0x7f) >= entries) 36162306a36Sopenharmony_ci return; 36262306a36Sopenharmony_ci udelay(1); 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci printk(KERN_ERR "radeonfb: FIFO Timeout !\n"); 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_civoid radeon_engine_flush(struct radeonfb_info *rinfo) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci int i; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* Initiate flush */ 37262306a36Sopenharmony_ci OUTREGP(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL, 37362306a36Sopenharmony_ci ~RB2D_DC_FLUSH_ALL); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* Ensure FIFO is empty, ie, make sure the flush commands 37662306a36Sopenharmony_ci * has reached the cache 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci _radeon_fifo_wait(rinfo, 64); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* Wait for the flush to complete */ 38162306a36Sopenharmony_ci for (i=0; i < 2000000; i++) { 38262306a36Sopenharmony_ci if (!(INREG(DSTCACHE_CTLSTAT) & RB2D_DC_BUSY)) 38362306a36Sopenharmony_ci return; 38462306a36Sopenharmony_ci udelay(1); 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci printk(KERN_ERR "radeonfb: Flush Timeout !\n"); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_civoid _radeon_engine_idle(struct radeonfb_info *rinfo) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci int i; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* ensure FIFO is empty before waiting for idle */ 39462306a36Sopenharmony_ci _radeon_fifo_wait(rinfo, 64); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci for (i=0; i<2000000; i++) { 39762306a36Sopenharmony_ci if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) { 39862306a36Sopenharmony_ci radeon_engine_flush(rinfo); 39962306a36Sopenharmony_ci return; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci udelay(1); 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci printk(KERN_ERR "radeonfb: Idle Timeout !\n"); 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci if (!rinfo->bios_seg) 41162306a36Sopenharmony_ci return; 41262306a36Sopenharmony_ci pci_unmap_rom(dev, rinfo->bios_seg); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci void __iomem *rom; 41862306a36Sopenharmony_ci u16 dptr; 41962306a36Sopenharmony_ci u8 rom_type; 42062306a36Sopenharmony_ci size_t rom_size; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* If this is a primary card, there is a shadow copy of the 42362306a36Sopenharmony_ci * ROM somewhere in the first meg. We will just ignore the copy 42462306a36Sopenharmony_ci * and use the ROM directly. 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* Fix from ATI for problem with Radeon hardware not leaving ROM enabled */ 42862306a36Sopenharmony_ci unsigned int temp; 42962306a36Sopenharmony_ci temp = INREG(MPP_TB_CONFIG); 43062306a36Sopenharmony_ci temp &= 0x00ffffffu; 43162306a36Sopenharmony_ci temp |= 0x04 << 24; 43262306a36Sopenharmony_ci OUTREG(MPP_TB_CONFIG, temp); 43362306a36Sopenharmony_ci temp = INREG(MPP_TB_CONFIG); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci rom = pci_map_rom(dev, &rom_size); 43662306a36Sopenharmony_ci if (!rom) { 43762306a36Sopenharmony_ci printk(KERN_ERR "radeonfb (%s): ROM failed to map\n", 43862306a36Sopenharmony_ci pci_name(rinfo->pdev)); 43962306a36Sopenharmony_ci return -ENOMEM; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci rinfo->bios_seg = rom; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* Very simple test to make sure it appeared */ 44562306a36Sopenharmony_ci if (BIOS_IN16(0) != 0xaa55) { 44662306a36Sopenharmony_ci printk(KERN_DEBUG "radeonfb (%s): Invalid ROM signature %x " 44762306a36Sopenharmony_ci "should be 0xaa55\n", 44862306a36Sopenharmony_ci pci_name(rinfo->pdev), BIOS_IN16(0)); 44962306a36Sopenharmony_ci goto failed; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci /* Look for the PCI data to check the ROM type */ 45262306a36Sopenharmony_ci dptr = BIOS_IN16(0x18); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* Check the PCI data signature. If it's wrong, we still assume a normal x86 ROM 45562306a36Sopenharmony_ci * for now, until I've verified this works everywhere. The goal here is more 45662306a36Sopenharmony_ci * to phase out Open Firmware images. 45762306a36Sopenharmony_ci * 45862306a36Sopenharmony_ci * Currently, we only look at the first PCI data, we could iteratre and deal with 45962306a36Sopenharmony_ci * them all, and we should use fb_bios_start relative to start of image and not 46062306a36Sopenharmony_ci * relative start of ROM, but so far, I never found a dual-image ATI card 46162306a36Sopenharmony_ci * 46262306a36Sopenharmony_ci * typedef struct { 46362306a36Sopenharmony_ci * u32 signature; + 0x00 46462306a36Sopenharmony_ci * u16 vendor; + 0x04 46562306a36Sopenharmony_ci * u16 device; + 0x06 46662306a36Sopenharmony_ci * u16 reserved_1; + 0x08 46762306a36Sopenharmony_ci * u16 dlen; + 0x0a 46862306a36Sopenharmony_ci * u8 drevision; + 0x0c 46962306a36Sopenharmony_ci * u8 class_hi; + 0x0d 47062306a36Sopenharmony_ci * u16 class_lo; + 0x0e 47162306a36Sopenharmony_ci * u16 ilen; + 0x10 47262306a36Sopenharmony_ci * u16 irevision; + 0x12 47362306a36Sopenharmony_ci * u8 type; + 0x14 47462306a36Sopenharmony_ci * u8 indicator; + 0x15 47562306a36Sopenharmony_ci * u16 reserved_2; + 0x16 47662306a36Sopenharmony_ci * } pci_data_t; 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_ci if (BIOS_IN32(dptr) != (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) { 47962306a36Sopenharmony_ci printk(KERN_WARNING "radeonfb (%s): PCI DATA signature in ROM" 48062306a36Sopenharmony_ci "incorrect: %08x\n", pci_name(rinfo->pdev), BIOS_IN32(dptr)); 48162306a36Sopenharmony_ci goto anyway; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci rom_type = BIOS_IN8(dptr + 0x14); 48462306a36Sopenharmony_ci switch(rom_type) { 48562306a36Sopenharmony_ci case 0: 48662306a36Sopenharmony_ci printk(KERN_INFO "radeonfb: Found Intel x86 BIOS ROM Image\n"); 48762306a36Sopenharmony_ci break; 48862306a36Sopenharmony_ci case 1: 48962306a36Sopenharmony_ci printk(KERN_INFO "radeonfb: Found Open Firmware ROM Image\n"); 49062306a36Sopenharmony_ci goto failed; 49162306a36Sopenharmony_ci case 2: 49262306a36Sopenharmony_ci printk(KERN_INFO "radeonfb: Found HP PA-RISC ROM Image\n"); 49362306a36Sopenharmony_ci goto failed; 49462306a36Sopenharmony_ci default: 49562306a36Sopenharmony_ci printk(KERN_INFO "radeonfb: Found unknown type %d ROM Image\n", rom_type); 49662306a36Sopenharmony_ci goto failed; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci anyway: 49962306a36Sopenharmony_ci /* Locate the flat panel infos, do some sanity checking !!! */ 50062306a36Sopenharmony_ci rinfo->fp_bios_start = BIOS_IN16(0x48); 50162306a36Sopenharmony_ci return 0; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci failed: 50462306a36Sopenharmony_ci rinfo->bios_seg = NULL; 50562306a36Sopenharmony_ci radeon_unmap_ROM(rinfo, dev); 50662306a36Sopenharmony_ci return -ENXIO; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci#ifdef CONFIG_X86 51062306a36Sopenharmony_cistatic int radeon_find_mem_vbios(struct radeonfb_info *rinfo) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci /* I simplified this code as we used to miss the signatures in 51362306a36Sopenharmony_ci * a lot of case. It's now closer to XFree, we just don't check 51462306a36Sopenharmony_ci * for signatures at all... Something better will have to be done 51562306a36Sopenharmony_ci * if we end up having conflicts 51662306a36Sopenharmony_ci */ 51762306a36Sopenharmony_ci u32 segstart; 51862306a36Sopenharmony_ci void __iomem *rom_base = NULL; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { 52162306a36Sopenharmony_ci rom_base = ioremap(segstart, 0x10000); 52262306a36Sopenharmony_ci if (rom_base == NULL) 52362306a36Sopenharmony_ci return -ENOMEM; 52462306a36Sopenharmony_ci if (readb(rom_base) == 0x55 && readb(rom_base + 1) == 0xaa) 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci iounmap(rom_base); 52762306a36Sopenharmony_ci rom_base = NULL; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci if (rom_base == NULL) 53062306a36Sopenharmony_ci return -ENXIO; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* Locate the flat panel infos, do some sanity checking !!! */ 53362306a36Sopenharmony_ci rinfo->bios_seg = rom_base; 53462306a36Sopenharmony_ci rinfo->fp_bios_start = BIOS_IN16(0x48); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return 0; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci#endif 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci#if defined(CONFIG_PPC) || defined(CONFIG_SPARC) 54162306a36Sopenharmony_ci/* 54262306a36Sopenharmony_ci * Read XTAL (ref clock), SCLK and MCLK from Open Firmware device 54362306a36Sopenharmony_ci * tree. Hopefully, ATI OF driver is kind enough to fill these 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_cistatic int radeon_read_xtal_OF(struct radeonfb_info *rinfo) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci struct device_node *dp = rinfo->of_node; 54862306a36Sopenharmony_ci const u32 *val; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (dp == NULL) 55162306a36Sopenharmony_ci return -ENODEV; 55262306a36Sopenharmony_ci val = of_get_property(dp, "ATY,RefCLK", NULL); 55362306a36Sopenharmony_ci if (!val || !*val) { 55462306a36Sopenharmony_ci printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n"); 55562306a36Sopenharmony_ci return -EINVAL; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci rinfo->pll.ref_clk = (*val) / 10; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci val = of_get_property(dp, "ATY,SCLK", NULL); 56162306a36Sopenharmony_ci if (val && *val) 56262306a36Sopenharmony_ci rinfo->pll.sclk = (*val) / 10; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci val = of_get_property(dp, "ATY,MCLK", NULL); 56562306a36Sopenharmony_ci if (val && *val) 56662306a36Sopenharmony_ci rinfo->pll.mclk = (*val) / 10; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return 0; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci#endif /* CONFIG_PPC || CONFIG_SPARC */ 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci/* 57362306a36Sopenharmony_ci * Read PLL infos from chip registers 57462306a36Sopenharmony_ci */ 57562306a36Sopenharmony_cistatic int radeon_probe_pll_params(struct radeonfb_info *rinfo) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci unsigned char ppll_div_sel; 57862306a36Sopenharmony_ci unsigned Ns, Nm, M; 57962306a36Sopenharmony_ci unsigned sclk, mclk, tmp, ref_div; 58062306a36Sopenharmony_ci int hTotal, vTotal, num, denom, m, n; 58162306a36Sopenharmony_ci unsigned long long hz, vclk; 58262306a36Sopenharmony_ci long xtal; 58362306a36Sopenharmony_ci ktime_t start_time, stop_time; 58462306a36Sopenharmony_ci u64 total_usecs; 58562306a36Sopenharmony_ci int i; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* Ugh, we cut interrupts, bad bad bad, but we want some precision 58862306a36Sopenharmony_ci * here, so... --BenH 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* Flush PCI buffers ? */ 59262306a36Sopenharmony_ci tmp = INREG16(DEVICE_ID); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci local_irq_disable(); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci for(i=0; i<1000000; i++) 59762306a36Sopenharmony_ci if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0) 59862306a36Sopenharmony_ci break; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci start_time = ktime_get(); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci for(i=0; i<1000000; i++) 60362306a36Sopenharmony_ci if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) != 0) 60462306a36Sopenharmony_ci break; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci for(i=0; i<1000000; i++) 60762306a36Sopenharmony_ci if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0) 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci stop_time = ktime_get(); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci local_irq_enable(); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci total_usecs = ktime_us_delta(stop_time, start_time); 61562306a36Sopenharmony_ci if (total_usecs >= 10 * USEC_PER_SEC || total_usecs == 0) 61662306a36Sopenharmony_ci return -1; 61762306a36Sopenharmony_ci hz = USEC_PER_SEC/(u32)total_usecs; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci hTotal = ((INREG(CRTC_H_TOTAL_DISP) & 0x1ff) + 1) * 8; 62062306a36Sopenharmony_ci vTotal = ((INREG(CRTC_V_TOTAL_DISP) & 0x3ff) + 1); 62162306a36Sopenharmony_ci vclk = (long long)hTotal * (long long)vTotal * hz; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci switch((INPLL(PPLL_REF_DIV) & 0x30000) >> 16) { 62462306a36Sopenharmony_ci case 0: 62562306a36Sopenharmony_ci default: 62662306a36Sopenharmony_ci num = 1; 62762306a36Sopenharmony_ci denom = 1; 62862306a36Sopenharmony_ci break; 62962306a36Sopenharmony_ci case 1: 63062306a36Sopenharmony_ci n = ((INPLL(M_SPLL_REF_FB_DIV) >> 16) & 0xff); 63162306a36Sopenharmony_ci m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff); 63262306a36Sopenharmony_ci num = 2*n; 63362306a36Sopenharmony_ci denom = 2*m; 63462306a36Sopenharmony_ci break; 63562306a36Sopenharmony_ci case 2: 63662306a36Sopenharmony_ci n = ((INPLL(M_SPLL_REF_FB_DIV) >> 8) & 0xff); 63762306a36Sopenharmony_ci m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff); 63862306a36Sopenharmony_ci num = 2*n; 63962306a36Sopenharmony_ci denom = 2*m; 64062306a36Sopenharmony_ci break; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3; 64462306a36Sopenharmony_ci radeon_pll_errata_after_index(rinfo); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci n = (INPLL(PPLL_DIV_0 + ppll_div_sel) & 0x7ff); 64762306a36Sopenharmony_ci m = (INPLL(PPLL_REF_DIV) & 0x3ff); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci num *= n; 65062306a36Sopenharmony_ci denom *= m; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci switch ((INPLL(PPLL_DIV_0 + ppll_div_sel) >> 16) & 0x7) { 65362306a36Sopenharmony_ci case 1: 65462306a36Sopenharmony_ci denom *= 2; 65562306a36Sopenharmony_ci break; 65662306a36Sopenharmony_ci case 2: 65762306a36Sopenharmony_ci denom *= 4; 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci case 3: 66062306a36Sopenharmony_ci denom *= 8; 66162306a36Sopenharmony_ci break; 66262306a36Sopenharmony_ci case 4: 66362306a36Sopenharmony_ci denom *= 3; 66462306a36Sopenharmony_ci break; 66562306a36Sopenharmony_ci case 6: 66662306a36Sopenharmony_ci denom *= 6; 66762306a36Sopenharmony_ci break; 66862306a36Sopenharmony_ci case 7: 66962306a36Sopenharmony_ci denom *= 12; 67062306a36Sopenharmony_ci break; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci vclk *= denom; 67462306a36Sopenharmony_ci do_div(vclk, 1000 * num); 67562306a36Sopenharmony_ci xtal = vclk; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if ((xtal > 26900) && (xtal < 27100)) 67862306a36Sopenharmony_ci xtal = 2700; 67962306a36Sopenharmony_ci else if ((xtal > 14200) && (xtal < 14400)) 68062306a36Sopenharmony_ci xtal = 1432; 68162306a36Sopenharmony_ci else if ((xtal > 29400) && (xtal < 29600)) 68262306a36Sopenharmony_ci xtal = 2950; 68362306a36Sopenharmony_ci else { 68462306a36Sopenharmony_ci printk(KERN_WARNING "xtal calculation failed: %ld\n", xtal); 68562306a36Sopenharmony_ci return -1; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci tmp = INPLL(M_SPLL_REF_FB_DIV); 68962306a36Sopenharmony_ci ref_div = INPLL(PPLL_REF_DIV) & 0x3ff; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci Ns = (tmp & 0xff0000) >> 16; 69262306a36Sopenharmony_ci Nm = (tmp & 0xff00) >> 8; 69362306a36Sopenharmony_ci M = (tmp & 0xff); 69462306a36Sopenharmony_ci sclk = round_div((2 * Ns * xtal), (2 * M)); 69562306a36Sopenharmony_ci mclk = round_div((2 * Nm * xtal), (2 * M)); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci /* we're done, hopefully these are sane values */ 69862306a36Sopenharmony_ci rinfo->pll.ref_clk = xtal; 69962306a36Sopenharmony_ci rinfo->pll.ref_div = ref_div; 70062306a36Sopenharmony_ci rinfo->pll.sclk = sclk; 70162306a36Sopenharmony_ci rinfo->pll.mclk = mclk; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci return 0; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci/* 70762306a36Sopenharmony_ci * Retrieve PLL infos by different means (BIOS, Open Firmware, register probing...) 70862306a36Sopenharmony_ci */ 70962306a36Sopenharmony_cistatic void radeon_get_pllinfo(struct radeonfb_info *rinfo) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci /* 71262306a36Sopenharmony_ci * In the case nothing works, these are defaults; they are mostly 71362306a36Sopenharmony_ci * incomplete, however. It does provide ppll_max and _min values 71462306a36Sopenharmony_ci * even for most other methods, however. 71562306a36Sopenharmony_ci */ 71662306a36Sopenharmony_ci switch (rinfo->chipset) { 71762306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_QW: 71862306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_QX: 71962306a36Sopenharmony_ci rinfo->pll.ppll_max = 35000; 72062306a36Sopenharmony_ci rinfo->pll.ppll_min = 12000; 72162306a36Sopenharmony_ci rinfo->pll.mclk = 23000; 72262306a36Sopenharmony_ci rinfo->pll.sclk = 23000; 72362306a36Sopenharmony_ci rinfo->pll.ref_clk = 2700; 72462306a36Sopenharmony_ci break; 72562306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_QL: 72662306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_QN: 72762306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_QO: 72862306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_Ql: 72962306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_BB: 73062306a36Sopenharmony_ci rinfo->pll.ppll_max = 35000; 73162306a36Sopenharmony_ci rinfo->pll.ppll_min = 12000; 73262306a36Sopenharmony_ci rinfo->pll.mclk = 27500; 73362306a36Sopenharmony_ci rinfo->pll.sclk = 27500; 73462306a36Sopenharmony_ci rinfo->pll.ref_clk = 2700; 73562306a36Sopenharmony_ci break; 73662306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_Id: 73762306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_Ie: 73862306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_If: 73962306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_Ig: 74062306a36Sopenharmony_ci rinfo->pll.ppll_max = 35000; 74162306a36Sopenharmony_ci rinfo->pll.ppll_min = 12000; 74262306a36Sopenharmony_ci rinfo->pll.mclk = 25000; 74362306a36Sopenharmony_ci rinfo->pll.sclk = 25000; 74462306a36Sopenharmony_ci rinfo->pll.ref_clk = 2700; 74562306a36Sopenharmony_ci break; 74662306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_ND: 74762306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_NE: 74862306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_NF: 74962306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_NG: 75062306a36Sopenharmony_ci rinfo->pll.ppll_max = 40000; 75162306a36Sopenharmony_ci rinfo->pll.ppll_min = 20000; 75262306a36Sopenharmony_ci rinfo->pll.mclk = 27000; 75362306a36Sopenharmony_ci rinfo->pll.sclk = 27000; 75462306a36Sopenharmony_ci rinfo->pll.ref_clk = 2700; 75562306a36Sopenharmony_ci break; 75662306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_QD: 75762306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_QE: 75862306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_QF: 75962306a36Sopenharmony_ci case PCI_DEVICE_ID_ATI_RADEON_QG: 76062306a36Sopenharmony_ci default: 76162306a36Sopenharmony_ci rinfo->pll.ppll_max = 35000; 76262306a36Sopenharmony_ci rinfo->pll.ppll_min = 12000; 76362306a36Sopenharmony_ci rinfo->pll.mclk = 16600; 76462306a36Sopenharmony_ci rinfo->pll.sclk = 16600; 76562306a36Sopenharmony_ci rinfo->pll.ref_clk = 2700; 76662306a36Sopenharmony_ci break; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci#if defined(CONFIG_PPC) || defined(CONFIG_SPARC) 77262306a36Sopenharmony_ci /* 77362306a36Sopenharmony_ci * Retrieve PLL infos from Open Firmware first 77462306a36Sopenharmony_ci */ 77562306a36Sopenharmony_ci if (!force_measure_pll && radeon_read_xtal_OF(rinfo) == 0) { 77662306a36Sopenharmony_ci printk(KERN_INFO "radeonfb: Retrieved PLL infos from Open Firmware\n"); 77762306a36Sopenharmony_ci goto found; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci#endif /* CONFIG_PPC || CONFIG_SPARC */ 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci /* 78262306a36Sopenharmony_ci * Check out if we have an X86 which gave us some PLL informations 78362306a36Sopenharmony_ci * and if yes, retrieve them 78462306a36Sopenharmony_ci */ 78562306a36Sopenharmony_ci if (!force_measure_pll && rinfo->bios_seg) { 78662306a36Sopenharmony_ci u16 pll_info_block = BIOS_IN16(rinfo->fp_bios_start + 0x30); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci rinfo->pll.sclk = BIOS_IN16(pll_info_block + 0x08); 78962306a36Sopenharmony_ci rinfo->pll.mclk = BIOS_IN16(pll_info_block + 0x0a); 79062306a36Sopenharmony_ci rinfo->pll.ref_clk = BIOS_IN16(pll_info_block + 0x0e); 79162306a36Sopenharmony_ci rinfo->pll.ref_div = BIOS_IN16(pll_info_block + 0x10); 79262306a36Sopenharmony_ci rinfo->pll.ppll_min = BIOS_IN32(pll_info_block + 0x12); 79362306a36Sopenharmony_ci rinfo->pll.ppll_max = BIOS_IN32(pll_info_block + 0x16); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci printk(KERN_INFO "radeonfb: Retrieved PLL infos from BIOS\n"); 79662306a36Sopenharmony_ci goto found; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* 80062306a36Sopenharmony_ci * We didn't get PLL parameters from either OF or BIOS, we try to 80162306a36Sopenharmony_ci * probe them 80262306a36Sopenharmony_ci */ 80362306a36Sopenharmony_ci if (radeon_probe_pll_params(rinfo) == 0) { 80462306a36Sopenharmony_ci printk(KERN_INFO "radeonfb: Retrieved PLL infos from registers\n"); 80562306a36Sopenharmony_ci goto found; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* 80962306a36Sopenharmony_ci * Fall back to already-set defaults... 81062306a36Sopenharmony_ci */ 81162306a36Sopenharmony_ci printk(KERN_INFO "radeonfb: Used default PLL infos\n"); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cifound: 81462306a36Sopenharmony_ci /* 81562306a36Sopenharmony_ci * Some methods fail to retrieve SCLK and MCLK values, we apply default 81662306a36Sopenharmony_ci * settings in this case (200Mhz). If that really happens often, we 81762306a36Sopenharmony_ci * could fetch from registers instead... 81862306a36Sopenharmony_ci */ 81962306a36Sopenharmony_ci if (rinfo->pll.mclk == 0) 82062306a36Sopenharmony_ci rinfo->pll.mclk = 20000; 82162306a36Sopenharmony_ci if (rinfo->pll.sclk == 0) 82262306a36Sopenharmony_ci rinfo->pll.sclk = 20000; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci printk("radeonfb: Reference=%d.%02d MHz (RefDiv=%d) Memory=%d.%02d Mhz, System=%d.%02d MHz\n", 82562306a36Sopenharmony_ci rinfo->pll.ref_clk / 100, rinfo->pll.ref_clk % 100, 82662306a36Sopenharmony_ci rinfo->pll.ref_div, 82762306a36Sopenharmony_ci rinfo->pll.mclk / 100, rinfo->pll.mclk % 100, 82862306a36Sopenharmony_ci rinfo->pll.sclk / 100, rinfo->pll.sclk % 100); 82962306a36Sopenharmony_ci printk("radeonfb: PLL min %d max %d\n", rinfo->pll.ppll_min, rinfo->pll.ppll_max); 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci struct radeonfb_info *rinfo = info->par; 83562306a36Sopenharmony_ci struct fb_var_screeninfo v; 83662306a36Sopenharmony_ci int nom, den; 83762306a36Sopenharmony_ci unsigned int pitch; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (radeon_match_mode(rinfo, &v, var)) 84062306a36Sopenharmony_ci return -EINVAL; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci switch (v.bits_per_pixel) { 84362306a36Sopenharmony_ci case 0 ... 8: 84462306a36Sopenharmony_ci v.bits_per_pixel = 8; 84562306a36Sopenharmony_ci break; 84662306a36Sopenharmony_ci case 9 ... 16: 84762306a36Sopenharmony_ci v.bits_per_pixel = 16; 84862306a36Sopenharmony_ci break; 84962306a36Sopenharmony_ci case 25 ... 32: 85062306a36Sopenharmony_ci v.bits_per_pixel = 32; 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci default: 85362306a36Sopenharmony_ci return -EINVAL; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci switch (var_to_depth(&v)) { 85762306a36Sopenharmony_ci case 8: 85862306a36Sopenharmony_ci nom = den = 1; 85962306a36Sopenharmony_ci v.red.offset = v.green.offset = v.blue.offset = 0; 86062306a36Sopenharmony_ci v.red.length = v.green.length = v.blue.length = 8; 86162306a36Sopenharmony_ci v.transp.offset = v.transp.length = 0; 86262306a36Sopenharmony_ci break; 86362306a36Sopenharmony_ci case 15: 86462306a36Sopenharmony_ci nom = 2; 86562306a36Sopenharmony_ci den = 1; 86662306a36Sopenharmony_ci v.red.offset = 10; 86762306a36Sopenharmony_ci v.green.offset = 5; 86862306a36Sopenharmony_ci v.blue.offset = 0; 86962306a36Sopenharmony_ci v.red.length = v.green.length = v.blue.length = 5; 87062306a36Sopenharmony_ci v.transp.offset = v.transp.length = 0; 87162306a36Sopenharmony_ci break; 87262306a36Sopenharmony_ci case 16: 87362306a36Sopenharmony_ci nom = 2; 87462306a36Sopenharmony_ci den = 1; 87562306a36Sopenharmony_ci v.red.offset = 11; 87662306a36Sopenharmony_ci v.green.offset = 5; 87762306a36Sopenharmony_ci v.blue.offset = 0; 87862306a36Sopenharmony_ci v.red.length = 5; 87962306a36Sopenharmony_ci v.green.length = 6; 88062306a36Sopenharmony_ci v.blue.length = 5; 88162306a36Sopenharmony_ci v.transp.offset = v.transp.length = 0; 88262306a36Sopenharmony_ci break; 88362306a36Sopenharmony_ci case 24: 88462306a36Sopenharmony_ci nom = 4; 88562306a36Sopenharmony_ci den = 1; 88662306a36Sopenharmony_ci v.red.offset = 16; 88762306a36Sopenharmony_ci v.green.offset = 8; 88862306a36Sopenharmony_ci v.blue.offset = 0; 88962306a36Sopenharmony_ci v.red.length = v.blue.length = v.green.length = 8; 89062306a36Sopenharmony_ci v.transp.offset = v.transp.length = 0; 89162306a36Sopenharmony_ci break; 89262306a36Sopenharmony_ci case 32: 89362306a36Sopenharmony_ci nom = 4; 89462306a36Sopenharmony_ci den = 1; 89562306a36Sopenharmony_ci v.red.offset = 16; 89662306a36Sopenharmony_ci v.green.offset = 8; 89762306a36Sopenharmony_ci v.blue.offset = 0; 89862306a36Sopenharmony_ci v.red.length = v.blue.length = v.green.length = 8; 89962306a36Sopenharmony_ci v.transp.offset = 24; 90062306a36Sopenharmony_ci v.transp.length = 8; 90162306a36Sopenharmony_ci break; 90262306a36Sopenharmony_ci default: 90362306a36Sopenharmony_ci printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n", 90462306a36Sopenharmony_ci var->xres, var->yres, var->bits_per_pixel); 90562306a36Sopenharmony_ci return -EINVAL; 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci if (v.yres_virtual < v.yres) 90962306a36Sopenharmony_ci v.yres_virtual = v.yres; 91062306a36Sopenharmony_ci if (v.xres_virtual < v.xres) 91162306a36Sopenharmony_ci v.xres_virtual = v.xres; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci /* XXX I'm adjusting xres_virtual to the pitch, that may help XFree 91562306a36Sopenharmony_ci * with some panels, though I don't quite like this solution 91662306a36Sopenharmony_ci */ 91762306a36Sopenharmony_ci if (rinfo->info->flags & FBINFO_HWACCEL_DISABLED) { 91862306a36Sopenharmony_ci v.xres_virtual = v.xres_virtual & ~7ul; 91962306a36Sopenharmony_ci } else { 92062306a36Sopenharmony_ci pitch = ((v.xres_virtual * ((v.bits_per_pixel + 1) / 8) + 0x3f) 92162306a36Sopenharmony_ci & ~(0x3f)) >> 6; 92262306a36Sopenharmony_ci v.xres_virtual = (pitch << 6) / ((v.bits_per_pixel + 1) / 8); 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (((v.xres_virtual * v.yres_virtual * nom) / den) > rinfo->mapped_vram) 92662306a36Sopenharmony_ci return -EINVAL; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci if (v.xres_virtual < v.xres) 92962306a36Sopenharmony_ci v.xres = v.xres_virtual; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (v.xoffset > v.xres_virtual - v.xres) 93262306a36Sopenharmony_ci v.xoffset = v.xres_virtual - v.xres - 1; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if (v.yoffset > v.yres_virtual - v.yres) 93562306a36Sopenharmony_ci v.yoffset = v.yres_virtual - v.yres - 1; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci v.red.msb_right = v.green.msb_right = v.blue.msb_right = 93862306a36Sopenharmony_ci v.transp.offset = v.transp.length = 93962306a36Sopenharmony_ci v.transp.msb_right = 0; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci memcpy(var, &v, sizeof(v)); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci return 0; 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_cistatic int radeonfb_pan_display (struct fb_var_screeninfo *var, 94862306a36Sopenharmony_ci struct fb_info *info) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci struct radeonfb_info *rinfo = info->par; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci if ((var->xoffset + info->var.xres > info->var.xres_virtual) 95362306a36Sopenharmony_ci || (var->yoffset + info->var.yres > info->var.yres_virtual)) 95462306a36Sopenharmony_ci return -EINVAL; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (rinfo->asleep) 95762306a36Sopenharmony_ci return 0; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci radeon_fifo_wait(2); 96062306a36Sopenharmony_ci OUTREG(CRTC_OFFSET, (var->yoffset * info->fix.line_length + 96162306a36Sopenharmony_ci var->xoffset * info->var.bits_per_pixel / 8) & ~7); 96262306a36Sopenharmony_ci return 0; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic int radeonfb_ioctl (struct fb_info *info, unsigned int cmd, 96762306a36Sopenharmony_ci unsigned long arg) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci struct radeonfb_info *rinfo = info->par; 97062306a36Sopenharmony_ci unsigned int tmp; 97162306a36Sopenharmony_ci u32 value = 0; 97262306a36Sopenharmony_ci int rc; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci switch (cmd) { 97562306a36Sopenharmony_ci /* 97662306a36Sopenharmony_ci * TODO: set mirror accordingly for non-Mobility chipsets with 2 CRTC's 97762306a36Sopenharmony_ci * and do something better using 2nd CRTC instead of just hackish 97862306a36Sopenharmony_ci * routing to second output 97962306a36Sopenharmony_ci */ 98062306a36Sopenharmony_ci case FBIO_RADEON_SET_MIRROR: 98162306a36Sopenharmony_ci if (!rinfo->is_mobility) 98262306a36Sopenharmony_ci return -EINVAL; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci rc = get_user(value, (__u32 __user *)arg); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (rc) 98762306a36Sopenharmony_ci return rc; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci radeon_fifo_wait(2); 99062306a36Sopenharmony_ci if (value & 0x01) { 99162306a36Sopenharmony_ci tmp = INREG(LVDS_GEN_CNTL); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci tmp |= (LVDS_ON | LVDS_BLON); 99462306a36Sopenharmony_ci } else { 99562306a36Sopenharmony_ci tmp = INREG(LVDS_GEN_CNTL); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci tmp &= ~(LVDS_ON | LVDS_BLON); 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci OUTREG(LVDS_GEN_CNTL, tmp); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci if (value & 0x02) { 100362306a36Sopenharmony_ci tmp = INREG(CRTC_EXT_CNTL); 100462306a36Sopenharmony_ci tmp |= CRTC_CRT_ON; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci mirror = 1; 100762306a36Sopenharmony_ci } else { 100862306a36Sopenharmony_ci tmp = INREG(CRTC_EXT_CNTL); 100962306a36Sopenharmony_ci tmp &= ~CRTC_CRT_ON; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci mirror = 0; 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci OUTREG(CRTC_EXT_CNTL, tmp); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci return 0; 101762306a36Sopenharmony_ci case FBIO_RADEON_GET_MIRROR: 101862306a36Sopenharmony_ci if (!rinfo->is_mobility) 101962306a36Sopenharmony_ci return -EINVAL; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci tmp = INREG(LVDS_GEN_CNTL); 102262306a36Sopenharmony_ci if ((LVDS_ON | LVDS_BLON) & tmp) 102362306a36Sopenharmony_ci value |= 0x01; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci tmp = INREG(CRTC_EXT_CNTL); 102662306a36Sopenharmony_ci if (CRTC_CRT_ON & tmp) 102762306a36Sopenharmony_ci value |= 0x02; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci return put_user(value, (__u32 __user *)arg); 103062306a36Sopenharmony_ci default: 103162306a36Sopenharmony_ci return -EINVAL; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci return -EINVAL; 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ciint radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci u32 val; 104162306a36Sopenharmony_ci u32 tmp_pix_clks; 104262306a36Sopenharmony_ci int unblank = 0; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci if (rinfo->lock_blank) 104562306a36Sopenharmony_ci return 0; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci radeon_engine_idle(); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci val = INREG(CRTC_EXT_CNTL); 105062306a36Sopenharmony_ci val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS | 105162306a36Sopenharmony_ci CRTC_VSYNC_DIS); 105262306a36Sopenharmony_ci switch (blank) { 105362306a36Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 105462306a36Sopenharmony_ci val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS); 105562306a36Sopenharmony_ci break; 105662306a36Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 105762306a36Sopenharmony_ci val |= (CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS); 105862306a36Sopenharmony_ci break; 105962306a36Sopenharmony_ci case FB_BLANK_POWERDOWN: 106062306a36Sopenharmony_ci val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | 106162306a36Sopenharmony_ci CRTC_HSYNC_DIS); 106262306a36Sopenharmony_ci break; 106362306a36Sopenharmony_ci case FB_BLANK_NORMAL: 106462306a36Sopenharmony_ci val |= CRTC_DISPLAY_DIS; 106562306a36Sopenharmony_ci break; 106662306a36Sopenharmony_ci case FB_BLANK_UNBLANK: 106762306a36Sopenharmony_ci default: 106862306a36Sopenharmony_ci unblank = 1; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci OUTREG(CRTC_EXT_CNTL, val); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci switch (rinfo->mon1_type) { 107462306a36Sopenharmony_ci case MT_DFP: 107562306a36Sopenharmony_ci if (unblank) 107662306a36Sopenharmony_ci OUTREGP(FP_GEN_CNTL, (FP_FPON | FP_TMDS_EN), 107762306a36Sopenharmony_ci ~(FP_FPON | FP_TMDS_EN)); 107862306a36Sopenharmony_ci else { 107962306a36Sopenharmony_ci if (mode_switch || blank == FB_BLANK_NORMAL) 108062306a36Sopenharmony_ci break; 108162306a36Sopenharmony_ci OUTREGP(FP_GEN_CNTL, 0, ~(FP_FPON | FP_TMDS_EN)); 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci break; 108462306a36Sopenharmony_ci case MT_LCD: 108562306a36Sopenharmony_ci del_timer_sync(&rinfo->lvds_timer); 108662306a36Sopenharmony_ci val = INREG(LVDS_GEN_CNTL); 108762306a36Sopenharmony_ci if (unblank) { 108862306a36Sopenharmony_ci u32 target_val = (val & ~LVDS_DISPLAY_DIS) | LVDS_BLON | LVDS_ON 108962306a36Sopenharmony_ci | LVDS_EN | (rinfo->init_state.lvds_gen_cntl 109062306a36Sopenharmony_ci & (LVDS_DIGON | LVDS_BL_MOD_EN)); 109162306a36Sopenharmony_ci if ((val ^ target_val) == LVDS_DISPLAY_DIS) 109262306a36Sopenharmony_ci OUTREG(LVDS_GEN_CNTL, target_val); 109362306a36Sopenharmony_ci else if ((val ^ target_val) != 0) { 109462306a36Sopenharmony_ci OUTREG(LVDS_GEN_CNTL, target_val 109562306a36Sopenharmony_ci & ~(LVDS_ON | LVDS_BL_MOD_EN)); 109662306a36Sopenharmony_ci rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; 109762306a36Sopenharmony_ci rinfo->init_state.lvds_gen_cntl |= 109862306a36Sopenharmony_ci target_val & LVDS_STATE_MASK; 109962306a36Sopenharmony_ci if (mode_switch) { 110062306a36Sopenharmony_ci radeon_msleep(rinfo->panel_info.pwr_delay); 110162306a36Sopenharmony_ci OUTREG(LVDS_GEN_CNTL, target_val); 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci else { 110462306a36Sopenharmony_ci rinfo->pending_lvds_gen_cntl = target_val; 110562306a36Sopenharmony_ci mod_timer(&rinfo->lvds_timer, 110662306a36Sopenharmony_ci jiffies + 110762306a36Sopenharmony_ci msecs_to_jiffies(rinfo->panel_info.pwr_delay)); 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci } else { 111162306a36Sopenharmony_ci val |= LVDS_DISPLAY_DIS; 111262306a36Sopenharmony_ci OUTREG(LVDS_GEN_CNTL, val); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci /* We don't do a full switch-off on a simple mode switch */ 111562306a36Sopenharmony_ci if (mode_switch || blank == FB_BLANK_NORMAL) 111662306a36Sopenharmony_ci break; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci /* Asic bug, when turning off LVDS_ON, we have to make sure 111962306a36Sopenharmony_ci * RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off 112062306a36Sopenharmony_ci */ 112162306a36Sopenharmony_ci tmp_pix_clks = INPLL(PIXCLKS_CNTL); 112262306a36Sopenharmony_ci if (rinfo->is_mobility || rinfo->is_IGP) 112362306a36Sopenharmony_ci OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb); 112462306a36Sopenharmony_ci val &= ~(LVDS_BL_MOD_EN); 112562306a36Sopenharmony_ci OUTREG(LVDS_GEN_CNTL, val); 112662306a36Sopenharmony_ci udelay(100); 112762306a36Sopenharmony_ci val &= ~(LVDS_ON | LVDS_EN); 112862306a36Sopenharmony_ci OUTREG(LVDS_GEN_CNTL, val); 112962306a36Sopenharmony_ci val &= ~LVDS_DIGON; 113062306a36Sopenharmony_ci rinfo->pending_lvds_gen_cntl = val; 113162306a36Sopenharmony_ci mod_timer(&rinfo->lvds_timer, 113262306a36Sopenharmony_ci jiffies + 113362306a36Sopenharmony_ci msecs_to_jiffies(rinfo->panel_info.pwr_delay)); 113462306a36Sopenharmony_ci rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; 113562306a36Sopenharmony_ci rinfo->init_state.lvds_gen_cntl |= val & LVDS_STATE_MASK; 113662306a36Sopenharmony_ci if (rinfo->is_mobility || rinfo->is_IGP) 113762306a36Sopenharmony_ci OUTPLL(PIXCLKS_CNTL, tmp_pix_clks); 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci break; 114062306a36Sopenharmony_ci case MT_CRT: 114162306a36Sopenharmony_ci // todo: powerdown DAC 114262306a36Sopenharmony_ci default: 114362306a36Sopenharmony_ci break; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci return 0; 114762306a36Sopenharmony_ci} 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_cistatic int radeonfb_blank (int blank, struct fb_info *info) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci struct radeonfb_info *rinfo = info->par; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci if (rinfo->asleep) 115462306a36Sopenharmony_ci return 0; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci return radeon_screen_blank(rinfo, blank, 0); 115762306a36Sopenharmony_ci} 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_cistatic int radeon_setcolreg (unsigned regno, unsigned red, unsigned green, 116062306a36Sopenharmony_ci unsigned blue, unsigned transp, 116162306a36Sopenharmony_ci struct radeonfb_info *rinfo) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci u32 pindex; 116462306a36Sopenharmony_ci unsigned int i; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (regno > 255) 116862306a36Sopenharmony_ci return -EINVAL; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci red >>= 8; 117162306a36Sopenharmony_ci green >>= 8; 117262306a36Sopenharmony_ci blue >>= 8; 117362306a36Sopenharmony_ci rinfo->palette[regno].red = red; 117462306a36Sopenharmony_ci rinfo->palette[regno].green = green; 117562306a36Sopenharmony_ci rinfo->palette[regno].blue = blue; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci /* default */ 117862306a36Sopenharmony_ci pindex = regno; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci if (!rinfo->asleep) { 118162306a36Sopenharmony_ci radeon_fifo_wait(9); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci if (rinfo->bpp == 16) { 118462306a36Sopenharmony_ci pindex = regno * 8; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (rinfo->depth == 16 && regno > 63) 118762306a36Sopenharmony_ci return -EINVAL; 118862306a36Sopenharmony_ci if (rinfo->depth == 15 && regno > 31) 118962306a36Sopenharmony_ci return -EINVAL; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci /* For 565, the green component is mixed one order 119262306a36Sopenharmony_ci * below 119362306a36Sopenharmony_ci */ 119462306a36Sopenharmony_ci if (rinfo->depth == 16) { 119562306a36Sopenharmony_ci OUTREG(PALETTE_INDEX, pindex>>1); 119662306a36Sopenharmony_ci OUTREG(PALETTE_DATA, 119762306a36Sopenharmony_ci (rinfo->palette[regno>>1].red << 16) | 119862306a36Sopenharmony_ci (green << 8) | 119962306a36Sopenharmony_ci (rinfo->palette[regno>>1].blue)); 120062306a36Sopenharmony_ci green = rinfo->palette[regno<<1].green; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci if (rinfo->depth != 16 || regno < 32) { 120562306a36Sopenharmony_ci OUTREG(PALETTE_INDEX, pindex); 120662306a36Sopenharmony_ci OUTREG(PALETTE_DATA, (red << 16) | 120762306a36Sopenharmony_ci (green << 8) | blue); 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci if (regno < 16) { 121162306a36Sopenharmony_ci u32 *pal = rinfo->info->pseudo_palette; 121262306a36Sopenharmony_ci switch (rinfo->depth) { 121362306a36Sopenharmony_ci case 15: 121462306a36Sopenharmony_ci pal[regno] = (regno << 10) | (regno << 5) | regno; 121562306a36Sopenharmony_ci break; 121662306a36Sopenharmony_ci case 16: 121762306a36Sopenharmony_ci pal[regno] = (regno << 11) | (regno << 5) | regno; 121862306a36Sopenharmony_ci break; 121962306a36Sopenharmony_ci case 24: 122062306a36Sopenharmony_ci pal[regno] = (regno << 16) | (regno << 8) | regno; 122162306a36Sopenharmony_ci break; 122262306a36Sopenharmony_ci case 32: 122362306a36Sopenharmony_ci i = (regno << 8) | regno; 122462306a36Sopenharmony_ci pal[regno] = (i << 16) | i; 122562306a36Sopenharmony_ci break; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci return 0; 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_cistatic int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green, 123262306a36Sopenharmony_ci unsigned blue, unsigned transp, 123362306a36Sopenharmony_ci struct fb_info *info) 123462306a36Sopenharmony_ci{ 123562306a36Sopenharmony_ci struct radeonfb_info *rinfo = info->par; 123662306a36Sopenharmony_ci u32 dac_cntl2, vclk_cntl = 0; 123762306a36Sopenharmony_ci int rc; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci if (!rinfo->asleep) { 124062306a36Sopenharmony_ci if (rinfo->is_mobility) { 124162306a36Sopenharmony_ci vclk_cntl = INPLL(VCLK_ECP_CNTL); 124262306a36Sopenharmony_ci OUTPLL(VCLK_ECP_CNTL, 124362306a36Sopenharmony_ci vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb); 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci /* Make sure we are on first palette */ 124762306a36Sopenharmony_ci if (rinfo->has_CRTC2) { 124862306a36Sopenharmony_ci dac_cntl2 = INREG(DAC_CNTL2); 124962306a36Sopenharmony_ci dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL; 125062306a36Sopenharmony_ci OUTREG(DAC_CNTL2, dac_cntl2); 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci rc = radeon_setcolreg (regno, red, green, blue, transp, rinfo); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci if (!rinfo->asleep && rinfo->is_mobility) 125762306a36Sopenharmony_ci OUTPLL(VCLK_ECP_CNTL, vclk_cntl); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci return rc; 126062306a36Sopenharmony_ci} 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_cistatic int radeonfb_setcmap(struct fb_cmap *cmap, struct fb_info *info) 126362306a36Sopenharmony_ci{ 126462306a36Sopenharmony_ci struct radeonfb_info *rinfo = info->par; 126562306a36Sopenharmony_ci u16 *red, *green, *blue, *transp; 126662306a36Sopenharmony_ci u32 dac_cntl2, vclk_cntl = 0; 126762306a36Sopenharmony_ci int i, start, rc = 0; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (!rinfo->asleep) { 127062306a36Sopenharmony_ci if (rinfo->is_mobility) { 127162306a36Sopenharmony_ci vclk_cntl = INPLL(VCLK_ECP_CNTL); 127262306a36Sopenharmony_ci OUTPLL(VCLK_ECP_CNTL, 127362306a36Sopenharmony_ci vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb); 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* Make sure we are on first palette */ 127762306a36Sopenharmony_ci if (rinfo->has_CRTC2) { 127862306a36Sopenharmony_ci dac_cntl2 = INREG(DAC_CNTL2); 127962306a36Sopenharmony_ci dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL; 128062306a36Sopenharmony_ci OUTREG(DAC_CNTL2, dac_cntl2); 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci red = cmap->red; 128562306a36Sopenharmony_ci green = cmap->green; 128662306a36Sopenharmony_ci blue = cmap->blue; 128762306a36Sopenharmony_ci transp = cmap->transp; 128862306a36Sopenharmony_ci start = cmap->start; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci for (i = 0; i < cmap->len; i++) { 129162306a36Sopenharmony_ci u_int hred, hgreen, hblue, htransp = 0xffff; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci hred = *red++; 129462306a36Sopenharmony_ci hgreen = *green++; 129562306a36Sopenharmony_ci hblue = *blue++; 129662306a36Sopenharmony_ci if (transp) 129762306a36Sopenharmony_ci htransp = *transp++; 129862306a36Sopenharmony_ci rc = radeon_setcolreg (start++, hred, hgreen, hblue, htransp, 129962306a36Sopenharmony_ci rinfo); 130062306a36Sopenharmony_ci if (rc) 130162306a36Sopenharmony_ci break; 130262306a36Sopenharmony_ci } 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci if (!rinfo->asleep && rinfo->is_mobility) 130562306a36Sopenharmony_ci OUTPLL(VCLK_ECP_CNTL, vclk_cntl); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci return rc; 130862306a36Sopenharmony_ci} 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_cistatic void radeon_save_state (struct radeonfb_info *rinfo, 131162306a36Sopenharmony_ci struct radeon_regs *save) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci /* CRTC regs */ 131462306a36Sopenharmony_ci save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL); 131562306a36Sopenharmony_ci save->crtc_ext_cntl = INREG(CRTC_EXT_CNTL); 131662306a36Sopenharmony_ci save->crtc_more_cntl = INREG(CRTC_MORE_CNTL); 131762306a36Sopenharmony_ci save->dac_cntl = INREG(DAC_CNTL); 131862306a36Sopenharmony_ci save->crtc_h_total_disp = INREG(CRTC_H_TOTAL_DISP); 131962306a36Sopenharmony_ci save->crtc_h_sync_strt_wid = INREG(CRTC_H_SYNC_STRT_WID); 132062306a36Sopenharmony_ci save->crtc_v_total_disp = INREG(CRTC_V_TOTAL_DISP); 132162306a36Sopenharmony_ci save->crtc_v_sync_strt_wid = INREG(CRTC_V_SYNC_STRT_WID); 132262306a36Sopenharmony_ci save->crtc_pitch = INREG(CRTC_PITCH); 132362306a36Sopenharmony_ci save->surface_cntl = INREG(SURFACE_CNTL); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci /* FP regs */ 132662306a36Sopenharmony_ci save->fp_crtc_h_total_disp = INREG(FP_CRTC_H_TOTAL_DISP); 132762306a36Sopenharmony_ci save->fp_crtc_v_total_disp = INREG(FP_CRTC_V_TOTAL_DISP); 132862306a36Sopenharmony_ci save->fp_gen_cntl = INREG(FP_GEN_CNTL); 132962306a36Sopenharmony_ci save->fp_h_sync_strt_wid = INREG(FP_H_SYNC_STRT_WID); 133062306a36Sopenharmony_ci save->fp_horz_stretch = INREG(FP_HORZ_STRETCH); 133162306a36Sopenharmony_ci save->fp_v_sync_strt_wid = INREG(FP_V_SYNC_STRT_WID); 133262306a36Sopenharmony_ci save->fp_vert_stretch = INREG(FP_VERT_STRETCH); 133362306a36Sopenharmony_ci save->lvds_gen_cntl = INREG(LVDS_GEN_CNTL); 133462306a36Sopenharmony_ci save->lvds_pll_cntl = INREG(LVDS_PLL_CNTL); 133562306a36Sopenharmony_ci save->tmds_crc = INREG(TMDS_CRC); 133662306a36Sopenharmony_ci save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL); 133762306a36Sopenharmony_ci save->vclk_ecp_cntl = INPLL(VCLK_ECP_CNTL); 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci /* PLL regs */ 134062306a36Sopenharmony_ci save->clk_cntl_index = INREG(CLOCK_CNTL_INDEX) & ~0x3f; 134162306a36Sopenharmony_ci radeon_pll_errata_after_index(rinfo); 134262306a36Sopenharmony_ci save->ppll_div_3 = INPLL(PPLL_DIV_3); 134362306a36Sopenharmony_ci save->ppll_ref_div = INPLL(PPLL_REF_DIV); 134462306a36Sopenharmony_ci} 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cistatic void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *mode) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci int i; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci radeon_fifo_wait(20); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci /* Workaround from XFree */ 135462306a36Sopenharmony_ci if (rinfo->is_mobility) { 135562306a36Sopenharmony_ci /* A temporal workaround for the occasional blanking on certain laptop 135662306a36Sopenharmony_ci * panels. This appears to related to the PLL divider registers 135762306a36Sopenharmony_ci * (fail to lock?). It occurs even when all dividers are the same 135862306a36Sopenharmony_ci * with their old settings. In this case we really don't need to 135962306a36Sopenharmony_ci * fiddle with PLL registers. By doing this we can avoid the blanking 136062306a36Sopenharmony_ci * problem with some panels. 136162306a36Sopenharmony_ci */ 136262306a36Sopenharmony_ci if ((mode->ppll_ref_div == (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK)) && 136362306a36Sopenharmony_ci (mode->ppll_div_3 == (INPLL(PPLL_DIV_3) & 136462306a36Sopenharmony_ci (PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK)))) { 136562306a36Sopenharmony_ci /* We still have to force a switch to selected PPLL div thanks to 136662306a36Sopenharmony_ci * an XFree86 driver bug which will switch it away in some cases 136762306a36Sopenharmony_ci * even when using UseFDev */ 136862306a36Sopenharmony_ci OUTREGP(CLOCK_CNTL_INDEX, 136962306a36Sopenharmony_ci mode->clk_cntl_index & PPLL_DIV_SEL_MASK, 137062306a36Sopenharmony_ci ~PPLL_DIV_SEL_MASK); 137162306a36Sopenharmony_ci radeon_pll_errata_after_index(rinfo); 137262306a36Sopenharmony_ci radeon_pll_errata_after_data(rinfo); 137362306a36Sopenharmony_ci return; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci /* Swich VCKL clock input to CPUCLK so it stays fed while PPLL updates*/ 137862306a36Sopenharmony_ci OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_CPUCLK, ~VCLK_SRC_SEL_MASK); 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci /* Reset PPLL & enable atomic update */ 138162306a36Sopenharmony_ci OUTPLLP(PPLL_CNTL, 138262306a36Sopenharmony_ci PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN, 138362306a36Sopenharmony_ci ~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN)); 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci /* Switch to selected PPLL divider */ 138662306a36Sopenharmony_ci OUTREGP(CLOCK_CNTL_INDEX, 138762306a36Sopenharmony_ci mode->clk_cntl_index & PPLL_DIV_SEL_MASK, 138862306a36Sopenharmony_ci ~PPLL_DIV_SEL_MASK); 138962306a36Sopenharmony_ci radeon_pll_errata_after_index(rinfo); 139062306a36Sopenharmony_ci radeon_pll_errata_after_data(rinfo); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci /* Set PPLL ref. div */ 139362306a36Sopenharmony_ci if (IS_R300_VARIANT(rinfo) || 139462306a36Sopenharmony_ci rinfo->family == CHIP_FAMILY_RS300 || 139562306a36Sopenharmony_ci rinfo->family == CHIP_FAMILY_RS400 || 139662306a36Sopenharmony_ci rinfo->family == CHIP_FAMILY_RS480) { 139762306a36Sopenharmony_ci if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { 139862306a36Sopenharmony_ci /* When restoring console mode, use saved PPLL_REF_DIV 139962306a36Sopenharmony_ci * setting. 140062306a36Sopenharmony_ci */ 140162306a36Sopenharmony_ci OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, 0); 140262306a36Sopenharmony_ci } else { 140362306a36Sopenharmony_ci /* R300 uses ref_div_acc field as real ref divider */ 140462306a36Sopenharmony_ci OUTPLLP(PPLL_REF_DIV, 140562306a36Sopenharmony_ci (mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), 140662306a36Sopenharmony_ci ~R300_PPLL_REF_DIV_ACC_MASK); 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci } else 140962306a36Sopenharmony_ci OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci /* Set PPLL divider 3 & post divider*/ 141262306a36Sopenharmony_ci OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK); 141362306a36Sopenharmony_ci OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci /* Write update */ 141662306a36Sopenharmony_ci while (INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R) 141762306a36Sopenharmony_ci ; 141862306a36Sopenharmony_ci OUTPLLP(PPLL_REF_DIV, PPLL_ATOMIC_UPDATE_W, ~PPLL_ATOMIC_UPDATE_W); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci /* Wait read update complete */ 142162306a36Sopenharmony_ci /* FIXME: Certain revisions of R300 can't recover here. Not sure of 142262306a36Sopenharmony_ci the cause yet, but this workaround will mask the problem for now. 142362306a36Sopenharmony_ci Other chips usually will pass at the very first test, so the 142462306a36Sopenharmony_ci workaround shouldn't have any effect on them. */ 142562306a36Sopenharmony_ci for (i = 0; (i < 10000 && INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); i++) 142662306a36Sopenharmony_ci ; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci OUTPLL(HTOTAL_CNTL, 0); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* Clear reset & atomic update */ 143162306a36Sopenharmony_ci OUTPLLP(PPLL_CNTL, 0, 143262306a36Sopenharmony_ci ~(PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN)); 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci /* We may want some locking ... oh well */ 143562306a36Sopenharmony_ci radeon_msleep(5); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci /* Switch back VCLK source to PPLL */ 143862306a36Sopenharmony_ci OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_PPLLCLK, ~VCLK_SRC_SEL_MASK); 143962306a36Sopenharmony_ci} 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci/* 144262306a36Sopenharmony_ci * Timer function for delayed LVDS panel power up/down 144362306a36Sopenharmony_ci */ 144462306a36Sopenharmony_cistatic void radeon_lvds_timer_func(struct timer_list *t) 144562306a36Sopenharmony_ci{ 144662306a36Sopenharmony_ci struct radeonfb_info *rinfo = from_timer(rinfo, t, lvds_timer); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci radeon_engine_idle(); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci OUTREG(LVDS_GEN_CNTL, rinfo->pending_lvds_gen_cntl); 145162306a36Sopenharmony_ci} 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci/* 145462306a36Sopenharmony_ci * Apply a video mode. This will apply the whole register set, including 145562306a36Sopenharmony_ci * the PLL registers, to the card 145662306a36Sopenharmony_ci */ 145762306a36Sopenharmony_civoid radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, 145862306a36Sopenharmony_ci int regs_only) 145962306a36Sopenharmony_ci{ 146062306a36Sopenharmony_ci int i; 146162306a36Sopenharmony_ci int primary_mon = PRIMARY_MONITOR(rinfo); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci if (nomodeset) 146462306a36Sopenharmony_ci return; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci if (!regs_only) 146762306a36Sopenharmony_ci radeon_screen_blank(rinfo, FB_BLANK_NORMAL, 0); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci radeon_fifo_wait(31); 147062306a36Sopenharmony_ci for (i=0; i<10; i++) 147162306a36Sopenharmony_ci OUTREG(common_regs[i].reg, common_regs[i].val); 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci /* Apply surface registers */ 147462306a36Sopenharmony_ci for (i=0; i<8; i++) { 147562306a36Sopenharmony_ci OUTREG(SURFACE0_LOWER_BOUND + 0x10*i, mode->surf_lower_bound[i]); 147662306a36Sopenharmony_ci OUTREG(SURFACE0_UPPER_BOUND + 0x10*i, mode->surf_upper_bound[i]); 147762306a36Sopenharmony_ci OUTREG(SURFACE0_INFO + 0x10*i, mode->surf_info[i]); 147862306a36Sopenharmony_ci } 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl); 148162306a36Sopenharmony_ci OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl, 148262306a36Sopenharmony_ci ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS)); 148362306a36Sopenharmony_ci OUTREG(CRTC_MORE_CNTL, mode->crtc_more_cntl); 148462306a36Sopenharmony_ci OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING); 148562306a36Sopenharmony_ci OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp); 148662306a36Sopenharmony_ci OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid); 148762306a36Sopenharmony_ci OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp); 148862306a36Sopenharmony_ci OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid); 148962306a36Sopenharmony_ci OUTREG(CRTC_OFFSET, 0); 149062306a36Sopenharmony_ci OUTREG(CRTC_OFFSET_CNTL, 0); 149162306a36Sopenharmony_ci OUTREG(CRTC_PITCH, mode->crtc_pitch); 149262306a36Sopenharmony_ci OUTREG(SURFACE_CNTL, mode->surface_cntl); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci radeon_write_pll_regs(rinfo, mode); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { 149762306a36Sopenharmony_ci radeon_fifo_wait(10); 149862306a36Sopenharmony_ci OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp); 149962306a36Sopenharmony_ci OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp); 150062306a36Sopenharmony_ci OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid); 150162306a36Sopenharmony_ci OUTREG(FP_V_SYNC_STRT_WID, mode->fp_v_sync_strt_wid); 150262306a36Sopenharmony_ci OUTREG(FP_HORZ_STRETCH, mode->fp_horz_stretch); 150362306a36Sopenharmony_ci OUTREG(FP_VERT_STRETCH, mode->fp_vert_stretch); 150462306a36Sopenharmony_ci OUTREG(FP_GEN_CNTL, mode->fp_gen_cntl); 150562306a36Sopenharmony_ci OUTREG(TMDS_CRC, mode->tmds_crc); 150662306a36Sopenharmony_ci OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl); 150762306a36Sopenharmony_ci } 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci if (!regs_only) 151062306a36Sopenharmony_ci radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 0); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci radeon_fifo_wait(2); 151362306a36Sopenharmony_ci OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl); 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci return; 151662306a36Sopenharmony_ci} 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci/* 151962306a36Sopenharmony_ci * Calculate the PLL values for a given mode 152062306a36Sopenharmony_ci */ 152162306a36Sopenharmony_cistatic void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *regs, 152262306a36Sopenharmony_ci unsigned long freq) 152362306a36Sopenharmony_ci{ 152462306a36Sopenharmony_ci static const struct { 152562306a36Sopenharmony_ci int divider; 152662306a36Sopenharmony_ci int bitvalue; 152762306a36Sopenharmony_ci } *post_div, 152862306a36Sopenharmony_ci post_divs[] = { 152962306a36Sopenharmony_ci { 1, 0 }, 153062306a36Sopenharmony_ci { 2, 1 }, 153162306a36Sopenharmony_ci { 4, 2 }, 153262306a36Sopenharmony_ci { 8, 3 }, 153362306a36Sopenharmony_ci { 3, 4 }, 153462306a36Sopenharmony_ci { 16, 5 }, 153562306a36Sopenharmony_ci { 6, 6 }, 153662306a36Sopenharmony_ci { 12, 7 }, 153762306a36Sopenharmony_ci { 0, 0 }, 153862306a36Sopenharmony_ci }; 153962306a36Sopenharmony_ci int fb_div, pll_output_freq = 0; 154062306a36Sopenharmony_ci int uses_dvo = 0; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci /* Check if the DVO port is enabled and sourced from the primary CRTC. I'm 154362306a36Sopenharmony_ci * not sure which model starts having FP2_GEN_CNTL, I assume anything more 154462306a36Sopenharmony_ci * recent than an r(v)100... 154562306a36Sopenharmony_ci */ 154662306a36Sopenharmony_ci#if 1 154762306a36Sopenharmony_ci /* XXX I had reports of flicker happening with the cinema display 154862306a36Sopenharmony_ci * on TMDS1 that seem to be fixed if I also forbit odd dividers in 154962306a36Sopenharmony_ci * this case. This could just be a bandwidth calculation issue, I 155062306a36Sopenharmony_ci * haven't implemented the bandwidth code yet, but in the meantime, 155162306a36Sopenharmony_ci * forcing uses_dvo to 1 fixes it and shouln't have bad side effects, 155262306a36Sopenharmony_ci * I haven't seen a case were were absolutely needed an odd PLL 155362306a36Sopenharmony_ci * divider. I'll find a better fix once I have more infos on the 155462306a36Sopenharmony_ci * real cause of the problem. 155562306a36Sopenharmony_ci */ 155662306a36Sopenharmony_ci while (rinfo->has_CRTC2) { 155762306a36Sopenharmony_ci u32 fp2_gen_cntl = INREG(FP2_GEN_CNTL); 155862306a36Sopenharmony_ci u32 disp_output_cntl; 155962306a36Sopenharmony_ci int source; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci /* FP2 path not enabled */ 156262306a36Sopenharmony_ci if ((fp2_gen_cntl & FP2_ON) == 0) 156362306a36Sopenharmony_ci break; 156462306a36Sopenharmony_ci /* Not all chip revs have the same format for this register, 156562306a36Sopenharmony_ci * extract the source selection 156662306a36Sopenharmony_ci */ 156762306a36Sopenharmony_ci if (rinfo->family == CHIP_FAMILY_R200 || IS_R300_VARIANT(rinfo)) { 156862306a36Sopenharmony_ci source = (fp2_gen_cntl >> 10) & 0x3; 156962306a36Sopenharmony_ci /* sourced from transform unit, check for transform unit 157062306a36Sopenharmony_ci * own source 157162306a36Sopenharmony_ci */ 157262306a36Sopenharmony_ci if (source == 3) { 157362306a36Sopenharmony_ci disp_output_cntl = INREG(DISP_OUTPUT_CNTL); 157462306a36Sopenharmony_ci source = (disp_output_cntl >> 12) & 0x3; 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci } else 157762306a36Sopenharmony_ci source = (fp2_gen_cntl >> 13) & 0x1; 157862306a36Sopenharmony_ci /* sourced from CRTC2 -> exit */ 157962306a36Sopenharmony_ci if (source == 1) 158062306a36Sopenharmony_ci break; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci /* so we end up on CRTC1, let's set uses_dvo to 1 now */ 158362306a36Sopenharmony_ci uses_dvo = 1; 158462306a36Sopenharmony_ci break; 158562306a36Sopenharmony_ci } 158662306a36Sopenharmony_ci#else 158762306a36Sopenharmony_ci uses_dvo = 1; 158862306a36Sopenharmony_ci#endif 158962306a36Sopenharmony_ci if (freq > rinfo->pll.ppll_max) 159062306a36Sopenharmony_ci freq = rinfo->pll.ppll_max; 159162306a36Sopenharmony_ci if (freq*12 < rinfo->pll.ppll_min) 159262306a36Sopenharmony_ci freq = rinfo->pll.ppll_min / 12; 159362306a36Sopenharmony_ci pr_debug("freq = %lu, PLL min = %u, PLL max = %u\n", 159462306a36Sopenharmony_ci freq, rinfo->pll.ppll_min, rinfo->pll.ppll_max); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci for (post_div = &post_divs[0]; post_div->divider; ++post_div) { 159762306a36Sopenharmony_ci pll_output_freq = post_div->divider * freq; 159862306a36Sopenharmony_ci /* If we output to the DVO port (external TMDS), we don't allow an 159962306a36Sopenharmony_ci * odd PLL divider as those aren't supported on this path 160062306a36Sopenharmony_ci */ 160162306a36Sopenharmony_ci if (uses_dvo && (post_div->divider & 1)) 160262306a36Sopenharmony_ci continue; 160362306a36Sopenharmony_ci if (pll_output_freq >= rinfo->pll.ppll_min && 160462306a36Sopenharmony_ci pll_output_freq <= rinfo->pll.ppll_max) 160562306a36Sopenharmony_ci break; 160662306a36Sopenharmony_ci } 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci /* If we fall through the bottom, try the "default value" 160962306a36Sopenharmony_ci given by the terminal post_div->bitvalue */ 161062306a36Sopenharmony_ci if ( !post_div->divider ) { 161162306a36Sopenharmony_ci post_div = &post_divs[post_div->bitvalue]; 161262306a36Sopenharmony_ci pll_output_freq = post_div->divider * freq; 161362306a36Sopenharmony_ci } 161462306a36Sopenharmony_ci pr_debug("ref_div = %d, ref_clk = %d, output_freq = %d\n", 161562306a36Sopenharmony_ci rinfo->pll.ref_div, rinfo->pll.ref_clk, 161662306a36Sopenharmony_ci pll_output_freq); 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci /* If we fall through the bottom, try the "default value" 161962306a36Sopenharmony_ci given by the terminal post_div->bitvalue */ 162062306a36Sopenharmony_ci if ( !post_div->divider ) { 162162306a36Sopenharmony_ci post_div = &post_divs[post_div->bitvalue]; 162262306a36Sopenharmony_ci pll_output_freq = post_div->divider * freq; 162362306a36Sopenharmony_ci } 162462306a36Sopenharmony_ci pr_debug("ref_div = %d, ref_clk = %d, output_freq = %d\n", 162562306a36Sopenharmony_ci rinfo->pll.ref_div, rinfo->pll.ref_clk, 162662306a36Sopenharmony_ci pll_output_freq); 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci fb_div = round_div(rinfo->pll.ref_div*pll_output_freq, 162962306a36Sopenharmony_ci rinfo->pll.ref_clk); 163062306a36Sopenharmony_ci regs->ppll_ref_div = rinfo->pll.ref_div; 163162306a36Sopenharmony_ci regs->ppll_div_3 = fb_div | (post_div->bitvalue << 16); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci pr_debug("post div = 0x%x\n", post_div->bitvalue); 163462306a36Sopenharmony_ci pr_debug("fb_div = 0x%x\n", fb_div); 163562306a36Sopenharmony_ci pr_debug("ppll_div_3 = 0x%x\n", regs->ppll_div_3); 163662306a36Sopenharmony_ci} 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_cistatic int radeonfb_set_par(struct fb_info *info) 163962306a36Sopenharmony_ci{ 164062306a36Sopenharmony_ci struct radeonfb_info *rinfo = info->par; 164162306a36Sopenharmony_ci struct fb_var_screeninfo *mode = &info->var; 164262306a36Sopenharmony_ci struct radeon_regs *newmode; 164362306a36Sopenharmony_ci int hTotal, vTotal, hSyncStart, hSyncEnd, 164462306a36Sopenharmony_ci vSyncStart, vSyncEnd; 164562306a36Sopenharmony_ci u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5}; 164662306a36Sopenharmony_ci u8 hsync_fudge_fp[] = {2, 2, 0, 0, 5, 5}; 164762306a36Sopenharmony_ci u32 sync, h_sync_pol, v_sync_pol, dotClock, pixClock; 164862306a36Sopenharmony_ci int i, freq; 164962306a36Sopenharmony_ci int format = 0; 165062306a36Sopenharmony_ci int nopllcalc = 0; 165162306a36Sopenharmony_ci int hsync_start, hsync_fudge, hsync_wid, vsync_wid; 165262306a36Sopenharmony_ci int primary_mon = PRIMARY_MONITOR(rinfo); 165362306a36Sopenharmony_ci int depth = var_to_depth(mode); 165462306a36Sopenharmony_ci int use_rmx = 0; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci newmode = kmalloc(sizeof(struct radeon_regs), GFP_KERNEL); 165762306a36Sopenharmony_ci if (!newmode) 165862306a36Sopenharmony_ci return -ENOMEM; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci /* We always want engine to be idle on a mode switch, even 166162306a36Sopenharmony_ci * if we won't actually change the mode 166262306a36Sopenharmony_ci */ 166362306a36Sopenharmony_ci radeon_engine_idle(); 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci hSyncStart = mode->xres + mode->right_margin; 166662306a36Sopenharmony_ci hSyncEnd = hSyncStart + mode->hsync_len; 166762306a36Sopenharmony_ci hTotal = hSyncEnd + mode->left_margin; 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci vSyncStart = mode->yres + mode->lower_margin; 167062306a36Sopenharmony_ci vSyncEnd = vSyncStart + mode->vsync_len; 167162306a36Sopenharmony_ci vTotal = vSyncEnd + mode->upper_margin; 167262306a36Sopenharmony_ci pixClock = mode->pixclock; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci sync = mode->sync; 167562306a36Sopenharmony_ci h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; 167662306a36Sopenharmony_ci v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci if (primary_mon == MT_DFP || primary_mon == MT_LCD) { 167962306a36Sopenharmony_ci if (rinfo->panel_info.xres < mode->xres) 168062306a36Sopenharmony_ci mode->xres = rinfo->panel_info.xres; 168162306a36Sopenharmony_ci if (rinfo->panel_info.yres < mode->yres) 168262306a36Sopenharmony_ci mode->yres = rinfo->panel_info.yres; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci hTotal = mode->xres + rinfo->panel_info.hblank; 168562306a36Sopenharmony_ci hSyncStart = mode->xres + rinfo->panel_info.hOver_plus; 168662306a36Sopenharmony_ci hSyncEnd = hSyncStart + rinfo->panel_info.hSync_width; 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci vTotal = mode->yres + rinfo->panel_info.vblank; 168962306a36Sopenharmony_ci vSyncStart = mode->yres + rinfo->panel_info.vOver_plus; 169062306a36Sopenharmony_ci vSyncEnd = vSyncStart + rinfo->panel_info.vSync_width; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci h_sync_pol = !rinfo->panel_info.hAct_high; 169362306a36Sopenharmony_ci v_sync_pol = !rinfo->panel_info.vAct_high; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci pixClock = 100000000 / rinfo->panel_info.clock; 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci if (rinfo->panel_info.use_bios_dividers) { 169862306a36Sopenharmony_ci nopllcalc = 1; 169962306a36Sopenharmony_ci newmode->ppll_div_3 = rinfo->panel_info.fbk_divider | 170062306a36Sopenharmony_ci (rinfo->panel_info.post_divider << 16); 170162306a36Sopenharmony_ci newmode->ppll_ref_div = rinfo->panel_info.ref_divider; 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci dotClock = 1000000000 / pixClock; 170562306a36Sopenharmony_ci freq = dotClock / 10; /* x100 */ 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci pr_debug("hStart = %d, hEnd = %d, hTotal = %d\n", 170862306a36Sopenharmony_ci hSyncStart, hSyncEnd, hTotal); 170962306a36Sopenharmony_ci pr_debug("vStart = %d, vEnd = %d, vTotal = %d\n", 171062306a36Sopenharmony_ci vSyncStart, vSyncEnd, vTotal); 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci hsync_wid = (hSyncEnd - hSyncStart) / 8; 171362306a36Sopenharmony_ci vsync_wid = vSyncEnd - vSyncStart; 171462306a36Sopenharmony_ci if (hsync_wid == 0) 171562306a36Sopenharmony_ci hsync_wid = 1; 171662306a36Sopenharmony_ci else if (hsync_wid > 0x3f) /* max */ 171762306a36Sopenharmony_ci hsync_wid = 0x3f; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci if (vsync_wid == 0) 172062306a36Sopenharmony_ci vsync_wid = 1; 172162306a36Sopenharmony_ci else if (vsync_wid > 0x1f) /* max */ 172262306a36Sopenharmony_ci vsync_wid = 0x1f; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci format = radeon_get_dstbpp(depth); 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) 172762306a36Sopenharmony_ci hsync_fudge = hsync_fudge_fp[format-1]; 172862306a36Sopenharmony_ci else 172962306a36Sopenharmony_ci hsync_fudge = hsync_adj_tab[format-1]; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci hsync_start = hSyncStart - 8 + hsync_fudge; 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci newmode->crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | 173462306a36Sopenharmony_ci (format << 8); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci /* Clear auto-center etc... */ 173762306a36Sopenharmony_ci newmode->crtc_more_cntl = rinfo->init_state.crtc_more_cntl; 173862306a36Sopenharmony_ci newmode->crtc_more_cntl &= 0xfffffff0; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { 174162306a36Sopenharmony_ci newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN; 174262306a36Sopenharmony_ci if (mirror) 174362306a36Sopenharmony_ci newmode->crtc_ext_cntl |= CRTC_CRT_ON; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci newmode->crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN | 174662306a36Sopenharmony_ci CRTC_INTERLACE_EN); 174762306a36Sopenharmony_ci } else { 174862306a36Sopenharmony_ci newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN | 174962306a36Sopenharmony_ci CRTC_CRT_ON; 175062306a36Sopenharmony_ci } 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci newmode->dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN | 175362306a36Sopenharmony_ci DAC_8BIT_EN; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci newmode->crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) | 175662306a36Sopenharmony_ci (((mode->xres / 8) - 1) << 16)); 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci newmode->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) | 175962306a36Sopenharmony_ci (hsync_wid << 16) | (h_sync_pol << 23)); 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci newmode->crtc_v_total_disp = ((vTotal - 1) & 0xffff) | 176262306a36Sopenharmony_ci ((mode->yres - 1) << 16); 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci newmode->crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) | 176562306a36Sopenharmony_ci (vsync_wid << 16) | (v_sync_pol << 23)); 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci if (!(info->flags & FBINFO_HWACCEL_DISABLED)) { 176862306a36Sopenharmony_ci /* We first calculate the engine pitch */ 176962306a36Sopenharmony_ci rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f) 177062306a36Sopenharmony_ci & ~(0x3f)) >> 6; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci /* Then, re-multiply it to get the CRTC pitch */ 177362306a36Sopenharmony_ci newmode->crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8); 177462306a36Sopenharmony_ci } else 177562306a36Sopenharmony_ci newmode->crtc_pitch = (mode->xres_virtual >> 3); 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci newmode->crtc_pitch |= (newmode->crtc_pitch << 16); 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci /* 178062306a36Sopenharmony_ci * It looks like recent chips have a problem with SURFACE_CNTL, 178162306a36Sopenharmony_ci * setting SURF_TRANSLATION_DIS completely disables the 178262306a36Sopenharmony_ci * swapper as well, so we leave it unset now. 178362306a36Sopenharmony_ci */ 178462306a36Sopenharmony_ci newmode->surface_cntl = 0; 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci#if defined(__BIG_ENDIAN) 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci /* Setup swapping on both apertures, though we currently 178962306a36Sopenharmony_ci * only use aperture 0, enabling swapper on aperture 1 179062306a36Sopenharmony_ci * won't harm 179162306a36Sopenharmony_ci */ 179262306a36Sopenharmony_ci switch (mode->bits_per_pixel) { 179362306a36Sopenharmony_ci case 16: 179462306a36Sopenharmony_ci newmode->surface_cntl |= NONSURF_AP0_SWP_16BPP; 179562306a36Sopenharmony_ci newmode->surface_cntl |= NONSURF_AP1_SWP_16BPP; 179662306a36Sopenharmony_ci break; 179762306a36Sopenharmony_ci case 24: 179862306a36Sopenharmony_ci case 32: 179962306a36Sopenharmony_ci newmode->surface_cntl |= NONSURF_AP0_SWP_32BPP; 180062306a36Sopenharmony_ci newmode->surface_cntl |= NONSURF_AP1_SWP_32BPP; 180162306a36Sopenharmony_ci break; 180262306a36Sopenharmony_ci } 180362306a36Sopenharmony_ci#endif 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci /* Clear surface registers */ 180662306a36Sopenharmony_ci for (i=0; i<8; i++) { 180762306a36Sopenharmony_ci newmode->surf_lower_bound[i] = 0; 180862306a36Sopenharmony_ci newmode->surf_upper_bound[i] = 0x1f; 180962306a36Sopenharmony_ci newmode->surf_info[i] = 0; 181062306a36Sopenharmony_ci } 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci pr_debug("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", 181362306a36Sopenharmony_ci newmode->crtc_h_total_disp, newmode->crtc_h_sync_strt_wid); 181462306a36Sopenharmony_ci pr_debug("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", 181562306a36Sopenharmony_ci newmode->crtc_v_total_disp, newmode->crtc_v_sync_strt_wid); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci rinfo->bpp = mode->bits_per_pixel; 181862306a36Sopenharmony_ci rinfo->depth = depth; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci pr_debug("pixclock = %lu\n", (unsigned long)pixClock); 182162306a36Sopenharmony_ci pr_debug("freq = %lu\n", (unsigned long)freq); 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci /* We use PPLL_DIV_3 */ 182462306a36Sopenharmony_ci newmode->clk_cntl_index = 0x300; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci /* Calculate PPLL value if necessary */ 182762306a36Sopenharmony_ci if (!nopllcalc) 182862306a36Sopenharmony_ci radeon_calc_pll_regs(rinfo, newmode, freq); 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci newmode->vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl; 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { 183362306a36Sopenharmony_ci unsigned int hRatio, vRatio; 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci if (mode->xres > rinfo->panel_info.xres) 183662306a36Sopenharmony_ci mode->xres = rinfo->panel_info.xres; 183762306a36Sopenharmony_ci if (mode->yres > rinfo->panel_info.yres) 183862306a36Sopenharmony_ci mode->yres = rinfo->panel_info.yres; 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci newmode->fp_horz_stretch = (((rinfo->panel_info.xres / 8) - 1) 184162306a36Sopenharmony_ci << HORZ_PANEL_SHIFT); 184262306a36Sopenharmony_ci newmode->fp_vert_stretch = ((rinfo->panel_info.yres - 1) 184362306a36Sopenharmony_ci << VERT_PANEL_SHIFT); 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci if (mode->xres != rinfo->panel_info.xres) { 184662306a36Sopenharmony_ci hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX, 184762306a36Sopenharmony_ci rinfo->panel_info.xres); 184862306a36Sopenharmony_ci newmode->fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) | 184962306a36Sopenharmony_ci (newmode->fp_horz_stretch & 185062306a36Sopenharmony_ci (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH | 185162306a36Sopenharmony_ci HORZ_AUTO_RATIO_INC))); 185262306a36Sopenharmony_ci newmode->fp_horz_stretch |= (HORZ_STRETCH_BLEND | 185362306a36Sopenharmony_ci HORZ_STRETCH_ENABLE); 185462306a36Sopenharmony_ci use_rmx = 1; 185562306a36Sopenharmony_ci } 185662306a36Sopenharmony_ci newmode->fp_horz_stretch &= ~HORZ_AUTO_RATIO; 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci if (mode->yres != rinfo->panel_info.yres) { 185962306a36Sopenharmony_ci vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX, 186062306a36Sopenharmony_ci rinfo->panel_info.yres); 186162306a36Sopenharmony_ci newmode->fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) | 186262306a36Sopenharmony_ci (newmode->fp_vert_stretch & 186362306a36Sopenharmony_ci (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED))); 186462306a36Sopenharmony_ci newmode->fp_vert_stretch |= (VERT_STRETCH_BLEND | 186562306a36Sopenharmony_ci VERT_STRETCH_ENABLE); 186662306a36Sopenharmony_ci use_rmx = 1; 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci newmode->fp_vert_stretch &= ~VERT_AUTO_RATIO_EN; 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci newmode->fp_gen_cntl = (rinfo->init_state.fp_gen_cntl & (u32) 187162306a36Sopenharmony_ci ~(FP_SEL_CRTC2 | 187262306a36Sopenharmony_ci FP_RMX_HVSYNC_CONTROL_EN | 187362306a36Sopenharmony_ci FP_DFP_SYNC_SEL | 187462306a36Sopenharmony_ci FP_CRT_SYNC_SEL | 187562306a36Sopenharmony_ci FP_CRTC_LOCK_8DOT | 187662306a36Sopenharmony_ci FP_USE_SHADOW_EN | 187762306a36Sopenharmony_ci FP_CRTC_USE_SHADOW_VEND | 187862306a36Sopenharmony_ci FP_CRT_SYNC_ALT)); 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci newmode->fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR | 188162306a36Sopenharmony_ci FP_CRTC_DONT_SHADOW_HEND | 188262306a36Sopenharmony_ci FP_PANEL_FORMAT); 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci if (IS_R300_VARIANT(rinfo) || 188562306a36Sopenharmony_ci (rinfo->family == CHIP_FAMILY_R200)) { 188662306a36Sopenharmony_ci newmode->fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; 188762306a36Sopenharmony_ci if (use_rmx) 188862306a36Sopenharmony_ci newmode->fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX; 188962306a36Sopenharmony_ci else 189062306a36Sopenharmony_ci newmode->fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1; 189162306a36Sopenharmony_ci } else 189262306a36Sopenharmony_ci newmode->fp_gen_cntl |= FP_SEL_CRTC1; 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci newmode->lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl; 189562306a36Sopenharmony_ci newmode->lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl; 189662306a36Sopenharmony_ci newmode->tmds_crc = rinfo->init_state.tmds_crc; 189762306a36Sopenharmony_ci newmode->tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl; 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci if (primary_mon == MT_LCD) { 190062306a36Sopenharmony_ci newmode->lvds_gen_cntl |= (LVDS_ON | LVDS_BLON); 190162306a36Sopenharmony_ci newmode->fp_gen_cntl &= ~(FP_FPON | FP_TMDS_EN); 190262306a36Sopenharmony_ci } else { 190362306a36Sopenharmony_ci /* DFP */ 190462306a36Sopenharmony_ci newmode->fp_gen_cntl |= (FP_FPON | FP_TMDS_EN); 190562306a36Sopenharmony_ci newmode->tmds_transmitter_cntl &= ~(TMDS_PLLRST); 190662306a36Sopenharmony_ci /* TMDS_PLL_EN bit is reversed on RV (and mobility) chips */ 190762306a36Sopenharmony_ci if (IS_R300_VARIANT(rinfo) || 190862306a36Sopenharmony_ci (rinfo->family == CHIP_FAMILY_R200) || !rinfo->has_CRTC2) 190962306a36Sopenharmony_ci newmode->tmds_transmitter_cntl &= ~TMDS_PLL_EN; 191062306a36Sopenharmony_ci else 191162306a36Sopenharmony_ci newmode->tmds_transmitter_cntl |= TMDS_PLL_EN; 191262306a36Sopenharmony_ci newmode->crtc_ext_cntl &= ~CRTC_CRT_ON; 191362306a36Sopenharmony_ci } 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci newmode->fp_crtc_h_total_disp = (((rinfo->panel_info.hblank / 8) & 0x3ff) | 191662306a36Sopenharmony_ci (((mode->xres / 8) - 1) << 16)); 191762306a36Sopenharmony_ci newmode->fp_crtc_v_total_disp = (rinfo->panel_info.vblank & 0xffff) | 191862306a36Sopenharmony_ci ((mode->yres - 1) << 16); 191962306a36Sopenharmony_ci newmode->fp_h_sync_strt_wid = ((rinfo->panel_info.hOver_plus & 0x1fff) | 192062306a36Sopenharmony_ci (hsync_wid << 16) | (h_sync_pol << 23)); 192162306a36Sopenharmony_ci newmode->fp_v_sync_strt_wid = ((rinfo->panel_info.vOver_plus & 0xfff) | 192262306a36Sopenharmony_ci (vsync_wid << 16) | (v_sync_pol << 23)); 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci /* do it! */ 192662306a36Sopenharmony_ci if (!rinfo->asleep) { 192762306a36Sopenharmony_ci memcpy(&rinfo->state, newmode, sizeof(*newmode)); 192862306a36Sopenharmony_ci radeon_write_mode (rinfo, newmode, 0); 192962306a36Sopenharmony_ci /* (re)initialize the engine */ 193062306a36Sopenharmony_ci if (!(info->flags & FBINFO_HWACCEL_DISABLED)) 193162306a36Sopenharmony_ci radeonfb_engine_init (rinfo); 193262306a36Sopenharmony_ci } 193362306a36Sopenharmony_ci /* Update fix */ 193462306a36Sopenharmony_ci if (!(info->flags & FBINFO_HWACCEL_DISABLED)) 193562306a36Sopenharmony_ci info->fix.line_length = rinfo->pitch*64; 193662306a36Sopenharmony_ci else 193762306a36Sopenharmony_ci info->fix.line_length = mode->xres_virtual 193862306a36Sopenharmony_ci * ((mode->bits_per_pixel + 1) / 8); 193962306a36Sopenharmony_ci info->fix.visual = rinfo->depth == 8 ? FB_VISUAL_PSEUDOCOLOR 194062306a36Sopenharmony_ci : FB_VISUAL_DIRECTCOLOR; 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci#ifdef CONFIG_BOOTX_TEXT 194362306a36Sopenharmony_ci /* Update debug text engine */ 194462306a36Sopenharmony_ci btext_update_display(rinfo->fb_base_phys, mode->xres, mode->yres, 194562306a36Sopenharmony_ci rinfo->depth, info->fix.line_length); 194662306a36Sopenharmony_ci#endif 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci kfree(newmode); 194962306a36Sopenharmony_ci return 0; 195062306a36Sopenharmony_ci} 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_cistatic const struct fb_ops radeonfb_ops = { 195462306a36Sopenharmony_ci .owner = THIS_MODULE, 195562306a36Sopenharmony_ci .fb_check_var = radeonfb_check_var, 195662306a36Sopenharmony_ci .fb_set_par = radeonfb_set_par, 195762306a36Sopenharmony_ci .fb_setcolreg = radeonfb_setcolreg, 195862306a36Sopenharmony_ci .fb_setcmap = radeonfb_setcmap, 195962306a36Sopenharmony_ci .fb_pan_display = radeonfb_pan_display, 196062306a36Sopenharmony_ci .fb_blank = radeonfb_blank, 196162306a36Sopenharmony_ci .fb_ioctl = radeonfb_ioctl, 196262306a36Sopenharmony_ci .fb_sync = radeonfb_sync, 196362306a36Sopenharmony_ci .fb_fillrect = radeonfb_fillrect, 196462306a36Sopenharmony_ci .fb_copyarea = radeonfb_copyarea, 196562306a36Sopenharmony_ci .fb_imageblit = radeonfb_imageblit, 196662306a36Sopenharmony_ci}; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_cistatic int radeon_set_fbinfo(struct radeonfb_info *rinfo) 197062306a36Sopenharmony_ci{ 197162306a36Sopenharmony_ci struct fb_info *info = rinfo->info; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci info->par = rinfo; 197462306a36Sopenharmony_ci info->pseudo_palette = rinfo->pseudo_palette; 197562306a36Sopenharmony_ci info->flags = FBINFO_HWACCEL_COPYAREA 197662306a36Sopenharmony_ci | FBINFO_HWACCEL_FILLRECT 197762306a36Sopenharmony_ci | FBINFO_HWACCEL_XPAN 197862306a36Sopenharmony_ci | FBINFO_HWACCEL_YPAN; 197962306a36Sopenharmony_ci info->fbops = &radeonfb_ops; 198062306a36Sopenharmony_ci info->screen_base = rinfo->fb_base; 198162306a36Sopenharmony_ci info->screen_size = rinfo->mapped_vram; 198262306a36Sopenharmony_ci /* Fill fix common fields */ 198362306a36Sopenharmony_ci strscpy(info->fix.id, rinfo->name, sizeof(info->fix.id)); 198462306a36Sopenharmony_ci info->fix.smem_start = rinfo->fb_base_phys; 198562306a36Sopenharmony_ci info->fix.smem_len = rinfo->video_ram; 198662306a36Sopenharmony_ci info->fix.type = FB_TYPE_PACKED_PIXELS; 198762306a36Sopenharmony_ci info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 198862306a36Sopenharmony_ci info->fix.xpanstep = 8; 198962306a36Sopenharmony_ci info->fix.ypanstep = 1; 199062306a36Sopenharmony_ci info->fix.ywrapstep = 0; 199162306a36Sopenharmony_ci info->fix.type_aux = 0; 199262306a36Sopenharmony_ci info->fix.mmio_start = rinfo->mmio_base_phys; 199362306a36Sopenharmony_ci info->fix.mmio_len = RADEON_REGSIZE; 199462306a36Sopenharmony_ci info->fix.accel = FB_ACCEL_ATI_RADEON; 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci fb_alloc_cmap(&info->cmap, 256, 0); 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci if (noaccel) 199962306a36Sopenharmony_ci info->flags |= FBINFO_HWACCEL_DISABLED; 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci return 0; 200262306a36Sopenharmony_ci} 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci/* 200562306a36Sopenharmony_ci * This reconfigure the card's internal memory map. In theory, we'd like 200662306a36Sopenharmony_ci * to setup the card's memory at the same address as it's PCI bus address, 200762306a36Sopenharmony_ci * and the AGP aperture right after that so that system RAM on 32 bits 200862306a36Sopenharmony_ci * machines at least, is directly accessible. However, doing so would 200962306a36Sopenharmony_ci * conflict with the current XFree drivers... 201062306a36Sopenharmony_ci * Ultimately, I hope XFree, GATOS and ATI binary drivers will all agree 201162306a36Sopenharmony_ci * on the proper way to set this up and duplicate this here. In the meantime, 201262306a36Sopenharmony_ci * I put the card's memory at 0 in card space and AGP at some random high 201362306a36Sopenharmony_ci * local (0xe0000000 for now) that will be changed by XFree/DRI anyway 201462306a36Sopenharmony_ci */ 201562306a36Sopenharmony_ci#ifdef CONFIG_PPC 201662306a36Sopenharmony_ci#undef SET_MC_FB_FROM_APERTURE 201762306a36Sopenharmony_cistatic void fixup_memory_mappings(struct radeonfb_info *rinfo) 201862306a36Sopenharmony_ci{ 201962306a36Sopenharmony_ci u32 save_crtc_gen_cntl, save_crtc2_gen_cntl = 0; 202062306a36Sopenharmony_ci u32 save_crtc_ext_cntl; 202162306a36Sopenharmony_ci u32 aper_base, aper_size; 202262306a36Sopenharmony_ci u32 agp_base; 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci /* First, we disable display to avoid interfering */ 202562306a36Sopenharmony_ci if (rinfo->has_CRTC2) { 202662306a36Sopenharmony_ci save_crtc2_gen_cntl = INREG(CRTC2_GEN_CNTL); 202762306a36Sopenharmony_ci OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl | CRTC2_DISP_REQ_EN_B); 202862306a36Sopenharmony_ci } 202962306a36Sopenharmony_ci save_crtc_gen_cntl = INREG(CRTC_GEN_CNTL); 203062306a36Sopenharmony_ci save_crtc_ext_cntl = INREG(CRTC_EXT_CNTL); 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl | CRTC_DISPLAY_DIS); 203362306a36Sopenharmony_ci OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl | CRTC_DISP_REQ_EN_B); 203462306a36Sopenharmony_ci mdelay(100); 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci aper_base = INREG(CNFG_APER_0_BASE); 203762306a36Sopenharmony_ci aper_size = INREG(CNFG_APER_SIZE); 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci#ifdef SET_MC_FB_FROM_APERTURE 204062306a36Sopenharmony_ci /* Set framebuffer to be at the same address as set in PCI BAR */ 204162306a36Sopenharmony_ci OUTREG(MC_FB_LOCATION, 204262306a36Sopenharmony_ci ((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16)); 204362306a36Sopenharmony_ci rinfo->fb_local_base = aper_base; 204462306a36Sopenharmony_ci#else 204562306a36Sopenharmony_ci OUTREG(MC_FB_LOCATION, 0x7fff0000); 204662306a36Sopenharmony_ci rinfo->fb_local_base = 0; 204762306a36Sopenharmony_ci#endif 204862306a36Sopenharmony_ci agp_base = aper_base + aper_size; 204962306a36Sopenharmony_ci if (agp_base & 0xf0000000) 205062306a36Sopenharmony_ci agp_base = (aper_base | 0x0fffffff) + 1; 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci /* Set AGP to be just after the framebuffer on a 256Mb boundary. This 205362306a36Sopenharmony_ci * assumes the FB isn't mapped to 0xf0000000 or above, but this is 205462306a36Sopenharmony_ci * always the case on PPCs afaik. 205562306a36Sopenharmony_ci */ 205662306a36Sopenharmony_ci#ifdef SET_MC_FB_FROM_APERTURE 205762306a36Sopenharmony_ci OUTREG(MC_AGP_LOCATION, 0xffff0000 | (agp_base >> 16)); 205862306a36Sopenharmony_ci#else 205962306a36Sopenharmony_ci OUTREG(MC_AGP_LOCATION, 0xffffe000); 206062306a36Sopenharmony_ci#endif 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci /* Fixup the display base addresses & engine offsets while we 206362306a36Sopenharmony_ci * are at it as well 206462306a36Sopenharmony_ci */ 206562306a36Sopenharmony_ci#ifdef SET_MC_FB_FROM_APERTURE 206662306a36Sopenharmony_ci OUTREG(DISPLAY_BASE_ADDR, aper_base); 206762306a36Sopenharmony_ci if (rinfo->has_CRTC2) 206862306a36Sopenharmony_ci OUTREG(CRTC2_DISPLAY_BASE_ADDR, aper_base); 206962306a36Sopenharmony_ci OUTREG(OV0_BASE_ADDR, aper_base); 207062306a36Sopenharmony_ci#else 207162306a36Sopenharmony_ci OUTREG(DISPLAY_BASE_ADDR, 0); 207262306a36Sopenharmony_ci if (rinfo->has_CRTC2) 207362306a36Sopenharmony_ci OUTREG(CRTC2_DISPLAY_BASE_ADDR, 0); 207462306a36Sopenharmony_ci OUTREG(OV0_BASE_ADDR, 0); 207562306a36Sopenharmony_ci#endif 207662306a36Sopenharmony_ci mdelay(100); 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci /* Restore display settings */ 207962306a36Sopenharmony_ci OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl); 208062306a36Sopenharmony_ci OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl); 208162306a36Sopenharmony_ci if (rinfo->has_CRTC2) 208262306a36Sopenharmony_ci OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl); 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci pr_debug("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n", 208562306a36Sopenharmony_ci aper_base, 208662306a36Sopenharmony_ci ((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16), 208762306a36Sopenharmony_ci 0xffff0000 | (agp_base >> 16)); 208862306a36Sopenharmony_ci} 208962306a36Sopenharmony_ci#endif /* CONFIG_PPC */ 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_cistatic void radeon_identify_vram(struct radeonfb_info *rinfo) 209362306a36Sopenharmony_ci{ 209462306a36Sopenharmony_ci u32 tmp; 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci /* framebuffer size */ 209762306a36Sopenharmony_ci if ((rinfo->family == CHIP_FAMILY_RS100) || 209862306a36Sopenharmony_ci (rinfo->family == CHIP_FAMILY_RS200) || 209962306a36Sopenharmony_ci (rinfo->family == CHIP_FAMILY_RS300) || 210062306a36Sopenharmony_ci (rinfo->family == CHIP_FAMILY_RC410) || 210162306a36Sopenharmony_ci (rinfo->family == CHIP_FAMILY_RS400) || 210262306a36Sopenharmony_ci (rinfo->family == CHIP_FAMILY_RS480) ) { 210362306a36Sopenharmony_ci u32 tom = INREG(NB_TOM); 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024); 210662306a36Sopenharmony_ci radeon_fifo_wait(6); 210762306a36Sopenharmony_ci OUTREG(MC_FB_LOCATION, tom); 210862306a36Sopenharmony_ci OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16); 210962306a36Sopenharmony_ci OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16); 211062306a36Sopenharmony_ci OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16); 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci /* This is supposed to fix the crtc2 noise problem. */ 211362306a36Sopenharmony_ci OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000); 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci if ((rinfo->family == CHIP_FAMILY_RS100) || 211662306a36Sopenharmony_ci (rinfo->family == CHIP_FAMILY_RS200)) { 211762306a36Sopenharmony_ci /* This is to workaround the asic bug for RMX, some versions 211862306a36Sopenharmony_ci * of BIOS doesn't have this register initialized correctly. 211962306a36Sopenharmony_ci */ 212062306a36Sopenharmony_ci OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN, 212162306a36Sopenharmony_ci ~CRTC_H_CUTOFF_ACTIVE_EN); 212262306a36Sopenharmony_ci } 212362306a36Sopenharmony_ci } else { 212462306a36Sopenharmony_ci tmp = INREG(CNFG_MEMSIZE); 212562306a36Sopenharmony_ci } 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci /* mem size is bits [28:0], mask off the rest */ 212862306a36Sopenharmony_ci rinfo->video_ram = tmp & CNFG_MEMSIZE_MASK; 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci /* 213162306a36Sopenharmony_ci * Hack to get around some busted production M6's 213262306a36Sopenharmony_ci * reporting no ram 213362306a36Sopenharmony_ci */ 213462306a36Sopenharmony_ci if (rinfo->video_ram == 0) { 213562306a36Sopenharmony_ci switch (rinfo->pdev->device) { 213662306a36Sopenharmony_ci case PCI_CHIP_RADEON_LY: 213762306a36Sopenharmony_ci case PCI_CHIP_RADEON_LZ: 213862306a36Sopenharmony_ci rinfo->video_ram = 8192 * 1024; 213962306a36Sopenharmony_ci break; 214062306a36Sopenharmony_ci default: 214162306a36Sopenharmony_ci break; 214262306a36Sopenharmony_ci } 214362306a36Sopenharmony_ci } 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci /* 214762306a36Sopenharmony_ci * Now try to identify VRAM type 214862306a36Sopenharmony_ci */ 214962306a36Sopenharmony_ci if (rinfo->is_IGP || (rinfo->family >= CHIP_FAMILY_R300) || 215062306a36Sopenharmony_ci (INREG(MEM_SDRAM_MODE_REG) & (1<<30))) 215162306a36Sopenharmony_ci rinfo->vram_ddr = 1; 215262306a36Sopenharmony_ci else 215362306a36Sopenharmony_ci rinfo->vram_ddr = 0; 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci tmp = INREG(MEM_CNTL); 215662306a36Sopenharmony_ci if (IS_R300_VARIANT(rinfo)) { 215762306a36Sopenharmony_ci tmp &= R300_MEM_NUM_CHANNELS_MASK; 215862306a36Sopenharmony_ci switch (tmp) { 215962306a36Sopenharmony_ci case 0: rinfo->vram_width = 64; break; 216062306a36Sopenharmony_ci case 1: rinfo->vram_width = 128; break; 216162306a36Sopenharmony_ci case 2: rinfo->vram_width = 256; break; 216262306a36Sopenharmony_ci default: rinfo->vram_width = 128; break; 216362306a36Sopenharmony_ci } 216462306a36Sopenharmony_ci } else if ((rinfo->family == CHIP_FAMILY_RV100) || 216562306a36Sopenharmony_ci (rinfo->family == CHIP_FAMILY_RS100) || 216662306a36Sopenharmony_ci (rinfo->family == CHIP_FAMILY_RS200)){ 216762306a36Sopenharmony_ci if (tmp & RV100_MEM_HALF_MODE) 216862306a36Sopenharmony_ci rinfo->vram_width = 32; 216962306a36Sopenharmony_ci else 217062306a36Sopenharmony_ci rinfo->vram_width = 64; 217162306a36Sopenharmony_ci } else { 217262306a36Sopenharmony_ci if (tmp & MEM_NUM_CHANNELS_MASK) 217362306a36Sopenharmony_ci rinfo->vram_width = 128; 217462306a36Sopenharmony_ci else 217562306a36Sopenharmony_ci rinfo->vram_width = 64; 217662306a36Sopenharmony_ci } 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci /* This may not be correct, as some cards can have half of channel disabled 217962306a36Sopenharmony_ci * ToDo: identify these cases 218062306a36Sopenharmony_ci */ 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci pr_debug("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n", 218362306a36Sopenharmony_ci pci_name(rinfo->pdev), 218462306a36Sopenharmony_ci rinfo->video_ram / 1024, 218562306a36Sopenharmony_ci rinfo->vram_ddr ? "DDR" : "SDRAM", 218662306a36Sopenharmony_ci rinfo->vram_width); 218762306a36Sopenharmony_ci} 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci/* 219062306a36Sopenharmony_ci * Sysfs 219162306a36Sopenharmony_ci */ 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_cistatic ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u8 *edid) 219462306a36Sopenharmony_ci{ 219562306a36Sopenharmony_ci return memory_read_from_buffer(buf, count, &off, edid, EDID_LENGTH); 219662306a36Sopenharmony_ci} 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_cistatic ssize_t radeon_show_edid1(struct file *filp, struct kobject *kobj, 220062306a36Sopenharmony_ci struct bin_attribute *bin_attr, 220162306a36Sopenharmony_ci char *buf, loff_t off, size_t count) 220262306a36Sopenharmony_ci{ 220362306a36Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 220462306a36Sopenharmony_ci struct fb_info *info = dev_get_drvdata(dev); 220562306a36Sopenharmony_ci struct radeonfb_info *rinfo = info->par; 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci return radeon_show_one_edid(buf, off, count, rinfo->mon1_EDID); 220862306a36Sopenharmony_ci} 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_cistatic ssize_t radeon_show_edid2(struct file *filp, struct kobject *kobj, 221262306a36Sopenharmony_ci struct bin_attribute *bin_attr, 221362306a36Sopenharmony_ci char *buf, loff_t off, size_t count) 221462306a36Sopenharmony_ci{ 221562306a36Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 221662306a36Sopenharmony_ci struct fb_info *info = dev_get_drvdata(dev); 221762306a36Sopenharmony_ci struct radeonfb_info *rinfo = info->par; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci return radeon_show_one_edid(buf, off, count, rinfo->mon2_EDID); 222062306a36Sopenharmony_ci} 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_cistatic const struct bin_attribute edid1_attr = { 222362306a36Sopenharmony_ci .attr = { 222462306a36Sopenharmony_ci .name = "edid1", 222562306a36Sopenharmony_ci .mode = 0444, 222662306a36Sopenharmony_ci }, 222762306a36Sopenharmony_ci .size = EDID_LENGTH, 222862306a36Sopenharmony_ci .read = radeon_show_edid1, 222962306a36Sopenharmony_ci}; 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_cistatic const struct bin_attribute edid2_attr = { 223262306a36Sopenharmony_ci .attr = { 223362306a36Sopenharmony_ci .name = "edid2", 223462306a36Sopenharmony_ci .mode = 0444, 223562306a36Sopenharmony_ci }, 223662306a36Sopenharmony_ci .size = EDID_LENGTH, 223762306a36Sopenharmony_ci .read = radeon_show_edid2, 223862306a36Sopenharmony_ci}; 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_cistatic int radeonfb_pci_register(struct pci_dev *pdev, 224162306a36Sopenharmony_ci const struct pci_device_id *ent) 224262306a36Sopenharmony_ci{ 224362306a36Sopenharmony_ci struct fb_info *info; 224462306a36Sopenharmony_ci struct radeonfb_info *rinfo; 224562306a36Sopenharmony_ci int ret; 224662306a36Sopenharmony_ci unsigned char c1, c2; 224762306a36Sopenharmony_ci int err = 0; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci pr_debug("radeonfb_pci_register BEGIN\n"); 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci /* Enable device in PCI config */ 225262306a36Sopenharmony_ci ret = pci_enable_device(pdev); 225362306a36Sopenharmony_ci if (ret < 0) { 225462306a36Sopenharmony_ci printk(KERN_ERR "radeonfb (%s): Cannot enable PCI device\n", 225562306a36Sopenharmony_ci pci_name(pdev)); 225662306a36Sopenharmony_ci goto err_out; 225762306a36Sopenharmony_ci } 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci info = framebuffer_alloc(sizeof(struct radeonfb_info), &pdev->dev); 226062306a36Sopenharmony_ci if (!info) { 226162306a36Sopenharmony_ci ret = -ENOMEM; 226262306a36Sopenharmony_ci goto err_disable; 226362306a36Sopenharmony_ci } 226462306a36Sopenharmony_ci rinfo = info->par; 226562306a36Sopenharmony_ci rinfo->info = info; 226662306a36Sopenharmony_ci rinfo->pdev = pdev; 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci spin_lock_init(&rinfo->reg_lock); 226962306a36Sopenharmony_ci timer_setup(&rinfo->lvds_timer, radeon_lvds_timer_func, 0); 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci c1 = ent->device >> 8; 227262306a36Sopenharmony_ci c2 = ent->device & 0xff; 227362306a36Sopenharmony_ci if (isprint(c1) && isprint(c2)) 227462306a36Sopenharmony_ci snprintf(rinfo->name, sizeof(rinfo->name), 227562306a36Sopenharmony_ci "ATI Radeon %x \"%c%c\"", ent->device & 0xffff, c1, c2); 227662306a36Sopenharmony_ci else 227762306a36Sopenharmony_ci snprintf(rinfo->name, sizeof(rinfo->name), 227862306a36Sopenharmony_ci "ATI Radeon %x", ent->device & 0xffff); 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci rinfo->family = ent->driver_data & CHIP_FAMILY_MASK; 228162306a36Sopenharmony_ci rinfo->chipset = pdev->device; 228262306a36Sopenharmony_ci rinfo->has_CRTC2 = (ent->driver_data & CHIP_HAS_CRTC2) != 0; 228362306a36Sopenharmony_ci rinfo->is_mobility = (ent->driver_data & CHIP_IS_MOBILITY) != 0; 228462306a36Sopenharmony_ci rinfo->is_IGP = (ent->driver_data & CHIP_IS_IGP) != 0; 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci /* Set base addrs */ 228762306a36Sopenharmony_ci rinfo->fb_base_phys = pci_resource_start (pdev, 0); 228862306a36Sopenharmony_ci rinfo->mmio_base_phys = pci_resource_start (pdev, 2); 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_ci ret = aperture_remove_conflicting_pci_devices(pdev, KBUILD_MODNAME); 229162306a36Sopenharmony_ci if (ret) 229262306a36Sopenharmony_ci goto err_release_fb; 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci /* request the mem regions */ 229562306a36Sopenharmony_ci ret = pci_request_region(pdev, 0, "radeonfb framebuffer"); 229662306a36Sopenharmony_ci if (ret < 0) { 229762306a36Sopenharmony_ci printk( KERN_ERR "radeonfb (%s): cannot request region 0.\n", 229862306a36Sopenharmony_ci pci_name(rinfo->pdev)); 229962306a36Sopenharmony_ci goto err_release_fb; 230062306a36Sopenharmony_ci } 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci ret = pci_request_region(pdev, 2, "radeonfb mmio"); 230362306a36Sopenharmony_ci if (ret < 0) { 230462306a36Sopenharmony_ci printk( KERN_ERR "radeonfb (%s): cannot request region 2.\n", 230562306a36Sopenharmony_ci pci_name(rinfo->pdev)); 230662306a36Sopenharmony_ci goto err_release_pci0; 230762306a36Sopenharmony_ci } 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci /* map the regions */ 231062306a36Sopenharmony_ci rinfo->mmio_base = ioremap(rinfo->mmio_base_phys, RADEON_REGSIZE); 231162306a36Sopenharmony_ci if (!rinfo->mmio_base) { 231262306a36Sopenharmony_ci printk(KERN_ERR "radeonfb (%s): cannot map MMIO\n", 231362306a36Sopenharmony_ci pci_name(rinfo->pdev)); 231462306a36Sopenharmony_ci ret = -EIO; 231562306a36Sopenharmony_ci goto err_release_pci2; 231662306a36Sopenharmony_ci } 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16; 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci /* 232162306a36Sopenharmony_ci * Check for errata 232262306a36Sopenharmony_ci */ 232362306a36Sopenharmony_ci rinfo->errata = 0; 232462306a36Sopenharmony_ci if (rinfo->family == CHIP_FAMILY_R300 && 232562306a36Sopenharmony_ci (INREG(CNFG_CNTL) & CFG_ATI_REV_ID_MASK) 232662306a36Sopenharmony_ci == CFG_ATI_REV_A11) 232762306a36Sopenharmony_ci rinfo->errata |= CHIP_ERRATA_R300_CG; 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci if (rinfo->family == CHIP_FAMILY_RV200 || 233062306a36Sopenharmony_ci rinfo->family == CHIP_FAMILY_RS200) 233162306a36Sopenharmony_ci rinfo->errata |= CHIP_ERRATA_PLL_DUMMYREADS; 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_ci if (rinfo->family == CHIP_FAMILY_RV100 || 233462306a36Sopenharmony_ci rinfo->family == CHIP_FAMILY_RS100 || 233562306a36Sopenharmony_ci rinfo->family == CHIP_FAMILY_RS200) 233662306a36Sopenharmony_ci rinfo->errata |= CHIP_ERRATA_PLL_DELAY; 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_ci#if defined(CONFIG_PPC) || defined(CONFIG_SPARC) 233962306a36Sopenharmony_ci /* On PPC, we obtain the OF device-node pointer to the firmware 234062306a36Sopenharmony_ci * data for this chip 234162306a36Sopenharmony_ci */ 234262306a36Sopenharmony_ci rinfo->of_node = pci_device_to_OF_node(pdev); 234362306a36Sopenharmony_ci if (rinfo->of_node == NULL) 234462306a36Sopenharmony_ci printk(KERN_WARNING "radeonfb (%s): Cannot match card to OF node !\n", 234562306a36Sopenharmony_ci pci_name(rinfo->pdev)); 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci#endif /* CONFIG_PPC || CONFIG_SPARC */ 234862306a36Sopenharmony_ci#ifdef CONFIG_PPC 234962306a36Sopenharmony_ci /* On PPC, the firmware sets up a memory mapping that tends 235062306a36Sopenharmony_ci * to cause lockups when enabling the engine. We reconfigure 235162306a36Sopenharmony_ci * the card internal memory mappings properly 235262306a36Sopenharmony_ci */ 235362306a36Sopenharmony_ci fixup_memory_mappings(rinfo); 235462306a36Sopenharmony_ci#endif /* CONFIG_PPC */ 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci /* Get VRAM size and type */ 235762306a36Sopenharmony_ci radeon_identify_vram(rinfo); 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci rinfo->mapped_vram = min_t(unsigned long, MAX_MAPPED_VRAM, rinfo->video_ram); 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci do { 236262306a36Sopenharmony_ci rinfo->fb_base = ioremap_wc(rinfo->fb_base_phys, 236362306a36Sopenharmony_ci rinfo->mapped_vram); 236462306a36Sopenharmony_ci } while (rinfo->fb_base == NULL && 236562306a36Sopenharmony_ci ((rinfo->mapped_vram /= 2) >= MIN_MAPPED_VRAM)); 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci if (rinfo->fb_base == NULL) { 236862306a36Sopenharmony_ci printk (KERN_ERR "radeonfb (%s): cannot map FB\n", 236962306a36Sopenharmony_ci pci_name(rinfo->pdev)); 237062306a36Sopenharmony_ci ret = -EIO; 237162306a36Sopenharmony_ci goto err_unmap_rom; 237262306a36Sopenharmony_ci } 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci pr_debug("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev), 237562306a36Sopenharmony_ci rinfo->mapped_vram/1024); 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci /* 237862306a36Sopenharmony_ci * Map the BIOS ROM if any and retrieve PLL parameters from 237962306a36Sopenharmony_ci * the BIOS. We skip that on mobility chips as the real panel 238062306a36Sopenharmony_ci * values we need aren't in the ROM but in the BIOS image in 238162306a36Sopenharmony_ci * memory. This is definitely not the best meacnism though, 238262306a36Sopenharmony_ci * we really need the arch code to tell us which is the "primary" 238362306a36Sopenharmony_ci * video adapter to use the memory image (or better, the arch 238462306a36Sopenharmony_ci * should provide us a copy of the BIOS image to shield us from 238562306a36Sopenharmony_ci * archs who would store that elsewhere and/or could initialize 238662306a36Sopenharmony_ci * more than one adapter during boot). 238762306a36Sopenharmony_ci */ 238862306a36Sopenharmony_ci if (!rinfo->is_mobility) 238962306a36Sopenharmony_ci radeon_map_ROM(rinfo, pdev); 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci /* 239262306a36Sopenharmony_ci * On x86, the primary display on laptop may have it's BIOS 239362306a36Sopenharmony_ci * ROM elsewhere, try to locate it at the legacy memory hole. 239462306a36Sopenharmony_ci * We probably need to make sure this is the primary display, 239562306a36Sopenharmony_ci * but that is difficult without some arch support. 239662306a36Sopenharmony_ci */ 239762306a36Sopenharmony_ci#ifdef CONFIG_X86 239862306a36Sopenharmony_ci if (rinfo->bios_seg == NULL) 239962306a36Sopenharmony_ci radeon_find_mem_vbios(rinfo); 240062306a36Sopenharmony_ci#endif 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci /* If both above failed, try the BIOS ROM again for mobility 240362306a36Sopenharmony_ci * chips 240462306a36Sopenharmony_ci */ 240562306a36Sopenharmony_ci if (rinfo->bios_seg == NULL && rinfo->is_mobility) 240662306a36Sopenharmony_ci radeon_map_ROM(rinfo, pdev); 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci /* Get informations about the board's PLL */ 240962306a36Sopenharmony_ci radeon_get_pllinfo(rinfo); 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci#ifdef CONFIG_FB_RADEON_I2C 241262306a36Sopenharmony_ci /* Register I2C bus */ 241362306a36Sopenharmony_ci radeon_create_i2c_busses(rinfo); 241462306a36Sopenharmony_ci#endif 241562306a36Sopenharmony_ci 241662306a36Sopenharmony_ci /* set all the vital stuff */ 241762306a36Sopenharmony_ci radeon_set_fbinfo (rinfo); 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci /* Probe screen types */ 242062306a36Sopenharmony_ci radeon_probe_screens(rinfo, monitor_layout, ignore_edid); 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci /* Build mode list, check out panel native model */ 242362306a36Sopenharmony_ci radeon_check_modes(rinfo, mode_option); 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci /* Register some sysfs stuff (should be done better) */ 242662306a36Sopenharmony_ci if (rinfo->mon1_EDID) 242762306a36Sopenharmony_ci err |= sysfs_create_bin_file(&rinfo->pdev->dev.kobj, 242862306a36Sopenharmony_ci &edid1_attr); 242962306a36Sopenharmony_ci if (rinfo->mon2_EDID) 243062306a36Sopenharmony_ci err |= sysfs_create_bin_file(&rinfo->pdev->dev.kobj, 243162306a36Sopenharmony_ci &edid2_attr); 243262306a36Sopenharmony_ci if (err) 243362306a36Sopenharmony_ci pr_warn("%s() Creating sysfs files failed, continuing\n", 243462306a36Sopenharmony_ci __func__); 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_ci /* save current mode regs before we switch into the new one 243762306a36Sopenharmony_ci * so we can restore this upon __exit 243862306a36Sopenharmony_ci */ 243962306a36Sopenharmony_ci radeon_save_state (rinfo, &rinfo->init_state); 244062306a36Sopenharmony_ci memcpy(&rinfo->state, &rinfo->init_state, sizeof(struct radeon_regs)); 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci /* Setup Power Management capabilities */ 244362306a36Sopenharmony_ci if (default_dynclk < -1) { 244462306a36Sopenharmony_ci /* -2 is special: means ON on mobility chips and do not 244562306a36Sopenharmony_ci * change on others 244662306a36Sopenharmony_ci */ 244762306a36Sopenharmony_ci radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1, ignore_devlist, force_sleep); 244862306a36Sopenharmony_ci } else 244962306a36Sopenharmony_ci radeonfb_pm_init(rinfo, default_dynclk, ignore_devlist, force_sleep); 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci pci_set_drvdata(pdev, info); 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci /* Register with fbdev layer */ 245462306a36Sopenharmony_ci ret = register_framebuffer(info); 245562306a36Sopenharmony_ci if (ret < 0) { 245662306a36Sopenharmony_ci printk (KERN_ERR "radeonfb (%s): could not register framebuffer\n", 245762306a36Sopenharmony_ci pci_name(rinfo->pdev)); 245862306a36Sopenharmony_ci goto err_unmap_fb; 245962306a36Sopenharmony_ci } 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci if (!nomtrr) 246262306a36Sopenharmony_ci rinfo->wc_cookie = arch_phys_wc_add(rinfo->fb_base_phys, 246362306a36Sopenharmony_ci rinfo->video_ram); 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci if (backlight) 246662306a36Sopenharmony_ci radeonfb_bl_init(rinfo); 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ci printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name); 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci if (rinfo->bios_seg) 247162306a36Sopenharmony_ci radeon_unmap_ROM(rinfo, pdev); 247262306a36Sopenharmony_ci pr_debug("radeonfb_pci_register END\n"); 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci return 0; 247562306a36Sopenharmony_cierr_unmap_fb: 247662306a36Sopenharmony_ci iounmap(rinfo->fb_base); 247762306a36Sopenharmony_cierr_unmap_rom: 247862306a36Sopenharmony_ci kfree(rinfo->mon1_EDID); 247962306a36Sopenharmony_ci kfree(rinfo->mon2_EDID); 248062306a36Sopenharmony_ci if (rinfo->mon1_modedb) 248162306a36Sopenharmony_ci fb_destroy_modedb(rinfo->mon1_modedb); 248262306a36Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 248362306a36Sopenharmony_ci#ifdef CONFIG_FB_RADEON_I2C 248462306a36Sopenharmony_ci radeon_delete_i2c_busses(rinfo); 248562306a36Sopenharmony_ci#endif 248662306a36Sopenharmony_ci if (rinfo->bios_seg) 248762306a36Sopenharmony_ci radeon_unmap_ROM(rinfo, pdev); 248862306a36Sopenharmony_ci iounmap(rinfo->mmio_base); 248962306a36Sopenharmony_cierr_release_pci2: 249062306a36Sopenharmony_ci pci_release_region(pdev, 2); 249162306a36Sopenharmony_cierr_release_pci0: 249262306a36Sopenharmony_ci pci_release_region(pdev, 0); 249362306a36Sopenharmony_cierr_release_fb: 249462306a36Sopenharmony_ci framebuffer_release(info); 249562306a36Sopenharmony_cierr_disable: 249662306a36Sopenharmony_cierr_out: 249762306a36Sopenharmony_ci return ret; 249862306a36Sopenharmony_ci} 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_cistatic void radeonfb_pci_unregister(struct pci_dev *pdev) 250362306a36Sopenharmony_ci{ 250462306a36Sopenharmony_ci struct fb_info *info = pci_get_drvdata(pdev); 250562306a36Sopenharmony_ci struct radeonfb_info *rinfo = info->par; 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci if (!rinfo) 250862306a36Sopenharmony_ci return; 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci radeonfb_pm_exit(rinfo); 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci if (rinfo->mon1_EDID) 251362306a36Sopenharmony_ci sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid1_attr); 251462306a36Sopenharmony_ci if (rinfo->mon2_EDID) 251562306a36Sopenharmony_ci sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid2_attr); 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci del_timer_sync(&rinfo->lvds_timer); 251862306a36Sopenharmony_ci arch_phys_wc_del(rinfo->wc_cookie); 251962306a36Sopenharmony_ci radeonfb_bl_exit(rinfo); 252062306a36Sopenharmony_ci unregister_framebuffer(info); 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci iounmap(rinfo->mmio_base); 252362306a36Sopenharmony_ci iounmap(rinfo->fb_base); 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ci pci_release_region(pdev, 2); 252662306a36Sopenharmony_ci pci_release_region(pdev, 0); 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci kfree(rinfo->mon1_EDID); 252962306a36Sopenharmony_ci kfree(rinfo->mon2_EDID); 253062306a36Sopenharmony_ci if (rinfo->mon1_modedb) 253162306a36Sopenharmony_ci fb_destroy_modedb(rinfo->mon1_modedb); 253262306a36Sopenharmony_ci#ifdef CONFIG_FB_RADEON_I2C 253362306a36Sopenharmony_ci radeon_delete_i2c_busses(rinfo); 253462306a36Sopenharmony_ci#endif 253562306a36Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 253662306a36Sopenharmony_ci framebuffer_release(info); 253762306a36Sopenharmony_ci} 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci#ifdef CONFIG_PM 254062306a36Sopenharmony_ci#define RADEONFB_PCI_PM_OPS (&radeonfb_pci_pm_ops) 254162306a36Sopenharmony_ci#else 254262306a36Sopenharmony_ci#define RADEONFB_PCI_PM_OPS NULL 254362306a36Sopenharmony_ci#endif 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_cistatic struct pci_driver radeonfb_driver = { 254662306a36Sopenharmony_ci .name = "radeonfb", 254762306a36Sopenharmony_ci .id_table = radeonfb_pci_table, 254862306a36Sopenharmony_ci .probe = radeonfb_pci_register, 254962306a36Sopenharmony_ci .remove = radeonfb_pci_unregister, 255062306a36Sopenharmony_ci .driver.pm = RADEONFB_PCI_PM_OPS, 255162306a36Sopenharmony_ci}; 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci#ifndef MODULE 255462306a36Sopenharmony_cistatic int __init radeonfb_setup (char *options) 255562306a36Sopenharmony_ci{ 255662306a36Sopenharmony_ci char *this_opt; 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci if (!options || !*options) 255962306a36Sopenharmony_ci return 0; 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci while ((this_opt = strsep (&options, ",")) != NULL) { 256262306a36Sopenharmony_ci if (!*this_opt) 256362306a36Sopenharmony_ci continue; 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci if (!strncmp(this_opt, "noaccel", 7)) { 256662306a36Sopenharmony_ci noaccel = 1; 256762306a36Sopenharmony_ci } else if (!strncmp(this_opt, "mirror", 6)) { 256862306a36Sopenharmony_ci mirror = 1; 256962306a36Sopenharmony_ci } else if (!strncmp(this_opt, "force_dfp", 9)) { 257062306a36Sopenharmony_ci force_dfp = 1; 257162306a36Sopenharmony_ci } else if (!strncmp(this_opt, "panel_yres:", 11)) { 257262306a36Sopenharmony_ci panel_yres = simple_strtoul((this_opt+11), NULL, 0); 257362306a36Sopenharmony_ci } else if (!strncmp(this_opt, "backlight:", 10)) { 257462306a36Sopenharmony_ci backlight = simple_strtoul(this_opt+10, NULL, 0); 257562306a36Sopenharmony_ci } else if (!strncmp(this_opt, "nomtrr", 6)) { 257662306a36Sopenharmony_ci nomtrr = 1; 257762306a36Sopenharmony_ci } else if (!strncmp(this_opt, "nomodeset", 9)) { 257862306a36Sopenharmony_ci nomodeset = 1; 257962306a36Sopenharmony_ci } else if (!strncmp(this_opt, "force_measure_pll", 17)) { 258062306a36Sopenharmony_ci force_measure_pll = 1; 258162306a36Sopenharmony_ci } else if (!strncmp(this_opt, "ignore_edid", 11)) { 258262306a36Sopenharmony_ci ignore_edid = 1; 258362306a36Sopenharmony_ci#if defined(CONFIG_PM) && defined(CONFIG_X86) 258462306a36Sopenharmony_ci } else if (!strncmp(this_opt, "force_sleep", 11)) { 258562306a36Sopenharmony_ci force_sleep = 1; 258662306a36Sopenharmony_ci } else if (!strncmp(this_opt, "ignore_devlist", 14)) { 258762306a36Sopenharmony_ci ignore_devlist = 1; 258862306a36Sopenharmony_ci#endif 258962306a36Sopenharmony_ci } else 259062306a36Sopenharmony_ci mode_option = this_opt; 259162306a36Sopenharmony_ci } 259262306a36Sopenharmony_ci return 0; 259362306a36Sopenharmony_ci} 259462306a36Sopenharmony_ci#endif /* MODULE */ 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_cistatic int __init radeonfb_init (void) 259762306a36Sopenharmony_ci{ 259862306a36Sopenharmony_ci#ifndef MODULE 259962306a36Sopenharmony_ci char *option = NULL; 260062306a36Sopenharmony_ci#endif 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci if (fb_modesetting_disabled("radeonfb")) 260362306a36Sopenharmony_ci return -ENODEV; 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci#ifndef MODULE 260662306a36Sopenharmony_ci if (fb_get_options("radeonfb", &option)) 260762306a36Sopenharmony_ci return -ENODEV; 260862306a36Sopenharmony_ci radeonfb_setup(option); 260962306a36Sopenharmony_ci#endif 261062306a36Sopenharmony_ci return pci_register_driver (&radeonfb_driver); 261162306a36Sopenharmony_ci} 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_cistatic void __exit radeonfb_exit (void) 261562306a36Sopenharmony_ci{ 261662306a36Sopenharmony_ci pci_unregister_driver (&radeonfb_driver); 261762306a36Sopenharmony_ci} 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_cimodule_init(radeonfb_init); 262062306a36Sopenharmony_cimodule_exit(radeonfb_exit); 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ciMODULE_AUTHOR("Ani Joshi"); 262362306a36Sopenharmony_ciMODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset"); 262462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 262562306a36Sopenharmony_cimodule_param(noaccel, bool, 0); 262662306a36Sopenharmony_cimodule_param(default_dynclk, int, 0); 262762306a36Sopenharmony_ciMODULE_PARM_DESC(default_dynclk, "int: -2=enable on mobility only,-1=do not change,0=off,1=on"); 262862306a36Sopenharmony_ciMODULE_PARM_DESC(noaccel, "bool: disable acceleration"); 262962306a36Sopenharmony_cimodule_param(nomodeset, bool, 0); 263062306a36Sopenharmony_ciMODULE_PARM_DESC(nomodeset, "bool: disable actual setting of video mode"); 263162306a36Sopenharmony_cimodule_param(mirror, bool, 0); 263262306a36Sopenharmony_ciMODULE_PARM_DESC(mirror, "bool: mirror the display to both monitors"); 263362306a36Sopenharmony_cimodule_param(force_dfp, bool, 0); 263462306a36Sopenharmony_ciMODULE_PARM_DESC(force_dfp, "bool: force display to dfp"); 263562306a36Sopenharmony_cimodule_param(ignore_edid, bool, 0); 263662306a36Sopenharmony_ciMODULE_PARM_DESC(ignore_edid, "bool: Ignore EDID data when doing DDC probe"); 263762306a36Sopenharmony_cimodule_param(monitor_layout, charp, 0); 263862306a36Sopenharmony_ciMODULE_PARM_DESC(monitor_layout, "Specify monitor mapping (like XFree86)"); 263962306a36Sopenharmony_cimodule_param(force_measure_pll, bool, 0); 264062306a36Sopenharmony_ciMODULE_PARM_DESC(force_measure_pll, "Force measurement of PLL (debug)"); 264162306a36Sopenharmony_cimodule_param(nomtrr, bool, 0); 264262306a36Sopenharmony_ciMODULE_PARM_DESC(nomtrr, "bool: disable use of MTRR registers"); 264362306a36Sopenharmony_cimodule_param(panel_yres, int, 0); 264462306a36Sopenharmony_ciMODULE_PARM_DESC(panel_yres, "int: set panel yres"); 264562306a36Sopenharmony_cimodule_param(mode_option, charp, 0); 264662306a36Sopenharmony_ciMODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); 264762306a36Sopenharmony_ci#if defined(CONFIG_PM) && defined(CONFIG_X86) 264862306a36Sopenharmony_cimodule_param(force_sleep, bool, 0); 264962306a36Sopenharmony_ciMODULE_PARM_DESC(force_sleep, "bool: force D2 sleep mode on all hardware"); 265062306a36Sopenharmony_cimodule_param(ignore_devlist, bool, 0); 265162306a36Sopenharmony_ciMODULE_PARM_DESC(ignore_devlist, "bool: ignore workarounds for bugs in specific laptops"); 265262306a36Sopenharmony_ci#endif 2653