18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * ATI Frame Buffer Device Driver Core 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2004 Alex Kern <alex.kern@gmx.de> 58c2ecf20Sopenharmony_ci * Copyright (C) 1997-2001 Geert Uytterhoeven 68c2ecf20Sopenharmony_ci * Copyright (C) 1998 Bernd Harries 78c2ecf20Sopenharmony_ci * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This driver supports the following ATI graphics chips: 108c2ecf20Sopenharmony_ci * - ATI Mach64 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * To do: add support for 138c2ecf20Sopenharmony_ci * - ATI Rage128 (from aty128fb.c) 148c2ecf20Sopenharmony_ci * - ATI Radeon (from radeonfb.c) 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * This driver is partly based on the PowerMac console driver: 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Copyright (C) 1996 Paul Mackerras 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * and on the PowerMac ATI/mach64 display driver: 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Copyright (C) 1997 Michael AK Tesch 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * with work by Jon Howell 258c2ecf20Sopenharmony_ci * Harry AC Eaton 268c2ecf20Sopenharmony_ci * Anthony Tong <atong@uiuc.edu> 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * Generic LCD support written by Daniel Mantione, ported from 2.4.20 by Alex Kern 298c2ecf20Sopenharmony_ci * Many Thanks to Ville Syrjälä for patches and fixing nasting 16 bit color bug. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 328c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 338c2ecf20Sopenharmony_ci * more details. 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Many thanks to Nitya from ATI devrel for support and patience ! 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/****************************************************************************** 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci TODO: 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci - cursor support on all cards and all ramdacs. 438c2ecf20Sopenharmony_ci - cursor parameters controlable via ioctl()s. 448c2ecf20Sopenharmony_ci - guess PLL and MCLK based on the original PLL register values initialized 458c2ecf20Sopenharmony_ci by Open Firmware (if they are initialized). BIOS is done 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci (Anyone with Mac to help with this?) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci******************************************************************************/ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#include <linux/compat.h> 528c2ecf20Sopenharmony_ci#include <linux/module.h> 538c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 548c2ecf20Sopenharmony_ci#include <linux/kernel.h> 558c2ecf20Sopenharmony_ci#include <linux/errno.h> 568c2ecf20Sopenharmony_ci#include <linux/string.h> 578c2ecf20Sopenharmony_ci#include <linux/mm.h> 588c2ecf20Sopenharmony_ci#include <linux/slab.h> 598c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 608c2ecf20Sopenharmony_ci#include <linux/delay.h> 618c2ecf20Sopenharmony_ci#include <linux/compiler.h> 628c2ecf20Sopenharmony_ci#include <linux/console.h> 638c2ecf20Sopenharmony_ci#include <linux/fb.h> 648c2ecf20Sopenharmony_ci#include <linux/init.h> 658c2ecf20Sopenharmony_ci#include <linux/pci.h> 668c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 678c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 688c2ecf20Sopenharmony_ci#include <linux/wait.h> 698c2ecf20Sopenharmony_ci#include <linux/backlight.h> 708c2ecf20Sopenharmony_ci#include <linux/reboot.h> 718c2ecf20Sopenharmony_ci#include <linux/dmi.h> 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#include <asm/io.h> 748c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#include <video/mach64.h> 778c2ecf20Sopenharmony_ci#include "atyfb.h" 788c2ecf20Sopenharmony_ci#include "ati_ids.h" 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#ifdef __powerpc__ 818c2ecf20Sopenharmony_ci#include <asm/machdep.h> 828c2ecf20Sopenharmony_ci#include <asm/prom.h> 838c2ecf20Sopenharmony_ci#include "../macmodes.h" 848c2ecf20Sopenharmony_ci#endif 858c2ecf20Sopenharmony_ci#ifdef __sparc__ 868c2ecf20Sopenharmony_ci#include <asm/fbio.h> 878c2ecf20Sopenharmony_ci#include <asm/oplib.h> 888c2ecf20Sopenharmony_ci#include <asm/prom.h> 898c2ecf20Sopenharmony_ci#endif 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#ifdef CONFIG_ADB_PMU 928c2ecf20Sopenharmony_ci#include <linux/adb.h> 938c2ecf20Sopenharmony_ci#include <linux/pmu.h> 948c2ecf20Sopenharmony_ci#endif 958c2ecf20Sopenharmony_ci#ifdef CONFIG_BOOTX_TEXT 968c2ecf20Sopenharmony_ci#include <asm/btext.h> 978c2ecf20Sopenharmony_ci#endif 988c2ecf20Sopenharmony_ci#ifdef CONFIG_PMAC_BACKLIGHT 998c2ecf20Sopenharmony_ci#include <asm/backlight.h> 1008c2ecf20Sopenharmony_ci#endif 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* 1038c2ecf20Sopenharmony_ci * Debug flags. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci#undef DEBUG 1068c2ecf20Sopenharmony_ci/*#define DEBUG*/ 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */ 1098c2ecf20Sopenharmony_ci/* - must be large enough to catch all GUI-Regs */ 1108c2ecf20Sopenharmony_ci/* - must be aligned to a PAGE boundary */ 1118c2ecf20Sopenharmony_ci#define GUI_RESERVE (1 * PAGE_SIZE) 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* FIXME: remove the FAIL definition */ 1148c2ecf20Sopenharmony_ci#define FAIL(msg) do { \ 1158c2ecf20Sopenharmony_ci if (!(var->activate & FB_ACTIVATE_TEST)) \ 1168c2ecf20Sopenharmony_ci printk(KERN_CRIT "atyfb: " msg "\n"); \ 1178c2ecf20Sopenharmony_ci return -EINVAL; \ 1188c2ecf20Sopenharmony_ci} while (0) 1198c2ecf20Sopenharmony_ci#define FAIL_MAX(msg, x, _max_) do { \ 1208c2ecf20Sopenharmony_ci if (x > _max_) { \ 1218c2ecf20Sopenharmony_ci if (!(var->activate & FB_ACTIVATE_TEST)) \ 1228c2ecf20Sopenharmony_ci printk(KERN_CRIT "atyfb: " msg " %x(%x)\n", x, _max_); \ 1238c2ecf20Sopenharmony_ci return -EINVAL; \ 1248c2ecf20Sopenharmony_ci } \ 1258c2ecf20Sopenharmony_ci} while (0) 1268c2ecf20Sopenharmony_ci#ifdef DEBUG 1278c2ecf20Sopenharmony_ci#define DPRINTK(fmt, args...) printk(KERN_DEBUG "atyfb: " fmt, ## args) 1288c2ecf20Sopenharmony_ci#else 1298c2ecf20Sopenharmony_ci#define DPRINTK(fmt, args...) no_printk(fmt, ##args) 1308c2ecf20Sopenharmony_ci#endif 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci#define PRINTKI(fmt, args...) printk(KERN_INFO "atyfb: " fmt, ## args) 1338c2ecf20Sopenharmony_ci#define PRINTKE(fmt, args...) printk(KERN_ERR "atyfb: " fmt, ## args) 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci#if defined(CONFIG_PMAC_BACKLIGHT) || defined(CONFIG_FB_ATY_GENERIC_LCD) || \ 1368c2ecf20Sopenharmony_cidefined(CONFIG_FB_ATY_BACKLIGHT) 1378c2ecf20Sopenharmony_cistatic const u32 lt_lcd_regs[] = { 1388c2ecf20Sopenharmony_ci CNFG_PANEL_LG, 1398c2ecf20Sopenharmony_ci LCD_GEN_CNTL_LG, 1408c2ecf20Sopenharmony_ci DSTN_CONTROL_LG, 1418c2ecf20Sopenharmony_ci HFB_PITCH_ADDR_LG, 1428c2ecf20Sopenharmony_ci HORZ_STRETCHING_LG, 1438c2ecf20Sopenharmony_ci VERT_STRETCHING_LG, 1448c2ecf20Sopenharmony_ci 0, /* EXT_VERT_STRETCH */ 1458c2ecf20Sopenharmony_ci LT_GIO_LG, 1468c2ecf20Sopenharmony_ci POWER_MANAGEMENT_LG 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_civoid aty_st_lcd(int index, u32 val, const struct atyfb_par *par) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci if (M64_HAS(LT_LCD_REGS)) { 1528c2ecf20Sopenharmony_ci aty_st_le32(lt_lcd_regs[index], val, par); 1538c2ecf20Sopenharmony_ci } else { 1548c2ecf20Sopenharmony_ci unsigned long temp; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* write addr byte */ 1578c2ecf20Sopenharmony_ci temp = aty_ld_le32(LCD_INDEX, par); 1588c2ecf20Sopenharmony_ci aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par); 1598c2ecf20Sopenharmony_ci /* write the register value */ 1608c2ecf20Sopenharmony_ci aty_st_le32(LCD_DATA, val, par); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ciu32 aty_ld_lcd(int index, const struct atyfb_par *par) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci if (M64_HAS(LT_LCD_REGS)) { 1678c2ecf20Sopenharmony_ci return aty_ld_le32(lt_lcd_regs[index], par); 1688c2ecf20Sopenharmony_ci } else { 1698c2ecf20Sopenharmony_ci unsigned long temp; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* write addr byte */ 1728c2ecf20Sopenharmony_ci temp = aty_ld_le32(LCD_INDEX, par); 1738c2ecf20Sopenharmony_ci aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par); 1748c2ecf20Sopenharmony_ci /* read the register value */ 1758c2ecf20Sopenharmony_ci return aty_ld_le32(LCD_DATA, par); 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci#endif /* defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) */ 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GENERIC_LCD 1818c2ecf20Sopenharmony_ci/* 1828c2ecf20Sopenharmony_ci * ATIReduceRatio -- 1838c2ecf20Sopenharmony_ci * 1848c2ecf20Sopenharmony_ci * Reduce a fraction by factoring out the largest common divider of the 1858c2ecf20Sopenharmony_ci * fraction's numerator and denominator. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_cistatic void ATIReduceRatio(int *Numerator, int *Denominator) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci int Multiplier, Divider, Remainder; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci Multiplier = *Numerator; 1928c2ecf20Sopenharmony_ci Divider = *Denominator; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci while ((Remainder = Multiplier % Divider)) { 1958c2ecf20Sopenharmony_ci Multiplier = Divider; 1968c2ecf20Sopenharmony_ci Divider = Remainder; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci *Numerator /= Divider; 2008c2ecf20Sopenharmony_ci *Denominator /= Divider; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci#endif 2038c2ecf20Sopenharmony_ci/* 2048c2ecf20Sopenharmony_ci * The Hardware parameters for each card 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistruct pci_mmap_map { 2088c2ecf20Sopenharmony_ci unsigned long voff; 2098c2ecf20Sopenharmony_ci unsigned long poff; 2108c2ecf20Sopenharmony_ci unsigned long size; 2118c2ecf20Sopenharmony_ci unsigned long prot_flag; 2128c2ecf20Sopenharmony_ci unsigned long prot_mask; 2138c2ecf20Sopenharmony_ci}; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic const struct fb_fix_screeninfo atyfb_fix = { 2168c2ecf20Sopenharmony_ci .id = "ATY Mach64", 2178c2ecf20Sopenharmony_ci .type = FB_TYPE_PACKED_PIXELS, 2188c2ecf20Sopenharmony_ci .visual = FB_VISUAL_PSEUDOCOLOR, 2198c2ecf20Sopenharmony_ci .xpanstep = 8, 2208c2ecf20Sopenharmony_ci .ypanstep = 1, 2218c2ecf20Sopenharmony_ci}; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* 2248c2ecf20Sopenharmony_ci * Frame buffer device API 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic int atyfb_open(struct fb_info *info, int user); 2288c2ecf20Sopenharmony_cistatic int atyfb_release(struct fb_info *info, int user); 2298c2ecf20Sopenharmony_cistatic int atyfb_check_var(struct fb_var_screeninfo *var, 2308c2ecf20Sopenharmony_ci struct fb_info *info); 2318c2ecf20Sopenharmony_cistatic int atyfb_set_par(struct fb_info *info); 2328c2ecf20Sopenharmony_cistatic int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 2338c2ecf20Sopenharmony_ci u_int transp, struct fb_info *info); 2348c2ecf20Sopenharmony_cistatic int atyfb_pan_display(struct fb_var_screeninfo *var, 2358c2ecf20Sopenharmony_ci struct fb_info *info); 2368c2ecf20Sopenharmony_cistatic int atyfb_blank(int blank, struct fb_info *info); 2378c2ecf20Sopenharmony_cistatic int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg); 2388c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 2398c2ecf20Sopenharmony_cistatic int atyfb_compat_ioctl(struct fb_info *info, u_int cmd, u_long arg) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci return atyfb_ioctl(info, cmd, (u_long)compat_ptr(arg)); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci#endif 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci#ifdef __sparc__ 2468c2ecf20Sopenharmony_cistatic int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma); 2478c2ecf20Sopenharmony_ci#endif 2488c2ecf20Sopenharmony_cistatic int atyfb_sync(struct fb_info *info); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* 2518c2ecf20Sopenharmony_ci * Internal routines 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int aty_init(struct fb_info *info); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc); 2598c2ecf20Sopenharmony_cistatic int aty_var_to_crtc(const struct fb_info *info, 2608c2ecf20Sopenharmony_ci const struct fb_var_screeninfo *var, 2618c2ecf20Sopenharmony_ci struct crtc *crtc); 2628c2ecf20Sopenharmony_cistatic int aty_crtc_to_var(const struct crtc *crtc, 2638c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var); 2648c2ecf20Sopenharmony_cistatic void set_off_pitch(struct atyfb_par *par, const struct fb_info *info); 2658c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC 2668c2ecf20Sopenharmony_cistatic int read_aty_sense(const struct atyfb_par *par); 2678c2ecf20Sopenharmony_ci#endif 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(reboot_lock); 2708c2ecf20Sopenharmony_cistatic struct fb_info *reboot_info; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/* 2738c2ecf20Sopenharmony_ci * Interface used by the world 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic struct fb_var_screeninfo default_var = { 2778c2ecf20Sopenharmony_ci /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ 2788c2ecf20Sopenharmony_ci 640, 480, 640, 480, 0, 0, 8, 0, 2798c2ecf20Sopenharmony_ci {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 2808c2ecf20Sopenharmony_ci 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2, 2818c2ecf20Sopenharmony_ci 0, FB_VMODE_NONINTERLACED 2828c2ecf20Sopenharmony_ci}; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic const struct fb_videomode defmode = { 2858c2ecf20Sopenharmony_ci /* 640x480 @ 60 Hz, 31.5 kHz hsync */ 2868c2ecf20Sopenharmony_ci NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, 2878c2ecf20Sopenharmony_ci 0, FB_VMODE_NONINTERLACED 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic struct fb_ops atyfb_ops = { 2918c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2928c2ecf20Sopenharmony_ci .fb_open = atyfb_open, 2938c2ecf20Sopenharmony_ci .fb_release = atyfb_release, 2948c2ecf20Sopenharmony_ci .fb_check_var = atyfb_check_var, 2958c2ecf20Sopenharmony_ci .fb_set_par = atyfb_set_par, 2968c2ecf20Sopenharmony_ci .fb_setcolreg = atyfb_setcolreg, 2978c2ecf20Sopenharmony_ci .fb_pan_display = atyfb_pan_display, 2988c2ecf20Sopenharmony_ci .fb_blank = atyfb_blank, 2998c2ecf20Sopenharmony_ci .fb_ioctl = atyfb_ioctl, 3008c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 3018c2ecf20Sopenharmony_ci .fb_compat_ioctl = atyfb_compat_ioctl, 3028c2ecf20Sopenharmony_ci#endif 3038c2ecf20Sopenharmony_ci .fb_fillrect = atyfb_fillrect, 3048c2ecf20Sopenharmony_ci .fb_copyarea = atyfb_copyarea, 3058c2ecf20Sopenharmony_ci .fb_imageblit = atyfb_imageblit, 3068c2ecf20Sopenharmony_ci#ifdef __sparc__ 3078c2ecf20Sopenharmony_ci .fb_mmap = atyfb_mmap, 3088c2ecf20Sopenharmony_ci#endif 3098c2ecf20Sopenharmony_ci .fb_sync = atyfb_sync, 3108c2ecf20Sopenharmony_ci}; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic bool noaccel; 3138c2ecf20Sopenharmony_cistatic bool nomtrr; 3148c2ecf20Sopenharmony_cistatic int vram; 3158c2ecf20Sopenharmony_cistatic int pll; 3168c2ecf20Sopenharmony_cistatic int mclk; 3178c2ecf20Sopenharmony_cistatic int xclk; 3188c2ecf20Sopenharmony_cistatic int comp_sync = -1; 3198c2ecf20Sopenharmony_cistatic char *mode; 3208c2ecf20Sopenharmony_cistatic int backlight = IS_BUILTIN(CONFIG_PMAC_BACKLIGHT); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC 3238c2ecf20Sopenharmony_cistatic int default_vmode = VMODE_CHOOSE; 3248c2ecf20Sopenharmony_cistatic int default_cmode = CMODE_CHOOSE; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cimodule_param_named(vmode, default_vmode, int, 0); 3278c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vmode, "int: video mode for mac"); 3288c2ecf20Sopenharmony_cimodule_param_named(cmode, default_cmode, int, 0); 3298c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cmode, "int: color mode for mac"); 3308c2ecf20Sopenharmony_ci#endif 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci#ifdef CONFIG_ATARI 3338c2ecf20Sopenharmony_cistatic unsigned int mach64_count = 0; 3348c2ecf20Sopenharmony_cistatic unsigned long phys_vmembase[FB_MAX] = { 0, }; 3358c2ecf20Sopenharmony_cistatic unsigned long phys_size[FB_MAX] = { 0, }; 3368c2ecf20Sopenharmony_cistatic unsigned long phys_guiregbase[FB_MAX] = { 0, }; 3378c2ecf20Sopenharmony_ci#endif 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/* top -> down is an evolution of mach64 chipset, any corrections? */ 3408c2ecf20Sopenharmony_ci#define ATI_CHIP_88800GX (M64F_GX) 3418c2ecf20Sopenharmony_ci#define ATI_CHIP_88800CX (M64F_GX) 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci#define ATI_CHIP_264CT (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO) 3448c2ecf20Sopenharmony_ci#define ATI_CHIP_264ET (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO) 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci#define ATI_CHIP_264VT (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO) 3478c2ecf20Sopenharmony_ci#define ATI_CHIP_264GT (M64F_GT | M64F_INTEGRATED | M64F_MAGIC_FIFO | M64F_EXTRA_BRIGHT) 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci#define ATI_CHIP_264VTB (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP) 3508c2ecf20Sopenharmony_ci#define ATI_CHIP_264VT3 (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL) 3518c2ecf20Sopenharmony_ci#define ATI_CHIP_264VT4 (M64F_VT | M64F_INTEGRATED | M64F_GTB_DSP) 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/* FIXME what is this chip? */ 3548c2ecf20Sopenharmony_ci#define ATI_CHIP_264LT (M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP) 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci/* make sets shorter */ 3578c2ecf20Sopenharmony_ci#define ATI_MODERN_SET (M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_EXTRA_BRIGHT) 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci#define ATI_CHIP_264GTB (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL) 3608c2ecf20Sopenharmony_ci/*#define ATI_CHIP_264GTDVD ?*/ 3618c2ecf20Sopenharmony_ci#define ATI_CHIP_264LTG (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL) 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci#define ATI_CHIP_264GT2C (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE) 3648c2ecf20Sopenharmony_ci#define ATI_CHIP_264GTPRO (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D) 3658c2ecf20Sopenharmony_ci#define ATI_CHIP_264LTPRO (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D) 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci#define ATI_CHIP_264XL (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM) 3688c2ecf20Sopenharmony_ci#define ATI_CHIP_MOBILITY (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM | M64F_MOBIL_BUS) 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic struct { 3718c2ecf20Sopenharmony_ci u16 pci_id; 3728c2ecf20Sopenharmony_ci const char *name; 3738c2ecf20Sopenharmony_ci int pll, mclk, xclk, ecp_max; 3748c2ecf20Sopenharmony_ci u32 features; 3758c2ecf20Sopenharmony_ci} aty_chips[] = { 3768c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GX 3778c2ecf20Sopenharmony_ci /* Mach64 GX */ 3788c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GX, "ATI888GX00 (Mach64 GX)", 135, 50, 50, 0, ATI_CHIP_88800GX }, 3798c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64CX, "ATI888CX00 (Mach64 CX)", 135, 50, 50, 0, ATI_CHIP_88800CX }, 3808c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_GX */ 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_CT 3838c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64CT, "ATI264CT (Mach64 CT)", 135, 60, 60, 0, ATI_CHIP_264CT }, 3848c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64ET, "ATI264ET (Mach64 ET)", 135, 60, 60, 0, ATI_CHIP_264ET }, 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* FIXME what is this chip? */ 3878c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64LT, "ATI264LT (Mach64 LT)", 135, 63, 63, 0, ATI_CHIP_264LT }, 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64VT, "ATI264VT (Mach64 VT)", 170, 67, 67, 80, ATI_CHIP_264VT }, 3908c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GT, "3D RAGE (Mach64 GT)", 135, 63, 63, 80, ATI_CHIP_264GT }, 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64VU, "ATI264VT3 (Mach64 VU)", 200, 67, 67, 80, ATI_CHIP_264VT3 }, 3938c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GU, "3D RAGE II+ (Mach64 GU)", 200, 67, 67, 100, ATI_CHIP_264GTB }, 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64LG, "3D RAGE LT (Mach64 LG)", 230, 63, 63, 100, ATI_CHIP_264LTG | M64F_LT_LCD_REGS | M64F_G3_PB_1024x768 }, 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64VV, "ATI264VT4 (Mach64 VV)", 230, 83, 83, 100, ATI_CHIP_264VT4 }, 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GV, "3D RAGE IIC (Mach64 GV, PCI)", 230, 83, 83, 100, ATI_CHIP_264GT2C }, 4008c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GW, "3D RAGE IIC (Mach64 GW, AGP)", 230, 83, 83, 100, ATI_CHIP_264GT2C }, 4018c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GY, "3D RAGE IIC (Mach64 GY, PCI)", 230, 83, 83, 100, ATI_CHIP_264GT2C }, 4028c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GZ, "3D RAGE IIC (Mach64 GZ, AGP)", 230, 83, 83, 100, ATI_CHIP_264GT2C }, 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GB, "3D RAGE PRO (Mach64 GB, BGA, AGP)", 230, 100, 100, 125, ATI_CHIP_264GTPRO }, 4058c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GD, "3D RAGE PRO (Mach64 GD, BGA, AGP 1x)", 230, 100, 100, 125, ATI_CHIP_264GTPRO }, 4068c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GI, "3D RAGE PRO (Mach64 GI, BGA, PCI)", 230, 100, 100, 125, ATI_CHIP_264GTPRO | M64F_MAGIC_VRAM_SIZE }, 4078c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GP, "3D RAGE PRO (Mach64 GP, PQFP, PCI)", 230, 100, 100, 125, ATI_CHIP_264GTPRO }, 4088c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GQ, "3D RAGE PRO (Mach64 GQ, PQFP, PCI, limited 3D)", 230, 100, 100, 125, ATI_CHIP_264GTPRO }, 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64LB, "3D RAGE LT PRO (Mach64 LB, AGP)", 236, 75, 100, 135, ATI_CHIP_264LTPRO }, 4118c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64LD, "3D RAGE LT PRO (Mach64 LD, AGP)", 230, 100, 100, 135, ATI_CHIP_264LTPRO }, 4128c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64LI, "3D RAGE LT PRO (Mach64 LI, PCI)", 230, 100, 100, 135, ATI_CHIP_264LTPRO | M64F_G3_PB_1_1 | M64F_G3_PB_1024x768 }, 4138c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64LP, "3D RAGE LT PRO (Mach64 LP, PCI)", 230, 100, 100, 135, ATI_CHIP_264LTPRO | M64F_G3_PB_1024x768 }, 4148c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64LQ, "3D RAGE LT PRO (Mach64 LQ, PCI)", 230, 100, 100, 135, ATI_CHIP_264LTPRO }, 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GM, "3D RAGE XL (Mach64 GM, AGP 2x)", 230, 83, 63, 135, ATI_CHIP_264XL }, 4178c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GN, "3D RAGE XC (Mach64 GN, AGP 2x)", 230, 83, 63, 135, ATI_CHIP_264XL }, 4188c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GO, "3D RAGE XL (Mach64 GO, PCI-66)", 230, 83, 63, 135, ATI_CHIP_264XL }, 4198c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GL, "3D RAGE XC (Mach64 GL, PCI-66)", 230, 83, 63, 135, ATI_CHIP_264XL }, 4208c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GR, "3D RAGE XL (Mach64 GR, PCI-33)", 230, 83, 63, 135, ATI_CHIP_264XL | M64F_SDRAM_MAGIC_PLL }, 4218c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64GS, "3D RAGE XC (Mach64 GS, PCI-33)", 230, 83, 63, 135, ATI_CHIP_264XL }, 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64LM, "3D RAGE Mobility P/M (Mach64 LM, AGP 2x)", 230, 83, 125, 135, ATI_CHIP_MOBILITY }, 4248c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64LN, "3D RAGE Mobility L (Mach64 LN, AGP 2x)", 230, 83, 125, 135, ATI_CHIP_MOBILITY }, 4258c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64LR, "3D RAGE Mobility P/M (Mach64 LR, PCI)", 230, 83, 125, 135, ATI_CHIP_MOBILITY }, 4268c2ecf20Sopenharmony_ci { PCI_CHIP_MACH64LS, "3D RAGE Mobility L (Mach64 LS, PCI)", 230, 83, 125, 135, ATI_CHIP_MOBILITY }, 4278c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_CT */ 4288c2ecf20Sopenharmony_ci}; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci/* 4318c2ecf20Sopenharmony_ci * Last page of 8 MB (4 MB on ISA) aperture is MMIO, 4328c2ecf20Sopenharmony_ci * unless the auxiliary register aperture is used. 4338c2ecf20Sopenharmony_ci */ 4348c2ecf20Sopenharmony_cistatic void aty_fudge_framebuffer_len(struct fb_info *info) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (!par->aux_start && 4398c2ecf20Sopenharmony_ci (info->fix.smem_len == 0x800000 || 4408c2ecf20Sopenharmony_ci (par->bus_type == ISA && info->fix.smem_len == 0x400000))) 4418c2ecf20Sopenharmony_ci info->fix.smem_len -= GUI_RESERVE; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int correct_chipset(struct atyfb_par *par) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci u8 rev; 4478c2ecf20Sopenharmony_ci u16 type; 4488c2ecf20Sopenharmony_ci u32 chip_id; 4498c2ecf20Sopenharmony_ci const char *name; 4508c2ecf20Sopenharmony_ci int i; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci for (i = (int)ARRAY_SIZE(aty_chips) - 1; i >= 0; i--) 4538c2ecf20Sopenharmony_ci if (par->pci_id == aty_chips[i].pci_id) 4548c2ecf20Sopenharmony_ci break; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (i < 0) 4578c2ecf20Sopenharmony_ci return -ENODEV; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci name = aty_chips[i].name; 4608c2ecf20Sopenharmony_ci par->pll_limits.pll_max = aty_chips[i].pll; 4618c2ecf20Sopenharmony_ci par->pll_limits.mclk = aty_chips[i].mclk; 4628c2ecf20Sopenharmony_ci par->pll_limits.xclk = aty_chips[i].xclk; 4638c2ecf20Sopenharmony_ci par->pll_limits.ecp_max = aty_chips[i].ecp_max; 4648c2ecf20Sopenharmony_ci par->features = aty_chips[i].features; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci chip_id = aty_ld_le32(CNFG_CHIP_ID, par); 4678c2ecf20Sopenharmony_ci type = chip_id & CFG_CHIP_TYPE; 4688c2ecf20Sopenharmony_ci rev = (chip_id & CFG_CHIP_REV) >> 24; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci switch (par->pci_id) { 4718c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GX 4728c2ecf20Sopenharmony_ci case PCI_CHIP_MACH64GX: 4738c2ecf20Sopenharmony_ci if (type != 0x00d7) 4748c2ecf20Sopenharmony_ci return -ENODEV; 4758c2ecf20Sopenharmony_ci break; 4768c2ecf20Sopenharmony_ci case PCI_CHIP_MACH64CX: 4778c2ecf20Sopenharmony_ci if (type != 0x0057) 4788c2ecf20Sopenharmony_ci return -ENODEV; 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci#endif 4818c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_CT 4828c2ecf20Sopenharmony_ci case PCI_CHIP_MACH64VT: 4838c2ecf20Sopenharmony_ci switch (rev & 0x07) { 4848c2ecf20Sopenharmony_ci case 0x00: 4858c2ecf20Sopenharmony_ci switch (rev & 0xc0) { 4868c2ecf20Sopenharmony_ci case 0x00: 4878c2ecf20Sopenharmony_ci name = "ATI264VT (A3) (Mach64 VT)"; 4888c2ecf20Sopenharmony_ci par->pll_limits.pll_max = 170; 4898c2ecf20Sopenharmony_ci par->pll_limits.mclk = 67; 4908c2ecf20Sopenharmony_ci par->pll_limits.xclk = 67; 4918c2ecf20Sopenharmony_ci par->pll_limits.ecp_max = 80; 4928c2ecf20Sopenharmony_ci par->features = ATI_CHIP_264VT; 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci case 0x40: 4958c2ecf20Sopenharmony_ci name = "ATI264VT2 (A4) (Mach64 VT)"; 4968c2ecf20Sopenharmony_ci par->pll_limits.pll_max = 200; 4978c2ecf20Sopenharmony_ci par->pll_limits.mclk = 67; 4988c2ecf20Sopenharmony_ci par->pll_limits.xclk = 67; 4998c2ecf20Sopenharmony_ci par->pll_limits.ecp_max = 80; 5008c2ecf20Sopenharmony_ci par->features = ATI_CHIP_264VT | M64F_MAGIC_POSTDIV; 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci case 0x01: 5058c2ecf20Sopenharmony_ci name = "ATI264VT3 (B1) (Mach64 VT)"; 5068c2ecf20Sopenharmony_ci par->pll_limits.pll_max = 200; 5078c2ecf20Sopenharmony_ci par->pll_limits.mclk = 67; 5088c2ecf20Sopenharmony_ci par->pll_limits.xclk = 67; 5098c2ecf20Sopenharmony_ci par->pll_limits.ecp_max = 80; 5108c2ecf20Sopenharmony_ci par->features = ATI_CHIP_264VTB; 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci case 0x02: 5138c2ecf20Sopenharmony_ci name = "ATI264VT3 (B2) (Mach64 VT)"; 5148c2ecf20Sopenharmony_ci par->pll_limits.pll_max = 200; 5158c2ecf20Sopenharmony_ci par->pll_limits.mclk = 67; 5168c2ecf20Sopenharmony_ci par->pll_limits.xclk = 67; 5178c2ecf20Sopenharmony_ci par->pll_limits.ecp_max = 80; 5188c2ecf20Sopenharmony_ci par->features = ATI_CHIP_264VT3; 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci break; 5228c2ecf20Sopenharmony_ci case PCI_CHIP_MACH64GT: 5238c2ecf20Sopenharmony_ci switch (rev & 0x07) { 5248c2ecf20Sopenharmony_ci case 0x01: 5258c2ecf20Sopenharmony_ci name = "3D RAGE II (Mach64 GT)"; 5268c2ecf20Sopenharmony_ci par->pll_limits.pll_max = 170; 5278c2ecf20Sopenharmony_ci par->pll_limits.mclk = 67; 5288c2ecf20Sopenharmony_ci par->pll_limits.xclk = 67; 5298c2ecf20Sopenharmony_ci par->pll_limits.ecp_max = 80; 5308c2ecf20Sopenharmony_ci par->features = ATI_CHIP_264GTB; 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci case 0x02: 5338c2ecf20Sopenharmony_ci name = "3D RAGE II+ (Mach64 GT)"; 5348c2ecf20Sopenharmony_ci par->pll_limits.pll_max = 200; 5358c2ecf20Sopenharmony_ci par->pll_limits.mclk = 67; 5368c2ecf20Sopenharmony_ci par->pll_limits.xclk = 67; 5378c2ecf20Sopenharmony_ci par->pll_limits.ecp_max = 100; 5388c2ecf20Sopenharmony_ci par->features = ATI_CHIP_264GTB; 5398c2ecf20Sopenharmony_ci break; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci#endif 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci PRINTKI("%s [0x%04x rev 0x%02x]\n", name, type, rev); 5468c2ecf20Sopenharmony_ci return 0; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic char ram_dram[] __maybe_unused = "DRAM"; 5508c2ecf20Sopenharmony_cistatic char ram_resv[] __maybe_unused = "RESV"; 5518c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GX 5528c2ecf20Sopenharmony_cistatic char ram_vram[] = "VRAM"; 5538c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_GX */ 5548c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_CT 5558c2ecf20Sopenharmony_cistatic char ram_edo[] = "EDO"; 5568c2ecf20Sopenharmony_cistatic char ram_sdram[] = "SDRAM (1:1)"; 5578c2ecf20Sopenharmony_cistatic char ram_sgram[] = "SGRAM (1:1)"; 5588c2ecf20Sopenharmony_cistatic char ram_sdram32[] = "SDRAM (2:1) (32-bit)"; 5598c2ecf20Sopenharmony_cistatic char ram_wram[] = "WRAM"; 5608c2ecf20Sopenharmony_cistatic char ram_off[] = "OFF"; 5618c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_CT */ 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GX 5658c2ecf20Sopenharmony_cistatic char *aty_gx_ram[8] = { 5668c2ecf20Sopenharmony_ci ram_dram, ram_vram, ram_vram, ram_dram, 5678c2ecf20Sopenharmony_ci ram_dram, ram_vram, ram_vram, ram_resv 5688c2ecf20Sopenharmony_ci}; 5698c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_GX */ 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_CT 5728c2ecf20Sopenharmony_cistatic char *aty_ct_ram[8] = { 5738c2ecf20Sopenharmony_ci ram_off, ram_dram, ram_edo, ram_edo, 5748c2ecf20Sopenharmony_ci ram_sdram, ram_sgram, ram_wram, ram_resv 5758c2ecf20Sopenharmony_ci}; 5768c2ecf20Sopenharmony_cistatic char *aty_xl_ram[8] = { 5778c2ecf20Sopenharmony_ci ram_off, ram_dram, ram_edo, ram_edo, 5788c2ecf20Sopenharmony_ci ram_sdram, ram_sgram, ram_sdram32, ram_resv 5798c2ecf20Sopenharmony_ci}; 5808c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_CT */ 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic u32 atyfb_get_pixclock(struct fb_var_screeninfo *var, 5838c2ecf20Sopenharmony_ci struct atyfb_par *par) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci u32 pixclock = var->pixclock; 5868c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GENERIC_LCD 5878c2ecf20Sopenharmony_ci u32 lcd_on_off; 5888c2ecf20Sopenharmony_ci par->pll.ct.xres = 0; 5898c2ecf20Sopenharmony_ci if (par->lcd_table != 0) { 5908c2ecf20Sopenharmony_ci lcd_on_off = aty_ld_lcd(LCD_GEN_CNTL, par); 5918c2ecf20Sopenharmony_ci if (lcd_on_off & LCD_ON) { 5928c2ecf20Sopenharmony_ci par->pll.ct.xres = var->xres; 5938c2ecf20Sopenharmony_ci pixclock = par->lcd_pixclock; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci#endif 5978c2ecf20Sopenharmony_ci return pixclock; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci#if defined(CONFIG_PPC) 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci/* 6038c2ecf20Sopenharmony_ci * Apple monitor sense 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic int read_aty_sense(const struct atyfb_par *par) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci int sense, i; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci aty_st_le32(GP_IO, 0x31003100, par); /* drive outputs high */ 6118c2ecf20Sopenharmony_ci __delay(200); 6128c2ecf20Sopenharmony_ci aty_st_le32(GP_IO, 0, par); /* turn off outputs */ 6138c2ecf20Sopenharmony_ci __delay(2000); 6148c2ecf20Sopenharmony_ci i = aty_ld_le32(GP_IO, par); /* get primary sense value */ 6158c2ecf20Sopenharmony_ci sense = ((i & 0x3000) >> 3) | (i & 0x100); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* drive each sense line low in turn and collect the other 2 */ 6188c2ecf20Sopenharmony_ci aty_st_le32(GP_IO, 0x20000000, par); /* drive A low */ 6198c2ecf20Sopenharmony_ci __delay(2000); 6208c2ecf20Sopenharmony_ci i = aty_ld_le32(GP_IO, par); 6218c2ecf20Sopenharmony_ci sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4); 6228c2ecf20Sopenharmony_ci aty_st_le32(GP_IO, 0x20002000, par); /* drive A high again */ 6238c2ecf20Sopenharmony_ci __delay(200); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci aty_st_le32(GP_IO, 0x10000000, par); /* drive B low */ 6268c2ecf20Sopenharmony_ci __delay(2000); 6278c2ecf20Sopenharmony_ci i = aty_ld_le32(GP_IO, par); 6288c2ecf20Sopenharmony_ci sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6); 6298c2ecf20Sopenharmony_ci aty_st_le32(GP_IO, 0x10001000, par); /* drive B high again */ 6308c2ecf20Sopenharmony_ci __delay(200); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci aty_st_le32(GP_IO, 0x01000000, par); /* drive C low */ 6338c2ecf20Sopenharmony_ci __delay(2000); 6348c2ecf20Sopenharmony_ci sense |= (aty_ld_le32(GP_IO, par) & 0x3000) >> 12; 6358c2ecf20Sopenharmony_ci aty_st_le32(GP_IO, 0, par); /* turn off outputs */ 6368c2ecf20Sopenharmony_ci return sense; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci#endif /* defined(CONFIG_PPC) */ 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------- */ 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/* 6448c2ecf20Sopenharmony_ci * CRTC programming 6458c2ecf20Sopenharmony_ci */ 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GENERIC_LCD 6508c2ecf20Sopenharmony_ci if (par->lcd_table != 0) { 6518c2ecf20Sopenharmony_ci if (!M64_HAS(LT_LCD_REGS)) { 6528c2ecf20Sopenharmony_ci crtc->lcd_index = aty_ld_le32(LCD_INDEX, par); 6538c2ecf20Sopenharmony_ci aty_st_le32(LCD_INDEX, crtc->lcd_index, par); 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci crtc->lcd_config_panel = aty_ld_lcd(CNFG_PANEL, par); 6568c2ecf20Sopenharmony_ci crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* switch to non shadow registers */ 6608c2ecf20Sopenharmony_ci aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl & 6618c2ecf20Sopenharmony_ci ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* save stretching */ 6648c2ecf20Sopenharmony_ci crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par); 6658c2ecf20Sopenharmony_ci crtc->vert_stretching = aty_ld_lcd(VERT_STRETCHING, par); 6668c2ecf20Sopenharmony_ci if (!M64_HAS(LT_LCD_REGS)) 6678c2ecf20Sopenharmony_ci crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci#endif 6708c2ecf20Sopenharmony_ci crtc->h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par); 6718c2ecf20Sopenharmony_ci crtc->h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par); 6728c2ecf20Sopenharmony_ci crtc->v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par); 6738c2ecf20Sopenharmony_ci crtc->v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par); 6748c2ecf20Sopenharmony_ci crtc->vline_crnt_vline = aty_ld_le32(CRTC_VLINE_CRNT_VLINE, par); 6758c2ecf20Sopenharmony_ci crtc->off_pitch = aty_ld_le32(CRTC_OFF_PITCH, par); 6768c2ecf20Sopenharmony_ci crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GENERIC_LCD 6798c2ecf20Sopenharmony_ci if (par->lcd_table != 0) { 6808c2ecf20Sopenharmony_ci /* switch to shadow registers */ 6818c2ecf20Sopenharmony_ci aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) | 6828c2ecf20Sopenharmony_ci SHADOW_EN | SHADOW_RW_EN, par); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci crtc->shadow_h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par); 6858c2ecf20Sopenharmony_ci crtc->shadow_h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par); 6868c2ecf20Sopenharmony_ci crtc->shadow_v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par); 6878c2ecf20Sopenharmony_ci crtc->shadow_v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci aty_st_le32(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par); 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_GENERIC_LCD */ 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GENERIC_LCD 6978c2ecf20Sopenharmony_ci if (par->lcd_table != 0) { 6988c2ecf20Sopenharmony_ci /* stop CRTC */ 6998c2ecf20Sopenharmony_ci aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & 7008c2ecf20Sopenharmony_ci ~(CRTC_EXT_DISP_EN | CRTC_EN), par); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* update non-shadow registers first */ 7038c2ecf20Sopenharmony_ci aty_st_lcd(CNFG_PANEL, crtc->lcd_config_panel, par); 7048c2ecf20Sopenharmony_ci aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl & 7058c2ecf20Sopenharmony_ci ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* temporarily disable stretching */ 7088c2ecf20Sopenharmony_ci aty_st_lcd(HORZ_STRETCHING, crtc->horz_stretching & 7098c2ecf20Sopenharmony_ci ~(HORZ_STRETCH_MODE | HORZ_STRETCH_EN), par); 7108c2ecf20Sopenharmony_ci aty_st_lcd(VERT_STRETCHING, crtc->vert_stretching & 7118c2ecf20Sopenharmony_ci ~(VERT_STRETCH_RATIO1 | VERT_STRETCH_RATIO2 | 7128c2ecf20Sopenharmony_ci VERT_STRETCH_USE0 | VERT_STRETCH_EN), par); 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci#endif 7158c2ecf20Sopenharmony_ci /* turn off CRT */ 7168c2ecf20Sopenharmony_ci aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~CRTC_EN, par); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci DPRINTK("setting up CRTC\n"); 7198c2ecf20Sopenharmony_ci DPRINTK("set primary CRT to %ix%i %c%c composite %c\n", 7208c2ecf20Sopenharmony_ci ((((crtc->h_tot_disp >> 16) & 0xff) + 1) << 3), 7218c2ecf20Sopenharmony_ci (((crtc->v_tot_disp >> 16) & 0x7ff) + 1), 7228c2ecf20Sopenharmony_ci (crtc->h_sync_strt_wid & 0x200000) ? 'N' : 'P', 7238c2ecf20Sopenharmony_ci (crtc->v_sync_strt_wid & 0x200000) ? 'N' : 'P', 7248c2ecf20Sopenharmony_ci (crtc->gen_cntl & CRTC_CSYNC_EN) ? 'P' : 'N'); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci DPRINTK("CRTC_H_TOTAL_DISP: %x\n", crtc->h_tot_disp); 7278c2ecf20Sopenharmony_ci DPRINTK("CRTC_H_SYNC_STRT_WID: %x\n", crtc->h_sync_strt_wid); 7288c2ecf20Sopenharmony_ci DPRINTK("CRTC_V_TOTAL_DISP: %x\n", crtc->v_tot_disp); 7298c2ecf20Sopenharmony_ci DPRINTK("CRTC_V_SYNC_STRT_WID: %x\n", crtc->v_sync_strt_wid); 7308c2ecf20Sopenharmony_ci DPRINTK("CRTC_OFF_PITCH: %x\n", crtc->off_pitch); 7318c2ecf20Sopenharmony_ci DPRINTK("CRTC_VLINE_CRNT_VLINE: %x\n", crtc->vline_crnt_vline); 7328c2ecf20Sopenharmony_ci DPRINTK("CRTC_GEN_CNTL: %x\n", crtc->gen_cntl); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, par); 7358c2ecf20Sopenharmony_ci aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, par); 7368c2ecf20Sopenharmony_ci aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, par); 7378c2ecf20Sopenharmony_ci aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, par); 7388c2ecf20Sopenharmony_ci aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, par); 7398c2ecf20Sopenharmony_ci aty_st_le32(CRTC_VLINE_CRNT_VLINE, crtc->vline_crnt_vline, par); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, par); 7428c2ecf20Sopenharmony_ci#if 0 7438c2ecf20Sopenharmony_ci FIXME 7448c2ecf20Sopenharmony_ci if (par->accel_flags & FB_ACCELF_TEXT) 7458c2ecf20Sopenharmony_ci aty_init_engine(par, info); 7468c2ecf20Sopenharmony_ci#endif 7478c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GENERIC_LCD 7488c2ecf20Sopenharmony_ci /* after setting the CRTC registers we should set the LCD registers. */ 7498c2ecf20Sopenharmony_ci if (par->lcd_table != 0) { 7508c2ecf20Sopenharmony_ci /* switch to shadow registers */ 7518c2ecf20Sopenharmony_ci aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) | 7528c2ecf20Sopenharmony_ci SHADOW_EN | SHADOW_RW_EN, par); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci DPRINTK("set shadow CRT to %ix%i %c%c\n", 7558c2ecf20Sopenharmony_ci ((((crtc->shadow_h_tot_disp >> 16) & 0xff) + 1) << 3), 7568c2ecf20Sopenharmony_ci (((crtc->shadow_v_tot_disp >> 16) & 0x7ff) + 1), 7578c2ecf20Sopenharmony_ci (crtc->shadow_h_sync_strt_wid & 0x200000) ? 'N' : 'P', 7588c2ecf20Sopenharmony_ci (crtc->shadow_v_sync_strt_wid & 0x200000) ? 'N' : 'P'); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci DPRINTK("SHADOW CRTC_H_TOTAL_DISP: %x\n", 7618c2ecf20Sopenharmony_ci crtc->shadow_h_tot_disp); 7628c2ecf20Sopenharmony_ci DPRINTK("SHADOW CRTC_H_SYNC_STRT_WID: %x\n", 7638c2ecf20Sopenharmony_ci crtc->shadow_h_sync_strt_wid); 7648c2ecf20Sopenharmony_ci DPRINTK("SHADOW CRTC_V_TOTAL_DISP: %x\n", 7658c2ecf20Sopenharmony_ci crtc->shadow_v_tot_disp); 7668c2ecf20Sopenharmony_ci DPRINTK("SHADOW CRTC_V_SYNC_STRT_WID: %x\n", 7678c2ecf20Sopenharmony_ci crtc->shadow_v_sync_strt_wid); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci aty_st_le32(CRTC_H_TOTAL_DISP, crtc->shadow_h_tot_disp, par); 7708c2ecf20Sopenharmony_ci aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->shadow_h_sync_strt_wid, par); 7718c2ecf20Sopenharmony_ci aty_st_le32(CRTC_V_TOTAL_DISP, crtc->shadow_v_tot_disp, par); 7728c2ecf20Sopenharmony_ci aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->shadow_v_sync_strt_wid, par); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* restore CRTC selection & shadow state and enable stretching */ 7758c2ecf20Sopenharmony_ci DPRINTK("LCD_GEN_CNTL: %x\n", crtc->lcd_gen_cntl); 7768c2ecf20Sopenharmony_ci DPRINTK("HORZ_STRETCHING: %x\n", crtc->horz_stretching); 7778c2ecf20Sopenharmony_ci DPRINTK("VERT_STRETCHING: %x\n", crtc->vert_stretching); 7788c2ecf20Sopenharmony_ci if (!M64_HAS(LT_LCD_REGS)) 7798c2ecf20Sopenharmony_ci DPRINTK("EXT_VERT_STRETCH: %x\n", crtc->ext_vert_stretch); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par); 7828c2ecf20Sopenharmony_ci aty_st_lcd(HORZ_STRETCHING, crtc->horz_stretching, par); 7838c2ecf20Sopenharmony_ci aty_st_lcd(VERT_STRETCHING, crtc->vert_stretching, par); 7848c2ecf20Sopenharmony_ci if (!M64_HAS(LT_LCD_REGS)) { 7858c2ecf20Sopenharmony_ci aty_st_lcd(EXT_VERT_STRETCH, crtc->ext_vert_stretch, par); 7868c2ecf20Sopenharmony_ci aty_ld_le32(LCD_INDEX, par); 7878c2ecf20Sopenharmony_ci aty_st_le32(LCD_INDEX, crtc->lcd_index, par); 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_GENERIC_LCD */ 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic u32 calc_line_length(struct atyfb_par *par, u32 vxres, u32 bpp) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci u32 line_length = vxres * bpp / 8; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci if (par->ram_type == SGRAM || 7988c2ecf20Sopenharmony_ci (!M64_HAS(XL_MEM) && par->ram_type == WRAM)) 7998c2ecf20Sopenharmony_ci line_length = (line_length + 63) & ~63; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci return line_length; 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_cistatic int aty_var_to_crtc(const struct fb_info *info, 8058c2ecf20Sopenharmony_ci const struct fb_var_screeninfo *var, 8068c2ecf20Sopenharmony_ci struct crtc *crtc) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 8098c2ecf20Sopenharmony_ci u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; 8108c2ecf20Sopenharmony_ci u32 sync, vmode; 8118c2ecf20Sopenharmony_ci u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol; 8128c2ecf20Sopenharmony_ci u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync; 8138c2ecf20Sopenharmony_ci u32 pix_width, dp_pix_width, dp_chain_mask; 8148c2ecf20Sopenharmony_ci u32 line_length; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci /* input */ 8178c2ecf20Sopenharmony_ci xres = (var->xres + 7) & ~7; 8188c2ecf20Sopenharmony_ci yres = var->yres; 8198c2ecf20Sopenharmony_ci vxres = (var->xres_virtual + 7) & ~7; 8208c2ecf20Sopenharmony_ci vyres = var->yres_virtual; 8218c2ecf20Sopenharmony_ci xoffset = (var->xoffset + 7) & ~7; 8228c2ecf20Sopenharmony_ci yoffset = var->yoffset; 8238c2ecf20Sopenharmony_ci bpp = var->bits_per_pixel; 8248c2ecf20Sopenharmony_ci if (bpp == 16) 8258c2ecf20Sopenharmony_ci bpp = (var->green.length == 5) ? 15 : 16; 8268c2ecf20Sopenharmony_ci sync = var->sync; 8278c2ecf20Sopenharmony_ci vmode = var->vmode; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* convert (and round up) and validate */ 8308c2ecf20Sopenharmony_ci if (vxres < xres + xoffset) 8318c2ecf20Sopenharmony_ci vxres = xres + xoffset; 8328c2ecf20Sopenharmony_ci h_disp = xres; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (vyres < yres + yoffset) 8358c2ecf20Sopenharmony_ci vyres = yres + yoffset; 8368c2ecf20Sopenharmony_ci v_disp = yres; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (bpp <= 8) { 8398c2ecf20Sopenharmony_ci bpp = 8; 8408c2ecf20Sopenharmony_ci pix_width = CRTC_PIX_WIDTH_8BPP; 8418c2ecf20Sopenharmony_ci dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | 8428c2ecf20Sopenharmony_ci BYTE_ORDER_LSB_TO_MSB; 8438c2ecf20Sopenharmony_ci dp_chain_mask = DP_CHAIN_8BPP; 8448c2ecf20Sopenharmony_ci } else if (bpp <= 15) { 8458c2ecf20Sopenharmony_ci bpp = 16; 8468c2ecf20Sopenharmony_ci pix_width = CRTC_PIX_WIDTH_15BPP; 8478c2ecf20Sopenharmony_ci dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP | 8488c2ecf20Sopenharmony_ci BYTE_ORDER_LSB_TO_MSB; 8498c2ecf20Sopenharmony_ci dp_chain_mask = DP_CHAIN_15BPP; 8508c2ecf20Sopenharmony_ci } else if (bpp <= 16) { 8518c2ecf20Sopenharmony_ci bpp = 16; 8528c2ecf20Sopenharmony_ci pix_width = CRTC_PIX_WIDTH_16BPP; 8538c2ecf20Sopenharmony_ci dp_pix_width = HOST_16BPP | SRC_16BPP | DST_16BPP | 8548c2ecf20Sopenharmony_ci BYTE_ORDER_LSB_TO_MSB; 8558c2ecf20Sopenharmony_ci dp_chain_mask = DP_CHAIN_16BPP; 8568c2ecf20Sopenharmony_ci } else if (bpp <= 24 && M64_HAS(INTEGRATED)) { 8578c2ecf20Sopenharmony_ci bpp = 24; 8588c2ecf20Sopenharmony_ci pix_width = CRTC_PIX_WIDTH_24BPP; 8598c2ecf20Sopenharmony_ci dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | 8608c2ecf20Sopenharmony_ci BYTE_ORDER_LSB_TO_MSB; 8618c2ecf20Sopenharmony_ci dp_chain_mask = DP_CHAIN_24BPP; 8628c2ecf20Sopenharmony_ci } else if (bpp <= 32) { 8638c2ecf20Sopenharmony_ci bpp = 32; 8648c2ecf20Sopenharmony_ci pix_width = CRTC_PIX_WIDTH_32BPP; 8658c2ecf20Sopenharmony_ci dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP | 8668c2ecf20Sopenharmony_ci BYTE_ORDER_LSB_TO_MSB; 8678c2ecf20Sopenharmony_ci dp_chain_mask = DP_CHAIN_32BPP; 8688c2ecf20Sopenharmony_ci } else 8698c2ecf20Sopenharmony_ci FAIL("invalid bpp"); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci line_length = calc_line_length(par, vxres, bpp); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (vyres * line_length > info->fix.smem_len) 8748c2ecf20Sopenharmony_ci FAIL("not enough video RAM"); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; 8778c2ecf20Sopenharmony_ci v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if ((xres > 1920) || (yres > 1200)) { 8808c2ecf20Sopenharmony_ci FAIL("MACH64 chips are designed for max 1920x1200\n" 8818c2ecf20Sopenharmony_ci "select another resolution."); 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci h_sync_strt = h_disp + var->right_margin; 8848c2ecf20Sopenharmony_ci h_sync_end = h_sync_strt + var->hsync_len; 8858c2ecf20Sopenharmony_ci h_sync_dly = var->right_margin & 7; 8868c2ecf20Sopenharmony_ci h_total = h_sync_end + h_sync_dly + var->left_margin; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci v_sync_strt = v_disp + var->lower_margin; 8898c2ecf20Sopenharmony_ci v_sync_end = v_sync_strt + var->vsync_len; 8908c2ecf20Sopenharmony_ci v_total = v_sync_end + var->upper_margin; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GENERIC_LCD 8938c2ecf20Sopenharmony_ci if (par->lcd_table != 0) { 8948c2ecf20Sopenharmony_ci if (!M64_HAS(LT_LCD_REGS)) { 8958c2ecf20Sopenharmony_ci u32 lcd_index = aty_ld_le32(LCD_INDEX, par); 8968c2ecf20Sopenharmony_ci crtc->lcd_index = lcd_index & 8978c2ecf20Sopenharmony_ci ~(LCD_INDEX_MASK | LCD_DISPLAY_DIS | 8988c2ecf20Sopenharmony_ci LCD_SRC_SEL | CRTC2_DISPLAY_DIS); 8998c2ecf20Sopenharmony_ci aty_st_le32(LCD_INDEX, lcd_index, par); 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (!M64_HAS(MOBIL_BUS)) 9038c2ecf20Sopenharmony_ci crtc->lcd_index |= CRTC2_DISPLAY_DIS; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci crtc->lcd_config_panel = aty_ld_lcd(CNFG_PANEL, par) | 0x4000; 9068c2ecf20Sopenharmony_ci crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par) & ~CRTC_RW_SELECT; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci crtc->lcd_gen_cntl &= 9098c2ecf20Sopenharmony_ci ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | TVCLK_PM_EN | 9108c2ecf20Sopenharmony_ci /*VCLK_DAC_PM_EN | USE_SHADOWED_VEND |*/ 9118c2ecf20Sopenharmony_ci USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN); 9128c2ecf20Sopenharmony_ci crtc->lcd_gen_cntl |= DONT_SHADOW_VPAR | LOCK_8DOT; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if ((crtc->lcd_gen_cntl & LCD_ON) && 9158c2ecf20Sopenharmony_ci ((xres > par->lcd_width) || (yres > par->lcd_height))) { 9168c2ecf20Sopenharmony_ci /* 9178c2ecf20Sopenharmony_ci * We cannot display the mode on the LCD. If the CRT is 9188c2ecf20Sopenharmony_ci * enabled we can turn off the LCD. 9198c2ecf20Sopenharmony_ci * If the CRT is off, it isn't a good idea to switch it 9208c2ecf20Sopenharmony_ci * on; we don't know if one is connected. So it's better 9218c2ecf20Sopenharmony_ci * to fail then. 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci if (crtc->lcd_gen_cntl & CRT_ON) { 9248c2ecf20Sopenharmony_ci if (!(var->activate & FB_ACTIVATE_TEST)) 9258c2ecf20Sopenharmony_ci PRINTKI("Disable LCD panel, because video mode does not fit.\n"); 9268c2ecf20Sopenharmony_ci crtc->lcd_gen_cntl &= ~LCD_ON; 9278c2ecf20Sopenharmony_ci /*aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);*/ 9288c2ecf20Sopenharmony_ci } else { 9298c2ecf20Sopenharmony_ci if (!(var->activate & FB_ACTIVATE_TEST)) 9308c2ecf20Sopenharmony_ci PRINTKE("Video mode exceeds size of LCD panel.\nConnect this computer to a conventional monitor if you really need this mode.\n"); 9318c2ecf20Sopenharmony_ci return -EINVAL; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if ((par->lcd_table != 0) && (crtc->lcd_gen_cntl & LCD_ON)) { 9378c2ecf20Sopenharmony_ci int VScan = 1; 9388c2ecf20Sopenharmony_ci /* bpp -> bytespp, 1,4 -> 0; 8 -> 2; 15,16 -> 1; 24 -> 6; 32 -> 5 9398c2ecf20Sopenharmony_ci const u8 DFP_h_sync_dly_LT[] = { 0, 2, 1, 6, 5 }; 9408c2ecf20Sopenharmony_ci const u8 ADD_to_strt_wid_and_dly_LT_DAC[] = { 0, 5, 6, 9, 9, 12, 12 }; */ 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci vmode &= ~(FB_VMODE_DOUBLE | FB_VMODE_INTERLACED); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* 9458c2ecf20Sopenharmony_ci * This is horror! When we simulate, say 640x480 on an 800x600 9468c2ecf20Sopenharmony_ci * LCD monitor, the CRTC should be programmed 800x600 values for 9478c2ecf20Sopenharmony_ci * the non visible part, but 640x480 for the visible part. 9488c2ecf20Sopenharmony_ci * This code has been tested on a laptop with it's 1400x1050 LCD 9498c2ecf20Sopenharmony_ci * monitor and a conventional monitor both switched on. 9508c2ecf20Sopenharmony_ci * Tested modes: 1280x1024, 1152x864, 1024x768, 800x600, 9518c2ecf20Sopenharmony_ci * works with little glitches also with DOUBLESCAN modes 9528c2ecf20Sopenharmony_ci */ 9538c2ecf20Sopenharmony_ci if (yres < par->lcd_height) { 9548c2ecf20Sopenharmony_ci VScan = par->lcd_height / yres; 9558c2ecf20Sopenharmony_ci if (VScan > 1) { 9568c2ecf20Sopenharmony_ci VScan = 2; 9578c2ecf20Sopenharmony_ci vmode |= FB_VMODE_DOUBLE; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci h_sync_strt = h_disp + par->lcd_right_margin; 9628c2ecf20Sopenharmony_ci h_sync_end = h_sync_strt + par->lcd_hsync_len; 9638c2ecf20Sopenharmony_ci h_sync_dly = /*DFP_h_sync_dly[ ( bpp + 1 ) / 3 ]; */par->lcd_hsync_dly; 9648c2ecf20Sopenharmony_ci h_total = h_disp + par->lcd_hblank_len; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci v_sync_strt = v_disp + par->lcd_lower_margin / VScan; 9678c2ecf20Sopenharmony_ci v_sync_end = v_sync_strt + par->lcd_vsync_len / VScan; 9688c2ecf20Sopenharmony_ci v_total = v_disp + par->lcd_vblank_len / VScan; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_GENERIC_LCD */ 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci h_disp = (h_disp >> 3) - 1; 9738c2ecf20Sopenharmony_ci h_sync_strt = (h_sync_strt >> 3) - 1; 9748c2ecf20Sopenharmony_ci h_sync_end = (h_sync_end >> 3) - 1; 9758c2ecf20Sopenharmony_ci h_total = (h_total >> 3) - 1; 9768c2ecf20Sopenharmony_ci h_sync_wid = h_sync_end - h_sync_strt; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci FAIL_MAX("h_disp too large", h_disp, 0xff); 9798c2ecf20Sopenharmony_ci FAIL_MAX("h_sync_strt too large", h_sync_strt, 0x1ff); 9808c2ecf20Sopenharmony_ci /*FAIL_MAX("h_sync_wid too large", h_sync_wid, 0x1f);*/ 9818c2ecf20Sopenharmony_ci if (h_sync_wid > 0x1f) 9828c2ecf20Sopenharmony_ci h_sync_wid = 0x1f; 9838c2ecf20Sopenharmony_ci FAIL_MAX("h_total too large", h_total, 0x1ff); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (vmode & FB_VMODE_DOUBLE) { 9868c2ecf20Sopenharmony_ci v_disp <<= 1; 9878c2ecf20Sopenharmony_ci v_sync_strt <<= 1; 9888c2ecf20Sopenharmony_ci v_sync_end <<= 1; 9898c2ecf20Sopenharmony_ci v_total <<= 1; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci v_disp--; 9938c2ecf20Sopenharmony_ci v_sync_strt--; 9948c2ecf20Sopenharmony_ci v_sync_end--; 9958c2ecf20Sopenharmony_ci v_total--; 9968c2ecf20Sopenharmony_ci v_sync_wid = v_sync_end - v_sync_strt; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci FAIL_MAX("v_disp too large", v_disp, 0x7ff); 9998c2ecf20Sopenharmony_ci FAIL_MAX("v_sync_stsrt too large", v_sync_strt, 0x7ff); 10008c2ecf20Sopenharmony_ci /*FAIL_MAX("v_sync_wid too large", v_sync_wid, 0x1f);*/ 10018c2ecf20Sopenharmony_ci if (v_sync_wid > 0x1f) 10028c2ecf20Sopenharmony_ci v_sync_wid = 0x1f; 10038c2ecf20Sopenharmony_ci FAIL_MAX("v_total too large", v_total, 0x7ff); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci /* output */ 10088c2ecf20Sopenharmony_ci crtc->vxres = vxres; 10098c2ecf20Sopenharmony_ci crtc->vyres = vyres; 10108c2ecf20Sopenharmony_ci crtc->xoffset = xoffset; 10118c2ecf20Sopenharmony_ci crtc->yoffset = yoffset; 10128c2ecf20Sopenharmony_ci crtc->bpp = bpp; 10138c2ecf20Sopenharmony_ci crtc->off_pitch = 10148c2ecf20Sopenharmony_ci ((yoffset * line_length + xoffset * bpp / 8) / 8) | 10158c2ecf20Sopenharmony_ci ((line_length / bpp) << 22); 10168c2ecf20Sopenharmony_ci crtc->vline_crnt_vline = 0; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci crtc->h_tot_disp = h_total | (h_disp << 16); 10198c2ecf20Sopenharmony_ci crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly << 8) | 10208c2ecf20Sopenharmony_ci ((h_sync_strt & 0x100) << 4) | (h_sync_wid << 16) | 10218c2ecf20Sopenharmony_ci (h_sync_pol << 21); 10228c2ecf20Sopenharmony_ci crtc->v_tot_disp = v_total | (v_disp << 16); 10238c2ecf20Sopenharmony_ci crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid << 16) | 10248c2ecf20Sopenharmony_ci (v_sync_pol << 21); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci /* crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_PRESERVED_MASK; */ 10278c2ecf20Sopenharmony_ci crtc->gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | pix_width | c_sync; 10288c2ecf20Sopenharmony_ci crtc->gen_cntl |= CRTC_VGA_LINEAR; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* Enable doublescan mode if requested */ 10318c2ecf20Sopenharmony_ci if (vmode & FB_VMODE_DOUBLE) 10328c2ecf20Sopenharmony_ci crtc->gen_cntl |= CRTC_DBL_SCAN_EN; 10338c2ecf20Sopenharmony_ci /* Enable interlaced mode if requested */ 10348c2ecf20Sopenharmony_ci if (vmode & FB_VMODE_INTERLACED) 10358c2ecf20Sopenharmony_ci crtc->gen_cntl |= CRTC_INTERLACE_EN; 10368c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GENERIC_LCD 10378c2ecf20Sopenharmony_ci if (par->lcd_table != 0) { 10388c2ecf20Sopenharmony_ci u32 vdisplay = yres; 10398c2ecf20Sopenharmony_ci if (vmode & FB_VMODE_DOUBLE) 10408c2ecf20Sopenharmony_ci vdisplay <<= 1; 10418c2ecf20Sopenharmony_ci crtc->gen_cntl &= ~(CRTC2_EN | CRTC2_PIX_WIDTH); 10428c2ecf20Sopenharmony_ci crtc->lcd_gen_cntl &= ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | 10438c2ecf20Sopenharmony_ci /*TVCLK_PM_EN | VCLK_DAC_PM_EN |*/ 10448c2ecf20Sopenharmony_ci USE_SHADOWED_VEND | 10458c2ecf20Sopenharmony_ci USE_SHADOWED_ROWCUR | 10468c2ecf20Sopenharmony_ci SHADOW_EN | SHADOW_RW_EN); 10478c2ecf20Sopenharmony_ci crtc->lcd_gen_cntl |= DONT_SHADOW_VPAR/* | LOCK_8DOT*/; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci /* MOBILITY M1 tested, FIXME: LT */ 10508c2ecf20Sopenharmony_ci crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par); 10518c2ecf20Sopenharmony_ci if (!M64_HAS(LT_LCD_REGS)) 10528c2ecf20Sopenharmony_ci crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par) & 10538c2ecf20Sopenharmony_ci ~(AUTO_VERT_RATIO | VERT_STRETCH_MODE | VERT_STRETCH_RATIO3); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci crtc->horz_stretching &= ~(HORZ_STRETCH_RATIO | 10568c2ecf20Sopenharmony_ci HORZ_STRETCH_LOOP | AUTO_HORZ_RATIO | 10578c2ecf20Sopenharmony_ci HORZ_STRETCH_MODE | HORZ_STRETCH_EN); 10588c2ecf20Sopenharmony_ci if (xres < par->lcd_width && crtc->lcd_gen_cntl & LCD_ON) { 10598c2ecf20Sopenharmony_ci do { 10608c2ecf20Sopenharmony_ci /* 10618c2ecf20Sopenharmony_ci * The horizontal blender misbehaves when 10628c2ecf20Sopenharmony_ci * HDisplay is less than a certain threshold 10638c2ecf20Sopenharmony_ci * (440 for a 1024-wide panel). It doesn't 10648c2ecf20Sopenharmony_ci * stretch such modes enough. Use pixel 10658c2ecf20Sopenharmony_ci * replication instead of blending to stretch 10668c2ecf20Sopenharmony_ci * modes that can be made to exactly fit the 10678c2ecf20Sopenharmony_ci * panel width. The undocumented "NoLCDBlend" 10688c2ecf20Sopenharmony_ci * option allows the pixel-replicated mode to 10698c2ecf20Sopenharmony_ci * be slightly wider or narrower than the 10708c2ecf20Sopenharmony_ci * panel width. It also causes a mode that is 10718c2ecf20Sopenharmony_ci * exactly half as wide as the panel to be 10728c2ecf20Sopenharmony_ci * pixel-replicated, rather than blended. 10738c2ecf20Sopenharmony_ci */ 10748c2ecf20Sopenharmony_ci int HDisplay = xres & ~7; 10758c2ecf20Sopenharmony_ci int nStretch = par->lcd_width / HDisplay; 10768c2ecf20Sopenharmony_ci int Remainder = par->lcd_width % HDisplay; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if ((!Remainder && ((nStretch > 2))) || 10798c2ecf20Sopenharmony_ci (((HDisplay * 16) / par->lcd_width) < 7)) { 10808c2ecf20Sopenharmony_ci static const char StretchLoops[] = { 10, 12, 13, 15, 16 }; 10818c2ecf20Sopenharmony_ci int horz_stretch_loop = -1, BestRemainder; 10828c2ecf20Sopenharmony_ci int Numerator = HDisplay, Denominator = par->lcd_width; 10838c2ecf20Sopenharmony_ci int Index = 5; 10848c2ecf20Sopenharmony_ci ATIReduceRatio(&Numerator, &Denominator); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci BestRemainder = (Numerator * 16) / Denominator; 10878c2ecf20Sopenharmony_ci while (--Index >= 0) { 10888c2ecf20Sopenharmony_ci Remainder = ((Denominator - Numerator) * StretchLoops[Index]) % 10898c2ecf20Sopenharmony_ci Denominator; 10908c2ecf20Sopenharmony_ci if (Remainder < BestRemainder) { 10918c2ecf20Sopenharmony_ci horz_stretch_loop = Index; 10928c2ecf20Sopenharmony_ci if (!(BestRemainder = Remainder)) 10938c2ecf20Sopenharmony_ci break; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if ((horz_stretch_loop >= 0) && !BestRemainder) { 10988c2ecf20Sopenharmony_ci int horz_stretch_ratio = 0, Accumulator = 0; 10998c2ecf20Sopenharmony_ci int reuse_previous = 1; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci Index = StretchLoops[horz_stretch_loop]; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci while (--Index >= 0) { 11048c2ecf20Sopenharmony_ci if (Accumulator > 0) 11058c2ecf20Sopenharmony_ci horz_stretch_ratio |= reuse_previous; 11068c2ecf20Sopenharmony_ci else 11078c2ecf20Sopenharmony_ci Accumulator += Denominator; 11088c2ecf20Sopenharmony_ci Accumulator -= Numerator; 11098c2ecf20Sopenharmony_ci reuse_previous <<= 1; 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci crtc->horz_stretching |= (HORZ_STRETCH_EN | 11138c2ecf20Sopenharmony_ci ((horz_stretch_loop & HORZ_STRETCH_LOOP) << 16) | 11148c2ecf20Sopenharmony_ci (horz_stretch_ratio & HORZ_STRETCH_RATIO)); 11158c2ecf20Sopenharmony_ci break; /* Out of the do { ... } while (0) */ 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci crtc->horz_stretching |= (HORZ_STRETCH_MODE | HORZ_STRETCH_EN | 11208c2ecf20Sopenharmony_ci (((HDisplay * (HORZ_STRETCH_BLEND + 1)) / par->lcd_width) & HORZ_STRETCH_BLEND)); 11218c2ecf20Sopenharmony_ci } while (0); 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci if (vdisplay < par->lcd_height && crtc->lcd_gen_cntl & LCD_ON) { 11258c2ecf20Sopenharmony_ci crtc->vert_stretching = (VERT_STRETCH_USE0 | VERT_STRETCH_EN | 11268c2ecf20Sopenharmony_ci (((vdisplay * (VERT_STRETCH_RATIO0 + 1)) / par->lcd_height) & VERT_STRETCH_RATIO0)); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (!M64_HAS(LT_LCD_REGS) && 11298c2ecf20Sopenharmony_ci xres <= (M64_HAS(MOBIL_BUS) ? 1024 : 800)) 11308c2ecf20Sopenharmony_ci crtc->ext_vert_stretch |= VERT_STRETCH_MODE; 11318c2ecf20Sopenharmony_ci } else { 11328c2ecf20Sopenharmony_ci /* 11338c2ecf20Sopenharmony_ci * Don't use vertical blending if the mode is too wide 11348c2ecf20Sopenharmony_ci * or not vertically stretched. 11358c2ecf20Sopenharmony_ci */ 11368c2ecf20Sopenharmony_ci crtc->vert_stretching = 0; 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci /* copy to shadow crtc */ 11398c2ecf20Sopenharmony_ci crtc->shadow_h_tot_disp = crtc->h_tot_disp; 11408c2ecf20Sopenharmony_ci crtc->shadow_h_sync_strt_wid = crtc->h_sync_strt_wid; 11418c2ecf20Sopenharmony_ci crtc->shadow_v_tot_disp = crtc->v_tot_disp; 11428c2ecf20Sopenharmony_ci crtc->shadow_v_sync_strt_wid = crtc->v_sync_strt_wid; 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_GENERIC_LCD */ 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci if (M64_HAS(MAGIC_FIFO)) { 11478c2ecf20Sopenharmony_ci /* FIXME: display FIFO low watermark values */ 11488c2ecf20Sopenharmony_ci crtc->gen_cntl |= (aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_FIFO_LWM); 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci crtc->dp_pix_width = dp_pix_width; 11518c2ecf20Sopenharmony_ci crtc->dp_chain_mask = dp_chain_mask; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci return 0; 11548c2ecf20Sopenharmony_ci} 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_cistatic int aty_crtc_to_var(const struct crtc *crtc, 11578c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync; 11608c2ecf20Sopenharmony_ci u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; 11618c2ecf20Sopenharmony_ci u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; 11628c2ecf20Sopenharmony_ci u32 pix_width; 11638c2ecf20Sopenharmony_ci u32 double_scan, interlace; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* input */ 11668c2ecf20Sopenharmony_ci h_total = crtc->h_tot_disp & 0x1ff; 11678c2ecf20Sopenharmony_ci h_disp = (crtc->h_tot_disp >> 16) & 0xff; 11688c2ecf20Sopenharmony_ci h_sync_strt = (crtc->h_sync_strt_wid & 0xff) | ((crtc->h_sync_strt_wid >> 4) & 0x100); 11698c2ecf20Sopenharmony_ci h_sync_dly = (crtc->h_sync_strt_wid >> 8) & 0x7; 11708c2ecf20Sopenharmony_ci h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x1f; 11718c2ecf20Sopenharmony_ci h_sync_pol = (crtc->h_sync_strt_wid >> 21) & 0x1; 11728c2ecf20Sopenharmony_ci v_total = crtc->v_tot_disp & 0x7ff; 11738c2ecf20Sopenharmony_ci v_disp = (crtc->v_tot_disp >> 16) & 0x7ff; 11748c2ecf20Sopenharmony_ci v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; 11758c2ecf20Sopenharmony_ci v_sync_wid = (crtc->v_sync_strt_wid >> 16) & 0x1f; 11768c2ecf20Sopenharmony_ci v_sync_pol = (crtc->v_sync_strt_wid >> 21) & 0x1; 11778c2ecf20Sopenharmony_ci c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; 11788c2ecf20Sopenharmony_ci pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; 11798c2ecf20Sopenharmony_ci double_scan = crtc->gen_cntl & CRTC_DBL_SCAN_EN; 11808c2ecf20Sopenharmony_ci interlace = crtc->gen_cntl & CRTC_INTERLACE_EN; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci /* convert */ 11838c2ecf20Sopenharmony_ci xres = (h_disp + 1) * 8; 11848c2ecf20Sopenharmony_ci yres = v_disp + 1; 11858c2ecf20Sopenharmony_ci left = (h_total - h_sync_strt - h_sync_wid) * 8 - h_sync_dly; 11868c2ecf20Sopenharmony_ci right = (h_sync_strt - h_disp) * 8 + h_sync_dly; 11878c2ecf20Sopenharmony_ci hslen = h_sync_wid * 8; 11888c2ecf20Sopenharmony_ci upper = v_total - v_sync_strt - v_sync_wid; 11898c2ecf20Sopenharmony_ci lower = v_sync_strt - v_disp; 11908c2ecf20Sopenharmony_ci vslen = v_sync_wid; 11918c2ecf20Sopenharmony_ci sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | 11928c2ecf20Sopenharmony_ci (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | 11938c2ecf20Sopenharmony_ci (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci switch (pix_width) { 11968c2ecf20Sopenharmony_ci case CRTC_PIX_WIDTH_8BPP: 11978c2ecf20Sopenharmony_ci bpp = 8; 11988c2ecf20Sopenharmony_ci var->red.offset = 0; 11998c2ecf20Sopenharmony_ci var->red.length = 8; 12008c2ecf20Sopenharmony_ci var->green.offset = 0; 12018c2ecf20Sopenharmony_ci var->green.length = 8; 12028c2ecf20Sopenharmony_ci var->blue.offset = 0; 12038c2ecf20Sopenharmony_ci var->blue.length = 8; 12048c2ecf20Sopenharmony_ci var->transp.offset = 0; 12058c2ecf20Sopenharmony_ci var->transp.length = 0; 12068c2ecf20Sopenharmony_ci break; 12078c2ecf20Sopenharmony_ci case CRTC_PIX_WIDTH_15BPP: /* RGB 555 */ 12088c2ecf20Sopenharmony_ci bpp = 16; 12098c2ecf20Sopenharmony_ci var->red.offset = 10; 12108c2ecf20Sopenharmony_ci var->red.length = 5; 12118c2ecf20Sopenharmony_ci var->green.offset = 5; 12128c2ecf20Sopenharmony_ci var->green.length = 5; 12138c2ecf20Sopenharmony_ci var->blue.offset = 0; 12148c2ecf20Sopenharmony_ci var->blue.length = 5; 12158c2ecf20Sopenharmony_ci var->transp.offset = 0; 12168c2ecf20Sopenharmony_ci var->transp.length = 0; 12178c2ecf20Sopenharmony_ci break; 12188c2ecf20Sopenharmony_ci case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */ 12198c2ecf20Sopenharmony_ci bpp = 16; 12208c2ecf20Sopenharmony_ci var->red.offset = 11; 12218c2ecf20Sopenharmony_ci var->red.length = 5; 12228c2ecf20Sopenharmony_ci var->green.offset = 5; 12238c2ecf20Sopenharmony_ci var->green.length = 6; 12248c2ecf20Sopenharmony_ci var->blue.offset = 0; 12258c2ecf20Sopenharmony_ci var->blue.length = 5; 12268c2ecf20Sopenharmony_ci var->transp.offset = 0; 12278c2ecf20Sopenharmony_ci var->transp.length = 0; 12288c2ecf20Sopenharmony_ci break; 12298c2ecf20Sopenharmony_ci case CRTC_PIX_WIDTH_24BPP: /* RGB 888 */ 12308c2ecf20Sopenharmony_ci bpp = 24; 12318c2ecf20Sopenharmony_ci var->red.offset = 16; 12328c2ecf20Sopenharmony_ci var->red.length = 8; 12338c2ecf20Sopenharmony_ci var->green.offset = 8; 12348c2ecf20Sopenharmony_ci var->green.length = 8; 12358c2ecf20Sopenharmony_ci var->blue.offset = 0; 12368c2ecf20Sopenharmony_ci var->blue.length = 8; 12378c2ecf20Sopenharmony_ci var->transp.offset = 0; 12388c2ecf20Sopenharmony_ci var->transp.length = 0; 12398c2ecf20Sopenharmony_ci break; 12408c2ecf20Sopenharmony_ci case CRTC_PIX_WIDTH_32BPP: /* ARGB 8888 */ 12418c2ecf20Sopenharmony_ci bpp = 32; 12428c2ecf20Sopenharmony_ci var->red.offset = 16; 12438c2ecf20Sopenharmony_ci var->red.length = 8; 12448c2ecf20Sopenharmony_ci var->green.offset = 8; 12458c2ecf20Sopenharmony_ci var->green.length = 8; 12468c2ecf20Sopenharmony_ci var->blue.offset = 0; 12478c2ecf20Sopenharmony_ci var->blue.length = 8; 12488c2ecf20Sopenharmony_ci var->transp.offset = 24; 12498c2ecf20Sopenharmony_ci var->transp.length = 8; 12508c2ecf20Sopenharmony_ci break; 12518c2ecf20Sopenharmony_ci default: 12528c2ecf20Sopenharmony_ci PRINTKE("Invalid pixel width\n"); 12538c2ecf20Sopenharmony_ci return -EINVAL; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci /* output */ 12578c2ecf20Sopenharmony_ci var->xres = xres; 12588c2ecf20Sopenharmony_ci var->yres = yres; 12598c2ecf20Sopenharmony_ci var->xres_virtual = crtc->vxres; 12608c2ecf20Sopenharmony_ci var->yres_virtual = crtc->vyres; 12618c2ecf20Sopenharmony_ci var->bits_per_pixel = bpp; 12628c2ecf20Sopenharmony_ci var->left_margin = left; 12638c2ecf20Sopenharmony_ci var->right_margin = right; 12648c2ecf20Sopenharmony_ci var->upper_margin = upper; 12658c2ecf20Sopenharmony_ci var->lower_margin = lower; 12668c2ecf20Sopenharmony_ci var->hsync_len = hslen; 12678c2ecf20Sopenharmony_ci var->vsync_len = vslen; 12688c2ecf20Sopenharmony_ci var->sync = sync; 12698c2ecf20Sopenharmony_ci var->vmode = FB_VMODE_NONINTERLACED; 12708c2ecf20Sopenharmony_ci /* 12718c2ecf20Sopenharmony_ci * In double scan mode, the vertical parameters are doubled, 12728c2ecf20Sopenharmony_ci * so we need to halve them to get the right values. 12738c2ecf20Sopenharmony_ci * In interlaced mode the values are already correct, 12748c2ecf20Sopenharmony_ci * so no correction is necessary. 12758c2ecf20Sopenharmony_ci */ 12768c2ecf20Sopenharmony_ci if (interlace) 12778c2ecf20Sopenharmony_ci var->vmode = FB_VMODE_INTERLACED; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (double_scan) { 12808c2ecf20Sopenharmony_ci var->vmode = FB_VMODE_DOUBLE; 12818c2ecf20Sopenharmony_ci var->yres >>= 1; 12828c2ecf20Sopenharmony_ci var->upper_margin >>= 1; 12838c2ecf20Sopenharmony_ci var->lower_margin >>= 1; 12848c2ecf20Sopenharmony_ci var->vsync_len >>= 1; 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci return 0; 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------- */ 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_cistatic int atyfb_set_par(struct fb_info *info) 12938c2ecf20Sopenharmony_ci{ 12948c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 12958c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var = &info->var; 12968c2ecf20Sopenharmony_ci u32 tmp, pixclock; 12978c2ecf20Sopenharmony_ci int err; 12988c2ecf20Sopenharmony_ci#ifdef DEBUG 12998c2ecf20Sopenharmony_ci struct fb_var_screeninfo debug; 13008c2ecf20Sopenharmony_ci u32 pixclock_in_ps; 13018c2ecf20Sopenharmony_ci#endif 13028c2ecf20Sopenharmony_ci if (par->asleep) 13038c2ecf20Sopenharmony_ci return 0; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci err = aty_var_to_crtc(info, var, &par->crtc); 13068c2ecf20Sopenharmony_ci if (err) 13078c2ecf20Sopenharmony_ci return err; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci pixclock = atyfb_get_pixclock(var, par); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci if (pixclock == 0) { 13128c2ecf20Sopenharmony_ci PRINTKE("Invalid pixclock\n"); 13138c2ecf20Sopenharmony_ci return -EINVAL; 13148c2ecf20Sopenharmony_ci } else { 13158c2ecf20Sopenharmony_ci err = par->pll_ops->var_to_pll(info, pixclock, 13168c2ecf20Sopenharmony_ci var->bits_per_pixel, &par->pll); 13178c2ecf20Sopenharmony_ci if (err) 13188c2ecf20Sopenharmony_ci return err; 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci par->accel_flags = var->accel_flags; /* hack */ 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci if (var->accel_flags) { 13248c2ecf20Sopenharmony_ci atyfb_ops.fb_sync = atyfb_sync; 13258c2ecf20Sopenharmony_ci info->flags &= ~FBINFO_HWACCEL_DISABLED; 13268c2ecf20Sopenharmony_ci } else { 13278c2ecf20Sopenharmony_ci atyfb_ops.fb_sync = NULL; 13288c2ecf20Sopenharmony_ci info->flags |= FBINFO_HWACCEL_DISABLED; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci if (par->blitter_may_be_busy) 13328c2ecf20Sopenharmony_ci wait_for_idle(par); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci aty_set_crtc(par, &par->crtc); 13358c2ecf20Sopenharmony_ci par->dac_ops->set_dac(info, &par->pll, 13368c2ecf20Sopenharmony_ci var->bits_per_pixel, par->accel_flags); 13378c2ecf20Sopenharmony_ci par->pll_ops->set_pll(info, &par->pll); 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci#ifdef DEBUG 13408c2ecf20Sopenharmony_ci if (par->pll_ops && par->pll_ops->pll_to_var) 13418c2ecf20Sopenharmony_ci pixclock_in_ps = par->pll_ops->pll_to_var(info, &par->pll); 13428c2ecf20Sopenharmony_ci else 13438c2ecf20Sopenharmony_ci pixclock_in_ps = 0; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci if (0 == pixclock_in_ps) { 13468c2ecf20Sopenharmony_ci PRINTKE("ALERT ops->pll_to_var get 0\n"); 13478c2ecf20Sopenharmony_ci pixclock_in_ps = pixclock; 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci memset(&debug, 0, sizeof(debug)); 13518c2ecf20Sopenharmony_ci if (!aty_crtc_to_var(&par->crtc, &debug)) { 13528c2ecf20Sopenharmony_ci u32 hSync, vRefresh; 13538c2ecf20Sopenharmony_ci u32 h_disp, h_sync_strt, h_sync_end, h_total; 13548c2ecf20Sopenharmony_ci u32 v_disp, v_sync_strt, v_sync_end, v_total; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci h_disp = debug.xres; 13578c2ecf20Sopenharmony_ci h_sync_strt = h_disp + debug.right_margin; 13588c2ecf20Sopenharmony_ci h_sync_end = h_sync_strt + debug.hsync_len; 13598c2ecf20Sopenharmony_ci h_total = h_sync_end + debug.left_margin; 13608c2ecf20Sopenharmony_ci v_disp = debug.yres; 13618c2ecf20Sopenharmony_ci v_sync_strt = v_disp + debug.lower_margin; 13628c2ecf20Sopenharmony_ci v_sync_end = v_sync_strt + debug.vsync_len; 13638c2ecf20Sopenharmony_ci v_total = v_sync_end + debug.upper_margin; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci hSync = 1000000000 / (pixclock_in_ps * h_total); 13668c2ecf20Sopenharmony_ci vRefresh = (hSync * 1000) / v_total; 13678c2ecf20Sopenharmony_ci if (par->crtc.gen_cntl & CRTC_INTERLACE_EN) 13688c2ecf20Sopenharmony_ci vRefresh *= 2; 13698c2ecf20Sopenharmony_ci if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN) 13708c2ecf20Sopenharmony_ci vRefresh /= 2; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci DPRINTK("atyfb_set_par\n"); 13738c2ecf20Sopenharmony_ci DPRINTK(" Set Visible Mode to %ix%i-%i\n", 13748c2ecf20Sopenharmony_ci var->xres, var->yres, var->bits_per_pixel); 13758c2ecf20Sopenharmony_ci DPRINTK(" Virtual resolution %ix%i, " 13768c2ecf20Sopenharmony_ci "pixclock_in_ps %i (calculated %i)\n", 13778c2ecf20Sopenharmony_ci var->xres_virtual, var->yres_virtual, 13788c2ecf20Sopenharmony_ci pixclock, pixclock_in_ps); 13798c2ecf20Sopenharmony_ci DPRINTK(" Dot clock: %i MHz\n", 13808c2ecf20Sopenharmony_ci 1000000 / pixclock_in_ps); 13818c2ecf20Sopenharmony_ci DPRINTK(" Horizontal sync: %i kHz\n", hSync); 13828c2ecf20Sopenharmony_ci DPRINTK(" Vertical refresh: %i Hz\n", vRefresh); 13838c2ecf20Sopenharmony_ci DPRINTK(" x style: %i.%03i %i %i %i %i %i %i %i %i\n", 13848c2ecf20Sopenharmony_ci 1000000 / pixclock_in_ps, 1000000 % pixclock_in_ps, 13858c2ecf20Sopenharmony_ci h_disp, h_sync_strt, h_sync_end, h_total, 13868c2ecf20Sopenharmony_ci v_disp, v_sync_strt, v_sync_end, v_total); 13878c2ecf20Sopenharmony_ci DPRINTK(" fb style: %i %i %i %i %i %i %i %i %i\n", 13888c2ecf20Sopenharmony_ci pixclock_in_ps, 13898c2ecf20Sopenharmony_ci debug.left_margin, h_disp, debug.right_margin, debug.hsync_len, 13908c2ecf20Sopenharmony_ci debug.upper_margin, v_disp, debug.lower_margin, debug.vsync_len); 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci#endif /* DEBUG */ 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (!M64_HAS(INTEGRATED)) { 13958c2ecf20Sopenharmony_ci /* Don't forget MEM_CNTL */ 13968c2ecf20Sopenharmony_ci tmp = aty_ld_le32(MEM_CNTL, par) & 0xf0ffffff; 13978c2ecf20Sopenharmony_ci switch (var->bits_per_pixel) { 13988c2ecf20Sopenharmony_ci case 8: 13998c2ecf20Sopenharmony_ci tmp |= 0x02000000; 14008c2ecf20Sopenharmony_ci break; 14018c2ecf20Sopenharmony_ci case 16: 14028c2ecf20Sopenharmony_ci tmp |= 0x03000000; 14038c2ecf20Sopenharmony_ci break; 14048c2ecf20Sopenharmony_ci case 32: 14058c2ecf20Sopenharmony_ci tmp |= 0x06000000; 14068c2ecf20Sopenharmony_ci break; 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci aty_st_le32(MEM_CNTL, tmp, par); 14098c2ecf20Sopenharmony_ci } else { 14108c2ecf20Sopenharmony_ci tmp = aty_ld_le32(MEM_CNTL, par) & 0xf00fffff; 14118c2ecf20Sopenharmony_ci if (!M64_HAS(MAGIC_POSTDIV)) 14128c2ecf20Sopenharmony_ci tmp |= par->mem_refresh_rate << 20; 14138c2ecf20Sopenharmony_ci switch (var->bits_per_pixel) { 14148c2ecf20Sopenharmony_ci case 8: 14158c2ecf20Sopenharmony_ci case 24: 14168c2ecf20Sopenharmony_ci tmp |= 0x00000000; 14178c2ecf20Sopenharmony_ci break; 14188c2ecf20Sopenharmony_ci case 16: 14198c2ecf20Sopenharmony_ci tmp |= 0x04000000; 14208c2ecf20Sopenharmony_ci break; 14218c2ecf20Sopenharmony_ci case 32: 14228c2ecf20Sopenharmony_ci tmp |= 0x08000000; 14238c2ecf20Sopenharmony_ci break; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci if (M64_HAS(CT_BUS)) { 14268c2ecf20Sopenharmony_ci aty_st_le32(DAC_CNTL, 0x87010184, par); 14278c2ecf20Sopenharmony_ci aty_st_le32(BUS_CNTL, 0x680000f9, par); 14288c2ecf20Sopenharmony_ci } else if (M64_HAS(VT_BUS)) { 14298c2ecf20Sopenharmony_ci aty_st_le32(DAC_CNTL, 0x87010184, par); 14308c2ecf20Sopenharmony_ci aty_st_le32(BUS_CNTL, 0x680000f9, par); 14318c2ecf20Sopenharmony_ci } else if (M64_HAS(MOBIL_BUS)) { 14328c2ecf20Sopenharmony_ci aty_st_le32(DAC_CNTL, 0x80010102, par); 14338c2ecf20Sopenharmony_ci aty_st_le32(BUS_CNTL, 0x7b33a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par); 14348c2ecf20Sopenharmony_ci } else { 14358c2ecf20Sopenharmony_ci /* GT */ 14368c2ecf20Sopenharmony_ci aty_st_le32(DAC_CNTL, 0x86010102, par); 14378c2ecf20Sopenharmony_ci aty_st_le32(BUS_CNTL, 0x7b23a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par); 14388c2ecf20Sopenharmony_ci aty_st_le32(EXT_MEM_CNTL, aty_ld_le32(EXT_MEM_CNTL, par) | 0x5000001, par); 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci aty_st_le32(MEM_CNTL, tmp, par); 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci aty_st_8(DAC_MASK, 0xff, par); 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci info->fix.line_length = calc_line_length(par, var->xres_virtual, 14458c2ecf20Sopenharmony_ci var->bits_per_pixel); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci info->fix.visual = var->bits_per_pixel <= 8 ? 14488c2ecf20Sopenharmony_ci FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci /* Initialize the graphics engine */ 14518c2ecf20Sopenharmony_ci if (par->accel_flags & FB_ACCELF_TEXT) 14528c2ecf20Sopenharmony_ci aty_init_engine(par, info); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci#ifdef CONFIG_BOOTX_TEXT 14558c2ecf20Sopenharmony_ci btext_update_display(info->fix.smem_start, 14568c2ecf20Sopenharmony_ci (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8, 14578c2ecf20Sopenharmony_ci ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1, 14588c2ecf20Sopenharmony_ci var->bits_per_pixel, 14598c2ecf20Sopenharmony_ci par->crtc.vxres * var->bits_per_pixel / 8); 14608c2ecf20Sopenharmony_ci#endif /* CONFIG_BOOTX_TEXT */ 14618c2ecf20Sopenharmony_ci#ifdef DEBUG 14628c2ecf20Sopenharmony_ci{ 14638c2ecf20Sopenharmony_ci /* dump non shadow CRTC, pll, LCD registers */ 14648c2ecf20Sopenharmony_ci int i; u32 base; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci /* CRTC registers */ 14678c2ecf20Sopenharmony_ci base = 0x2000; 14688c2ecf20Sopenharmony_ci printk("debug atyfb: Mach64 non-shadow register values:"); 14698c2ecf20Sopenharmony_ci for (i = 0; i < 256; i = i+4) { 14708c2ecf20Sopenharmony_ci if (i % 16 == 0) { 14718c2ecf20Sopenharmony_ci pr_cont("\n"); 14728c2ecf20Sopenharmony_ci printk("debug atyfb: 0x%04X: ", base + i); 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci pr_cont(" %08X", aty_ld_le32(i, par)); 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci pr_cont("\n\n"); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_CT 14798c2ecf20Sopenharmony_ci /* PLL registers */ 14808c2ecf20Sopenharmony_ci base = 0x00; 14818c2ecf20Sopenharmony_ci printk("debug atyfb: Mach64 PLL register values:"); 14828c2ecf20Sopenharmony_ci for (i = 0; i < 64; i++) { 14838c2ecf20Sopenharmony_ci if (i % 16 == 0) { 14848c2ecf20Sopenharmony_ci pr_cont("\n"); 14858c2ecf20Sopenharmony_ci printk("debug atyfb: 0x%02X: ", base + i); 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci if (i % 4 == 0) 14888c2ecf20Sopenharmony_ci pr_cont(" "); 14898c2ecf20Sopenharmony_ci pr_cont("%02X", aty_ld_pll_ct(i, par)); 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci pr_cont("\n\n"); 14928c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_CT */ 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GENERIC_LCD 14958c2ecf20Sopenharmony_ci if (par->lcd_table != 0) { 14968c2ecf20Sopenharmony_ci /* LCD registers */ 14978c2ecf20Sopenharmony_ci base = 0x00; 14988c2ecf20Sopenharmony_ci printk("debug atyfb: LCD register values:"); 14998c2ecf20Sopenharmony_ci if (M64_HAS(LT_LCD_REGS)) { 15008c2ecf20Sopenharmony_ci for (i = 0; i <= POWER_MANAGEMENT; i++) { 15018c2ecf20Sopenharmony_ci if (i == EXT_VERT_STRETCH) 15028c2ecf20Sopenharmony_ci continue; 15038c2ecf20Sopenharmony_ci pr_cont("\ndebug atyfb: 0x%04X: ", 15048c2ecf20Sopenharmony_ci lt_lcd_regs[i]); 15058c2ecf20Sopenharmony_ci pr_cont(" %08X", aty_ld_lcd(i, par)); 15068c2ecf20Sopenharmony_ci } 15078c2ecf20Sopenharmony_ci } else { 15088c2ecf20Sopenharmony_ci for (i = 0; i < 64; i++) { 15098c2ecf20Sopenharmony_ci if (i % 4 == 0) 15108c2ecf20Sopenharmony_ci pr_cont("\ndebug atyfb: 0x%02X: ", 15118c2ecf20Sopenharmony_ci base + i); 15128c2ecf20Sopenharmony_ci pr_cont(" %08X", aty_ld_lcd(i, par)); 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci pr_cont("\n\n"); 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_GENERIC_LCD */ 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci#endif /* DEBUG */ 15208c2ecf20Sopenharmony_ci return 0; 15218c2ecf20Sopenharmony_ci} 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_cistatic int atyfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 15248c2ecf20Sopenharmony_ci{ 15258c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 15268c2ecf20Sopenharmony_ci int err; 15278c2ecf20Sopenharmony_ci struct crtc crtc; 15288c2ecf20Sopenharmony_ci union aty_pll pll; 15298c2ecf20Sopenharmony_ci u32 pixclock; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci memcpy(&pll, &par->pll, sizeof(pll)); 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci err = aty_var_to_crtc(info, var, &crtc); 15348c2ecf20Sopenharmony_ci if (err) 15358c2ecf20Sopenharmony_ci return err; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci pixclock = atyfb_get_pixclock(var, par); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci if (pixclock == 0) { 15408c2ecf20Sopenharmony_ci if (!(var->activate & FB_ACTIVATE_TEST)) 15418c2ecf20Sopenharmony_ci PRINTKE("Invalid pixclock\n"); 15428c2ecf20Sopenharmony_ci return -EINVAL; 15438c2ecf20Sopenharmony_ci } else { 15448c2ecf20Sopenharmony_ci err = par->pll_ops->var_to_pll(info, pixclock, 15458c2ecf20Sopenharmony_ci var->bits_per_pixel, &pll); 15468c2ecf20Sopenharmony_ci if (err) 15478c2ecf20Sopenharmony_ci return err; 15488c2ecf20Sopenharmony_ci } 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci if (var->accel_flags & FB_ACCELF_TEXT) 15518c2ecf20Sopenharmony_ci info->var.accel_flags = FB_ACCELF_TEXT; 15528c2ecf20Sopenharmony_ci else 15538c2ecf20Sopenharmony_ci info->var.accel_flags = 0; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci aty_crtc_to_var(&crtc, var); 15568c2ecf20Sopenharmony_ci var->pixclock = par->pll_ops->pll_to_var(info, &pll); 15578c2ecf20Sopenharmony_ci return 0; 15588c2ecf20Sopenharmony_ci} 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_cistatic void set_off_pitch(struct atyfb_par *par, const struct fb_info *info) 15618c2ecf20Sopenharmony_ci{ 15628c2ecf20Sopenharmony_ci u32 xoffset = info->var.xoffset; 15638c2ecf20Sopenharmony_ci u32 yoffset = info->var.yoffset; 15648c2ecf20Sopenharmony_ci u32 line_length = info->fix.line_length; 15658c2ecf20Sopenharmony_ci u32 bpp = info->var.bits_per_pixel; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci par->crtc.off_pitch = 15688c2ecf20Sopenharmony_ci ((yoffset * line_length + xoffset * bpp / 8) / 8) | 15698c2ecf20Sopenharmony_ci ((line_length / bpp) << 22); 15708c2ecf20Sopenharmony_ci} 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci/* 15748c2ecf20Sopenharmony_ci * Open/Release the frame buffer device 15758c2ecf20Sopenharmony_ci */ 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_cistatic int atyfb_open(struct fb_info *info, int user) 15788c2ecf20Sopenharmony_ci{ 15798c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci if (user) { 15828c2ecf20Sopenharmony_ci par->open++; 15838c2ecf20Sopenharmony_ci#ifdef __sparc__ 15848c2ecf20Sopenharmony_ci par->mmaped = 0; 15858c2ecf20Sopenharmony_ci#endif 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci return 0; 15888c2ecf20Sopenharmony_ci} 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_cistatic irqreturn_t aty_irq(int irq, void *dev_id) 15918c2ecf20Sopenharmony_ci{ 15928c2ecf20Sopenharmony_ci struct atyfb_par *par = dev_id; 15938c2ecf20Sopenharmony_ci int handled = 0; 15948c2ecf20Sopenharmony_ci u32 int_cntl; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci spin_lock(&par->int_lock); 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci int_cntl = aty_ld_le32(CRTC_INT_CNTL, par); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (int_cntl & CRTC_VBLANK_INT) { 16018c2ecf20Sopenharmony_ci /* clear interrupt */ 16028c2ecf20Sopenharmony_ci aty_st_le32(CRTC_INT_CNTL, (int_cntl & CRTC_INT_EN_MASK) | 16038c2ecf20Sopenharmony_ci CRTC_VBLANK_INT_AK, par); 16048c2ecf20Sopenharmony_ci par->vblank.count++; 16058c2ecf20Sopenharmony_ci if (par->vblank.pan_display) { 16068c2ecf20Sopenharmony_ci par->vblank.pan_display = 0; 16078c2ecf20Sopenharmony_ci aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par); 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci wake_up_interruptible(&par->vblank.wait); 16108c2ecf20Sopenharmony_ci handled = 1; 16118c2ecf20Sopenharmony_ci } 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci spin_unlock(&par->int_lock); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 16168c2ecf20Sopenharmony_ci} 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_cistatic int aty_enable_irq(struct atyfb_par *par, int reenable) 16198c2ecf20Sopenharmony_ci{ 16208c2ecf20Sopenharmony_ci u32 int_cntl; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci if (!test_and_set_bit(0, &par->irq_flags)) { 16238c2ecf20Sopenharmony_ci if (request_irq(par->irq, aty_irq, IRQF_SHARED, "atyfb", par)) { 16248c2ecf20Sopenharmony_ci clear_bit(0, &par->irq_flags); 16258c2ecf20Sopenharmony_ci return -EINVAL; 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci spin_lock_irq(&par->int_lock); 16288c2ecf20Sopenharmony_ci int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK; 16298c2ecf20Sopenharmony_ci /* clear interrupt */ 16308c2ecf20Sopenharmony_ci aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_AK, par); 16318c2ecf20Sopenharmony_ci /* enable interrupt */ 16328c2ecf20Sopenharmony_ci aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_EN, par); 16338c2ecf20Sopenharmony_ci spin_unlock_irq(&par->int_lock); 16348c2ecf20Sopenharmony_ci } else if (reenable) { 16358c2ecf20Sopenharmony_ci spin_lock_irq(&par->int_lock); 16368c2ecf20Sopenharmony_ci int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK; 16378c2ecf20Sopenharmony_ci if (!(int_cntl & CRTC_VBLANK_INT_EN)) { 16388c2ecf20Sopenharmony_ci printk("atyfb: someone disabled IRQ [%08x]\n", 16398c2ecf20Sopenharmony_ci int_cntl); 16408c2ecf20Sopenharmony_ci /* re-enable interrupt */ 16418c2ecf20Sopenharmony_ci aty_st_le32(CRTC_INT_CNTL, int_cntl | 16428c2ecf20Sopenharmony_ci CRTC_VBLANK_INT_EN, par); 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci spin_unlock_irq(&par->int_lock); 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci return 0; 16488c2ecf20Sopenharmony_ci} 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_cistatic int aty_disable_irq(struct atyfb_par *par) 16518c2ecf20Sopenharmony_ci{ 16528c2ecf20Sopenharmony_ci u32 int_cntl; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci if (test_and_clear_bit(0, &par->irq_flags)) { 16558c2ecf20Sopenharmony_ci if (par->vblank.pan_display) { 16568c2ecf20Sopenharmony_ci par->vblank.pan_display = 0; 16578c2ecf20Sopenharmony_ci aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par); 16588c2ecf20Sopenharmony_ci } 16598c2ecf20Sopenharmony_ci spin_lock_irq(&par->int_lock); 16608c2ecf20Sopenharmony_ci int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK; 16618c2ecf20Sopenharmony_ci /* disable interrupt */ 16628c2ecf20Sopenharmony_ci aty_st_le32(CRTC_INT_CNTL, int_cntl & ~CRTC_VBLANK_INT_EN, par); 16638c2ecf20Sopenharmony_ci spin_unlock_irq(&par->int_lock); 16648c2ecf20Sopenharmony_ci free_irq(par->irq, par); 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci return 0; 16688c2ecf20Sopenharmony_ci} 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_cistatic int atyfb_release(struct fb_info *info, int user) 16718c2ecf20Sopenharmony_ci{ 16728c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 16738c2ecf20Sopenharmony_ci#ifdef __sparc__ 16748c2ecf20Sopenharmony_ci int was_mmaped; 16758c2ecf20Sopenharmony_ci#endif 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (!user) 16788c2ecf20Sopenharmony_ci return 0; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci par->open--; 16818c2ecf20Sopenharmony_ci mdelay(1); 16828c2ecf20Sopenharmony_ci wait_for_idle(par); 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci if (par->open) 16858c2ecf20Sopenharmony_ci return 0; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci#ifdef __sparc__ 16888c2ecf20Sopenharmony_ci was_mmaped = par->mmaped; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci par->mmaped = 0; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci if (was_mmaped) { 16938c2ecf20Sopenharmony_ci struct fb_var_screeninfo var; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci /* 16968c2ecf20Sopenharmony_ci * Now reset the default display config, we have 16978c2ecf20Sopenharmony_ci * no idea what the program(s) which mmap'd the 16988c2ecf20Sopenharmony_ci * chip did to the configuration, nor whether it 16998c2ecf20Sopenharmony_ci * restored it correctly. 17008c2ecf20Sopenharmony_ci */ 17018c2ecf20Sopenharmony_ci var = default_var; 17028c2ecf20Sopenharmony_ci if (noaccel) 17038c2ecf20Sopenharmony_ci var.accel_flags &= ~FB_ACCELF_TEXT; 17048c2ecf20Sopenharmony_ci else 17058c2ecf20Sopenharmony_ci var.accel_flags |= FB_ACCELF_TEXT; 17068c2ecf20Sopenharmony_ci if (var.yres == var.yres_virtual) { 17078c2ecf20Sopenharmony_ci u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2)); 17088c2ecf20Sopenharmony_ci var.yres_virtual = 17098c2ecf20Sopenharmony_ci ((videoram * 8) / var.bits_per_pixel) / 17108c2ecf20Sopenharmony_ci var.xres_virtual; 17118c2ecf20Sopenharmony_ci if (var.yres_virtual < var.yres) 17128c2ecf20Sopenharmony_ci var.yres_virtual = var.yres; 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci#endif 17168c2ecf20Sopenharmony_ci aty_disable_irq(par); 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci return 0; 17198c2ecf20Sopenharmony_ci} 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci/* 17228c2ecf20Sopenharmony_ci * Pan or Wrap the Display 17238c2ecf20Sopenharmony_ci * 17248c2ecf20Sopenharmony_ci * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag 17258c2ecf20Sopenharmony_ci */ 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_cistatic int atyfb_pan_display(struct fb_var_screeninfo *var, 17288c2ecf20Sopenharmony_ci struct fb_info *info) 17298c2ecf20Sopenharmony_ci{ 17308c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 17318c2ecf20Sopenharmony_ci u32 xres, yres, xoffset, yoffset; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8; 17348c2ecf20Sopenharmony_ci yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1; 17358c2ecf20Sopenharmony_ci if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN) 17368c2ecf20Sopenharmony_ci yres >>= 1; 17378c2ecf20Sopenharmony_ci xoffset = (var->xoffset + 7) & ~7; 17388c2ecf20Sopenharmony_ci yoffset = var->yoffset; 17398c2ecf20Sopenharmony_ci if (xoffset + xres > par->crtc.vxres || 17408c2ecf20Sopenharmony_ci yoffset + yres > par->crtc.vyres) 17418c2ecf20Sopenharmony_ci return -EINVAL; 17428c2ecf20Sopenharmony_ci info->var.xoffset = xoffset; 17438c2ecf20Sopenharmony_ci info->var.yoffset = yoffset; 17448c2ecf20Sopenharmony_ci if (par->asleep) 17458c2ecf20Sopenharmony_ci return 0; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci set_off_pitch(par, info); 17488c2ecf20Sopenharmony_ci if ((var->activate & FB_ACTIVATE_VBL) && !aty_enable_irq(par, 0)) { 17498c2ecf20Sopenharmony_ci par->vblank.pan_display = 1; 17508c2ecf20Sopenharmony_ci } else { 17518c2ecf20Sopenharmony_ci par->vblank.pan_display = 0; 17528c2ecf20Sopenharmony_ci aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par); 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci return 0; 17568c2ecf20Sopenharmony_ci} 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_cistatic int aty_waitforvblank(struct atyfb_par *par, u32 crtc) 17598c2ecf20Sopenharmony_ci{ 17608c2ecf20Sopenharmony_ci struct aty_interrupt *vbl; 17618c2ecf20Sopenharmony_ci unsigned int count; 17628c2ecf20Sopenharmony_ci int ret; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci switch (crtc) { 17658c2ecf20Sopenharmony_ci case 0: 17668c2ecf20Sopenharmony_ci vbl = &par->vblank; 17678c2ecf20Sopenharmony_ci break; 17688c2ecf20Sopenharmony_ci default: 17698c2ecf20Sopenharmony_ci return -ENODEV; 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci ret = aty_enable_irq(par, 0); 17738c2ecf20Sopenharmony_ci if (ret) 17748c2ecf20Sopenharmony_ci return ret; 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci count = vbl->count; 17778c2ecf20Sopenharmony_ci ret = wait_event_interruptible_timeout(vbl->wait, 17788c2ecf20Sopenharmony_ci count != vbl->count, HZ/10); 17798c2ecf20Sopenharmony_ci if (ret < 0) 17808c2ecf20Sopenharmony_ci return ret; 17818c2ecf20Sopenharmony_ci if (ret == 0) { 17828c2ecf20Sopenharmony_ci aty_enable_irq(par, 1); 17838c2ecf20Sopenharmony_ci return -ETIMEDOUT; 17848c2ecf20Sopenharmony_ci } 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci return 0; 17878c2ecf20Sopenharmony_ci} 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci#ifdef DEBUG 17918c2ecf20Sopenharmony_ci#define ATYIO_CLKR 0x41545900 /* ATY\00 */ 17928c2ecf20Sopenharmony_ci#define ATYIO_CLKW 0x41545901 /* ATY\01 */ 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_cistruct atyclk { 17958c2ecf20Sopenharmony_ci u32 ref_clk_per; 17968c2ecf20Sopenharmony_ci u8 pll_ref_div; 17978c2ecf20Sopenharmony_ci u8 mclk_fb_div; 17988c2ecf20Sopenharmony_ci u8 mclk_post_div; /* 1,2,3,4,8 */ 17998c2ecf20Sopenharmony_ci u8 mclk_fb_mult; /* 2 or 4 */ 18008c2ecf20Sopenharmony_ci u8 xclk_post_div; /* 1,2,3,4,8 */ 18018c2ecf20Sopenharmony_ci u8 vclk_fb_div; 18028c2ecf20Sopenharmony_ci u8 vclk_post_div; /* 1,2,3,4,6,8,12 */ 18038c2ecf20Sopenharmony_ci u32 dsp_xclks_per_row; /* 0-16383 */ 18048c2ecf20Sopenharmony_ci u32 dsp_loop_latency; /* 0-15 */ 18058c2ecf20Sopenharmony_ci u32 dsp_precision; /* 0-7 */ 18068c2ecf20Sopenharmony_ci u32 dsp_on; /* 0-2047 */ 18078c2ecf20Sopenharmony_ci u32 dsp_off; /* 0-2047 */ 18088c2ecf20Sopenharmony_ci}; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci#define ATYIO_FEATR 0x41545902 /* ATY\02 */ 18118c2ecf20Sopenharmony_ci#define ATYIO_FEATW 0x41545903 /* ATY\03 */ 18128c2ecf20Sopenharmony_ci#endif 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_cistatic int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg) 18158c2ecf20Sopenharmony_ci{ 18168c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 18178c2ecf20Sopenharmony_ci#ifdef __sparc__ 18188c2ecf20Sopenharmony_ci struct fbtype fbtyp; 18198c2ecf20Sopenharmony_ci#endif 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci switch (cmd) { 18228c2ecf20Sopenharmony_ci#ifdef __sparc__ 18238c2ecf20Sopenharmony_ci case FBIOGTYPE: 18248c2ecf20Sopenharmony_ci fbtyp.fb_type = FBTYPE_PCI_GENERIC; 18258c2ecf20Sopenharmony_ci fbtyp.fb_width = par->crtc.vxres; 18268c2ecf20Sopenharmony_ci fbtyp.fb_height = par->crtc.vyres; 18278c2ecf20Sopenharmony_ci fbtyp.fb_depth = info->var.bits_per_pixel; 18288c2ecf20Sopenharmony_ci fbtyp.fb_cmsize = info->cmap.len; 18298c2ecf20Sopenharmony_ci fbtyp.fb_size = info->fix.smem_len; 18308c2ecf20Sopenharmony_ci if (copy_to_user((struct fbtype __user *) arg, &fbtyp, 18318c2ecf20Sopenharmony_ci sizeof(fbtyp))) 18328c2ecf20Sopenharmony_ci return -EFAULT; 18338c2ecf20Sopenharmony_ci break; 18348c2ecf20Sopenharmony_ci#endif /* __sparc__ */ 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci case FBIO_WAITFORVSYNC: 18378c2ecf20Sopenharmony_ci { 18388c2ecf20Sopenharmony_ci u32 crtc; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci if (get_user(crtc, (__u32 __user *) arg)) 18418c2ecf20Sopenharmony_ci return -EFAULT; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci return aty_waitforvblank(par, crtc); 18448c2ecf20Sopenharmony_ci } 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci#if defined(DEBUG) && defined(CONFIG_FB_ATY_CT) 18478c2ecf20Sopenharmony_ci case ATYIO_CLKR: 18488c2ecf20Sopenharmony_ci if (M64_HAS(INTEGRATED)) { 18498c2ecf20Sopenharmony_ci struct atyclk clk = { 0 }; 18508c2ecf20Sopenharmony_ci union aty_pll *pll = &par->pll; 18518c2ecf20Sopenharmony_ci u32 dsp_config = pll->ct.dsp_config; 18528c2ecf20Sopenharmony_ci u32 dsp_on_off = pll->ct.dsp_on_off; 18538c2ecf20Sopenharmony_ci clk.ref_clk_per = par->ref_clk_per; 18548c2ecf20Sopenharmony_ci clk.pll_ref_div = pll->ct.pll_ref_div; 18558c2ecf20Sopenharmony_ci clk.mclk_fb_div = pll->ct.mclk_fb_div; 18568c2ecf20Sopenharmony_ci clk.mclk_post_div = pll->ct.mclk_post_div_real; 18578c2ecf20Sopenharmony_ci clk.mclk_fb_mult = pll->ct.mclk_fb_mult; 18588c2ecf20Sopenharmony_ci clk.xclk_post_div = pll->ct.xclk_post_div_real; 18598c2ecf20Sopenharmony_ci clk.vclk_fb_div = pll->ct.vclk_fb_div; 18608c2ecf20Sopenharmony_ci clk.vclk_post_div = pll->ct.vclk_post_div_real; 18618c2ecf20Sopenharmony_ci clk.dsp_xclks_per_row = dsp_config & 0x3fff; 18628c2ecf20Sopenharmony_ci clk.dsp_loop_latency = (dsp_config >> 16) & 0xf; 18638c2ecf20Sopenharmony_ci clk.dsp_precision = (dsp_config >> 20) & 7; 18648c2ecf20Sopenharmony_ci clk.dsp_off = dsp_on_off & 0x7ff; 18658c2ecf20Sopenharmony_ci clk.dsp_on = (dsp_on_off >> 16) & 0x7ff; 18668c2ecf20Sopenharmony_ci if (copy_to_user((struct atyclk __user *) arg, &clk, 18678c2ecf20Sopenharmony_ci sizeof(clk))) 18688c2ecf20Sopenharmony_ci return -EFAULT; 18698c2ecf20Sopenharmony_ci } else 18708c2ecf20Sopenharmony_ci return -EINVAL; 18718c2ecf20Sopenharmony_ci break; 18728c2ecf20Sopenharmony_ci case ATYIO_CLKW: 18738c2ecf20Sopenharmony_ci if (M64_HAS(INTEGRATED)) { 18748c2ecf20Sopenharmony_ci struct atyclk clk; 18758c2ecf20Sopenharmony_ci union aty_pll *pll = &par->pll; 18768c2ecf20Sopenharmony_ci if (copy_from_user(&clk, (struct atyclk __user *) arg, 18778c2ecf20Sopenharmony_ci sizeof(clk))) 18788c2ecf20Sopenharmony_ci return -EFAULT; 18798c2ecf20Sopenharmony_ci par->ref_clk_per = clk.ref_clk_per; 18808c2ecf20Sopenharmony_ci pll->ct.pll_ref_div = clk.pll_ref_div; 18818c2ecf20Sopenharmony_ci pll->ct.mclk_fb_div = clk.mclk_fb_div; 18828c2ecf20Sopenharmony_ci pll->ct.mclk_post_div_real = clk.mclk_post_div; 18838c2ecf20Sopenharmony_ci pll->ct.mclk_fb_mult = clk.mclk_fb_mult; 18848c2ecf20Sopenharmony_ci pll->ct.xclk_post_div_real = clk.xclk_post_div; 18858c2ecf20Sopenharmony_ci pll->ct.vclk_fb_div = clk.vclk_fb_div; 18868c2ecf20Sopenharmony_ci pll->ct.vclk_post_div_real = clk.vclk_post_div; 18878c2ecf20Sopenharmony_ci pll->ct.dsp_config = (clk.dsp_xclks_per_row & 0x3fff) | 18888c2ecf20Sopenharmony_ci ((clk.dsp_loop_latency & 0xf) << 16) | 18898c2ecf20Sopenharmony_ci ((clk.dsp_precision & 7) << 20); 18908c2ecf20Sopenharmony_ci pll->ct.dsp_on_off = (clk.dsp_off & 0x7ff) | 18918c2ecf20Sopenharmony_ci ((clk.dsp_on & 0x7ff) << 16); 18928c2ecf20Sopenharmony_ci /*aty_calc_pll_ct(info, &pll->ct);*/ 18938c2ecf20Sopenharmony_ci aty_set_pll_ct(info, pll); 18948c2ecf20Sopenharmony_ci } else 18958c2ecf20Sopenharmony_ci return -EINVAL; 18968c2ecf20Sopenharmony_ci break; 18978c2ecf20Sopenharmony_ci case ATYIO_FEATR: 18988c2ecf20Sopenharmony_ci if (get_user(par->features, (u32 __user *) arg)) 18998c2ecf20Sopenharmony_ci return -EFAULT; 19008c2ecf20Sopenharmony_ci break; 19018c2ecf20Sopenharmony_ci case ATYIO_FEATW: 19028c2ecf20Sopenharmony_ci if (put_user(par->features, (u32 __user *) arg)) 19038c2ecf20Sopenharmony_ci return -EFAULT; 19048c2ecf20Sopenharmony_ci break; 19058c2ecf20Sopenharmony_ci#endif /* DEBUG && CONFIG_FB_ATY_CT */ 19068c2ecf20Sopenharmony_ci default: 19078c2ecf20Sopenharmony_ci return -EINVAL; 19088c2ecf20Sopenharmony_ci } 19098c2ecf20Sopenharmony_ci return 0; 19108c2ecf20Sopenharmony_ci} 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_cistatic int atyfb_sync(struct fb_info *info) 19138c2ecf20Sopenharmony_ci{ 19148c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci if (par->blitter_may_be_busy) 19178c2ecf20Sopenharmony_ci wait_for_idle(par); 19188c2ecf20Sopenharmony_ci return 0; 19198c2ecf20Sopenharmony_ci} 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci#ifdef __sparc__ 19228c2ecf20Sopenharmony_cistatic int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma) 19238c2ecf20Sopenharmony_ci{ 19248c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 19258c2ecf20Sopenharmony_ci unsigned int size, page, map_size = 0; 19268c2ecf20Sopenharmony_ci unsigned long map_offset = 0; 19278c2ecf20Sopenharmony_ci unsigned long off; 19288c2ecf20Sopenharmony_ci int i; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci if (!par->mmap_map) 19318c2ecf20Sopenharmony_ci return -ENXIO; 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) 19348c2ecf20Sopenharmony_ci return -EINVAL; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci off = vma->vm_pgoff << PAGE_SHIFT; 19378c2ecf20Sopenharmony_ci size = vma->vm_end - vma->vm_start; 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */ 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci if (((vma->vm_pgoff == 0) && (size == info->fix.smem_len)) || 19428c2ecf20Sopenharmony_ci ((off == info->fix.smem_len) && (size == PAGE_SIZE))) 19438c2ecf20Sopenharmony_ci off += 0x8000000000000000UL; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci vma->vm_pgoff = off >> PAGE_SHIFT; /* propagate off changes */ 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci /* Each page, see which map applies */ 19488c2ecf20Sopenharmony_ci for (page = 0; page < size;) { 19498c2ecf20Sopenharmony_ci map_size = 0; 19508c2ecf20Sopenharmony_ci for (i = 0; par->mmap_map[i].size; i++) { 19518c2ecf20Sopenharmony_ci unsigned long start = par->mmap_map[i].voff; 19528c2ecf20Sopenharmony_ci unsigned long end = start + par->mmap_map[i].size; 19538c2ecf20Sopenharmony_ci unsigned long offset = off + page; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci if (start > offset) 19568c2ecf20Sopenharmony_ci continue; 19578c2ecf20Sopenharmony_ci if (offset >= end) 19588c2ecf20Sopenharmony_ci continue; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci map_size = par->mmap_map[i].size - (offset - start); 19618c2ecf20Sopenharmony_ci map_offset = par->mmap_map[i].poff + (offset - start); 19628c2ecf20Sopenharmony_ci break; 19638c2ecf20Sopenharmony_ci } 19648c2ecf20Sopenharmony_ci if (!map_size) { 19658c2ecf20Sopenharmony_ci page += PAGE_SIZE; 19668c2ecf20Sopenharmony_ci continue; 19678c2ecf20Sopenharmony_ci } 19688c2ecf20Sopenharmony_ci if (page + map_size > size) 19698c2ecf20Sopenharmony_ci map_size = size - page; 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci pgprot_val(vma->vm_page_prot) &= ~(par->mmap_map[i].prot_mask); 19728c2ecf20Sopenharmony_ci pgprot_val(vma->vm_page_prot) |= par->mmap_map[i].prot_flag; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci if (remap_pfn_range(vma, vma->vm_start + page, 19758c2ecf20Sopenharmony_ci map_offset >> PAGE_SHIFT, map_size, vma->vm_page_prot)) 19768c2ecf20Sopenharmony_ci return -EAGAIN; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci page += map_size; 19798c2ecf20Sopenharmony_ci } 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci if (!map_size) 19828c2ecf20Sopenharmony_ci return -EINVAL; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci if (!par->mmaped) 19858c2ecf20Sopenharmony_ci par->mmaped = 1; 19868c2ecf20Sopenharmony_ci return 0; 19878c2ecf20Sopenharmony_ci} 19888c2ecf20Sopenharmony_ci#endif /* __sparc__ */ 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci#if defined(CONFIG_PCI) 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 19958c2ecf20Sopenharmony_ci/* Power management routines. Those are used for PowerBook sleep. 19968c2ecf20Sopenharmony_ci */ 19978c2ecf20Sopenharmony_cistatic int aty_power_mgmt(int sleep, struct atyfb_par *par) 19988c2ecf20Sopenharmony_ci{ 19998c2ecf20Sopenharmony_ci u32 pm; 20008c2ecf20Sopenharmony_ci int timeout; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci pm = aty_ld_lcd(POWER_MANAGEMENT, par); 20038c2ecf20Sopenharmony_ci pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; 20048c2ecf20Sopenharmony_ci aty_st_lcd(POWER_MANAGEMENT, pm, par); 20058c2ecf20Sopenharmony_ci pm = aty_ld_lcd(POWER_MANAGEMENT, par); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci timeout = 2000; 20088c2ecf20Sopenharmony_ci if (sleep) { 20098c2ecf20Sopenharmony_ci /* Sleep */ 20108c2ecf20Sopenharmony_ci pm &= ~PWR_MGT_ON; 20118c2ecf20Sopenharmony_ci aty_st_lcd(POWER_MANAGEMENT, pm, par); 20128c2ecf20Sopenharmony_ci pm = aty_ld_lcd(POWER_MANAGEMENT, par); 20138c2ecf20Sopenharmony_ci udelay(10); 20148c2ecf20Sopenharmony_ci pm &= ~(PWR_BLON | AUTO_PWR_UP); 20158c2ecf20Sopenharmony_ci pm |= SUSPEND_NOW; 20168c2ecf20Sopenharmony_ci aty_st_lcd(POWER_MANAGEMENT, pm, par); 20178c2ecf20Sopenharmony_ci pm = aty_ld_lcd(POWER_MANAGEMENT, par); 20188c2ecf20Sopenharmony_ci udelay(10); 20198c2ecf20Sopenharmony_ci pm |= PWR_MGT_ON; 20208c2ecf20Sopenharmony_ci aty_st_lcd(POWER_MANAGEMENT, pm, par); 20218c2ecf20Sopenharmony_ci do { 20228c2ecf20Sopenharmony_ci pm = aty_ld_lcd(POWER_MANAGEMENT, par); 20238c2ecf20Sopenharmony_ci mdelay(1); 20248c2ecf20Sopenharmony_ci if ((--timeout) == 0) 20258c2ecf20Sopenharmony_ci break; 20268c2ecf20Sopenharmony_ci } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); 20278c2ecf20Sopenharmony_ci } else { 20288c2ecf20Sopenharmony_ci /* Wakeup */ 20298c2ecf20Sopenharmony_ci pm &= ~PWR_MGT_ON; 20308c2ecf20Sopenharmony_ci aty_st_lcd(POWER_MANAGEMENT, pm, par); 20318c2ecf20Sopenharmony_ci pm = aty_ld_lcd(POWER_MANAGEMENT, par); 20328c2ecf20Sopenharmony_ci udelay(10); 20338c2ecf20Sopenharmony_ci pm &= ~SUSPEND_NOW; 20348c2ecf20Sopenharmony_ci pm |= (PWR_BLON | AUTO_PWR_UP); 20358c2ecf20Sopenharmony_ci aty_st_lcd(POWER_MANAGEMENT, pm, par); 20368c2ecf20Sopenharmony_ci pm = aty_ld_lcd(POWER_MANAGEMENT, par); 20378c2ecf20Sopenharmony_ci udelay(10); 20388c2ecf20Sopenharmony_ci pm |= PWR_MGT_ON; 20398c2ecf20Sopenharmony_ci aty_st_lcd(POWER_MANAGEMENT, pm, par); 20408c2ecf20Sopenharmony_ci do { 20418c2ecf20Sopenharmony_ci pm = aty_ld_lcd(POWER_MANAGEMENT, par); 20428c2ecf20Sopenharmony_ci mdelay(1); 20438c2ecf20Sopenharmony_ci if ((--timeout) == 0) 20448c2ecf20Sopenharmony_ci break; 20458c2ecf20Sopenharmony_ci } while ((pm & PWR_MGT_STATUS_MASK) != 0); 20468c2ecf20Sopenharmony_ci } 20478c2ecf20Sopenharmony_ci mdelay(500); 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci return timeout ? 0 : -EIO; 20508c2ecf20Sopenharmony_ci} 20518c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_PMAC */ 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_cistatic int atyfb_pci_suspend_late(struct device *dev, pm_message_t state) 20548c2ecf20Sopenharmony_ci{ 20558c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 20568c2ecf20Sopenharmony_ci struct fb_info *info = pci_get_drvdata(pdev); 20578c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci if (state.event == pdev->dev.power.power_state.event) 20608c2ecf20Sopenharmony_ci return 0; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci console_lock(); 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci fb_set_suspend(info, 1); 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci /* Idle & reset engine */ 20678c2ecf20Sopenharmony_ci wait_for_idle(par); 20688c2ecf20Sopenharmony_ci aty_reset_engine(par); 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci /* Blank display and LCD */ 20718c2ecf20Sopenharmony_ci atyfb_blank(FB_BLANK_POWERDOWN, info); 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci par->asleep = 1; 20748c2ecf20Sopenharmony_ci par->lock_blank = 1; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci /* 20778c2ecf20Sopenharmony_ci * Because we may change PCI D state ourselves, we need to 20788c2ecf20Sopenharmony_ci * first save the config space content so the core can 20798c2ecf20Sopenharmony_ci * restore it properly on resume. 20808c2ecf20Sopenharmony_ci */ 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 20838c2ecf20Sopenharmony_ci /* Set chip to "suspend" mode */ 20848c2ecf20Sopenharmony_ci if (machine_is(powermac) && aty_power_mgmt(1, par)) { 20858c2ecf20Sopenharmony_ci par->asleep = 0; 20868c2ecf20Sopenharmony_ci par->lock_blank = 0; 20878c2ecf20Sopenharmony_ci atyfb_blank(FB_BLANK_UNBLANK, info); 20888c2ecf20Sopenharmony_ci fb_set_suspend(info, 0); 20898c2ecf20Sopenharmony_ci console_unlock(); 20908c2ecf20Sopenharmony_ci return -EIO; 20918c2ecf20Sopenharmony_ci } 20928c2ecf20Sopenharmony_ci#endif 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci console_unlock(); 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci pdev->dev.power.power_state = state; 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci return 0; 20998c2ecf20Sopenharmony_ci} 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_cistatic int __maybe_unused atyfb_pci_suspend(struct device *dev) 21028c2ecf20Sopenharmony_ci{ 21038c2ecf20Sopenharmony_ci return atyfb_pci_suspend_late(dev, PMSG_SUSPEND); 21048c2ecf20Sopenharmony_ci} 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_cistatic int __maybe_unused atyfb_pci_hibernate(struct device *dev) 21078c2ecf20Sopenharmony_ci{ 21088c2ecf20Sopenharmony_ci return atyfb_pci_suspend_late(dev, PMSG_HIBERNATE); 21098c2ecf20Sopenharmony_ci} 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_cistatic int __maybe_unused atyfb_pci_freeze(struct device *dev) 21128c2ecf20Sopenharmony_ci{ 21138c2ecf20Sopenharmony_ci return atyfb_pci_suspend_late(dev, PMSG_FREEZE); 21148c2ecf20Sopenharmony_ci} 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_cistatic void aty_resume_chip(struct fb_info *info) 21178c2ecf20Sopenharmony_ci{ 21188c2ecf20Sopenharmony_ci struct atyfb_par *par = info->par; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci aty_st_le32(MEM_CNTL, par->mem_cntl, par); 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci if (par->pll_ops->resume_pll) 21238c2ecf20Sopenharmony_ci par->pll_ops->resume_pll(info, &par->pll); 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci if (par->aux_start) 21268c2ecf20Sopenharmony_ci aty_st_le32(BUS_CNTL, 21278c2ecf20Sopenharmony_ci aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par); 21288c2ecf20Sopenharmony_ci} 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_cistatic int __maybe_unused atyfb_pci_resume(struct device *dev) 21318c2ecf20Sopenharmony_ci{ 21328c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 21338c2ecf20Sopenharmony_ci struct fb_info *info = pci_get_drvdata(pdev); 21348c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci if (pdev->dev.power.power_state.event == PM_EVENT_ON) 21378c2ecf20Sopenharmony_ci return 0; 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci console_lock(); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci /* 21428c2ecf20Sopenharmony_ci * PCI state will have been restored by the core, so 21438c2ecf20Sopenharmony_ci * we should be in D0 now with our config space fully 21448c2ecf20Sopenharmony_ci * restored 21458c2ecf20Sopenharmony_ci */ 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 21488c2ecf20Sopenharmony_ci if (machine_is(powermac) && 21498c2ecf20Sopenharmony_ci pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) 21508c2ecf20Sopenharmony_ci aty_power_mgmt(0, par); 21518c2ecf20Sopenharmony_ci#endif 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci aty_resume_chip(info); 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci par->asleep = 0; 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci /* Restore display */ 21588c2ecf20Sopenharmony_ci atyfb_set_par(info); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci /* Refresh */ 21618c2ecf20Sopenharmony_ci fb_set_suspend(info, 0); 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci /* Unblank */ 21648c2ecf20Sopenharmony_ci par->lock_blank = 0; 21658c2ecf20Sopenharmony_ci atyfb_blank(FB_BLANK_UNBLANK, info); 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci console_unlock(); 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci pdev->dev.power.power_state = PMSG_ON; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci return 0; 21728c2ecf20Sopenharmony_ci} 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_cistatic const struct dev_pm_ops atyfb_pci_pm_ops = { 21758c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 21768c2ecf20Sopenharmony_ci .suspend = atyfb_pci_suspend, 21778c2ecf20Sopenharmony_ci .resume = atyfb_pci_resume, 21788c2ecf20Sopenharmony_ci .freeze = atyfb_pci_freeze, 21798c2ecf20Sopenharmony_ci .thaw = atyfb_pci_resume, 21808c2ecf20Sopenharmony_ci .poweroff = atyfb_pci_hibernate, 21818c2ecf20Sopenharmony_ci .restore = atyfb_pci_resume, 21828c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 21838c2ecf20Sopenharmony_ci}; 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci#endif /* defined(CONFIG_PCI) */ 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci/* Backlight */ 21888c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_BACKLIGHT 21898c2ecf20Sopenharmony_ci#define MAX_LEVEL 0xFF 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_cistatic int aty_bl_get_level_brightness(struct atyfb_par *par, int level) 21928c2ecf20Sopenharmony_ci{ 21938c2ecf20Sopenharmony_ci struct fb_info *info = pci_get_drvdata(par->pdev); 21948c2ecf20Sopenharmony_ci int atylevel; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci /* Get and convert the value */ 21978c2ecf20Sopenharmony_ci /* No locking of bl_curve since we read a single value */ 21988c2ecf20Sopenharmony_ci atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL; 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci if (atylevel < 0) 22018c2ecf20Sopenharmony_ci atylevel = 0; 22028c2ecf20Sopenharmony_ci else if (atylevel > MAX_LEVEL) 22038c2ecf20Sopenharmony_ci atylevel = MAX_LEVEL; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci return atylevel; 22068c2ecf20Sopenharmony_ci} 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_cistatic int aty_bl_update_status(struct backlight_device *bd) 22098c2ecf20Sopenharmony_ci{ 22108c2ecf20Sopenharmony_ci struct atyfb_par *par = bl_get_data(bd); 22118c2ecf20Sopenharmony_ci unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par); 22128c2ecf20Sopenharmony_ci int level; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci if (bd->props.power != FB_BLANK_UNBLANK || 22158c2ecf20Sopenharmony_ci bd->props.fb_blank != FB_BLANK_UNBLANK) 22168c2ecf20Sopenharmony_ci level = 0; 22178c2ecf20Sopenharmony_ci else 22188c2ecf20Sopenharmony_ci level = bd->props.brightness; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci reg |= (BLMOD_EN | BIASMOD_EN); 22218c2ecf20Sopenharmony_ci if (level > 0) { 22228c2ecf20Sopenharmony_ci reg &= ~BIAS_MOD_LEVEL_MASK; 22238c2ecf20Sopenharmony_ci reg |= (aty_bl_get_level_brightness(par, level) << BIAS_MOD_LEVEL_SHIFT); 22248c2ecf20Sopenharmony_ci } else { 22258c2ecf20Sopenharmony_ci reg &= ~BIAS_MOD_LEVEL_MASK; 22268c2ecf20Sopenharmony_ci reg |= (aty_bl_get_level_brightness(par, 0) << BIAS_MOD_LEVEL_SHIFT); 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci aty_st_lcd(LCD_MISC_CNTL, reg, par); 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci return 0; 22318c2ecf20Sopenharmony_ci} 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_cistatic const struct backlight_ops aty_bl_data = { 22348c2ecf20Sopenharmony_ci .update_status = aty_bl_update_status, 22358c2ecf20Sopenharmony_ci}; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_cistatic void aty_bl_init(struct atyfb_par *par) 22388c2ecf20Sopenharmony_ci{ 22398c2ecf20Sopenharmony_ci struct backlight_properties props; 22408c2ecf20Sopenharmony_ci struct fb_info *info = pci_get_drvdata(par->pdev); 22418c2ecf20Sopenharmony_ci struct backlight_device *bd; 22428c2ecf20Sopenharmony_ci char name[12]; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci#ifdef CONFIG_PMAC_BACKLIGHT 22458c2ecf20Sopenharmony_ci if (!pmac_has_backlight_type("ati")) 22468c2ecf20Sopenharmony_ci return; 22478c2ecf20Sopenharmony_ci#endif 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "atybl%d", info->node); 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci memset(&props, 0, sizeof(struct backlight_properties)); 22528c2ecf20Sopenharmony_ci props.type = BACKLIGHT_RAW; 22538c2ecf20Sopenharmony_ci props.max_brightness = FB_BACKLIGHT_LEVELS - 1; 22548c2ecf20Sopenharmony_ci bd = backlight_device_register(name, info->dev, par, &aty_bl_data, 22558c2ecf20Sopenharmony_ci &props); 22568c2ecf20Sopenharmony_ci if (IS_ERR(bd)) { 22578c2ecf20Sopenharmony_ci info->bl_dev = NULL; 22588c2ecf20Sopenharmony_ci printk(KERN_WARNING "aty: Backlight registration failed\n"); 22598c2ecf20Sopenharmony_ci goto error; 22608c2ecf20Sopenharmony_ci } 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci info->bl_dev = bd; 22638c2ecf20Sopenharmony_ci fb_bl_default_curve(info, 0, 22648c2ecf20Sopenharmony_ci 0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL, 22658c2ecf20Sopenharmony_ci 0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL); 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci bd->props.brightness = bd->props.max_brightness; 22688c2ecf20Sopenharmony_ci bd->props.power = FB_BLANK_UNBLANK; 22698c2ecf20Sopenharmony_ci backlight_update_status(bd); 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci printk("aty: Backlight initialized (%s)\n", name); 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci return; 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_cierror: 22768c2ecf20Sopenharmony_ci return; 22778c2ecf20Sopenharmony_ci} 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 22808c2ecf20Sopenharmony_cistatic void aty_bl_exit(struct backlight_device *bd) 22818c2ecf20Sopenharmony_ci{ 22828c2ecf20Sopenharmony_ci backlight_device_unregister(bd); 22838c2ecf20Sopenharmony_ci printk("aty: Backlight unloaded\n"); 22848c2ecf20Sopenharmony_ci} 22858c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_BACKLIGHT */ 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_cistatic void aty_calc_mem_refresh(struct atyfb_par *par, int xclk) 22908c2ecf20Sopenharmony_ci{ 22918c2ecf20Sopenharmony_ci static const int ragepro_tbl[] = { 22928c2ecf20Sopenharmony_ci 44, 50, 55, 66, 75, 80, 100 22938c2ecf20Sopenharmony_ci }; 22948c2ecf20Sopenharmony_ci static const int ragexl_tbl[] = { 22958c2ecf20Sopenharmony_ci 50, 66, 75, 83, 90, 95, 100, 105, 22968c2ecf20Sopenharmony_ci 110, 115, 120, 125, 133, 143, 166 22978c2ecf20Sopenharmony_ci }; 22988c2ecf20Sopenharmony_ci const int *refresh_tbl; 22998c2ecf20Sopenharmony_ci int i, size; 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci if (M64_HAS(XL_MEM)) { 23028c2ecf20Sopenharmony_ci refresh_tbl = ragexl_tbl; 23038c2ecf20Sopenharmony_ci size = ARRAY_SIZE(ragexl_tbl); 23048c2ecf20Sopenharmony_ci } else { 23058c2ecf20Sopenharmony_ci refresh_tbl = ragepro_tbl; 23068c2ecf20Sopenharmony_ci size = ARRAY_SIZE(ragepro_tbl); 23078c2ecf20Sopenharmony_ci } 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 23108c2ecf20Sopenharmony_ci if (xclk < refresh_tbl[i]) 23118c2ecf20Sopenharmony_ci break; 23128c2ecf20Sopenharmony_ci } 23138c2ecf20Sopenharmony_ci par->mem_refresh_rate = i; 23148c2ecf20Sopenharmony_ci} 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci/* 23178c2ecf20Sopenharmony_ci * Initialisation 23188c2ecf20Sopenharmony_ci */ 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_cistatic struct fb_info *fb_list = NULL; 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci#if defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) 23238c2ecf20Sopenharmony_cistatic int atyfb_get_timings_from_lcd(struct atyfb_par *par, 23248c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var) 23258c2ecf20Sopenharmony_ci{ 23268c2ecf20Sopenharmony_ci int ret = -EINVAL; 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci if (par->lcd_table != 0 && (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { 23298c2ecf20Sopenharmony_ci *var = default_var; 23308c2ecf20Sopenharmony_ci var->xres = var->xres_virtual = par->lcd_hdisp; 23318c2ecf20Sopenharmony_ci var->right_margin = par->lcd_right_margin; 23328c2ecf20Sopenharmony_ci var->left_margin = par->lcd_hblank_len - 23338c2ecf20Sopenharmony_ci (par->lcd_right_margin + par->lcd_hsync_dly + 23348c2ecf20Sopenharmony_ci par->lcd_hsync_len); 23358c2ecf20Sopenharmony_ci var->hsync_len = par->lcd_hsync_len + par->lcd_hsync_dly; 23368c2ecf20Sopenharmony_ci var->yres = var->yres_virtual = par->lcd_vdisp; 23378c2ecf20Sopenharmony_ci var->lower_margin = par->lcd_lower_margin; 23388c2ecf20Sopenharmony_ci var->upper_margin = par->lcd_vblank_len - 23398c2ecf20Sopenharmony_ci (par->lcd_lower_margin + par->lcd_vsync_len); 23408c2ecf20Sopenharmony_ci var->vsync_len = par->lcd_vsync_len; 23418c2ecf20Sopenharmony_ci var->pixclock = par->lcd_pixclock; 23428c2ecf20Sopenharmony_ci ret = 0; 23438c2ecf20Sopenharmony_ci } 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci return ret; 23468c2ecf20Sopenharmony_ci} 23478c2ecf20Sopenharmony_ci#endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */ 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_cistatic int aty_init(struct fb_info *info) 23508c2ecf20Sopenharmony_ci{ 23518c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 23528c2ecf20Sopenharmony_ci const char *ramname = NULL, *xtal; 23538c2ecf20Sopenharmony_ci int gtb_memsize, has_var = 0; 23548c2ecf20Sopenharmony_ci struct fb_var_screeninfo var; 23558c2ecf20Sopenharmony_ci int ret; 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci init_waitqueue_head(&par->vblank.wait); 23588c2ecf20Sopenharmony_ci spin_lock_init(&par->int_lock); 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GX 23618c2ecf20Sopenharmony_ci if (!M64_HAS(INTEGRATED)) { 23628c2ecf20Sopenharmony_ci u32 stat0; 23638c2ecf20Sopenharmony_ci u8 dac_type, dac_subtype, clk_type; 23648c2ecf20Sopenharmony_ci stat0 = aty_ld_le32(CNFG_STAT0, par); 23658c2ecf20Sopenharmony_ci par->bus_type = (stat0 >> 0) & 0x07; 23668c2ecf20Sopenharmony_ci par->ram_type = (stat0 >> 3) & 0x07; 23678c2ecf20Sopenharmony_ci ramname = aty_gx_ram[par->ram_type]; 23688c2ecf20Sopenharmony_ci /* FIXME: clockchip/RAMDAC probing? */ 23698c2ecf20Sopenharmony_ci dac_type = (aty_ld_le32(DAC_CNTL, par) >> 16) & 0x07; 23708c2ecf20Sopenharmony_ci#ifdef CONFIG_ATARI 23718c2ecf20Sopenharmony_ci clk_type = CLK_ATI18818_1; 23728c2ecf20Sopenharmony_ci dac_type = (stat0 >> 9) & 0x07; 23738c2ecf20Sopenharmony_ci if (dac_type == 0x07) 23748c2ecf20Sopenharmony_ci dac_subtype = DAC_ATT20C408; 23758c2ecf20Sopenharmony_ci else 23768c2ecf20Sopenharmony_ci dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, par) & 0xF0) | dac_type; 23778c2ecf20Sopenharmony_ci#else 23788c2ecf20Sopenharmony_ci dac_type = DAC_IBMRGB514; 23798c2ecf20Sopenharmony_ci dac_subtype = DAC_IBMRGB514; 23808c2ecf20Sopenharmony_ci clk_type = CLK_IBMRGB514; 23818c2ecf20Sopenharmony_ci#endif 23828c2ecf20Sopenharmony_ci switch (dac_subtype) { 23838c2ecf20Sopenharmony_ci case DAC_IBMRGB514: 23848c2ecf20Sopenharmony_ci par->dac_ops = &aty_dac_ibm514; 23858c2ecf20Sopenharmony_ci break; 23868c2ecf20Sopenharmony_ci#ifdef CONFIG_ATARI 23878c2ecf20Sopenharmony_ci case DAC_ATI68860_B: 23888c2ecf20Sopenharmony_ci case DAC_ATI68860_C: 23898c2ecf20Sopenharmony_ci par->dac_ops = &aty_dac_ati68860b; 23908c2ecf20Sopenharmony_ci break; 23918c2ecf20Sopenharmony_ci case DAC_ATT20C408: 23928c2ecf20Sopenharmony_ci case DAC_ATT21C498: 23938c2ecf20Sopenharmony_ci par->dac_ops = &aty_dac_att21c498; 23948c2ecf20Sopenharmony_ci break; 23958c2ecf20Sopenharmony_ci#endif 23968c2ecf20Sopenharmony_ci default: 23978c2ecf20Sopenharmony_ci PRINTKI("aty_init: DAC type not implemented yet!\n"); 23988c2ecf20Sopenharmony_ci par->dac_ops = &aty_dac_unsupported; 23998c2ecf20Sopenharmony_ci break; 24008c2ecf20Sopenharmony_ci } 24018c2ecf20Sopenharmony_ci switch (clk_type) { 24028c2ecf20Sopenharmony_ci#ifdef CONFIG_ATARI 24038c2ecf20Sopenharmony_ci case CLK_ATI18818_1: 24048c2ecf20Sopenharmony_ci par->pll_ops = &aty_pll_ati18818_1; 24058c2ecf20Sopenharmony_ci break; 24068c2ecf20Sopenharmony_ci#else 24078c2ecf20Sopenharmony_ci case CLK_IBMRGB514: 24088c2ecf20Sopenharmony_ci par->pll_ops = &aty_pll_ibm514; 24098c2ecf20Sopenharmony_ci break; 24108c2ecf20Sopenharmony_ci#endif 24118c2ecf20Sopenharmony_ci default: 24128c2ecf20Sopenharmony_ci PRINTKI("aty_init: CLK type not implemented yet!"); 24138c2ecf20Sopenharmony_ci par->pll_ops = &aty_pll_unsupported; 24148c2ecf20Sopenharmony_ci break; 24158c2ecf20Sopenharmony_ci } 24168c2ecf20Sopenharmony_ci } 24178c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_GX */ 24188c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_CT 24198c2ecf20Sopenharmony_ci if (M64_HAS(INTEGRATED)) { 24208c2ecf20Sopenharmony_ci par->dac_ops = &aty_dac_ct; 24218c2ecf20Sopenharmony_ci par->pll_ops = &aty_pll_ct; 24228c2ecf20Sopenharmony_ci par->bus_type = PCI; 24238c2ecf20Sopenharmony_ci par->ram_type = (aty_ld_le32(CNFG_STAT0, par) & 0x07); 24248c2ecf20Sopenharmony_ci if (M64_HAS(XL_MEM)) 24258c2ecf20Sopenharmony_ci ramname = aty_xl_ram[par->ram_type]; 24268c2ecf20Sopenharmony_ci else 24278c2ecf20Sopenharmony_ci ramname = aty_ct_ram[par->ram_type]; 24288c2ecf20Sopenharmony_ci /* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */ 24298c2ecf20Sopenharmony_ci if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM) 24308c2ecf20Sopenharmony_ci par->pll_limits.mclk = 63; 24318c2ecf20Sopenharmony_ci /* Mobility + 32bit memory interface need halved XCLK. */ 24328c2ecf20Sopenharmony_ci if (M64_HAS(MOBIL_BUS) && par->ram_type == SDRAM32) 24338c2ecf20Sopenharmony_ci par->pll_limits.xclk = (par->pll_limits.xclk + 1) >> 1; 24348c2ecf20Sopenharmony_ci } 24358c2ecf20Sopenharmony_ci#endif 24368c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 24378c2ecf20Sopenharmony_ci /* 24388c2ecf20Sopenharmony_ci * The Apple iBook1 uses non-standard memory frequencies. 24398c2ecf20Sopenharmony_ci * We detect it and set the frequency manually. 24408c2ecf20Sopenharmony_ci */ 24418c2ecf20Sopenharmony_ci if (of_machine_is_compatible("PowerBook2,1")) { 24428c2ecf20Sopenharmony_ci par->pll_limits.mclk = 70; 24438c2ecf20Sopenharmony_ci par->pll_limits.xclk = 53; 24448c2ecf20Sopenharmony_ci } 24458c2ecf20Sopenharmony_ci#endif 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci /* Allow command line to override clocks. */ 24488c2ecf20Sopenharmony_ci if (pll) 24498c2ecf20Sopenharmony_ci par->pll_limits.pll_max = pll; 24508c2ecf20Sopenharmony_ci if (mclk) 24518c2ecf20Sopenharmony_ci par->pll_limits.mclk = mclk; 24528c2ecf20Sopenharmony_ci if (xclk) 24538c2ecf20Sopenharmony_ci par->pll_limits.xclk = xclk; 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_ci aty_calc_mem_refresh(par, par->pll_limits.xclk); 24568c2ecf20Sopenharmony_ci par->pll_per = 1000000/par->pll_limits.pll_max; 24578c2ecf20Sopenharmony_ci par->mclk_per = 1000000/par->pll_limits.mclk; 24588c2ecf20Sopenharmony_ci par->xclk_per = 1000000/par->pll_limits.xclk; 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci par->ref_clk_per = 1000000000000ULL / 14318180; 24618c2ecf20Sopenharmony_ci xtal = "14.31818"; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_CT 24648c2ecf20Sopenharmony_ci if (M64_HAS(GTB_DSP)) { 24658c2ecf20Sopenharmony_ci u8 pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par); 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci if (pll_ref_div) { 24688c2ecf20Sopenharmony_ci int diff1, diff2; 24698c2ecf20Sopenharmony_ci diff1 = 510 * 14 / pll_ref_div - par->pll_limits.pll_max; 24708c2ecf20Sopenharmony_ci diff2 = 510 * 29 / pll_ref_div - par->pll_limits.pll_max; 24718c2ecf20Sopenharmony_ci if (diff1 < 0) 24728c2ecf20Sopenharmony_ci diff1 = -diff1; 24738c2ecf20Sopenharmony_ci if (diff2 < 0) 24748c2ecf20Sopenharmony_ci diff2 = -diff2; 24758c2ecf20Sopenharmony_ci if (diff2 < diff1) { 24768c2ecf20Sopenharmony_ci par->ref_clk_per = 1000000000000ULL / 29498928; 24778c2ecf20Sopenharmony_ci xtal = "29.498928"; 24788c2ecf20Sopenharmony_ci } 24798c2ecf20Sopenharmony_ci } 24808c2ecf20Sopenharmony_ci } 24818c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_CT */ 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci /* save previous video mode */ 24848c2ecf20Sopenharmony_ci aty_get_crtc(par, &par->saved_crtc); 24858c2ecf20Sopenharmony_ci if (par->pll_ops->get_pll) 24868c2ecf20Sopenharmony_ci par->pll_ops->get_pll(info, &par->saved_pll); 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci par->mem_cntl = aty_ld_le32(MEM_CNTL, par); 24898c2ecf20Sopenharmony_ci gtb_memsize = M64_HAS(GTB_DSP); 24908c2ecf20Sopenharmony_ci if (gtb_memsize) 24918c2ecf20Sopenharmony_ci /* 0xF used instead of MEM_SIZE_ALIAS */ 24928c2ecf20Sopenharmony_ci switch (par->mem_cntl & 0xF) { 24938c2ecf20Sopenharmony_ci case MEM_SIZE_512K: 24948c2ecf20Sopenharmony_ci info->fix.smem_len = 0x80000; 24958c2ecf20Sopenharmony_ci break; 24968c2ecf20Sopenharmony_ci case MEM_SIZE_1M: 24978c2ecf20Sopenharmony_ci info->fix.smem_len = 0x100000; 24988c2ecf20Sopenharmony_ci break; 24998c2ecf20Sopenharmony_ci case MEM_SIZE_2M_GTB: 25008c2ecf20Sopenharmony_ci info->fix.smem_len = 0x200000; 25018c2ecf20Sopenharmony_ci break; 25028c2ecf20Sopenharmony_ci case MEM_SIZE_4M_GTB: 25038c2ecf20Sopenharmony_ci info->fix.smem_len = 0x400000; 25048c2ecf20Sopenharmony_ci break; 25058c2ecf20Sopenharmony_ci case MEM_SIZE_6M_GTB: 25068c2ecf20Sopenharmony_ci info->fix.smem_len = 0x600000; 25078c2ecf20Sopenharmony_ci break; 25088c2ecf20Sopenharmony_ci case MEM_SIZE_8M_GTB: 25098c2ecf20Sopenharmony_ci info->fix.smem_len = 0x800000; 25108c2ecf20Sopenharmony_ci break; 25118c2ecf20Sopenharmony_ci default: 25128c2ecf20Sopenharmony_ci info->fix.smem_len = 0x80000; 25138c2ecf20Sopenharmony_ci } else 25148c2ecf20Sopenharmony_ci switch (par->mem_cntl & MEM_SIZE_ALIAS) { 25158c2ecf20Sopenharmony_ci case MEM_SIZE_512K: 25168c2ecf20Sopenharmony_ci info->fix.smem_len = 0x80000; 25178c2ecf20Sopenharmony_ci break; 25188c2ecf20Sopenharmony_ci case MEM_SIZE_1M: 25198c2ecf20Sopenharmony_ci info->fix.smem_len = 0x100000; 25208c2ecf20Sopenharmony_ci break; 25218c2ecf20Sopenharmony_ci case MEM_SIZE_2M: 25228c2ecf20Sopenharmony_ci info->fix.smem_len = 0x200000; 25238c2ecf20Sopenharmony_ci break; 25248c2ecf20Sopenharmony_ci case MEM_SIZE_4M: 25258c2ecf20Sopenharmony_ci info->fix.smem_len = 0x400000; 25268c2ecf20Sopenharmony_ci break; 25278c2ecf20Sopenharmony_ci case MEM_SIZE_6M: 25288c2ecf20Sopenharmony_ci info->fix.smem_len = 0x600000; 25298c2ecf20Sopenharmony_ci break; 25308c2ecf20Sopenharmony_ci case MEM_SIZE_8M: 25318c2ecf20Sopenharmony_ci info->fix.smem_len = 0x800000; 25328c2ecf20Sopenharmony_ci break; 25338c2ecf20Sopenharmony_ci default: 25348c2ecf20Sopenharmony_ci info->fix.smem_len = 0x80000; 25358c2ecf20Sopenharmony_ci } 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci if (M64_HAS(MAGIC_VRAM_SIZE)) { 25388c2ecf20Sopenharmony_ci if (aty_ld_le32(CNFG_STAT1, par) & 0x40000000) 25398c2ecf20Sopenharmony_ci info->fix.smem_len += 0x400000; 25408c2ecf20Sopenharmony_ci } 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci if (vram) { 25438c2ecf20Sopenharmony_ci info->fix.smem_len = vram * 1024; 25448c2ecf20Sopenharmony_ci par->mem_cntl &= ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS); 25458c2ecf20Sopenharmony_ci if (info->fix.smem_len <= 0x80000) 25468c2ecf20Sopenharmony_ci par->mem_cntl |= MEM_SIZE_512K; 25478c2ecf20Sopenharmony_ci else if (info->fix.smem_len <= 0x100000) 25488c2ecf20Sopenharmony_ci par->mem_cntl |= MEM_SIZE_1M; 25498c2ecf20Sopenharmony_ci else if (info->fix.smem_len <= 0x200000) 25508c2ecf20Sopenharmony_ci par->mem_cntl |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M; 25518c2ecf20Sopenharmony_ci else if (info->fix.smem_len <= 0x400000) 25528c2ecf20Sopenharmony_ci par->mem_cntl |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M; 25538c2ecf20Sopenharmony_ci else if (info->fix.smem_len <= 0x600000) 25548c2ecf20Sopenharmony_ci par->mem_cntl |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M; 25558c2ecf20Sopenharmony_ci else 25568c2ecf20Sopenharmony_ci par->mem_cntl |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M; 25578c2ecf20Sopenharmony_ci aty_st_le32(MEM_CNTL, par->mem_cntl, par); 25588c2ecf20Sopenharmony_ci } 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci /* 25618c2ecf20Sopenharmony_ci * Reg Block 0 (CT-compatible block) is at mmio_start 25628c2ecf20Sopenharmony_ci * Reg Block 1 (multimedia extensions) is at mmio_start - 0x400 25638c2ecf20Sopenharmony_ci */ 25648c2ecf20Sopenharmony_ci if (M64_HAS(GX)) { 25658c2ecf20Sopenharmony_ci info->fix.mmio_len = 0x400; 25668c2ecf20Sopenharmony_ci info->fix.accel = FB_ACCEL_ATI_MACH64GX; 25678c2ecf20Sopenharmony_ci } else if (M64_HAS(CT)) { 25688c2ecf20Sopenharmony_ci info->fix.mmio_len = 0x400; 25698c2ecf20Sopenharmony_ci info->fix.accel = FB_ACCEL_ATI_MACH64CT; 25708c2ecf20Sopenharmony_ci } else if (M64_HAS(VT)) { 25718c2ecf20Sopenharmony_ci info->fix.mmio_start -= 0x400; 25728c2ecf20Sopenharmony_ci info->fix.mmio_len = 0x800; 25738c2ecf20Sopenharmony_ci info->fix.accel = FB_ACCEL_ATI_MACH64VT; 25748c2ecf20Sopenharmony_ci } else {/* GT */ 25758c2ecf20Sopenharmony_ci info->fix.mmio_start -= 0x400; 25768c2ecf20Sopenharmony_ci info->fix.mmio_len = 0x800; 25778c2ecf20Sopenharmony_ci info->fix.accel = FB_ACCEL_ATI_MACH64GT; 25788c2ecf20Sopenharmony_ci } 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci PRINTKI("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK, %d MHz XCLK\n", 25818c2ecf20Sopenharmony_ci info->fix.smem_len == 0x80000 ? 512 : (info->fix.smem_len>>20), 25828c2ecf20Sopenharmony_ci info->fix.smem_len == 0x80000 ? 'K' : 'M', ramname, xtal, 25838c2ecf20Sopenharmony_ci par->pll_limits.pll_max, par->pll_limits.mclk, 25848c2ecf20Sopenharmony_ci par->pll_limits.xclk); 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci#if defined(DEBUG) && defined(CONFIG_FB_ATY_CT) 25878c2ecf20Sopenharmony_ci if (M64_HAS(INTEGRATED)) { 25888c2ecf20Sopenharmony_ci int i; 25898c2ecf20Sopenharmony_ci printk("debug atyfb: BUS_CNTL DAC_CNTL MEM_CNTL " 25908c2ecf20Sopenharmony_ci "EXT_MEM_CNTL CRTC_GEN_CNTL DSP_CONFIG " 25918c2ecf20Sopenharmony_ci "DSP_ON_OFF CLOCK_CNTL\n" 25928c2ecf20Sopenharmony_ci "debug atyfb: %08x %08x %08x " 25938c2ecf20Sopenharmony_ci "%08x %08x %08x " 25948c2ecf20Sopenharmony_ci "%08x %08x\n" 25958c2ecf20Sopenharmony_ci "debug atyfb: PLL", 25968c2ecf20Sopenharmony_ci aty_ld_le32(BUS_CNTL, par), 25978c2ecf20Sopenharmony_ci aty_ld_le32(DAC_CNTL, par), 25988c2ecf20Sopenharmony_ci aty_ld_le32(MEM_CNTL, par), 25998c2ecf20Sopenharmony_ci aty_ld_le32(EXT_MEM_CNTL, par), 26008c2ecf20Sopenharmony_ci aty_ld_le32(CRTC_GEN_CNTL, par), 26018c2ecf20Sopenharmony_ci aty_ld_le32(DSP_CONFIG, par), 26028c2ecf20Sopenharmony_ci aty_ld_le32(DSP_ON_OFF, par), 26038c2ecf20Sopenharmony_ci aty_ld_le32(CLOCK_CNTL, par)); 26048c2ecf20Sopenharmony_ci for (i = 0; i < 40; i++) 26058c2ecf20Sopenharmony_ci pr_cont(" %02x", aty_ld_pll_ct(i, par)); 26068c2ecf20Sopenharmony_ci pr_cont("\n"); 26078c2ecf20Sopenharmony_ci } 26088c2ecf20Sopenharmony_ci#endif 26098c2ecf20Sopenharmony_ci if (par->pll_ops->init_pll) 26108c2ecf20Sopenharmony_ci par->pll_ops->init_pll(info, &par->pll); 26118c2ecf20Sopenharmony_ci if (par->pll_ops->resume_pll) 26128c2ecf20Sopenharmony_ci par->pll_ops->resume_pll(info, &par->pll); 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci aty_fudge_framebuffer_len(info); 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci /* 26178c2ecf20Sopenharmony_ci * Disable register access through the linear aperture 26188c2ecf20Sopenharmony_ci * if the auxiliary aperture is used so we can access 26198c2ecf20Sopenharmony_ci * the full 8 MB of video RAM on 8 MB boards. 26208c2ecf20Sopenharmony_ci */ 26218c2ecf20Sopenharmony_ci if (par->aux_start) 26228c2ecf20Sopenharmony_ci aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) | 26238c2ecf20Sopenharmony_ci BUS_APER_REG_DIS, par); 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci if (!nomtrr) 26268c2ecf20Sopenharmony_ci /* 26278c2ecf20Sopenharmony_ci * Only the ioremap_wc()'d area will get WC here 26288c2ecf20Sopenharmony_ci * since ioremap_uc() was used on the entire PCI BAR. 26298c2ecf20Sopenharmony_ci */ 26308c2ecf20Sopenharmony_ci par->wc_cookie = arch_phys_wc_add(par->res_start, 26318c2ecf20Sopenharmony_ci par->res_size); 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci info->fbops = &atyfb_ops; 26348c2ecf20Sopenharmony_ci info->pseudo_palette = par->pseudo_palette; 26358c2ecf20Sopenharmony_ci info->flags = FBINFO_DEFAULT | 26368c2ecf20Sopenharmony_ci FBINFO_HWACCEL_IMAGEBLIT | 26378c2ecf20Sopenharmony_ci FBINFO_HWACCEL_FILLRECT | 26388c2ecf20Sopenharmony_ci FBINFO_HWACCEL_COPYAREA | 26398c2ecf20Sopenharmony_ci FBINFO_HWACCEL_YPAN | 26408c2ecf20Sopenharmony_ci FBINFO_READS_FAST; 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci#ifdef CONFIG_PMAC_BACKLIGHT 26438c2ecf20Sopenharmony_ci if (M64_HAS(G3_PB_1_1) && of_machine_is_compatible("PowerBook1,1")) { 26448c2ecf20Sopenharmony_ci /* 26458c2ecf20Sopenharmony_ci * these bits let the 101 powerbook 26468c2ecf20Sopenharmony_ci * wake up from sleep -- paulus 26478c2ecf20Sopenharmony_ci */ 26488c2ecf20Sopenharmony_ci aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par) | 26498c2ecf20Sopenharmony_ci USE_F32KHZ | TRISTATE_MEM_EN, par); 26508c2ecf20Sopenharmony_ci } else 26518c2ecf20Sopenharmony_ci#endif 26528c2ecf20Sopenharmony_ci if (M64_HAS(MOBIL_BUS) && backlight) { 26538c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_BACKLIGHT 26548c2ecf20Sopenharmony_ci aty_bl_init(par); 26558c2ecf20Sopenharmony_ci#endif 26568c2ecf20Sopenharmony_ci } 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci memset(&var, 0, sizeof(var)); 26598c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC 26608c2ecf20Sopenharmony_ci if (machine_is(powermac)) { 26618c2ecf20Sopenharmony_ci /* 26628c2ecf20Sopenharmony_ci * FIXME: The NVRAM stuff should be put in a Mac-specific file, 26638c2ecf20Sopenharmony_ci * as it applies to all Mac video cards 26648c2ecf20Sopenharmony_ci */ 26658c2ecf20Sopenharmony_ci if (mode) { 26668c2ecf20Sopenharmony_ci if (mac_find_mode(&var, info, mode, 8)) 26678c2ecf20Sopenharmony_ci has_var = 1; 26688c2ecf20Sopenharmony_ci } else { 26698c2ecf20Sopenharmony_ci if (default_vmode == VMODE_CHOOSE) { 26708c2ecf20Sopenharmony_ci int sense; 26718c2ecf20Sopenharmony_ci if (M64_HAS(G3_PB_1024x768)) 26728c2ecf20Sopenharmony_ci /* G3 PowerBook with 1024x768 LCD */ 26738c2ecf20Sopenharmony_ci default_vmode = VMODE_1024_768_60; 26748c2ecf20Sopenharmony_ci else if (of_machine_is_compatible("iMac")) 26758c2ecf20Sopenharmony_ci default_vmode = VMODE_1024_768_75; 26768c2ecf20Sopenharmony_ci else if (of_machine_is_compatible("PowerBook2,1")) 26778c2ecf20Sopenharmony_ci /* iBook with 800x600 LCD */ 26788c2ecf20Sopenharmony_ci default_vmode = VMODE_800_600_60; 26798c2ecf20Sopenharmony_ci else 26808c2ecf20Sopenharmony_ci default_vmode = VMODE_640_480_67; 26818c2ecf20Sopenharmony_ci sense = read_aty_sense(par); 26828c2ecf20Sopenharmony_ci PRINTKI("monitor sense=%x, mode %d\n", 26838c2ecf20Sopenharmony_ci sense, mac_map_monitor_sense(sense)); 26848c2ecf20Sopenharmony_ci } 26858c2ecf20Sopenharmony_ci if (default_vmode <= 0 || default_vmode > VMODE_MAX) 26868c2ecf20Sopenharmony_ci default_vmode = VMODE_640_480_60; 26878c2ecf20Sopenharmony_ci if (default_cmode < CMODE_8 || default_cmode > CMODE_32) 26888c2ecf20Sopenharmony_ci default_cmode = CMODE_8; 26898c2ecf20Sopenharmony_ci if (!mac_vmode_to_var(default_vmode, default_cmode, 26908c2ecf20Sopenharmony_ci &var)) 26918c2ecf20Sopenharmony_ci has_var = 1; 26928c2ecf20Sopenharmony_ci } 26938c2ecf20Sopenharmony_ci } 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci#endif /* !CONFIG_PPC */ 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci#if defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) 26988c2ecf20Sopenharmony_ci if (!atyfb_get_timings_from_lcd(par, &var)) 26998c2ecf20Sopenharmony_ci has_var = 1; 27008c2ecf20Sopenharmony_ci#endif 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci if (mode && fb_find_mode(&var, info, mode, NULL, 0, &defmode, 8)) 27038c2ecf20Sopenharmony_ci has_var = 1; 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci if (!has_var) 27068c2ecf20Sopenharmony_ci var = default_var; 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci if (noaccel) 27098c2ecf20Sopenharmony_ci var.accel_flags &= ~FB_ACCELF_TEXT; 27108c2ecf20Sopenharmony_ci else 27118c2ecf20Sopenharmony_ci var.accel_flags |= FB_ACCELF_TEXT; 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci if (comp_sync != -1) { 27148c2ecf20Sopenharmony_ci if (!comp_sync) 27158c2ecf20Sopenharmony_ci var.sync &= ~FB_SYNC_COMP_HIGH_ACT; 27168c2ecf20Sopenharmony_ci else 27178c2ecf20Sopenharmony_ci var.sync |= FB_SYNC_COMP_HIGH_ACT; 27188c2ecf20Sopenharmony_ci } 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_ci if (var.yres == var.yres_virtual) { 27218c2ecf20Sopenharmony_ci u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2)); 27228c2ecf20Sopenharmony_ci var.yres_virtual = ((videoram * 8) / var.bits_per_pixel) / var.xres_virtual; 27238c2ecf20Sopenharmony_ci if (var.yres_virtual < var.yres) 27248c2ecf20Sopenharmony_ci var.yres_virtual = var.yres; 27258c2ecf20Sopenharmony_ci } 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci ret = atyfb_check_var(&var, info); 27288c2ecf20Sopenharmony_ci if (ret) { 27298c2ecf20Sopenharmony_ci PRINTKE("can't set default video mode\n"); 27308c2ecf20Sopenharmony_ci goto aty_init_exit; 27318c2ecf20Sopenharmony_ci } 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_CT 27348c2ecf20Sopenharmony_ci if (!noaccel && M64_HAS(INTEGRATED)) 27358c2ecf20Sopenharmony_ci aty_init_cursor(info, &atyfb_ops); 27368c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_CT */ 27378c2ecf20Sopenharmony_ci info->var = var; 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci ret = fb_alloc_cmap(&info->cmap, 256, 0); 27408c2ecf20Sopenharmony_ci if (ret < 0) 27418c2ecf20Sopenharmony_ci goto aty_init_exit; 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci ret = register_framebuffer(info); 27448c2ecf20Sopenharmony_ci if (ret < 0) { 27458c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 27468c2ecf20Sopenharmony_ci goto aty_init_exit; 27478c2ecf20Sopenharmony_ci } 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci fb_list = info; 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_ci PRINTKI("fb%d: %s frame buffer device on %s\n", 27528c2ecf20Sopenharmony_ci info->node, info->fix.id, par->bus_type == ISA ? "ISA" : "PCI"); 27538c2ecf20Sopenharmony_ci return 0; 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ciaty_init_exit: 27568c2ecf20Sopenharmony_ci /* restore video mode */ 27578c2ecf20Sopenharmony_ci aty_set_crtc(par, &par->saved_crtc); 27588c2ecf20Sopenharmony_ci par->pll_ops->set_pll(info, &par->saved_pll); 27598c2ecf20Sopenharmony_ci arch_phys_wc_del(par->wc_cookie); 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci return ret; 27628c2ecf20Sopenharmony_ci} 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci#if defined(CONFIG_ATARI) && !defined(MODULE) 27658c2ecf20Sopenharmony_cistatic int store_video_par(char *video_str, unsigned char m64_num) 27668c2ecf20Sopenharmony_ci{ 27678c2ecf20Sopenharmony_ci char *p; 27688c2ecf20Sopenharmony_ci unsigned long vmembase, size, guiregbase; 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci PRINTKI("store_video_par() '%s' \n", video_str); 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci if (!(p = strsep(&video_str, ";")) || !*p) 27738c2ecf20Sopenharmony_ci goto mach64_invalid; 27748c2ecf20Sopenharmony_ci vmembase = simple_strtoul(p, NULL, 0); 27758c2ecf20Sopenharmony_ci if (!(p = strsep(&video_str, ";")) || !*p) 27768c2ecf20Sopenharmony_ci goto mach64_invalid; 27778c2ecf20Sopenharmony_ci size = simple_strtoul(p, NULL, 0); 27788c2ecf20Sopenharmony_ci if (!(p = strsep(&video_str, ";")) || !*p) 27798c2ecf20Sopenharmony_ci goto mach64_invalid; 27808c2ecf20Sopenharmony_ci guiregbase = simple_strtoul(p, NULL, 0); 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_ci phys_vmembase[m64_num] = vmembase; 27838c2ecf20Sopenharmony_ci phys_size[m64_num] = size; 27848c2ecf20Sopenharmony_ci phys_guiregbase[m64_num] = guiregbase; 27858c2ecf20Sopenharmony_ci PRINTKI("stored them all: $%08lX $%08lX $%08lX \n", vmembase, size, 27868c2ecf20Sopenharmony_ci guiregbase); 27878c2ecf20Sopenharmony_ci return 0; 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci mach64_invalid: 27908c2ecf20Sopenharmony_ci phys_vmembase[m64_num] = 0; 27918c2ecf20Sopenharmony_ci return -1; 27928c2ecf20Sopenharmony_ci} 27938c2ecf20Sopenharmony_ci#endif /* CONFIG_ATARI && !MODULE */ 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci/* 27968c2ecf20Sopenharmony_ci * Blank the display. 27978c2ecf20Sopenharmony_ci */ 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_cistatic int atyfb_blank(int blank, struct fb_info *info) 28008c2ecf20Sopenharmony_ci{ 28018c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 28028c2ecf20Sopenharmony_ci u32 gen_cntl; 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci if (par->lock_blank || par->asleep) 28058c2ecf20Sopenharmony_ci return 0; 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GENERIC_LCD 28088c2ecf20Sopenharmony_ci if (par->lcd_table && blank > FB_BLANK_NORMAL && 28098c2ecf20Sopenharmony_ci (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { 28108c2ecf20Sopenharmony_ci u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par); 28118c2ecf20Sopenharmony_ci pm &= ~PWR_BLON; 28128c2ecf20Sopenharmony_ci aty_st_lcd(POWER_MANAGEMENT, pm, par); 28138c2ecf20Sopenharmony_ci } 28148c2ecf20Sopenharmony_ci#endif 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par); 28178c2ecf20Sopenharmony_ci gen_cntl &= ~0x400004c; 28188c2ecf20Sopenharmony_ci switch (blank) { 28198c2ecf20Sopenharmony_ci case FB_BLANK_UNBLANK: 28208c2ecf20Sopenharmony_ci break; 28218c2ecf20Sopenharmony_ci case FB_BLANK_NORMAL: 28228c2ecf20Sopenharmony_ci gen_cntl |= 0x4000040; 28238c2ecf20Sopenharmony_ci break; 28248c2ecf20Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 28258c2ecf20Sopenharmony_ci gen_cntl |= 0x4000048; 28268c2ecf20Sopenharmony_ci break; 28278c2ecf20Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 28288c2ecf20Sopenharmony_ci gen_cntl |= 0x4000044; 28298c2ecf20Sopenharmony_ci break; 28308c2ecf20Sopenharmony_ci case FB_BLANK_POWERDOWN: 28318c2ecf20Sopenharmony_ci gen_cntl |= 0x400004c; 28328c2ecf20Sopenharmony_ci break; 28338c2ecf20Sopenharmony_ci } 28348c2ecf20Sopenharmony_ci aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par); 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GENERIC_LCD 28378c2ecf20Sopenharmony_ci if (par->lcd_table && blank <= FB_BLANK_NORMAL && 28388c2ecf20Sopenharmony_ci (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { 28398c2ecf20Sopenharmony_ci u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par); 28408c2ecf20Sopenharmony_ci pm |= PWR_BLON; 28418c2ecf20Sopenharmony_ci aty_st_lcd(POWER_MANAGEMENT, pm, par); 28428c2ecf20Sopenharmony_ci } 28438c2ecf20Sopenharmony_ci#endif 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_ci return 0; 28468c2ecf20Sopenharmony_ci} 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_cistatic void aty_st_pal(u_int regno, u_int red, u_int green, u_int blue, 28498c2ecf20Sopenharmony_ci const struct atyfb_par *par) 28508c2ecf20Sopenharmony_ci{ 28518c2ecf20Sopenharmony_ci aty_st_8(DAC_W_INDEX, regno, par); 28528c2ecf20Sopenharmony_ci aty_st_8(DAC_DATA, red, par); 28538c2ecf20Sopenharmony_ci aty_st_8(DAC_DATA, green, par); 28548c2ecf20Sopenharmony_ci aty_st_8(DAC_DATA, blue, par); 28558c2ecf20Sopenharmony_ci} 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci/* 28588c2ecf20Sopenharmony_ci * Set a single color register. The values supplied are already 28598c2ecf20Sopenharmony_ci * rounded down to the hardware's capabilities (according to the 28608c2ecf20Sopenharmony_ci * entries in the var structure). Return != 0 for invalid regno. 28618c2ecf20Sopenharmony_ci * !! 4 & 8 = PSEUDO, > 8 = DIRECTCOLOR 28628c2ecf20Sopenharmony_ci */ 28638c2ecf20Sopenharmony_ci 28648c2ecf20Sopenharmony_cistatic int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 28658c2ecf20Sopenharmony_ci u_int transp, struct fb_info *info) 28668c2ecf20Sopenharmony_ci{ 28678c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 28688c2ecf20Sopenharmony_ci int i, depth; 28698c2ecf20Sopenharmony_ci u32 *pal = info->pseudo_palette; 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci depth = info->var.bits_per_pixel; 28728c2ecf20Sopenharmony_ci if (depth == 16) 28738c2ecf20Sopenharmony_ci depth = (info->var.green.length == 5) ? 15 : 16; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci if (par->asleep) 28768c2ecf20Sopenharmony_ci return 0; 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci if (regno > 255 || 28798c2ecf20Sopenharmony_ci (depth == 16 && regno > 63) || 28808c2ecf20Sopenharmony_ci (depth == 15 && regno > 31)) 28818c2ecf20Sopenharmony_ci return 1; 28828c2ecf20Sopenharmony_ci 28838c2ecf20Sopenharmony_ci red >>= 8; 28848c2ecf20Sopenharmony_ci green >>= 8; 28858c2ecf20Sopenharmony_ci blue >>= 8; 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci par->palette[regno].red = red; 28888c2ecf20Sopenharmony_ci par->palette[regno].green = green; 28898c2ecf20Sopenharmony_ci par->palette[regno].blue = blue; 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ci if (regno < 16) { 28928c2ecf20Sopenharmony_ci switch (depth) { 28938c2ecf20Sopenharmony_ci case 15: 28948c2ecf20Sopenharmony_ci pal[regno] = (regno << 10) | (regno << 5) | regno; 28958c2ecf20Sopenharmony_ci break; 28968c2ecf20Sopenharmony_ci case 16: 28978c2ecf20Sopenharmony_ci pal[regno] = (regno << 11) | (regno << 5) | regno; 28988c2ecf20Sopenharmony_ci break; 28998c2ecf20Sopenharmony_ci case 24: 29008c2ecf20Sopenharmony_ci pal[regno] = (regno << 16) | (regno << 8) | regno; 29018c2ecf20Sopenharmony_ci break; 29028c2ecf20Sopenharmony_ci case 32: 29038c2ecf20Sopenharmony_ci i = (regno << 8) | regno; 29048c2ecf20Sopenharmony_ci pal[regno] = (i << 16) | i; 29058c2ecf20Sopenharmony_ci break; 29068c2ecf20Sopenharmony_ci } 29078c2ecf20Sopenharmony_ci } 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_ci i = aty_ld_8(DAC_CNTL, par) & 0xfc; 29108c2ecf20Sopenharmony_ci if (M64_HAS(EXTRA_BRIGHT)) 29118c2ecf20Sopenharmony_ci i |= 0x2; /* DAC_CNTL | 0x2 turns off the extra brightness for gt */ 29128c2ecf20Sopenharmony_ci aty_st_8(DAC_CNTL, i, par); 29138c2ecf20Sopenharmony_ci aty_st_8(DAC_MASK, 0xff, par); 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci if (M64_HAS(INTEGRATED)) { 29168c2ecf20Sopenharmony_ci if (depth == 16) { 29178c2ecf20Sopenharmony_ci if (regno < 32) 29188c2ecf20Sopenharmony_ci aty_st_pal(regno << 3, red, 29198c2ecf20Sopenharmony_ci par->palette[regno << 1].green, 29208c2ecf20Sopenharmony_ci blue, par); 29218c2ecf20Sopenharmony_ci red = par->palette[regno >> 1].red; 29228c2ecf20Sopenharmony_ci blue = par->palette[regno >> 1].blue; 29238c2ecf20Sopenharmony_ci regno <<= 2; 29248c2ecf20Sopenharmony_ci } else if (depth == 15) { 29258c2ecf20Sopenharmony_ci regno <<= 3; 29268c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 29278c2ecf20Sopenharmony_ci aty_st_pal(regno + i, red, green, blue, par); 29288c2ecf20Sopenharmony_ci } 29298c2ecf20Sopenharmony_ci } 29308c2ecf20Sopenharmony_ci aty_st_pal(regno, red, green, blue, par); 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_ci return 0; 29338c2ecf20Sopenharmony_ci} 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci#ifdef __sparc__ 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_cistatic int atyfb_setup_sparc(struct pci_dev *pdev, struct fb_info *info, 29408c2ecf20Sopenharmony_ci unsigned long addr) 29418c2ecf20Sopenharmony_ci{ 29428c2ecf20Sopenharmony_ci struct atyfb_par *par = info->par; 29438c2ecf20Sopenharmony_ci struct device_node *dp; 29448c2ecf20Sopenharmony_ci u32 mem, chip_id; 29458c2ecf20Sopenharmony_ci int i, j, ret; 29468c2ecf20Sopenharmony_ci 29478c2ecf20Sopenharmony_ci /* 29488c2ecf20Sopenharmony_ci * Map memory-mapped registers. 29498c2ecf20Sopenharmony_ci */ 29508c2ecf20Sopenharmony_ci par->ati_regbase = (void *)addr + 0x7ffc00UL; 29518c2ecf20Sopenharmony_ci info->fix.mmio_start = addr + 0x7ffc00UL; 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci /* 29548c2ecf20Sopenharmony_ci * Map in big-endian aperture. 29558c2ecf20Sopenharmony_ci */ 29568c2ecf20Sopenharmony_ci info->screen_base = (char *) (addr + 0x800000UL); 29578c2ecf20Sopenharmony_ci info->fix.smem_start = addr + 0x800000UL; 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_ci /* 29608c2ecf20Sopenharmony_ci * Figure mmap addresses from PCI config space. 29618c2ecf20Sopenharmony_ci * Split Framebuffer in big- and little-endian halfs. 29628c2ecf20Sopenharmony_ci */ 29638c2ecf20Sopenharmony_ci for (i = 0; i < 6 && pdev->resource[i].start; i++) 29648c2ecf20Sopenharmony_ci /* nothing */ ; 29658c2ecf20Sopenharmony_ci j = i + 4; 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci par->mmap_map = kcalloc(j, sizeof(*par->mmap_map), GFP_ATOMIC); 29688c2ecf20Sopenharmony_ci if (!par->mmap_map) { 29698c2ecf20Sopenharmony_ci PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n"); 29708c2ecf20Sopenharmony_ci return -ENOMEM; 29718c2ecf20Sopenharmony_ci } 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) { 29748c2ecf20Sopenharmony_ci struct resource *rp = &pdev->resource[i]; 29758c2ecf20Sopenharmony_ci int io, breg = PCI_BASE_ADDRESS_0 + (i << 2); 29768c2ecf20Sopenharmony_ci unsigned long base; 29778c2ecf20Sopenharmony_ci u32 size, pbase; 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_ci base = rp->start; 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci io = (rp->flags & IORESOURCE_IO); 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci size = rp->end - base + 1; 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, breg, &pbase); 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci if (io) 29888c2ecf20Sopenharmony_ci size &= ~1; 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci /* 29918c2ecf20Sopenharmony_ci * Map the framebuffer a second time, this time without 29928c2ecf20Sopenharmony_ci * the braindead _PAGE_IE setting. This is used by the 29938c2ecf20Sopenharmony_ci * fixed Xserver, but we need to maintain the old mapping 29948c2ecf20Sopenharmony_ci * to stay compatible with older ones... 29958c2ecf20Sopenharmony_ci */ 29968c2ecf20Sopenharmony_ci if (base == addr) { 29978c2ecf20Sopenharmony_ci par->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK; 29988c2ecf20Sopenharmony_ci par->mmap_map[j].poff = base & PAGE_MASK; 29998c2ecf20Sopenharmony_ci par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK; 30008c2ecf20Sopenharmony_ci par->mmap_map[j].prot_mask = _PAGE_CACHE; 30018c2ecf20Sopenharmony_ci par->mmap_map[j].prot_flag = _PAGE_E; 30028c2ecf20Sopenharmony_ci j++; 30038c2ecf20Sopenharmony_ci } 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_ci /* 30068c2ecf20Sopenharmony_ci * Here comes the old framebuffer mapping with _PAGE_IE 30078c2ecf20Sopenharmony_ci * set for the big endian half of the framebuffer... 30088c2ecf20Sopenharmony_ci */ 30098c2ecf20Sopenharmony_ci if (base == addr) { 30108c2ecf20Sopenharmony_ci par->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK; 30118c2ecf20Sopenharmony_ci par->mmap_map[j].poff = (base + 0x800000) & PAGE_MASK; 30128c2ecf20Sopenharmony_ci par->mmap_map[j].size = 0x800000; 30138c2ecf20Sopenharmony_ci par->mmap_map[j].prot_mask = _PAGE_CACHE; 30148c2ecf20Sopenharmony_ci par->mmap_map[j].prot_flag = _PAGE_E | _PAGE_IE; 30158c2ecf20Sopenharmony_ci size -= 0x800000; 30168c2ecf20Sopenharmony_ci j++; 30178c2ecf20Sopenharmony_ci } 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci par->mmap_map[j].voff = pbase & PAGE_MASK; 30208c2ecf20Sopenharmony_ci par->mmap_map[j].poff = base & PAGE_MASK; 30218c2ecf20Sopenharmony_ci par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK; 30228c2ecf20Sopenharmony_ci par->mmap_map[j].prot_mask = _PAGE_CACHE; 30238c2ecf20Sopenharmony_ci par->mmap_map[j].prot_flag = _PAGE_E; 30248c2ecf20Sopenharmony_ci j++; 30258c2ecf20Sopenharmony_ci } 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci ret = correct_chipset(par); 30288c2ecf20Sopenharmony_ci if (ret) 30298c2ecf20Sopenharmony_ci return ret; 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci if (IS_XL(pdev->device)) { 30328c2ecf20Sopenharmony_ci /* 30338c2ecf20Sopenharmony_ci * Fix PROMs idea of MEM_CNTL settings... 30348c2ecf20Sopenharmony_ci */ 30358c2ecf20Sopenharmony_ci mem = aty_ld_le32(MEM_CNTL, par); 30368c2ecf20Sopenharmony_ci chip_id = aty_ld_le32(CNFG_CHIP_ID, par); 30378c2ecf20Sopenharmony_ci if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && !((chip_id >> 24) & 1)) { 30388c2ecf20Sopenharmony_ci switch (mem & 0x0f) { 30398c2ecf20Sopenharmony_ci case 3: 30408c2ecf20Sopenharmony_ci mem = (mem & ~(0x0f)) | 2; 30418c2ecf20Sopenharmony_ci break; 30428c2ecf20Sopenharmony_ci case 7: 30438c2ecf20Sopenharmony_ci mem = (mem & ~(0x0f)) | 3; 30448c2ecf20Sopenharmony_ci break; 30458c2ecf20Sopenharmony_ci case 9: 30468c2ecf20Sopenharmony_ci mem = (mem & ~(0x0f)) | 4; 30478c2ecf20Sopenharmony_ci break; 30488c2ecf20Sopenharmony_ci case 11: 30498c2ecf20Sopenharmony_ci mem = (mem & ~(0x0f)) | 5; 30508c2ecf20Sopenharmony_ci break; 30518c2ecf20Sopenharmony_ci default: 30528c2ecf20Sopenharmony_ci break; 30538c2ecf20Sopenharmony_ci } 30548c2ecf20Sopenharmony_ci if ((aty_ld_le32(CNFG_STAT0, par) & 7) >= SDRAM) 30558c2ecf20Sopenharmony_ci mem &= ~(0x00700000); 30568c2ecf20Sopenharmony_ci } 30578c2ecf20Sopenharmony_ci mem &= ~(0xcf80e000); /* Turn off all undocumented bits. */ 30588c2ecf20Sopenharmony_ci aty_st_le32(MEM_CNTL, mem, par); 30598c2ecf20Sopenharmony_ci } 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_ci dp = pci_device_to_OF_node(pdev); 30628c2ecf20Sopenharmony_ci if (dp == of_console_device) { 30638c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var = &default_var; 30648c2ecf20Sopenharmony_ci unsigned int N, P, Q, M, T, R; 30658c2ecf20Sopenharmony_ci u32 v_total, h_total; 30668c2ecf20Sopenharmony_ci struct crtc crtc; 30678c2ecf20Sopenharmony_ci u8 pll_regs[16]; 30688c2ecf20Sopenharmony_ci u8 clock_cntl; 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci crtc.vxres = of_getintprop_default(dp, "width", 1024); 30718c2ecf20Sopenharmony_ci crtc.vyres = of_getintprop_default(dp, "height", 768); 30728c2ecf20Sopenharmony_ci var->bits_per_pixel = of_getintprop_default(dp, "depth", 8); 30738c2ecf20Sopenharmony_ci var->xoffset = var->yoffset = 0; 30748c2ecf20Sopenharmony_ci crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par); 30758c2ecf20Sopenharmony_ci crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par); 30768c2ecf20Sopenharmony_ci crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par); 30778c2ecf20Sopenharmony_ci crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par); 30788c2ecf20Sopenharmony_ci crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par); 30798c2ecf20Sopenharmony_ci aty_crtc_to_var(&crtc, var); 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci h_total = var->xres + var->right_margin + var->hsync_len + var->left_margin; 30828c2ecf20Sopenharmony_ci v_total = var->yres + var->lower_margin + var->vsync_len + var->upper_margin; 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ci /* 30858c2ecf20Sopenharmony_ci * Read the PLL to figure actual Refresh Rate. 30868c2ecf20Sopenharmony_ci */ 30878c2ecf20Sopenharmony_ci clock_cntl = aty_ld_8(CLOCK_CNTL, par); 30888c2ecf20Sopenharmony_ci /* DPRINTK("CLOCK_CNTL %02x\n", clock_cntl); */ 30898c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 30908c2ecf20Sopenharmony_ci pll_regs[i] = aty_ld_pll_ct(i, par); 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci /* 30938c2ecf20Sopenharmony_ci * PLL Reference Divider M: 30948c2ecf20Sopenharmony_ci */ 30958c2ecf20Sopenharmony_ci M = pll_regs[PLL_REF_DIV]; 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci /* 30988c2ecf20Sopenharmony_ci * PLL Feedback Divider N (Dependent on CLOCK_CNTL): 30998c2ecf20Sopenharmony_ci */ 31008c2ecf20Sopenharmony_ci N = pll_regs[VCLK0_FB_DIV + (clock_cntl & 3)]; 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci /* 31038c2ecf20Sopenharmony_ci * PLL Post Divider P (Dependent on CLOCK_CNTL): 31048c2ecf20Sopenharmony_ci */ 31058c2ecf20Sopenharmony_ci P = aty_postdividers[((pll_regs[VCLK_POST_DIV] >> ((clock_cntl & 3) << 1)) & 3) | 31068c2ecf20Sopenharmony_ci ((pll_regs[PLL_EXT_CNTL] >> (2 + (clock_cntl & 3))) & 4)]; 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_ci /* 31098c2ecf20Sopenharmony_ci * PLL Divider Q: 31108c2ecf20Sopenharmony_ci */ 31118c2ecf20Sopenharmony_ci Q = N / P; 31128c2ecf20Sopenharmony_ci 31138c2ecf20Sopenharmony_ci /* 31148c2ecf20Sopenharmony_ci * Target Frequency: 31158c2ecf20Sopenharmony_ci * 31168c2ecf20Sopenharmony_ci * T * M 31178c2ecf20Sopenharmony_ci * Q = ------- 31188c2ecf20Sopenharmony_ci * 2 * R 31198c2ecf20Sopenharmony_ci * 31208c2ecf20Sopenharmony_ci * where R is XTALIN (= 14318 or 29498 kHz). 31218c2ecf20Sopenharmony_ci */ 31228c2ecf20Sopenharmony_ci if (IS_XL(pdev->device)) 31238c2ecf20Sopenharmony_ci R = 29498; 31248c2ecf20Sopenharmony_ci else 31258c2ecf20Sopenharmony_ci R = 14318; 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci T = 2 * Q * R / M; 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_ci default_var.pixclock = 1000000000 / T; 31308c2ecf20Sopenharmony_ci } 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_ci return 0; 31338c2ecf20Sopenharmony_ci} 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci#else /* __sparc__ */ 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_ci#ifdef __i386__ 31388c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GENERIC_LCD 31398c2ecf20Sopenharmony_cistatic void aty_init_lcd(struct atyfb_par *par, u32 bios_base) 31408c2ecf20Sopenharmony_ci{ 31418c2ecf20Sopenharmony_ci u32 driv_inf_tab, sig; 31428c2ecf20Sopenharmony_ci u16 lcd_ofs; 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_ci /* 31458c2ecf20Sopenharmony_ci * To support an LCD panel, we should know it's dimensions and 31468c2ecf20Sopenharmony_ci * it's desired pixel clock. 31478c2ecf20Sopenharmony_ci * There are two ways to do it: 31488c2ecf20Sopenharmony_ci * - Check the startup video mode and calculate the panel 31498c2ecf20Sopenharmony_ci * size from it. This is unreliable. 31508c2ecf20Sopenharmony_ci * - Read it from the driver information table in the video BIOS. 31518c2ecf20Sopenharmony_ci */ 31528c2ecf20Sopenharmony_ci /* Address of driver information table is at offset 0x78. */ 31538c2ecf20Sopenharmony_ci driv_inf_tab = bios_base + *((u16 *)(bios_base+0x78)); 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_ci /* Check for the driver information table signature. */ 31568c2ecf20Sopenharmony_ci sig = *(u32 *)driv_inf_tab; 31578c2ecf20Sopenharmony_ci if ((sig == 0x54504c24) || /* Rage LT pro */ 31588c2ecf20Sopenharmony_ci (sig == 0x544d5224) || /* Rage mobility */ 31598c2ecf20Sopenharmony_ci (sig == 0x54435824) || /* Rage XC */ 31608c2ecf20Sopenharmony_ci (sig == 0x544c5824)) { /* Rage XL */ 31618c2ecf20Sopenharmony_ci PRINTKI("BIOS contains driver information table.\n"); 31628c2ecf20Sopenharmony_ci lcd_ofs = *(u16 *)(driv_inf_tab + 10); 31638c2ecf20Sopenharmony_ci par->lcd_table = 0; 31648c2ecf20Sopenharmony_ci if (lcd_ofs != 0) 31658c2ecf20Sopenharmony_ci par->lcd_table = bios_base + lcd_ofs; 31668c2ecf20Sopenharmony_ci } 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_ci if (par->lcd_table != 0) { 31698c2ecf20Sopenharmony_ci char model[24]; 31708c2ecf20Sopenharmony_ci char strbuf[16]; 31718c2ecf20Sopenharmony_ci char refresh_rates_buf[100]; 31728c2ecf20Sopenharmony_ci int id, tech, f, i, m, default_refresh_rate; 31738c2ecf20Sopenharmony_ci char *txtcolour; 31748c2ecf20Sopenharmony_ci char *txtmonitor; 31758c2ecf20Sopenharmony_ci char *txtdual; 31768c2ecf20Sopenharmony_ci char *txtformat; 31778c2ecf20Sopenharmony_ci u16 width, height, panel_type, refresh_rates; 31788c2ecf20Sopenharmony_ci u16 *lcdmodeptr; 31798c2ecf20Sopenharmony_ci u32 format; 31808c2ecf20Sopenharmony_ci u8 lcd_refresh_rates[16] = { 50, 56, 60, 67, 70, 72, 75, 76, 85, 31818c2ecf20Sopenharmony_ci 90, 100, 120, 140, 150, 160, 200 }; 31828c2ecf20Sopenharmony_ci /* 31838c2ecf20Sopenharmony_ci * The most important information is the panel size at 31848c2ecf20Sopenharmony_ci * offset 25 and 27, but there's some other nice information 31858c2ecf20Sopenharmony_ci * which we print to the screen. 31868c2ecf20Sopenharmony_ci */ 31878c2ecf20Sopenharmony_ci id = *(u8 *)par->lcd_table; 31888c2ecf20Sopenharmony_ci strncpy(model, (char *)par->lcd_table+1, 24); 31898c2ecf20Sopenharmony_ci model[23] = 0; 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_ci width = par->lcd_width = *(u16 *)(par->lcd_table+25); 31928c2ecf20Sopenharmony_ci height = par->lcd_height = *(u16 *)(par->lcd_table+27); 31938c2ecf20Sopenharmony_ci panel_type = *(u16 *)(par->lcd_table+29); 31948c2ecf20Sopenharmony_ci if (panel_type & 1) 31958c2ecf20Sopenharmony_ci txtcolour = "colour"; 31968c2ecf20Sopenharmony_ci else 31978c2ecf20Sopenharmony_ci txtcolour = "monochrome"; 31988c2ecf20Sopenharmony_ci if (panel_type & 2) 31998c2ecf20Sopenharmony_ci txtdual = "dual (split) "; 32008c2ecf20Sopenharmony_ci else 32018c2ecf20Sopenharmony_ci txtdual = ""; 32028c2ecf20Sopenharmony_ci tech = (panel_type >> 2) & 63; 32038c2ecf20Sopenharmony_ci switch (tech) { 32048c2ecf20Sopenharmony_ci case 0: 32058c2ecf20Sopenharmony_ci txtmonitor = "passive matrix"; 32068c2ecf20Sopenharmony_ci break; 32078c2ecf20Sopenharmony_ci case 1: 32088c2ecf20Sopenharmony_ci txtmonitor = "active matrix"; 32098c2ecf20Sopenharmony_ci break; 32108c2ecf20Sopenharmony_ci case 2: 32118c2ecf20Sopenharmony_ci txtmonitor = "active addressed STN"; 32128c2ecf20Sopenharmony_ci break; 32138c2ecf20Sopenharmony_ci case 3: 32148c2ecf20Sopenharmony_ci txtmonitor = "EL"; 32158c2ecf20Sopenharmony_ci break; 32168c2ecf20Sopenharmony_ci case 4: 32178c2ecf20Sopenharmony_ci txtmonitor = "plasma"; 32188c2ecf20Sopenharmony_ci break; 32198c2ecf20Sopenharmony_ci default: 32208c2ecf20Sopenharmony_ci txtmonitor = "unknown"; 32218c2ecf20Sopenharmony_ci } 32228c2ecf20Sopenharmony_ci format = *(u32 *)(par->lcd_table+57); 32238c2ecf20Sopenharmony_ci if (tech == 0 || tech == 2) { 32248c2ecf20Sopenharmony_ci switch (format & 7) { 32258c2ecf20Sopenharmony_ci case 0: 32268c2ecf20Sopenharmony_ci txtformat = "12 bit interface"; 32278c2ecf20Sopenharmony_ci break; 32288c2ecf20Sopenharmony_ci case 1: 32298c2ecf20Sopenharmony_ci txtformat = "16 bit interface"; 32308c2ecf20Sopenharmony_ci break; 32318c2ecf20Sopenharmony_ci case 2: 32328c2ecf20Sopenharmony_ci txtformat = "24 bit interface"; 32338c2ecf20Sopenharmony_ci break; 32348c2ecf20Sopenharmony_ci default: 32358c2ecf20Sopenharmony_ci txtformat = "unknown format"; 32368c2ecf20Sopenharmony_ci } 32378c2ecf20Sopenharmony_ci } else { 32388c2ecf20Sopenharmony_ci switch (format & 7) { 32398c2ecf20Sopenharmony_ci case 0: 32408c2ecf20Sopenharmony_ci txtformat = "8 colours"; 32418c2ecf20Sopenharmony_ci break; 32428c2ecf20Sopenharmony_ci case 1: 32438c2ecf20Sopenharmony_ci txtformat = "512 colours"; 32448c2ecf20Sopenharmony_ci break; 32458c2ecf20Sopenharmony_ci case 2: 32468c2ecf20Sopenharmony_ci txtformat = "4096 colours"; 32478c2ecf20Sopenharmony_ci break; 32488c2ecf20Sopenharmony_ci case 4: 32498c2ecf20Sopenharmony_ci txtformat = "262144 colours (LT mode)"; 32508c2ecf20Sopenharmony_ci break; 32518c2ecf20Sopenharmony_ci case 5: 32528c2ecf20Sopenharmony_ci txtformat = "16777216 colours"; 32538c2ecf20Sopenharmony_ci break; 32548c2ecf20Sopenharmony_ci case 6: 32558c2ecf20Sopenharmony_ci txtformat = "262144 colours (FDPI-2 mode)"; 32568c2ecf20Sopenharmony_ci break; 32578c2ecf20Sopenharmony_ci default: 32588c2ecf20Sopenharmony_ci txtformat = "unknown format"; 32598c2ecf20Sopenharmony_ci } 32608c2ecf20Sopenharmony_ci } 32618c2ecf20Sopenharmony_ci PRINTKI("%s%s %s monitor detected: %s\n", 32628c2ecf20Sopenharmony_ci txtdual, txtcolour, txtmonitor, model); 32638c2ecf20Sopenharmony_ci PRINTKI(" id=%d, %dx%d pixels, %s\n", 32648c2ecf20Sopenharmony_ci id, width, height, txtformat); 32658c2ecf20Sopenharmony_ci refresh_rates_buf[0] = 0; 32668c2ecf20Sopenharmony_ci refresh_rates = *(u16 *)(par->lcd_table+62); 32678c2ecf20Sopenharmony_ci m = 1; 32688c2ecf20Sopenharmony_ci f = 0; 32698c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 32708c2ecf20Sopenharmony_ci if (refresh_rates & m) { 32718c2ecf20Sopenharmony_ci if (f == 0) { 32728c2ecf20Sopenharmony_ci sprintf(strbuf, "%d", 32738c2ecf20Sopenharmony_ci lcd_refresh_rates[i]); 32748c2ecf20Sopenharmony_ci f++; 32758c2ecf20Sopenharmony_ci } else { 32768c2ecf20Sopenharmony_ci sprintf(strbuf, ",%d", 32778c2ecf20Sopenharmony_ci lcd_refresh_rates[i]); 32788c2ecf20Sopenharmony_ci } 32798c2ecf20Sopenharmony_ci strcat(refresh_rates_buf, strbuf); 32808c2ecf20Sopenharmony_ci } 32818c2ecf20Sopenharmony_ci m = m << 1; 32828c2ecf20Sopenharmony_ci } 32838c2ecf20Sopenharmony_ci default_refresh_rate = (*(u8 *)(par->lcd_table+61) & 0xf0) >> 4; 32848c2ecf20Sopenharmony_ci PRINTKI(" supports refresh rates [%s], default %d Hz\n", 32858c2ecf20Sopenharmony_ci refresh_rates_buf, lcd_refresh_rates[default_refresh_rate]); 32868c2ecf20Sopenharmony_ci par->lcd_refreshrate = lcd_refresh_rates[default_refresh_rate]; 32878c2ecf20Sopenharmony_ci /* 32888c2ecf20Sopenharmony_ci * We now need to determine the crtc parameters for the 32898c2ecf20Sopenharmony_ci * LCD monitor. This is tricky, because they are not stored 32908c2ecf20Sopenharmony_ci * individually in the BIOS. Instead, the BIOS contains a 32918c2ecf20Sopenharmony_ci * table of display modes that work for this monitor. 32928c2ecf20Sopenharmony_ci * 32938c2ecf20Sopenharmony_ci * The idea is that we search for a mode of the same dimensions 32948c2ecf20Sopenharmony_ci * as the dimensions of the LCD monitor. Say our LCD monitor 32958c2ecf20Sopenharmony_ci * is 800x600 pixels, we search for a 800x600 monitor. 32968c2ecf20Sopenharmony_ci * The CRTC parameters we find here are the ones that we need 32978c2ecf20Sopenharmony_ci * to use to simulate other resolutions on the LCD screen. 32988c2ecf20Sopenharmony_ci */ 32998c2ecf20Sopenharmony_ci lcdmodeptr = (u16 *)(par->lcd_table + 64); 33008c2ecf20Sopenharmony_ci while (*lcdmodeptr != 0) { 33018c2ecf20Sopenharmony_ci u32 modeptr; 33028c2ecf20Sopenharmony_ci u16 mwidth, mheight, lcd_hsync_start, lcd_vsync_start; 33038c2ecf20Sopenharmony_ci modeptr = bios_base + *lcdmodeptr; 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ci mwidth = *((u16 *)(modeptr+0)); 33068c2ecf20Sopenharmony_ci mheight = *((u16 *)(modeptr+2)); 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci if (mwidth == width && mheight == height) { 33098c2ecf20Sopenharmony_ci par->lcd_pixclock = 100000000 / *((u16 *)(modeptr+9)); 33108c2ecf20Sopenharmony_ci par->lcd_htotal = *((u16 *)(modeptr+17)) & 511; 33118c2ecf20Sopenharmony_ci par->lcd_hdisp = *((u16 *)(modeptr+19)) & 511; 33128c2ecf20Sopenharmony_ci lcd_hsync_start = *((u16 *)(modeptr+21)) & 511; 33138c2ecf20Sopenharmony_ci par->lcd_hsync_dly = (*((u16 *)(modeptr+21)) >> 9) & 7; 33148c2ecf20Sopenharmony_ci par->lcd_hsync_len = *((u8 *)(modeptr+23)) & 63; 33158c2ecf20Sopenharmony_ci 33168c2ecf20Sopenharmony_ci par->lcd_vtotal = *((u16 *)(modeptr+24)) & 2047; 33178c2ecf20Sopenharmony_ci par->lcd_vdisp = *((u16 *)(modeptr+26)) & 2047; 33188c2ecf20Sopenharmony_ci lcd_vsync_start = *((u16 *)(modeptr+28)) & 2047; 33198c2ecf20Sopenharmony_ci par->lcd_vsync_len = (*((u16 *)(modeptr+28)) >> 11) & 31; 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_ci par->lcd_htotal = (par->lcd_htotal + 1) * 8; 33228c2ecf20Sopenharmony_ci par->lcd_hdisp = (par->lcd_hdisp + 1) * 8; 33238c2ecf20Sopenharmony_ci lcd_hsync_start = (lcd_hsync_start + 1) * 8; 33248c2ecf20Sopenharmony_ci par->lcd_hsync_len = par->lcd_hsync_len * 8; 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci par->lcd_vtotal++; 33278c2ecf20Sopenharmony_ci par->lcd_vdisp++; 33288c2ecf20Sopenharmony_ci lcd_vsync_start++; 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ci par->lcd_right_margin = lcd_hsync_start - par->lcd_hdisp; 33318c2ecf20Sopenharmony_ci par->lcd_lower_margin = lcd_vsync_start - par->lcd_vdisp; 33328c2ecf20Sopenharmony_ci par->lcd_hblank_len = par->lcd_htotal - par->lcd_hdisp; 33338c2ecf20Sopenharmony_ci par->lcd_vblank_len = par->lcd_vtotal - par->lcd_vdisp; 33348c2ecf20Sopenharmony_ci break; 33358c2ecf20Sopenharmony_ci } 33368c2ecf20Sopenharmony_ci 33378c2ecf20Sopenharmony_ci lcdmodeptr++; 33388c2ecf20Sopenharmony_ci } 33398c2ecf20Sopenharmony_ci if (*lcdmodeptr == 0) { 33408c2ecf20Sopenharmony_ci PRINTKE("LCD monitor CRTC parameters not found!!!\n"); 33418c2ecf20Sopenharmony_ci /* To do: Switch to CRT if possible. */ 33428c2ecf20Sopenharmony_ci } else { 33438c2ecf20Sopenharmony_ci PRINTKI(" LCD CRTC parameters: %d.%d %d %d %d %d %d %d %d %d\n", 33448c2ecf20Sopenharmony_ci 1000000 / par->lcd_pixclock, 1000000 % par->lcd_pixclock, 33458c2ecf20Sopenharmony_ci par->lcd_hdisp, 33468c2ecf20Sopenharmony_ci par->lcd_hdisp + par->lcd_right_margin, 33478c2ecf20Sopenharmony_ci par->lcd_hdisp + par->lcd_right_margin 33488c2ecf20Sopenharmony_ci + par->lcd_hsync_dly + par->lcd_hsync_len, 33498c2ecf20Sopenharmony_ci par->lcd_htotal, 33508c2ecf20Sopenharmony_ci par->lcd_vdisp, 33518c2ecf20Sopenharmony_ci par->lcd_vdisp + par->lcd_lower_margin, 33528c2ecf20Sopenharmony_ci par->lcd_vdisp + par->lcd_lower_margin + par->lcd_vsync_len, 33538c2ecf20Sopenharmony_ci par->lcd_vtotal); 33548c2ecf20Sopenharmony_ci PRINTKI(" : %d %d %d %d %d %d %d %d %d\n", 33558c2ecf20Sopenharmony_ci par->lcd_pixclock, 33568c2ecf20Sopenharmony_ci par->lcd_hblank_len - (par->lcd_right_margin + 33578c2ecf20Sopenharmony_ci par->lcd_hsync_dly + par->lcd_hsync_len), 33588c2ecf20Sopenharmony_ci par->lcd_hdisp, 33598c2ecf20Sopenharmony_ci par->lcd_right_margin, 33608c2ecf20Sopenharmony_ci par->lcd_hsync_len, 33618c2ecf20Sopenharmony_ci par->lcd_vblank_len - (par->lcd_lower_margin + par->lcd_vsync_len), 33628c2ecf20Sopenharmony_ci par->lcd_vdisp, 33638c2ecf20Sopenharmony_ci par->lcd_lower_margin, 33648c2ecf20Sopenharmony_ci par->lcd_vsync_len); 33658c2ecf20Sopenharmony_ci } 33668c2ecf20Sopenharmony_ci } 33678c2ecf20Sopenharmony_ci} 33688c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_GENERIC_LCD */ 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_cistatic int init_from_bios(struct atyfb_par *par) 33718c2ecf20Sopenharmony_ci{ 33728c2ecf20Sopenharmony_ci u32 bios_base, rom_addr; 33738c2ecf20Sopenharmony_ci int ret; 33748c2ecf20Sopenharmony_ci 33758c2ecf20Sopenharmony_ci rom_addr = 0xc0000 + ((aty_ld_le32(SCRATCH_REG1, par) & 0x7f) << 11); 33768c2ecf20Sopenharmony_ci bios_base = (unsigned long)ioremap(rom_addr, 0x10000); 33778c2ecf20Sopenharmony_ci 33788c2ecf20Sopenharmony_ci /* The BIOS starts with 0xaa55. */ 33798c2ecf20Sopenharmony_ci if (*((u16 *)bios_base) == 0xaa55) { 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci u8 *bios_ptr; 33828c2ecf20Sopenharmony_ci u16 rom_table_offset, freq_table_offset; 33838c2ecf20Sopenharmony_ci PLL_BLOCK_MACH64 pll_block; 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_ci PRINTKI("Mach64 BIOS is located at %x, mapped at %x.\n", rom_addr, bios_base); 33868c2ecf20Sopenharmony_ci 33878c2ecf20Sopenharmony_ci /* check for frequncy table */ 33888c2ecf20Sopenharmony_ci bios_ptr = (u8*)bios_base; 33898c2ecf20Sopenharmony_ci rom_table_offset = (u16)(bios_ptr[0x48] | (bios_ptr[0x49] << 8)); 33908c2ecf20Sopenharmony_ci freq_table_offset = bios_ptr[rom_table_offset + 16] | (bios_ptr[rom_table_offset + 17] << 8); 33918c2ecf20Sopenharmony_ci memcpy(&pll_block, bios_ptr + freq_table_offset, sizeof(PLL_BLOCK_MACH64)); 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_ci PRINTKI("BIOS frequency table:\n"); 33948c2ecf20Sopenharmony_ci PRINTKI("PCLK_min_freq %d, PCLK_max_freq %d, ref_freq %d, ref_divider %d\n", 33958c2ecf20Sopenharmony_ci pll_block.PCLK_min_freq, pll_block.PCLK_max_freq, 33968c2ecf20Sopenharmony_ci pll_block.ref_freq, pll_block.ref_divider); 33978c2ecf20Sopenharmony_ci PRINTKI("MCLK_pwd %d, MCLK_max_freq %d, XCLK_max_freq %d, SCLK_freq %d\n", 33988c2ecf20Sopenharmony_ci pll_block.MCLK_pwd, pll_block.MCLK_max_freq, 33998c2ecf20Sopenharmony_ci pll_block.XCLK_max_freq, pll_block.SCLK_freq); 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_ci par->pll_limits.pll_min = pll_block.PCLK_min_freq/100; 34028c2ecf20Sopenharmony_ci par->pll_limits.pll_max = pll_block.PCLK_max_freq/100; 34038c2ecf20Sopenharmony_ci par->pll_limits.ref_clk = pll_block.ref_freq/100; 34048c2ecf20Sopenharmony_ci par->pll_limits.ref_div = pll_block.ref_divider; 34058c2ecf20Sopenharmony_ci par->pll_limits.sclk = pll_block.SCLK_freq/100; 34068c2ecf20Sopenharmony_ci par->pll_limits.mclk = pll_block.MCLK_max_freq/100; 34078c2ecf20Sopenharmony_ci par->pll_limits.mclk_pm = pll_block.MCLK_pwd/100; 34088c2ecf20Sopenharmony_ci par->pll_limits.xclk = pll_block.XCLK_max_freq/100; 34098c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GENERIC_LCD 34108c2ecf20Sopenharmony_ci aty_init_lcd(par, bios_base); 34118c2ecf20Sopenharmony_ci#endif 34128c2ecf20Sopenharmony_ci ret = 0; 34138c2ecf20Sopenharmony_ci } else { 34148c2ecf20Sopenharmony_ci PRINTKE("no BIOS frequency table found, use parameters\n"); 34158c2ecf20Sopenharmony_ci ret = -ENXIO; 34168c2ecf20Sopenharmony_ci } 34178c2ecf20Sopenharmony_ci iounmap((void __iomem *)bios_base); 34188c2ecf20Sopenharmony_ci 34198c2ecf20Sopenharmony_ci return ret; 34208c2ecf20Sopenharmony_ci} 34218c2ecf20Sopenharmony_ci#endif /* __i386__ */ 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_cistatic int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info, 34248c2ecf20Sopenharmony_ci unsigned long addr) 34258c2ecf20Sopenharmony_ci{ 34268c2ecf20Sopenharmony_ci struct atyfb_par *par = info->par; 34278c2ecf20Sopenharmony_ci u16 tmp; 34288c2ecf20Sopenharmony_ci unsigned long raddr; 34298c2ecf20Sopenharmony_ci struct resource *rrp; 34308c2ecf20Sopenharmony_ci int ret = 0; 34318c2ecf20Sopenharmony_ci 34328c2ecf20Sopenharmony_ci raddr = addr + 0x7ff000UL; 34338c2ecf20Sopenharmony_ci rrp = &pdev->resource[2]; 34348c2ecf20Sopenharmony_ci if ((rrp->flags & IORESOURCE_MEM) && 34358c2ecf20Sopenharmony_ci request_mem_region(rrp->start, resource_size(rrp), "atyfb")) { 34368c2ecf20Sopenharmony_ci par->aux_start = rrp->start; 34378c2ecf20Sopenharmony_ci par->aux_size = resource_size(rrp); 34388c2ecf20Sopenharmony_ci raddr = rrp->start; 34398c2ecf20Sopenharmony_ci PRINTKI("using auxiliary register aperture\n"); 34408c2ecf20Sopenharmony_ci } 34418c2ecf20Sopenharmony_ci 34428c2ecf20Sopenharmony_ci info->fix.mmio_start = raddr; 34438c2ecf20Sopenharmony_ci#if defined(__i386__) || defined(__ia64__) 34448c2ecf20Sopenharmony_ci /* 34458c2ecf20Sopenharmony_ci * By using strong UC we force the MTRR to never have an 34468c2ecf20Sopenharmony_ci * effect on the MMIO region on both non-PAT and PAT systems. 34478c2ecf20Sopenharmony_ci */ 34488c2ecf20Sopenharmony_ci par->ati_regbase = ioremap_uc(info->fix.mmio_start, 0x1000); 34498c2ecf20Sopenharmony_ci#else 34508c2ecf20Sopenharmony_ci par->ati_regbase = ioremap(info->fix.mmio_start, 0x1000); 34518c2ecf20Sopenharmony_ci#endif 34528c2ecf20Sopenharmony_ci if (par->ati_regbase == NULL) 34538c2ecf20Sopenharmony_ci return -ENOMEM; 34548c2ecf20Sopenharmony_ci 34558c2ecf20Sopenharmony_ci info->fix.mmio_start += par->aux_start ? 0x400 : 0xc00; 34568c2ecf20Sopenharmony_ci par->ati_regbase += par->aux_start ? 0x400 : 0xc00; 34578c2ecf20Sopenharmony_ci 34588c2ecf20Sopenharmony_ci /* 34598c2ecf20Sopenharmony_ci * Enable memory-space accesses using config-space 34608c2ecf20Sopenharmony_ci * command register. 34618c2ecf20Sopenharmony_ci */ 34628c2ecf20Sopenharmony_ci pci_read_config_word(pdev, PCI_COMMAND, &tmp); 34638c2ecf20Sopenharmony_ci if (!(tmp & PCI_COMMAND_MEMORY)) { 34648c2ecf20Sopenharmony_ci tmp |= PCI_COMMAND_MEMORY; 34658c2ecf20Sopenharmony_ci pci_write_config_word(pdev, PCI_COMMAND, tmp); 34668c2ecf20Sopenharmony_ci } 34678c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 34688c2ecf20Sopenharmony_ci /* Use the big-endian aperture */ 34698c2ecf20Sopenharmony_ci addr += 0x800000; 34708c2ecf20Sopenharmony_ci#endif 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_ci /* Map in frame buffer */ 34738c2ecf20Sopenharmony_ci info->fix.smem_start = addr; 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_ci /* 34768c2ecf20Sopenharmony_ci * The framebuffer is not always 8 MiB, that's just the size of the 34778c2ecf20Sopenharmony_ci * PCI BAR. We temporarily abuse smem_len here to store the size 34788c2ecf20Sopenharmony_ci * of the BAR. aty_init() will later correct it to match the actual 34798c2ecf20Sopenharmony_ci * framebuffer size. 34808c2ecf20Sopenharmony_ci * 34818c2ecf20Sopenharmony_ci * On devices that don't have the auxiliary register aperture, the 34828c2ecf20Sopenharmony_ci * registers are housed at the top end of the framebuffer PCI BAR. 34838c2ecf20Sopenharmony_ci * aty_fudge_framebuffer_len() is used to reduce smem_len to not 34848c2ecf20Sopenharmony_ci * overlap with the registers. 34858c2ecf20Sopenharmony_ci */ 34868c2ecf20Sopenharmony_ci info->fix.smem_len = 0x800000; 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ci aty_fudge_framebuffer_len(info); 34898c2ecf20Sopenharmony_ci 34908c2ecf20Sopenharmony_ci info->screen_base = ioremap_wc(info->fix.smem_start, 34918c2ecf20Sopenharmony_ci info->fix.smem_len); 34928c2ecf20Sopenharmony_ci if (info->screen_base == NULL) { 34938c2ecf20Sopenharmony_ci ret = -ENOMEM; 34948c2ecf20Sopenharmony_ci goto atyfb_setup_generic_fail; 34958c2ecf20Sopenharmony_ci } 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci ret = correct_chipset(par); 34988c2ecf20Sopenharmony_ci if (ret) 34998c2ecf20Sopenharmony_ci goto atyfb_setup_generic_fail; 35008c2ecf20Sopenharmony_ci#ifdef __i386__ 35018c2ecf20Sopenharmony_ci ret = init_from_bios(par); 35028c2ecf20Sopenharmony_ci if (ret) 35038c2ecf20Sopenharmony_ci goto atyfb_setup_generic_fail; 35048c2ecf20Sopenharmony_ci#endif 35058c2ecf20Sopenharmony_ci if (!(aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_EXT_DISP_EN)) 35068c2ecf20Sopenharmony_ci par->clk_wr_offset = (inb(R_GENMO) & 0x0CU) >> 2; 35078c2ecf20Sopenharmony_ci else 35088c2ecf20Sopenharmony_ci par->clk_wr_offset = aty_ld_8(CLOCK_CNTL, par) & 0x03U; 35098c2ecf20Sopenharmony_ci 35108c2ecf20Sopenharmony_ci /* according to ATI, we should use clock 3 for acelerated mode */ 35118c2ecf20Sopenharmony_ci par->clk_wr_offset = 3; 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_ci return 0; 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_ciatyfb_setup_generic_fail: 35168c2ecf20Sopenharmony_ci iounmap(par->ati_regbase); 35178c2ecf20Sopenharmony_ci par->ati_regbase = NULL; 35188c2ecf20Sopenharmony_ci if (info->screen_base) { 35198c2ecf20Sopenharmony_ci iounmap(info->screen_base); 35208c2ecf20Sopenharmony_ci info->screen_base = NULL; 35218c2ecf20Sopenharmony_ci } 35228c2ecf20Sopenharmony_ci return ret; 35238c2ecf20Sopenharmony_ci} 35248c2ecf20Sopenharmony_ci 35258c2ecf20Sopenharmony_ci#endif /* !__sparc__ */ 35268c2ecf20Sopenharmony_ci 35278c2ecf20Sopenharmony_cistatic int atyfb_pci_probe(struct pci_dev *pdev, 35288c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 35298c2ecf20Sopenharmony_ci{ 35308c2ecf20Sopenharmony_ci unsigned long addr, res_start, res_size; 35318c2ecf20Sopenharmony_ci struct fb_info *info; 35328c2ecf20Sopenharmony_ci struct resource *rp; 35338c2ecf20Sopenharmony_ci struct atyfb_par *par; 35348c2ecf20Sopenharmony_ci int rc = -ENOMEM; 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_ci /* Enable device in PCI config */ 35378c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) { 35388c2ecf20Sopenharmony_ci PRINTKE("Cannot enable PCI device\n"); 35398c2ecf20Sopenharmony_ci return -ENXIO; 35408c2ecf20Sopenharmony_ci } 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci /* Find which resource to use */ 35438c2ecf20Sopenharmony_ci rp = &pdev->resource[0]; 35448c2ecf20Sopenharmony_ci if (rp->flags & IORESOURCE_IO) 35458c2ecf20Sopenharmony_ci rp = &pdev->resource[1]; 35468c2ecf20Sopenharmony_ci addr = rp->start; 35478c2ecf20Sopenharmony_ci if (!addr) 35488c2ecf20Sopenharmony_ci return -ENXIO; 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci /* Reserve space */ 35518c2ecf20Sopenharmony_ci res_start = rp->start; 35528c2ecf20Sopenharmony_ci res_size = resource_size(rp); 35538c2ecf20Sopenharmony_ci if (!request_mem_region(res_start, res_size, "atyfb")) 35548c2ecf20Sopenharmony_ci return -EBUSY; 35558c2ecf20Sopenharmony_ci 35568c2ecf20Sopenharmony_ci /* Allocate framebuffer */ 35578c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(struct atyfb_par), &pdev->dev); 35588c2ecf20Sopenharmony_ci if (!info) 35598c2ecf20Sopenharmony_ci return -ENOMEM; 35608c2ecf20Sopenharmony_ci 35618c2ecf20Sopenharmony_ci par = info->par; 35628c2ecf20Sopenharmony_ci par->bus_type = PCI; 35638c2ecf20Sopenharmony_ci info->fix = atyfb_fix; 35648c2ecf20Sopenharmony_ci info->device = &pdev->dev; 35658c2ecf20Sopenharmony_ci par->pci_id = pdev->device; 35668c2ecf20Sopenharmony_ci par->res_start = res_start; 35678c2ecf20Sopenharmony_ci par->res_size = res_size; 35688c2ecf20Sopenharmony_ci par->irq = pdev->irq; 35698c2ecf20Sopenharmony_ci par->pdev = pdev; 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_ci /* Setup "info" structure */ 35728c2ecf20Sopenharmony_ci#ifdef __sparc__ 35738c2ecf20Sopenharmony_ci rc = atyfb_setup_sparc(pdev, info, addr); 35748c2ecf20Sopenharmony_ci#else 35758c2ecf20Sopenharmony_ci rc = atyfb_setup_generic(pdev, info, addr); 35768c2ecf20Sopenharmony_ci#endif 35778c2ecf20Sopenharmony_ci if (rc) 35788c2ecf20Sopenharmony_ci goto err_release_mem; 35798c2ecf20Sopenharmony_ci 35808c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, info); 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_ci /* Init chip & register framebuffer */ 35838c2ecf20Sopenharmony_ci rc = aty_init(info); 35848c2ecf20Sopenharmony_ci if (rc) 35858c2ecf20Sopenharmony_ci goto err_release_io; 35868c2ecf20Sopenharmony_ci 35878c2ecf20Sopenharmony_ci#ifdef __sparc__ 35888c2ecf20Sopenharmony_ci /* 35898c2ecf20Sopenharmony_ci * Add /dev/fb mmap values. 35908c2ecf20Sopenharmony_ci */ 35918c2ecf20Sopenharmony_ci par->mmap_map[0].voff = 0x8000000000000000UL; 35928c2ecf20Sopenharmony_ci par->mmap_map[0].poff = (unsigned long) info->screen_base & PAGE_MASK; 35938c2ecf20Sopenharmony_ci par->mmap_map[0].size = info->fix.smem_len; 35948c2ecf20Sopenharmony_ci par->mmap_map[0].prot_mask = _PAGE_CACHE; 35958c2ecf20Sopenharmony_ci par->mmap_map[0].prot_flag = _PAGE_E; 35968c2ecf20Sopenharmony_ci par->mmap_map[1].voff = par->mmap_map[0].voff + info->fix.smem_len; 35978c2ecf20Sopenharmony_ci par->mmap_map[1].poff = (long)par->ati_regbase & PAGE_MASK; 35988c2ecf20Sopenharmony_ci par->mmap_map[1].size = PAGE_SIZE; 35998c2ecf20Sopenharmony_ci par->mmap_map[1].prot_mask = _PAGE_CACHE; 36008c2ecf20Sopenharmony_ci par->mmap_map[1].prot_flag = _PAGE_E; 36018c2ecf20Sopenharmony_ci#endif /* __sparc__ */ 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_ci mutex_lock(&reboot_lock); 36048c2ecf20Sopenharmony_ci if (!reboot_info) 36058c2ecf20Sopenharmony_ci reboot_info = info; 36068c2ecf20Sopenharmony_ci mutex_unlock(&reboot_lock); 36078c2ecf20Sopenharmony_ci 36088c2ecf20Sopenharmony_ci return 0; 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_cierr_release_io: 36118c2ecf20Sopenharmony_ci#ifdef __sparc__ 36128c2ecf20Sopenharmony_ci kfree(par->mmap_map); 36138c2ecf20Sopenharmony_ci#else 36148c2ecf20Sopenharmony_ci if (par->ati_regbase) 36158c2ecf20Sopenharmony_ci iounmap(par->ati_regbase); 36168c2ecf20Sopenharmony_ci if (info->screen_base) 36178c2ecf20Sopenharmony_ci iounmap(info->screen_base); 36188c2ecf20Sopenharmony_ci#endif 36198c2ecf20Sopenharmony_cierr_release_mem: 36208c2ecf20Sopenharmony_ci if (par->aux_start) 36218c2ecf20Sopenharmony_ci release_mem_region(par->aux_start, par->aux_size); 36228c2ecf20Sopenharmony_ci 36238c2ecf20Sopenharmony_ci release_mem_region(par->res_start, par->res_size); 36248c2ecf20Sopenharmony_ci framebuffer_release(info); 36258c2ecf20Sopenharmony_ci 36268c2ecf20Sopenharmony_ci return rc; 36278c2ecf20Sopenharmony_ci} 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 36308c2ecf20Sopenharmony_ci 36318c2ecf20Sopenharmony_ci#ifdef CONFIG_ATARI 36328c2ecf20Sopenharmony_ci 36338c2ecf20Sopenharmony_cistatic int __init atyfb_atari_probe(void) 36348c2ecf20Sopenharmony_ci{ 36358c2ecf20Sopenharmony_ci struct atyfb_par *par; 36368c2ecf20Sopenharmony_ci struct fb_info *info; 36378c2ecf20Sopenharmony_ci int m64_num; 36388c2ecf20Sopenharmony_ci u32 clock_r; 36398c2ecf20Sopenharmony_ci int num_found = 0; 36408c2ecf20Sopenharmony_ci 36418c2ecf20Sopenharmony_ci for (m64_num = 0; m64_num < mach64_count; m64_num++) { 36428c2ecf20Sopenharmony_ci if (!phys_vmembase[m64_num] || !phys_size[m64_num] || 36438c2ecf20Sopenharmony_ci !phys_guiregbase[m64_num]) { 36448c2ecf20Sopenharmony_ci PRINTKI("phys_*[%d] parameters not set => " 36458c2ecf20Sopenharmony_ci "returning early. \n", m64_num); 36468c2ecf20Sopenharmony_ci continue; 36478c2ecf20Sopenharmony_ci } 36488c2ecf20Sopenharmony_ci 36498c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(struct atyfb_par), NULL); 36508c2ecf20Sopenharmony_ci if (!info) 36518c2ecf20Sopenharmony_ci return -ENOMEM; 36528c2ecf20Sopenharmony_ci 36538c2ecf20Sopenharmony_ci par = info->par; 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_ci info->fix = atyfb_fix; 36568c2ecf20Sopenharmony_ci 36578c2ecf20Sopenharmony_ci par->irq = (unsigned int) -1; /* something invalid */ 36588c2ecf20Sopenharmony_ci 36598c2ecf20Sopenharmony_ci /* 36608c2ecf20Sopenharmony_ci * Map the video memory (physical address given) 36618c2ecf20Sopenharmony_ci * to somewhere in the kernel address space. 36628c2ecf20Sopenharmony_ci */ 36638c2ecf20Sopenharmony_ci info->screen_base = ioremap_wc(phys_vmembase[m64_num], 36648c2ecf20Sopenharmony_ci phys_size[m64_num]); 36658c2ecf20Sopenharmony_ci info->fix.smem_start = (unsigned long)info->screen_base; /* Fake! */ 36668c2ecf20Sopenharmony_ci par->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000) + 36678c2ecf20Sopenharmony_ci 0xFC00ul; 36688c2ecf20Sopenharmony_ci info->fix.mmio_start = (unsigned long)par->ati_regbase; /* Fake! */ 36698c2ecf20Sopenharmony_ci 36708c2ecf20Sopenharmony_ci aty_st_le32(CLOCK_CNTL, 0x12345678, par); 36718c2ecf20Sopenharmony_ci clock_r = aty_ld_le32(CLOCK_CNTL, par); 36728c2ecf20Sopenharmony_ci 36738c2ecf20Sopenharmony_ci switch (clock_r & 0x003F) { 36748c2ecf20Sopenharmony_ci case 0x12: 36758c2ecf20Sopenharmony_ci par->clk_wr_offset = 3; /* */ 36768c2ecf20Sopenharmony_ci break; 36778c2ecf20Sopenharmony_ci case 0x34: 36788c2ecf20Sopenharmony_ci par->clk_wr_offset = 2; /* Medusa ST-IO ISA Adapter etc. */ 36798c2ecf20Sopenharmony_ci break; 36808c2ecf20Sopenharmony_ci case 0x16: 36818c2ecf20Sopenharmony_ci par->clk_wr_offset = 1; /* */ 36828c2ecf20Sopenharmony_ci break; 36838c2ecf20Sopenharmony_ci case 0x38: 36848c2ecf20Sopenharmony_ci par->clk_wr_offset = 0; /* Panther 1 ISA Adapter (Gerald) */ 36858c2ecf20Sopenharmony_ci break; 36868c2ecf20Sopenharmony_ci } 36878c2ecf20Sopenharmony_ci 36888c2ecf20Sopenharmony_ci /* Fake pci_id for correct_chipset() */ 36898c2ecf20Sopenharmony_ci switch (aty_ld_le32(CNFG_CHIP_ID, par) & CFG_CHIP_TYPE) { 36908c2ecf20Sopenharmony_ci case 0x00d7: 36918c2ecf20Sopenharmony_ci par->pci_id = PCI_CHIP_MACH64GX; 36928c2ecf20Sopenharmony_ci break; 36938c2ecf20Sopenharmony_ci case 0x0057: 36948c2ecf20Sopenharmony_ci par->pci_id = PCI_CHIP_MACH64CX; 36958c2ecf20Sopenharmony_ci break; 36968c2ecf20Sopenharmony_ci default: 36978c2ecf20Sopenharmony_ci break; 36988c2ecf20Sopenharmony_ci } 36998c2ecf20Sopenharmony_ci 37008c2ecf20Sopenharmony_ci if (correct_chipset(par) || aty_init(info)) { 37018c2ecf20Sopenharmony_ci iounmap(info->screen_base); 37028c2ecf20Sopenharmony_ci iounmap(par->ati_regbase); 37038c2ecf20Sopenharmony_ci framebuffer_release(info); 37048c2ecf20Sopenharmony_ci } else { 37058c2ecf20Sopenharmony_ci num_found++; 37068c2ecf20Sopenharmony_ci } 37078c2ecf20Sopenharmony_ci } 37088c2ecf20Sopenharmony_ci 37098c2ecf20Sopenharmony_ci return num_found ? 0 : -ENXIO; 37108c2ecf20Sopenharmony_ci} 37118c2ecf20Sopenharmony_ci 37128c2ecf20Sopenharmony_ci#endif /* CONFIG_ATARI */ 37138c2ecf20Sopenharmony_ci 37148c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 37158c2ecf20Sopenharmony_ci 37168c2ecf20Sopenharmony_cistatic void atyfb_remove(struct fb_info *info) 37178c2ecf20Sopenharmony_ci{ 37188c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_ci /* restore video mode */ 37218c2ecf20Sopenharmony_ci aty_set_crtc(par, &par->saved_crtc); 37228c2ecf20Sopenharmony_ci par->pll_ops->set_pll(info, &par->saved_pll); 37238c2ecf20Sopenharmony_ci 37248c2ecf20Sopenharmony_ci unregister_framebuffer(info); 37258c2ecf20Sopenharmony_ci 37268c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_BACKLIGHT 37278c2ecf20Sopenharmony_ci if (M64_HAS(MOBIL_BUS)) 37288c2ecf20Sopenharmony_ci aty_bl_exit(info->bl_dev); 37298c2ecf20Sopenharmony_ci#endif 37308c2ecf20Sopenharmony_ci arch_phys_wc_del(par->wc_cookie); 37318c2ecf20Sopenharmony_ci 37328c2ecf20Sopenharmony_ci#ifndef __sparc__ 37338c2ecf20Sopenharmony_ci if (par->ati_regbase) 37348c2ecf20Sopenharmony_ci iounmap(par->ati_regbase); 37358c2ecf20Sopenharmony_ci if (info->screen_base) 37368c2ecf20Sopenharmony_ci iounmap(info->screen_base); 37378c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 37388c2ecf20Sopenharmony_ci if (info->sprite.addr) 37398c2ecf20Sopenharmony_ci iounmap(info->sprite.addr); 37408c2ecf20Sopenharmony_ci#endif 37418c2ecf20Sopenharmony_ci#endif 37428c2ecf20Sopenharmony_ci#ifdef __sparc__ 37438c2ecf20Sopenharmony_ci kfree(par->mmap_map); 37448c2ecf20Sopenharmony_ci#endif 37458c2ecf20Sopenharmony_ci if (par->aux_start) 37468c2ecf20Sopenharmony_ci release_mem_region(par->aux_start, par->aux_size); 37478c2ecf20Sopenharmony_ci 37488c2ecf20Sopenharmony_ci if (par->res_start) 37498c2ecf20Sopenharmony_ci release_mem_region(par->res_start, par->res_size); 37508c2ecf20Sopenharmony_ci 37518c2ecf20Sopenharmony_ci framebuffer_release(info); 37528c2ecf20Sopenharmony_ci} 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_ci 37558c2ecf20Sopenharmony_cistatic void atyfb_pci_remove(struct pci_dev *pdev) 37568c2ecf20Sopenharmony_ci{ 37578c2ecf20Sopenharmony_ci struct fb_info *info = pci_get_drvdata(pdev); 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_ci mutex_lock(&reboot_lock); 37608c2ecf20Sopenharmony_ci if (reboot_info == info) 37618c2ecf20Sopenharmony_ci reboot_info = NULL; 37628c2ecf20Sopenharmony_ci mutex_unlock(&reboot_lock); 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci atyfb_remove(info); 37658c2ecf20Sopenharmony_ci} 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_cistatic const struct pci_device_id atyfb_pci_tbl[] = { 37688c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_GX 37698c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GX) }, 37708c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64CX) }, 37718c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_GX */ 37728c2ecf20Sopenharmony_ci 37738c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_ATY_CT 37748c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64CT) }, 37758c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64ET) }, 37768c2ecf20Sopenharmony_ci 37778c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LT) }, 37788c2ecf20Sopenharmony_ci 37798c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VT) }, 37808c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GT) }, 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VU) }, 37838c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GU) }, 37848c2ecf20Sopenharmony_ci 37858c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LG) }, 37868c2ecf20Sopenharmony_ci 37878c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VV) }, 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GV) }, 37908c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GW) }, 37918c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GY) }, 37928c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GZ) }, 37938c2ecf20Sopenharmony_ci 37948c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GB) }, 37958c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GD) }, 37968c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GI) }, 37978c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GP) }, 37988c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GQ) }, 37998c2ecf20Sopenharmony_ci 38008c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LB) }, 38018c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LD) }, 38028c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LI) }, 38038c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LP) }, 38048c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LQ) }, 38058c2ecf20Sopenharmony_ci 38068c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GM) }, 38078c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GN) }, 38088c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GO) }, 38098c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GL) }, 38108c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GR) }, 38118c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GS) }, 38128c2ecf20Sopenharmony_ci 38138c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LM) }, 38148c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LN) }, 38158c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LR) }, 38168c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LS) }, 38178c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_ATY_CT */ 38188c2ecf20Sopenharmony_ci { } 38198c2ecf20Sopenharmony_ci}; 38208c2ecf20Sopenharmony_ci 38218c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, atyfb_pci_tbl); 38228c2ecf20Sopenharmony_ci 38238c2ecf20Sopenharmony_cistatic struct pci_driver atyfb_driver = { 38248c2ecf20Sopenharmony_ci .name = "atyfb", 38258c2ecf20Sopenharmony_ci .id_table = atyfb_pci_tbl, 38268c2ecf20Sopenharmony_ci .probe = atyfb_pci_probe, 38278c2ecf20Sopenharmony_ci .remove = atyfb_pci_remove, 38288c2ecf20Sopenharmony_ci .driver.pm = &atyfb_pci_pm_ops, 38298c2ecf20Sopenharmony_ci}; 38308c2ecf20Sopenharmony_ci 38318c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 38328c2ecf20Sopenharmony_ci 38338c2ecf20Sopenharmony_ci#ifndef MODULE 38348c2ecf20Sopenharmony_cistatic int __init atyfb_setup(char *options) 38358c2ecf20Sopenharmony_ci{ 38368c2ecf20Sopenharmony_ci char *this_opt; 38378c2ecf20Sopenharmony_ci 38388c2ecf20Sopenharmony_ci if (!options || !*options) 38398c2ecf20Sopenharmony_ci return 0; 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci while ((this_opt = strsep(&options, ",")) != NULL) { 38428c2ecf20Sopenharmony_ci if (!strncmp(this_opt, "noaccel", 7)) { 38438c2ecf20Sopenharmony_ci noaccel = true; 38448c2ecf20Sopenharmony_ci } else if (!strncmp(this_opt, "nomtrr", 6)) { 38458c2ecf20Sopenharmony_ci nomtrr = true; 38468c2ecf20Sopenharmony_ci } else if (!strncmp(this_opt, "vram:", 5)) 38478c2ecf20Sopenharmony_ci vram = simple_strtoul(this_opt + 5, NULL, 0); 38488c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "pll:", 4)) 38498c2ecf20Sopenharmony_ci pll = simple_strtoul(this_opt + 4, NULL, 0); 38508c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "mclk:", 5)) 38518c2ecf20Sopenharmony_ci mclk = simple_strtoul(this_opt + 5, NULL, 0); 38528c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "xclk:", 5)) 38538c2ecf20Sopenharmony_ci xclk = simple_strtoul(this_opt+5, NULL, 0); 38548c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "comp_sync:", 10)) 38558c2ecf20Sopenharmony_ci comp_sync = simple_strtoul(this_opt+10, NULL, 0); 38568c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "backlight:", 10)) 38578c2ecf20Sopenharmony_ci backlight = simple_strtoul(this_opt+10, NULL, 0); 38588c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC 38598c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "vmode:", 6)) { 38608c2ecf20Sopenharmony_ci unsigned int vmode = 38618c2ecf20Sopenharmony_ci simple_strtoul(this_opt + 6, NULL, 0); 38628c2ecf20Sopenharmony_ci if (vmode > 0 && vmode <= VMODE_MAX) 38638c2ecf20Sopenharmony_ci default_vmode = vmode; 38648c2ecf20Sopenharmony_ci } else if (!strncmp(this_opt, "cmode:", 6)) { 38658c2ecf20Sopenharmony_ci unsigned int cmode = 38668c2ecf20Sopenharmony_ci simple_strtoul(this_opt + 6, NULL, 0); 38678c2ecf20Sopenharmony_ci switch (cmode) { 38688c2ecf20Sopenharmony_ci case 0: 38698c2ecf20Sopenharmony_ci case 8: 38708c2ecf20Sopenharmony_ci default_cmode = CMODE_8; 38718c2ecf20Sopenharmony_ci break; 38728c2ecf20Sopenharmony_ci case 15: 38738c2ecf20Sopenharmony_ci case 16: 38748c2ecf20Sopenharmony_ci default_cmode = CMODE_16; 38758c2ecf20Sopenharmony_ci break; 38768c2ecf20Sopenharmony_ci case 24: 38778c2ecf20Sopenharmony_ci case 32: 38788c2ecf20Sopenharmony_ci default_cmode = CMODE_32; 38798c2ecf20Sopenharmony_ci break; 38808c2ecf20Sopenharmony_ci } 38818c2ecf20Sopenharmony_ci } 38828c2ecf20Sopenharmony_ci#endif 38838c2ecf20Sopenharmony_ci#ifdef CONFIG_ATARI 38848c2ecf20Sopenharmony_ci /* 38858c2ecf20Sopenharmony_ci * Why do we need this silly Mach64 argument? 38868c2ecf20Sopenharmony_ci * We are already here because of mach64= so its redundant. 38878c2ecf20Sopenharmony_ci */ 38888c2ecf20Sopenharmony_ci else if (MACH_IS_ATARI 38898c2ecf20Sopenharmony_ci && (!strncmp(this_opt, "Mach64:", 7))) { 38908c2ecf20Sopenharmony_ci static unsigned char m64_num; 38918c2ecf20Sopenharmony_ci static char mach64_str[80]; 38928c2ecf20Sopenharmony_ci strlcpy(mach64_str, this_opt + 7, sizeof(mach64_str)); 38938c2ecf20Sopenharmony_ci if (!store_video_par(mach64_str, m64_num)) { 38948c2ecf20Sopenharmony_ci m64_num++; 38958c2ecf20Sopenharmony_ci mach64_count = m64_num; 38968c2ecf20Sopenharmony_ci } 38978c2ecf20Sopenharmony_ci } 38988c2ecf20Sopenharmony_ci#endif 38998c2ecf20Sopenharmony_ci else 39008c2ecf20Sopenharmony_ci mode = this_opt; 39018c2ecf20Sopenharmony_ci } 39028c2ecf20Sopenharmony_ci return 0; 39038c2ecf20Sopenharmony_ci} 39048c2ecf20Sopenharmony_ci#endif /* MODULE */ 39058c2ecf20Sopenharmony_ci 39068c2ecf20Sopenharmony_cistatic int atyfb_reboot_notify(struct notifier_block *nb, 39078c2ecf20Sopenharmony_ci unsigned long code, void *unused) 39088c2ecf20Sopenharmony_ci{ 39098c2ecf20Sopenharmony_ci struct atyfb_par *par; 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_ci if (code != SYS_RESTART) 39128c2ecf20Sopenharmony_ci return NOTIFY_DONE; 39138c2ecf20Sopenharmony_ci 39148c2ecf20Sopenharmony_ci mutex_lock(&reboot_lock); 39158c2ecf20Sopenharmony_ci 39168c2ecf20Sopenharmony_ci if (!reboot_info) 39178c2ecf20Sopenharmony_ci goto out; 39188c2ecf20Sopenharmony_ci 39198c2ecf20Sopenharmony_ci lock_fb_info(reboot_info); 39208c2ecf20Sopenharmony_ci 39218c2ecf20Sopenharmony_ci par = reboot_info->par; 39228c2ecf20Sopenharmony_ci 39238c2ecf20Sopenharmony_ci /* 39248c2ecf20Sopenharmony_ci * HP OmniBook 500's BIOS doesn't like the state of the 39258c2ecf20Sopenharmony_ci * hardware after atyfb has been used. Restore the hardware 39268c2ecf20Sopenharmony_ci * to the original state to allow successful reboots. 39278c2ecf20Sopenharmony_ci */ 39288c2ecf20Sopenharmony_ci aty_set_crtc(par, &par->saved_crtc); 39298c2ecf20Sopenharmony_ci par->pll_ops->set_pll(reboot_info, &par->saved_pll); 39308c2ecf20Sopenharmony_ci 39318c2ecf20Sopenharmony_ci unlock_fb_info(reboot_info); 39328c2ecf20Sopenharmony_ci out: 39338c2ecf20Sopenharmony_ci mutex_unlock(&reboot_lock); 39348c2ecf20Sopenharmony_ci 39358c2ecf20Sopenharmony_ci return NOTIFY_DONE; 39368c2ecf20Sopenharmony_ci} 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_cistatic struct notifier_block atyfb_reboot_notifier = { 39398c2ecf20Sopenharmony_ci .notifier_call = atyfb_reboot_notify, 39408c2ecf20Sopenharmony_ci}; 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_cistatic const struct dmi_system_id atyfb_reboot_ids[] __initconst = { 39438c2ecf20Sopenharmony_ci { 39448c2ecf20Sopenharmony_ci .ident = "HP OmniBook 500", 39458c2ecf20Sopenharmony_ci .matches = { 39468c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 39478c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "HP OmniBook PC"), 39488c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_VERSION, "HP OmniBook 500 FA"), 39498c2ecf20Sopenharmony_ci }, 39508c2ecf20Sopenharmony_ci }, 39518c2ecf20Sopenharmony_ci 39528c2ecf20Sopenharmony_ci { } 39538c2ecf20Sopenharmony_ci}; 39548c2ecf20Sopenharmony_cistatic bool registered_notifier = false; 39558c2ecf20Sopenharmony_ci 39568c2ecf20Sopenharmony_cistatic int __init atyfb_init(void) 39578c2ecf20Sopenharmony_ci{ 39588c2ecf20Sopenharmony_ci int err1 = 1, err2 = 1; 39598c2ecf20Sopenharmony_ci#ifndef MODULE 39608c2ecf20Sopenharmony_ci char *option = NULL; 39618c2ecf20Sopenharmony_ci 39628c2ecf20Sopenharmony_ci if (fb_get_options("atyfb", &option)) 39638c2ecf20Sopenharmony_ci return -ENODEV; 39648c2ecf20Sopenharmony_ci atyfb_setup(option); 39658c2ecf20Sopenharmony_ci#endif 39668c2ecf20Sopenharmony_ci 39678c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 39688c2ecf20Sopenharmony_ci err1 = pci_register_driver(&atyfb_driver); 39698c2ecf20Sopenharmony_ci#endif 39708c2ecf20Sopenharmony_ci#ifdef CONFIG_ATARI 39718c2ecf20Sopenharmony_ci err2 = atyfb_atari_probe(); 39728c2ecf20Sopenharmony_ci#endif 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_ci if (err1 && err2) 39758c2ecf20Sopenharmony_ci return -ENODEV; 39768c2ecf20Sopenharmony_ci 39778c2ecf20Sopenharmony_ci if (dmi_check_system(atyfb_reboot_ids)) { 39788c2ecf20Sopenharmony_ci register_reboot_notifier(&atyfb_reboot_notifier); 39798c2ecf20Sopenharmony_ci registered_notifier = true; 39808c2ecf20Sopenharmony_ci } 39818c2ecf20Sopenharmony_ci 39828c2ecf20Sopenharmony_ci return 0; 39838c2ecf20Sopenharmony_ci} 39848c2ecf20Sopenharmony_ci 39858c2ecf20Sopenharmony_cistatic void __exit atyfb_exit(void) 39868c2ecf20Sopenharmony_ci{ 39878c2ecf20Sopenharmony_ci if (registered_notifier) 39888c2ecf20Sopenharmony_ci unregister_reboot_notifier(&atyfb_reboot_notifier); 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 39918c2ecf20Sopenharmony_ci pci_unregister_driver(&atyfb_driver); 39928c2ecf20Sopenharmony_ci#endif 39938c2ecf20Sopenharmony_ci} 39948c2ecf20Sopenharmony_ci 39958c2ecf20Sopenharmony_cimodule_init(atyfb_init); 39968c2ecf20Sopenharmony_cimodule_exit(atyfb_exit); 39978c2ecf20Sopenharmony_ci 39988c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("FBDev driver for ATI Mach64 cards"); 39998c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 40008c2ecf20Sopenharmony_cimodule_param(noaccel, bool, 0); 40018c2ecf20Sopenharmony_ciMODULE_PARM_DESC(noaccel, "bool: disable acceleration"); 40028c2ecf20Sopenharmony_cimodule_param(vram, int, 0); 40038c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vram, "int: override size of video ram"); 40048c2ecf20Sopenharmony_cimodule_param(pll, int, 0); 40058c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pll, "int: override video clock"); 40068c2ecf20Sopenharmony_cimodule_param(mclk, int, 0); 40078c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mclk, "int: override memory clock"); 40088c2ecf20Sopenharmony_cimodule_param(xclk, int, 0); 40098c2ecf20Sopenharmony_ciMODULE_PARM_DESC(xclk, "int: override accelerated engine clock"); 40108c2ecf20Sopenharmony_cimodule_param(comp_sync, int, 0); 40118c2ecf20Sopenharmony_ciMODULE_PARM_DESC(comp_sync, "Set composite sync signal to low (0) or high (1)"); 40128c2ecf20Sopenharmony_cimodule_param(mode, charp, 0); 40138c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); 40148c2ecf20Sopenharmony_cimodule_param(nomtrr, bool, 0); 40158c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nomtrr, "bool: disable use of MTRR registers"); 4016