18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 1995-2003 Geert Uytterhoeven 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * with work by Roman Zippel 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This file is based on the Atari frame buffer device (atafb.c): 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright (C) 1994 Martin Schaller 128c2ecf20Sopenharmony_ci * Roman Hodek 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * with work by Andreas Schwab 158c2ecf20Sopenharmony_ci * Guenther Kelleter 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * and on the original Amiga console driver (amicon.c): 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Copyright (C) 1993 Hamish Macdonald 208c2ecf20Sopenharmony_ci * Greg Harp 218c2ecf20Sopenharmony_ci * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * with work by William Rucklidge (wjr@cs.cornell.edu) 248c2ecf20Sopenharmony_ci * Geert Uytterhoeven 258c2ecf20Sopenharmony_ci * Jes Sorensen (jds@kom.auc.dk) 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * History: 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * - 24 Jul 96: Copper generates now vblank interrupt and 318c2ecf20Sopenharmony_ci * VESA Power Saving Protocol is fully implemented 328c2ecf20Sopenharmony_ci * - 14 Jul 96: Rework and hopefully last ECS bugs fixed 338c2ecf20Sopenharmony_ci * - 7 Mar 96: Hardware sprite support by Roman Zippel 348c2ecf20Sopenharmony_ci * - 18 Feb 96: OCS and ECS support by Roman Zippel 358c2ecf20Sopenharmony_ci * Hardware functions completely rewritten 368c2ecf20Sopenharmony_ci * - 2 Dec 95: AGA version by Geert Uytterhoeven 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 398c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive 408c2ecf20Sopenharmony_ci * for more details. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include <linux/module.h> 448c2ecf20Sopenharmony_ci#include <linux/kernel.h> 458c2ecf20Sopenharmony_ci#include <linux/errno.h> 468c2ecf20Sopenharmony_ci#include <linux/string.h> 478c2ecf20Sopenharmony_ci#include <linux/mm.h> 488c2ecf20Sopenharmony_ci#include <linux/delay.h> 498c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 508c2ecf20Sopenharmony_ci#include <linux/fb.h> 518c2ecf20Sopenharmony_ci#include <linux/init.h> 528c2ecf20Sopenharmony_ci#include <linux/ioport.h> 538c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 548c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#include <asm/irq.h> 578c2ecf20Sopenharmony_ci#include <asm/amigahw.h> 588c2ecf20Sopenharmony_ci#include <asm/amigaints.h> 598c2ecf20Sopenharmony_ci#include <asm/setup.h> 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#include "c2p.h" 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define DEBUG 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#if !defined(CONFIG_FB_AMIGA_OCS) && !defined(CONFIG_FB_AMIGA_ECS) && !defined(CONFIG_FB_AMIGA_AGA) 678c2ecf20Sopenharmony_ci#define CONFIG_FB_AMIGA_OCS /* define at least one fb driver, this will change later */ 688c2ecf20Sopenharmony_ci#endif 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#if !defined(CONFIG_FB_AMIGA_OCS) 718c2ecf20Sopenharmony_ci# define IS_OCS (0) 728c2ecf20Sopenharmony_ci#elif defined(CONFIG_FB_AMIGA_ECS) || defined(CONFIG_FB_AMIGA_AGA) 738c2ecf20Sopenharmony_ci# define IS_OCS (chipset == TAG_OCS) 748c2ecf20Sopenharmony_ci#else 758c2ecf20Sopenharmony_ci# define CONFIG_FB_AMIGA_OCS_ONLY 768c2ecf20Sopenharmony_ci# define IS_OCS (1) 778c2ecf20Sopenharmony_ci#endif 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#if !defined(CONFIG_FB_AMIGA_ECS) 808c2ecf20Sopenharmony_ci# define IS_ECS (0) 818c2ecf20Sopenharmony_ci#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_AGA) 828c2ecf20Sopenharmony_ci# define IS_ECS (chipset == TAG_ECS) 838c2ecf20Sopenharmony_ci#else 848c2ecf20Sopenharmony_ci# define CONFIG_FB_AMIGA_ECS_ONLY 858c2ecf20Sopenharmony_ci# define IS_ECS (1) 868c2ecf20Sopenharmony_ci#endif 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#if !defined(CONFIG_FB_AMIGA_AGA) 898c2ecf20Sopenharmony_ci# define IS_AGA (0) 908c2ecf20Sopenharmony_ci#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_ECS) 918c2ecf20Sopenharmony_ci# define IS_AGA (chipset == TAG_AGA) 928c2ecf20Sopenharmony_ci#else 938c2ecf20Sopenharmony_ci# define CONFIG_FB_AMIGA_AGA_ONLY 948c2ecf20Sopenharmony_ci# define IS_AGA (1) 958c2ecf20Sopenharmony_ci#endif 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci#ifdef DEBUG 988c2ecf20Sopenharmony_ci# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) 998c2ecf20Sopenharmony_ci#else 1008c2ecf20Sopenharmony_ci# define DPRINTK(fmt, args...) 1018c2ecf20Sopenharmony_ci#endif 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/******************************************************************************* 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci Generic video timings 1078c2ecf20Sopenharmony_ci --------------------- 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci Timings used by the frame buffer interface: 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci +----------+---------------------------------------------+----------+-------+ 1128c2ecf20Sopenharmony_ci | | ^ | | | 1138c2ecf20Sopenharmony_ci | | |upper_margin | | | 1148c2ecf20Sopenharmony_ci | | v | | | 1158c2ecf20Sopenharmony_ci +----------###############################################----------+-------+ 1168c2ecf20Sopenharmony_ci | # ^ # | | 1178c2ecf20Sopenharmony_ci | # | # | | 1188c2ecf20Sopenharmony_ci | # | # | | 1198c2ecf20Sopenharmony_ci | # | # | | 1208c2ecf20Sopenharmony_ci | left # | # right | hsync | 1218c2ecf20Sopenharmony_ci | margin # | xres # margin | len | 1228c2ecf20Sopenharmony_ci |<-------->#<---------------+--------------------------->#<-------->|<----->| 1238c2ecf20Sopenharmony_ci | # | # | | 1248c2ecf20Sopenharmony_ci | # | # | | 1258c2ecf20Sopenharmony_ci | # | # | | 1268c2ecf20Sopenharmony_ci | # |yres # | | 1278c2ecf20Sopenharmony_ci | # | # | | 1288c2ecf20Sopenharmony_ci | # | # | | 1298c2ecf20Sopenharmony_ci | # | # | | 1308c2ecf20Sopenharmony_ci | # | # | | 1318c2ecf20Sopenharmony_ci | # | # | | 1328c2ecf20Sopenharmony_ci | # | # | | 1338c2ecf20Sopenharmony_ci | # | # | | 1348c2ecf20Sopenharmony_ci | # | # | | 1358c2ecf20Sopenharmony_ci | # v # | | 1368c2ecf20Sopenharmony_ci +----------###############################################----------+-------+ 1378c2ecf20Sopenharmony_ci | | ^ | | | 1388c2ecf20Sopenharmony_ci | | |lower_margin | | | 1398c2ecf20Sopenharmony_ci | | v | | | 1408c2ecf20Sopenharmony_ci +----------+---------------------------------------------+----------+-------+ 1418c2ecf20Sopenharmony_ci | | ^ | | | 1428c2ecf20Sopenharmony_ci | | |vsync_len | | | 1438c2ecf20Sopenharmony_ci | | v | | | 1448c2ecf20Sopenharmony_ci +----------+---------------------------------------------+----------+-------+ 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci Amiga video timings 1488c2ecf20Sopenharmony_ci ------------------- 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci The Amiga native chipsets uses another timing scheme: 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci - hsstrt: Start of horizontal synchronization pulse 1538c2ecf20Sopenharmony_ci - hsstop: End of horizontal synchronization pulse 1548c2ecf20Sopenharmony_ci - htotal: Last value on the line (i.e. line length = htotal + 1) 1558c2ecf20Sopenharmony_ci - vsstrt: Start of vertical synchronization pulse 1568c2ecf20Sopenharmony_ci - vsstop: End of vertical synchronization pulse 1578c2ecf20Sopenharmony_ci - vtotal: Last line value (i.e. number of lines = vtotal + 1) 1588c2ecf20Sopenharmony_ci - hcenter: Start of vertical retrace for interlace 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci You can specify the blanking timings independently. Currently I just set 1618c2ecf20Sopenharmony_ci them equal to the respective synchronization values: 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci - hbstrt: Start of horizontal blank 1648c2ecf20Sopenharmony_ci - hbstop: End of horizontal blank 1658c2ecf20Sopenharmony_ci - vbstrt: Start of vertical blank 1668c2ecf20Sopenharmony_ci - vbstop: End of vertical blank 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci Horizontal values are in color clock cycles (280 ns), vertical values are in 1698c2ecf20Sopenharmony_ci scanlines. 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci (0, 0) is somewhere in the upper-left corner :-) 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci Amiga visible window definitions 1758c2ecf20Sopenharmony_ci -------------------------------- 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to 1788c2ecf20Sopenharmony_ci make corrections and/or additions. 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci Within the above synchronization specifications, the visible window is 1818c2ecf20Sopenharmony_ci defined by the following parameters (actual register resolutions may be 1828c2ecf20Sopenharmony_ci different; all horizontal values are normalized with respect to the pixel 1838c2ecf20Sopenharmony_ci clock): 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci - diwstrt_h: Horizontal start of the visible window 1868c2ecf20Sopenharmony_ci - diwstop_h: Horizontal stop + 1(*) of the visible window 1878c2ecf20Sopenharmony_ci - diwstrt_v: Vertical start of the visible window 1888c2ecf20Sopenharmony_ci - diwstop_v: Vertical stop of the visible window 1898c2ecf20Sopenharmony_ci - ddfstrt: Horizontal start of display DMA 1908c2ecf20Sopenharmony_ci - ddfstop: Horizontal stop of display DMA 1918c2ecf20Sopenharmony_ci - hscroll: Horizontal display output delay 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci Sprite positioning: 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci - sprstrt_h: Horizontal start - 4 of sprite 1968c2ecf20Sopenharmony_ci - sprstrt_v: Vertical start of sprite 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1. 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci Horizontal values are in dotclock cycles (35 ns), vertical values are in 2018c2ecf20Sopenharmony_ci scanlines. 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci (0, 0) is somewhere in the upper-left corner :-) 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci Dependencies (AGA, SHRES (35 ns dotclock)) 2078c2ecf20Sopenharmony_ci ------------------------------------------- 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci Since there are much more parameters for the Amiga display than for the 2108c2ecf20Sopenharmony_ci frame buffer interface, there must be some dependencies among the Amiga 2118c2ecf20Sopenharmony_ci display parameters. Here's what I found out: 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci - ddfstrt and ddfstop are best aligned to 64 pixels. 2148c2ecf20Sopenharmony_ci - the chipset needs 64 + 4 horizontal pixels after the DMA start before 2158c2ecf20Sopenharmony_ci the first pixel is output, so diwstrt_h = ddfstrt + 64 + 4 if you want 2168c2ecf20Sopenharmony_ci to display the first pixel on the line too. Increase diwstrt_h for 2178c2ecf20Sopenharmony_ci virtual screen panning. 2188c2ecf20Sopenharmony_ci - the display DMA always fetches 64 pixels at a time (fmode = 3). 2198c2ecf20Sopenharmony_ci - ddfstop is ddfstrt+#pixels - 64. 2208c2ecf20Sopenharmony_ci - diwstop_h = diwstrt_h + xres + 1. Because of the additional 1 this can 2218c2ecf20Sopenharmony_ci be 1 more than htotal. 2228c2ecf20Sopenharmony_ci - hscroll simply adds a delay to the display output. Smooth horizontal 2238c2ecf20Sopenharmony_ci panning needs an extra 64 pixels on the left to prefetch the pixels that 2248c2ecf20Sopenharmony_ci `fall off' on the left. 2258c2ecf20Sopenharmony_ci - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane 2268c2ecf20Sopenharmony_ci DMA, so it's best to make the DMA start as late as possible. 2278c2ecf20Sopenharmony_ci - you really don't want to make ddfstrt < 128, since this will steal DMA 2288c2ecf20Sopenharmony_ci cycles from the other DMA channels (audio, floppy and Chip RAM refresh). 2298c2ecf20Sopenharmony_ci - I make diwstop_h and diwstop_v as large as possible. 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci General dependencies 2328c2ecf20Sopenharmony_ci -------------------- 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci - all values are SHRES pixel (35ns) 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci table 1:fetchstart table 2:prefetch table 3:fetchsize 2378c2ecf20Sopenharmony_ci ------------------ ---------------- ----------------- 2388c2ecf20Sopenharmony_ci Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES 2398c2ecf20Sopenharmony_ci -------------#------+-----+------#------+-----+------#------+-----+------ 2408c2ecf20Sopenharmony_ci Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64 2418c2ecf20Sopenharmony_ci Bus width 2x # 32 | 64 | 128 # 32 | 64 | 64 # 64 | 64 | 128 2428c2ecf20Sopenharmony_ci Bus width 4x # 64 | 128 | 256 # 64 | 64 | 64 # 64 | 128 | 256 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci - chipset needs 4 pixels before the first pixel is output 2458c2ecf20Sopenharmony_ci - ddfstrt must be aligned to fetchstart (table 1) 2468c2ecf20Sopenharmony_ci - chipset needs also prefetch (table 2) to get first pixel data, so 2478c2ecf20Sopenharmony_ci ddfstrt = ((diwstrt_h - 4) & -fetchstart) - prefetch 2488c2ecf20Sopenharmony_ci - for horizontal panning decrease diwstrt_h 2498c2ecf20Sopenharmony_ci - the length of a fetchline must be aligned to fetchsize (table 3) 2508c2ecf20Sopenharmony_ci - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit 2518c2ecf20Sopenharmony_ci moved to optimize use of dma (useful for OCS/ECS overscan displays) 2528c2ecf20Sopenharmony_ci - ddfstop is ddfstrt + ddfsize - fetchsize 2538c2ecf20Sopenharmony_ci - If C= didn't change anything for AGA, then at following positions the 2548c2ecf20Sopenharmony_ci dma bus is already used: 2558c2ecf20Sopenharmony_ci ddfstrt < 48 -> memory refresh 2568c2ecf20Sopenharmony_ci < 96 -> disk dma 2578c2ecf20Sopenharmony_ci < 160 -> audio dma 2588c2ecf20Sopenharmony_ci < 192 -> sprite 0 dma 2598c2ecf20Sopenharmony_ci < 416 -> sprite dma (32 per sprite) 2608c2ecf20Sopenharmony_ci - in accordance with the hardware reference manual a hardware stop is at 2618c2ecf20Sopenharmony_ci 192, but AGA (ECS?) can go below this. 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci DMA priorities 2648c2ecf20Sopenharmony_ci -------------- 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci Since there are limits on the earliest start value for display DMA and the 2678c2ecf20Sopenharmony_ci display of sprites, I use the following policy on horizontal panning and 2688c2ecf20Sopenharmony_ci the hardware cursor: 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci - if you want to start display DMA too early, you lose the ability to 2718c2ecf20Sopenharmony_ci do smooth horizontal panning (xpanstep 1 -> 64). 2728c2ecf20Sopenharmony_ci - if you want to go even further, you lose the hardware cursor too. 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci IMHO a hardware cursor is more important for X than horizontal scrolling, 2758c2ecf20Sopenharmony_ci so that's my motivation. 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci Implementation 2798c2ecf20Sopenharmony_ci -------------- 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci ami_decode_var() converts the frame buffer values to the Amiga values. It's 2828c2ecf20Sopenharmony_ci just a `straightforward' implementation of the above rules. 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci Standard VGA timings 2868c2ecf20Sopenharmony_ci -------------------- 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci xres yres left right upper lower hsync vsync 2898c2ecf20Sopenharmony_ci ---- ---- ---- ----- ----- ----- ----- ----- 2908c2ecf20Sopenharmony_ci 80x25 720 400 27 45 35 12 108 2 2918c2ecf20Sopenharmony_ci 80x30 720 480 27 45 30 9 108 2 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci These were taken from a XFree86 configuration file, recalculated for a 28 MHz 2948c2ecf20Sopenharmony_ci dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer 2958c2ecf20Sopenharmony_ci generic timings. 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci As a comparison, graphics/monitor.h suggests the following: 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci xres yres left right upper lower hsync vsync 3008c2ecf20Sopenharmony_ci ---- ---- ---- ----- ----- ----- ----- ----- 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci VGA 640 480 52 112 24 19 112 - 2 + 3038c2ecf20Sopenharmony_ci VGA70 640 400 52 112 27 21 112 - 2 - 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci Sync polarities 3078c2ecf20Sopenharmony_ci --------------- 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci VSYNC HSYNC Vertical size Vertical total 3108c2ecf20Sopenharmony_ci ----- ----- ------------- -------------- 3118c2ecf20Sopenharmony_ci + + Reserved Reserved 3128c2ecf20Sopenharmony_ci + - 400 414 3138c2ecf20Sopenharmony_ci - + 350 362 3148c2ecf20Sopenharmony_ci - - 480 496 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci Broadcast video timings 3208c2ecf20Sopenharmony_ci ----------------------- 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci According to the CCIR and RETMA specifications, we have the following values: 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci CCIR -> PAL 3258c2ecf20Sopenharmony_ci ----------- 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci - a scanline is 64 µs long, of which 52.48 µs are visible. This is about 3288c2ecf20Sopenharmony_ci 736 visible 70 ns pixels per line. 3298c2ecf20Sopenharmony_ci - we have 625 scanlines, of which 575 are visible (interlaced); after 3308c2ecf20Sopenharmony_ci rounding this becomes 576. 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci RETMA -> NTSC 3338c2ecf20Sopenharmony_ci ------------- 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about 3368c2ecf20Sopenharmony_ci 736 visible 70 ns pixels per line. 3378c2ecf20Sopenharmony_ci - we have 525 scanlines, of which 485 are visible (interlaced); after 3388c2ecf20Sopenharmony_ci rounding this becomes 484. 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci Thus if you want a PAL compatible display, you have to do the following: 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast 3438c2ecf20Sopenharmony_ci timings are to be used. 3448c2ecf20Sopenharmony_ci - make sure upper_margin + yres + lower_margin + vsync_len = 625 for an 3458c2ecf20Sopenharmony_ci interlaced, 312 for a non-interlaced and 156 for a doublescanned 3468c2ecf20Sopenharmony_ci display. 3478c2ecf20Sopenharmony_ci - make sure left_margin + xres + right_margin + hsync_len = 1816 for a 3488c2ecf20Sopenharmony_ci SHRES, 908 for a HIRES and 454 for a LORES display. 3498c2ecf20Sopenharmony_ci - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90), 3508c2ecf20Sopenharmony_ci left_margin + 2 * hsync_len must be greater or equal. 3518c2ecf20Sopenharmony_ci - the upper visible part begins at 48 (interlaced; non-interlaced:24, 3528c2ecf20Sopenharmony_ci doublescanned:12), upper_margin + 2 * vsync_len must be greater or 3538c2ecf20Sopenharmony_ci equal. 3548c2ecf20Sopenharmony_ci - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync 3558c2ecf20Sopenharmony_ci of 4 scanlines 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci The settings for a NTSC compatible display are straightforward. 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci Note that in a strict sense the PAL and NTSC standards only define the 3608c2ecf20Sopenharmony_ci encoding of the color part (chrominance) of the video signal and don't say 3618c2ecf20Sopenharmony_ci anything about horizontal/vertical synchronization nor refresh rates. 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci -- Geert -- 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci*******************************************************************************/ 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* 3708c2ecf20Sopenharmony_ci * Custom Chipset Definitions 3718c2ecf20Sopenharmony_ci */ 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci#define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld) 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* 3768c2ecf20Sopenharmony_ci * BPLCON0 -- Bitplane Control Register 0 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci#define BPC0_HIRES (0x8000) 3808c2ecf20Sopenharmony_ci#define BPC0_BPU2 (0x4000) /* Bit plane used count */ 3818c2ecf20Sopenharmony_ci#define BPC0_BPU1 (0x2000) 3828c2ecf20Sopenharmony_ci#define BPC0_BPU0 (0x1000) 3838c2ecf20Sopenharmony_ci#define BPC0_HAM (0x0800) /* HAM mode */ 3848c2ecf20Sopenharmony_ci#define BPC0_DPF (0x0400) /* Double playfield */ 3858c2ecf20Sopenharmony_ci#define BPC0_COLOR (0x0200) /* Enable colorburst */ 3868c2ecf20Sopenharmony_ci#define BPC0_GAUD (0x0100) /* Genlock audio enable */ 3878c2ecf20Sopenharmony_ci#define BPC0_UHRES (0x0080) /* Ultrahi res enable */ 3888c2ecf20Sopenharmony_ci#define BPC0_SHRES (0x0040) /* Super hi res mode */ 3898c2ecf20Sopenharmony_ci#define BPC0_BYPASS (0x0020) /* Bypass LUT - AGA */ 3908c2ecf20Sopenharmony_ci#define BPC0_BPU3 (0x0010) /* AGA */ 3918c2ecf20Sopenharmony_ci#define BPC0_LPEN (0x0008) /* Light pen enable */ 3928c2ecf20Sopenharmony_ci#define BPC0_LACE (0x0004) /* Interlace */ 3938c2ecf20Sopenharmony_ci#define BPC0_ERSY (0x0002) /* External resync */ 3948c2ecf20Sopenharmony_ci#define BPC0_ECSENA (0x0001) /* ECS enable */ 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* 3978c2ecf20Sopenharmony_ci * BPLCON2 -- Bitplane Control Register 2 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci#define BPC2_ZDBPSEL2 (0x4000) /* Bitplane to be used for ZD - AGA */ 4018c2ecf20Sopenharmony_ci#define BPC2_ZDBPSEL1 (0x2000) 4028c2ecf20Sopenharmony_ci#define BPC2_ZDBPSEL0 (0x1000) 4038c2ecf20Sopenharmony_ci#define BPC2_ZDBPEN (0x0800) /* Enable ZD with ZDBPSELx - AGA */ 4048c2ecf20Sopenharmony_ci#define BPC2_ZDCTEN (0x0400) /* Enable ZD with palette bit #31 - AGA */ 4058c2ecf20Sopenharmony_ci#define BPC2_KILLEHB (0x0200) /* Kill EHB mode - AGA */ 4068c2ecf20Sopenharmony_ci#define BPC2_RDRAM (0x0100) /* Color table accesses read, not write - AGA */ 4078c2ecf20Sopenharmony_ci#define BPC2_SOGEN (0x0080) /* SOG output pin high - AGA */ 4088c2ecf20Sopenharmony_ci#define BPC2_PF2PRI (0x0040) /* PF2 priority over PF1 */ 4098c2ecf20Sopenharmony_ci#define BPC2_PF2P2 (0x0020) /* PF2 priority wrt sprites */ 4108c2ecf20Sopenharmony_ci#define BPC2_PF2P1 (0x0010) 4118c2ecf20Sopenharmony_ci#define BPC2_PF2P0 (0x0008) 4128c2ecf20Sopenharmony_ci#define BPC2_PF1P2 (0x0004) /* ditto PF1 */ 4138c2ecf20Sopenharmony_ci#define BPC2_PF1P1 (0x0002) 4148c2ecf20Sopenharmony_ci#define BPC2_PF1P0 (0x0001) 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* 4178c2ecf20Sopenharmony_ci * BPLCON3 -- Bitplane Control Register 3 (AGA) 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci#define BPC3_BANK2 (0x8000) /* Bits to select color register bank */ 4218c2ecf20Sopenharmony_ci#define BPC3_BANK1 (0x4000) 4228c2ecf20Sopenharmony_ci#define BPC3_BANK0 (0x2000) 4238c2ecf20Sopenharmony_ci#define BPC3_PF2OF2 (0x1000) /* Bits for color table offset when PF2 */ 4248c2ecf20Sopenharmony_ci#define BPC3_PF2OF1 (0x0800) 4258c2ecf20Sopenharmony_ci#define BPC3_PF2OF0 (0x0400) 4268c2ecf20Sopenharmony_ci#define BPC3_LOCT (0x0200) /* Color register writes go to low bits */ 4278c2ecf20Sopenharmony_ci#define BPC3_SPRES1 (0x0080) /* Sprite resolution bits */ 4288c2ecf20Sopenharmony_ci#define BPC3_SPRES0 (0x0040) 4298c2ecf20Sopenharmony_ci#define BPC3_BRDRBLNK (0x0020) /* Border blanked? */ 4308c2ecf20Sopenharmony_ci#define BPC3_BRDRTRAN (0x0010) /* Border transparent? */ 4318c2ecf20Sopenharmony_ci#define BPC3_ZDCLKEN (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */ 4328c2ecf20Sopenharmony_ci#define BPC3_BRDRSPRT (0x0002) /* Sprites in border? */ 4338c2ecf20Sopenharmony_ci#define BPC3_EXTBLKEN (0x0001) /* BLANK programmable */ 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* 4368c2ecf20Sopenharmony_ci * BPLCON4 -- Bitplane Control Register 4 (AGA) 4378c2ecf20Sopenharmony_ci */ 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci#define BPC4_BPLAM7 (0x8000) /* bitplane color XOR field */ 4408c2ecf20Sopenharmony_ci#define BPC4_BPLAM6 (0x4000) 4418c2ecf20Sopenharmony_ci#define BPC4_BPLAM5 (0x2000) 4428c2ecf20Sopenharmony_ci#define BPC4_BPLAM4 (0x1000) 4438c2ecf20Sopenharmony_ci#define BPC4_BPLAM3 (0x0800) 4448c2ecf20Sopenharmony_ci#define BPC4_BPLAM2 (0x0400) 4458c2ecf20Sopenharmony_ci#define BPC4_BPLAM1 (0x0200) 4468c2ecf20Sopenharmony_ci#define BPC4_BPLAM0 (0x0100) 4478c2ecf20Sopenharmony_ci#define BPC4_ESPRM7 (0x0080) /* 4 high bits for even sprite colors */ 4488c2ecf20Sopenharmony_ci#define BPC4_ESPRM6 (0x0040) 4498c2ecf20Sopenharmony_ci#define BPC4_ESPRM5 (0x0020) 4508c2ecf20Sopenharmony_ci#define BPC4_ESPRM4 (0x0010) 4518c2ecf20Sopenharmony_ci#define BPC4_OSPRM7 (0x0008) /* 4 high bits for odd sprite colors */ 4528c2ecf20Sopenharmony_ci#define BPC4_OSPRM6 (0x0004) 4538c2ecf20Sopenharmony_ci#define BPC4_OSPRM5 (0x0002) 4548c2ecf20Sopenharmony_ci#define BPC4_OSPRM4 (0x0001) 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* 4578c2ecf20Sopenharmony_ci * BEAMCON0 -- Beam Control Register 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci#define BMC0_HARDDIS (0x4000) /* Disable hardware limits */ 4618c2ecf20Sopenharmony_ci#define BMC0_LPENDIS (0x2000) /* Disable light pen latch */ 4628c2ecf20Sopenharmony_ci#define BMC0_VARVBEN (0x1000) /* Enable variable vertical blank */ 4638c2ecf20Sopenharmony_ci#define BMC0_LOLDIS (0x0800) /* Disable long/short line toggle */ 4648c2ecf20Sopenharmony_ci#define BMC0_CSCBEN (0x0400) /* Composite sync/blank */ 4658c2ecf20Sopenharmony_ci#define BMC0_VARVSYEN (0x0200) /* Enable variable vertical sync */ 4668c2ecf20Sopenharmony_ci#define BMC0_VARHSYEN (0x0100) /* Enable variable horizontal sync */ 4678c2ecf20Sopenharmony_ci#define BMC0_VARBEAMEN (0x0080) /* Enable variable beam counters */ 4688c2ecf20Sopenharmony_ci#define BMC0_DUAL (0x0040) /* Enable alternate horizontal beam counter */ 4698c2ecf20Sopenharmony_ci#define BMC0_PAL (0x0020) /* Set decodes for PAL */ 4708c2ecf20Sopenharmony_ci#define BMC0_VARCSYEN (0x0010) /* Enable variable composite sync */ 4718c2ecf20Sopenharmony_ci#define BMC0_BLANKEN (0x0008) /* Blank enable (no longer used on AGA) */ 4728c2ecf20Sopenharmony_ci#define BMC0_CSYTRUE (0x0004) /* CSY polarity */ 4738c2ecf20Sopenharmony_ci#define BMC0_VSYTRUE (0x0002) /* VSY polarity */ 4748c2ecf20Sopenharmony_ci#define BMC0_HSYTRUE (0x0001) /* HSY polarity */ 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* 4788c2ecf20Sopenharmony_ci * FMODE -- Fetch Mode Control Register (AGA) 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci#define FMODE_SSCAN2 (0x8000) /* Sprite scan-doubling */ 4828c2ecf20Sopenharmony_ci#define FMODE_BSCAN2 (0x4000) /* Use PF2 modulus every other line */ 4838c2ecf20Sopenharmony_ci#define FMODE_SPAGEM (0x0008) /* Sprite page mode */ 4848c2ecf20Sopenharmony_ci#define FMODE_SPR32 (0x0004) /* Sprite 32 bit fetch */ 4858c2ecf20Sopenharmony_ci#define FMODE_BPAGEM (0x0002) /* Bitplane page mode */ 4868c2ecf20Sopenharmony_ci#define FMODE_BPL32 (0x0001) /* Bitplane 32 bit fetch */ 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* 4898c2ecf20Sopenharmony_ci * Tags used to indicate a specific Pixel Clock 4908c2ecf20Sopenharmony_ci * 4918c2ecf20Sopenharmony_ci * clk_shift is the shift value to get the timings in 35 ns units 4928c2ecf20Sopenharmony_ci */ 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cienum { TAG_SHRES, TAG_HIRES, TAG_LORES }; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* 4978c2ecf20Sopenharmony_ci * Tags used to indicate the specific chipset 4988c2ecf20Sopenharmony_ci */ 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cienum { TAG_OCS, TAG_ECS, TAG_AGA }; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* 5038c2ecf20Sopenharmony_ci * Tags used to indicate the memory bandwidth 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cienum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 }; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* 5108c2ecf20Sopenharmony_ci * Clock Definitions, Maximum Display Depth 5118c2ecf20Sopenharmony_ci * 5128c2ecf20Sopenharmony_ci * These depend on the E-Clock or the Chipset, so they are filled in 5138c2ecf20Sopenharmony_ci * dynamically 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic u_long pixclock[3]; /* SHRES/HIRES/LORES: index = clk_shift */ 5178c2ecf20Sopenharmony_cistatic u_short maxdepth[3]; /* SHRES/HIRES/LORES: index = clk_shift */ 5188c2ecf20Sopenharmony_cistatic u_short maxfmode, chipset; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* 5228c2ecf20Sopenharmony_ci * Broadcast Video Timings 5238c2ecf20Sopenharmony_ci * 5248c2ecf20Sopenharmony_ci * Horizontal values are in 35 ns (SHRES) units 5258c2ecf20Sopenharmony_ci * Vertical values are in interlaced scanlines 5268c2ecf20Sopenharmony_ci */ 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci#define PAL_DIWSTRT_H (360) /* PAL Window Limits */ 5298c2ecf20Sopenharmony_ci#define PAL_DIWSTRT_V (48) 5308c2ecf20Sopenharmony_ci#define PAL_HTOTAL (1816) 5318c2ecf20Sopenharmony_ci#define PAL_VTOTAL (625) 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci#define NTSC_DIWSTRT_H (360) /* NTSC Window Limits */ 5348c2ecf20Sopenharmony_ci#define NTSC_DIWSTRT_V (40) 5358c2ecf20Sopenharmony_ci#define NTSC_HTOTAL (1816) 5368c2ecf20Sopenharmony_ci#define NTSC_VTOTAL (525) 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* 5408c2ecf20Sopenharmony_ci * Various macros 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci#define up2(v) (((v) + 1) & -2) 5448c2ecf20Sopenharmony_ci#define down2(v) ((v) & -2) 5458c2ecf20Sopenharmony_ci#define div2(v) ((v)>>1) 5468c2ecf20Sopenharmony_ci#define mod2(v) ((v) & 1) 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci#define up4(v) (((v) + 3) & -4) 5498c2ecf20Sopenharmony_ci#define down4(v) ((v) & -4) 5508c2ecf20Sopenharmony_ci#define mul4(v) ((v) << 2) 5518c2ecf20Sopenharmony_ci#define div4(v) ((v)>>2) 5528c2ecf20Sopenharmony_ci#define mod4(v) ((v) & 3) 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci#define up8(v) (((v) + 7) & -8) 5558c2ecf20Sopenharmony_ci#define down8(v) ((v) & -8) 5568c2ecf20Sopenharmony_ci#define div8(v) ((v)>>3) 5578c2ecf20Sopenharmony_ci#define mod8(v) ((v) & 7) 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci#define up16(v) (((v) + 15) & -16) 5608c2ecf20Sopenharmony_ci#define down16(v) ((v) & -16) 5618c2ecf20Sopenharmony_ci#define div16(v) ((v)>>4) 5628c2ecf20Sopenharmony_ci#define mod16(v) ((v) & 15) 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci#define up32(v) (((v) + 31) & -32) 5658c2ecf20Sopenharmony_ci#define down32(v) ((v) & -32) 5668c2ecf20Sopenharmony_ci#define div32(v) ((v)>>5) 5678c2ecf20Sopenharmony_ci#define mod32(v) ((v) & 31) 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci#define up64(v) (((v) + 63) & -64) 5708c2ecf20Sopenharmony_ci#define down64(v) ((v) & -64) 5718c2ecf20Sopenharmony_ci#define div64(v) ((v)>>6) 5728c2ecf20Sopenharmony_ci#define mod64(v) ((v) & 63) 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci#define upx(x, v) (((v) + (x) - 1) & -(x)) 5758c2ecf20Sopenharmony_ci#define downx(x, v) ((v) & -(x)) 5768c2ecf20Sopenharmony_ci#define modx(x, v) ((v) & ((x) - 1)) 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci/* 5798c2ecf20Sopenharmony_ci * FIXME: Use C variants of the code marked with #ifdef __mc68000__ 5808c2ecf20Sopenharmony_ci * in the driver. It shouldn't negatively affect the performance and 5818c2ecf20Sopenharmony_ci * is required for APUS support (once it is re-added to the kernel). 5828c2ecf20Sopenharmony_ci * Needs to be tested on the hardware though.. 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_ci/* if x1 is not a constant, this macro won't make real sense :-) */ 5858c2ecf20Sopenharmony_ci#ifdef __mc68000__ 5868c2ecf20Sopenharmony_ci#define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \ 5878c2ecf20Sopenharmony_ci "d" (x2), "d" ((long)((x1) / 0x100000000ULL)), "0" ((long)(x1))); res;}) 5888c2ecf20Sopenharmony_ci#else 5898c2ecf20Sopenharmony_ci/* We know a bit about the numbers, so we can do it this way */ 5908c2ecf20Sopenharmony_ci#define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \ 5918c2ecf20Sopenharmony_ci ((((long)((unsigned long long)x1 >> 8) % x2) << 8) / x2)) 5928c2ecf20Sopenharmony_ci#endif 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci#define highw(x) ((u_long)(x)>>16 & 0xffff) 5958c2ecf20Sopenharmony_ci#define loww(x) ((u_long)(x) & 0xffff) 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci#define custom amiga_custom 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci#define VBlankOn() custom.intena = IF_SETCLR|IF_COPER 6008c2ecf20Sopenharmony_ci#define VBlankOff() custom.intena = IF_COPER 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* 6048c2ecf20Sopenharmony_ci * Chip RAM we reserve for the Frame Buffer 6058c2ecf20Sopenharmony_ci * 6068c2ecf20Sopenharmony_ci * This defines the Maximum Virtual Screen Size 6078c2ecf20Sopenharmony_ci * (Setable per kernel options?) 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci#define VIDEOMEMSIZE_AGA_2M (1310720) /* AGA (2MB) : max 1280*1024*256 */ 6118c2ecf20Sopenharmony_ci#define VIDEOMEMSIZE_AGA_1M (786432) /* AGA (1MB) : max 1024*768*256 */ 6128c2ecf20Sopenharmony_ci#define VIDEOMEMSIZE_ECS_2M (655360) /* ECS (2MB) : max 1280*1024*16 */ 6138c2ecf20Sopenharmony_ci#define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */ 6148c2ecf20Sopenharmony_ci#define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */ 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci#define SPRITEMEMSIZE (64 * 64 / 4) /* max 64*64*4 */ 6178c2ecf20Sopenharmony_ci#define DUMMYSPRITEMEMSIZE (8) 6188c2ecf20Sopenharmony_cistatic u_long spritememory; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci#define CHIPRAM_SAFETY_LIMIT (16384) 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic u_long videomemory; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* 6258c2ecf20Sopenharmony_ci * This is the earliest allowed start of fetching display data. 6268c2ecf20Sopenharmony_ci * Only if you really want no hardware cursor and audio, 6278c2ecf20Sopenharmony_ci * set this to 128, but let it better at 192 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic u_long min_fstrt = 192; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci#define assignchunk(name, type, ptr, size) \ 6338c2ecf20Sopenharmony_ci{ \ 6348c2ecf20Sopenharmony_ci (name) = (type)(ptr); \ 6358c2ecf20Sopenharmony_ci ptr += size; \ 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci /* 6408c2ecf20Sopenharmony_ci * Copper Instructions 6418c2ecf20Sopenharmony_ci */ 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci#define CMOVE(val, reg) (CUSTOM_OFS(reg) << 16 | (val)) 6448c2ecf20Sopenharmony_ci#define CMOVE2(val, reg) ((CUSTOM_OFS(reg) + 2) << 16 | (val)) 6458c2ecf20Sopenharmony_ci#define CWAIT(x, y) (((y) & 0x1fe) << 23 | ((x) & 0x7f0) << 13 | 0x0001fffe) 6468c2ecf20Sopenharmony_ci#define CEND (0xfffffffe) 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_citypedef union { 6508c2ecf20Sopenharmony_ci u_long l; 6518c2ecf20Sopenharmony_ci u_short w[2]; 6528c2ecf20Sopenharmony_ci} copins; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic struct copdisplay { 6558c2ecf20Sopenharmony_ci copins *init; 6568c2ecf20Sopenharmony_ci copins *wait; 6578c2ecf20Sopenharmony_ci copins *list[2][2]; 6588c2ecf20Sopenharmony_ci copins *rebuild[2]; 6598c2ecf20Sopenharmony_ci} copdisplay; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cistatic u_short currentcop = 0; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* 6648c2ecf20Sopenharmony_ci * Hardware Cursor API Definitions 6658c2ecf20Sopenharmony_ci * These used to be in linux/fb.h, but were preliminary and used by 6668c2ecf20Sopenharmony_ci * amifb only anyway 6678c2ecf20Sopenharmony_ci */ 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci#define FBIOGET_FCURSORINFO 0x4607 6708c2ecf20Sopenharmony_ci#define FBIOGET_VCURSORINFO 0x4608 6718c2ecf20Sopenharmony_ci#define FBIOPUT_VCURSORINFO 0x4609 6728c2ecf20Sopenharmony_ci#define FBIOGET_CURSORSTATE 0x460A 6738c2ecf20Sopenharmony_ci#define FBIOPUT_CURSORSTATE 0x460B 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistruct fb_fix_cursorinfo { 6778c2ecf20Sopenharmony_ci __u16 crsr_width; /* width and height of the cursor in */ 6788c2ecf20Sopenharmony_ci __u16 crsr_height; /* pixels (zero if no cursor) */ 6798c2ecf20Sopenharmony_ci __u16 crsr_xsize; /* cursor size in display pixels */ 6808c2ecf20Sopenharmony_ci __u16 crsr_ysize; 6818c2ecf20Sopenharmony_ci __u16 crsr_color1; /* colormap entry for cursor color1 */ 6828c2ecf20Sopenharmony_ci __u16 crsr_color2; /* colormap entry for cursor color2 */ 6838c2ecf20Sopenharmony_ci}; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_cistruct fb_var_cursorinfo { 6868c2ecf20Sopenharmony_ci __u16 width; 6878c2ecf20Sopenharmony_ci __u16 height; 6888c2ecf20Sopenharmony_ci __u16 xspot; 6898c2ecf20Sopenharmony_ci __u16 yspot; 6908c2ecf20Sopenharmony_ci __u8 data[1]; /* field with [height][width] */ 6918c2ecf20Sopenharmony_ci}; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistruct fb_cursorstate { 6948c2ecf20Sopenharmony_ci __s16 xoffset; 6958c2ecf20Sopenharmony_ci __s16 yoffset; 6968c2ecf20Sopenharmony_ci __u16 mode; 6978c2ecf20Sopenharmony_ci}; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci#define FB_CURSOR_OFF 0 7008c2ecf20Sopenharmony_ci#define FB_CURSOR_ON 1 7018c2ecf20Sopenharmony_ci#define FB_CURSOR_FLASH 2 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci /* 7058c2ecf20Sopenharmony_ci * Hardware Cursor 7068c2ecf20Sopenharmony_ci */ 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic int cursorrate = 20; /* Number of frames/flash toggle */ 7098c2ecf20Sopenharmony_cistatic u_short cursorstate = -1; 7108c2ecf20Sopenharmony_cistatic u_short cursormode = FB_CURSOR_OFF; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic u_short *lofsprite, *shfsprite, *dummysprite; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* 7158c2ecf20Sopenharmony_ci * Current Video Mode 7168c2ecf20Sopenharmony_ci */ 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistruct amifb_par { 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci /* General Values */ 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci int xres; /* vmode */ 7238c2ecf20Sopenharmony_ci int yres; /* vmode */ 7248c2ecf20Sopenharmony_ci int vxres; /* vmode */ 7258c2ecf20Sopenharmony_ci int vyres; /* vmode */ 7268c2ecf20Sopenharmony_ci int xoffset; /* vmode */ 7278c2ecf20Sopenharmony_ci int yoffset; /* vmode */ 7288c2ecf20Sopenharmony_ci u_short bpp; /* vmode */ 7298c2ecf20Sopenharmony_ci u_short clk_shift; /* vmode */ 7308c2ecf20Sopenharmony_ci u_short line_shift; /* vmode */ 7318c2ecf20Sopenharmony_ci int vmode; /* vmode */ 7328c2ecf20Sopenharmony_ci u_short diwstrt_h; /* vmode */ 7338c2ecf20Sopenharmony_ci u_short diwstop_h; /* vmode */ 7348c2ecf20Sopenharmony_ci u_short diwstrt_v; /* vmode */ 7358c2ecf20Sopenharmony_ci u_short diwstop_v; /* vmode */ 7368c2ecf20Sopenharmony_ci u_long next_line; /* modulo for next line */ 7378c2ecf20Sopenharmony_ci u_long next_plane; /* modulo for next plane */ 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* Cursor Values */ 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci struct { 7428c2ecf20Sopenharmony_ci short crsr_x; /* movecursor */ 7438c2ecf20Sopenharmony_ci short crsr_y; /* movecursor */ 7448c2ecf20Sopenharmony_ci short spot_x; 7458c2ecf20Sopenharmony_ci short spot_y; 7468c2ecf20Sopenharmony_ci u_short height; 7478c2ecf20Sopenharmony_ci u_short width; 7488c2ecf20Sopenharmony_ci u_short fmode; 7498c2ecf20Sopenharmony_ci } crsr; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* OCS Hardware Registers */ 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci u_long bplpt0; /* vmode, pan (Note: physical address) */ 7548c2ecf20Sopenharmony_ci u_long bplpt0wrap; /* vmode, pan (Note: physical address) */ 7558c2ecf20Sopenharmony_ci u_short ddfstrt; 7568c2ecf20Sopenharmony_ci u_short ddfstop; 7578c2ecf20Sopenharmony_ci u_short bpl1mod; 7588c2ecf20Sopenharmony_ci u_short bpl2mod; 7598c2ecf20Sopenharmony_ci u_short bplcon0; /* vmode */ 7608c2ecf20Sopenharmony_ci u_short bplcon1; /* vmode */ 7618c2ecf20Sopenharmony_ci u_short htotal; /* vmode */ 7628c2ecf20Sopenharmony_ci u_short vtotal; /* vmode */ 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* Additional ECS Hardware Registers */ 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci u_short bplcon3; /* vmode */ 7678c2ecf20Sopenharmony_ci u_short beamcon0; /* vmode */ 7688c2ecf20Sopenharmony_ci u_short hsstrt; /* vmode */ 7698c2ecf20Sopenharmony_ci u_short hsstop; /* vmode */ 7708c2ecf20Sopenharmony_ci u_short hbstrt; /* vmode */ 7718c2ecf20Sopenharmony_ci u_short hbstop; /* vmode */ 7728c2ecf20Sopenharmony_ci u_short vsstrt; /* vmode */ 7738c2ecf20Sopenharmony_ci u_short vsstop; /* vmode */ 7748c2ecf20Sopenharmony_ci u_short vbstrt; /* vmode */ 7758c2ecf20Sopenharmony_ci u_short vbstop; /* vmode */ 7768c2ecf20Sopenharmony_ci u_short hcenter; /* vmode */ 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* Additional AGA Hardware Registers */ 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci u_short fmode; /* vmode */ 7818c2ecf20Sopenharmony_ci}; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* 7858c2ecf20Sopenharmony_ci * Saved color entry 0 so we can restore it when unblanking 7868c2ecf20Sopenharmony_ci */ 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_cistatic u_char red0, green0, blue0; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_AMIGA_ECS) 7928c2ecf20Sopenharmony_cistatic u_short ecs_palette[32]; 7938c2ecf20Sopenharmony_ci#endif 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci /* 7978c2ecf20Sopenharmony_ci * Latches for Display Changes during VBlank 7988c2ecf20Sopenharmony_ci */ 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_cistatic u_short do_vmode_full = 0; /* Change the Video Mode */ 8018c2ecf20Sopenharmony_cistatic u_short do_vmode_pan = 0; /* Update the Video Mode */ 8028c2ecf20Sopenharmony_cistatic short do_blank = 0; /* (Un)Blank the Screen (±1) */ 8038c2ecf20Sopenharmony_cistatic u_short do_cursor = 0; /* Move the Cursor */ 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci /* 8078c2ecf20Sopenharmony_ci * Various Flags 8088c2ecf20Sopenharmony_ci */ 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic u_short is_blanked = 0; /* Screen is Blanked */ 8118c2ecf20Sopenharmony_cistatic u_short is_lace = 0; /* Screen is laced */ 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci /* 8148c2ecf20Sopenharmony_ci * Predefined Video Modes 8158c2ecf20Sopenharmony_ci * 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cistatic struct fb_videomode ami_modedb[] __initdata = { 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci /* 8218c2ecf20Sopenharmony_ci * AmigaOS Video Modes 8228c2ecf20Sopenharmony_ci * 8238c2ecf20Sopenharmony_ci * If you change these, make sure to update DEFMODE_* as well! 8248c2ecf20Sopenharmony_ci */ 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci { 8278c2ecf20Sopenharmony_ci /* 640x200, 15 kHz, 60 Hz (NTSC) */ 8288c2ecf20Sopenharmony_ci "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2, 8298c2ecf20Sopenharmony_ci FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 8308c2ecf20Sopenharmony_ci }, { 8318c2ecf20Sopenharmony_ci /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ 8328c2ecf20Sopenharmony_ci "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4, 8338c2ecf20Sopenharmony_ci FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 8348c2ecf20Sopenharmony_ci }, { 8358c2ecf20Sopenharmony_ci /* 640x256, 15 kHz, 50 Hz (PAL) */ 8368c2ecf20Sopenharmony_ci "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2, 8378c2ecf20Sopenharmony_ci FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 8388c2ecf20Sopenharmony_ci }, { 8398c2ecf20Sopenharmony_ci /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */ 8408c2ecf20Sopenharmony_ci "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4, 8418c2ecf20Sopenharmony_ci FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 8428c2ecf20Sopenharmony_ci }, { 8438c2ecf20Sopenharmony_ci /* 640x480, 29 kHz, 57 Hz */ 8448c2ecf20Sopenharmony_ci "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8, 8458c2ecf20Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 8468c2ecf20Sopenharmony_ci }, { 8478c2ecf20Sopenharmony_ci /* 640x960, 29 kHz, 57 Hz interlaced */ 8488c2ecf20Sopenharmony_ci "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, 8498c2ecf20Sopenharmony_ci 16, 8508c2ecf20Sopenharmony_ci 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 8518c2ecf20Sopenharmony_ci }, { 8528c2ecf20Sopenharmony_ci /* 640x200, 15 kHz, 72 Hz */ 8538c2ecf20Sopenharmony_ci "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5, 8548c2ecf20Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 8558c2ecf20Sopenharmony_ci }, { 8568c2ecf20Sopenharmony_ci /* 640x400, 15 kHz, 72 Hz interlaced */ 8578c2ecf20Sopenharmony_ci "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, 8588c2ecf20Sopenharmony_ci 10, 8598c2ecf20Sopenharmony_ci 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 8608c2ecf20Sopenharmony_ci }, { 8618c2ecf20Sopenharmony_ci /* 640x400, 29 kHz, 68 Hz */ 8628c2ecf20Sopenharmony_ci "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8, 8638c2ecf20Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 8648c2ecf20Sopenharmony_ci }, { 8658c2ecf20Sopenharmony_ci /* 640x800, 29 kHz, 68 Hz interlaced */ 8668c2ecf20Sopenharmony_ci "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, 8678c2ecf20Sopenharmony_ci 16, 8688c2ecf20Sopenharmony_ci 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 8698c2ecf20Sopenharmony_ci }, { 8708c2ecf20Sopenharmony_ci /* 800x300, 23 kHz, 70 Hz */ 8718c2ecf20Sopenharmony_ci "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7, 8728c2ecf20Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 8738c2ecf20Sopenharmony_ci }, { 8748c2ecf20Sopenharmony_ci /* 800x600, 23 kHz, 70 Hz interlaced */ 8758c2ecf20Sopenharmony_ci "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, 8768c2ecf20Sopenharmony_ci 14, 8778c2ecf20Sopenharmony_ci 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 8788c2ecf20Sopenharmony_ci }, { 8798c2ecf20Sopenharmony_ci /* 640x200, 27 kHz, 57 Hz doublescan */ 8808c2ecf20Sopenharmony_ci "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4, 8818c2ecf20Sopenharmony_ci 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP 8828c2ecf20Sopenharmony_ci }, { 8838c2ecf20Sopenharmony_ci /* 640x400, 27 kHz, 57 Hz */ 8848c2ecf20Sopenharmony_ci "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7, 8858c2ecf20Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 8868c2ecf20Sopenharmony_ci }, { 8878c2ecf20Sopenharmony_ci /* 640x800, 27 kHz, 57 Hz interlaced */ 8888c2ecf20Sopenharmony_ci "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, 8898c2ecf20Sopenharmony_ci 14, 8908c2ecf20Sopenharmony_ci 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 8918c2ecf20Sopenharmony_ci }, { 8928c2ecf20Sopenharmony_ci /* 640x256, 27 kHz, 47 Hz doublescan */ 8938c2ecf20Sopenharmony_ci "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4, 8948c2ecf20Sopenharmony_ci 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP 8958c2ecf20Sopenharmony_ci }, { 8968c2ecf20Sopenharmony_ci /* 640x512, 27 kHz, 47 Hz */ 8978c2ecf20Sopenharmony_ci "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7, 8988c2ecf20Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 8998c2ecf20Sopenharmony_ci }, { 9008c2ecf20Sopenharmony_ci /* 640x1024, 27 kHz, 47 Hz interlaced */ 9018c2ecf20Sopenharmony_ci "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, 9028c2ecf20Sopenharmony_ci 14, 9038c2ecf20Sopenharmony_ci 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 9048c2ecf20Sopenharmony_ci }, 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci /* 9078c2ecf20Sopenharmony_ci * VGA Video Modes 9088c2ecf20Sopenharmony_ci */ 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci { 9118c2ecf20Sopenharmony_ci /* 640x480, 31 kHz, 60 Hz (VGA) */ 9128c2ecf20Sopenharmony_ci "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2, 9138c2ecf20Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 9148c2ecf20Sopenharmony_ci }, { 9158c2ecf20Sopenharmony_ci /* 640x400, 31 kHz, 70 Hz (VGA) */ 9168c2ecf20Sopenharmony_ci "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2, 9178c2ecf20Sopenharmony_ci FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, 9188c2ecf20Sopenharmony_ci FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 9198c2ecf20Sopenharmony_ci }, 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci#if 0 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* 9248c2ecf20Sopenharmony_ci * A2024 video modes 9258c2ecf20Sopenharmony_ci * These modes don't work yet because there's no A2024 driver. 9268c2ecf20Sopenharmony_ci */ 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci { 9298c2ecf20Sopenharmony_ci /* 1024x800, 10 Hz */ 9308c2ecf20Sopenharmony_ci "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, 9318c2ecf20Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 9328c2ecf20Sopenharmony_ci }, { 9338c2ecf20Sopenharmony_ci /* 1024x800, 15 Hz */ 9348c2ecf20Sopenharmony_ci "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, 9358c2ecf20Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci#endif 9388c2ecf20Sopenharmony_ci}; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci#define NUM_TOTAL_MODES ARRAY_SIZE(ami_modedb) 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic char *mode_option __initdata = NULL; 9438c2ecf20Sopenharmony_cistatic int round_down_bpp = 1; /* for mode probing */ 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci /* 9468c2ecf20Sopenharmony_ci * Some default modes 9478c2ecf20Sopenharmony_ci */ 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci#define DEFMODE_PAL 2 /* "pal" for PAL OCS/ECS */ 9518c2ecf20Sopenharmony_ci#define DEFMODE_NTSC 0 /* "ntsc" for NTSC OCS/ECS */ 9528c2ecf20Sopenharmony_ci#define DEFMODE_AMBER_PAL 3 /* "pal-lace" for flicker fixed PAL (A3000) */ 9538c2ecf20Sopenharmony_ci#define DEFMODE_AMBER_NTSC 1 /* "ntsc-lace" for flicker fixed NTSC (A3000) */ 9548c2ecf20Sopenharmony_ci#define DEFMODE_AGA 19 /* "vga70" for AGA */ 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_cistatic int amifb_ilbm = 0; /* interleaved or normal bitplanes */ 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic u32 amifb_hfmin __initdata; /* monitor hfreq lower limit (Hz) */ 9608c2ecf20Sopenharmony_cistatic u32 amifb_hfmax __initdata; /* monitor hfreq upper limit (Hz) */ 9618c2ecf20Sopenharmony_cistatic u16 amifb_vfmin __initdata; /* monitor vfreq lower limit (Hz) */ 9628c2ecf20Sopenharmony_cistatic u16 amifb_vfmax __initdata; /* monitor vfreq upper limit (Hz) */ 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci /* 9668c2ecf20Sopenharmony_ci * Macros for the conversion from real world values to hardware register 9678c2ecf20Sopenharmony_ci * values 9688c2ecf20Sopenharmony_ci * 9698c2ecf20Sopenharmony_ci * This helps us to keep our attention on the real stuff... 9708c2ecf20Sopenharmony_ci * 9718c2ecf20Sopenharmony_ci * Hardware limits for AGA: 9728c2ecf20Sopenharmony_ci * 9738c2ecf20Sopenharmony_ci * parameter min max step 9748c2ecf20Sopenharmony_ci * --------- --- ---- ---- 9758c2ecf20Sopenharmony_ci * diwstrt_h 0 2047 1 9768c2ecf20Sopenharmony_ci * diwstrt_v 0 2047 1 9778c2ecf20Sopenharmony_ci * diwstop_h 0 4095 1 9788c2ecf20Sopenharmony_ci * diwstop_v 0 4095 1 9798c2ecf20Sopenharmony_ci * 9808c2ecf20Sopenharmony_ci * ddfstrt 0 2032 16 9818c2ecf20Sopenharmony_ci * ddfstop 0 2032 16 9828c2ecf20Sopenharmony_ci * 9838c2ecf20Sopenharmony_ci * htotal 8 2048 8 9848c2ecf20Sopenharmony_ci * hsstrt 0 2040 8 9858c2ecf20Sopenharmony_ci * hsstop 0 2040 8 9868c2ecf20Sopenharmony_ci * vtotal 1 4096 1 9878c2ecf20Sopenharmony_ci * vsstrt 0 4095 1 9888c2ecf20Sopenharmony_ci * vsstop 0 4095 1 9898c2ecf20Sopenharmony_ci * hcenter 0 2040 8 9908c2ecf20Sopenharmony_ci * 9918c2ecf20Sopenharmony_ci * hbstrt 0 2047 1 9928c2ecf20Sopenharmony_ci * hbstop 0 2047 1 9938c2ecf20Sopenharmony_ci * vbstrt 0 4095 1 9948c2ecf20Sopenharmony_ci * vbstop 0 4095 1 9958c2ecf20Sopenharmony_ci * 9968c2ecf20Sopenharmony_ci * Horizontal values are in 35 ns (SHRES) pixels 9978c2ecf20Sopenharmony_ci * Vertical values are in half scanlines 9988c2ecf20Sopenharmony_ci */ 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci/* bplcon1 (smooth scrolling) */ 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci#define hscroll2hw(hscroll) \ 10038c2ecf20Sopenharmony_ci (((hscroll) << 12 & 0x3000) | ((hscroll) << 8 & 0xc300) | \ 10048c2ecf20Sopenharmony_ci ((hscroll) << 4 & 0x0c00) | ((hscroll) << 2 & 0x00f0) | \ 10058c2ecf20Sopenharmony_ci ((hscroll)>>2 & 0x000f)) 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci/* diwstrt/diwstop/diwhigh (visible display window) */ 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci#define diwstrt2hw(diwstrt_h, diwstrt_v) \ 10108c2ecf20Sopenharmony_ci (((diwstrt_v) << 7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff)) 10118c2ecf20Sopenharmony_ci#define diwstop2hw(diwstop_h, diwstop_v) \ 10128c2ecf20Sopenharmony_ci (((diwstop_v) << 7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff)) 10138c2ecf20Sopenharmony_ci#define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \ 10148c2ecf20Sopenharmony_ci (((diwstop_h) << 3 & 0x2000) | ((diwstop_h) << 11 & 0x1800) | \ 10158c2ecf20Sopenharmony_ci ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \ 10168c2ecf20Sopenharmony_ci ((diwstrt_h) << 3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007)) 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci/* ddfstrt/ddfstop (display DMA) */ 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci#define ddfstrt2hw(ddfstrt) div8(ddfstrt) 10218c2ecf20Sopenharmony_ci#define ddfstop2hw(ddfstop) div8(ddfstop) 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */ 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci#define hsstrt2hw(hsstrt) (div8(hsstrt)) 10268c2ecf20Sopenharmony_ci#define hsstop2hw(hsstop) (div8(hsstop)) 10278c2ecf20Sopenharmony_ci#define htotal2hw(htotal) (div8(htotal) - 1) 10288c2ecf20Sopenharmony_ci#define vsstrt2hw(vsstrt) (div2(vsstrt)) 10298c2ecf20Sopenharmony_ci#define vsstop2hw(vsstop) (div2(vsstop)) 10308c2ecf20Sopenharmony_ci#define vtotal2hw(vtotal) (div2(vtotal) - 1) 10318c2ecf20Sopenharmony_ci#define hcenter2hw(htotal) (div8(htotal)) 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */ 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci#define hbstrt2hw(hbstrt) (((hbstrt) << 8 & 0x0700) | ((hbstrt)>>3 & 0x00ff)) 10368c2ecf20Sopenharmony_ci#define hbstop2hw(hbstop) (((hbstop) << 8 & 0x0700) | ((hbstop)>>3 & 0x00ff)) 10378c2ecf20Sopenharmony_ci#define vbstrt2hw(vbstrt) (div2(vbstrt)) 10388c2ecf20Sopenharmony_ci#define vbstop2hw(vbstop) (div2(vbstop)) 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci/* colour */ 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci#define rgb2hw8_high(red, green, blue) \ 10438c2ecf20Sopenharmony_ci (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) 10448c2ecf20Sopenharmony_ci#define rgb2hw8_low(red, green, blue) \ 10458c2ecf20Sopenharmony_ci (((red & 0x0f) << 8) | ((green & 0x0f) << 4) | (blue & 0x0f)) 10468c2ecf20Sopenharmony_ci#define rgb2hw4(red, green, blue) \ 10478c2ecf20Sopenharmony_ci (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) 10488c2ecf20Sopenharmony_ci#define rgb2hw2(red, green, blue) \ 10498c2ecf20Sopenharmony_ci (((red & 0xc0) << 4) | (green & 0xc0) | ((blue & 0xc0)>>4)) 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci/* sprpos/sprctl (sprite positioning) */ 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci#define spr2hw_pos(start_v, start_h) \ 10548c2ecf20Sopenharmony_ci (((start_v) << 7 & 0xff00) | ((start_h)>>3 & 0x00ff)) 10558c2ecf20Sopenharmony_ci#define spr2hw_ctl(start_v, start_h, stop_v) \ 10568c2ecf20Sopenharmony_ci (((stop_v) << 7 & 0xff00) | ((start_v)>>4 & 0x0040) | \ 10578c2ecf20Sopenharmony_ci ((stop_v)>>5 & 0x0020) | ((start_h) << 3 & 0x0018) | \ 10588c2ecf20Sopenharmony_ci ((start_v)>>7 & 0x0004) | ((stop_v)>>8 & 0x0002) | \ 10598c2ecf20Sopenharmony_ci ((start_h)>>2 & 0x0001)) 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci/* get current vertical position of beam */ 10628c2ecf20Sopenharmony_ci#define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe)) 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* 10658c2ecf20Sopenharmony_ci * Copper Initialisation List 10668c2ecf20Sopenharmony_ci */ 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci#define COPINITSIZE (sizeof(copins) * 40) 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_cienum { 10718c2ecf20Sopenharmony_ci cip_bplcon0 10728c2ecf20Sopenharmony_ci}; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci /* 10758c2ecf20Sopenharmony_ci * Long Frame/Short Frame Copper List 10768c2ecf20Sopenharmony_ci * Don't change the order, build_copper()/rebuild_copper() rely on this 10778c2ecf20Sopenharmony_ci */ 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci#define COPLISTSIZE (sizeof(copins) * 64) 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_cienum { 10828c2ecf20Sopenharmony_ci cop_wait, cop_bplcon0, 10838c2ecf20Sopenharmony_ci cop_spr0ptrh, cop_spr0ptrl, 10848c2ecf20Sopenharmony_ci cop_diwstrt, cop_diwstop, 10858c2ecf20Sopenharmony_ci cop_diwhigh, 10868c2ecf20Sopenharmony_ci}; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci /* 10898c2ecf20Sopenharmony_ci * Pixel modes for Bitplanes and Sprites 10908c2ecf20Sopenharmony_ci */ 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_cistatic u_short bplpixmode[3] = { 10938c2ecf20Sopenharmony_ci BPC0_SHRES, /* 35 ns */ 10948c2ecf20Sopenharmony_ci BPC0_HIRES, /* 70 ns */ 10958c2ecf20Sopenharmony_ci 0 /* 140 ns */ 10968c2ecf20Sopenharmony_ci}; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic u_short sprpixmode[3] = { 10998c2ecf20Sopenharmony_ci BPC3_SPRES1 | BPC3_SPRES0, /* 35 ns */ 11008c2ecf20Sopenharmony_ci BPC3_SPRES1, /* 70 ns */ 11018c2ecf20Sopenharmony_ci BPC3_SPRES0 /* 140 ns */ 11028c2ecf20Sopenharmony_ci}; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* 11058c2ecf20Sopenharmony_ci * Fetch modes for Bitplanes and Sprites 11068c2ecf20Sopenharmony_ci */ 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic u_short bplfetchmode[3] = { 11098c2ecf20Sopenharmony_ci 0, /* 1x */ 11108c2ecf20Sopenharmony_ci FMODE_BPL32, /* 2x */ 11118c2ecf20Sopenharmony_ci FMODE_BPAGEM | FMODE_BPL32 /* 4x */ 11128c2ecf20Sopenharmony_ci}; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_cistatic u_short sprfetchmode[3] = { 11158c2ecf20Sopenharmony_ci 0, /* 1x */ 11168c2ecf20Sopenharmony_ci FMODE_SPR32, /* 2x */ 11178c2ecf20Sopenharmony_ci FMODE_SPAGEM | FMODE_SPR32 /* 4x */ 11188c2ecf20Sopenharmony_ci}; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci/* --------------------------- Hardware routines --------------------------- */ 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* 11248c2ecf20Sopenharmony_ci * Get the video params out of `var'. If a value doesn't fit, round 11258c2ecf20Sopenharmony_ci * it up, if it's too big, return -EINVAL. 11268c2ecf20Sopenharmony_ci */ 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cistatic int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par, 11298c2ecf20Sopenharmony_ci const struct fb_info *info) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci u_short clk_shift, line_shift; 11328c2ecf20Sopenharmony_ci u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; 11338c2ecf20Sopenharmony_ci u_int htotal, vtotal; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci /* 11368c2ecf20Sopenharmony_ci * Find a matching Pixel Clock 11378c2ecf20Sopenharmony_ci */ 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++) 11408c2ecf20Sopenharmony_ci if (var->pixclock <= pixclock[clk_shift]) 11418c2ecf20Sopenharmony_ci break; 11428c2ecf20Sopenharmony_ci if (clk_shift > TAG_LORES) { 11438c2ecf20Sopenharmony_ci DPRINTK("pixclock too high\n"); 11448c2ecf20Sopenharmony_ci return -EINVAL; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci par->clk_shift = clk_shift; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci /* 11498c2ecf20Sopenharmony_ci * Check the Geometry Values 11508c2ecf20Sopenharmony_ci */ 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci if ((par->xres = var->xres) < 64) 11538c2ecf20Sopenharmony_ci par->xres = 64; 11548c2ecf20Sopenharmony_ci if ((par->yres = var->yres) < 64) 11558c2ecf20Sopenharmony_ci par->yres = 64; 11568c2ecf20Sopenharmony_ci if ((par->vxres = var->xres_virtual) < par->xres) 11578c2ecf20Sopenharmony_ci par->vxres = par->xres; 11588c2ecf20Sopenharmony_ci if ((par->vyres = var->yres_virtual) < par->yres) 11598c2ecf20Sopenharmony_ci par->vyres = par->yres; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci par->bpp = var->bits_per_pixel; 11628c2ecf20Sopenharmony_ci if (!var->nonstd) { 11638c2ecf20Sopenharmony_ci if (par->bpp < 1) 11648c2ecf20Sopenharmony_ci par->bpp = 1; 11658c2ecf20Sopenharmony_ci if (par->bpp > maxdepth[clk_shift]) { 11668c2ecf20Sopenharmony_ci if (round_down_bpp && maxdepth[clk_shift]) 11678c2ecf20Sopenharmony_ci par->bpp = maxdepth[clk_shift]; 11688c2ecf20Sopenharmony_ci else { 11698c2ecf20Sopenharmony_ci DPRINTK("invalid bpp\n"); 11708c2ecf20Sopenharmony_ci return -EINVAL; 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci } else if (var->nonstd == FB_NONSTD_HAM) { 11748c2ecf20Sopenharmony_ci if (par->bpp < 6) 11758c2ecf20Sopenharmony_ci par->bpp = 6; 11768c2ecf20Sopenharmony_ci if (par->bpp != 6) { 11778c2ecf20Sopenharmony_ci if (par->bpp < 8) 11788c2ecf20Sopenharmony_ci par->bpp = 8; 11798c2ecf20Sopenharmony_ci if (par->bpp != 8 || !IS_AGA) { 11808c2ecf20Sopenharmony_ci DPRINTK("invalid bpp for ham mode\n"); 11818c2ecf20Sopenharmony_ci return -EINVAL; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci } else { 11858c2ecf20Sopenharmony_ci DPRINTK("unknown nonstd mode\n"); 11868c2ecf20Sopenharmony_ci return -EINVAL; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci /* 11908c2ecf20Sopenharmony_ci * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the following 11918c2ecf20Sopenharmony_ci * checks failed and smooth scrolling is not possible 11928c2ecf20Sopenharmony_ci */ 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN; 11958c2ecf20Sopenharmony_ci switch (par->vmode & FB_VMODE_MASK) { 11968c2ecf20Sopenharmony_ci case FB_VMODE_INTERLACED: 11978c2ecf20Sopenharmony_ci line_shift = 0; 11988c2ecf20Sopenharmony_ci break; 11998c2ecf20Sopenharmony_ci case FB_VMODE_NONINTERLACED: 12008c2ecf20Sopenharmony_ci line_shift = 1; 12018c2ecf20Sopenharmony_ci break; 12028c2ecf20Sopenharmony_ci case FB_VMODE_DOUBLE: 12038c2ecf20Sopenharmony_ci if (!IS_AGA) { 12048c2ecf20Sopenharmony_ci DPRINTK("double mode only possible with aga\n"); 12058c2ecf20Sopenharmony_ci return -EINVAL; 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci line_shift = 2; 12088c2ecf20Sopenharmony_ci break; 12098c2ecf20Sopenharmony_ci default: 12108c2ecf20Sopenharmony_ci DPRINTK("unknown video mode\n"); 12118c2ecf20Sopenharmony_ci return -EINVAL; 12128c2ecf20Sopenharmony_ci break; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci par->line_shift = line_shift; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci /* 12178c2ecf20Sopenharmony_ci * Vertical and Horizontal Timings 12188c2ecf20Sopenharmony_ci */ 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci xres_n = par->xres << clk_shift; 12218c2ecf20Sopenharmony_ci yres_n = par->yres << line_shift; 12228c2ecf20Sopenharmony_ci par->htotal = down8((var->left_margin + par->xres + var->right_margin + 12238c2ecf20Sopenharmony_ci var->hsync_len) << clk_shift); 12248c2ecf20Sopenharmony_ci par->vtotal = 12258c2ecf20Sopenharmony_ci down2(((var->upper_margin + par->yres + var->lower_margin + 12268c2ecf20Sopenharmony_ci var->vsync_len) << line_shift) + 1); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci if (IS_AGA) 12298c2ecf20Sopenharmony_ci par->bplcon3 = sprpixmode[clk_shift]; 12308c2ecf20Sopenharmony_ci else 12318c2ecf20Sopenharmony_ci par->bplcon3 = 0; 12328c2ecf20Sopenharmony_ci if (var->sync & FB_SYNC_BROADCAST) { 12338c2ecf20Sopenharmony_ci par->diwstop_h = par->htotal - 12348c2ecf20Sopenharmony_ci ((var->right_margin - var->hsync_len) << clk_shift); 12358c2ecf20Sopenharmony_ci if (IS_AGA) 12368c2ecf20Sopenharmony_ci par->diwstop_h += mod4(var->hsync_len); 12378c2ecf20Sopenharmony_ci else 12388c2ecf20Sopenharmony_ci par->diwstop_h = down4(par->diwstop_h); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci par->diwstrt_h = par->diwstop_h - xres_n; 12418c2ecf20Sopenharmony_ci par->diwstop_v = par->vtotal - 12428c2ecf20Sopenharmony_ci ((var->lower_margin - var->vsync_len) << line_shift); 12438c2ecf20Sopenharmony_ci par->diwstrt_v = par->diwstop_v - yres_n; 12448c2ecf20Sopenharmony_ci if (par->diwstop_h >= par->htotal + 8) { 12458c2ecf20Sopenharmony_ci DPRINTK("invalid diwstop_h\n"); 12468c2ecf20Sopenharmony_ci return -EINVAL; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci if (par->diwstop_v > par->vtotal) { 12498c2ecf20Sopenharmony_ci DPRINTK("invalid diwstop_v\n"); 12508c2ecf20Sopenharmony_ci return -EINVAL; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci if (!IS_OCS) { 12548c2ecf20Sopenharmony_ci /* Initialize sync with some reasonable values for pwrsave */ 12558c2ecf20Sopenharmony_ci par->hsstrt = 160; 12568c2ecf20Sopenharmony_ci par->hsstop = 320; 12578c2ecf20Sopenharmony_ci par->vsstrt = 30; 12588c2ecf20Sopenharmony_ci par->vsstop = 34; 12598c2ecf20Sopenharmony_ci } else { 12608c2ecf20Sopenharmony_ci par->hsstrt = 0; 12618c2ecf20Sopenharmony_ci par->hsstop = 0; 12628c2ecf20Sopenharmony_ci par->vsstrt = 0; 12638c2ecf20Sopenharmony_ci par->vsstop = 0; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci if (par->vtotal > (PAL_VTOTAL + NTSC_VTOTAL) / 2) { 12668c2ecf20Sopenharmony_ci /* PAL video mode */ 12678c2ecf20Sopenharmony_ci if (par->htotal != PAL_HTOTAL) { 12688c2ecf20Sopenharmony_ci DPRINTK("htotal invalid for pal\n"); 12698c2ecf20Sopenharmony_ci return -EINVAL; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci if (par->diwstrt_h < PAL_DIWSTRT_H) { 12728c2ecf20Sopenharmony_ci DPRINTK("diwstrt_h too low for pal\n"); 12738c2ecf20Sopenharmony_ci return -EINVAL; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci if (par->diwstrt_v < PAL_DIWSTRT_V) { 12768c2ecf20Sopenharmony_ci DPRINTK("diwstrt_v too low for pal\n"); 12778c2ecf20Sopenharmony_ci return -EINVAL; 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci htotal = PAL_HTOTAL>>clk_shift; 12808c2ecf20Sopenharmony_ci vtotal = PAL_VTOTAL>>1; 12818c2ecf20Sopenharmony_ci if (!IS_OCS) { 12828c2ecf20Sopenharmony_ci par->beamcon0 = BMC0_PAL; 12838c2ecf20Sopenharmony_ci par->bplcon3 |= BPC3_BRDRBLNK; 12848c2ecf20Sopenharmony_ci } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || 12858c2ecf20Sopenharmony_ci AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { 12868c2ecf20Sopenharmony_ci par->beamcon0 = BMC0_PAL; 12878c2ecf20Sopenharmony_ci par->hsstop = 1; 12888c2ecf20Sopenharmony_ci } else if (amiga_vblank != 50) { 12898c2ecf20Sopenharmony_ci DPRINTK("pal not supported by this chipset\n"); 12908c2ecf20Sopenharmony_ci return -EINVAL; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci } else { 12938c2ecf20Sopenharmony_ci /* NTSC video mode 12948c2ecf20Sopenharmony_ci * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK 12958c2ecf20Sopenharmony_ci * and NTSC activated, so than better let diwstop_h <= 1812 12968c2ecf20Sopenharmony_ci */ 12978c2ecf20Sopenharmony_ci if (par->htotal != NTSC_HTOTAL) { 12988c2ecf20Sopenharmony_ci DPRINTK("htotal invalid for ntsc\n"); 12998c2ecf20Sopenharmony_ci return -EINVAL; 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci if (par->diwstrt_h < NTSC_DIWSTRT_H) { 13028c2ecf20Sopenharmony_ci DPRINTK("diwstrt_h too low for ntsc\n"); 13038c2ecf20Sopenharmony_ci return -EINVAL; 13048c2ecf20Sopenharmony_ci } 13058c2ecf20Sopenharmony_ci if (par->diwstrt_v < NTSC_DIWSTRT_V) { 13068c2ecf20Sopenharmony_ci DPRINTK("diwstrt_v too low for ntsc\n"); 13078c2ecf20Sopenharmony_ci return -EINVAL; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci htotal = NTSC_HTOTAL>>clk_shift; 13108c2ecf20Sopenharmony_ci vtotal = NTSC_VTOTAL>>1; 13118c2ecf20Sopenharmony_ci if (!IS_OCS) { 13128c2ecf20Sopenharmony_ci par->beamcon0 = 0; 13138c2ecf20Sopenharmony_ci par->bplcon3 |= BPC3_BRDRBLNK; 13148c2ecf20Sopenharmony_ci } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || 13158c2ecf20Sopenharmony_ci AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { 13168c2ecf20Sopenharmony_ci par->beamcon0 = 0; 13178c2ecf20Sopenharmony_ci par->hsstop = 1; 13188c2ecf20Sopenharmony_ci } else if (amiga_vblank != 60) { 13198c2ecf20Sopenharmony_ci DPRINTK("ntsc not supported by this chipset\n"); 13208c2ecf20Sopenharmony_ci return -EINVAL; 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci if (IS_OCS) { 13248c2ecf20Sopenharmony_ci if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 || 13258c2ecf20Sopenharmony_ci par->diwstrt_v >= 512 || par->diwstop_v < 256) { 13268c2ecf20Sopenharmony_ci DPRINTK("invalid position for display on ocs\n"); 13278c2ecf20Sopenharmony_ci return -EINVAL; 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci } else if (!IS_OCS) { 13318c2ecf20Sopenharmony_ci /* Programmable video mode */ 13328c2ecf20Sopenharmony_ci par->hsstrt = var->right_margin << clk_shift; 13338c2ecf20Sopenharmony_ci par->hsstop = (var->right_margin + var->hsync_len) << clk_shift; 13348c2ecf20Sopenharmony_ci par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift); 13358c2ecf20Sopenharmony_ci if (!IS_AGA) 13368c2ecf20Sopenharmony_ci par->diwstop_h = down4(par->diwstop_h) - 16; 13378c2ecf20Sopenharmony_ci par->diwstrt_h = par->diwstop_h - xres_n; 13388c2ecf20Sopenharmony_ci par->hbstop = par->diwstrt_h + 4; 13398c2ecf20Sopenharmony_ci par->hbstrt = par->diwstop_h + 4; 13408c2ecf20Sopenharmony_ci if (par->hbstrt >= par->htotal + 8) 13418c2ecf20Sopenharmony_ci par->hbstrt -= par->htotal; 13428c2ecf20Sopenharmony_ci par->hcenter = par->hsstrt + (par->htotal >> 1); 13438c2ecf20Sopenharmony_ci par->vsstrt = var->lower_margin << line_shift; 13448c2ecf20Sopenharmony_ci par->vsstop = (var->lower_margin + var->vsync_len) << line_shift; 13458c2ecf20Sopenharmony_ci par->diwstop_v = par->vtotal; 13468c2ecf20Sopenharmony_ci if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) 13478c2ecf20Sopenharmony_ci par->diwstop_v -= 2; 13488c2ecf20Sopenharmony_ci par->diwstrt_v = par->diwstop_v - yres_n; 13498c2ecf20Sopenharmony_ci par->vbstop = par->diwstrt_v - 2; 13508c2ecf20Sopenharmony_ci par->vbstrt = par->diwstop_v - 2; 13518c2ecf20Sopenharmony_ci if (par->vtotal > 2048) { 13528c2ecf20Sopenharmony_ci DPRINTK("vtotal too high\n"); 13538c2ecf20Sopenharmony_ci return -EINVAL; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci if (par->htotal > 2048) { 13568c2ecf20Sopenharmony_ci DPRINTK("htotal too high\n"); 13578c2ecf20Sopenharmony_ci return -EINVAL; 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci par->bplcon3 |= BPC3_EXTBLKEN; 13608c2ecf20Sopenharmony_ci par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | 13618c2ecf20Sopenharmony_ci BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN | 13628c2ecf20Sopenharmony_ci BMC0_PAL | BMC0_VARCSYEN; 13638c2ecf20Sopenharmony_ci if (var->sync & FB_SYNC_HOR_HIGH_ACT) 13648c2ecf20Sopenharmony_ci par->beamcon0 |= BMC0_HSYTRUE; 13658c2ecf20Sopenharmony_ci if (var->sync & FB_SYNC_VERT_HIGH_ACT) 13668c2ecf20Sopenharmony_ci par->beamcon0 |= BMC0_VSYTRUE; 13678c2ecf20Sopenharmony_ci if (var->sync & FB_SYNC_COMP_HIGH_ACT) 13688c2ecf20Sopenharmony_ci par->beamcon0 |= BMC0_CSYTRUE; 13698c2ecf20Sopenharmony_ci htotal = par->htotal>>clk_shift; 13708c2ecf20Sopenharmony_ci vtotal = par->vtotal>>1; 13718c2ecf20Sopenharmony_ci } else { 13728c2ecf20Sopenharmony_ci DPRINTK("only broadcast modes possible for ocs\n"); 13738c2ecf20Sopenharmony_ci return -EINVAL; 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci /* 13778c2ecf20Sopenharmony_ci * Checking the DMA timing 13788c2ecf20Sopenharmony_ci */ 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci fconst = 16 << maxfmode << clk_shift; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci /* 13838c2ecf20Sopenharmony_ci * smallest window start value without turn off other dma cycles 13848c2ecf20Sopenharmony_ci * than sprite1-7, unless you change min_fstrt 13858c2ecf20Sopenharmony_ci */ 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci fsize = ((maxfmode + clk_shift <= 1) ? fconst : 64); 13898c2ecf20Sopenharmony_ci fstrt = downx(fconst, par->diwstrt_h - 4) - fsize; 13908c2ecf20Sopenharmony_ci if (fstrt < min_fstrt) { 13918c2ecf20Sopenharmony_ci DPRINTK("fetch start too low\n"); 13928c2ecf20Sopenharmony_ci return -EINVAL; 13938c2ecf20Sopenharmony_ci } 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci /* 13968c2ecf20Sopenharmony_ci * smallest window start value where smooth scrolling is possible 13978c2ecf20Sopenharmony_ci */ 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci fstrt = downx(fconst, par->diwstrt_h - fconst + (1 << clk_shift) - 4) - 14008c2ecf20Sopenharmony_ci fsize; 14018c2ecf20Sopenharmony_ci if (fstrt < min_fstrt) 14028c2ecf20Sopenharmony_ci par->vmode &= ~FB_VMODE_SMOOTH_XPAN; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci maxfetchstop = down16(par->htotal - 80); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci fstrt = downx(fconst, par->diwstrt_h - 4) - 64 - fconst; 14078c2ecf20Sopenharmony_ci fsize = upx(fconst, xres_n + 14088c2ecf20Sopenharmony_ci modx(fconst, downx(1 << clk_shift, par->diwstrt_h - 4))); 14098c2ecf20Sopenharmony_ci if (fstrt + fsize > maxfetchstop) 14108c2ecf20Sopenharmony_ci par->vmode &= ~FB_VMODE_SMOOTH_XPAN; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci fsize = upx(fconst, xres_n); 14138c2ecf20Sopenharmony_ci if (fstrt + fsize > maxfetchstop) { 14148c2ecf20Sopenharmony_ci DPRINTK("fetch stop too high\n"); 14158c2ecf20Sopenharmony_ci return -EINVAL; 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci if (maxfmode + clk_shift <= 1) { 14198c2ecf20Sopenharmony_ci fsize = up64(xres_n + fconst - 1); 14208c2ecf20Sopenharmony_ci if (min_fstrt + fsize - 64 > maxfetchstop) 14218c2ecf20Sopenharmony_ci par->vmode &= ~FB_VMODE_SMOOTH_XPAN; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci fsize = up64(xres_n); 14248c2ecf20Sopenharmony_ci if (min_fstrt + fsize - 64 > maxfetchstop) { 14258c2ecf20Sopenharmony_ci DPRINTK("fetch size too high\n"); 14268c2ecf20Sopenharmony_ci return -EINVAL; 14278c2ecf20Sopenharmony_ci } 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci fsize -= 64; 14308c2ecf20Sopenharmony_ci } else 14318c2ecf20Sopenharmony_ci fsize -= fconst; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci /* 14348c2ecf20Sopenharmony_ci * Check if there is enough time to update the bitplane pointers for ywrap 14358c2ecf20Sopenharmony_ci */ 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci if (par->htotal - fsize - 64 < par->bpp * 64) 14388c2ecf20Sopenharmony_ci par->vmode &= ~FB_VMODE_YWRAP; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci /* 14418c2ecf20Sopenharmony_ci * Bitplane calculations and check the Memory Requirements 14428c2ecf20Sopenharmony_ci */ 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci if (amifb_ilbm) { 14458c2ecf20Sopenharmony_ci par->next_plane = div8(upx(16 << maxfmode, par->vxres)); 14468c2ecf20Sopenharmony_ci par->next_line = par->bpp * par->next_plane; 14478c2ecf20Sopenharmony_ci if (par->next_line * par->vyres > info->fix.smem_len) { 14488c2ecf20Sopenharmony_ci DPRINTK("too few video mem\n"); 14498c2ecf20Sopenharmony_ci return -EINVAL; 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci } else { 14528c2ecf20Sopenharmony_ci par->next_line = div8(upx(16 << maxfmode, par->vxres)); 14538c2ecf20Sopenharmony_ci par->next_plane = par->vyres * par->next_line; 14548c2ecf20Sopenharmony_ci if (par->next_plane * par->bpp > info->fix.smem_len) { 14558c2ecf20Sopenharmony_ci DPRINTK("too few video mem\n"); 14568c2ecf20Sopenharmony_ci return -EINVAL; 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* 14618c2ecf20Sopenharmony_ci * Hardware Register Values 14628c2ecf20Sopenharmony_ci */ 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift]; 14658c2ecf20Sopenharmony_ci if (!IS_OCS) 14668c2ecf20Sopenharmony_ci par->bplcon0 |= BPC0_ECSENA; 14678c2ecf20Sopenharmony_ci if (par->bpp == 8) 14688c2ecf20Sopenharmony_ci par->bplcon0 |= BPC0_BPU3; 14698c2ecf20Sopenharmony_ci else 14708c2ecf20Sopenharmony_ci par->bplcon0 |= par->bpp << 12; 14718c2ecf20Sopenharmony_ci if (var->nonstd == FB_NONSTD_HAM) 14728c2ecf20Sopenharmony_ci par->bplcon0 |= BPC0_HAM; 14738c2ecf20Sopenharmony_ci if (var->sync & FB_SYNC_EXT) 14748c2ecf20Sopenharmony_ci par->bplcon0 |= BPC0_ERSY; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci if (IS_AGA) 14778c2ecf20Sopenharmony_ci par->fmode = bplfetchmode[maxfmode]; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci switch (par->vmode & FB_VMODE_MASK) { 14808c2ecf20Sopenharmony_ci case FB_VMODE_INTERLACED: 14818c2ecf20Sopenharmony_ci par->bplcon0 |= BPC0_LACE; 14828c2ecf20Sopenharmony_ci break; 14838c2ecf20Sopenharmony_ci case FB_VMODE_DOUBLE: 14848c2ecf20Sopenharmony_ci if (IS_AGA) 14858c2ecf20Sopenharmony_ci par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2; 14868c2ecf20Sopenharmony_ci break; 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) { 14908c2ecf20Sopenharmony_ci par->xoffset = var->xoffset; 14918c2ecf20Sopenharmony_ci par->yoffset = var->yoffset; 14928c2ecf20Sopenharmony_ci if (par->vmode & FB_VMODE_YWRAP) { 14938c2ecf20Sopenharmony_ci if (par->yoffset >= par->vyres) 14948c2ecf20Sopenharmony_ci par->xoffset = par->yoffset = 0; 14958c2ecf20Sopenharmony_ci } else { 14968c2ecf20Sopenharmony_ci if (par->xoffset > upx(16 << maxfmode, par->vxres - par->xres) || 14978c2ecf20Sopenharmony_ci par->yoffset > par->vyres - par->yres) 14988c2ecf20Sopenharmony_ci par->xoffset = par->yoffset = 0; 14998c2ecf20Sopenharmony_ci } 15008c2ecf20Sopenharmony_ci } else 15018c2ecf20Sopenharmony_ci par->xoffset = par->yoffset = 0; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci par->crsr.crsr_x = par->crsr.crsr_y = 0; 15048c2ecf20Sopenharmony_ci par->crsr.spot_x = par->crsr.spot_y = 0; 15058c2ecf20Sopenharmony_ci par->crsr.height = par->crsr.width = 0; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci return 0; 15088c2ecf20Sopenharmony_ci} 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci /* 15118c2ecf20Sopenharmony_ci * Fill the `var' structure based on the values in `par' and maybe 15128c2ecf20Sopenharmony_ci * other values read out of the hardware. 15138c2ecf20Sopenharmony_ci */ 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_cistatic void ami_encode_var(struct fb_var_screeninfo *var, 15168c2ecf20Sopenharmony_ci struct amifb_par *par) 15178c2ecf20Sopenharmony_ci{ 15188c2ecf20Sopenharmony_ci u_short clk_shift, line_shift; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci memset(var, 0, sizeof(struct fb_var_screeninfo)); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci clk_shift = par->clk_shift; 15238c2ecf20Sopenharmony_ci line_shift = par->line_shift; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci var->xres = par->xres; 15268c2ecf20Sopenharmony_ci var->yres = par->yres; 15278c2ecf20Sopenharmony_ci var->xres_virtual = par->vxres; 15288c2ecf20Sopenharmony_ci var->yres_virtual = par->vyres; 15298c2ecf20Sopenharmony_ci var->xoffset = par->xoffset; 15308c2ecf20Sopenharmony_ci var->yoffset = par->yoffset; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci var->bits_per_pixel = par->bpp; 15338c2ecf20Sopenharmony_ci var->grayscale = 0; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci var->red.offset = 0; 15368c2ecf20Sopenharmony_ci var->red.msb_right = 0; 15378c2ecf20Sopenharmony_ci var->red.length = par->bpp; 15388c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_HAM) 15398c2ecf20Sopenharmony_ci var->red.length -= 2; 15408c2ecf20Sopenharmony_ci var->blue = var->green = var->red; 15418c2ecf20Sopenharmony_ci var->transp.offset = 0; 15428c2ecf20Sopenharmony_ci var->transp.length = 0; 15438c2ecf20Sopenharmony_ci var->transp.msb_right = 0; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_HAM) 15468c2ecf20Sopenharmony_ci var->nonstd = FB_NONSTD_HAM; 15478c2ecf20Sopenharmony_ci else 15488c2ecf20Sopenharmony_ci var->nonstd = 0; 15498c2ecf20Sopenharmony_ci var->activate = 0; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci var->height = -1; 15528c2ecf20Sopenharmony_ci var->width = -1; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci var->pixclock = pixclock[clk_shift]; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci if (IS_AGA && par->fmode & FMODE_BSCAN2) 15578c2ecf20Sopenharmony_ci var->vmode = FB_VMODE_DOUBLE; 15588c2ecf20Sopenharmony_ci else if (par->bplcon0 & BPC0_LACE) 15598c2ecf20Sopenharmony_ci var->vmode = FB_VMODE_INTERLACED; 15608c2ecf20Sopenharmony_ci else 15618c2ecf20Sopenharmony_ci var->vmode = FB_VMODE_NONINTERLACED; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) { 15648c2ecf20Sopenharmony_ci var->hsync_len = (par->hsstop - par->hsstrt)>>clk_shift; 15658c2ecf20Sopenharmony_ci var->right_margin = par->hsstrt>>clk_shift; 15668c2ecf20Sopenharmony_ci var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; 15678c2ecf20Sopenharmony_ci var->vsync_len = (par->vsstop - par->vsstrt)>>line_shift; 15688c2ecf20Sopenharmony_ci var->lower_margin = par->vsstrt>>line_shift; 15698c2ecf20Sopenharmony_ci var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len; 15708c2ecf20Sopenharmony_ci var->sync = 0; 15718c2ecf20Sopenharmony_ci if (par->beamcon0 & BMC0_HSYTRUE) 15728c2ecf20Sopenharmony_ci var->sync |= FB_SYNC_HOR_HIGH_ACT; 15738c2ecf20Sopenharmony_ci if (par->beamcon0 & BMC0_VSYTRUE) 15748c2ecf20Sopenharmony_ci var->sync |= FB_SYNC_VERT_HIGH_ACT; 15758c2ecf20Sopenharmony_ci if (par->beamcon0 & BMC0_CSYTRUE) 15768c2ecf20Sopenharmony_ci var->sync |= FB_SYNC_COMP_HIGH_ACT; 15778c2ecf20Sopenharmony_ci } else { 15788c2ecf20Sopenharmony_ci var->sync = FB_SYNC_BROADCAST; 15798c2ecf20Sopenharmony_ci var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h); 15808c2ecf20Sopenharmony_ci var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len; 15818c2ecf20Sopenharmony_ci var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; 15828c2ecf20Sopenharmony_ci var->vsync_len = 4>>line_shift; 15838c2ecf20Sopenharmony_ci var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len; 15848c2ecf20Sopenharmony_ci var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres - 15858c2ecf20Sopenharmony_ci var->lower_margin - var->vsync_len; 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_ERSY) 15898c2ecf20Sopenharmony_ci var->sync |= FB_SYNC_EXT; 15908c2ecf20Sopenharmony_ci if (par->vmode & FB_VMODE_YWRAP) 15918c2ecf20Sopenharmony_ci var->vmode |= FB_VMODE_YWRAP; 15928c2ecf20Sopenharmony_ci} 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci /* 15968c2ecf20Sopenharmony_ci * Update hardware 15978c2ecf20Sopenharmony_ci */ 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_cistatic void ami_update_par(struct fb_info *info) 16008c2ecf20Sopenharmony_ci{ 16018c2ecf20Sopenharmony_ci struct amifb_par *par = info->par; 16028c2ecf20Sopenharmony_ci short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci clk_shift = par->clk_shift; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci if (!(par->vmode & FB_VMODE_SMOOTH_XPAN)) 16078c2ecf20Sopenharmony_ci par->xoffset = upx(16 << maxfmode, par->xoffset); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci fconst = 16 << maxfmode << clk_shift; 16108c2ecf20Sopenharmony_ci vshift = modx(16 << maxfmode, par->xoffset); 16118c2ecf20Sopenharmony_ci fstrt = par->diwstrt_h - (vshift << clk_shift) - 4; 16128c2ecf20Sopenharmony_ci fsize = (par->xres + vshift) << clk_shift; 16138c2ecf20Sopenharmony_ci shift = modx(fconst, fstrt); 16148c2ecf20Sopenharmony_ci move = downx(2 << maxfmode, div8(par->xoffset)); 16158c2ecf20Sopenharmony_ci if (maxfmode + clk_shift > 1) { 16168c2ecf20Sopenharmony_ci fstrt = downx(fconst, fstrt) - 64; 16178c2ecf20Sopenharmony_ci fsize = upx(fconst, fsize); 16188c2ecf20Sopenharmony_ci fstop = fstrt + fsize - fconst; 16198c2ecf20Sopenharmony_ci } else { 16208c2ecf20Sopenharmony_ci mod = fstrt = downx(fconst, fstrt) - fconst; 16218c2ecf20Sopenharmony_ci fstop = fstrt + upx(fconst, fsize) - 64; 16228c2ecf20Sopenharmony_ci fsize = up64(fsize); 16238c2ecf20Sopenharmony_ci fstrt = fstop - fsize + 64; 16248c2ecf20Sopenharmony_ci if (fstrt < min_fstrt) { 16258c2ecf20Sopenharmony_ci fstop += min_fstrt - fstrt; 16268c2ecf20Sopenharmony_ci fstrt = min_fstrt; 16278c2ecf20Sopenharmony_ci } 16288c2ecf20Sopenharmony_ci move = move - div8((mod - fstrt)>>clk_shift); 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci mod = par->next_line - div8(fsize>>clk_shift); 16318c2ecf20Sopenharmony_ci par->ddfstrt = fstrt; 16328c2ecf20Sopenharmony_ci par->ddfstop = fstop; 16338c2ecf20Sopenharmony_ci par->bplcon1 = hscroll2hw(shift); 16348c2ecf20Sopenharmony_ci par->bpl2mod = mod; 16358c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) 16368c2ecf20Sopenharmony_ci par->bpl2mod += par->next_line; 16378c2ecf20Sopenharmony_ci if (IS_AGA && (par->fmode & FMODE_BSCAN2)) 16388c2ecf20Sopenharmony_ci par->bpl1mod = -div8(fsize>>clk_shift); 16398c2ecf20Sopenharmony_ci else 16408c2ecf20Sopenharmony_ci par->bpl1mod = par->bpl2mod; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci if (par->yoffset) { 16438c2ecf20Sopenharmony_ci par->bplpt0 = info->fix.smem_start + 16448c2ecf20Sopenharmony_ci par->next_line * par->yoffset + move; 16458c2ecf20Sopenharmony_ci if (par->vmode & FB_VMODE_YWRAP) { 16468c2ecf20Sopenharmony_ci if (par->yoffset > par->vyres - par->yres) { 16478c2ecf20Sopenharmony_ci par->bplpt0wrap = info->fix.smem_start + move; 16488c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_LACE && 16498c2ecf20Sopenharmony_ci mod2(par->diwstrt_v + par->vyres - 16508c2ecf20Sopenharmony_ci par->yoffset)) 16518c2ecf20Sopenharmony_ci par->bplpt0wrap += par->next_line; 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci } 16548c2ecf20Sopenharmony_ci } else 16558c2ecf20Sopenharmony_ci par->bplpt0 = info->fix.smem_start + move; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) 16588c2ecf20Sopenharmony_ci par->bplpt0 += par->next_line; 16598c2ecf20Sopenharmony_ci} 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci /* 16638c2ecf20Sopenharmony_ci * Pan or Wrap the Display 16648c2ecf20Sopenharmony_ci * 16658c2ecf20Sopenharmony_ci * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag 16668c2ecf20Sopenharmony_ci * in `var'. 16678c2ecf20Sopenharmony_ci */ 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_cistatic void ami_pan_var(struct fb_var_screeninfo *var, struct fb_info *info) 16708c2ecf20Sopenharmony_ci{ 16718c2ecf20Sopenharmony_ci struct amifb_par *par = info->par; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci par->xoffset = var->xoffset; 16748c2ecf20Sopenharmony_ci par->yoffset = var->yoffset; 16758c2ecf20Sopenharmony_ci if (var->vmode & FB_VMODE_YWRAP) 16768c2ecf20Sopenharmony_ci par->vmode |= FB_VMODE_YWRAP; 16778c2ecf20Sopenharmony_ci else 16788c2ecf20Sopenharmony_ci par->vmode &= ~FB_VMODE_YWRAP; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci do_vmode_pan = 0; 16818c2ecf20Sopenharmony_ci ami_update_par(info); 16828c2ecf20Sopenharmony_ci do_vmode_pan = 1; 16838c2ecf20Sopenharmony_ci} 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_cistatic void ami_update_display(const struct amifb_par *par) 16878c2ecf20Sopenharmony_ci{ 16888c2ecf20Sopenharmony_ci custom.bplcon1 = par->bplcon1; 16898c2ecf20Sopenharmony_ci custom.bpl1mod = par->bpl1mod; 16908c2ecf20Sopenharmony_ci custom.bpl2mod = par->bpl2mod; 16918c2ecf20Sopenharmony_ci custom.ddfstrt = ddfstrt2hw(par->ddfstrt); 16928c2ecf20Sopenharmony_ci custom.ddfstop = ddfstop2hw(par->ddfstop); 16938c2ecf20Sopenharmony_ci} 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci /* 16968c2ecf20Sopenharmony_ci * Change the video mode (called by VBlank interrupt) 16978c2ecf20Sopenharmony_ci */ 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_cistatic void ami_init_display(const struct amifb_par *par) 17008c2ecf20Sopenharmony_ci{ 17018c2ecf20Sopenharmony_ci int i; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; 17048c2ecf20Sopenharmony_ci custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2; 17058c2ecf20Sopenharmony_ci if (!IS_OCS) { 17068c2ecf20Sopenharmony_ci custom.bplcon3 = par->bplcon3; 17078c2ecf20Sopenharmony_ci if (IS_AGA) 17088c2ecf20Sopenharmony_ci custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4; 17098c2ecf20Sopenharmony_ci if (par->beamcon0 & BMC0_VARBEAMEN) { 17108c2ecf20Sopenharmony_ci custom.htotal = htotal2hw(par->htotal); 17118c2ecf20Sopenharmony_ci custom.hbstrt = hbstrt2hw(par->hbstrt); 17128c2ecf20Sopenharmony_ci custom.hbstop = hbstop2hw(par->hbstop); 17138c2ecf20Sopenharmony_ci custom.hsstrt = hsstrt2hw(par->hsstrt); 17148c2ecf20Sopenharmony_ci custom.hsstop = hsstop2hw(par->hsstop); 17158c2ecf20Sopenharmony_ci custom.hcenter = hcenter2hw(par->hcenter); 17168c2ecf20Sopenharmony_ci custom.vtotal = vtotal2hw(par->vtotal); 17178c2ecf20Sopenharmony_ci custom.vbstrt = vbstrt2hw(par->vbstrt); 17188c2ecf20Sopenharmony_ci custom.vbstop = vbstop2hw(par->vbstop); 17198c2ecf20Sopenharmony_ci custom.vsstrt = vsstrt2hw(par->vsstrt); 17208c2ecf20Sopenharmony_ci custom.vsstop = vsstop2hw(par->vsstop); 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci if (!IS_OCS || par->hsstop) 17248c2ecf20Sopenharmony_ci custom.beamcon0 = par->beamcon0; 17258c2ecf20Sopenharmony_ci if (IS_AGA) 17268c2ecf20Sopenharmony_ci custom.fmode = par->fmode; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci /* 17298c2ecf20Sopenharmony_ci * The minimum period for audio depends on htotal 17308c2ecf20Sopenharmony_ci */ 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci amiga_audio_min_period = div16(par->htotal); 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0; 17358c2ecf20Sopenharmony_ci#if 1 17368c2ecf20Sopenharmony_ci if (is_lace) { 17378c2ecf20Sopenharmony_ci i = custom.vposr >> 15; 17388c2ecf20Sopenharmony_ci } else { 17398c2ecf20Sopenharmony_ci custom.vposw = custom.vposr | 0x8000; 17408c2ecf20Sopenharmony_ci i = 1; 17418c2ecf20Sopenharmony_ci } 17428c2ecf20Sopenharmony_ci#else 17438c2ecf20Sopenharmony_ci i = 1; 17448c2ecf20Sopenharmony_ci custom.vposw = custom.vposr | 0x8000; 17458c2ecf20Sopenharmony_ci#endif 17468c2ecf20Sopenharmony_ci custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]); 17478c2ecf20Sopenharmony_ci} 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci /* 17508c2ecf20Sopenharmony_ci * (Un)Blank the screen (called by VBlank interrupt) 17518c2ecf20Sopenharmony_ci */ 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_cistatic void ami_do_blank(const struct amifb_par *par) 17548c2ecf20Sopenharmony_ci{ 17558c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_AMIGA_AGA) 17568c2ecf20Sopenharmony_ci u_short bplcon3 = par->bplcon3; 17578c2ecf20Sopenharmony_ci#endif 17588c2ecf20Sopenharmony_ci u_char red, green, blue; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci if (do_blank > 0) { 17618c2ecf20Sopenharmony_ci custom.dmacon = DMAF_RASTER | DMAF_SPRITE; 17628c2ecf20Sopenharmony_ci red = green = blue = 0; 17638c2ecf20Sopenharmony_ci if (!IS_OCS && do_blank > 1) { 17648c2ecf20Sopenharmony_ci switch (do_blank) { 17658c2ecf20Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 17668c2ecf20Sopenharmony_ci custom.hsstrt = hsstrt2hw(par->hsstrt); 17678c2ecf20Sopenharmony_ci custom.hsstop = hsstop2hw(par->hsstop); 17688c2ecf20Sopenharmony_ci custom.vsstrt = vsstrt2hw(par->vtotal + 4); 17698c2ecf20Sopenharmony_ci custom.vsstop = vsstop2hw(par->vtotal + 4); 17708c2ecf20Sopenharmony_ci break; 17718c2ecf20Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 17728c2ecf20Sopenharmony_ci custom.hsstrt = hsstrt2hw(par->htotal + 16); 17738c2ecf20Sopenharmony_ci custom.hsstop = hsstop2hw(par->htotal + 16); 17748c2ecf20Sopenharmony_ci custom.vsstrt = vsstrt2hw(par->vsstrt); 17758c2ecf20Sopenharmony_ci custom.vsstop = vsstrt2hw(par->vsstop); 17768c2ecf20Sopenharmony_ci break; 17778c2ecf20Sopenharmony_ci case FB_BLANK_POWERDOWN: 17788c2ecf20Sopenharmony_ci custom.hsstrt = hsstrt2hw(par->htotal + 16); 17798c2ecf20Sopenharmony_ci custom.hsstop = hsstop2hw(par->htotal + 16); 17808c2ecf20Sopenharmony_ci custom.vsstrt = vsstrt2hw(par->vtotal + 4); 17818c2ecf20Sopenharmony_ci custom.vsstop = vsstop2hw(par->vtotal + 4); 17828c2ecf20Sopenharmony_ci break; 17838c2ecf20Sopenharmony_ci } 17848c2ecf20Sopenharmony_ci if (!(par->beamcon0 & BMC0_VARBEAMEN)) { 17858c2ecf20Sopenharmony_ci custom.htotal = htotal2hw(par->htotal); 17868c2ecf20Sopenharmony_ci custom.vtotal = vtotal2hw(par->vtotal); 17878c2ecf20Sopenharmony_ci custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN | 17888c2ecf20Sopenharmony_ci BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN; 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci } 17918c2ecf20Sopenharmony_ci } else { 17928c2ecf20Sopenharmony_ci custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; 17938c2ecf20Sopenharmony_ci red = red0; 17948c2ecf20Sopenharmony_ci green = green0; 17958c2ecf20Sopenharmony_ci blue = blue0; 17968c2ecf20Sopenharmony_ci if (!IS_OCS) { 17978c2ecf20Sopenharmony_ci custom.hsstrt = hsstrt2hw(par->hsstrt); 17988c2ecf20Sopenharmony_ci custom.hsstop = hsstop2hw(par->hsstop); 17998c2ecf20Sopenharmony_ci custom.vsstrt = vsstrt2hw(par->vsstrt); 18008c2ecf20Sopenharmony_ci custom.vsstop = vsstop2hw(par->vsstop); 18018c2ecf20Sopenharmony_ci custom.beamcon0 = par->beamcon0; 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_AMIGA_AGA) 18058c2ecf20Sopenharmony_ci if (IS_AGA) { 18068c2ecf20Sopenharmony_ci custom.bplcon3 = bplcon3; 18078c2ecf20Sopenharmony_ci custom.color[0] = rgb2hw8_high(red, green, blue); 18088c2ecf20Sopenharmony_ci custom.bplcon3 = bplcon3 | BPC3_LOCT; 18098c2ecf20Sopenharmony_ci custom.color[0] = rgb2hw8_low(red, green, blue); 18108c2ecf20Sopenharmony_ci custom.bplcon3 = bplcon3; 18118c2ecf20Sopenharmony_ci } else 18128c2ecf20Sopenharmony_ci#endif 18138c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_AMIGA_ECS) 18148c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_SHRES) { 18158c2ecf20Sopenharmony_ci u_short color, mask; 18168c2ecf20Sopenharmony_ci int i; 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci mask = 0x3333; 18198c2ecf20Sopenharmony_ci color = rgb2hw2(red, green, blue); 18208c2ecf20Sopenharmony_ci for (i = 12; i >= 0; i -= 4) 18218c2ecf20Sopenharmony_ci custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; 18228c2ecf20Sopenharmony_ci mask <<= 2; color >>= 2; 18238c2ecf20Sopenharmony_ci for (i = 3; i >= 0; i--) 18248c2ecf20Sopenharmony_ci custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; 18258c2ecf20Sopenharmony_ci } else 18268c2ecf20Sopenharmony_ci#endif 18278c2ecf20Sopenharmony_ci custom.color[0] = rgb2hw4(red, green, blue); 18288c2ecf20Sopenharmony_ci is_blanked = do_blank > 0 ? do_blank : 0; 18298c2ecf20Sopenharmony_ci} 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_cistatic int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, 18328c2ecf20Sopenharmony_ci const struct amifb_par *par) 18338c2ecf20Sopenharmony_ci{ 18348c2ecf20Sopenharmony_ci fix->crsr_width = fix->crsr_xsize = par->crsr.width; 18358c2ecf20Sopenharmony_ci fix->crsr_height = fix->crsr_ysize = par->crsr.height; 18368c2ecf20Sopenharmony_ci fix->crsr_color1 = 17; 18378c2ecf20Sopenharmony_ci fix->crsr_color2 = 18; 18388c2ecf20Sopenharmony_ci return 0; 18398c2ecf20Sopenharmony_ci} 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_cistatic int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, 18428c2ecf20Sopenharmony_ci u_char __user *data, 18438c2ecf20Sopenharmony_ci const struct amifb_par *par) 18448c2ecf20Sopenharmony_ci{ 18458c2ecf20Sopenharmony_ci register u_short *lspr, *sspr; 18468c2ecf20Sopenharmony_ci#ifdef __mc68000__ 18478c2ecf20Sopenharmony_ci register u_long datawords asm ("d2"); 18488c2ecf20Sopenharmony_ci#else 18498c2ecf20Sopenharmony_ci register u_long datawords; 18508c2ecf20Sopenharmony_ci#endif 18518c2ecf20Sopenharmony_ci register short delta; 18528c2ecf20Sopenharmony_ci register u_char color; 18538c2ecf20Sopenharmony_ci short height, width, bits, words; 18548c2ecf20Sopenharmony_ci int size, alloc; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci size = par->crsr.height * par->crsr.width; 18578c2ecf20Sopenharmony_ci alloc = var->height * var->width; 18588c2ecf20Sopenharmony_ci var->height = par->crsr.height; 18598c2ecf20Sopenharmony_ci var->width = par->crsr.width; 18608c2ecf20Sopenharmony_ci var->xspot = par->crsr.spot_x; 18618c2ecf20Sopenharmony_ci var->yspot = par->crsr.spot_y; 18628c2ecf20Sopenharmony_ci if (size > var->height * var->width) 18638c2ecf20Sopenharmony_ci return -ENAMETOOLONG; 18648c2ecf20Sopenharmony_ci delta = 1 << par->crsr.fmode; 18658c2ecf20Sopenharmony_ci lspr = lofsprite + (delta << 1); 18668c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) 18678c2ecf20Sopenharmony_ci sspr = shfsprite + (delta << 1); 18688c2ecf20Sopenharmony_ci else 18698c2ecf20Sopenharmony_ci sspr = NULL; 18708c2ecf20Sopenharmony_ci for (height = (short)var->height - 1; height >= 0; height--) { 18718c2ecf20Sopenharmony_ci bits = 0; words = delta; datawords = 0; 18728c2ecf20Sopenharmony_ci for (width = (short)var->width - 1; width >= 0; width--) { 18738c2ecf20Sopenharmony_ci if (bits == 0) { 18748c2ecf20Sopenharmony_ci bits = 16; --words; 18758c2ecf20Sopenharmony_ci#ifdef __mc68000__ 18768c2ecf20Sopenharmony_ci asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0" 18778c2ecf20Sopenharmony_ci : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta)); 18788c2ecf20Sopenharmony_ci#else 18798c2ecf20Sopenharmony_ci datawords = (*(lspr + delta) << 16) | (*lspr++); 18808c2ecf20Sopenharmony_ci#endif 18818c2ecf20Sopenharmony_ci } 18828c2ecf20Sopenharmony_ci --bits; 18838c2ecf20Sopenharmony_ci#ifdef __mc68000__ 18848c2ecf20Sopenharmony_ci asm volatile ( 18858c2ecf20Sopenharmony_ci "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; " 18868c2ecf20Sopenharmony_ci "swap %1 ; lslw #1,%1 ; roxlb #1,%0" 18878c2ecf20Sopenharmony_ci : "=d" (color), "=d" (datawords) : "1" (datawords)); 18888c2ecf20Sopenharmony_ci#else 18898c2ecf20Sopenharmony_ci color = (((datawords >> 30) & 2) 18908c2ecf20Sopenharmony_ci | ((datawords >> 15) & 1)); 18918c2ecf20Sopenharmony_ci datawords <<= 1; 18928c2ecf20Sopenharmony_ci#endif 18938c2ecf20Sopenharmony_ci /* FIXME: check the return value + test the change */ 18948c2ecf20Sopenharmony_ci put_user(color, data++); 18958c2ecf20Sopenharmony_ci } 18968c2ecf20Sopenharmony_ci if (bits > 0) { 18978c2ecf20Sopenharmony_ci --words; ++lspr; 18988c2ecf20Sopenharmony_ci } 18998c2ecf20Sopenharmony_ci while (--words >= 0) 19008c2ecf20Sopenharmony_ci ++lspr; 19018c2ecf20Sopenharmony_ci#ifdef __mc68000__ 19028c2ecf20Sopenharmony_ci asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" 19038c2ecf20Sopenharmony_ci : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); 19048c2ecf20Sopenharmony_ci#else 19058c2ecf20Sopenharmony_ci lspr += delta; 19068c2ecf20Sopenharmony_ci if (sspr) { 19078c2ecf20Sopenharmony_ci u_short *tmp = lspr; 19088c2ecf20Sopenharmony_ci lspr = sspr; 19098c2ecf20Sopenharmony_ci sspr = tmp; 19108c2ecf20Sopenharmony_ci } 19118c2ecf20Sopenharmony_ci#endif 19128c2ecf20Sopenharmony_ci } 19138c2ecf20Sopenharmony_ci return 0; 19148c2ecf20Sopenharmony_ci} 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_cistatic int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, 19178c2ecf20Sopenharmony_ci u_char __user *data, struct amifb_par *par) 19188c2ecf20Sopenharmony_ci{ 19198c2ecf20Sopenharmony_ci register u_short *lspr, *sspr; 19208c2ecf20Sopenharmony_ci#ifdef __mc68000__ 19218c2ecf20Sopenharmony_ci register u_long datawords asm ("d2"); 19228c2ecf20Sopenharmony_ci#else 19238c2ecf20Sopenharmony_ci register u_long datawords; 19248c2ecf20Sopenharmony_ci#endif 19258c2ecf20Sopenharmony_ci register short delta; 19268c2ecf20Sopenharmony_ci u_short fmode; 19278c2ecf20Sopenharmony_ci short height, width, bits, words; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci if (!var->width) 19308c2ecf20Sopenharmony_ci return -EINVAL; 19318c2ecf20Sopenharmony_ci else if (var->width <= 16) 19328c2ecf20Sopenharmony_ci fmode = TAG_FMODE_1; 19338c2ecf20Sopenharmony_ci else if (var->width <= 32) 19348c2ecf20Sopenharmony_ci fmode = TAG_FMODE_2; 19358c2ecf20Sopenharmony_ci else if (var->width <= 64) 19368c2ecf20Sopenharmony_ci fmode = TAG_FMODE_4; 19378c2ecf20Sopenharmony_ci else 19388c2ecf20Sopenharmony_ci return -EINVAL; 19398c2ecf20Sopenharmony_ci if (fmode > maxfmode) 19408c2ecf20Sopenharmony_ci return -EINVAL; 19418c2ecf20Sopenharmony_ci if (!var->height) 19428c2ecf20Sopenharmony_ci return -EINVAL; 19438c2ecf20Sopenharmony_ci delta = 1 << fmode; 19448c2ecf20Sopenharmony_ci lofsprite = shfsprite = (u_short *)spritememory; 19458c2ecf20Sopenharmony_ci lspr = lofsprite + (delta << 1); 19468c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) { 19478c2ecf20Sopenharmony_ci if (((var->height + 4) << fmode << 2) > SPRITEMEMSIZE) 19488c2ecf20Sopenharmony_ci return -EINVAL; 19498c2ecf20Sopenharmony_ci memset(lspr, 0, (var->height + 4) << fmode << 2); 19508c2ecf20Sopenharmony_ci shfsprite += ((var->height + 5)&-2) << fmode; 19518c2ecf20Sopenharmony_ci sspr = shfsprite + (delta << 1); 19528c2ecf20Sopenharmony_ci } else { 19538c2ecf20Sopenharmony_ci if (((var->height + 2) << fmode << 2) > SPRITEMEMSIZE) 19548c2ecf20Sopenharmony_ci return -EINVAL; 19558c2ecf20Sopenharmony_ci memset(lspr, 0, (var->height + 2) << fmode << 2); 19568c2ecf20Sopenharmony_ci sspr = NULL; 19578c2ecf20Sopenharmony_ci } 19588c2ecf20Sopenharmony_ci for (height = (short)var->height - 1; height >= 0; height--) { 19598c2ecf20Sopenharmony_ci bits = 16; words = delta; datawords = 0; 19608c2ecf20Sopenharmony_ci for (width = (short)var->width - 1; width >= 0; width--) { 19618c2ecf20Sopenharmony_ci unsigned long tdata = 0; 19628c2ecf20Sopenharmony_ci /* FIXME: check the return value + test the change */ 19638c2ecf20Sopenharmony_ci get_user(tdata, data); 19648c2ecf20Sopenharmony_ci data++; 19658c2ecf20Sopenharmony_ci#ifdef __mc68000__ 19668c2ecf20Sopenharmony_ci asm volatile ( 19678c2ecf20Sopenharmony_ci "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; " 19688c2ecf20Sopenharmony_ci "lsrb #1,%2 ; roxlw #1,%0 ; swap %0" 19698c2ecf20Sopenharmony_ci : "=d" (datawords) 19708c2ecf20Sopenharmony_ci : "0" (datawords), "d" (tdata)); 19718c2ecf20Sopenharmony_ci#else 19728c2ecf20Sopenharmony_ci datawords = ((datawords << 1) & 0xfffefffe); 19738c2ecf20Sopenharmony_ci datawords |= tdata & 1; 19748c2ecf20Sopenharmony_ci datawords |= (tdata & 2) << (16 - 1); 19758c2ecf20Sopenharmony_ci#endif 19768c2ecf20Sopenharmony_ci if (--bits == 0) { 19778c2ecf20Sopenharmony_ci bits = 16; --words; 19788c2ecf20Sopenharmony_ci#ifdef __mc68000__ 19798c2ecf20Sopenharmony_ci asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+" 19808c2ecf20Sopenharmony_ci : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta)); 19818c2ecf20Sopenharmony_ci#else 19828c2ecf20Sopenharmony_ci *(lspr + delta) = (u_short) (datawords >> 16); 19838c2ecf20Sopenharmony_ci *lspr++ = (u_short) (datawords & 0xffff); 19848c2ecf20Sopenharmony_ci#endif 19858c2ecf20Sopenharmony_ci } 19868c2ecf20Sopenharmony_ci } 19878c2ecf20Sopenharmony_ci if (bits < 16) { 19888c2ecf20Sopenharmony_ci --words; 19898c2ecf20Sopenharmony_ci#ifdef __mc68000__ 19908c2ecf20Sopenharmony_ci asm volatile ( 19918c2ecf20Sopenharmony_ci "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; " 19928c2ecf20Sopenharmony_ci "swap %2 ; lslw %4,%2 ; movew %2,%0@+" 19938c2ecf20Sopenharmony_ci : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits)); 19948c2ecf20Sopenharmony_ci#else 19958c2ecf20Sopenharmony_ci *(lspr + delta) = (u_short) (datawords >> (16 + bits)); 19968c2ecf20Sopenharmony_ci *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits); 19978c2ecf20Sopenharmony_ci#endif 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci while (--words >= 0) { 20008c2ecf20Sopenharmony_ci#ifdef __mc68000__ 20018c2ecf20Sopenharmony_ci asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+" 20028c2ecf20Sopenharmony_ci : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0"); 20038c2ecf20Sopenharmony_ci#else 20048c2ecf20Sopenharmony_ci *(lspr + delta) = 0; 20058c2ecf20Sopenharmony_ci *lspr++ = 0; 20068c2ecf20Sopenharmony_ci#endif 20078c2ecf20Sopenharmony_ci } 20088c2ecf20Sopenharmony_ci#ifdef __mc68000__ 20098c2ecf20Sopenharmony_ci asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" 20108c2ecf20Sopenharmony_ci : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); 20118c2ecf20Sopenharmony_ci#else 20128c2ecf20Sopenharmony_ci lspr += delta; 20138c2ecf20Sopenharmony_ci if (sspr) { 20148c2ecf20Sopenharmony_ci u_short *tmp = lspr; 20158c2ecf20Sopenharmony_ci lspr = sspr; 20168c2ecf20Sopenharmony_ci sspr = tmp; 20178c2ecf20Sopenharmony_ci } 20188c2ecf20Sopenharmony_ci#endif 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci par->crsr.height = var->height; 20218c2ecf20Sopenharmony_ci par->crsr.width = var->width; 20228c2ecf20Sopenharmony_ci par->crsr.spot_x = var->xspot; 20238c2ecf20Sopenharmony_ci par->crsr.spot_y = var->yspot; 20248c2ecf20Sopenharmony_ci par->crsr.fmode = fmode; 20258c2ecf20Sopenharmony_ci if (IS_AGA) { 20268c2ecf20Sopenharmony_ci par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32); 20278c2ecf20Sopenharmony_ci par->fmode |= sprfetchmode[fmode]; 20288c2ecf20Sopenharmony_ci custom.fmode = par->fmode; 20298c2ecf20Sopenharmony_ci } 20308c2ecf20Sopenharmony_ci return 0; 20318c2ecf20Sopenharmony_ci} 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_cistatic int ami_get_cursorstate(struct fb_cursorstate *state, 20348c2ecf20Sopenharmony_ci const struct amifb_par *par) 20358c2ecf20Sopenharmony_ci{ 20368c2ecf20Sopenharmony_ci state->xoffset = par->crsr.crsr_x; 20378c2ecf20Sopenharmony_ci state->yoffset = par->crsr.crsr_y; 20388c2ecf20Sopenharmony_ci state->mode = cursormode; 20398c2ecf20Sopenharmony_ci return 0; 20408c2ecf20Sopenharmony_ci} 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_cistatic int ami_set_cursorstate(struct fb_cursorstate *state, 20438c2ecf20Sopenharmony_ci struct amifb_par *par) 20448c2ecf20Sopenharmony_ci{ 20458c2ecf20Sopenharmony_ci par->crsr.crsr_x = state->xoffset; 20468c2ecf20Sopenharmony_ci par->crsr.crsr_y = state->yoffset; 20478c2ecf20Sopenharmony_ci if ((cursormode = state->mode) == FB_CURSOR_OFF) 20488c2ecf20Sopenharmony_ci cursorstate = -1; 20498c2ecf20Sopenharmony_ci do_cursor = 1; 20508c2ecf20Sopenharmony_ci return 0; 20518c2ecf20Sopenharmony_ci} 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_cistatic void ami_set_sprite(const struct amifb_par *par) 20548c2ecf20Sopenharmony_ci{ 20558c2ecf20Sopenharmony_ci copins *copl, *cops; 20568c2ecf20Sopenharmony_ci u_short hs, vs, ve; 20578c2ecf20Sopenharmony_ci u_long pl, ps; 20588c2ecf20Sopenharmony_ci short mx, my; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci cops = copdisplay.list[currentcop][0]; 20618c2ecf20Sopenharmony_ci copl = copdisplay.list[currentcop][1]; 20628c2ecf20Sopenharmony_ci ps = pl = ZTWO_PADDR(dummysprite); 20638c2ecf20Sopenharmony_ci mx = par->crsr.crsr_x - par->crsr.spot_x; 20648c2ecf20Sopenharmony_ci my = par->crsr.crsr_y - par->crsr.spot_y; 20658c2ecf20Sopenharmony_ci if (!(par->vmode & FB_VMODE_YWRAP)) { 20668c2ecf20Sopenharmony_ci mx -= par->xoffset; 20678c2ecf20Sopenharmony_ci my -= par->yoffset; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 && 20708c2ecf20Sopenharmony_ci mx > -(short)par->crsr.width && mx < par->xres && 20718c2ecf20Sopenharmony_ci my > -(short)par->crsr.height && my < par->yres) { 20728c2ecf20Sopenharmony_ci pl = ZTWO_PADDR(lofsprite); 20738c2ecf20Sopenharmony_ci hs = par->diwstrt_h + (mx << par->clk_shift) - 4; 20748c2ecf20Sopenharmony_ci vs = par->diwstrt_v + (my << par->line_shift); 20758c2ecf20Sopenharmony_ci ve = vs + (par->crsr.height << par->line_shift); 20768c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) { 20778c2ecf20Sopenharmony_ci ps = ZTWO_PADDR(shfsprite); 20788c2ecf20Sopenharmony_ci lofsprite[0] = spr2hw_pos(vs, hs); 20798c2ecf20Sopenharmony_ci shfsprite[0] = spr2hw_pos(vs + 1, hs); 20808c2ecf20Sopenharmony_ci if (mod2(vs)) { 20818c2ecf20Sopenharmony_ci lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); 20828c2ecf20Sopenharmony_ci shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve + 1); 20838c2ecf20Sopenharmony_ci swap(pl, ps); 20848c2ecf20Sopenharmony_ci } else { 20858c2ecf20Sopenharmony_ci lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve + 1); 20868c2ecf20Sopenharmony_ci shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve); 20878c2ecf20Sopenharmony_ci } 20888c2ecf20Sopenharmony_ci } else { 20898c2ecf20Sopenharmony_ci lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0); 20908c2ecf20Sopenharmony_ci lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); 20918c2ecf20Sopenharmony_ci } 20928c2ecf20Sopenharmony_ci } 20938c2ecf20Sopenharmony_ci copl[cop_spr0ptrh].w[1] = highw(pl); 20948c2ecf20Sopenharmony_ci copl[cop_spr0ptrl].w[1] = loww(pl); 20958c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) { 20968c2ecf20Sopenharmony_ci cops[cop_spr0ptrh].w[1] = highw(ps); 20978c2ecf20Sopenharmony_ci cops[cop_spr0ptrl].w[1] = loww(ps); 20988c2ecf20Sopenharmony_ci } 20998c2ecf20Sopenharmony_ci} 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci /* 21038c2ecf20Sopenharmony_ci * Initialise the Copper Initialisation List 21048c2ecf20Sopenharmony_ci */ 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_cistatic void __init ami_init_copper(void) 21078c2ecf20Sopenharmony_ci{ 21088c2ecf20Sopenharmony_ci copins *cop = copdisplay.init; 21098c2ecf20Sopenharmony_ci u_long p; 21108c2ecf20Sopenharmony_ci int i; 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci if (!IS_OCS) { 21138c2ecf20Sopenharmony_ci (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0); 21148c2ecf20Sopenharmony_ci (cop++)->l = CMOVE(0x0181, diwstrt); 21158c2ecf20Sopenharmony_ci (cop++)->l = CMOVE(0x0281, diwstop); 21168c2ecf20Sopenharmony_ci (cop++)->l = CMOVE(0x0000, diwhigh); 21178c2ecf20Sopenharmony_ci } else 21188c2ecf20Sopenharmony_ci (cop++)->l = CMOVE(BPC0_COLOR, bplcon0); 21198c2ecf20Sopenharmony_ci p = ZTWO_PADDR(dummysprite); 21208c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 21218c2ecf20Sopenharmony_ci (cop++)->l = CMOVE(0, spr[i].pos); 21228c2ecf20Sopenharmony_ci (cop++)->l = CMOVE(highw(p), sprpt[i]); 21238c2ecf20Sopenharmony_ci (cop++)->l = CMOVE2(loww(p), sprpt[i]); 21248c2ecf20Sopenharmony_ci } 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq); 21278c2ecf20Sopenharmony_ci copdisplay.wait = cop; 21288c2ecf20Sopenharmony_ci (cop++)->l = CEND; 21298c2ecf20Sopenharmony_ci (cop++)->l = CMOVE(0, copjmp2); 21308c2ecf20Sopenharmony_ci cop->l = CEND; 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init); 21338c2ecf20Sopenharmony_ci custom.copjmp1 = 0; 21348c2ecf20Sopenharmony_ci} 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_cistatic void ami_reinit_copper(const struct amifb_par *par) 21378c2ecf20Sopenharmony_ci{ 21388c2ecf20Sopenharmony_ci copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; 21398c2ecf20Sopenharmony_ci copdisplay.wait->l = CWAIT(32, par->diwstrt_v - 4); 21408c2ecf20Sopenharmony_ci} 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci /* 21448c2ecf20Sopenharmony_ci * Rebuild the Copper List 21458c2ecf20Sopenharmony_ci * 21468c2ecf20Sopenharmony_ci * We only change the things that are not static 21478c2ecf20Sopenharmony_ci */ 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_cistatic void ami_rebuild_copper(const struct amifb_par *par) 21508c2ecf20Sopenharmony_ci{ 21518c2ecf20Sopenharmony_ci copins *copl, *cops; 21528c2ecf20Sopenharmony_ci u_short line, h_end1, h_end2; 21538c2ecf20Sopenharmony_ci short i; 21548c2ecf20Sopenharmony_ci u_long p; 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci if (IS_AGA && maxfmode + par->clk_shift == 0) 21578c2ecf20Sopenharmony_ci h_end1 = par->diwstrt_h - 64; 21588c2ecf20Sopenharmony_ci else 21598c2ecf20Sopenharmony_ci h_end1 = par->htotal - 32; 21608c2ecf20Sopenharmony_ci h_end2 = par->ddfstop + 64; 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci ami_set_sprite(par); 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci copl = copdisplay.rebuild[1]; 21658c2ecf20Sopenharmony_ci p = par->bplpt0; 21668c2ecf20Sopenharmony_ci if (par->vmode & FB_VMODE_YWRAP) { 21678c2ecf20Sopenharmony_ci if ((par->vyres - par->yoffset) != 1 || !mod2(par->diwstrt_v)) { 21688c2ecf20Sopenharmony_ci if (par->yoffset > par->vyres - par->yres) { 21698c2ecf20Sopenharmony_ci for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { 21708c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(highw(p), bplpt[i]); 21718c2ecf20Sopenharmony_ci (copl++)->l = CMOVE2(loww(p), bplpt[i]); 21728c2ecf20Sopenharmony_ci } 21738c2ecf20Sopenharmony_ci line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 1; 21748c2ecf20Sopenharmony_ci while (line >= 512) { 21758c2ecf20Sopenharmony_ci (copl++)->l = CWAIT(h_end1, 510); 21768c2ecf20Sopenharmony_ci line -= 512; 21778c2ecf20Sopenharmony_ci } 21788c2ecf20Sopenharmony_ci if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0) 21798c2ecf20Sopenharmony_ci (copl++)->l = CWAIT(h_end1, line); 21808c2ecf20Sopenharmony_ci else 21818c2ecf20Sopenharmony_ci (copl++)->l = CWAIT(h_end2, line); 21828c2ecf20Sopenharmony_ci p = par->bplpt0wrap; 21838c2ecf20Sopenharmony_ci } 21848c2ecf20Sopenharmony_ci } else 21858c2ecf20Sopenharmony_ci p = par->bplpt0wrap; 21868c2ecf20Sopenharmony_ci } 21878c2ecf20Sopenharmony_ci for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { 21888c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(highw(p), bplpt[i]); 21898c2ecf20Sopenharmony_ci (copl++)->l = CMOVE2(loww(p), bplpt[i]); 21908c2ecf20Sopenharmony_ci } 21918c2ecf20Sopenharmony_ci copl->l = CEND; 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) { 21948c2ecf20Sopenharmony_ci cops = copdisplay.rebuild[0]; 21958c2ecf20Sopenharmony_ci p = par->bplpt0; 21968c2ecf20Sopenharmony_ci if (mod2(par->diwstrt_v)) 21978c2ecf20Sopenharmony_ci p -= par->next_line; 21988c2ecf20Sopenharmony_ci else 21998c2ecf20Sopenharmony_ci p += par->next_line; 22008c2ecf20Sopenharmony_ci if (par->vmode & FB_VMODE_YWRAP) { 22018c2ecf20Sopenharmony_ci if ((par->vyres - par->yoffset) != 1 || mod2(par->diwstrt_v)) { 22028c2ecf20Sopenharmony_ci if (par->yoffset > par->vyres - par->yres + 1) { 22038c2ecf20Sopenharmony_ci for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { 22048c2ecf20Sopenharmony_ci (cops++)->l = CMOVE(highw(p), bplpt[i]); 22058c2ecf20Sopenharmony_ci (cops++)->l = CMOVE2(loww(p), bplpt[i]); 22068c2ecf20Sopenharmony_ci } 22078c2ecf20Sopenharmony_ci line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 2; 22088c2ecf20Sopenharmony_ci while (line >= 512) { 22098c2ecf20Sopenharmony_ci (cops++)->l = CWAIT(h_end1, 510); 22108c2ecf20Sopenharmony_ci line -= 512; 22118c2ecf20Sopenharmony_ci } 22128c2ecf20Sopenharmony_ci if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0) 22138c2ecf20Sopenharmony_ci (cops++)->l = CWAIT(h_end1, line); 22148c2ecf20Sopenharmony_ci else 22158c2ecf20Sopenharmony_ci (cops++)->l = CWAIT(h_end2, line); 22168c2ecf20Sopenharmony_ci p = par->bplpt0wrap; 22178c2ecf20Sopenharmony_ci if (mod2(par->diwstrt_v + par->vyres - 22188c2ecf20Sopenharmony_ci par->yoffset)) 22198c2ecf20Sopenharmony_ci p -= par->next_line; 22208c2ecf20Sopenharmony_ci else 22218c2ecf20Sopenharmony_ci p += par->next_line; 22228c2ecf20Sopenharmony_ci } 22238c2ecf20Sopenharmony_ci } else 22248c2ecf20Sopenharmony_ci p = par->bplpt0wrap - par->next_line; 22258c2ecf20Sopenharmony_ci } 22268c2ecf20Sopenharmony_ci for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { 22278c2ecf20Sopenharmony_ci (cops++)->l = CMOVE(highw(p), bplpt[i]); 22288c2ecf20Sopenharmony_ci (cops++)->l = CMOVE2(loww(p), bplpt[i]); 22298c2ecf20Sopenharmony_ci } 22308c2ecf20Sopenharmony_ci cops->l = CEND; 22318c2ecf20Sopenharmony_ci } 22328c2ecf20Sopenharmony_ci} 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci /* 22368c2ecf20Sopenharmony_ci * Build the Copper List 22378c2ecf20Sopenharmony_ci */ 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_cistatic void ami_build_copper(struct fb_info *info) 22408c2ecf20Sopenharmony_ci{ 22418c2ecf20Sopenharmony_ci struct amifb_par *par = info->par; 22428c2ecf20Sopenharmony_ci copins *copl, *cops; 22438c2ecf20Sopenharmony_ci u_long p; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci currentcop = 1 - currentcop; 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci copl = copdisplay.list[currentcop][1]; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci (copl++)->l = CWAIT(0, 10); 22508c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(par->bplcon0, bplcon0); 22518c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(0, sprpt[0]); 22528c2ecf20Sopenharmony_ci (copl++)->l = CMOVE2(0, sprpt[0]); 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) { 22558c2ecf20Sopenharmony_ci cops = copdisplay.list[currentcop][0]; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci (cops++)->l = CWAIT(0, 10); 22588c2ecf20Sopenharmony_ci (cops++)->l = CMOVE(par->bplcon0, bplcon0); 22598c2ecf20Sopenharmony_ci (cops++)->l = CMOVE(0, sprpt[0]); 22608c2ecf20Sopenharmony_ci (cops++)->l = CMOVE2(0, sprpt[0]); 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v + 1), diwstrt); 22638c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v + 1), diwstop); 22648c2ecf20Sopenharmony_ci (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); 22658c2ecf20Sopenharmony_ci (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); 22668c2ecf20Sopenharmony_ci if (!IS_OCS) { 22678c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v + 1, 22688c2ecf20Sopenharmony_ci par->diwstop_h, par->diwstop_v + 1), diwhigh); 22698c2ecf20Sopenharmony_ci (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, 22708c2ecf20Sopenharmony_ci par->diwstop_h, par->diwstop_v), diwhigh); 22718c2ecf20Sopenharmony_ci#if 0 22728c2ecf20Sopenharmony_ci if (par->beamcon0 & BMC0_VARBEAMEN) { 22738c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); 22748c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt + 1), vbstrt); 22758c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(vbstop2hw(par->vbstop + 1), vbstop); 22768c2ecf20Sopenharmony_ci (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); 22778c2ecf20Sopenharmony_ci (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); 22788c2ecf20Sopenharmony_ci (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); 22798c2ecf20Sopenharmony_ci } 22808c2ecf20Sopenharmony_ci#endif 22818c2ecf20Sopenharmony_ci } 22828c2ecf20Sopenharmony_ci p = ZTWO_PADDR(copdisplay.list[currentcop][0]); 22838c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(highw(p), cop2lc); 22848c2ecf20Sopenharmony_ci (copl++)->l = CMOVE2(loww(p), cop2lc); 22858c2ecf20Sopenharmony_ci p = ZTWO_PADDR(copdisplay.list[currentcop][1]); 22868c2ecf20Sopenharmony_ci (cops++)->l = CMOVE(highw(p), cop2lc); 22878c2ecf20Sopenharmony_ci (cops++)->l = CMOVE2(loww(p), cop2lc); 22888c2ecf20Sopenharmony_ci copdisplay.rebuild[0] = cops; 22898c2ecf20Sopenharmony_ci } else { 22908c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); 22918c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); 22928c2ecf20Sopenharmony_ci if (!IS_OCS) { 22938c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, 22948c2ecf20Sopenharmony_ci par->diwstop_h, par->diwstop_v), diwhigh); 22958c2ecf20Sopenharmony_ci#if 0 22968c2ecf20Sopenharmony_ci if (par->beamcon0 & BMC0_VARBEAMEN) { 22978c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); 22988c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); 22998c2ecf20Sopenharmony_ci (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); 23008c2ecf20Sopenharmony_ci } 23018c2ecf20Sopenharmony_ci#endif 23028c2ecf20Sopenharmony_ci } 23038c2ecf20Sopenharmony_ci } 23048c2ecf20Sopenharmony_ci copdisplay.rebuild[1] = copl; 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci ami_update_par(info); 23078c2ecf20Sopenharmony_ci ami_rebuild_copper(info->par); 23088c2ecf20Sopenharmony_ci} 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci#ifndef MODULE 23118c2ecf20Sopenharmony_cistatic void __init amifb_setup_mcap(char *spec) 23128c2ecf20Sopenharmony_ci{ 23138c2ecf20Sopenharmony_ci char *p; 23148c2ecf20Sopenharmony_ci int vmin, vmax, hmin, hmax; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax> 23178c2ecf20Sopenharmony_ci * <V*> vertical freq. in Hz 23188c2ecf20Sopenharmony_ci * <H*> horizontal freq. in kHz 23198c2ecf20Sopenharmony_ci */ 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci if (!(p = strsep(&spec, ";")) || !*p) 23228c2ecf20Sopenharmony_ci return; 23238c2ecf20Sopenharmony_ci vmin = simple_strtoul(p, NULL, 10); 23248c2ecf20Sopenharmony_ci if (vmin <= 0) 23258c2ecf20Sopenharmony_ci return; 23268c2ecf20Sopenharmony_ci if (!(p = strsep(&spec, ";")) || !*p) 23278c2ecf20Sopenharmony_ci return; 23288c2ecf20Sopenharmony_ci vmax = simple_strtoul(p, NULL, 10); 23298c2ecf20Sopenharmony_ci if (vmax <= 0 || vmax <= vmin) 23308c2ecf20Sopenharmony_ci return; 23318c2ecf20Sopenharmony_ci if (!(p = strsep(&spec, ";")) || !*p) 23328c2ecf20Sopenharmony_ci return; 23338c2ecf20Sopenharmony_ci hmin = 1000 * simple_strtoul(p, NULL, 10); 23348c2ecf20Sopenharmony_ci if (hmin <= 0) 23358c2ecf20Sopenharmony_ci return; 23368c2ecf20Sopenharmony_ci if (!(p = strsep(&spec, "")) || !*p) 23378c2ecf20Sopenharmony_ci return; 23388c2ecf20Sopenharmony_ci hmax = 1000 * simple_strtoul(p, NULL, 10); 23398c2ecf20Sopenharmony_ci if (hmax <= 0 || hmax <= hmin) 23408c2ecf20Sopenharmony_ci return; 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci amifb_hfmin = hmin; 23438c2ecf20Sopenharmony_ci amifb_hfmax = hmax; 23448c2ecf20Sopenharmony_ci amifb_vfmin = vmin; 23458c2ecf20Sopenharmony_ci amifb_vfmax = vmax; 23468c2ecf20Sopenharmony_ci} 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_cistatic int __init amifb_setup(char *options) 23498c2ecf20Sopenharmony_ci{ 23508c2ecf20Sopenharmony_ci char *this_opt; 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ci if (!options || !*options) 23538c2ecf20Sopenharmony_ci return 0; 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci while ((this_opt = strsep(&options, ",")) != NULL) { 23568c2ecf20Sopenharmony_ci if (!*this_opt) 23578c2ecf20Sopenharmony_ci continue; 23588c2ecf20Sopenharmony_ci if (!strcmp(this_opt, "inverse")) { 23598c2ecf20Sopenharmony_ci fb_invert_cmaps(); 23608c2ecf20Sopenharmony_ci } else if (!strcmp(this_opt, "ilbm")) 23618c2ecf20Sopenharmony_ci amifb_ilbm = 1; 23628c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "monitorcap:", 11)) 23638c2ecf20Sopenharmony_ci amifb_setup_mcap(this_opt + 11); 23648c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "fstart:", 7)) 23658c2ecf20Sopenharmony_ci min_fstrt = simple_strtoul(this_opt + 7, NULL, 0); 23668c2ecf20Sopenharmony_ci else 23678c2ecf20Sopenharmony_ci mode_option = this_opt; 23688c2ecf20Sopenharmony_ci } 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci if (min_fstrt < 48) 23718c2ecf20Sopenharmony_ci min_fstrt = 48; 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci return 0; 23748c2ecf20Sopenharmony_ci} 23758c2ecf20Sopenharmony_ci#endif 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_cistatic int amifb_check_var(struct fb_var_screeninfo *var, 23788c2ecf20Sopenharmony_ci struct fb_info *info) 23798c2ecf20Sopenharmony_ci{ 23808c2ecf20Sopenharmony_ci int err; 23818c2ecf20Sopenharmony_ci struct amifb_par par; 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci /* Validate wanted screen parameters */ 23848c2ecf20Sopenharmony_ci err = ami_decode_var(var, &par, info); 23858c2ecf20Sopenharmony_ci if (err) 23868c2ecf20Sopenharmony_ci return err; 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci /* Encode (possibly rounded) screen parameters */ 23898c2ecf20Sopenharmony_ci ami_encode_var(var, &par); 23908c2ecf20Sopenharmony_ci return 0; 23918c2ecf20Sopenharmony_ci} 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_cistatic int amifb_set_par(struct fb_info *info) 23958c2ecf20Sopenharmony_ci{ 23968c2ecf20Sopenharmony_ci struct amifb_par *par = info->par; 23978c2ecf20Sopenharmony_ci int error; 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci do_vmode_pan = 0; 24008c2ecf20Sopenharmony_ci do_vmode_full = 0; 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci /* Decode wanted screen parameters */ 24038c2ecf20Sopenharmony_ci error = ami_decode_var(&info->var, par, info); 24048c2ecf20Sopenharmony_ci if (error) 24058c2ecf20Sopenharmony_ci return error; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci /* Set new videomode */ 24088c2ecf20Sopenharmony_ci ami_build_copper(info); 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci /* Set VBlank trigger */ 24118c2ecf20Sopenharmony_ci do_vmode_full = 1; 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci /* Update fix for new screen parameters */ 24148c2ecf20Sopenharmony_ci if (par->bpp == 1) { 24158c2ecf20Sopenharmony_ci info->fix.type = FB_TYPE_PACKED_PIXELS; 24168c2ecf20Sopenharmony_ci info->fix.type_aux = 0; 24178c2ecf20Sopenharmony_ci } else if (amifb_ilbm) { 24188c2ecf20Sopenharmony_ci info->fix.type = FB_TYPE_INTERLEAVED_PLANES; 24198c2ecf20Sopenharmony_ci info->fix.type_aux = par->next_line; 24208c2ecf20Sopenharmony_ci } else { 24218c2ecf20Sopenharmony_ci info->fix.type = FB_TYPE_PLANES; 24228c2ecf20Sopenharmony_ci info->fix.type_aux = 0; 24238c2ecf20Sopenharmony_ci } 24248c2ecf20Sopenharmony_ci info->fix.line_length = div8(upx(16 << maxfmode, par->vxres)); 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci if (par->vmode & FB_VMODE_YWRAP) { 24278c2ecf20Sopenharmony_ci info->fix.ywrapstep = 1; 24288c2ecf20Sopenharmony_ci info->fix.xpanstep = 0; 24298c2ecf20Sopenharmony_ci info->fix.ypanstep = 0; 24308c2ecf20Sopenharmony_ci info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP | 24318c2ecf20Sopenharmony_ci FBINFO_READS_FAST; /* override SCROLL_REDRAW */ 24328c2ecf20Sopenharmony_ci } else { 24338c2ecf20Sopenharmony_ci info->fix.ywrapstep = 0; 24348c2ecf20Sopenharmony_ci if (par->vmode & FB_VMODE_SMOOTH_XPAN) 24358c2ecf20Sopenharmony_ci info->fix.xpanstep = 1; 24368c2ecf20Sopenharmony_ci else 24378c2ecf20Sopenharmony_ci info->fix.xpanstep = 16 << maxfmode; 24388c2ecf20Sopenharmony_ci info->fix.ypanstep = 1; 24398c2ecf20Sopenharmony_ci info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; 24408c2ecf20Sopenharmony_ci } 24418c2ecf20Sopenharmony_ci return 0; 24428c2ecf20Sopenharmony_ci} 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci /* 24468c2ecf20Sopenharmony_ci * Set a single color register. The values supplied are already 24478c2ecf20Sopenharmony_ci * rounded down to the hardware's capabilities (according to the 24488c2ecf20Sopenharmony_ci * entries in the var structure). Return != 0 for invalid regno. 24498c2ecf20Sopenharmony_ci */ 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_cistatic int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 24528c2ecf20Sopenharmony_ci u_int transp, struct fb_info *info) 24538c2ecf20Sopenharmony_ci{ 24548c2ecf20Sopenharmony_ci const struct amifb_par *par = info->par; 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci if (IS_AGA) { 24578c2ecf20Sopenharmony_ci if (regno > 255) 24588c2ecf20Sopenharmony_ci return 1; 24598c2ecf20Sopenharmony_ci } else if (par->bplcon0 & BPC0_SHRES) { 24608c2ecf20Sopenharmony_ci if (regno > 3) 24618c2ecf20Sopenharmony_ci return 1; 24628c2ecf20Sopenharmony_ci } else { 24638c2ecf20Sopenharmony_ci if (regno > 31) 24648c2ecf20Sopenharmony_ci return 1; 24658c2ecf20Sopenharmony_ci } 24668c2ecf20Sopenharmony_ci red >>= 8; 24678c2ecf20Sopenharmony_ci green >>= 8; 24688c2ecf20Sopenharmony_ci blue >>= 8; 24698c2ecf20Sopenharmony_ci if (!regno) { 24708c2ecf20Sopenharmony_ci red0 = red; 24718c2ecf20Sopenharmony_ci green0 = green; 24728c2ecf20Sopenharmony_ci blue0 = blue; 24738c2ecf20Sopenharmony_ci } 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci /* 24768c2ecf20Sopenharmony_ci * Update the corresponding Hardware Color Register, unless it's Color 24778c2ecf20Sopenharmony_ci * Register 0 and the screen is blanked. 24788c2ecf20Sopenharmony_ci * 24798c2ecf20Sopenharmony_ci * VBlank is switched off to protect bplcon3 or ecs_palette[] from 24808c2ecf20Sopenharmony_ci * being changed by ami_do_blank() during the VBlank. 24818c2ecf20Sopenharmony_ci */ 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci if (regno || !is_blanked) { 24848c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_AMIGA_AGA) 24858c2ecf20Sopenharmony_ci if (IS_AGA) { 24868c2ecf20Sopenharmony_ci u_short bplcon3 = par->bplcon3; 24878c2ecf20Sopenharmony_ci VBlankOff(); 24888c2ecf20Sopenharmony_ci custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000); 24898c2ecf20Sopenharmony_ci custom.color[regno & 31] = rgb2hw8_high(red, green, 24908c2ecf20Sopenharmony_ci blue); 24918c2ecf20Sopenharmony_ci custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000) | 24928c2ecf20Sopenharmony_ci BPC3_LOCT; 24938c2ecf20Sopenharmony_ci custom.color[regno & 31] = rgb2hw8_low(red, green, 24948c2ecf20Sopenharmony_ci blue); 24958c2ecf20Sopenharmony_ci custom.bplcon3 = bplcon3; 24968c2ecf20Sopenharmony_ci VBlankOn(); 24978c2ecf20Sopenharmony_ci } else 24988c2ecf20Sopenharmony_ci#endif 24998c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_AMIGA_ECS) 25008c2ecf20Sopenharmony_ci if (par->bplcon0 & BPC0_SHRES) { 25018c2ecf20Sopenharmony_ci u_short color, mask; 25028c2ecf20Sopenharmony_ci int i; 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci mask = 0x3333; 25058c2ecf20Sopenharmony_ci color = rgb2hw2(red, green, blue); 25068c2ecf20Sopenharmony_ci VBlankOff(); 25078c2ecf20Sopenharmony_ci for (i = regno + 12; i >= (int)regno; i -= 4) 25088c2ecf20Sopenharmony_ci custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; 25098c2ecf20Sopenharmony_ci mask <<= 2; color >>= 2; 25108c2ecf20Sopenharmony_ci regno = down16(regno) + mul4(mod4(regno)); 25118c2ecf20Sopenharmony_ci for (i = regno + 3; i >= (int)regno; i--) 25128c2ecf20Sopenharmony_ci custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; 25138c2ecf20Sopenharmony_ci VBlankOn(); 25148c2ecf20Sopenharmony_ci } else 25158c2ecf20Sopenharmony_ci#endif 25168c2ecf20Sopenharmony_ci custom.color[regno] = rgb2hw4(red, green, blue); 25178c2ecf20Sopenharmony_ci } 25188c2ecf20Sopenharmony_ci return 0; 25198c2ecf20Sopenharmony_ci} 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci /* 25238c2ecf20Sopenharmony_ci * Blank the display. 25248c2ecf20Sopenharmony_ci */ 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_cistatic int amifb_blank(int blank, struct fb_info *info) 25278c2ecf20Sopenharmony_ci{ 25288c2ecf20Sopenharmony_ci do_blank = blank ? blank : -1; 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci return 0; 25318c2ecf20Sopenharmony_ci} 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci /* 25358c2ecf20Sopenharmony_ci * Pan or Wrap the Display 25368c2ecf20Sopenharmony_ci * 25378c2ecf20Sopenharmony_ci * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag 25388c2ecf20Sopenharmony_ci */ 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_cistatic int amifb_pan_display(struct fb_var_screeninfo *var, 25418c2ecf20Sopenharmony_ci struct fb_info *info) 25428c2ecf20Sopenharmony_ci{ 25438c2ecf20Sopenharmony_ci if (var->vmode & FB_VMODE_YWRAP) { 25448c2ecf20Sopenharmony_ci if (var->yoffset < 0 || 25458c2ecf20Sopenharmony_ci var->yoffset >= info->var.yres_virtual || var->xoffset) 25468c2ecf20Sopenharmony_ci return -EINVAL; 25478c2ecf20Sopenharmony_ci } else { 25488c2ecf20Sopenharmony_ci /* 25498c2ecf20Sopenharmony_ci * TODO: There will be problems when xpan!=1, so some columns 25508c2ecf20Sopenharmony_ci * on the right side will never be seen 25518c2ecf20Sopenharmony_ci */ 25528c2ecf20Sopenharmony_ci if (var->xoffset + info->var.xres > 25538c2ecf20Sopenharmony_ci upx(16 << maxfmode, info->var.xres_virtual) || 25548c2ecf20Sopenharmony_ci var->yoffset + info->var.yres > info->var.yres_virtual) 25558c2ecf20Sopenharmony_ci return -EINVAL; 25568c2ecf20Sopenharmony_ci } 25578c2ecf20Sopenharmony_ci ami_pan_var(var, info); 25588c2ecf20Sopenharmony_ci info->var.xoffset = var->xoffset; 25598c2ecf20Sopenharmony_ci info->var.yoffset = var->yoffset; 25608c2ecf20Sopenharmony_ci if (var->vmode & FB_VMODE_YWRAP) 25618c2ecf20Sopenharmony_ci info->var.vmode |= FB_VMODE_YWRAP; 25628c2ecf20Sopenharmony_ci else 25638c2ecf20Sopenharmony_ci info->var.vmode &= ~FB_VMODE_YWRAP; 25648c2ecf20Sopenharmony_ci return 0; 25658c2ecf20Sopenharmony_ci} 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 32 25698c2ecf20Sopenharmony_ci#define BYTES_PER_LONG 4 25708c2ecf20Sopenharmony_ci#define SHIFT_PER_LONG 5 25718c2ecf20Sopenharmony_ci#elif BITS_PER_LONG == 64 25728c2ecf20Sopenharmony_ci#define BYTES_PER_LONG 8 25738c2ecf20Sopenharmony_ci#define SHIFT_PER_LONG 6 25748c2ecf20Sopenharmony_ci#else 25758c2ecf20Sopenharmony_ci#define Please update me 25768c2ecf20Sopenharmony_ci#endif 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci /* 25808c2ecf20Sopenharmony_ci * Compose two values, using a bitmask as decision value 25818c2ecf20Sopenharmony_ci * This is equivalent to (a & mask) | (b & ~mask) 25828c2ecf20Sopenharmony_ci */ 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_cistatic inline unsigned long comp(unsigned long a, unsigned long b, 25858c2ecf20Sopenharmony_ci unsigned long mask) 25868c2ecf20Sopenharmony_ci{ 25878c2ecf20Sopenharmony_ci return ((a ^ b) & mask) ^ b; 25888c2ecf20Sopenharmony_ci} 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_cistatic inline unsigned long xor(unsigned long a, unsigned long b, 25928c2ecf20Sopenharmony_ci unsigned long mask) 25938c2ecf20Sopenharmony_ci{ 25948c2ecf20Sopenharmony_ci return (a & mask) ^ b; 25958c2ecf20Sopenharmony_ci} 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci /* 25998c2ecf20Sopenharmony_ci * Unaligned forward bit copy using 32-bit or 64-bit memory accesses 26008c2ecf20Sopenharmony_ci */ 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_cistatic void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, 26038c2ecf20Sopenharmony_ci int src_idx, u32 n) 26048c2ecf20Sopenharmony_ci{ 26058c2ecf20Sopenharmony_ci unsigned long first, last; 26068c2ecf20Sopenharmony_ci int shift = dst_idx - src_idx, left, right; 26078c2ecf20Sopenharmony_ci unsigned long d0, d1; 26088c2ecf20Sopenharmony_ci int m; 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci if (!n) 26118c2ecf20Sopenharmony_ci return; 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci shift = dst_idx - src_idx; 26148c2ecf20Sopenharmony_ci first = ~0UL >> dst_idx; 26158c2ecf20Sopenharmony_ci last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci if (!shift) { 26188c2ecf20Sopenharmony_ci // Same alignment for source and dest 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci if (dst_idx + n <= BITS_PER_LONG) { 26218c2ecf20Sopenharmony_ci // Single word 26228c2ecf20Sopenharmony_ci if (last) 26238c2ecf20Sopenharmony_ci first &= last; 26248c2ecf20Sopenharmony_ci *dst = comp(*src, *dst, first); 26258c2ecf20Sopenharmony_ci } else { 26268c2ecf20Sopenharmony_ci // Multiple destination words 26278c2ecf20Sopenharmony_ci // Leading bits 26288c2ecf20Sopenharmony_ci if (first) { 26298c2ecf20Sopenharmony_ci *dst = comp(*src, *dst, first); 26308c2ecf20Sopenharmony_ci dst++; 26318c2ecf20Sopenharmony_ci src++; 26328c2ecf20Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 26338c2ecf20Sopenharmony_ci } 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci // Main chunk 26368c2ecf20Sopenharmony_ci n /= BITS_PER_LONG; 26378c2ecf20Sopenharmony_ci while (n >= 8) { 26388c2ecf20Sopenharmony_ci *dst++ = *src++; 26398c2ecf20Sopenharmony_ci *dst++ = *src++; 26408c2ecf20Sopenharmony_ci *dst++ = *src++; 26418c2ecf20Sopenharmony_ci *dst++ = *src++; 26428c2ecf20Sopenharmony_ci *dst++ = *src++; 26438c2ecf20Sopenharmony_ci *dst++ = *src++; 26448c2ecf20Sopenharmony_ci *dst++ = *src++; 26458c2ecf20Sopenharmony_ci *dst++ = *src++; 26468c2ecf20Sopenharmony_ci n -= 8; 26478c2ecf20Sopenharmony_ci } 26488c2ecf20Sopenharmony_ci while (n--) 26498c2ecf20Sopenharmony_ci *dst++ = *src++; 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci // Trailing bits 26528c2ecf20Sopenharmony_ci if (last) 26538c2ecf20Sopenharmony_ci *dst = comp(*src, *dst, last); 26548c2ecf20Sopenharmony_ci } 26558c2ecf20Sopenharmony_ci } else { 26568c2ecf20Sopenharmony_ci // Different alignment for source and dest 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci right = shift & (BITS_PER_LONG - 1); 26598c2ecf20Sopenharmony_ci left = -shift & (BITS_PER_LONG - 1); 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci if (dst_idx + n <= BITS_PER_LONG) { 26628c2ecf20Sopenharmony_ci // Single destination word 26638c2ecf20Sopenharmony_ci if (last) 26648c2ecf20Sopenharmony_ci first &= last; 26658c2ecf20Sopenharmony_ci if (shift > 0) { 26668c2ecf20Sopenharmony_ci // Single source word 26678c2ecf20Sopenharmony_ci *dst = comp(*src >> right, *dst, first); 26688c2ecf20Sopenharmony_ci } else if (src_idx + n <= BITS_PER_LONG) { 26698c2ecf20Sopenharmony_ci // Single source word 26708c2ecf20Sopenharmony_ci *dst = comp(*src << left, *dst, first); 26718c2ecf20Sopenharmony_ci } else { 26728c2ecf20Sopenharmony_ci // 2 source words 26738c2ecf20Sopenharmony_ci d0 = *src++; 26748c2ecf20Sopenharmony_ci d1 = *src; 26758c2ecf20Sopenharmony_ci *dst = comp(d0 << left | d1 >> right, *dst, 26768c2ecf20Sopenharmony_ci first); 26778c2ecf20Sopenharmony_ci } 26788c2ecf20Sopenharmony_ci } else { 26798c2ecf20Sopenharmony_ci // Multiple destination words 26808c2ecf20Sopenharmony_ci d0 = *src++; 26818c2ecf20Sopenharmony_ci // Leading bits 26828c2ecf20Sopenharmony_ci if (shift > 0) { 26838c2ecf20Sopenharmony_ci // Single source word 26848c2ecf20Sopenharmony_ci *dst = comp(d0 >> right, *dst, first); 26858c2ecf20Sopenharmony_ci dst++; 26868c2ecf20Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 26878c2ecf20Sopenharmony_ci } else { 26888c2ecf20Sopenharmony_ci // 2 source words 26898c2ecf20Sopenharmony_ci d1 = *src++; 26908c2ecf20Sopenharmony_ci *dst = comp(d0 << left | d1 >> right, *dst, 26918c2ecf20Sopenharmony_ci first); 26928c2ecf20Sopenharmony_ci d0 = d1; 26938c2ecf20Sopenharmony_ci dst++; 26948c2ecf20Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 26958c2ecf20Sopenharmony_ci } 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci // Main chunk 26988c2ecf20Sopenharmony_ci m = n % BITS_PER_LONG; 26998c2ecf20Sopenharmony_ci n /= BITS_PER_LONG; 27008c2ecf20Sopenharmony_ci while (n >= 4) { 27018c2ecf20Sopenharmony_ci d1 = *src++; 27028c2ecf20Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 27038c2ecf20Sopenharmony_ci d0 = d1; 27048c2ecf20Sopenharmony_ci d1 = *src++; 27058c2ecf20Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 27068c2ecf20Sopenharmony_ci d0 = d1; 27078c2ecf20Sopenharmony_ci d1 = *src++; 27088c2ecf20Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 27098c2ecf20Sopenharmony_ci d0 = d1; 27108c2ecf20Sopenharmony_ci d1 = *src++; 27118c2ecf20Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 27128c2ecf20Sopenharmony_ci d0 = d1; 27138c2ecf20Sopenharmony_ci n -= 4; 27148c2ecf20Sopenharmony_ci } 27158c2ecf20Sopenharmony_ci while (n--) { 27168c2ecf20Sopenharmony_ci d1 = *src++; 27178c2ecf20Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 27188c2ecf20Sopenharmony_ci d0 = d1; 27198c2ecf20Sopenharmony_ci } 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci // Trailing bits 27228c2ecf20Sopenharmony_ci if (last) { 27238c2ecf20Sopenharmony_ci if (m <= right) { 27248c2ecf20Sopenharmony_ci // Single source word 27258c2ecf20Sopenharmony_ci *dst = comp(d0 << left, *dst, last); 27268c2ecf20Sopenharmony_ci } else { 27278c2ecf20Sopenharmony_ci // 2 source words 27288c2ecf20Sopenharmony_ci d1 = *src; 27298c2ecf20Sopenharmony_ci *dst = comp(d0 << left | d1 >> right, 27308c2ecf20Sopenharmony_ci *dst, last); 27318c2ecf20Sopenharmony_ci } 27328c2ecf20Sopenharmony_ci } 27338c2ecf20Sopenharmony_ci } 27348c2ecf20Sopenharmony_ci } 27358c2ecf20Sopenharmony_ci} 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_ci /* 27398c2ecf20Sopenharmony_ci * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses 27408c2ecf20Sopenharmony_ci */ 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_cistatic void bitcpy_rev(unsigned long *dst, int dst_idx, 27438c2ecf20Sopenharmony_ci const unsigned long *src, int src_idx, u32 n) 27448c2ecf20Sopenharmony_ci{ 27458c2ecf20Sopenharmony_ci unsigned long first, last; 27468c2ecf20Sopenharmony_ci int shift = dst_idx - src_idx, left, right; 27478c2ecf20Sopenharmony_ci unsigned long d0, d1; 27488c2ecf20Sopenharmony_ci int m; 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci if (!n) 27518c2ecf20Sopenharmony_ci return; 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci dst += (n - 1) / BITS_PER_LONG; 27548c2ecf20Sopenharmony_ci src += (n - 1) / BITS_PER_LONG; 27558c2ecf20Sopenharmony_ci if ((n - 1) % BITS_PER_LONG) { 27568c2ecf20Sopenharmony_ci dst_idx += (n - 1) % BITS_PER_LONG; 27578c2ecf20Sopenharmony_ci dst += dst_idx >> SHIFT_PER_LONG; 27588c2ecf20Sopenharmony_ci dst_idx &= BITS_PER_LONG - 1; 27598c2ecf20Sopenharmony_ci src_idx += (n - 1) % BITS_PER_LONG; 27608c2ecf20Sopenharmony_ci src += src_idx >> SHIFT_PER_LONG; 27618c2ecf20Sopenharmony_ci src_idx &= BITS_PER_LONG - 1; 27628c2ecf20Sopenharmony_ci } 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci shift = dst_idx - src_idx; 27658c2ecf20Sopenharmony_ci first = ~0UL << (BITS_PER_LONG - 1 - dst_idx); 27668c2ecf20Sopenharmony_ci last = ~(~0UL << (BITS_PER_LONG - 1 - ((dst_idx - n) % BITS_PER_LONG))); 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci if (!shift) { 27698c2ecf20Sopenharmony_ci // Same alignment for source and dest 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci if ((unsigned long)dst_idx + 1 >= n) { 27728c2ecf20Sopenharmony_ci // Single word 27738c2ecf20Sopenharmony_ci if (last) 27748c2ecf20Sopenharmony_ci first &= last; 27758c2ecf20Sopenharmony_ci *dst = comp(*src, *dst, first); 27768c2ecf20Sopenharmony_ci } else { 27778c2ecf20Sopenharmony_ci // Multiple destination words 27788c2ecf20Sopenharmony_ci // Leading bits 27798c2ecf20Sopenharmony_ci if (first) { 27808c2ecf20Sopenharmony_ci *dst = comp(*src, *dst, first); 27818c2ecf20Sopenharmony_ci dst--; 27828c2ecf20Sopenharmony_ci src--; 27838c2ecf20Sopenharmony_ci n -= dst_idx + 1; 27848c2ecf20Sopenharmony_ci } 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci // Main chunk 27878c2ecf20Sopenharmony_ci n /= BITS_PER_LONG; 27888c2ecf20Sopenharmony_ci while (n >= 8) { 27898c2ecf20Sopenharmony_ci *dst-- = *src--; 27908c2ecf20Sopenharmony_ci *dst-- = *src--; 27918c2ecf20Sopenharmony_ci *dst-- = *src--; 27928c2ecf20Sopenharmony_ci *dst-- = *src--; 27938c2ecf20Sopenharmony_ci *dst-- = *src--; 27948c2ecf20Sopenharmony_ci *dst-- = *src--; 27958c2ecf20Sopenharmony_ci *dst-- = *src--; 27968c2ecf20Sopenharmony_ci *dst-- = *src--; 27978c2ecf20Sopenharmony_ci n -= 8; 27988c2ecf20Sopenharmony_ci } 27998c2ecf20Sopenharmony_ci while (n--) 28008c2ecf20Sopenharmony_ci *dst-- = *src--; 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci // Trailing bits 28038c2ecf20Sopenharmony_ci if (last) 28048c2ecf20Sopenharmony_ci *dst = comp(*src, *dst, last); 28058c2ecf20Sopenharmony_ci } 28068c2ecf20Sopenharmony_ci } else { 28078c2ecf20Sopenharmony_ci // Different alignment for source and dest 28088c2ecf20Sopenharmony_ci 28098c2ecf20Sopenharmony_ci right = shift & (BITS_PER_LONG - 1); 28108c2ecf20Sopenharmony_ci left = -shift & (BITS_PER_LONG - 1); 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci if ((unsigned long)dst_idx + 1 >= n) { 28138c2ecf20Sopenharmony_ci // Single destination word 28148c2ecf20Sopenharmony_ci if (last) 28158c2ecf20Sopenharmony_ci first &= last; 28168c2ecf20Sopenharmony_ci if (shift < 0) { 28178c2ecf20Sopenharmony_ci // Single source word 28188c2ecf20Sopenharmony_ci *dst = comp(*src << left, *dst, first); 28198c2ecf20Sopenharmony_ci } else if (1 + (unsigned long)src_idx >= n) { 28208c2ecf20Sopenharmony_ci // Single source word 28218c2ecf20Sopenharmony_ci *dst = comp(*src >> right, *dst, first); 28228c2ecf20Sopenharmony_ci } else { 28238c2ecf20Sopenharmony_ci // 2 source words 28248c2ecf20Sopenharmony_ci d0 = *src--; 28258c2ecf20Sopenharmony_ci d1 = *src; 28268c2ecf20Sopenharmony_ci *dst = comp(d0 >> right | d1 << left, *dst, 28278c2ecf20Sopenharmony_ci first); 28288c2ecf20Sopenharmony_ci } 28298c2ecf20Sopenharmony_ci } else { 28308c2ecf20Sopenharmony_ci // Multiple destination words 28318c2ecf20Sopenharmony_ci d0 = *src--; 28328c2ecf20Sopenharmony_ci // Leading bits 28338c2ecf20Sopenharmony_ci if (shift < 0) { 28348c2ecf20Sopenharmony_ci // Single source word 28358c2ecf20Sopenharmony_ci *dst = comp(d0 << left, *dst, first); 28368c2ecf20Sopenharmony_ci dst--; 28378c2ecf20Sopenharmony_ci n -= dst_idx + 1; 28388c2ecf20Sopenharmony_ci } else { 28398c2ecf20Sopenharmony_ci // 2 source words 28408c2ecf20Sopenharmony_ci d1 = *src--; 28418c2ecf20Sopenharmony_ci *dst = comp(d0 >> right | d1 << left, *dst, 28428c2ecf20Sopenharmony_ci first); 28438c2ecf20Sopenharmony_ci d0 = d1; 28448c2ecf20Sopenharmony_ci dst--; 28458c2ecf20Sopenharmony_ci n -= dst_idx + 1; 28468c2ecf20Sopenharmony_ci } 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci // Main chunk 28498c2ecf20Sopenharmony_ci m = n % BITS_PER_LONG; 28508c2ecf20Sopenharmony_ci n /= BITS_PER_LONG; 28518c2ecf20Sopenharmony_ci while (n >= 4) { 28528c2ecf20Sopenharmony_ci d1 = *src--; 28538c2ecf20Sopenharmony_ci *dst-- = d0 >> right | d1 << left; 28548c2ecf20Sopenharmony_ci d0 = d1; 28558c2ecf20Sopenharmony_ci d1 = *src--; 28568c2ecf20Sopenharmony_ci *dst-- = d0 >> right | d1 << left; 28578c2ecf20Sopenharmony_ci d0 = d1; 28588c2ecf20Sopenharmony_ci d1 = *src--; 28598c2ecf20Sopenharmony_ci *dst-- = d0 >> right | d1 << left; 28608c2ecf20Sopenharmony_ci d0 = d1; 28618c2ecf20Sopenharmony_ci d1 = *src--; 28628c2ecf20Sopenharmony_ci *dst-- = d0 >> right | d1 << left; 28638c2ecf20Sopenharmony_ci d0 = d1; 28648c2ecf20Sopenharmony_ci n -= 4; 28658c2ecf20Sopenharmony_ci } 28668c2ecf20Sopenharmony_ci while (n--) { 28678c2ecf20Sopenharmony_ci d1 = *src--; 28688c2ecf20Sopenharmony_ci *dst-- = d0 >> right | d1 << left; 28698c2ecf20Sopenharmony_ci d0 = d1; 28708c2ecf20Sopenharmony_ci } 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci // Trailing bits 28738c2ecf20Sopenharmony_ci if (last) { 28748c2ecf20Sopenharmony_ci if (m <= left) { 28758c2ecf20Sopenharmony_ci // Single source word 28768c2ecf20Sopenharmony_ci *dst = comp(d0 >> right, *dst, last); 28778c2ecf20Sopenharmony_ci } else { 28788c2ecf20Sopenharmony_ci // 2 source words 28798c2ecf20Sopenharmony_ci d1 = *src; 28808c2ecf20Sopenharmony_ci *dst = comp(d0 >> right | d1 << left, 28818c2ecf20Sopenharmony_ci *dst, last); 28828c2ecf20Sopenharmony_ci } 28838c2ecf20Sopenharmony_ci } 28848c2ecf20Sopenharmony_ci } 28858c2ecf20Sopenharmony_ci } 28868c2ecf20Sopenharmony_ci} 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci /* 28908c2ecf20Sopenharmony_ci * Unaligned forward inverting bit copy using 32-bit or 64-bit memory 28918c2ecf20Sopenharmony_ci * accesses 28928c2ecf20Sopenharmony_ci */ 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_cistatic void bitcpy_not(unsigned long *dst, int dst_idx, 28958c2ecf20Sopenharmony_ci const unsigned long *src, int src_idx, u32 n) 28968c2ecf20Sopenharmony_ci{ 28978c2ecf20Sopenharmony_ci unsigned long first, last; 28988c2ecf20Sopenharmony_ci int shift = dst_idx - src_idx, left, right; 28998c2ecf20Sopenharmony_ci unsigned long d0, d1; 29008c2ecf20Sopenharmony_ci int m; 29018c2ecf20Sopenharmony_ci 29028c2ecf20Sopenharmony_ci if (!n) 29038c2ecf20Sopenharmony_ci return; 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci shift = dst_idx - src_idx; 29068c2ecf20Sopenharmony_ci first = ~0UL >> dst_idx; 29078c2ecf20Sopenharmony_ci last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_ci if (!shift) { 29108c2ecf20Sopenharmony_ci // Same alignment for source and dest 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ci if (dst_idx + n <= BITS_PER_LONG) { 29138c2ecf20Sopenharmony_ci // Single word 29148c2ecf20Sopenharmony_ci if (last) 29158c2ecf20Sopenharmony_ci first &= last; 29168c2ecf20Sopenharmony_ci *dst = comp(~*src, *dst, first); 29178c2ecf20Sopenharmony_ci } else { 29188c2ecf20Sopenharmony_ci // Multiple destination words 29198c2ecf20Sopenharmony_ci // Leading bits 29208c2ecf20Sopenharmony_ci if (first) { 29218c2ecf20Sopenharmony_ci *dst = comp(~*src, *dst, first); 29228c2ecf20Sopenharmony_ci dst++; 29238c2ecf20Sopenharmony_ci src++; 29248c2ecf20Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 29258c2ecf20Sopenharmony_ci } 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci // Main chunk 29288c2ecf20Sopenharmony_ci n /= BITS_PER_LONG; 29298c2ecf20Sopenharmony_ci while (n >= 8) { 29308c2ecf20Sopenharmony_ci *dst++ = ~*src++; 29318c2ecf20Sopenharmony_ci *dst++ = ~*src++; 29328c2ecf20Sopenharmony_ci *dst++ = ~*src++; 29338c2ecf20Sopenharmony_ci *dst++ = ~*src++; 29348c2ecf20Sopenharmony_ci *dst++ = ~*src++; 29358c2ecf20Sopenharmony_ci *dst++ = ~*src++; 29368c2ecf20Sopenharmony_ci *dst++ = ~*src++; 29378c2ecf20Sopenharmony_ci *dst++ = ~*src++; 29388c2ecf20Sopenharmony_ci n -= 8; 29398c2ecf20Sopenharmony_ci } 29408c2ecf20Sopenharmony_ci while (n--) 29418c2ecf20Sopenharmony_ci *dst++ = ~*src++; 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci // Trailing bits 29448c2ecf20Sopenharmony_ci if (last) 29458c2ecf20Sopenharmony_ci *dst = comp(~*src, *dst, last); 29468c2ecf20Sopenharmony_ci } 29478c2ecf20Sopenharmony_ci } else { 29488c2ecf20Sopenharmony_ci // Different alignment for source and dest 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ci right = shift & (BITS_PER_LONG - 1); 29518c2ecf20Sopenharmony_ci left = -shift & (BITS_PER_LONG - 1); 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci if (dst_idx + n <= BITS_PER_LONG) { 29548c2ecf20Sopenharmony_ci // Single destination word 29558c2ecf20Sopenharmony_ci if (last) 29568c2ecf20Sopenharmony_ci first &= last; 29578c2ecf20Sopenharmony_ci if (shift > 0) { 29588c2ecf20Sopenharmony_ci // Single source word 29598c2ecf20Sopenharmony_ci *dst = comp(~*src >> right, *dst, first); 29608c2ecf20Sopenharmony_ci } else if (src_idx + n <= BITS_PER_LONG) { 29618c2ecf20Sopenharmony_ci // Single source word 29628c2ecf20Sopenharmony_ci *dst = comp(~*src << left, *dst, first); 29638c2ecf20Sopenharmony_ci } else { 29648c2ecf20Sopenharmony_ci // 2 source words 29658c2ecf20Sopenharmony_ci d0 = ~*src++; 29668c2ecf20Sopenharmony_ci d1 = ~*src; 29678c2ecf20Sopenharmony_ci *dst = comp(d0 << left | d1 >> right, *dst, 29688c2ecf20Sopenharmony_ci first); 29698c2ecf20Sopenharmony_ci } 29708c2ecf20Sopenharmony_ci } else { 29718c2ecf20Sopenharmony_ci // Multiple destination words 29728c2ecf20Sopenharmony_ci d0 = ~*src++; 29738c2ecf20Sopenharmony_ci // Leading bits 29748c2ecf20Sopenharmony_ci if (shift > 0) { 29758c2ecf20Sopenharmony_ci // Single source word 29768c2ecf20Sopenharmony_ci *dst = comp(d0 >> right, *dst, first); 29778c2ecf20Sopenharmony_ci dst++; 29788c2ecf20Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 29798c2ecf20Sopenharmony_ci } else { 29808c2ecf20Sopenharmony_ci // 2 source words 29818c2ecf20Sopenharmony_ci d1 = ~*src++; 29828c2ecf20Sopenharmony_ci *dst = comp(d0 << left | d1 >> right, *dst, 29838c2ecf20Sopenharmony_ci first); 29848c2ecf20Sopenharmony_ci d0 = d1; 29858c2ecf20Sopenharmony_ci dst++; 29868c2ecf20Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 29878c2ecf20Sopenharmony_ci } 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_ci // Main chunk 29908c2ecf20Sopenharmony_ci m = n % BITS_PER_LONG; 29918c2ecf20Sopenharmony_ci n /= BITS_PER_LONG; 29928c2ecf20Sopenharmony_ci while (n >= 4) { 29938c2ecf20Sopenharmony_ci d1 = ~*src++; 29948c2ecf20Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 29958c2ecf20Sopenharmony_ci d0 = d1; 29968c2ecf20Sopenharmony_ci d1 = ~*src++; 29978c2ecf20Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 29988c2ecf20Sopenharmony_ci d0 = d1; 29998c2ecf20Sopenharmony_ci d1 = ~*src++; 30008c2ecf20Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 30018c2ecf20Sopenharmony_ci d0 = d1; 30028c2ecf20Sopenharmony_ci d1 = ~*src++; 30038c2ecf20Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 30048c2ecf20Sopenharmony_ci d0 = d1; 30058c2ecf20Sopenharmony_ci n -= 4; 30068c2ecf20Sopenharmony_ci } 30078c2ecf20Sopenharmony_ci while (n--) { 30088c2ecf20Sopenharmony_ci d1 = ~*src++; 30098c2ecf20Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 30108c2ecf20Sopenharmony_ci d0 = d1; 30118c2ecf20Sopenharmony_ci } 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci // Trailing bits 30148c2ecf20Sopenharmony_ci if (last) { 30158c2ecf20Sopenharmony_ci if (m <= right) { 30168c2ecf20Sopenharmony_ci // Single source word 30178c2ecf20Sopenharmony_ci *dst = comp(d0 << left, *dst, last); 30188c2ecf20Sopenharmony_ci } else { 30198c2ecf20Sopenharmony_ci // 2 source words 30208c2ecf20Sopenharmony_ci d1 = ~*src; 30218c2ecf20Sopenharmony_ci *dst = comp(d0 << left | d1 >> right, 30228c2ecf20Sopenharmony_ci *dst, last); 30238c2ecf20Sopenharmony_ci } 30248c2ecf20Sopenharmony_ci } 30258c2ecf20Sopenharmony_ci } 30268c2ecf20Sopenharmony_ci } 30278c2ecf20Sopenharmony_ci} 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci /* 30318c2ecf20Sopenharmony_ci * Unaligned 32-bit pattern fill using 32/64-bit memory accesses 30328c2ecf20Sopenharmony_ci */ 30338c2ecf20Sopenharmony_ci 30348c2ecf20Sopenharmony_cistatic void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) 30358c2ecf20Sopenharmony_ci{ 30368c2ecf20Sopenharmony_ci unsigned long val = pat; 30378c2ecf20Sopenharmony_ci unsigned long first, last; 30388c2ecf20Sopenharmony_ci 30398c2ecf20Sopenharmony_ci if (!n) 30408c2ecf20Sopenharmony_ci return; 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 64 30438c2ecf20Sopenharmony_ci val |= val << 32; 30448c2ecf20Sopenharmony_ci#endif 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci first = ~0UL >> dst_idx; 30478c2ecf20Sopenharmony_ci last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); 30488c2ecf20Sopenharmony_ci 30498c2ecf20Sopenharmony_ci if (dst_idx + n <= BITS_PER_LONG) { 30508c2ecf20Sopenharmony_ci // Single word 30518c2ecf20Sopenharmony_ci if (last) 30528c2ecf20Sopenharmony_ci first &= last; 30538c2ecf20Sopenharmony_ci *dst = comp(val, *dst, first); 30548c2ecf20Sopenharmony_ci } else { 30558c2ecf20Sopenharmony_ci // Multiple destination words 30568c2ecf20Sopenharmony_ci // Leading bits 30578c2ecf20Sopenharmony_ci if (first) { 30588c2ecf20Sopenharmony_ci *dst = comp(val, *dst, first); 30598c2ecf20Sopenharmony_ci dst++; 30608c2ecf20Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 30618c2ecf20Sopenharmony_ci } 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci // Main chunk 30648c2ecf20Sopenharmony_ci n /= BITS_PER_LONG; 30658c2ecf20Sopenharmony_ci while (n >= 8) { 30668c2ecf20Sopenharmony_ci *dst++ = val; 30678c2ecf20Sopenharmony_ci *dst++ = val; 30688c2ecf20Sopenharmony_ci *dst++ = val; 30698c2ecf20Sopenharmony_ci *dst++ = val; 30708c2ecf20Sopenharmony_ci *dst++ = val; 30718c2ecf20Sopenharmony_ci *dst++ = val; 30728c2ecf20Sopenharmony_ci *dst++ = val; 30738c2ecf20Sopenharmony_ci *dst++ = val; 30748c2ecf20Sopenharmony_ci n -= 8; 30758c2ecf20Sopenharmony_ci } 30768c2ecf20Sopenharmony_ci while (n--) 30778c2ecf20Sopenharmony_ci *dst++ = val; 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci // Trailing bits 30808c2ecf20Sopenharmony_ci if (last) 30818c2ecf20Sopenharmony_ci *dst = comp(val, *dst, last); 30828c2ecf20Sopenharmony_ci } 30838c2ecf20Sopenharmony_ci} 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci /* 30878c2ecf20Sopenharmony_ci * Unaligned 32-bit pattern xor using 32/64-bit memory accesses 30888c2ecf20Sopenharmony_ci */ 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_cistatic void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) 30918c2ecf20Sopenharmony_ci{ 30928c2ecf20Sopenharmony_ci unsigned long val = pat; 30938c2ecf20Sopenharmony_ci unsigned long first, last; 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci if (!n) 30968c2ecf20Sopenharmony_ci return; 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 64 30998c2ecf20Sopenharmony_ci val |= val << 32; 31008c2ecf20Sopenharmony_ci#endif 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci first = ~0UL >> dst_idx; 31038c2ecf20Sopenharmony_ci last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci if (dst_idx + n <= BITS_PER_LONG) { 31068c2ecf20Sopenharmony_ci // Single word 31078c2ecf20Sopenharmony_ci if (last) 31088c2ecf20Sopenharmony_ci first &= last; 31098c2ecf20Sopenharmony_ci *dst = xor(val, *dst, first); 31108c2ecf20Sopenharmony_ci } else { 31118c2ecf20Sopenharmony_ci // Multiple destination words 31128c2ecf20Sopenharmony_ci // Leading bits 31138c2ecf20Sopenharmony_ci if (first) { 31148c2ecf20Sopenharmony_ci *dst = xor(val, *dst, first); 31158c2ecf20Sopenharmony_ci dst++; 31168c2ecf20Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 31178c2ecf20Sopenharmony_ci } 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci // Main chunk 31208c2ecf20Sopenharmony_ci n /= BITS_PER_LONG; 31218c2ecf20Sopenharmony_ci while (n >= 4) { 31228c2ecf20Sopenharmony_ci *dst++ ^= val; 31238c2ecf20Sopenharmony_ci *dst++ ^= val; 31248c2ecf20Sopenharmony_ci *dst++ ^= val; 31258c2ecf20Sopenharmony_ci *dst++ ^= val; 31268c2ecf20Sopenharmony_ci n -= 4; 31278c2ecf20Sopenharmony_ci } 31288c2ecf20Sopenharmony_ci while (n--) 31298c2ecf20Sopenharmony_ci *dst++ ^= val; 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci // Trailing bits 31328c2ecf20Sopenharmony_ci if (last) 31338c2ecf20Sopenharmony_ci *dst = xor(val, *dst, last); 31348c2ecf20Sopenharmony_ci } 31358c2ecf20Sopenharmony_ci} 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_cistatic inline void fill_one_line(int bpp, unsigned long next_plane, 31388c2ecf20Sopenharmony_ci unsigned long *dst, int dst_idx, u32 n, 31398c2ecf20Sopenharmony_ci u32 color) 31408c2ecf20Sopenharmony_ci{ 31418c2ecf20Sopenharmony_ci while (1) { 31428c2ecf20Sopenharmony_ci dst += dst_idx >> SHIFT_PER_LONG; 31438c2ecf20Sopenharmony_ci dst_idx &= (BITS_PER_LONG - 1); 31448c2ecf20Sopenharmony_ci bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n); 31458c2ecf20Sopenharmony_ci if (!--bpp) 31468c2ecf20Sopenharmony_ci break; 31478c2ecf20Sopenharmony_ci color >>= 1; 31488c2ecf20Sopenharmony_ci dst_idx += next_plane * 8; 31498c2ecf20Sopenharmony_ci } 31508c2ecf20Sopenharmony_ci} 31518c2ecf20Sopenharmony_ci 31528c2ecf20Sopenharmony_cistatic inline void xor_one_line(int bpp, unsigned long next_plane, 31538c2ecf20Sopenharmony_ci unsigned long *dst, int dst_idx, u32 n, 31548c2ecf20Sopenharmony_ci u32 color) 31558c2ecf20Sopenharmony_ci{ 31568c2ecf20Sopenharmony_ci while (color) { 31578c2ecf20Sopenharmony_ci dst += dst_idx >> SHIFT_PER_LONG; 31588c2ecf20Sopenharmony_ci dst_idx &= (BITS_PER_LONG - 1); 31598c2ecf20Sopenharmony_ci bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n); 31608c2ecf20Sopenharmony_ci if (!--bpp) 31618c2ecf20Sopenharmony_ci break; 31628c2ecf20Sopenharmony_ci color >>= 1; 31638c2ecf20Sopenharmony_ci dst_idx += next_plane * 8; 31648c2ecf20Sopenharmony_ci } 31658c2ecf20Sopenharmony_ci} 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_cistatic void amifb_fillrect(struct fb_info *info, 31698c2ecf20Sopenharmony_ci const struct fb_fillrect *rect) 31708c2ecf20Sopenharmony_ci{ 31718c2ecf20Sopenharmony_ci struct amifb_par *par = info->par; 31728c2ecf20Sopenharmony_ci int dst_idx, x2, y2; 31738c2ecf20Sopenharmony_ci unsigned long *dst; 31748c2ecf20Sopenharmony_ci u32 width, height; 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci if (!rect->width || !rect->height) 31778c2ecf20Sopenharmony_ci return; 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci /* 31808c2ecf20Sopenharmony_ci * We could use hardware clipping but on many cards you get around 31818c2ecf20Sopenharmony_ci * hardware clipping by writing to framebuffer directly. 31828c2ecf20Sopenharmony_ci * */ 31838c2ecf20Sopenharmony_ci x2 = rect->dx + rect->width; 31848c2ecf20Sopenharmony_ci y2 = rect->dy + rect->height; 31858c2ecf20Sopenharmony_ci x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; 31868c2ecf20Sopenharmony_ci y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; 31878c2ecf20Sopenharmony_ci width = x2 - rect->dx; 31888c2ecf20Sopenharmony_ci height = y2 - rect->dy; 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci dst = (unsigned long *) 31918c2ecf20Sopenharmony_ci ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); 31928c2ecf20Sopenharmony_ci dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; 31938c2ecf20Sopenharmony_ci dst_idx += rect->dy * par->next_line * 8 + rect->dx; 31948c2ecf20Sopenharmony_ci while (height--) { 31958c2ecf20Sopenharmony_ci switch (rect->rop) { 31968c2ecf20Sopenharmony_ci case ROP_COPY: 31978c2ecf20Sopenharmony_ci fill_one_line(info->var.bits_per_pixel, 31988c2ecf20Sopenharmony_ci par->next_plane, dst, dst_idx, width, 31998c2ecf20Sopenharmony_ci rect->color); 32008c2ecf20Sopenharmony_ci break; 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci case ROP_XOR: 32038c2ecf20Sopenharmony_ci xor_one_line(info->var.bits_per_pixel, par->next_plane, 32048c2ecf20Sopenharmony_ci dst, dst_idx, width, rect->color); 32058c2ecf20Sopenharmony_ci break; 32068c2ecf20Sopenharmony_ci } 32078c2ecf20Sopenharmony_ci dst_idx += par->next_line * 8; 32088c2ecf20Sopenharmony_ci } 32098c2ecf20Sopenharmony_ci} 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_cistatic inline void copy_one_line(int bpp, unsigned long next_plane, 32128c2ecf20Sopenharmony_ci unsigned long *dst, int dst_idx, 32138c2ecf20Sopenharmony_ci unsigned long *src, int src_idx, u32 n) 32148c2ecf20Sopenharmony_ci{ 32158c2ecf20Sopenharmony_ci while (1) { 32168c2ecf20Sopenharmony_ci dst += dst_idx >> SHIFT_PER_LONG; 32178c2ecf20Sopenharmony_ci dst_idx &= (BITS_PER_LONG - 1); 32188c2ecf20Sopenharmony_ci src += src_idx >> SHIFT_PER_LONG; 32198c2ecf20Sopenharmony_ci src_idx &= (BITS_PER_LONG - 1); 32208c2ecf20Sopenharmony_ci bitcpy(dst, dst_idx, src, src_idx, n); 32218c2ecf20Sopenharmony_ci if (!--bpp) 32228c2ecf20Sopenharmony_ci break; 32238c2ecf20Sopenharmony_ci dst_idx += next_plane * 8; 32248c2ecf20Sopenharmony_ci src_idx += next_plane * 8; 32258c2ecf20Sopenharmony_ci } 32268c2ecf20Sopenharmony_ci} 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_cistatic inline void copy_one_line_rev(int bpp, unsigned long next_plane, 32298c2ecf20Sopenharmony_ci unsigned long *dst, int dst_idx, 32308c2ecf20Sopenharmony_ci unsigned long *src, int src_idx, u32 n) 32318c2ecf20Sopenharmony_ci{ 32328c2ecf20Sopenharmony_ci while (1) { 32338c2ecf20Sopenharmony_ci dst += dst_idx >> SHIFT_PER_LONG; 32348c2ecf20Sopenharmony_ci dst_idx &= (BITS_PER_LONG - 1); 32358c2ecf20Sopenharmony_ci src += src_idx >> SHIFT_PER_LONG; 32368c2ecf20Sopenharmony_ci src_idx &= (BITS_PER_LONG - 1); 32378c2ecf20Sopenharmony_ci bitcpy_rev(dst, dst_idx, src, src_idx, n); 32388c2ecf20Sopenharmony_ci if (!--bpp) 32398c2ecf20Sopenharmony_ci break; 32408c2ecf20Sopenharmony_ci dst_idx += next_plane * 8; 32418c2ecf20Sopenharmony_ci src_idx += next_plane * 8; 32428c2ecf20Sopenharmony_ci } 32438c2ecf20Sopenharmony_ci} 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_cistatic void amifb_copyarea(struct fb_info *info, 32478c2ecf20Sopenharmony_ci const struct fb_copyarea *area) 32488c2ecf20Sopenharmony_ci{ 32498c2ecf20Sopenharmony_ci struct amifb_par *par = info->par; 32508c2ecf20Sopenharmony_ci int x2, y2; 32518c2ecf20Sopenharmony_ci u32 dx, dy, sx, sy, width, height; 32528c2ecf20Sopenharmony_ci unsigned long *dst, *src; 32538c2ecf20Sopenharmony_ci int dst_idx, src_idx; 32548c2ecf20Sopenharmony_ci int rev_copy = 0; 32558c2ecf20Sopenharmony_ci 32568c2ecf20Sopenharmony_ci /* clip the destination */ 32578c2ecf20Sopenharmony_ci x2 = area->dx + area->width; 32588c2ecf20Sopenharmony_ci y2 = area->dy + area->height; 32598c2ecf20Sopenharmony_ci dx = area->dx > 0 ? area->dx : 0; 32608c2ecf20Sopenharmony_ci dy = area->dy > 0 ? area->dy : 0; 32618c2ecf20Sopenharmony_ci x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; 32628c2ecf20Sopenharmony_ci y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; 32638c2ecf20Sopenharmony_ci width = x2 - dx; 32648c2ecf20Sopenharmony_ci height = y2 - dy; 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci if (area->sx + dx < area->dx || area->sy + dy < area->dy) 32678c2ecf20Sopenharmony_ci return; 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci /* update sx,sy */ 32708c2ecf20Sopenharmony_ci sx = area->sx + (dx - area->dx); 32718c2ecf20Sopenharmony_ci sy = area->sy + (dy - area->dy); 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci /* the source must be completely inside the virtual screen */ 32748c2ecf20Sopenharmony_ci if (sx + width > info->var.xres_virtual || 32758c2ecf20Sopenharmony_ci sy + height > info->var.yres_virtual) 32768c2ecf20Sopenharmony_ci return; 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_ci if (dy > sy || (dy == sy && dx > sx)) { 32798c2ecf20Sopenharmony_ci dy += height; 32808c2ecf20Sopenharmony_ci sy += height; 32818c2ecf20Sopenharmony_ci rev_copy = 1; 32828c2ecf20Sopenharmony_ci } 32838c2ecf20Sopenharmony_ci dst = (unsigned long *) 32848c2ecf20Sopenharmony_ci ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); 32858c2ecf20Sopenharmony_ci src = dst; 32868c2ecf20Sopenharmony_ci dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; 32878c2ecf20Sopenharmony_ci src_idx = dst_idx; 32888c2ecf20Sopenharmony_ci dst_idx += dy * par->next_line * 8 + dx; 32898c2ecf20Sopenharmony_ci src_idx += sy * par->next_line * 8 + sx; 32908c2ecf20Sopenharmony_ci if (rev_copy) { 32918c2ecf20Sopenharmony_ci while (height--) { 32928c2ecf20Sopenharmony_ci dst_idx -= par->next_line * 8; 32938c2ecf20Sopenharmony_ci src_idx -= par->next_line * 8; 32948c2ecf20Sopenharmony_ci copy_one_line_rev(info->var.bits_per_pixel, 32958c2ecf20Sopenharmony_ci par->next_plane, dst, dst_idx, src, 32968c2ecf20Sopenharmony_ci src_idx, width); 32978c2ecf20Sopenharmony_ci } 32988c2ecf20Sopenharmony_ci } else { 32998c2ecf20Sopenharmony_ci while (height--) { 33008c2ecf20Sopenharmony_ci copy_one_line(info->var.bits_per_pixel, 33018c2ecf20Sopenharmony_ci par->next_plane, dst, dst_idx, src, 33028c2ecf20Sopenharmony_ci src_idx, width); 33038c2ecf20Sopenharmony_ci dst_idx += par->next_line * 8; 33048c2ecf20Sopenharmony_ci src_idx += par->next_line * 8; 33058c2ecf20Sopenharmony_ci } 33068c2ecf20Sopenharmony_ci } 33078c2ecf20Sopenharmony_ci} 33088c2ecf20Sopenharmony_ci 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_cistatic inline void expand_one_line(int bpp, unsigned long next_plane, 33118c2ecf20Sopenharmony_ci unsigned long *dst, int dst_idx, u32 n, 33128c2ecf20Sopenharmony_ci const u8 *data, u32 bgcolor, u32 fgcolor) 33138c2ecf20Sopenharmony_ci{ 33148c2ecf20Sopenharmony_ci const unsigned long *src; 33158c2ecf20Sopenharmony_ci int src_idx; 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci while (1) { 33188c2ecf20Sopenharmony_ci dst += dst_idx >> SHIFT_PER_LONG; 33198c2ecf20Sopenharmony_ci dst_idx &= (BITS_PER_LONG - 1); 33208c2ecf20Sopenharmony_ci if ((bgcolor ^ fgcolor) & 1) { 33218c2ecf20Sopenharmony_ci src = (unsigned long *) 33228c2ecf20Sopenharmony_ci ((unsigned long)data & ~(BYTES_PER_LONG - 1)); 33238c2ecf20Sopenharmony_ci src_idx = ((unsigned long)data & (BYTES_PER_LONG - 1)) * 8; 33248c2ecf20Sopenharmony_ci if (fgcolor & 1) 33258c2ecf20Sopenharmony_ci bitcpy(dst, dst_idx, src, src_idx, n); 33268c2ecf20Sopenharmony_ci else 33278c2ecf20Sopenharmony_ci bitcpy_not(dst, dst_idx, src, src_idx, n); 33288c2ecf20Sopenharmony_ci /* set or clear */ 33298c2ecf20Sopenharmony_ci } else 33308c2ecf20Sopenharmony_ci bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n); 33318c2ecf20Sopenharmony_ci if (!--bpp) 33328c2ecf20Sopenharmony_ci break; 33338c2ecf20Sopenharmony_ci bgcolor >>= 1; 33348c2ecf20Sopenharmony_ci fgcolor >>= 1; 33358c2ecf20Sopenharmony_ci dst_idx += next_plane * 8; 33368c2ecf20Sopenharmony_ci } 33378c2ecf20Sopenharmony_ci} 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci 33408c2ecf20Sopenharmony_cistatic void amifb_imageblit(struct fb_info *info, const struct fb_image *image) 33418c2ecf20Sopenharmony_ci{ 33428c2ecf20Sopenharmony_ci struct amifb_par *par = info->par; 33438c2ecf20Sopenharmony_ci int x2, y2; 33448c2ecf20Sopenharmony_ci unsigned long *dst; 33458c2ecf20Sopenharmony_ci int dst_idx; 33468c2ecf20Sopenharmony_ci const char *src; 33478c2ecf20Sopenharmony_ci u32 dx, dy, width, height, pitch; 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_ci /* 33508c2ecf20Sopenharmony_ci * We could use hardware clipping but on many cards you get around 33518c2ecf20Sopenharmony_ci * hardware clipping by writing to framebuffer directly like we are 33528c2ecf20Sopenharmony_ci * doing here. 33538c2ecf20Sopenharmony_ci */ 33548c2ecf20Sopenharmony_ci x2 = image->dx + image->width; 33558c2ecf20Sopenharmony_ci y2 = image->dy + image->height; 33568c2ecf20Sopenharmony_ci dx = image->dx; 33578c2ecf20Sopenharmony_ci dy = image->dy; 33588c2ecf20Sopenharmony_ci x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; 33598c2ecf20Sopenharmony_ci y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; 33608c2ecf20Sopenharmony_ci width = x2 - dx; 33618c2ecf20Sopenharmony_ci height = y2 - dy; 33628c2ecf20Sopenharmony_ci 33638c2ecf20Sopenharmony_ci if (image->depth == 1) { 33648c2ecf20Sopenharmony_ci dst = (unsigned long *) 33658c2ecf20Sopenharmony_ci ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); 33668c2ecf20Sopenharmony_ci dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; 33678c2ecf20Sopenharmony_ci dst_idx += dy * par->next_line * 8 + dx; 33688c2ecf20Sopenharmony_ci src = image->data; 33698c2ecf20Sopenharmony_ci pitch = (image->width + 7) / 8; 33708c2ecf20Sopenharmony_ci while (height--) { 33718c2ecf20Sopenharmony_ci expand_one_line(info->var.bits_per_pixel, 33728c2ecf20Sopenharmony_ci par->next_plane, dst, dst_idx, width, 33738c2ecf20Sopenharmony_ci src, image->bg_color, 33748c2ecf20Sopenharmony_ci image->fg_color); 33758c2ecf20Sopenharmony_ci dst_idx += par->next_line * 8; 33768c2ecf20Sopenharmony_ci src += pitch; 33778c2ecf20Sopenharmony_ci } 33788c2ecf20Sopenharmony_ci } else { 33798c2ecf20Sopenharmony_ci c2p_planar(info->screen_base, image->data, dx, dy, width, 33808c2ecf20Sopenharmony_ci height, par->next_line, par->next_plane, 33818c2ecf20Sopenharmony_ci image->width, info->var.bits_per_pixel); 33828c2ecf20Sopenharmony_ci } 33838c2ecf20Sopenharmony_ci} 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_ci 33868c2ecf20Sopenharmony_ci /* 33878c2ecf20Sopenharmony_ci * Amiga Frame Buffer Specific ioctls 33888c2ecf20Sopenharmony_ci */ 33898c2ecf20Sopenharmony_ci 33908c2ecf20Sopenharmony_cistatic int amifb_ioctl(struct fb_info *info, 33918c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 33928c2ecf20Sopenharmony_ci{ 33938c2ecf20Sopenharmony_ci union { 33948c2ecf20Sopenharmony_ci struct fb_fix_cursorinfo fix; 33958c2ecf20Sopenharmony_ci struct fb_var_cursorinfo var; 33968c2ecf20Sopenharmony_ci struct fb_cursorstate state; 33978c2ecf20Sopenharmony_ci } crsr; 33988c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 33998c2ecf20Sopenharmony_ci int i; 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_ci switch (cmd) { 34028c2ecf20Sopenharmony_ci case FBIOGET_FCURSORINFO: 34038c2ecf20Sopenharmony_ci i = ami_get_fix_cursorinfo(&crsr.fix, info->par); 34048c2ecf20Sopenharmony_ci if (i) 34058c2ecf20Sopenharmony_ci return i; 34068c2ecf20Sopenharmony_ci return copy_to_user(argp, &crsr.fix, 34078c2ecf20Sopenharmony_ci sizeof(crsr.fix)) ? -EFAULT : 0; 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci case FBIOGET_VCURSORINFO: 34108c2ecf20Sopenharmony_ci i = ami_get_var_cursorinfo(&crsr.var, 34118c2ecf20Sopenharmony_ci ((struct fb_var_cursorinfo __user *)arg)->data, 34128c2ecf20Sopenharmony_ci info->par); 34138c2ecf20Sopenharmony_ci if (i) 34148c2ecf20Sopenharmony_ci return i; 34158c2ecf20Sopenharmony_ci return copy_to_user(argp, &crsr.var, 34168c2ecf20Sopenharmony_ci sizeof(crsr.var)) ? -EFAULT : 0; 34178c2ecf20Sopenharmony_ci 34188c2ecf20Sopenharmony_ci case FBIOPUT_VCURSORINFO: 34198c2ecf20Sopenharmony_ci if (copy_from_user(&crsr.var, argp, sizeof(crsr.var))) 34208c2ecf20Sopenharmony_ci return -EFAULT; 34218c2ecf20Sopenharmony_ci return ami_set_var_cursorinfo(&crsr.var, 34228c2ecf20Sopenharmony_ci ((struct fb_var_cursorinfo __user *)arg)->data, 34238c2ecf20Sopenharmony_ci info->par); 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_ci case FBIOGET_CURSORSTATE: 34268c2ecf20Sopenharmony_ci i = ami_get_cursorstate(&crsr.state, info->par); 34278c2ecf20Sopenharmony_ci if (i) 34288c2ecf20Sopenharmony_ci return i; 34298c2ecf20Sopenharmony_ci return copy_to_user(argp, &crsr.state, 34308c2ecf20Sopenharmony_ci sizeof(crsr.state)) ? -EFAULT : 0; 34318c2ecf20Sopenharmony_ci 34328c2ecf20Sopenharmony_ci case FBIOPUT_CURSORSTATE: 34338c2ecf20Sopenharmony_ci if (copy_from_user(&crsr.state, argp, sizeof(crsr.state))) 34348c2ecf20Sopenharmony_ci return -EFAULT; 34358c2ecf20Sopenharmony_ci return ami_set_cursorstate(&crsr.state, info->par); 34368c2ecf20Sopenharmony_ci } 34378c2ecf20Sopenharmony_ci return -EINVAL; 34388c2ecf20Sopenharmony_ci} 34398c2ecf20Sopenharmony_ci 34408c2ecf20Sopenharmony_ci 34418c2ecf20Sopenharmony_ci /* 34428c2ecf20Sopenharmony_ci * Flash the cursor (called by VBlank interrupt) 34438c2ecf20Sopenharmony_ci */ 34448c2ecf20Sopenharmony_ci 34458c2ecf20Sopenharmony_cistatic int flash_cursor(void) 34468c2ecf20Sopenharmony_ci{ 34478c2ecf20Sopenharmony_ci static int cursorcount = 1; 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci if (cursormode == FB_CURSOR_FLASH) { 34508c2ecf20Sopenharmony_ci if (!--cursorcount) { 34518c2ecf20Sopenharmony_ci cursorstate = -cursorstate; 34528c2ecf20Sopenharmony_ci cursorcount = cursorrate; 34538c2ecf20Sopenharmony_ci if (!is_blanked) 34548c2ecf20Sopenharmony_ci return 1; 34558c2ecf20Sopenharmony_ci } 34568c2ecf20Sopenharmony_ci } 34578c2ecf20Sopenharmony_ci return 0; 34588c2ecf20Sopenharmony_ci} 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_ci /* 34618c2ecf20Sopenharmony_ci * VBlank Display Interrupt 34628c2ecf20Sopenharmony_ci */ 34638c2ecf20Sopenharmony_ci 34648c2ecf20Sopenharmony_cistatic irqreturn_t amifb_interrupt(int irq, void *dev_id) 34658c2ecf20Sopenharmony_ci{ 34668c2ecf20Sopenharmony_ci struct amifb_par *par = dev_id; 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci if (do_vmode_pan || do_vmode_full) 34698c2ecf20Sopenharmony_ci ami_update_display(par); 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ci if (do_vmode_full) 34728c2ecf20Sopenharmony_ci ami_init_display(par); 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci if (do_vmode_pan) { 34758c2ecf20Sopenharmony_ci flash_cursor(); 34768c2ecf20Sopenharmony_ci ami_rebuild_copper(par); 34778c2ecf20Sopenharmony_ci do_cursor = do_vmode_pan = 0; 34788c2ecf20Sopenharmony_ci } else if (do_cursor) { 34798c2ecf20Sopenharmony_ci flash_cursor(); 34808c2ecf20Sopenharmony_ci ami_set_sprite(par); 34818c2ecf20Sopenharmony_ci do_cursor = 0; 34828c2ecf20Sopenharmony_ci } else { 34838c2ecf20Sopenharmony_ci if (flash_cursor()) 34848c2ecf20Sopenharmony_ci ami_set_sprite(par); 34858c2ecf20Sopenharmony_ci } 34868c2ecf20Sopenharmony_ci 34878c2ecf20Sopenharmony_ci if (do_blank) { 34888c2ecf20Sopenharmony_ci ami_do_blank(par); 34898c2ecf20Sopenharmony_ci do_blank = 0; 34908c2ecf20Sopenharmony_ci } 34918c2ecf20Sopenharmony_ci 34928c2ecf20Sopenharmony_ci if (do_vmode_full) { 34938c2ecf20Sopenharmony_ci ami_reinit_copper(par); 34948c2ecf20Sopenharmony_ci do_vmode_full = 0; 34958c2ecf20Sopenharmony_ci } 34968c2ecf20Sopenharmony_ci return IRQ_HANDLED; 34978c2ecf20Sopenharmony_ci} 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_ci 35008c2ecf20Sopenharmony_cistatic const struct fb_ops amifb_ops = { 35018c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 35028c2ecf20Sopenharmony_ci .fb_check_var = amifb_check_var, 35038c2ecf20Sopenharmony_ci .fb_set_par = amifb_set_par, 35048c2ecf20Sopenharmony_ci .fb_setcolreg = amifb_setcolreg, 35058c2ecf20Sopenharmony_ci .fb_blank = amifb_blank, 35068c2ecf20Sopenharmony_ci .fb_pan_display = amifb_pan_display, 35078c2ecf20Sopenharmony_ci .fb_fillrect = amifb_fillrect, 35088c2ecf20Sopenharmony_ci .fb_copyarea = amifb_copyarea, 35098c2ecf20Sopenharmony_ci .fb_imageblit = amifb_imageblit, 35108c2ecf20Sopenharmony_ci .fb_ioctl = amifb_ioctl, 35118c2ecf20Sopenharmony_ci}; 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_ci 35148c2ecf20Sopenharmony_ci /* 35158c2ecf20Sopenharmony_ci * Allocate, Clear and Align a Block of Chip Memory 35168c2ecf20Sopenharmony_ci */ 35178c2ecf20Sopenharmony_ci 35188c2ecf20Sopenharmony_cistatic void *aligned_chipptr; 35198c2ecf20Sopenharmony_ci 35208c2ecf20Sopenharmony_cistatic inline u_long __init chipalloc(u_long size) 35218c2ecf20Sopenharmony_ci{ 35228c2ecf20Sopenharmony_ci aligned_chipptr = amiga_chip_alloc(size, "amifb [RAM]"); 35238c2ecf20Sopenharmony_ci if (!aligned_chipptr) { 35248c2ecf20Sopenharmony_ci pr_err("amifb: No Chip RAM for frame buffer"); 35258c2ecf20Sopenharmony_ci return 0; 35268c2ecf20Sopenharmony_ci } 35278c2ecf20Sopenharmony_ci memset(aligned_chipptr, 0, size); 35288c2ecf20Sopenharmony_ci return (u_long)aligned_chipptr; 35298c2ecf20Sopenharmony_ci} 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_cistatic inline void chipfree(void) 35328c2ecf20Sopenharmony_ci{ 35338c2ecf20Sopenharmony_ci if (aligned_chipptr) 35348c2ecf20Sopenharmony_ci amiga_chip_free(aligned_chipptr); 35358c2ecf20Sopenharmony_ci} 35368c2ecf20Sopenharmony_ci 35378c2ecf20Sopenharmony_ci 35388c2ecf20Sopenharmony_ci /* 35398c2ecf20Sopenharmony_ci * Initialisation 35408c2ecf20Sopenharmony_ci */ 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_cistatic int __init amifb_probe(struct platform_device *pdev) 35438c2ecf20Sopenharmony_ci{ 35448c2ecf20Sopenharmony_ci struct fb_info *info; 35458c2ecf20Sopenharmony_ci int tag, i, err = 0; 35468c2ecf20Sopenharmony_ci u_long chipptr; 35478c2ecf20Sopenharmony_ci u_int defmode; 35488c2ecf20Sopenharmony_ci 35498c2ecf20Sopenharmony_ci#ifndef MODULE 35508c2ecf20Sopenharmony_ci char *option = NULL; 35518c2ecf20Sopenharmony_ci 35528c2ecf20Sopenharmony_ci if (fb_get_options("amifb", &option)) { 35538c2ecf20Sopenharmony_ci amifb_video_off(); 35548c2ecf20Sopenharmony_ci return -ENODEV; 35558c2ecf20Sopenharmony_ci } 35568c2ecf20Sopenharmony_ci amifb_setup(option); 35578c2ecf20Sopenharmony_ci#endif 35588c2ecf20Sopenharmony_ci custom.dmacon = DMAF_ALL | DMAF_MASTER; 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev); 35618c2ecf20Sopenharmony_ci if (!info) 35628c2ecf20Sopenharmony_ci return -ENOMEM; 35638c2ecf20Sopenharmony_ci 35648c2ecf20Sopenharmony_ci strcpy(info->fix.id, "Amiga "); 35658c2ecf20Sopenharmony_ci info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 35668c2ecf20Sopenharmony_ci info->fix.accel = FB_ACCEL_AMIGABLITT; 35678c2ecf20Sopenharmony_ci 35688c2ecf20Sopenharmony_ci switch (amiga_chipset) { 35698c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_AMIGA_OCS 35708c2ecf20Sopenharmony_ci case CS_OCS: 35718c2ecf20Sopenharmony_ci strcat(info->fix.id, "OCS"); 35728c2ecf20Sopenharmony_cidefault_chipset: 35738c2ecf20Sopenharmony_ci chipset = TAG_OCS; 35748c2ecf20Sopenharmony_ci maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ 35758c2ecf20Sopenharmony_ci maxdepth[TAG_HIRES] = 4; 35768c2ecf20Sopenharmony_ci maxdepth[TAG_LORES] = 6; 35778c2ecf20Sopenharmony_ci maxfmode = TAG_FMODE_1; 35788c2ecf20Sopenharmony_ci defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC; 35798c2ecf20Sopenharmony_ci info->fix.smem_len = VIDEOMEMSIZE_OCS; 35808c2ecf20Sopenharmony_ci break; 35818c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_AMIGA_OCS */ 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_AMIGA_ECS 35848c2ecf20Sopenharmony_ci case CS_ECS: 35858c2ecf20Sopenharmony_ci strcat(info->fix.id, "ECS"); 35868c2ecf20Sopenharmony_ci chipset = TAG_ECS; 35878c2ecf20Sopenharmony_ci maxdepth[TAG_SHRES] = 2; 35888c2ecf20Sopenharmony_ci maxdepth[TAG_HIRES] = 4; 35898c2ecf20Sopenharmony_ci maxdepth[TAG_LORES] = 6; 35908c2ecf20Sopenharmony_ci maxfmode = TAG_FMODE_1; 35918c2ecf20Sopenharmony_ci if (AMIGAHW_PRESENT(AMBER_FF)) 35928c2ecf20Sopenharmony_ci defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL 35938c2ecf20Sopenharmony_ci : DEFMODE_AMBER_NTSC; 35948c2ecf20Sopenharmony_ci else 35958c2ecf20Sopenharmony_ci defmode = amiga_vblank == 50 ? DEFMODE_PAL 35968c2ecf20Sopenharmony_ci : DEFMODE_NTSC; 35978c2ecf20Sopenharmony_ci if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > 35988c2ecf20Sopenharmony_ci VIDEOMEMSIZE_ECS_2M) 35998c2ecf20Sopenharmony_ci info->fix.smem_len = VIDEOMEMSIZE_ECS_2M; 36008c2ecf20Sopenharmony_ci else 36018c2ecf20Sopenharmony_ci info->fix.smem_len = VIDEOMEMSIZE_ECS_1M; 36028c2ecf20Sopenharmony_ci break; 36038c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_AMIGA_ECS */ 36048c2ecf20Sopenharmony_ci 36058c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_AMIGA_AGA 36068c2ecf20Sopenharmony_ci case CS_AGA: 36078c2ecf20Sopenharmony_ci strcat(info->fix.id, "AGA"); 36088c2ecf20Sopenharmony_ci chipset = TAG_AGA; 36098c2ecf20Sopenharmony_ci maxdepth[TAG_SHRES] = 8; 36108c2ecf20Sopenharmony_ci maxdepth[TAG_HIRES] = 8; 36118c2ecf20Sopenharmony_ci maxdepth[TAG_LORES] = 8; 36128c2ecf20Sopenharmony_ci maxfmode = TAG_FMODE_4; 36138c2ecf20Sopenharmony_ci defmode = DEFMODE_AGA; 36148c2ecf20Sopenharmony_ci if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > 36158c2ecf20Sopenharmony_ci VIDEOMEMSIZE_AGA_2M) 36168c2ecf20Sopenharmony_ci info->fix.smem_len = VIDEOMEMSIZE_AGA_2M; 36178c2ecf20Sopenharmony_ci else 36188c2ecf20Sopenharmony_ci info->fix.smem_len = VIDEOMEMSIZE_AGA_1M; 36198c2ecf20Sopenharmony_ci break; 36208c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_AMIGA_AGA */ 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ci default: 36238c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_AMIGA_OCS 36248c2ecf20Sopenharmony_ci printk("Unknown graphics chipset, defaulting to OCS\n"); 36258c2ecf20Sopenharmony_ci strcat(info->fix.id, "Unknown"); 36268c2ecf20Sopenharmony_ci goto default_chipset; 36278c2ecf20Sopenharmony_ci#else /* CONFIG_FB_AMIGA_OCS */ 36288c2ecf20Sopenharmony_ci err = -ENODEV; 36298c2ecf20Sopenharmony_ci goto release; 36308c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_AMIGA_OCS */ 36318c2ecf20Sopenharmony_ci break; 36328c2ecf20Sopenharmony_ci } 36338c2ecf20Sopenharmony_ci 36348c2ecf20Sopenharmony_ci /* 36358c2ecf20Sopenharmony_ci * Calculate the Pixel Clock Values for this Machine 36368c2ecf20Sopenharmony_ci */ 36378c2ecf20Sopenharmony_ci 36388c2ecf20Sopenharmony_ci { 36398c2ecf20Sopenharmony_ci u_long tmp = DIVUL(200000000000ULL, amiga_eclock); 36408c2ecf20Sopenharmony_ci 36418c2ecf20Sopenharmony_ci pixclock[TAG_SHRES] = (tmp + 4) / 8; /* SHRES: 35 ns / 28 MHz */ 36428c2ecf20Sopenharmony_ci pixclock[TAG_HIRES] = (tmp + 2) / 4; /* HIRES: 70 ns / 14 MHz */ 36438c2ecf20Sopenharmony_ci pixclock[TAG_LORES] = (tmp + 1) / 2; /* LORES: 140 ns / 7 MHz */ 36448c2ecf20Sopenharmony_ci } 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_ci /* 36478c2ecf20Sopenharmony_ci * Replace the Tag Values with the Real Pixel Clock Values 36488c2ecf20Sopenharmony_ci */ 36498c2ecf20Sopenharmony_ci 36508c2ecf20Sopenharmony_ci for (i = 0; i < NUM_TOTAL_MODES; i++) { 36518c2ecf20Sopenharmony_ci struct fb_videomode *mode = &ami_modedb[i]; 36528c2ecf20Sopenharmony_ci tag = mode->pixclock; 36538c2ecf20Sopenharmony_ci if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) { 36548c2ecf20Sopenharmony_ci mode->pixclock = pixclock[tag]; 36558c2ecf20Sopenharmony_ci } 36568c2ecf20Sopenharmony_ci } 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_ci if (amifb_hfmin) { 36598c2ecf20Sopenharmony_ci info->monspecs.hfmin = amifb_hfmin; 36608c2ecf20Sopenharmony_ci info->monspecs.hfmax = amifb_hfmax; 36618c2ecf20Sopenharmony_ci info->monspecs.vfmin = amifb_vfmin; 36628c2ecf20Sopenharmony_ci info->monspecs.vfmax = amifb_vfmax; 36638c2ecf20Sopenharmony_ci } else { 36648c2ecf20Sopenharmony_ci /* 36658c2ecf20Sopenharmony_ci * These are for a typical Amiga monitor (e.g. A1960) 36668c2ecf20Sopenharmony_ci */ 36678c2ecf20Sopenharmony_ci info->monspecs.hfmin = 15000; 36688c2ecf20Sopenharmony_ci info->monspecs.hfmax = 38000; 36698c2ecf20Sopenharmony_ci info->monspecs.vfmin = 49; 36708c2ecf20Sopenharmony_ci info->monspecs.vfmax = 90; 36718c2ecf20Sopenharmony_ci } 36728c2ecf20Sopenharmony_ci 36738c2ecf20Sopenharmony_ci info->fbops = &amifb_ops; 36748c2ecf20Sopenharmony_ci info->flags = FBINFO_DEFAULT; 36758c2ecf20Sopenharmony_ci info->device = &pdev->dev; 36768c2ecf20Sopenharmony_ci 36778c2ecf20Sopenharmony_ci if (!fb_find_mode(&info->var, info, mode_option, ami_modedb, 36788c2ecf20Sopenharmony_ci NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { 36798c2ecf20Sopenharmony_ci err = -EINVAL; 36808c2ecf20Sopenharmony_ci goto release; 36818c2ecf20Sopenharmony_ci } 36828c2ecf20Sopenharmony_ci 36838c2ecf20Sopenharmony_ci fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES, 36848c2ecf20Sopenharmony_ci &info->modelist); 36858c2ecf20Sopenharmony_ci 36868c2ecf20Sopenharmony_ci round_down_bpp = 0; 36878c2ecf20Sopenharmony_ci chipptr = chipalloc(info->fix.smem_len + SPRITEMEMSIZE + 36888c2ecf20Sopenharmony_ci DUMMYSPRITEMEMSIZE + COPINITSIZE + 36898c2ecf20Sopenharmony_ci 4 * COPLISTSIZE); 36908c2ecf20Sopenharmony_ci if (!chipptr) { 36918c2ecf20Sopenharmony_ci err = -ENOMEM; 36928c2ecf20Sopenharmony_ci goto release; 36938c2ecf20Sopenharmony_ci } 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci assignchunk(videomemory, u_long, chipptr, info->fix.smem_len); 36968c2ecf20Sopenharmony_ci assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); 36978c2ecf20Sopenharmony_ci assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); 36988c2ecf20Sopenharmony_ci assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); 36998c2ecf20Sopenharmony_ci assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE); 37008c2ecf20Sopenharmony_ci assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE); 37018c2ecf20Sopenharmony_ci assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE); 37028c2ecf20Sopenharmony_ci assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE); 37038c2ecf20Sopenharmony_ci 37048c2ecf20Sopenharmony_ci /* 37058c2ecf20Sopenharmony_ci * access the videomem with writethrough cache 37068c2ecf20Sopenharmony_ci */ 37078c2ecf20Sopenharmony_ci info->fix.smem_start = (u_long)ZTWO_PADDR(videomemory); 37088c2ecf20Sopenharmony_ci videomemory = (u_long)ioremap_wt(info->fix.smem_start, 37098c2ecf20Sopenharmony_ci info->fix.smem_len); 37108c2ecf20Sopenharmony_ci if (!videomemory) { 37118c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 37128c2ecf20Sopenharmony_ci "Unable to map videomem cached writethrough\n"); 37138c2ecf20Sopenharmony_ci info->screen_base = ZTWO_VADDR(info->fix.smem_start); 37148c2ecf20Sopenharmony_ci } else 37158c2ecf20Sopenharmony_ci info->screen_base = (char *)videomemory; 37168c2ecf20Sopenharmony_ci 37178c2ecf20Sopenharmony_ci memset(dummysprite, 0, DUMMYSPRITEMEMSIZE); 37188c2ecf20Sopenharmony_ci 37198c2ecf20Sopenharmony_ci /* 37208c2ecf20Sopenharmony_ci * Make sure the Copper has something to do 37218c2ecf20Sopenharmony_ci */ 37228c2ecf20Sopenharmony_ci ami_init_copper(); 37238c2ecf20Sopenharmony_ci 37248c2ecf20Sopenharmony_ci /* 37258c2ecf20Sopenharmony_ci * Enable Display DMA 37268c2ecf20Sopenharmony_ci */ 37278c2ecf20Sopenharmony_ci custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | 37288c2ecf20Sopenharmony_ci DMAF_BLITTER | DMAF_SPRITE; 37298c2ecf20Sopenharmony_ci 37308c2ecf20Sopenharmony_ci err = request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, 37318c2ecf20Sopenharmony_ci "fb vertb handler", info->par); 37328c2ecf20Sopenharmony_ci if (err) 37338c2ecf20Sopenharmony_ci goto disable_dma; 37348c2ecf20Sopenharmony_ci 37358c2ecf20Sopenharmony_ci err = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0); 37368c2ecf20Sopenharmony_ci if (err) 37378c2ecf20Sopenharmony_ci goto free_irq; 37388c2ecf20Sopenharmony_ci 37398c2ecf20Sopenharmony_ci dev_set_drvdata(&pdev->dev, info); 37408c2ecf20Sopenharmony_ci 37418c2ecf20Sopenharmony_ci err = register_framebuffer(info); 37428c2ecf20Sopenharmony_ci if (err) 37438c2ecf20Sopenharmony_ci goto unset_drvdata; 37448c2ecf20Sopenharmony_ci 37458c2ecf20Sopenharmony_ci fb_info(info, "%s frame buffer device, using %dK of video memory\n", 37468c2ecf20Sopenharmony_ci info->fix.id, info->fix.smem_len>>10); 37478c2ecf20Sopenharmony_ci 37488c2ecf20Sopenharmony_ci return 0; 37498c2ecf20Sopenharmony_ci 37508c2ecf20Sopenharmony_ciunset_drvdata: 37518c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 37528c2ecf20Sopenharmony_cifree_irq: 37538c2ecf20Sopenharmony_ci free_irq(IRQ_AMIGA_COPPER, info->par); 37548c2ecf20Sopenharmony_cidisable_dma: 37558c2ecf20Sopenharmony_ci custom.dmacon = DMAF_ALL | DMAF_MASTER; 37568c2ecf20Sopenharmony_ci if (videomemory) 37578c2ecf20Sopenharmony_ci iounmap((void *)videomemory); 37588c2ecf20Sopenharmony_ci chipfree(); 37598c2ecf20Sopenharmony_cirelease: 37608c2ecf20Sopenharmony_ci framebuffer_release(info); 37618c2ecf20Sopenharmony_ci return err; 37628c2ecf20Sopenharmony_ci} 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci 37658c2ecf20Sopenharmony_cistatic int __exit amifb_remove(struct platform_device *pdev) 37668c2ecf20Sopenharmony_ci{ 37678c2ecf20Sopenharmony_ci struct fb_info *info = dev_get_drvdata(&pdev->dev); 37688c2ecf20Sopenharmony_ci 37698c2ecf20Sopenharmony_ci unregister_framebuffer(info); 37708c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 37718c2ecf20Sopenharmony_ci free_irq(IRQ_AMIGA_COPPER, info->par); 37728c2ecf20Sopenharmony_ci custom.dmacon = DMAF_ALL | DMAF_MASTER; 37738c2ecf20Sopenharmony_ci if (videomemory) 37748c2ecf20Sopenharmony_ci iounmap((void *)videomemory); 37758c2ecf20Sopenharmony_ci chipfree(); 37768c2ecf20Sopenharmony_ci framebuffer_release(info); 37778c2ecf20Sopenharmony_ci amifb_video_off(); 37788c2ecf20Sopenharmony_ci return 0; 37798c2ecf20Sopenharmony_ci} 37808c2ecf20Sopenharmony_ci 37818c2ecf20Sopenharmony_cistatic struct platform_driver amifb_driver = { 37828c2ecf20Sopenharmony_ci .remove = __exit_p(amifb_remove), 37838c2ecf20Sopenharmony_ci .driver = { 37848c2ecf20Sopenharmony_ci .name = "amiga-video", 37858c2ecf20Sopenharmony_ci }, 37868c2ecf20Sopenharmony_ci}; 37878c2ecf20Sopenharmony_ci 37888c2ecf20Sopenharmony_cimodule_platform_driver_probe(amifb_driver, amifb_probe); 37898c2ecf20Sopenharmony_ci 37908c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 37918c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:amiga-video"); 3792