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