162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 1995-2003 Geert Uytterhoeven 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * with work by Roman Zippel 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This file is based on the Atari frame buffer device (atafb.c): 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Copyright (C) 1994 Martin Schaller 1262306a36Sopenharmony_ci * Roman Hodek 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * with work by Andreas Schwab 1562306a36Sopenharmony_ci * Guenther Kelleter 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * and on the original Amiga console driver (amicon.c): 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Copyright (C) 1993 Hamish Macdonald 2062306a36Sopenharmony_ci * Greg Harp 2162306a36Sopenharmony_ci * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * with work by William Rucklidge (wjr@cs.cornell.edu) 2462306a36Sopenharmony_ci * Geert Uytterhoeven 2562306a36Sopenharmony_ci * Jes Sorensen (jds@kom.auc.dk) 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * History: 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * - 24 Jul 96: Copper generates now vblank interrupt and 3162306a36Sopenharmony_ci * VESA Power Saving Protocol is fully implemented 3262306a36Sopenharmony_ci * - 14 Jul 96: Rework and hopefully last ECS bugs fixed 3362306a36Sopenharmony_ci * - 7 Mar 96: Hardware sprite support by Roman Zippel 3462306a36Sopenharmony_ci * - 18 Feb 96: OCS and ECS support by Roman Zippel 3562306a36Sopenharmony_ci * Hardware functions completely rewritten 3662306a36Sopenharmony_ci * - 2 Dec 95: AGA version by Geert Uytterhoeven 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 3962306a36Sopenharmony_ci * License. See the file COPYING in the main directory of this archive 4062306a36Sopenharmony_ci * for more details. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include <linux/module.h> 4462306a36Sopenharmony_ci#include <linux/kernel.h> 4562306a36Sopenharmony_ci#include <linux/errno.h> 4662306a36Sopenharmony_ci#include <linux/string.h> 4762306a36Sopenharmony_ci#include <linux/mm.h> 4862306a36Sopenharmony_ci#include <linux/delay.h> 4962306a36Sopenharmony_ci#include <linux/interrupt.h> 5062306a36Sopenharmony_ci#include <linux/fb.h> 5162306a36Sopenharmony_ci#include <linux/init.h> 5262306a36Sopenharmony_ci#include <linux/ioport.h> 5362306a36Sopenharmony_ci#include <linux/platform_device.h> 5462306a36Sopenharmony_ci#include <linux/uaccess.h> 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#include <asm/irq.h> 5762306a36Sopenharmony_ci#include <asm/amigahw.h> 5862306a36Sopenharmony_ci#include <asm/amigaints.h> 5962306a36Sopenharmony_ci#include <asm/setup.h> 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#include "c2p.h" 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define DEBUG 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#if !defined(CONFIG_FB_AMIGA_OCS) && !defined(CONFIG_FB_AMIGA_ECS) && !defined(CONFIG_FB_AMIGA_AGA) 6762306a36Sopenharmony_ci#define CONFIG_FB_AMIGA_OCS /* define at least one fb driver, this will change later */ 6862306a36Sopenharmony_ci#endif 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#if !defined(CONFIG_FB_AMIGA_OCS) 7162306a36Sopenharmony_ci# define IS_OCS (0) 7262306a36Sopenharmony_ci#elif defined(CONFIG_FB_AMIGA_ECS) || defined(CONFIG_FB_AMIGA_AGA) 7362306a36Sopenharmony_ci# define IS_OCS (chipset == TAG_OCS) 7462306a36Sopenharmony_ci#else 7562306a36Sopenharmony_ci# define CONFIG_FB_AMIGA_OCS_ONLY 7662306a36Sopenharmony_ci# define IS_OCS (1) 7762306a36Sopenharmony_ci#endif 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#if !defined(CONFIG_FB_AMIGA_ECS) 8062306a36Sopenharmony_ci# define IS_ECS (0) 8162306a36Sopenharmony_ci#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_AGA) 8262306a36Sopenharmony_ci# define IS_ECS (chipset == TAG_ECS) 8362306a36Sopenharmony_ci#else 8462306a36Sopenharmony_ci# define CONFIG_FB_AMIGA_ECS_ONLY 8562306a36Sopenharmony_ci# define IS_ECS (1) 8662306a36Sopenharmony_ci#endif 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#if !defined(CONFIG_FB_AMIGA_AGA) 8962306a36Sopenharmony_ci# define IS_AGA (0) 9062306a36Sopenharmony_ci#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_ECS) 9162306a36Sopenharmony_ci# define IS_AGA (chipset == TAG_AGA) 9262306a36Sopenharmony_ci#else 9362306a36Sopenharmony_ci# define CONFIG_FB_AMIGA_AGA_ONLY 9462306a36Sopenharmony_ci# define IS_AGA (1) 9562306a36Sopenharmony_ci#endif 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#ifdef DEBUG 9862306a36Sopenharmony_ci# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) 9962306a36Sopenharmony_ci#else 10062306a36Sopenharmony_ci# define DPRINTK(fmt, args...) 10162306a36Sopenharmony_ci#endif 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/******************************************************************************* 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci Generic video timings 10762306a36Sopenharmony_ci --------------------- 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci Timings used by the frame buffer interface: 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci +----------+---------------------------------------------+----------+-------+ 11262306a36Sopenharmony_ci | | ^ | | | 11362306a36Sopenharmony_ci | | |upper_margin | | | 11462306a36Sopenharmony_ci | | v | | | 11562306a36Sopenharmony_ci +----------###############################################----------+-------+ 11662306a36Sopenharmony_ci | # ^ # | | 11762306a36Sopenharmony_ci | # | # | | 11862306a36Sopenharmony_ci | # | # | | 11962306a36Sopenharmony_ci | # | # | | 12062306a36Sopenharmony_ci | left # | # right | hsync | 12162306a36Sopenharmony_ci | margin # | xres # margin | len | 12262306a36Sopenharmony_ci |<-------->#<---------------+--------------------------->#<-------->|<----->| 12362306a36Sopenharmony_ci | # | # | | 12462306a36Sopenharmony_ci | # | # | | 12562306a36Sopenharmony_ci | # | # | | 12662306a36Sopenharmony_ci | # |yres # | | 12762306a36Sopenharmony_ci | # | # | | 12862306a36Sopenharmony_ci | # | # | | 12962306a36Sopenharmony_ci | # | # | | 13062306a36Sopenharmony_ci | # | # | | 13162306a36Sopenharmony_ci | # | # | | 13262306a36Sopenharmony_ci | # | # | | 13362306a36Sopenharmony_ci | # | # | | 13462306a36Sopenharmony_ci | # | # | | 13562306a36Sopenharmony_ci | # v # | | 13662306a36Sopenharmony_ci +----------###############################################----------+-------+ 13762306a36Sopenharmony_ci | | ^ | | | 13862306a36Sopenharmony_ci | | |lower_margin | | | 13962306a36Sopenharmony_ci | | v | | | 14062306a36Sopenharmony_ci +----------+---------------------------------------------+----------+-------+ 14162306a36Sopenharmony_ci | | ^ | | | 14262306a36Sopenharmony_ci | | |vsync_len | | | 14362306a36Sopenharmony_ci | | v | | | 14462306a36Sopenharmony_ci +----------+---------------------------------------------+----------+-------+ 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci Amiga video timings 14862306a36Sopenharmony_ci ------------------- 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci The Amiga native chipsets uses another timing scheme: 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci - hsstrt: Start of horizontal synchronization pulse 15362306a36Sopenharmony_ci - hsstop: End of horizontal synchronization pulse 15462306a36Sopenharmony_ci - htotal: Last value on the line (i.e. line length = htotal + 1) 15562306a36Sopenharmony_ci - vsstrt: Start of vertical synchronization pulse 15662306a36Sopenharmony_ci - vsstop: End of vertical synchronization pulse 15762306a36Sopenharmony_ci - vtotal: Last line value (i.e. number of lines = vtotal + 1) 15862306a36Sopenharmony_ci - hcenter: Start of vertical retrace for interlace 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci You can specify the blanking timings independently. Currently I just set 16162306a36Sopenharmony_ci them equal to the respective synchronization values: 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci - hbstrt: Start of horizontal blank 16462306a36Sopenharmony_ci - hbstop: End of horizontal blank 16562306a36Sopenharmony_ci - vbstrt: Start of vertical blank 16662306a36Sopenharmony_ci - vbstop: End of vertical blank 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci Horizontal values are in color clock cycles (280 ns), vertical values are in 16962306a36Sopenharmony_ci scanlines. 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci (0, 0) is somewhere in the upper-left corner :-) 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci Amiga visible window definitions 17562306a36Sopenharmony_ci -------------------------------- 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to 17862306a36Sopenharmony_ci make corrections and/or additions. 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci Within the above synchronization specifications, the visible window is 18162306a36Sopenharmony_ci defined by the following parameters (actual register resolutions may be 18262306a36Sopenharmony_ci different; all horizontal values are normalized with respect to the pixel 18362306a36Sopenharmony_ci clock): 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci - diwstrt_h: Horizontal start of the visible window 18662306a36Sopenharmony_ci - diwstop_h: Horizontal stop + 1(*) of the visible window 18762306a36Sopenharmony_ci - diwstrt_v: Vertical start of the visible window 18862306a36Sopenharmony_ci - diwstop_v: Vertical stop of the visible window 18962306a36Sopenharmony_ci - ddfstrt: Horizontal start of display DMA 19062306a36Sopenharmony_ci - ddfstop: Horizontal stop of display DMA 19162306a36Sopenharmony_ci - hscroll: Horizontal display output delay 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci Sprite positioning: 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci - sprstrt_h: Horizontal start - 4 of sprite 19662306a36Sopenharmony_ci - sprstrt_v: Vertical start of sprite 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1. 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci Horizontal values are in dotclock cycles (35 ns), vertical values are in 20162306a36Sopenharmony_ci scanlines. 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci (0, 0) is somewhere in the upper-left corner :-) 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci Dependencies (AGA, SHRES (35 ns dotclock)) 20762306a36Sopenharmony_ci ------------------------------------------- 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci Since there are much more parameters for the Amiga display than for the 21062306a36Sopenharmony_ci frame buffer interface, there must be some dependencies among the Amiga 21162306a36Sopenharmony_ci display parameters. Here's what I found out: 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci - ddfstrt and ddfstop are best aligned to 64 pixels. 21462306a36Sopenharmony_ci - the chipset needs 64 + 4 horizontal pixels after the DMA start before 21562306a36Sopenharmony_ci the first pixel is output, so diwstrt_h = ddfstrt + 64 + 4 if you want 21662306a36Sopenharmony_ci to display the first pixel on the line too. Increase diwstrt_h for 21762306a36Sopenharmony_ci virtual screen panning. 21862306a36Sopenharmony_ci - the display DMA always fetches 64 pixels at a time (fmode = 3). 21962306a36Sopenharmony_ci - ddfstop is ddfstrt+#pixels - 64. 22062306a36Sopenharmony_ci - diwstop_h = diwstrt_h + xres + 1. Because of the additional 1 this can 22162306a36Sopenharmony_ci be 1 more than htotal. 22262306a36Sopenharmony_ci - hscroll simply adds a delay to the display output. Smooth horizontal 22362306a36Sopenharmony_ci panning needs an extra 64 pixels on the left to prefetch the pixels that 22462306a36Sopenharmony_ci `fall off' on the left. 22562306a36Sopenharmony_ci - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane 22662306a36Sopenharmony_ci DMA, so it's best to make the DMA start as late as possible. 22762306a36Sopenharmony_ci - you really don't want to make ddfstrt < 128, since this will steal DMA 22862306a36Sopenharmony_ci cycles from the other DMA channels (audio, floppy and Chip RAM refresh). 22962306a36Sopenharmony_ci - I make diwstop_h and diwstop_v as large as possible. 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci General dependencies 23262306a36Sopenharmony_ci -------------------- 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci - all values are SHRES pixel (35ns) 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci table 1:fetchstart table 2:prefetch table 3:fetchsize 23762306a36Sopenharmony_ci ------------------ ---------------- ----------------- 23862306a36Sopenharmony_ci Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES 23962306a36Sopenharmony_ci -------------#------+-----+------#------+-----+------#------+-----+------ 24062306a36Sopenharmony_ci Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64 24162306a36Sopenharmony_ci Bus width 2x # 32 | 64 | 128 # 32 | 64 | 64 # 64 | 64 | 128 24262306a36Sopenharmony_ci Bus width 4x # 64 | 128 | 256 # 64 | 64 | 64 # 64 | 128 | 256 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci - chipset needs 4 pixels before the first pixel is output 24562306a36Sopenharmony_ci - ddfstrt must be aligned to fetchstart (table 1) 24662306a36Sopenharmony_ci - chipset needs also prefetch (table 2) to get first pixel data, so 24762306a36Sopenharmony_ci ddfstrt = ((diwstrt_h - 4) & -fetchstart) - prefetch 24862306a36Sopenharmony_ci - for horizontal panning decrease diwstrt_h 24962306a36Sopenharmony_ci - the length of a fetchline must be aligned to fetchsize (table 3) 25062306a36Sopenharmony_ci - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit 25162306a36Sopenharmony_ci moved to optimize use of dma (useful for OCS/ECS overscan displays) 25262306a36Sopenharmony_ci - ddfstop is ddfstrt + ddfsize - fetchsize 25362306a36Sopenharmony_ci - If C= didn't change anything for AGA, then at following positions the 25462306a36Sopenharmony_ci dma bus is already used: 25562306a36Sopenharmony_ci ddfstrt < 48 -> memory refresh 25662306a36Sopenharmony_ci < 96 -> disk dma 25762306a36Sopenharmony_ci < 160 -> audio dma 25862306a36Sopenharmony_ci < 192 -> sprite 0 dma 25962306a36Sopenharmony_ci < 416 -> sprite dma (32 per sprite) 26062306a36Sopenharmony_ci - in accordance with the hardware reference manual a hardware stop is at 26162306a36Sopenharmony_ci 192, but AGA (ECS?) can go below this. 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci DMA priorities 26462306a36Sopenharmony_ci -------------- 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci Since there are limits on the earliest start value for display DMA and the 26762306a36Sopenharmony_ci display of sprites, I use the following policy on horizontal panning and 26862306a36Sopenharmony_ci the hardware cursor: 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci - if you want to start display DMA too early, you lose the ability to 27162306a36Sopenharmony_ci do smooth horizontal panning (xpanstep 1 -> 64). 27262306a36Sopenharmony_ci - if you want to go even further, you lose the hardware cursor too. 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci IMHO a hardware cursor is more important for X than horizontal scrolling, 27562306a36Sopenharmony_ci so that's my motivation. 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci Implementation 27962306a36Sopenharmony_ci -------------- 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ami_decode_var() converts the frame buffer values to the Amiga values. It's 28262306a36Sopenharmony_ci just a `straightforward' implementation of the above rules. 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci Standard VGA timings 28662306a36Sopenharmony_ci -------------------- 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci xres yres left right upper lower hsync vsync 28962306a36Sopenharmony_ci ---- ---- ---- ----- ----- ----- ----- ----- 29062306a36Sopenharmony_ci 80x25 720 400 27 45 35 12 108 2 29162306a36Sopenharmony_ci 80x30 720 480 27 45 30 9 108 2 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci These were taken from a XFree86 configuration file, recalculated for a 28 MHz 29462306a36Sopenharmony_ci dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer 29562306a36Sopenharmony_ci generic timings. 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci As a comparison, graphics/monitor.h suggests the following: 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci xres yres left right upper lower hsync vsync 30062306a36Sopenharmony_ci ---- ---- ---- ----- ----- ----- ----- ----- 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci VGA 640 480 52 112 24 19 112 - 2 + 30362306a36Sopenharmony_ci VGA70 640 400 52 112 27 21 112 - 2 - 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci Sync polarities 30762306a36Sopenharmony_ci --------------- 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci VSYNC HSYNC Vertical size Vertical total 31062306a36Sopenharmony_ci ----- ----- ------------- -------------- 31162306a36Sopenharmony_ci + + Reserved Reserved 31262306a36Sopenharmony_ci + - 400 414 31362306a36Sopenharmony_ci - + 350 362 31462306a36Sopenharmony_ci - - 480 496 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci Broadcast video timings 32062306a36Sopenharmony_ci ----------------------- 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci According to the CCIR and RETMA specifications, we have the following values: 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci CCIR -> PAL 32562306a36Sopenharmony_ci ----------- 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci - a scanline is 64 µs long, of which 52.48 µs are visible. This is about 32862306a36Sopenharmony_ci 736 visible 70 ns pixels per line. 32962306a36Sopenharmony_ci - we have 625 scanlines, of which 575 are visible (interlaced); after 33062306a36Sopenharmony_ci rounding this becomes 576. 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci RETMA -> NTSC 33362306a36Sopenharmony_ci ------------- 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about 33662306a36Sopenharmony_ci 736 visible 70 ns pixels per line. 33762306a36Sopenharmony_ci - we have 525 scanlines, of which 485 are visible (interlaced); after 33862306a36Sopenharmony_ci rounding this becomes 484. 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci Thus if you want a PAL compatible display, you have to do the following: 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast 34362306a36Sopenharmony_ci timings are to be used. 34462306a36Sopenharmony_ci - make sure upper_margin + yres + lower_margin + vsync_len = 625 for an 34562306a36Sopenharmony_ci interlaced, 312 for a non-interlaced and 156 for a doublescanned 34662306a36Sopenharmony_ci display. 34762306a36Sopenharmony_ci - make sure left_margin + xres + right_margin + hsync_len = 1816 for a 34862306a36Sopenharmony_ci SHRES, 908 for a HIRES and 454 for a LORES display. 34962306a36Sopenharmony_ci - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90), 35062306a36Sopenharmony_ci left_margin + 2 * hsync_len must be greater or equal. 35162306a36Sopenharmony_ci - the upper visible part begins at 48 (interlaced; non-interlaced:24, 35262306a36Sopenharmony_ci doublescanned:12), upper_margin + 2 * vsync_len must be greater or 35362306a36Sopenharmony_ci equal. 35462306a36Sopenharmony_ci - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync 35562306a36Sopenharmony_ci of 4 scanlines 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci The settings for a NTSC compatible display are straightforward. 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci Note that in a strict sense the PAL and NTSC standards only define the 36062306a36Sopenharmony_ci encoding of the color part (chrominance) of the video signal and don't say 36162306a36Sopenharmony_ci anything about horizontal/vertical synchronization nor refresh rates. 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci -- Geert -- 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci*******************************************************************************/ 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* 37062306a36Sopenharmony_ci * Custom Chipset Definitions 37162306a36Sopenharmony_ci */ 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci#define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld) 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* 37662306a36Sopenharmony_ci * BPLCON0 -- Bitplane Control Register 0 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci#define BPC0_HIRES (0x8000) 38062306a36Sopenharmony_ci#define BPC0_BPU2 (0x4000) /* Bit plane used count */ 38162306a36Sopenharmony_ci#define BPC0_BPU1 (0x2000) 38262306a36Sopenharmony_ci#define BPC0_BPU0 (0x1000) 38362306a36Sopenharmony_ci#define BPC0_HAM (0x0800) /* HAM mode */ 38462306a36Sopenharmony_ci#define BPC0_DPF (0x0400) /* Double playfield */ 38562306a36Sopenharmony_ci#define BPC0_COLOR (0x0200) /* Enable colorburst */ 38662306a36Sopenharmony_ci#define BPC0_GAUD (0x0100) /* Genlock audio enable */ 38762306a36Sopenharmony_ci#define BPC0_UHRES (0x0080) /* Ultrahi res enable */ 38862306a36Sopenharmony_ci#define BPC0_SHRES (0x0040) /* Super hi res mode */ 38962306a36Sopenharmony_ci#define BPC0_BYPASS (0x0020) /* Bypass LUT - AGA */ 39062306a36Sopenharmony_ci#define BPC0_BPU3 (0x0010) /* AGA */ 39162306a36Sopenharmony_ci#define BPC0_LPEN (0x0008) /* Light pen enable */ 39262306a36Sopenharmony_ci#define BPC0_LACE (0x0004) /* Interlace */ 39362306a36Sopenharmony_ci#define BPC0_ERSY (0x0002) /* External resync */ 39462306a36Sopenharmony_ci#define BPC0_ECSENA (0x0001) /* ECS enable */ 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * BPLCON2 -- Bitplane Control Register 2 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci#define BPC2_ZDBPSEL2 (0x4000) /* Bitplane to be used for ZD - AGA */ 40162306a36Sopenharmony_ci#define BPC2_ZDBPSEL1 (0x2000) 40262306a36Sopenharmony_ci#define BPC2_ZDBPSEL0 (0x1000) 40362306a36Sopenharmony_ci#define BPC2_ZDBPEN (0x0800) /* Enable ZD with ZDBPSELx - AGA */ 40462306a36Sopenharmony_ci#define BPC2_ZDCTEN (0x0400) /* Enable ZD with palette bit #31 - AGA */ 40562306a36Sopenharmony_ci#define BPC2_KILLEHB (0x0200) /* Kill EHB mode - AGA */ 40662306a36Sopenharmony_ci#define BPC2_RDRAM (0x0100) /* Color table accesses read, not write - AGA */ 40762306a36Sopenharmony_ci#define BPC2_SOGEN (0x0080) /* SOG output pin high - AGA */ 40862306a36Sopenharmony_ci#define BPC2_PF2PRI (0x0040) /* PF2 priority over PF1 */ 40962306a36Sopenharmony_ci#define BPC2_PF2P2 (0x0020) /* PF2 priority wrt sprites */ 41062306a36Sopenharmony_ci#define BPC2_PF2P1 (0x0010) 41162306a36Sopenharmony_ci#define BPC2_PF2P0 (0x0008) 41262306a36Sopenharmony_ci#define BPC2_PF1P2 (0x0004) /* ditto PF1 */ 41362306a36Sopenharmony_ci#define BPC2_PF1P1 (0x0002) 41462306a36Sopenharmony_ci#define BPC2_PF1P0 (0x0001) 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* 41762306a36Sopenharmony_ci * BPLCON3 -- Bitplane Control Register 3 (AGA) 41862306a36Sopenharmony_ci */ 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci#define BPC3_BANK2 (0x8000) /* Bits to select color register bank */ 42162306a36Sopenharmony_ci#define BPC3_BANK1 (0x4000) 42262306a36Sopenharmony_ci#define BPC3_BANK0 (0x2000) 42362306a36Sopenharmony_ci#define BPC3_PF2OF2 (0x1000) /* Bits for color table offset when PF2 */ 42462306a36Sopenharmony_ci#define BPC3_PF2OF1 (0x0800) 42562306a36Sopenharmony_ci#define BPC3_PF2OF0 (0x0400) 42662306a36Sopenharmony_ci#define BPC3_LOCT (0x0200) /* Color register writes go to low bits */ 42762306a36Sopenharmony_ci#define BPC3_SPRES1 (0x0080) /* Sprite resolution bits */ 42862306a36Sopenharmony_ci#define BPC3_SPRES0 (0x0040) 42962306a36Sopenharmony_ci#define BPC3_BRDRBLNK (0x0020) /* Border blanked? */ 43062306a36Sopenharmony_ci#define BPC3_BRDRTRAN (0x0010) /* Border transparent? */ 43162306a36Sopenharmony_ci#define BPC3_ZDCLKEN (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */ 43262306a36Sopenharmony_ci#define BPC3_BRDRSPRT (0x0002) /* Sprites in border? */ 43362306a36Sopenharmony_ci#define BPC3_EXTBLKEN (0x0001) /* BLANK programmable */ 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* 43662306a36Sopenharmony_ci * BPLCON4 -- Bitplane Control Register 4 (AGA) 43762306a36Sopenharmony_ci */ 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci#define BPC4_BPLAM7 (0x8000) /* bitplane color XOR field */ 44062306a36Sopenharmony_ci#define BPC4_BPLAM6 (0x4000) 44162306a36Sopenharmony_ci#define BPC4_BPLAM5 (0x2000) 44262306a36Sopenharmony_ci#define BPC4_BPLAM4 (0x1000) 44362306a36Sopenharmony_ci#define BPC4_BPLAM3 (0x0800) 44462306a36Sopenharmony_ci#define BPC4_BPLAM2 (0x0400) 44562306a36Sopenharmony_ci#define BPC4_BPLAM1 (0x0200) 44662306a36Sopenharmony_ci#define BPC4_BPLAM0 (0x0100) 44762306a36Sopenharmony_ci#define BPC4_ESPRM7 (0x0080) /* 4 high bits for even sprite colors */ 44862306a36Sopenharmony_ci#define BPC4_ESPRM6 (0x0040) 44962306a36Sopenharmony_ci#define BPC4_ESPRM5 (0x0020) 45062306a36Sopenharmony_ci#define BPC4_ESPRM4 (0x0010) 45162306a36Sopenharmony_ci#define BPC4_OSPRM7 (0x0008) /* 4 high bits for odd sprite colors */ 45262306a36Sopenharmony_ci#define BPC4_OSPRM6 (0x0004) 45362306a36Sopenharmony_ci#define BPC4_OSPRM5 (0x0002) 45462306a36Sopenharmony_ci#define BPC4_OSPRM4 (0x0001) 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* 45762306a36Sopenharmony_ci * BEAMCON0 -- Beam Control Register 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci#define BMC0_HARDDIS (0x4000) /* Disable hardware limits */ 46162306a36Sopenharmony_ci#define BMC0_LPENDIS (0x2000) /* Disable light pen latch */ 46262306a36Sopenharmony_ci#define BMC0_VARVBEN (0x1000) /* Enable variable vertical blank */ 46362306a36Sopenharmony_ci#define BMC0_LOLDIS (0x0800) /* Disable long/short line toggle */ 46462306a36Sopenharmony_ci#define BMC0_CSCBEN (0x0400) /* Composite sync/blank */ 46562306a36Sopenharmony_ci#define BMC0_VARVSYEN (0x0200) /* Enable variable vertical sync */ 46662306a36Sopenharmony_ci#define BMC0_VARHSYEN (0x0100) /* Enable variable horizontal sync */ 46762306a36Sopenharmony_ci#define BMC0_VARBEAMEN (0x0080) /* Enable variable beam counters */ 46862306a36Sopenharmony_ci#define BMC0_DUAL (0x0040) /* Enable alternate horizontal beam counter */ 46962306a36Sopenharmony_ci#define BMC0_PAL (0x0020) /* Set decodes for PAL */ 47062306a36Sopenharmony_ci#define BMC0_VARCSYEN (0x0010) /* Enable variable composite sync */ 47162306a36Sopenharmony_ci#define BMC0_BLANKEN (0x0008) /* Blank enable (no longer used on AGA) */ 47262306a36Sopenharmony_ci#define BMC0_CSYTRUE (0x0004) /* CSY polarity */ 47362306a36Sopenharmony_ci#define BMC0_VSYTRUE (0x0002) /* VSY polarity */ 47462306a36Sopenharmony_ci#define BMC0_HSYTRUE (0x0001) /* HSY polarity */ 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* 47862306a36Sopenharmony_ci * FMODE -- Fetch Mode Control Register (AGA) 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci#define FMODE_SSCAN2 (0x8000) /* Sprite scan-doubling */ 48262306a36Sopenharmony_ci#define FMODE_BSCAN2 (0x4000) /* Use PF2 modulus every other line */ 48362306a36Sopenharmony_ci#define FMODE_SPAGEM (0x0008) /* Sprite page mode */ 48462306a36Sopenharmony_ci#define FMODE_SPR32 (0x0004) /* Sprite 32 bit fetch */ 48562306a36Sopenharmony_ci#define FMODE_BPAGEM (0x0002) /* Bitplane page mode */ 48662306a36Sopenharmony_ci#define FMODE_BPL32 (0x0001) /* Bitplane 32 bit fetch */ 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* 48962306a36Sopenharmony_ci * Tags used to indicate a specific Pixel Clock 49062306a36Sopenharmony_ci * 49162306a36Sopenharmony_ci * clk_shift is the shift value to get the timings in 35 ns units 49262306a36Sopenharmony_ci */ 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cienum { TAG_SHRES, TAG_HIRES, TAG_LORES }; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* 49762306a36Sopenharmony_ci * Tags used to indicate the specific chipset 49862306a36Sopenharmony_ci */ 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cienum { TAG_OCS, TAG_ECS, TAG_AGA }; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* 50362306a36Sopenharmony_ci * Tags used to indicate the memory bandwidth 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cienum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 }; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* 51062306a36Sopenharmony_ci * Clock Definitions, Maximum Display Depth 51162306a36Sopenharmony_ci * 51262306a36Sopenharmony_ci * These depend on the E-Clock or the Chipset, so they are filled in 51362306a36Sopenharmony_ci * dynamically 51462306a36Sopenharmony_ci */ 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic u_long pixclock[3]; /* SHRES/HIRES/LORES: index = clk_shift */ 51762306a36Sopenharmony_cistatic u_short maxdepth[3]; /* SHRES/HIRES/LORES: index = clk_shift */ 51862306a36Sopenharmony_cistatic u_short maxfmode, chipset; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* 52262306a36Sopenharmony_ci * Broadcast Video Timings 52362306a36Sopenharmony_ci * 52462306a36Sopenharmony_ci * Horizontal values are in 35 ns (SHRES) units 52562306a36Sopenharmony_ci * Vertical values are in interlaced scanlines 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci#define PAL_DIWSTRT_H (360) /* PAL Window Limits */ 52962306a36Sopenharmony_ci#define PAL_DIWSTRT_V (48) 53062306a36Sopenharmony_ci#define PAL_HTOTAL (1816) 53162306a36Sopenharmony_ci#define PAL_VTOTAL (625) 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci#define NTSC_DIWSTRT_H (360) /* NTSC Window Limits */ 53462306a36Sopenharmony_ci#define NTSC_DIWSTRT_V (40) 53562306a36Sopenharmony_ci#define NTSC_HTOTAL (1816) 53662306a36Sopenharmony_ci#define NTSC_VTOTAL (525) 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* 54062306a36Sopenharmony_ci * Various macros 54162306a36Sopenharmony_ci */ 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci#define up2(v) (((v) + 1) & -2) 54462306a36Sopenharmony_ci#define down2(v) ((v) & -2) 54562306a36Sopenharmony_ci#define div2(v) ((v)>>1) 54662306a36Sopenharmony_ci#define mod2(v) ((v) & 1) 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci#define up4(v) (((v) + 3) & -4) 54962306a36Sopenharmony_ci#define down4(v) ((v) & -4) 55062306a36Sopenharmony_ci#define mul4(v) ((v) << 2) 55162306a36Sopenharmony_ci#define div4(v) ((v)>>2) 55262306a36Sopenharmony_ci#define mod4(v) ((v) & 3) 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci#define up8(v) (((v) + 7) & -8) 55562306a36Sopenharmony_ci#define down8(v) ((v) & -8) 55662306a36Sopenharmony_ci#define div8(v) ((v)>>3) 55762306a36Sopenharmony_ci#define mod8(v) ((v) & 7) 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci#define up16(v) (((v) + 15) & -16) 56062306a36Sopenharmony_ci#define down16(v) ((v) & -16) 56162306a36Sopenharmony_ci#define div16(v) ((v)>>4) 56262306a36Sopenharmony_ci#define mod16(v) ((v) & 15) 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci#define up32(v) (((v) + 31) & -32) 56562306a36Sopenharmony_ci#define down32(v) ((v) & -32) 56662306a36Sopenharmony_ci#define div32(v) ((v)>>5) 56762306a36Sopenharmony_ci#define mod32(v) ((v) & 31) 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci#define up64(v) (((v) + 63) & -64) 57062306a36Sopenharmony_ci#define down64(v) ((v) & -64) 57162306a36Sopenharmony_ci#define div64(v) ((v)>>6) 57262306a36Sopenharmony_ci#define mod64(v) ((v) & 63) 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci#define upx(x, v) (((v) + (x) - 1) & -(x)) 57562306a36Sopenharmony_ci#define downx(x, v) ((v) & -(x)) 57662306a36Sopenharmony_ci#define modx(x, v) ((v) & ((x) - 1)) 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci/* 57962306a36Sopenharmony_ci * FIXME: Use C variants of the code marked with #ifdef __mc68000__ 58062306a36Sopenharmony_ci * in the driver. It shouldn't negatively affect the performance and 58162306a36Sopenharmony_ci * is required for APUS support (once it is re-added to the kernel). 58262306a36Sopenharmony_ci * Needs to be tested on the hardware though.. 58362306a36Sopenharmony_ci */ 58462306a36Sopenharmony_ci/* if x1 is not a constant, this macro won't make real sense :-) */ 58562306a36Sopenharmony_ci#ifdef __mc68000__ 58662306a36Sopenharmony_ci#define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \ 58762306a36Sopenharmony_ci "d" (x2), "d" ((long)((x1) / 0x100000000ULL)), "0" ((long)(x1))); res;}) 58862306a36Sopenharmony_ci#else 58962306a36Sopenharmony_ci/* We know a bit about the numbers, so we can do it this way */ 59062306a36Sopenharmony_ci#define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \ 59162306a36Sopenharmony_ci ((((long)((unsigned long long)x1 >> 8) % x2) << 8) / x2)) 59262306a36Sopenharmony_ci#endif 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci#define highw(x) ((u_long)(x)>>16 & 0xffff) 59562306a36Sopenharmony_ci#define loww(x) ((u_long)(x) & 0xffff) 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci#define custom amiga_custom 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci#define VBlankOn() custom.intena = IF_SETCLR|IF_COPER 60062306a36Sopenharmony_ci#define VBlankOff() custom.intena = IF_COPER 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* 60462306a36Sopenharmony_ci * Chip RAM we reserve for the Frame Buffer 60562306a36Sopenharmony_ci * 60662306a36Sopenharmony_ci * This defines the Maximum Virtual Screen Size 60762306a36Sopenharmony_ci * (Setable per kernel options?) 60862306a36Sopenharmony_ci */ 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci#define VIDEOMEMSIZE_AGA_2M (1310720) /* AGA (2MB) : max 1280*1024*256 */ 61162306a36Sopenharmony_ci#define VIDEOMEMSIZE_AGA_1M (786432) /* AGA (1MB) : max 1024*768*256 */ 61262306a36Sopenharmony_ci#define VIDEOMEMSIZE_ECS_2M (655360) /* ECS (2MB) : max 1280*1024*16 */ 61362306a36Sopenharmony_ci#define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */ 61462306a36Sopenharmony_ci#define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */ 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci#define SPRITEMEMSIZE (64 * 64 / 4) /* max 64*64*4 */ 61762306a36Sopenharmony_ci#define DUMMYSPRITEMEMSIZE (8) 61862306a36Sopenharmony_cistatic u_long spritememory; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci#define CHIPRAM_SAFETY_LIMIT (16384) 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic u_long videomemory; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* 62562306a36Sopenharmony_ci * This is the earliest allowed start of fetching display data. 62662306a36Sopenharmony_ci * Only if you really want no hardware cursor and audio, 62762306a36Sopenharmony_ci * set this to 128, but let it better at 192 62862306a36Sopenharmony_ci */ 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_cistatic u_long min_fstrt = 192; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci#define assignchunk(name, type, ptr, size) \ 63362306a36Sopenharmony_ci{ \ 63462306a36Sopenharmony_ci (name) = (type)(ptr); \ 63562306a36Sopenharmony_ci ptr += size; \ 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci /* 64062306a36Sopenharmony_ci * Copper Instructions 64162306a36Sopenharmony_ci */ 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci#define CMOVE(val, reg) (CUSTOM_OFS(reg) << 16 | (val)) 64462306a36Sopenharmony_ci#define CMOVE2(val, reg) ((CUSTOM_OFS(reg) + 2) << 16 | (val)) 64562306a36Sopenharmony_ci#define CWAIT(x, y) (((y) & 0x1fe) << 23 | ((x) & 0x7f0) << 13 | 0x0001fffe) 64662306a36Sopenharmony_ci#define CEND (0xfffffffe) 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_citypedef union { 65062306a36Sopenharmony_ci u_long l; 65162306a36Sopenharmony_ci u_short w[2]; 65262306a36Sopenharmony_ci} copins; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic struct copdisplay { 65562306a36Sopenharmony_ci copins *init; 65662306a36Sopenharmony_ci copins *wait; 65762306a36Sopenharmony_ci copins *list[2][2]; 65862306a36Sopenharmony_ci copins *rebuild[2]; 65962306a36Sopenharmony_ci} copdisplay; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic u_short currentcop = 0; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* 66462306a36Sopenharmony_ci * Hardware Cursor API Definitions 66562306a36Sopenharmony_ci * These used to be in linux/fb.h, but were preliminary and used by 66662306a36Sopenharmony_ci * amifb only anyway 66762306a36Sopenharmony_ci */ 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci#define FBIOGET_FCURSORINFO 0x4607 67062306a36Sopenharmony_ci#define FBIOGET_VCURSORINFO 0x4608 67162306a36Sopenharmony_ci#define FBIOPUT_VCURSORINFO 0x4609 67262306a36Sopenharmony_ci#define FBIOGET_CURSORSTATE 0x460A 67362306a36Sopenharmony_ci#define FBIOPUT_CURSORSTATE 0x460B 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistruct fb_fix_cursorinfo { 67762306a36Sopenharmony_ci __u16 crsr_width; /* width and height of the cursor in */ 67862306a36Sopenharmony_ci __u16 crsr_height; /* pixels (zero if no cursor) */ 67962306a36Sopenharmony_ci __u16 crsr_xsize; /* cursor size in display pixels */ 68062306a36Sopenharmony_ci __u16 crsr_ysize; 68162306a36Sopenharmony_ci __u16 crsr_color1; /* colormap entry for cursor color1 */ 68262306a36Sopenharmony_ci __u16 crsr_color2; /* colormap entry for cursor color2 */ 68362306a36Sopenharmony_ci}; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistruct fb_var_cursorinfo { 68662306a36Sopenharmony_ci __u16 width; 68762306a36Sopenharmony_ci __u16 height; 68862306a36Sopenharmony_ci __u16 xspot; 68962306a36Sopenharmony_ci __u16 yspot; 69062306a36Sopenharmony_ci DECLARE_FLEX_ARRAY(__u8, data); /* field with [height][width] */ 69162306a36Sopenharmony_ci}; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistruct fb_cursorstate { 69462306a36Sopenharmony_ci __s16 xoffset; 69562306a36Sopenharmony_ci __s16 yoffset; 69662306a36Sopenharmony_ci __u16 mode; 69762306a36Sopenharmony_ci}; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci#define FB_CURSOR_OFF 0 70062306a36Sopenharmony_ci#define FB_CURSOR_ON 1 70162306a36Sopenharmony_ci#define FB_CURSOR_FLASH 2 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci /* 70562306a36Sopenharmony_ci * Hardware Cursor 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic int cursorrate = 20; /* Number of frames/flash toggle */ 70962306a36Sopenharmony_cistatic u_short cursorstate = -1; 71062306a36Sopenharmony_cistatic u_short cursormode = FB_CURSOR_OFF; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic u_short *lofsprite, *shfsprite, *dummysprite; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci /* 71562306a36Sopenharmony_ci * Current Video Mode 71662306a36Sopenharmony_ci */ 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistruct amifb_par { 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* General Values */ 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci int xres; /* vmode */ 72362306a36Sopenharmony_ci int yres; /* vmode */ 72462306a36Sopenharmony_ci int vxres; /* vmode */ 72562306a36Sopenharmony_ci int vyres; /* vmode */ 72662306a36Sopenharmony_ci int xoffset; /* vmode */ 72762306a36Sopenharmony_ci int yoffset; /* vmode */ 72862306a36Sopenharmony_ci u_short bpp; /* vmode */ 72962306a36Sopenharmony_ci u_short clk_shift; /* vmode */ 73062306a36Sopenharmony_ci u_short line_shift; /* vmode */ 73162306a36Sopenharmony_ci int vmode; /* vmode */ 73262306a36Sopenharmony_ci u_short diwstrt_h; /* vmode */ 73362306a36Sopenharmony_ci u_short diwstop_h; /* vmode */ 73462306a36Sopenharmony_ci u_short diwstrt_v; /* vmode */ 73562306a36Sopenharmony_ci u_short diwstop_v; /* vmode */ 73662306a36Sopenharmony_ci u_long next_line; /* modulo for next line */ 73762306a36Sopenharmony_ci u_long next_plane; /* modulo for next plane */ 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* Cursor Values */ 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci struct { 74262306a36Sopenharmony_ci short crsr_x; /* movecursor */ 74362306a36Sopenharmony_ci short crsr_y; /* movecursor */ 74462306a36Sopenharmony_ci short spot_x; 74562306a36Sopenharmony_ci short spot_y; 74662306a36Sopenharmony_ci u_short height; 74762306a36Sopenharmony_ci u_short width; 74862306a36Sopenharmony_ci u_short fmode; 74962306a36Sopenharmony_ci } crsr; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* OCS Hardware Registers */ 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci u_long bplpt0; /* vmode, pan (Note: physical address) */ 75462306a36Sopenharmony_ci u_long bplpt0wrap; /* vmode, pan (Note: physical address) */ 75562306a36Sopenharmony_ci u_short ddfstrt; 75662306a36Sopenharmony_ci u_short ddfstop; 75762306a36Sopenharmony_ci u_short bpl1mod; 75862306a36Sopenharmony_ci u_short bpl2mod; 75962306a36Sopenharmony_ci u_short bplcon0; /* vmode */ 76062306a36Sopenharmony_ci u_short bplcon1; /* vmode */ 76162306a36Sopenharmony_ci u_short htotal; /* vmode */ 76262306a36Sopenharmony_ci u_short vtotal; /* vmode */ 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci /* Additional ECS Hardware Registers */ 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci u_short bplcon3; /* vmode */ 76762306a36Sopenharmony_ci u_short beamcon0; /* vmode */ 76862306a36Sopenharmony_ci u_short hsstrt; /* vmode */ 76962306a36Sopenharmony_ci u_short hsstop; /* vmode */ 77062306a36Sopenharmony_ci u_short hbstrt; /* vmode */ 77162306a36Sopenharmony_ci u_short hbstop; /* vmode */ 77262306a36Sopenharmony_ci u_short vsstrt; /* vmode */ 77362306a36Sopenharmony_ci u_short vsstop; /* vmode */ 77462306a36Sopenharmony_ci u_short vbstrt; /* vmode */ 77562306a36Sopenharmony_ci u_short vbstop; /* vmode */ 77662306a36Sopenharmony_ci u_short hcenter; /* vmode */ 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci /* Additional AGA Hardware Registers */ 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci u_short fmode; /* vmode */ 78162306a36Sopenharmony_ci}; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci /* 78562306a36Sopenharmony_ci * Saved color entry 0 so we can restore it when unblanking 78662306a36Sopenharmony_ci */ 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic u_char red0, green0, blue0; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci#if defined(CONFIG_FB_AMIGA_ECS) 79262306a36Sopenharmony_cistatic u_short ecs_palette[32]; 79362306a36Sopenharmony_ci#endif 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci /* 79762306a36Sopenharmony_ci * Latches for Display Changes during VBlank 79862306a36Sopenharmony_ci */ 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_cistatic u_short do_vmode_full = 0; /* Change the Video Mode */ 80162306a36Sopenharmony_cistatic u_short do_vmode_pan = 0; /* Update the Video Mode */ 80262306a36Sopenharmony_cistatic short do_blank = 0; /* (Un)Blank the Screen (±1) */ 80362306a36Sopenharmony_cistatic u_short do_cursor = 0; /* Move the Cursor */ 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci /* 80762306a36Sopenharmony_ci * Various Flags 80862306a36Sopenharmony_ci */ 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_cistatic u_short is_blanked = 0; /* Screen is Blanked */ 81162306a36Sopenharmony_cistatic u_short is_lace = 0; /* Screen is laced */ 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci /* 81462306a36Sopenharmony_ci * Predefined Video Modes 81562306a36Sopenharmony_ci * 81662306a36Sopenharmony_ci */ 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic struct fb_videomode ami_modedb[] __initdata = { 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci /* 82162306a36Sopenharmony_ci * AmigaOS Video Modes 82262306a36Sopenharmony_ci * 82362306a36Sopenharmony_ci * If you change these, make sure to update DEFMODE_* as well! 82462306a36Sopenharmony_ci */ 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci { 82762306a36Sopenharmony_ci /* 640x200, 15 kHz, 60 Hz (NTSC) */ 82862306a36Sopenharmony_ci "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2, 82962306a36Sopenharmony_ci FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 83062306a36Sopenharmony_ci }, { 83162306a36Sopenharmony_ci /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ 83262306a36Sopenharmony_ci "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4, 83362306a36Sopenharmony_ci FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 83462306a36Sopenharmony_ci }, { 83562306a36Sopenharmony_ci /* 640x256, 15 kHz, 50 Hz (PAL) */ 83662306a36Sopenharmony_ci "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2, 83762306a36Sopenharmony_ci FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 83862306a36Sopenharmony_ci }, { 83962306a36Sopenharmony_ci /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */ 84062306a36Sopenharmony_ci "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4, 84162306a36Sopenharmony_ci FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 84262306a36Sopenharmony_ci }, { 84362306a36Sopenharmony_ci /* 640x480, 29 kHz, 57 Hz */ 84462306a36Sopenharmony_ci "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8, 84562306a36Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 84662306a36Sopenharmony_ci }, { 84762306a36Sopenharmony_ci /* 640x960, 29 kHz, 57 Hz interlaced */ 84862306a36Sopenharmony_ci "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, 84962306a36Sopenharmony_ci 16, 85062306a36Sopenharmony_ci 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 85162306a36Sopenharmony_ci }, { 85262306a36Sopenharmony_ci /* 640x200, 15 kHz, 72 Hz */ 85362306a36Sopenharmony_ci "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5, 85462306a36Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 85562306a36Sopenharmony_ci }, { 85662306a36Sopenharmony_ci /* 640x400, 15 kHz, 72 Hz interlaced */ 85762306a36Sopenharmony_ci "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, 85862306a36Sopenharmony_ci 10, 85962306a36Sopenharmony_ci 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 86062306a36Sopenharmony_ci }, { 86162306a36Sopenharmony_ci /* 640x400, 29 kHz, 68 Hz */ 86262306a36Sopenharmony_ci "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8, 86362306a36Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 86462306a36Sopenharmony_ci }, { 86562306a36Sopenharmony_ci /* 640x800, 29 kHz, 68 Hz interlaced */ 86662306a36Sopenharmony_ci "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, 86762306a36Sopenharmony_ci 16, 86862306a36Sopenharmony_ci 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 86962306a36Sopenharmony_ci }, { 87062306a36Sopenharmony_ci /* 800x300, 23 kHz, 70 Hz */ 87162306a36Sopenharmony_ci "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7, 87262306a36Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 87362306a36Sopenharmony_ci }, { 87462306a36Sopenharmony_ci /* 800x600, 23 kHz, 70 Hz interlaced */ 87562306a36Sopenharmony_ci "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, 87662306a36Sopenharmony_ci 14, 87762306a36Sopenharmony_ci 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 87862306a36Sopenharmony_ci }, { 87962306a36Sopenharmony_ci /* 640x200, 27 kHz, 57 Hz doublescan */ 88062306a36Sopenharmony_ci "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4, 88162306a36Sopenharmony_ci 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP 88262306a36Sopenharmony_ci }, { 88362306a36Sopenharmony_ci /* 640x400, 27 kHz, 57 Hz */ 88462306a36Sopenharmony_ci "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7, 88562306a36Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 88662306a36Sopenharmony_ci }, { 88762306a36Sopenharmony_ci /* 640x800, 27 kHz, 57 Hz interlaced */ 88862306a36Sopenharmony_ci "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, 88962306a36Sopenharmony_ci 14, 89062306a36Sopenharmony_ci 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 89162306a36Sopenharmony_ci }, { 89262306a36Sopenharmony_ci /* 640x256, 27 kHz, 47 Hz doublescan */ 89362306a36Sopenharmony_ci "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4, 89462306a36Sopenharmony_ci 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP 89562306a36Sopenharmony_ci }, { 89662306a36Sopenharmony_ci /* 640x512, 27 kHz, 47 Hz */ 89762306a36Sopenharmony_ci "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7, 89862306a36Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 89962306a36Sopenharmony_ci }, { 90062306a36Sopenharmony_ci /* 640x1024, 27 kHz, 47 Hz interlaced */ 90162306a36Sopenharmony_ci "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, 90262306a36Sopenharmony_ci 14, 90362306a36Sopenharmony_ci 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP 90462306a36Sopenharmony_ci }, 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci /* 90762306a36Sopenharmony_ci * VGA Video Modes 90862306a36Sopenharmony_ci */ 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci { 91162306a36Sopenharmony_ci /* 640x480, 31 kHz, 60 Hz (VGA) */ 91262306a36Sopenharmony_ci "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2, 91362306a36Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 91462306a36Sopenharmony_ci }, { 91562306a36Sopenharmony_ci /* 640x400, 31 kHz, 70 Hz (VGA) */ 91662306a36Sopenharmony_ci "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2, 91762306a36Sopenharmony_ci FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, 91862306a36Sopenharmony_ci FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 91962306a36Sopenharmony_ci }, 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci#if 0 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci /* 92462306a36Sopenharmony_ci * A2024 video modes 92562306a36Sopenharmony_ci * These modes don't work yet because there's no A2024 driver. 92662306a36Sopenharmony_ci */ 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci { 92962306a36Sopenharmony_ci /* 1024x800, 10 Hz */ 93062306a36Sopenharmony_ci "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, 93162306a36Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 93262306a36Sopenharmony_ci }, { 93362306a36Sopenharmony_ci /* 1024x800, 15 Hz */ 93462306a36Sopenharmony_ci "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, 93562306a36Sopenharmony_ci 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci#endif 93862306a36Sopenharmony_ci}; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci#define NUM_TOTAL_MODES ARRAY_SIZE(ami_modedb) 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_cistatic char *mode_option __initdata = NULL; 94362306a36Sopenharmony_cistatic int round_down_bpp = 1; /* for mode probing */ 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* 94662306a36Sopenharmony_ci * Some default modes 94762306a36Sopenharmony_ci */ 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci#define DEFMODE_PAL 2 /* "pal" for PAL OCS/ECS */ 95162306a36Sopenharmony_ci#define DEFMODE_NTSC 0 /* "ntsc" for NTSC OCS/ECS */ 95262306a36Sopenharmony_ci#define DEFMODE_AMBER_PAL 3 /* "pal-lace" for flicker fixed PAL (A3000) */ 95362306a36Sopenharmony_ci#define DEFMODE_AMBER_NTSC 1 /* "ntsc-lace" for flicker fixed NTSC (A3000) */ 95462306a36Sopenharmony_ci#define DEFMODE_AGA 19 /* "vga70" for AGA */ 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_cistatic int amifb_ilbm = 0; /* interleaved or normal bitplanes */ 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic u32 amifb_hfmin __initdata; /* monitor hfreq lower limit (Hz) */ 96062306a36Sopenharmony_cistatic u32 amifb_hfmax __initdata; /* monitor hfreq upper limit (Hz) */ 96162306a36Sopenharmony_cistatic u16 amifb_vfmin __initdata; /* monitor vfreq lower limit (Hz) */ 96262306a36Sopenharmony_cistatic u16 amifb_vfmax __initdata; /* monitor vfreq upper limit (Hz) */ 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* 96662306a36Sopenharmony_ci * Macros for the conversion from real world values to hardware register 96762306a36Sopenharmony_ci * values 96862306a36Sopenharmony_ci * 96962306a36Sopenharmony_ci * This helps us to keep our attention on the real stuff... 97062306a36Sopenharmony_ci * 97162306a36Sopenharmony_ci * Hardware limits for AGA: 97262306a36Sopenharmony_ci * 97362306a36Sopenharmony_ci * parameter min max step 97462306a36Sopenharmony_ci * --------- --- ---- ---- 97562306a36Sopenharmony_ci * diwstrt_h 0 2047 1 97662306a36Sopenharmony_ci * diwstrt_v 0 2047 1 97762306a36Sopenharmony_ci * diwstop_h 0 4095 1 97862306a36Sopenharmony_ci * diwstop_v 0 4095 1 97962306a36Sopenharmony_ci * 98062306a36Sopenharmony_ci * ddfstrt 0 2032 16 98162306a36Sopenharmony_ci * ddfstop 0 2032 16 98262306a36Sopenharmony_ci * 98362306a36Sopenharmony_ci * htotal 8 2048 8 98462306a36Sopenharmony_ci * hsstrt 0 2040 8 98562306a36Sopenharmony_ci * hsstop 0 2040 8 98662306a36Sopenharmony_ci * vtotal 1 4096 1 98762306a36Sopenharmony_ci * vsstrt 0 4095 1 98862306a36Sopenharmony_ci * vsstop 0 4095 1 98962306a36Sopenharmony_ci * hcenter 0 2040 8 99062306a36Sopenharmony_ci * 99162306a36Sopenharmony_ci * hbstrt 0 2047 1 99262306a36Sopenharmony_ci * hbstop 0 2047 1 99362306a36Sopenharmony_ci * vbstrt 0 4095 1 99462306a36Sopenharmony_ci * vbstop 0 4095 1 99562306a36Sopenharmony_ci * 99662306a36Sopenharmony_ci * Horizontal values are in 35 ns (SHRES) pixels 99762306a36Sopenharmony_ci * Vertical values are in half scanlines 99862306a36Sopenharmony_ci */ 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci/* bplcon1 (smooth scrolling) */ 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci#define hscroll2hw(hscroll) \ 100362306a36Sopenharmony_ci (((hscroll) << 12 & 0x3000) | ((hscroll) << 8 & 0xc300) | \ 100462306a36Sopenharmony_ci ((hscroll) << 4 & 0x0c00) | ((hscroll) << 2 & 0x00f0) | \ 100562306a36Sopenharmony_ci ((hscroll)>>2 & 0x000f)) 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci/* diwstrt/diwstop/diwhigh (visible display window) */ 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci#define diwstrt2hw(diwstrt_h, diwstrt_v) \ 101062306a36Sopenharmony_ci (((diwstrt_v) << 7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff)) 101162306a36Sopenharmony_ci#define diwstop2hw(diwstop_h, diwstop_v) \ 101262306a36Sopenharmony_ci (((diwstop_v) << 7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff)) 101362306a36Sopenharmony_ci#define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \ 101462306a36Sopenharmony_ci (((diwstop_h) << 3 & 0x2000) | ((diwstop_h) << 11 & 0x1800) | \ 101562306a36Sopenharmony_ci ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \ 101662306a36Sopenharmony_ci ((diwstrt_h) << 3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007)) 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci/* ddfstrt/ddfstop (display DMA) */ 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci#define ddfstrt2hw(ddfstrt) div8(ddfstrt) 102162306a36Sopenharmony_ci#define ddfstop2hw(ddfstop) div8(ddfstop) 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */ 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci#define hsstrt2hw(hsstrt) (div8(hsstrt)) 102662306a36Sopenharmony_ci#define hsstop2hw(hsstop) (div8(hsstop)) 102762306a36Sopenharmony_ci#define htotal2hw(htotal) (div8(htotal) - 1) 102862306a36Sopenharmony_ci#define vsstrt2hw(vsstrt) (div2(vsstrt)) 102962306a36Sopenharmony_ci#define vsstop2hw(vsstop) (div2(vsstop)) 103062306a36Sopenharmony_ci#define vtotal2hw(vtotal) (div2(vtotal) - 1) 103162306a36Sopenharmony_ci#define hcenter2hw(htotal) (div8(htotal)) 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */ 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci#define hbstrt2hw(hbstrt) (((hbstrt) << 8 & 0x0700) | ((hbstrt)>>3 & 0x00ff)) 103662306a36Sopenharmony_ci#define hbstop2hw(hbstop) (((hbstop) << 8 & 0x0700) | ((hbstop)>>3 & 0x00ff)) 103762306a36Sopenharmony_ci#define vbstrt2hw(vbstrt) (div2(vbstrt)) 103862306a36Sopenharmony_ci#define vbstop2hw(vbstop) (div2(vbstop)) 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci/* colour */ 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci#define rgb2hw8_high(red, green, blue) \ 104362306a36Sopenharmony_ci (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) 104462306a36Sopenharmony_ci#define rgb2hw8_low(red, green, blue) \ 104562306a36Sopenharmony_ci (((red & 0x0f) << 8) | ((green & 0x0f) << 4) | (blue & 0x0f)) 104662306a36Sopenharmony_ci#define rgb2hw4(red, green, blue) \ 104762306a36Sopenharmony_ci (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) 104862306a36Sopenharmony_ci#define rgb2hw2(red, green, blue) \ 104962306a36Sopenharmony_ci (((red & 0xc0) << 4) | (green & 0xc0) | ((blue & 0xc0)>>4)) 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci/* sprpos/sprctl (sprite positioning) */ 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci#define spr2hw_pos(start_v, start_h) \ 105462306a36Sopenharmony_ci (((start_v) << 7 & 0xff00) | ((start_h)>>3 & 0x00ff)) 105562306a36Sopenharmony_ci#define spr2hw_ctl(start_v, start_h, stop_v) \ 105662306a36Sopenharmony_ci (((stop_v) << 7 & 0xff00) | ((start_v)>>4 & 0x0040) | \ 105762306a36Sopenharmony_ci ((stop_v)>>5 & 0x0020) | ((start_h) << 3 & 0x0018) | \ 105862306a36Sopenharmony_ci ((start_v)>>7 & 0x0004) | ((stop_v)>>8 & 0x0002) | \ 105962306a36Sopenharmony_ci ((start_h)>>2 & 0x0001)) 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci/* get current vertical position of beam */ 106262306a36Sopenharmony_ci#define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe)) 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci /* 106562306a36Sopenharmony_ci * Copper Initialisation List 106662306a36Sopenharmony_ci */ 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci#define COPINITSIZE (sizeof(copins) * 40) 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_cienum { 107162306a36Sopenharmony_ci cip_bplcon0 107262306a36Sopenharmony_ci}; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci /* 107562306a36Sopenharmony_ci * Long Frame/Short Frame Copper List 107662306a36Sopenharmony_ci * Don't change the order, build_copper()/rebuild_copper() rely on this 107762306a36Sopenharmony_ci */ 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci#define COPLISTSIZE (sizeof(copins) * 64) 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_cienum { 108262306a36Sopenharmony_ci cop_wait, cop_bplcon0, 108362306a36Sopenharmony_ci cop_spr0ptrh, cop_spr0ptrl, 108462306a36Sopenharmony_ci cop_diwstrt, cop_diwstop, 108562306a36Sopenharmony_ci cop_diwhigh, 108662306a36Sopenharmony_ci}; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci /* 108962306a36Sopenharmony_ci * Pixel modes for Bitplanes and Sprites 109062306a36Sopenharmony_ci */ 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic u_short bplpixmode[3] = { 109362306a36Sopenharmony_ci BPC0_SHRES, /* 35 ns */ 109462306a36Sopenharmony_ci BPC0_HIRES, /* 70 ns */ 109562306a36Sopenharmony_ci 0 /* 140 ns */ 109662306a36Sopenharmony_ci}; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_cistatic u_short sprpixmode[3] = { 109962306a36Sopenharmony_ci BPC3_SPRES1 | BPC3_SPRES0, /* 35 ns */ 110062306a36Sopenharmony_ci BPC3_SPRES1, /* 70 ns */ 110162306a36Sopenharmony_ci BPC3_SPRES0 /* 140 ns */ 110262306a36Sopenharmony_ci}; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci /* 110562306a36Sopenharmony_ci * Fetch modes for Bitplanes and Sprites 110662306a36Sopenharmony_ci */ 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_cistatic u_short bplfetchmode[3] = { 110962306a36Sopenharmony_ci 0, /* 1x */ 111062306a36Sopenharmony_ci FMODE_BPL32, /* 2x */ 111162306a36Sopenharmony_ci FMODE_BPAGEM | FMODE_BPL32 /* 4x */ 111262306a36Sopenharmony_ci}; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistatic u_short sprfetchmode[3] = { 111562306a36Sopenharmony_ci 0, /* 1x */ 111662306a36Sopenharmony_ci FMODE_SPR32, /* 2x */ 111762306a36Sopenharmony_ci FMODE_SPAGEM | FMODE_SPR32 /* 4x */ 111862306a36Sopenharmony_ci}; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci/* --------------------------- Hardware routines --------------------------- */ 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci /* 112462306a36Sopenharmony_ci * Get the video params out of `var'. If a value doesn't fit, round 112562306a36Sopenharmony_ci * it up, if it's too big, return -EINVAL. 112662306a36Sopenharmony_ci */ 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_cistatic int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par, 112962306a36Sopenharmony_ci const struct fb_info *info) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci u_short clk_shift, line_shift; 113262306a36Sopenharmony_ci u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; 113362306a36Sopenharmony_ci u_int htotal, vtotal; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci /* 113662306a36Sopenharmony_ci * Find a matching Pixel Clock 113762306a36Sopenharmony_ci */ 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++) 114062306a36Sopenharmony_ci if (var->pixclock <= pixclock[clk_shift]) 114162306a36Sopenharmony_ci break; 114262306a36Sopenharmony_ci if (clk_shift > TAG_LORES) { 114362306a36Sopenharmony_ci DPRINTK("pixclock too high\n"); 114462306a36Sopenharmony_ci return -EINVAL; 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci par->clk_shift = clk_shift; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci /* 114962306a36Sopenharmony_ci * Check the Geometry Values 115062306a36Sopenharmony_ci */ 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci if ((par->xres = var->xres) < 64) 115362306a36Sopenharmony_ci par->xres = 64; 115462306a36Sopenharmony_ci if ((par->yres = var->yres) < 64) 115562306a36Sopenharmony_ci par->yres = 64; 115662306a36Sopenharmony_ci if ((par->vxres = var->xres_virtual) < par->xres) 115762306a36Sopenharmony_ci par->vxres = par->xres; 115862306a36Sopenharmony_ci if ((par->vyres = var->yres_virtual) < par->yres) 115962306a36Sopenharmony_ci par->vyres = par->yres; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci par->bpp = var->bits_per_pixel; 116262306a36Sopenharmony_ci if (!var->nonstd) { 116362306a36Sopenharmony_ci if (par->bpp < 1) 116462306a36Sopenharmony_ci par->bpp = 1; 116562306a36Sopenharmony_ci if (par->bpp > maxdepth[clk_shift]) { 116662306a36Sopenharmony_ci if (round_down_bpp && maxdepth[clk_shift]) 116762306a36Sopenharmony_ci par->bpp = maxdepth[clk_shift]; 116862306a36Sopenharmony_ci else { 116962306a36Sopenharmony_ci DPRINTK("invalid bpp\n"); 117062306a36Sopenharmony_ci return -EINVAL; 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci } 117362306a36Sopenharmony_ci } else if (var->nonstd == FB_NONSTD_HAM) { 117462306a36Sopenharmony_ci if (par->bpp < 6) 117562306a36Sopenharmony_ci par->bpp = 6; 117662306a36Sopenharmony_ci if (par->bpp != 6) { 117762306a36Sopenharmony_ci if (par->bpp < 8) 117862306a36Sopenharmony_ci par->bpp = 8; 117962306a36Sopenharmony_ci if (par->bpp != 8 || !IS_AGA) { 118062306a36Sopenharmony_ci DPRINTK("invalid bpp for ham mode\n"); 118162306a36Sopenharmony_ci return -EINVAL; 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci } else { 118562306a36Sopenharmony_ci DPRINTK("unknown nonstd mode\n"); 118662306a36Sopenharmony_ci return -EINVAL; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci /* 119062306a36Sopenharmony_ci * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the following 119162306a36Sopenharmony_ci * checks failed and smooth scrolling is not possible 119262306a36Sopenharmony_ci */ 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN; 119562306a36Sopenharmony_ci switch (par->vmode & FB_VMODE_MASK) { 119662306a36Sopenharmony_ci case FB_VMODE_INTERLACED: 119762306a36Sopenharmony_ci line_shift = 0; 119862306a36Sopenharmony_ci break; 119962306a36Sopenharmony_ci case FB_VMODE_NONINTERLACED: 120062306a36Sopenharmony_ci line_shift = 1; 120162306a36Sopenharmony_ci break; 120262306a36Sopenharmony_ci case FB_VMODE_DOUBLE: 120362306a36Sopenharmony_ci if (!IS_AGA) { 120462306a36Sopenharmony_ci DPRINTK("double mode only possible with aga\n"); 120562306a36Sopenharmony_ci return -EINVAL; 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci line_shift = 2; 120862306a36Sopenharmony_ci break; 120962306a36Sopenharmony_ci default: 121062306a36Sopenharmony_ci DPRINTK("unknown video mode\n"); 121162306a36Sopenharmony_ci return -EINVAL; 121262306a36Sopenharmony_ci break; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci par->line_shift = line_shift; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci /* 121762306a36Sopenharmony_ci * Vertical and Horizontal Timings 121862306a36Sopenharmony_ci */ 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci xres_n = par->xres << clk_shift; 122162306a36Sopenharmony_ci yres_n = par->yres << line_shift; 122262306a36Sopenharmony_ci par->htotal = down8((var->left_margin + par->xres + var->right_margin + 122362306a36Sopenharmony_ci var->hsync_len) << clk_shift); 122462306a36Sopenharmony_ci par->vtotal = 122562306a36Sopenharmony_ci down2(((var->upper_margin + par->yres + var->lower_margin + 122662306a36Sopenharmony_ci var->vsync_len) << line_shift) + 1); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci if (IS_AGA) 122962306a36Sopenharmony_ci par->bplcon3 = sprpixmode[clk_shift]; 123062306a36Sopenharmony_ci else 123162306a36Sopenharmony_ci par->bplcon3 = 0; 123262306a36Sopenharmony_ci if (var->sync & FB_SYNC_BROADCAST) { 123362306a36Sopenharmony_ci par->diwstop_h = par->htotal - 123462306a36Sopenharmony_ci ((var->right_margin - var->hsync_len) << clk_shift); 123562306a36Sopenharmony_ci if (IS_AGA) 123662306a36Sopenharmony_ci par->diwstop_h += mod4(var->hsync_len); 123762306a36Sopenharmony_ci else 123862306a36Sopenharmony_ci par->diwstop_h = down4(par->diwstop_h); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci par->diwstrt_h = par->diwstop_h - xres_n; 124162306a36Sopenharmony_ci par->diwstop_v = par->vtotal - 124262306a36Sopenharmony_ci ((var->lower_margin - var->vsync_len) << line_shift); 124362306a36Sopenharmony_ci par->diwstrt_v = par->diwstop_v - yres_n; 124462306a36Sopenharmony_ci if (par->diwstop_h >= par->htotal + 8) { 124562306a36Sopenharmony_ci DPRINTK("invalid diwstop_h\n"); 124662306a36Sopenharmony_ci return -EINVAL; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci if (par->diwstop_v > par->vtotal) { 124962306a36Sopenharmony_ci DPRINTK("invalid diwstop_v\n"); 125062306a36Sopenharmony_ci return -EINVAL; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci if (!IS_OCS) { 125462306a36Sopenharmony_ci /* Initialize sync with some reasonable values for pwrsave */ 125562306a36Sopenharmony_ci par->hsstrt = 160; 125662306a36Sopenharmony_ci par->hsstop = 320; 125762306a36Sopenharmony_ci par->vsstrt = 30; 125862306a36Sopenharmony_ci par->vsstop = 34; 125962306a36Sopenharmony_ci } else { 126062306a36Sopenharmony_ci par->hsstrt = 0; 126162306a36Sopenharmony_ci par->hsstop = 0; 126262306a36Sopenharmony_ci par->vsstrt = 0; 126362306a36Sopenharmony_ci par->vsstop = 0; 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci if (par->vtotal > (PAL_VTOTAL + NTSC_VTOTAL) / 2) { 126662306a36Sopenharmony_ci /* PAL video mode */ 126762306a36Sopenharmony_ci if (par->htotal != PAL_HTOTAL) { 126862306a36Sopenharmony_ci DPRINTK("htotal invalid for pal\n"); 126962306a36Sopenharmony_ci return -EINVAL; 127062306a36Sopenharmony_ci } 127162306a36Sopenharmony_ci if (par->diwstrt_h < PAL_DIWSTRT_H) { 127262306a36Sopenharmony_ci DPRINTK("diwstrt_h too low for pal\n"); 127362306a36Sopenharmony_ci return -EINVAL; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci if (par->diwstrt_v < PAL_DIWSTRT_V) { 127662306a36Sopenharmony_ci DPRINTK("diwstrt_v too low for pal\n"); 127762306a36Sopenharmony_ci return -EINVAL; 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci htotal = PAL_HTOTAL>>clk_shift; 128062306a36Sopenharmony_ci vtotal = PAL_VTOTAL>>1; 128162306a36Sopenharmony_ci if (!IS_OCS) { 128262306a36Sopenharmony_ci par->beamcon0 = BMC0_PAL; 128362306a36Sopenharmony_ci par->bplcon3 |= BPC3_BRDRBLNK; 128462306a36Sopenharmony_ci } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || 128562306a36Sopenharmony_ci AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { 128662306a36Sopenharmony_ci par->beamcon0 = BMC0_PAL; 128762306a36Sopenharmony_ci par->hsstop = 1; 128862306a36Sopenharmony_ci } else if (amiga_vblank != 50) { 128962306a36Sopenharmony_ci DPRINTK("pal not supported by this chipset\n"); 129062306a36Sopenharmony_ci return -EINVAL; 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci } else { 129362306a36Sopenharmony_ci /* NTSC video mode 129462306a36Sopenharmony_ci * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK 129562306a36Sopenharmony_ci * and NTSC activated, so than better let diwstop_h <= 1812 129662306a36Sopenharmony_ci */ 129762306a36Sopenharmony_ci if (par->htotal != NTSC_HTOTAL) { 129862306a36Sopenharmony_ci DPRINTK("htotal invalid for ntsc\n"); 129962306a36Sopenharmony_ci return -EINVAL; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci if (par->diwstrt_h < NTSC_DIWSTRT_H) { 130262306a36Sopenharmony_ci DPRINTK("diwstrt_h too low for ntsc\n"); 130362306a36Sopenharmony_ci return -EINVAL; 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci if (par->diwstrt_v < NTSC_DIWSTRT_V) { 130662306a36Sopenharmony_ci DPRINTK("diwstrt_v too low for ntsc\n"); 130762306a36Sopenharmony_ci return -EINVAL; 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci htotal = NTSC_HTOTAL>>clk_shift; 131062306a36Sopenharmony_ci vtotal = NTSC_VTOTAL>>1; 131162306a36Sopenharmony_ci if (!IS_OCS) { 131262306a36Sopenharmony_ci par->beamcon0 = 0; 131362306a36Sopenharmony_ci par->bplcon3 |= BPC3_BRDRBLNK; 131462306a36Sopenharmony_ci } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || 131562306a36Sopenharmony_ci AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { 131662306a36Sopenharmony_ci par->beamcon0 = 0; 131762306a36Sopenharmony_ci par->hsstop = 1; 131862306a36Sopenharmony_ci } else if (amiga_vblank != 60) { 131962306a36Sopenharmony_ci DPRINTK("ntsc not supported by this chipset\n"); 132062306a36Sopenharmony_ci return -EINVAL; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci if (IS_OCS) { 132462306a36Sopenharmony_ci if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 || 132562306a36Sopenharmony_ci par->diwstrt_v >= 512 || par->diwstop_v < 256) { 132662306a36Sopenharmony_ci DPRINTK("invalid position for display on ocs\n"); 132762306a36Sopenharmony_ci return -EINVAL; 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci } else if (!IS_OCS) { 133162306a36Sopenharmony_ci /* Programmable video mode */ 133262306a36Sopenharmony_ci par->hsstrt = var->right_margin << clk_shift; 133362306a36Sopenharmony_ci par->hsstop = (var->right_margin + var->hsync_len) << clk_shift; 133462306a36Sopenharmony_ci par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift); 133562306a36Sopenharmony_ci if (!IS_AGA) 133662306a36Sopenharmony_ci par->diwstop_h = down4(par->diwstop_h) - 16; 133762306a36Sopenharmony_ci par->diwstrt_h = par->diwstop_h - xres_n; 133862306a36Sopenharmony_ci par->hbstop = par->diwstrt_h + 4; 133962306a36Sopenharmony_ci par->hbstrt = par->diwstop_h + 4; 134062306a36Sopenharmony_ci if (par->hbstrt >= par->htotal + 8) 134162306a36Sopenharmony_ci par->hbstrt -= par->htotal; 134262306a36Sopenharmony_ci par->hcenter = par->hsstrt + (par->htotal >> 1); 134362306a36Sopenharmony_ci par->vsstrt = var->lower_margin << line_shift; 134462306a36Sopenharmony_ci par->vsstop = (var->lower_margin + var->vsync_len) << line_shift; 134562306a36Sopenharmony_ci par->diwstop_v = par->vtotal; 134662306a36Sopenharmony_ci if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) 134762306a36Sopenharmony_ci par->diwstop_v -= 2; 134862306a36Sopenharmony_ci par->diwstrt_v = par->diwstop_v - yres_n; 134962306a36Sopenharmony_ci par->vbstop = par->diwstrt_v - 2; 135062306a36Sopenharmony_ci par->vbstrt = par->diwstop_v - 2; 135162306a36Sopenharmony_ci if (par->vtotal > 2048) { 135262306a36Sopenharmony_ci DPRINTK("vtotal too high\n"); 135362306a36Sopenharmony_ci return -EINVAL; 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci if (par->htotal > 2048) { 135662306a36Sopenharmony_ci DPRINTK("htotal too high\n"); 135762306a36Sopenharmony_ci return -EINVAL; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci par->bplcon3 |= BPC3_EXTBLKEN; 136062306a36Sopenharmony_ci par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | 136162306a36Sopenharmony_ci BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN | 136262306a36Sopenharmony_ci BMC0_PAL | BMC0_VARCSYEN; 136362306a36Sopenharmony_ci if (var->sync & FB_SYNC_HOR_HIGH_ACT) 136462306a36Sopenharmony_ci par->beamcon0 |= BMC0_HSYTRUE; 136562306a36Sopenharmony_ci if (var->sync & FB_SYNC_VERT_HIGH_ACT) 136662306a36Sopenharmony_ci par->beamcon0 |= BMC0_VSYTRUE; 136762306a36Sopenharmony_ci if (var->sync & FB_SYNC_COMP_HIGH_ACT) 136862306a36Sopenharmony_ci par->beamcon0 |= BMC0_CSYTRUE; 136962306a36Sopenharmony_ci htotal = par->htotal>>clk_shift; 137062306a36Sopenharmony_ci vtotal = par->vtotal>>1; 137162306a36Sopenharmony_ci } else { 137262306a36Sopenharmony_ci DPRINTK("only broadcast modes possible for ocs\n"); 137362306a36Sopenharmony_ci return -EINVAL; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci /* 137762306a36Sopenharmony_ci * Checking the DMA timing 137862306a36Sopenharmony_ci */ 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci fconst = 16 << maxfmode << clk_shift; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci /* 138362306a36Sopenharmony_ci * smallest window start value without turn off other dma cycles 138462306a36Sopenharmony_ci * than sprite1-7, unless you change min_fstrt 138562306a36Sopenharmony_ci */ 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci fsize = ((maxfmode + clk_shift <= 1) ? fconst : 64); 138962306a36Sopenharmony_ci fstrt = downx(fconst, par->diwstrt_h - 4) - fsize; 139062306a36Sopenharmony_ci if (fstrt < min_fstrt) { 139162306a36Sopenharmony_ci DPRINTK("fetch start too low\n"); 139262306a36Sopenharmony_ci return -EINVAL; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci /* 139662306a36Sopenharmony_ci * smallest window start value where smooth scrolling is possible 139762306a36Sopenharmony_ci */ 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci fstrt = downx(fconst, par->diwstrt_h - fconst + (1 << clk_shift) - 4) - 140062306a36Sopenharmony_ci fsize; 140162306a36Sopenharmony_ci if (fstrt < min_fstrt) 140262306a36Sopenharmony_ci par->vmode &= ~FB_VMODE_SMOOTH_XPAN; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci maxfetchstop = down16(par->htotal - 80); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci fstrt = downx(fconst, par->diwstrt_h - 4) - 64 - fconst; 140762306a36Sopenharmony_ci fsize = upx(fconst, xres_n + 140862306a36Sopenharmony_ci modx(fconst, downx(1 << clk_shift, par->diwstrt_h - 4))); 140962306a36Sopenharmony_ci if (fstrt + fsize > maxfetchstop) 141062306a36Sopenharmony_ci par->vmode &= ~FB_VMODE_SMOOTH_XPAN; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci fsize = upx(fconst, xres_n); 141362306a36Sopenharmony_ci if (fstrt + fsize > maxfetchstop) { 141462306a36Sopenharmony_ci DPRINTK("fetch stop too high\n"); 141562306a36Sopenharmony_ci return -EINVAL; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci if (maxfmode + clk_shift <= 1) { 141962306a36Sopenharmony_ci fsize = up64(xres_n + fconst - 1); 142062306a36Sopenharmony_ci if (min_fstrt + fsize - 64 > maxfetchstop) 142162306a36Sopenharmony_ci par->vmode &= ~FB_VMODE_SMOOTH_XPAN; 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci fsize = up64(xres_n); 142462306a36Sopenharmony_ci if (min_fstrt + fsize - 64 > maxfetchstop) { 142562306a36Sopenharmony_ci DPRINTK("fetch size too high\n"); 142662306a36Sopenharmony_ci return -EINVAL; 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci fsize -= 64; 143062306a36Sopenharmony_ci } else 143162306a36Sopenharmony_ci fsize -= fconst; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci /* 143462306a36Sopenharmony_ci * Check if there is enough time to update the bitplane pointers for ywrap 143562306a36Sopenharmony_ci */ 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci if (par->htotal - fsize - 64 < par->bpp * 64) 143862306a36Sopenharmony_ci par->vmode &= ~FB_VMODE_YWRAP; 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci /* 144162306a36Sopenharmony_ci * Bitplane calculations and check the Memory Requirements 144262306a36Sopenharmony_ci */ 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci if (amifb_ilbm) { 144562306a36Sopenharmony_ci par->next_plane = div8(upx(16 << maxfmode, par->vxres)); 144662306a36Sopenharmony_ci par->next_line = par->bpp * par->next_plane; 144762306a36Sopenharmony_ci if (par->next_line * par->vyres > info->fix.smem_len) { 144862306a36Sopenharmony_ci DPRINTK("too few video mem\n"); 144962306a36Sopenharmony_ci return -EINVAL; 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci } else { 145262306a36Sopenharmony_ci par->next_line = div8(upx(16 << maxfmode, par->vxres)); 145362306a36Sopenharmony_ci par->next_plane = par->vyres * par->next_line; 145462306a36Sopenharmony_ci if (par->next_plane * par->bpp > info->fix.smem_len) { 145562306a36Sopenharmony_ci DPRINTK("too few video mem\n"); 145662306a36Sopenharmony_ci return -EINVAL; 145762306a36Sopenharmony_ci } 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci /* 146162306a36Sopenharmony_ci * Hardware Register Values 146262306a36Sopenharmony_ci */ 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift]; 146562306a36Sopenharmony_ci if (!IS_OCS) 146662306a36Sopenharmony_ci par->bplcon0 |= BPC0_ECSENA; 146762306a36Sopenharmony_ci if (par->bpp == 8) 146862306a36Sopenharmony_ci par->bplcon0 |= BPC0_BPU3; 146962306a36Sopenharmony_ci else 147062306a36Sopenharmony_ci par->bplcon0 |= par->bpp << 12; 147162306a36Sopenharmony_ci if (var->nonstd == FB_NONSTD_HAM) 147262306a36Sopenharmony_ci par->bplcon0 |= BPC0_HAM; 147362306a36Sopenharmony_ci if (var->sync & FB_SYNC_EXT) 147462306a36Sopenharmony_ci par->bplcon0 |= BPC0_ERSY; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci if (IS_AGA) 147762306a36Sopenharmony_ci par->fmode = bplfetchmode[maxfmode]; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci switch (par->vmode & FB_VMODE_MASK) { 148062306a36Sopenharmony_ci case FB_VMODE_INTERLACED: 148162306a36Sopenharmony_ci par->bplcon0 |= BPC0_LACE; 148262306a36Sopenharmony_ci break; 148362306a36Sopenharmony_ci case FB_VMODE_DOUBLE: 148462306a36Sopenharmony_ci if (IS_AGA) 148562306a36Sopenharmony_ci par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2; 148662306a36Sopenharmony_ci break; 148762306a36Sopenharmony_ci } 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) { 149062306a36Sopenharmony_ci par->xoffset = var->xoffset; 149162306a36Sopenharmony_ci par->yoffset = var->yoffset; 149262306a36Sopenharmony_ci if (par->vmode & FB_VMODE_YWRAP) { 149362306a36Sopenharmony_ci if (par->yoffset >= par->vyres) 149462306a36Sopenharmony_ci par->xoffset = par->yoffset = 0; 149562306a36Sopenharmony_ci } else { 149662306a36Sopenharmony_ci if (par->xoffset > upx(16 << maxfmode, par->vxres - par->xres) || 149762306a36Sopenharmony_ci par->yoffset > par->vyres - par->yres) 149862306a36Sopenharmony_ci par->xoffset = par->yoffset = 0; 149962306a36Sopenharmony_ci } 150062306a36Sopenharmony_ci } else 150162306a36Sopenharmony_ci par->xoffset = par->yoffset = 0; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci par->crsr.crsr_x = par->crsr.crsr_y = 0; 150462306a36Sopenharmony_ci par->crsr.spot_x = par->crsr.spot_y = 0; 150562306a36Sopenharmony_ci par->crsr.height = par->crsr.width = 0; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci return 0; 150862306a36Sopenharmony_ci} 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci /* 151162306a36Sopenharmony_ci * Fill the `var' structure based on the values in `par' and maybe 151262306a36Sopenharmony_ci * other values read out of the hardware. 151362306a36Sopenharmony_ci */ 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_cistatic void ami_encode_var(struct fb_var_screeninfo *var, 151662306a36Sopenharmony_ci struct amifb_par *par) 151762306a36Sopenharmony_ci{ 151862306a36Sopenharmony_ci u_short clk_shift, line_shift; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci memset(var, 0, sizeof(struct fb_var_screeninfo)); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci clk_shift = par->clk_shift; 152362306a36Sopenharmony_ci line_shift = par->line_shift; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci var->xres = par->xres; 152662306a36Sopenharmony_ci var->yres = par->yres; 152762306a36Sopenharmony_ci var->xres_virtual = par->vxres; 152862306a36Sopenharmony_ci var->yres_virtual = par->vyres; 152962306a36Sopenharmony_ci var->xoffset = par->xoffset; 153062306a36Sopenharmony_ci var->yoffset = par->yoffset; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci var->bits_per_pixel = par->bpp; 153362306a36Sopenharmony_ci var->grayscale = 0; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci var->red.offset = 0; 153662306a36Sopenharmony_ci var->red.msb_right = 0; 153762306a36Sopenharmony_ci var->red.length = par->bpp; 153862306a36Sopenharmony_ci if (par->bplcon0 & BPC0_HAM) 153962306a36Sopenharmony_ci var->red.length -= 2; 154062306a36Sopenharmony_ci var->blue = var->green = var->red; 154162306a36Sopenharmony_ci var->transp.offset = 0; 154262306a36Sopenharmony_ci var->transp.length = 0; 154362306a36Sopenharmony_ci var->transp.msb_right = 0; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (par->bplcon0 & BPC0_HAM) 154662306a36Sopenharmony_ci var->nonstd = FB_NONSTD_HAM; 154762306a36Sopenharmony_ci else 154862306a36Sopenharmony_ci var->nonstd = 0; 154962306a36Sopenharmony_ci var->activate = 0; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci var->height = -1; 155262306a36Sopenharmony_ci var->width = -1; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci var->pixclock = pixclock[clk_shift]; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci if (IS_AGA && par->fmode & FMODE_BSCAN2) 155762306a36Sopenharmony_ci var->vmode = FB_VMODE_DOUBLE; 155862306a36Sopenharmony_ci else if (par->bplcon0 & BPC0_LACE) 155962306a36Sopenharmony_ci var->vmode = FB_VMODE_INTERLACED; 156062306a36Sopenharmony_ci else 156162306a36Sopenharmony_ci var->vmode = FB_VMODE_NONINTERLACED; 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) { 156462306a36Sopenharmony_ci var->hsync_len = (par->hsstop - par->hsstrt)>>clk_shift; 156562306a36Sopenharmony_ci var->right_margin = par->hsstrt>>clk_shift; 156662306a36Sopenharmony_ci var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; 156762306a36Sopenharmony_ci var->vsync_len = (par->vsstop - par->vsstrt)>>line_shift; 156862306a36Sopenharmony_ci var->lower_margin = par->vsstrt>>line_shift; 156962306a36Sopenharmony_ci var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len; 157062306a36Sopenharmony_ci var->sync = 0; 157162306a36Sopenharmony_ci if (par->beamcon0 & BMC0_HSYTRUE) 157262306a36Sopenharmony_ci var->sync |= FB_SYNC_HOR_HIGH_ACT; 157362306a36Sopenharmony_ci if (par->beamcon0 & BMC0_VSYTRUE) 157462306a36Sopenharmony_ci var->sync |= FB_SYNC_VERT_HIGH_ACT; 157562306a36Sopenharmony_ci if (par->beamcon0 & BMC0_CSYTRUE) 157662306a36Sopenharmony_ci var->sync |= FB_SYNC_COMP_HIGH_ACT; 157762306a36Sopenharmony_ci } else { 157862306a36Sopenharmony_ci var->sync = FB_SYNC_BROADCAST; 157962306a36Sopenharmony_ci var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h); 158062306a36Sopenharmony_ci var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len; 158162306a36Sopenharmony_ci var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; 158262306a36Sopenharmony_ci var->vsync_len = 4>>line_shift; 158362306a36Sopenharmony_ci var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len; 158462306a36Sopenharmony_ci var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres - 158562306a36Sopenharmony_ci var->lower_margin - var->vsync_len; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci if (par->bplcon0 & BPC0_ERSY) 158962306a36Sopenharmony_ci var->sync |= FB_SYNC_EXT; 159062306a36Sopenharmony_ci if (par->vmode & FB_VMODE_YWRAP) 159162306a36Sopenharmony_ci var->vmode |= FB_VMODE_YWRAP; 159262306a36Sopenharmony_ci} 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci /* 159662306a36Sopenharmony_ci * Update hardware 159762306a36Sopenharmony_ci */ 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_cistatic void ami_update_par(struct fb_info *info) 160062306a36Sopenharmony_ci{ 160162306a36Sopenharmony_ci struct amifb_par *par = info->par; 160262306a36Sopenharmony_ci short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci clk_shift = par->clk_shift; 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci if (!(par->vmode & FB_VMODE_SMOOTH_XPAN)) 160762306a36Sopenharmony_ci par->xoffset = upx(16 << maxfmode, par->xoffset); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci fconst = 16 << maxfmode << clk_shift; 161062306a36Sopenharmony_ci vshift = modx(16 << maxfmode, par->xoffset); 161162306a36Sopenharmony_ci fstrt = par->diwstrt_h - (vshift << clk_shift) - 4; 161262306a36Sopenharmony_ci fsize = (par->xres + vshift) << clk_shift; 161362306a36Sopenharmony_ci shift = modx(fconst, fstrt); 161462306a36Sopenharmony_ci move = downx(2 << maxfmode, div8(par->xoffset)); 161562306a36Sopenharmony_ci if (maxfmode + clk_shift > 1) { 161662306a36Sopenharmony_ci fstrt = downx(fconst, fstrt) - 64; 161762306a36Sopenharmony_ci fsize = upx(fconst, fsize); 161862306a36Sopenharmony_ci fstop = fstrt + fsize - fconst; 161962306a36Sopenharmony_ci } else { 162062306a36Sopenharmony_ci mod = fstrt = downx(fconst, fstrt) - fconst; 162162306a36Sopenharmony_ci fstop = fstrt + upx(fconst, fsize) - 64; 162262306a36Sopenharmony_ci fsize = up64(fsize); 162362306a36Sopenharmony_ci fstrt = fstop - fsize + 64; 162462306a36Sopenharmony_ci if (fstrt < min_fstrt) { 162562306a36Sopenharmony_ci fstop += min_fstrt - fstrt; 162662306a36Sopenharmony_ci fstrt = min_fstrt; 162762306a36Sopenharmony_ci } 162862306a36Sopenharmony_ci move = move - div8((mod - fstrt)>>clk_shift); 162962306a36Sopenharmony_ci } 163062306a36Sopenharmony_ci mod = par->next_line - div8(fsize>>clk_shift); 163162306a36Sopenharmony_ci par->ddfstrt = fstrt; 163262306a36Sopenharmony_ci par->ddfstop = fstop; 163362306a36Sopenharmony_ci par->bplcon1 = hscroll2hw(shift); 163462306a36Sopenharmony_ci par->bpl2mod = mod; 163562306a36Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) 163662306a36Sopenharmony_ci par->bpl2mod += par->next_line; 163762306a36Sopenharmony_ci if (IS_AGA && (par->fmode & FMODE_BSCAN2)) 163862306a36Sopenharmony_ci par->bpl1mod = -div8(fsize>>clk_shift); 163962306a36Sopenharmony_ci else 164062306a36Sopenharmony_ci par->bpl1mod = par->bpl2mod; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci if (par->yoffset) { 164362306a36Sopenharmony_ci par->bplpt0 = info->fix.smem_start + 164462306a36Sopenharmony_ci par->next_line * par->yoffset + move; 164562306a36Sopenharmony_ci if (par->vmode & FB_VMODE_YWRAP) { 164662306a36Sopenharmony_ci if (par->yoffset > par->vyres - par->yres) { 164762306a36Sopenharmony_ci par->bplpt0wrap = info->fix.smem_start + move; 164862306a36Sopenharmony_ci if (par->bplcon0 & BPC0_LACE && 164962306a36Sopenharmony_ci mod2(par->diwstrt_v + par->vyres - 165062306a36Sopenharmony_ci par->yoffset)) 165162306a36Sopenharmony_ci par->bplpt0wrap += par->next_line; 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci } 165462306a36Sopenharmony_ci } else 165562306a36Sopenharmony_ci par->bplpt0 = info->fix.smem_start + move; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) 165862306a36Sopenharmony_ci par->bplpt0 += par->next_line; 165962306a36Sopenharmony_ci} 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci /* 166362306a36Sopenharmony_ci * Pan or Wrap the Display 166462306a36Sopenharmony_ci * 166562306a36Sopenharmony_ci * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag 166662306a36Sopenharmony_ci * in `var'. 166762306a36Sopenharmony_ci */ 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_cistatic void ami_pan_var(struct fb_var_screeninfo *var, struct fb_info *info) 167062306a36Sopenharmony_ci{ 167162306a36Sopenharmony_ci struct amifb_par *par = info->par; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci par->xoffset = var->xoffset; 167462306a36Sopenharmony_ci par->yoffset = var->yoffset; 167562306a36Sopenharmony_ci if (var->vmode & FB_VMODE_YWRAP) 167662306a36Sopenharmony_ci par->vmode |= FB_VMODE_YWRAP; 167762306a36Sopenharmony_ci else 167862306a36Sopenharmony_ci par->vmode &= ~FB_VMODE_YWRAP; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci do_vmode_pan = 0; 168162306a36Sopenharmony_ci ami_update_par(info); 168262306a36Sopenharmony_ci do_vmode_pan = 1; 168362306a36Sopenharmony_ci} 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_cistatic void ami_update_display(const struct amifb_par *par) 168762306a36Sopenharmony_ci{ 168862306a36Sopenharmony_ci custom.bplcon1 = par->bplcon1; 168962306a36Sopenharmony_ci custom.bpl1mod = par->bpl1mod; 169062306a36Sopenharmony_ci custom.bpl2mod = par->bpl2mod; 169162306a36Sopenharmony_ci custom.ddfstrt = ddfstrt2hw(par->ddfstrt); 169262306a36Sopenharmony_ci custom.ddfstop = ddfstop2hw(par->ddfstop); 169362306a36Sopenharmony_ci} 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci /* 169662306a36Sopenharmony_ci * Change the video mode (called by VBlank interrupt) 169762306a36Sopenharmony_ci */ 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_cistatic void ami_init_display(const struct amifb_par *par) 170062306a36Sopenharmony_ci{ 170162306a36Sopenharmony_ci int i; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; 170462306a36Sopenharmony_ci custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2; 170562306a36Sopenharmony_ci if (!IS_OCS) { 170662306a36Sopenharmony_ci custom.bplcon3 = par->bplcon3; 170762306a36Sopenharmony_ci if (IS_AGA) 170862306a36Sopenharmony_ci custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4; 170962306a36Sopenharmony_ci if (par->beamcon0 & BMC0_VARBEAMEN) { 171062306a36Sopenharmony_ci custom.htotal = htotal2hw(par->htotal); 171162306a36Sopenharmony_ci custom.hbstrt = hbstrt2hw(par->hbstrt); 171262306a36Sopenharmony_ci custom.hbstop = hbstop2hw(par->hbstop); 171362306a36Sopenharmony_ci custom.hsstrt = hsstrt2hw(par->hsstrt); 171462306a36Sopenharmony_ci custom.hsstop = hsstop2hw(par->hsstop); 171562306a36Sopenharmony_ci custom.hcenter = hcenter2hw(par->hcenter); 171662306a36Sopenharmony_ci custom.vtotal = vtotal2hw(par->vtotal); 171762306a36Sopenharmony_ci custom.vbstrt = vbstrt2hw(par->vbstrt); 171862306a36Sopenharmony_ci custom.vbstop = vbstop2hw(par->vbstop); 171962306a36Sopenharmony_ci custom.vsstrt = vsstrt2hw(par->vsstrt); 172062306a36Sopenharmony_ci custom.vsstop = vsstop2hw(par->vsstop); 172162306a36Sopenharmony_ci } 172262306a36Sopenharmony_ci } 172362306a36Sopenharmony_ci if (!IS_OCS || par->hsstop) 172462306a36Sopenharmony_ci custom.beamcon0 = par->beamcon0; 172562306a36Sopenharmony_ci if (IS_AGA) 172662306a36Sopenharmony_ci custom.fmode = par->fmode; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci /* 172962306a36Sopenharmony_ci * The minimum period for audio depends on htotal 173062306a36Sopenharmony_ci */ 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci amiga_audio_min_period = div16(par->htotal); 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0; 173562306a36Sopenharmony_ci#if 1 173662306a36Sopenharmony_ci if (is_lace) { 173762306a36Sopenharmony_ci i = custom.vposr >> 15; 173862306a36Sopenharmony_ci } else { 173962306a36Sopenharmony_ci custom.vposw = custom.vposr | 0x8000; 174062306a36Sopenharmony_ci i = 1; 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci#else 174362306a36Sopenharmony_ci i = 1; 174462306a36Sopenharmony_ci custom.vposw = custom.vposr | 0x8000; 174562306a36Sopenharmony_ci#endif 174662306a36Sopenharmony_ci custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]); 174762306a36Sopenharmony_ci} 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci /* 175062306a36Sopenharmony_ci * (Un)Blank the screen (called by VBlank interrupt) 175162306a36Sopenharmony_ci */ 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_cistatic void ami_do_blank(const struct amifb_par *par) 175462306a36Sopenharmony_ci{ 175562306a36Sopenharmony_ci#if defined(CONFIG_FB_AMIGA_AGA) 175662306a36Sopenharmony_ci u_short bplcon3 = par->bplcon3; 175762306a36Sopenharmony_ci#endif 175862306a36Sopenharmony_ci u_char red, green, blue; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci if (do_blank > 0) { 176162306a36Sopenharmony_ci custom.dmacon = DMAF_RASTER | DMAF_SPRITE; 176262306a36Sopenharmony_ci red = green = blue = 0; 176362306a36Sopenharmony_ci if (!IS_OCS && do_blank > 1) { 176462306a36Sopenharmony_ci switch (do_blank) { 176562306a36Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 176662306a36Sopenharmony_ci custom.hsstrt = hsstrt2hw(par->hsstrt); 176762306a36Sopenharmony_ci custom.hsstop = hsstop2hw(par->hsstop); 176862306a36Sopenharmony_ci custom.vsstrt = vsstrt2hw(par->vtotal + 4); 176962306a36Sopenharmony_ci custom.vsstop = vsstop2hw(par->vtotal + 4); 177062306a36Sopenharmony_ci break; 177162306a36Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 177262306a36Sopenharmony_ci custom.hsstrt = hsstrt2hw(par->htotal + 16); 177362306a36Sopenharmony_ci custom.hsstop = hsstop2hw(par->htotal + 16); 177462306a36Sopenharmony_ci custom.vsstrt = vsstrt2hw(par->vsstrt); 177562306a36Sopenharmony_ci custom.vsstop = vsstrt2hw(par->vsstop); 177662306a36Sopenharmony_ci break; 177762306a36Sopenharmony_ci case FB_BLANK_POWERDOWN: 177862306a36Sopenharmony_ci custom.hsstrt = hsstrt2hw(par->htotal + 16); 177962306a36Sopenharmony_ci custom.hsstop = hsstop2hw(par->htotal + 16); 178062306a36Sopenharmony_ci custom.vsstrt = vsstrt2hw(par->vtotal + 4); 178162306a36Sopenharmony_ci custom.vsstop = vsstop2hw(par->vtotal + 4); 178262306a36Sopenharmony_ci break; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci if (!(par->beamcon0 & BMC0_VARBEAMEN)) { 178562306a36Sopenharmony_ci custom.htotal = htotal2hw(par->htotal); 178662306a36Sopenharmony_ci custom.vtotal = vtotal2hw(par->vtotal); 178762306a36Sopenharmony_ci custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN | 178862306a36Sopenharmony_ci BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN; 178962306a36Sopenharmony_ci } 179062306a36Sopenharmony_ci } 179162306a36Sopenharmony_ci } else { 179262306a36Sopenharmony_ci custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; 179362306a36Sopenharmony_ci red = red0; 179462306a36Sopenharmony_ci green = green0; 179562306a36Sopenharmony_ci blue = blue0; 179662306a36Sopenharmony_ci if (!IS_OCS) { 179762306a36Sopenharmony_ci custom.hsstrt = hsstrt2hw(par->hsstrt); 179862306a36Sopenharmony_ci custom.hsstop = hsstop2hw(par->hsstop); 179962306a36Sopenharmony_ci custom.vsstrt = vsstrt2hw(par->vsstrt); 180062306a36Sopenharmony_ci custom.vsstop = vsstop2hw(par->vsstop); 180162306a36Sopenharmony_ci custom.beamcon0 = par->beamcon0; 180262306a36Sopenharmony_ci } 180362306a36Sopenharmony_ci } 180462306a36Sopenharmony_ci#if defined(CONFIG_FB_AMIGA_AGA) 180562306a36Sopenharmony_ci if (IS_AGA) { 180662306a36Sopenharmony_ci custom.bplcon3 = bplcon3; 180762306a36Sopenharmony_ci custom.color[0] = rgb2hw8_high(red, green, blue); 180862306a36Sopenharmony_ci custom.bplcon3 = bplcon3 | BPC3_LOCT; 180962306a36Sopenharmony_ci custom.color[0] = rgb2hw8_low(red, green, blue); 181062306a36Sopenharmony_ci custom.bplcon3 = bplcon3; 181162306a36Sopenharmony_ci } else 181262306a36Sopenharmony_ci#endif 181362306a36Sopenharmony_ci#if defined(CONFIG_FB_AMIGA_ECS) 181462306a36Sopenharmony_ci if (par->bplcon0 & BPC0_SHRES) { 181562306a36Sopenharmony_ci u_short color, mask; 181662306a36Sopenharmony_ci int i; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci mask = 0x3333; 181962306a36Sopenharmony_ci color = rgb2hw2(red, green, blue); 182062306a36Sopenharmony_ci for (i = 12; i >= 0; i -= 4) 182162306a36Sopenharmony_ci custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; 182262306a36Sopenharmony_ci mask <<= 2; color >>= 2; 182362306a36Sopenharmony_ci for (i = 3; i >= 0; i--) 182462306a36Sopenharmony_ci custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; 182562306a36Sopenharmony_ci } else 182662306a36Sopenharmony_ci#endif 182762306a36Sopenharmony_ci custom.color[0] = rgb2hw4(red, green, blue); 182862306a36Sopenharmony_ci is_blanked = do_blank > 0 ? do_blank : 0; 182962306a36Sopenharmony_ci} 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_cistatic int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, 183262306a36Sopenharmony_ci const struct amifb_par *par) 183362306a36Sopenharmony_ci{ 183462306a36Sopenharmony_ci fix->crsr_width = fix->crsr_xsize = par->crsr.width; 183562306a36Sopenharmony_ci fix->crsr_height = fix->crsr_ysize = par->crsr.height; 183662306a36Sopenharmony_ci fix->crsr_color1 = 17; 183762306a36Sopenharmony_ci fix->crsr_color2 = 18; 183862306a36Sopenharmony_ci return 0; 183962306a36Sopenharmony_ci} 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_cistatic int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, 184262306a36Sopenharmony_ci u_char __user *data, 184362306a36Sopenharmony_ci const struct amifb_par *par) 184462306a36Sopenharmony_ci{ 184562306a36Sopenharmony_ci register u_short *lspr, *sspr; 184662306a36Sopenharmony_ci#ifdef __mc68000__ 184762306a36Sopenharmony_ci register u_long datawords asm ("d2"); 184862306a36Sopenharmony_ci#else 184962306a36Sopenharmony_ci register u_long datawords; 185062306a36Sopenharmony_ci#endif 185162306a36Sopenharmony_ci register short delta; 185262306a36Sopenharmony_ci register u_char color; 185362306a36Sopenharmony_ci short height, width, bits, words; 185462306a36Sopenharmony_ci int size, alloc; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci size = par->crsr.height * par->crsr.width; 185762306a36Sopenharmony_ci alloc = var->height * var->width; 185862306a36Sopenharmony_ci var->height = par->crsr.height; 185962306a36Sopenharmony_ci var->width = par->crsr.width; 186062306a36Sopenharmony_ci var->xspot = par->crsr.spot_x; 186162306a36Sopenharmony_ci var->yspot = par->crsr.spot_y; 186262306a36Sopenharmony_ci if (size > var->height * var->width) 186362306a36Sopenharmony_ci return -ENAMETOOLONG; 186462306a36Sopenharmony_ci delta = 1 << par->crsr.fmode; 186562306a36Sopenharmony_ci lspr = lofsprite + (delta << 1); 186662306a36Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) 186762306a36Sopenharmony_ci sspr = shfsprite + (delta << 1); 186862306a36Sopenharmony_ci else 186962306a36Sopenharmony_ci sspr = NULL; 187062306a36Sopenharmony_ci for (height = (short)var->height - 1; height >= 0; height--) { 187162306a36Sopenharmony_ci bits = 0; words = delta; datawords = 0; 187262306a36Sopenharmony_ci for (width = (short)var->width - 1; width >= 0; width--) { 187362306a36Sopenharmony_ci if (bits == 0) { 187462306a36Sopenharmony_ci bits = 16; --words; 187562306a36Sopenharmony_ci#ifdef __mc68000__ 187662306a36Sopenharmony_ci asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0" 187762306a36Sopenharmony_ci : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta)); 187862306a36Sopenharmony_ci#else 187962306a36Sopenharmony_ci datawords = (*(lspr + delta) << 16) | (*lspr++); 188062306a36Sopenharmony_ci#endif 188162306a36Sopenharmony_ci } 188262306a36Sopenharmony_ci --bits; 188362306a36Sopenharmony_ci#ifdef __mc68000__ 188462306a36Sopenharmony_ci asm volatile ( 188562306a36Sopenharmony_ci "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; " 188662306a36Sopenharmony_ci "swap %1 ; lslw #1,%1 ; roxlb #1,%0" 188762306a36Sopenharmony_ci : "=d" (color), "=d" (datawords) : "1" (datawords)); 188862306a36Sopenharmony_ci#else 188962306a36Sopenharmony_ci color = (((datawords >> 30) & 2) 189062306a36Sopenharmony_ci | ((datawords >> 15) & 1)); 189162306a36Sopenharmony_ci datawords <<= 1; 189262306a36Sopenharmony_ci#endif 189362306a36Sopenharmony_ci /* FIXME: check the return value + test the change */ 189462306a36Sopenharmony_ci put_user(color, data++); 189562306a36Sopenharmony_ci } 189662306a36Sopenharmony_ci if (bits > 0) { 189762306a36Sopenharmony_ci --words; ++lspr; 189862306a36Sopenharmony_ci } 189962306a36Sopenharmony_ci while (--words >= 0) 190062306a36Sopenharmony_ci ++lspr; 190162306a36Sopenharmony_ci#ifdef __mc68000__ 190262306a36Sopenharmony_ci asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" 190362306a36Sopenharmony_ci : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); 190462306a36Sopenharmony_ci#else 190562306a36Sopenharmony_ci lspr += delta; 190662306a36Sopenharmony_ci if (sspr) { 190762306a36Sopenharmony_ci u_short *tmp = lspr; 190862306a36Sopenharmony_ci lspr = sspr; 190962306a36Sopenharmony_ci sspr = tmp; 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci#endif 191262306a36Sopenharmony_ci } 191362306a36Sopenharmony_ci return 0; 191462306a36Sopenharmony_ci} 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_cistatic int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, 191762306a36Sopenharmony_ci u_char __user *data, struct amifb_par *par) 191862306a36Sopenharmony_ci{ 191962306a36Sopenharmony_ci register u_short *lspr, *sspr; 192062306a36Sopenharmony_ci#ifdef __mc68000__ 192162306a36Sopenharmony_ci register u_long datawords asm ("d2"); 192262306a36Sopenharmony_ci#else 192362306a36Sopenharmony_ci register u_long datawords; 192462306a36Sopenharmony_ci#endif 192562306a36Sopenharmony_ci register short delta; 192662306a36Sopenharmony_ci u_short fmode; 192762306a36Sopenharmony_ci short height, width, bits, words; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci if (!var->width) 193062306a36Sopenharmony_ci return -EINVAL; 193162306a36Sopenharmony_ci else if (var->width <= 16) 193262306a36Sopenharmony_ci fmode = TAG_FMODE_1; 193362306a36Sopenharmony_ci else if (var->width <= 32) 193462306a36Sopenharmony_ci fmode = TAG_FMODE_2; 193562306a36Sopenharmony_ci else if (var->width <= 64) 193662306a36Sopenharmony_ci fmode = TAG_FMODE_4; 193762306a36Sopenharmony_ci else 193862306a36Sopenharmony_ci return -EINVAL; 193962306a36Sopenharmony_ci if (fmode > maxfmode) 194062306a36Sopenharmony_ci return -EINVAL; 194162306a36Sopenharmony_ci if (!var->height) 194262306a36Sopenharmony_ci return -EINVAL; 194362306a36Sopenharmony_ci delta = 1 << fmode; 194462306a36Sopenharmony_ci lofsprite = shfsprite = (u_short *)spritememory; 194562306a36Sopenharmony_ci lspr = lofsprite + (delta << 1); 194662306a36Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) { 194762306a36Sopenharmony_ci if (((var->height + 4) << fmode << 2) > SPRITEMEMSIZE) 194862306a36Sopenharmony_ci return -EINVAL; 194962306a36Sopenharmony_ci memset(lspr, 0, (var->height + 4) << fmode << 2); 195062306a36Sopenharmony_ci shfsprite += ((var->height + 5)&-2) << fmode; 195162306a36Sopenharmony_ci sspr = shfsprite + (delta << 1); 195262306a36Sopenharmony_ci } else { 195362306a36Sopenharmony_ci if (((var->height + 2) << fmode << 2) > SPRITEMEMSIZE) 195462306a36Sopenharmony_ci return -EINVAL; 195562306a36Sopenharmony_ci memset(lspr, 0, (var->height + 2) << fmode << 2); 195662306a36Sopenharmony_ci sspr = NULL; 195762306a36Sopenharmony_ci } 195862306a36Sopenharmony_ci for (height = (short)var->height - 1; height >= 0; height--) { 195962306a36Sopenharmony_ci bits = 16; words = delta; datawords = 0; 196062306a36Sopenharmony_ci for (width = (short)var->width - 1; width >= 0; width--) { 196162306a36Sopenharmony_ci unsigned long tdata = 0; 196262306a36Sopenharmony_ci /* FIXME: check the return value + test the change */ 196362306a36Sopenharmony_ci get_user(tdata, data); 196462306a36Sopenharmony_ci data++; 196562306a36Sopenharmony_ci#ifdef __mc68000__ 196662306a36Sopenharmony_ci asm volatile ( 196762306a36Sopenharmony_ci "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; " 196862306a36Sopenharmony_ci "lsrb #1,%2 ; roxlw #1,%0 ; swap %0" 196962306a36Sopenharmony_ci : "=d" (datawords) 197062306a36Sopenharmony_ci : "0" (datawords), "d" (tdata)); 197162306a36Sopenharmony_ci#else 197262306a36Sopenharmony_ci datawords = ((datawords << 1) & 0xfffefffe); 197362306a36Sopenharmony_ci datawords |= tdata & 1; 197462306a36Sopenharmony_ci datawords |= (tdata & 2) << (16 - 1); 197562306a36Sopenharmony_ci#endif 197662306a36Sopenharmony_ci if (--bits == 0) { 197762306a36Sopenharmony_ci bits = 16; --words; 197862306a36Sopenharmony_ci#ifdef __mc68000__ 197962306a36Sopenharmony_ci asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+" 198062306a36Sopenharmony_ci : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta)); 198162306a36Sopenharmony_ci#else 198262306a36Sopenharmony_ci *(lspr + delta) = (u_short) (datawords >> 16); 198362306a36Sopenharmony_ci *lspr++ = (u_short) (datawords & 0xffff); 198462306a36Sopenharmony_ci#endif 198562306a36Sopenharmony_ci } 198662306a36Sopenharmony_ci } 198762306a36Sopenharmony_ci if (bits < 16) { 198862306a36Sopenharmony_ci --words; 198962306a36Sopenharmony_ci#ifdef __mc68000__ 199062306a36Sopenharmony_ci asm volatile ( 199162306a36Sopenharmony_ci "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; " 199262306a36Sopenharmony_ci "swap %2 ; lslw %4,%2 ; movew %2,%0@+" 199362306a36Sopenharmony_ci : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits)); 199462306a36Sopenharmony_ci#else 199562306a36Sopenharmony_ci *(lspr + delta) = (u_short) (datawords >> (16 + bits)); 199662306a36Sopenharmony_ci *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits); 199762306a36Sopenharmony_ci#endif 199862306a36Sopenharmony_ci } 199962306a36Sopenharmony_ci while (--words >= 0) { 200062306a36Sopenharmony_ci#ifdef __mc68000__ 200162306a36Sopenharmony_ci asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+" 200262306a36Sopenharmony_ci : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0"); 200362306a36Sopenharmony_ci#else 200462306a36Sopenharmony_ci *(lspr + delta) = 0; 200562306a36Sopenharmony_ci *lspr++ = 0; 200662306a36Sopenharmony_ci#endif 200762306a36Sopenharmony_ci } 200862306a36Sopenharmony_ci#ifdef __mc68000__ 200962306a36Sopenharmony_ci asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" 201062306a36Sopenharmony_ci : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); 201162306a36Sopenharmony_ci#else 201262306a36Sopenharmony_ci lspr += delta; 201362306a36Sopenharmony_ci if (sspr) { 201462306a36Sopenharmony_ci u_short *tmp = lspr; 201562306a36Sopenharmony_ci lspr = sspr; 201662306a36Sopenharmony_ci sspr = tmp; 201762306a36Sopenharmony_ci } 201862306a36Sopenharmony_ci#endif 201962306a36Sopenharmony_ci } 202062306a36Sopenharmony_ci par->crsr.height = var->height; 202162306a36Sopenharmony_ci par->crsr.width = var->width; 202262306a36Sopenharmony_ci par->crsr.spot_x = var->xspot; 202362306a36Sopenharmony_ci par->crsr.spot_y = var->yspot; 202462306a36Sopenharmony_ci par->crsr.fmode = fmode; 202562306a36Sopenharmony_ci if (IS_AGA) { 202662306a36Sopenharmony_ci par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32); 202762306a36Sopenharmony_ci par->fmode |= sprfetchmode[fmode]; 202862306a36Sopenharmony_ci custom.fmode = par->fmode; 202962306a36Sopenharmony_ci } 203062306a36Sopenharmony_ci return 0; 203162306a36Sopenharmony_ci} 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_cistatic int ami_get_cursorstate(struct fb_cursorstate *state, 203462306a36Sopenharmony_ci const struct amifb_par *par) 203562306a36Sopenharmony_ci{ 203662306a36Sopenharmony_ci state->xoffset = par->crsr.crsr_x; 203762306a36Sopenharmony_ci state->yoffset = par->crsr.crsr_y; 203862306a36Sopenharmony_ci state->mode = cursormode; 203962306a36Sopenharmony_ci return 0; 204062306a36Sopenharmony_ci} 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_cistatic int ami_set_cursorstate(struct fb_cursorstate *state, 204362306a36Sopenharmony_ci struct amifb_par *par) 204462306a36Sopenharmony_ci{ 204562306a36Sopenharmony_ci par->crsr.crsr_x = state->xoffset; 204662306a36Sopenharmony_ci par->crsr.crsr_y = state->yoffset; 204762306a36Sopenharmony_ci if ((cursormode = state->mode) == FB_CURSOR_OFF) 204862306a36Sopenharmony_ci cursorstate = -1; 204962306a36Sopenharmony_ci do_cursor = 1; 205062306a36Sopenharmony_ci return 0; 205162306a36Sopenharmony_ci} 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_cistatic void ami_set_sprite(const struct amifb_par *par) 205462306a36Sopenharmony_ci{ 205562306a36Sopenharmony_ci copins *copl, *cops; 205662306a36Sopenharmony_ci u_short hs, vs, ve; 205762306a36Sopenharmony_ci u_long pl, ps; 205862306a36Sopenharmony_ci short mx, my; 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci cops = copdisplay.list[currentcop][0]; 206162306a36Sopenharmony_ci copl = copdisplay.list[currentcop][1]; 206262306a36Sopenharmony_ci ps = pl = ZTWO_PADDR(dummysprite); 206362306a36Sopenharmony_ci mx = par->crsr.crsr_x - par->crsr.spot_x; 206462306a36Sopenharmony_ci my = par->crsr.crsr_y - par->crsr.spot_y; 206562306a36Sopenharmony_ci if (!(par->vmode & FB_VMODE_YWRAP)) { 206662306a36Sopenharmony_ci mx -= par->xoffset; 206762306a36Sopenharmony_ci my -= par->yoffset; 206862306a36Sopenharmony_ci } 206962306a36Sopenharmony_ci if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 && 207062306a36Sopenharmony_ci mx > -(short)par->crsr.width && mx < par->xres && 207162306a36Sopenharmony_ci my > -(short)par->crsr.height && my < par->yres) { 207262306a36Sopenharmony_ci pl = ZTWO_PADDR(lofsprite); 207362306a36Sopenharmony_ci hs = par->diwstrt_h + (mx << par->clk_shift) - 4; 207462306a36Sopenharmony_ci vs = par->diwstrt_v + (my << par->line_shift); 207562306a36Sopenharmony_ci ve = vs + (par->crsr.height << par->line_shift); 207662306a36Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) { 207762306a36Sopenharmony_ci ps = ZTWO_PADDR(shfsprite); 207862306a36Sopenharmony_ci lofsprite[0] = spr2hw_pos(vs, hs); 207962306a36Sopenharmony_ci shfsprite[0] = spr2hw_pos(vs + 1, hs); 208062306a36Sopenharmony_ci if (mod2(vs)) { 208162306a36Sopenharmony_ci lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); 208262306a36Sopenharmony_ci shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve + 1); 208362306a36Sopenharmony_ci swap(pl, ps); 208462306a36Sopenharmony_ci } else { 208562306a36Sopenharmony_ci lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve + 1); 208662306a36Sopenharmony_ci shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve); 208762306a36Sopenharmony_ci } 208862306a36Sopenharmony_ci } else { 208962306a36Sopenharmony_ci lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0); 209062306a36Sopenharmony_ci lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); 209162306a36Sopenharmony_ci } 209262306a36Sopenharmony_ci } 209362306a36Sopenharmony_ci copl[cop_spr0ptrh].w[1] = highw(pl); 209462306a36Sopenharmony_ci copl[cop_spr0ptrl].w[1] = loww(pl); 209562306a36Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) { 209662306a36Sopenharmony_ci cops[cop_spr0ptrh].w[1] = highw(ps); 209762306a36Sopenharmony_ci cops[cop_spr0ptrl].w[1] = loww(ps); 209862306a36Sopenharmony_ci } 209962306a36Sopenharmony_ci} 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci /* 210362306a36Sopenharmony_ci * Initialise the Copper Initialisation List 210462306a36Sopenharmony_ci */ 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_cistatic void __init ami_init_copper(void) 210762306a36Sopenharmony_ci{ 210862306a36Sopenharmony_ci copins *cop = copdisplay.init; 210962306a36Sopenharmony_ci u_long p; 211062306a36Sopenharmony_ci int i; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci if (!IS_OCS) { 211362306a36Sopenharmony_ci (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0); 211462306a36Sopenharmony_ci (cop++)->l = CMOVE(0x0181, diwstrt); 211562306a36Sopenharmony_ci (cop++)->l = CMOVE(0x0281, diwstop); 211662306a36Sopenharmony_ci (cop++)->l = CMOVE(0x0000, diwhigh); 211762306a36Sopenharmony_ci } else 211862306a36Sopenharmony_ci (cop++)->l = CMOVE(BPC0_COLOR, bplcon0); 211962306a36Sopenharmony_ci p = ZTWO_PADDR(dummysprite); 212062306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 212162306a36Sopenharmony_ci (cop++)->l = CMOVE(0, spr[i].pos); 212262306a36Sopenharmony_ci (cop++)->l = CMOVE(highw(p), sprpt[i]); 212362306a36Sopenharmony_ci (cop++)->l = CMOVE2(loww(p), sprpt[i]); 212462306a36Sopenharmony_ci } 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq); 212762306a36Sopenharmony_ci copdisplay.wait = cop; 212862306a36Sopenharmony_ci (cop++)->l = CEND; 212962306a36Sopenharmony_ci (cop++)->l = CMOVE(0, copjmp2); 213062306a36Sopenharmony_ci cop->l = CEND; 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init); 213362306a36Sopenharmony_ci custom.copjmp1 = 0; 213462306a36Sopenharmony_ci} 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_cistatic void ami_reinit_copper(const struct amifb_par *par) 213762306a36Sopenharmony_ci{ 213862306a36Sopenharmony_ci copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; 213962306a36Sopenharmony_ci copdisplay.wait->l = CWAIT(32, par->diwstrt_v - 4); 214062306a36Sopenharmony_ci} 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci /* 214462306a36Sopenharmony_ci * Rebuild the Copper List 214562306a36Sopenharmony_ci * 214662306a36Sopenharmony_ci * We only change the things that are not static 214762306a36Sopenharmony_ci */ 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_cistatic void ami_rebuild_copper(const struct amifb_par *par) 215062306a36Sopenharmony_ci{ 215162306a36Sopenharmony_ci copins *copl, *cops; 215262306a36Sopenharmony_ci u_short line, h_end1, h_end2; 215362306a36Sopenharmony_ci short i; 215462306a36Sopenharmony_ci u_long p; 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci if (IS_AGA && maxfmode + par->clk_shift == 0) 215762306a36Sopenharmony_ci h_end1 = par->diwstrt_h - 64; 215862306a36Sopenharmony_ci else 215962306a36Sopenharmony_ci h_end1 = par->htotal - 32; 216062306a36Sopenharmony_ci h_end2 = par->ddfstop + 64; 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci ami_set_sprite(par); 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci copl = copdisplay.rebuild[1]; 216562306a36Sopenharmony_ci p = par->bplpt0; 216662306a36Sopenharmony_ci if (par->vmode & FB_VMODE_YWRAP) { 216762306a36Sopenharmony_ci if ((par->vyres - par->yoffset) != 1 || !mod2(par->diwstrt_v)) { 216862306a36Sopenharmony_ci if (par->yoffset > par->vyres - par->yres) { 216962306a36Sopenharmony_ci for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { 217062306a36Sopenharmony_ci (copl++)->l = CMOVE(highw(p), bplpt[i]); 217162306a36Sopenharmony_ci (copl++)->l = CMOVE2(loww(p), bplpt[i]); 217262306a36Sopenharmony_ci } 217362306a36Sopenharmony_ci line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 1; 217462306a36Sopenharmony_ci while (line >= 512) { 217562306a36Sopenharmony_ci (copl++)->l = CWAIT(h_end1, 510); 217662306a36Sopenharmony_ci line -= 512; 217762306a36Sopenharmony_ci } 217862306a36Sopenharmony_ci if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0) 217962306a36Sopenharmony_ci (copl++)->l = CWAIT(h_end1, line); 218062306a36Sopenharmony_ci else 218162306a36Sopenharmony_ci (copl++)->l = CWAIT(h_end2, line); 218262306a36Sopenharmony_ci p = par->bplpt0wrap; 218362306a36Sopenharmony_ci } 218462306a36Sopenharmony_ci } else 218562306a36Sopenharmony_ci p = par->bplpt0wrap; 218662306a36Sopenharmony_ci } 218762306a36Sopenharmony_ci for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { 218862306a36Sopenharmony_ci (copl++)->l = CMOVE(highw(p), bplpt[i]); 218962306a36Sopenharmony_ci (copl++)->l = CMOVE2(loww(p), bplpt[i]); 219062306a36Sopenharmony_ci } 219162306a36Sopenharmony_ci copl->l = CEND; 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) { 219462306a36Sopenharmony_ci cops = copdisplay.rebuild[0]; 219562306a36Sopenharmony_ci p = par->bplpt0; 219662306a36Sopenharmony_ci if (mod2(par->diwstrt_v)) 219762306a36Sopenharmony_ci p -= par->next_line; 219862306a36Sopenharmony_ci else 219962306a36Sopenharmony_ci p += par->next_line; 220062306a36Sopenharmony_ci if (par->vmode & FB_VMODE_YWRAP) { 220162306a36Sopenharmony_ci if ((par->vyres - par->yoffset) != 1 || mod2(par->diwstrt_v)) { 220262306a36Sopenharmony_ci if (par->yoffset > par->vyres - par->yres + 1) { 220362306a36Sopenharmony_ci for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { 220462306a36Sopenharmony_ci (cops++)->l = CMOVE(highw(p), bplpt[i]); 220562306a36Sopenharmony_ci (cops++)->l = CMOVE2(loww(p), bplpt[i]); 220662306a36Sopenharmony_ci } 220762306a36Sopenharmony_ci line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 2; 220862306a36Sopenharmony_ci while (line >= 512) { 220962306a36Sopenharmony_ci (cops++)->l = CWAIT(h_end1, 510); 221062306a36Sopenharmony_ci line -= 512; 221162306a36Sopenharmony_ci } 221262306a36Sopenharmony_ci if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0) 221362306a36Sopenharmony_ci (cops++)->l = CWAIT(h_end1, line); 221462306a36Sopenharmony_ci else 221562306a36Sopenharmony_ci (cops++)->l = CWAIT(h_end2, line); 221662306a36Sopenharmony_ci p = par->bplpt0wrap; 221762306a36Sopenharmony_ci if (mod2(par->diwstrt_v + par->vyres - 221862306a36Sopenharmony_ci par->yoffset)) 221962306a36Sopenharmony_ci p -= par->next_line; 222062306a36Sopenharmony_ci else 222162306a36Sopenharmony_ci p += par->next_line; 222262306a36Sopenharmony_ci } 222362306a36Sopenharmony_ci } else 222462306a36Sopenharmony_ci p = par->bplpt0wrap - par->next_line; 222562306a36Sopenharmony_ci } 222662306a36Sopenharmony_ci for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { 222762306a36Sopenharmony_ci (cops++)->l = CMOVE(highw(p), bplpt[i]); 222862306a36Sopenharmony_ci (cops++)->l = CMOVE2(loww(p), bplpt[i]); 222962306a36Sopenharmony_ci } 223062306a36Sopenharmony_ci cops->l = CEND; 223162306a36Sopenharmony_ci } 223262306a36Sopenharmony_ci} 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci /* 223662306a36Sopenharmony_ci * Build the Copper List 223762306a36Sopenharmony_ci */ 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_cistatic void ami_build_copper(struct fb_info *info) 224062306a36Sopenharmony_ci{ 224162306a36Sopenharmony_ci struct amifb_par *par = info->par; 224262306a36Sopenharmony_ci copins *copl, *cops; 224362306a36Sopenharmony_ci u_long p; 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci currentcop = 1 - currentcop; 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci copl = copdisplay.list[currentcop][1]; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci (copl++)->l = CWAIT(0, 10); 225062306a36Sopenharmony_ci (copl++)->l = CMOVE(par->bplcon0, bplcon0); 225162306a36Sopenharmony_ci (copl++)->l = CMOVE(0, sprpt[0]); 225262306a36Sopenharmony_ci (copl++)->l = CMOVE2(0, sprpt[0]); 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci if (par->bplcon0 & BPC0_LACE) { 225562306a36Sopenharmony_ci cops = copdisplay.list[currentcop][0]; 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci (cops++)->l = CWAIT(0, 10); 225862306a36Sopenharmony_ci (cops++)->l = CMOVE(par->bplcon0, bplcon0); 225962306a36Sopenharmony_ci (cops++)->l = CMOVE(0, sprpt[0]); 226062306a36Sopenharmony_ci (cops++)->l = CMOVE2(0, sprpt[0]); 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v + 1), diwstrt); 226362306a36Sopenharmony_ci (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v + 1), diwstop); 226462306a36Sopenharmony_ci (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); 226562306a36Sopenharmony_ci (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); 226662306a36Sopenharmony_ci if (!IS_OCS) { 226762306a36Sopenharmony_ci (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v + 1, 226862306a36Sopenharmony_ci par->diwstop_h, par->diwstop_v + 1), diwhigh); 226962306a36Sopenharmony_ci (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, 227062306a36Sopenharmony_ci par->diwstop_h, par->diwstop_v), diwhigh); 227162306a36Sopenharmony_ci#if 0 227262306a36Sopenharmony_ci if (par->beamcon0 & BMC0_VARBEAMEN) { 227362306a36Sopenharmony_ci (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); 227462306a36Sopenharmony_ci (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt + 1), vbstrt); 227562306a36Sopenharmony_ci (copl++)->l = CMOVE(vbstop2hw(par->vbstop + 1), vbstop); 227662306a36Sopenharmony_ci (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); 227762306a36Sopenharmony_ci (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); 227862306a36Sopenharmony_ci (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); 227962306a36Sopenharmony_ci } 228062306a36Sopenharmony_ci#endif 228162306a36Sopenharmony_ci } 228262306a36Sopenharmony_ci p = ZTWO_PADDR(copdisplay.list[currentcop][0]); 228362306a36Sopenharmony_ci (copl++)->l = CMOVE(highw(p), cop2lc); 228462306a36Sopenharmony_ci (copl++)->l = CMOVE2(loww(p), cop2lc); 228562306a36Sopenharmony_ci p = ZTWO_PADDR(copdisplay.list[currentcop][1]); 228662306a36Sopenharmony_ci (cops++)->l = CMOVE(highw(p), cop2lc); 228762306a36Sopenharmony_ci (cops++)->l = CMOVE2(loww(p), cop2lc); 228862306a36Sopenharmony_ci copdisplay.rebuild[0] = cops; 228962306a36Sopenharmony_ci } else { 229062306a36Sopenharmony_ci (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); 229162306a36Sopenharmony_ci (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); 229262306a36Sopenharmony_ci if (!IS_OCS) { 229362306a36Sopenharmony_ci (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, 229462306a36Sopenharmony_ci par->diwstop_h, par->diwstop_v), diwhigh); 229562306a36Sopenharmony_ci#if 0 229662306a36Sopenharmony_ci if (par->beamcon0 & BMC0_VARBEAMEN) { 229762306a36Sopenharmony_ci (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); 229862306a36Sopenharmony_ci (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); 229962306a36Sopenharmony_ci (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); 230062306a36Sopenharmony_ci } 230162306a36Sopenharmony_ci#endif 230262306a36Sopenharmony_ci } 230362306a36Sopenharmony_ci } 230462306a36Sopenharmony_ci copdisplay.rebuild[1] = copl; 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ci ami_update_par(info); 230762306a36Sopenharmony_ci ami_rebuild_copper(info->par); 230862306a36Sopenharmony_ci} 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci#ifndef MODULE 231162306a36Sopenharmony_cistatic void __init amifb_setup_mcap(char *spec) 231262306a36Sopenharmony_ci{ 231362306a36Sopenharmony_ci char *p; 231462306a36Sopenharmony_ci int vmin, vmax, hmin, hmax; 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax> 231762306a36Sopenharmony_ci * <V*> vertical freq. in Hz 231862306a36Sopenharmony_ci * <H*> horizontal freq. in kHz 231962306a36Sopenharmony_ci */ 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci if (!(p = strsep(&spec, ";")) || !*p) 232262306a36Sopenharmony_ci return; 232362306a36Sopenharmony_ci vmin = simple_strtoul(p, NULL, 10); 232462306a36Sopenharmony_ci if (vmin <= 0) 232562306a36Sopenharmony_ci return; 232662306a36Sopenharmony_ci if (!(p = strsep(&spec, ";")) || !*p) 232762306a36Sopenharmony_ci return; 232862306a36Sopenharmony_ci vmax = simple_strtoul(p, NULL, 10); 232962306a36Sopenharmony_ci if (vmax <= 0 || vmax <= vmin) 233062306a36Sopenharmony_ci return; 233162306a36Sopenharmony_ci if (!(p = strsep(&spec, ";")) || !*p) 233262306a36Sopenharmony_ci return; 233362306a36Sopenharmony_ci hmin = 1000 * simple_strtoul(p, NULL, 10); 233462306a36Sopenharmony_ci if (hmin <= 0) 233562306a36Sopenharmony_ci return; 233662306a36Sopenharmony_ci if (!(p = strsep(&spec, "")) || !*p) 233762306a36Sopenharmony_ci return; 233862306a36Sopenharmony_ci hmax = 1000 * simple_strtoul(p, NULL, 10); 233962306a36Sopenharmony_ci if (hmax <= 0 || hmax <= hmin) 234062306a36Sopenharmony_ci return; 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_ci amifb_hfmin = hmin; 234362306a36Sopenharmony_ci amifb_hfmax = hmax; 234462306a36Sopenharmony_ci amifb_vfmin = vmin; 234562306a36Sopenharmony_ci amifb_vfmax = vmax; 234662306a36Sopenharmony_ci} 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_cistatic int __init amifb_setup(char *options) 234962306a36Sopenharmony_ci{ 235062306a36Sopenharmony_ci char *this_opt; 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci if (!options || !*options) 235362306a36Sopenharmony_ci return 0; 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci while ((this_opt = strsep(&options, ",")) != NULL) { 235662306a36Sopenharmony_ci if (!*this_opt) 235762306a36Sopenharmony_ci continue; 235862306a36Sopenharmony_ci if (!strcmp(this_opt, "inverse")) { 235962306a36Sopenharmony_ci fb_invert_cmaps(); 236062306a36Sopenharmony_ci } else if (!strcmp(this_opt, "ilbm")) 236162306a36Sopenharmony_ci amifb_ilbm = 1; 236262306a36Sopenharmony_ci else if (!strncmp(this_opt, "monitorcap:", 11)) 236362306a36Sopenharmony_ci amifb_setup_mcap(this_opt + 11); 236462306a36Sopenharmony_ci else if (!strncmp(this_opt, "fstart:", 7)) 236562306a36Sopenharmony_ci min_fstrt = simple_strtoul(this_opt + 7, NULL, 0); 236662306a36Sopenharmony_ci else 236762306a36Sopenharmony_ci mode_option = this_opt; 236862306a36Sopenharmony_ci } 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci if (min_fstrt < 48) 237162306a36Sopenharmony_ci min_fstrt = 48; 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci return 0; 237462306a36Sopenharmony_ci} 237562306a36Sopenharmony_ci#endif 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_cistatic int amifb_check_var(struct fb_var_screeninfo *var, 237862306a36Sopenharmony_ci struct fb_info *info) 237962306a36Sopenharmony_ci{ 238062306a36Sopenharmony_ci int err; 238162306a36Sopenharmony_ci struct amifb_par par; 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_ci /* Validate wanted screen parameters */ 238462306a36Sopenharmony_ci err = ami_decode_var(var, &par, info); 238562306a36Sopenharmony_ci if (err) 238662306a36Sopenharmony_ci return err; 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci /* Encode (possibly rounded) screen parameters */ 238962306a36Sopenharmony_ci ami_encode_var(var, &par); 239062306a36Sopenharmony_ci return 0; 239162306a36Sopenharmony_ci} 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_cistatic int amifb_set_par(struct fb_info *info) 239562306a36Sopenharmony_ci{ 239662306a36Sopenharmony_ci struct amifb_par *par = info->par; 239762306a36Sopenharmony_ci int error; 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci do_vmode_pan = 0; 240062306a36Sopenharmony_ci do_vmode_full = 0; 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci /* Decode wanted screen parameters */ 240362306a36Sopenharmony_ci error = ami_decode_var(&info->var, par, info); 240462306a36Sopenharmony_ci if (error) 240562306a36Sopenharmony_ci return error; 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci /* Set new videomode */ 240862306a36Sopenharmony_ci ami_build_copper(info); 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci /* Set VBlank trigger */ 241162306a36Sopenharmony_ci do_vmode_full = 1; 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci /* Update fix for new screen parameters */ 241462306a36Sopenharmony_ci if (par->bpp == 1) { 241562306a36Sopenharmony_ci info->fix.type = FB_TYPE_PACKED_PIXELS; 241662306a36Sopenharmony_ci info->fix.type_aux = 0; 241762306a36Sopenharmony_ci } else if (amifb_ilbm) { 241862306a36Sopenharmony_ci info->fix.type = FB_TYPE_INTERLEAVED_PLANES; 241962306a36Sopenharmony_ci info->fix.type_aux = par->next_line; 242062306a36Sopenharmony_ci } else { 242162306a36Sopenharmony_ci info->fix.type = FB_TYPE_PLANES; 242262306a36Sopenharmony_ci info->fix.type_aux = 0; 242362306a36Sopenharmony_ci } 242462306a36Sopenharmony_ci info->fix.line_length = div8(upx(16 << maxfmode, par->vxres)); 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci if (par->vmode & FB_VMODE_YWRAP) { 242762306a36Sopenharmony_ci info->fix.ywrapstep = 1; 242862306a36Sopenharmony_ci info->fix.xpanstep = 0; 242962306a36Sopenharmony_ci info->fix.ypanstep = 0; 243062306a36Sopenharmony_ci info->flags = FBINFO_HWACCEL_YWRAP | 243162306a36Sopenharmony_ci FBINFO_READS_FAST; /* override SCROLL_REDRAW */ 243262306a36Sopenharmony_ci } else { 243362306a36Sopenharmony_ci info->fix.ywrapstep = 0; 243462306a36Sopenharmony_ci if (par->vmode & FB_VMODE_SMOOTH_XPAN) 243562306a36Sopenharmony_ci info->fix.xpanstep = 1; 243662306a36Sopenharmony_ci else 243762306a36Sopenharmony_ci info->fix.xpanstep = 16 << maxfmode; 243862306a36Sopenharmony_ci info->fix.ypanstep = 1; 243962306a36Sopenharmony_ci info->flags = FBINFO_HWACCEL_YPAN; 244062306a36Sopenharmony_ci } 244162306a36Sopenharmony_ci return 0; 244262306a36Sopenharmony_ci} 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci 244562306a36Sopenharmony_ci /* 244662306a36Sopenharmony_ci * Set a single color register. The values supplied are already 244762306a36Sopenharmony_ci * rounded down to the hardware's capabilities (according to the 244862306a36Sopenharmony_ci * entries in the var structure). Return != 0 for invalid regno. 244962306a36Sopenharmony_ci */ 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_cistatic int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 245262306a36Sopenharmony_ci u_int transp, struct fb_info *info) 245362306a36Sopenharmony_ci{ 245462306a36Sopenharmony_ci const struct amifb_par *par = info->par; 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci if (IS_AGA) { 245762306a36Sopenharmony_ci if (regno > 255) 245862306a36Sopenharmony_ci return 1; 245962306a36Sopenharmony_ci } else if (par->bplcon0 & BPC0_SHRES) { 246062306a36Sopenharmony_ci if (regno > 3) 246162306a36Sopenharmony_ci return 1; 246262306a36Sopenharmony_ci } else { 246362306a36Sopenharmony_ci if (regno > 31) 246462306a36Sopenharmony_ci return 1; 246562306a36Sopenharmony_ci } 246662306a36Sopenharmony_ci red >>= 8; 246762306a36Sopenharmony_ci green >>= 8; 246862306a36Sopenharmony_ci blue >>= 8; 246962306a36Sopenharmony_ci if (!regno) { 247062306a36Sopenharmony_ci red0 = red; 247162306a36Sopenharmony_ci green0 = green; 247262306a36Sopenharmony_ci blue0 = blue; 247362306a36Sopenharmony_ci } 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci /* 247662306a36Sopenharmony_ci * Update the corresponding Hardware Color Register, unless it's Color 247762306a36Sopenharmony_ci * Register 0 and the screen is blanked. 247862306a36Sopenharmony_ci * 247962306a36Sopenharmony_ci * VBlank is switched off to protect bplcon3 or ecs_palette[] from 248062306a36Sopenharmony_ci * being changed by ami_do_blank() during the VBlank. 248162306a36Sopenharmony_ci */ 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci if (regno || !is_blanked) { 248462306a36Sopenharmony_ci#if defined(CONFIG_FB_AMIGA_AGA) 248562306a36Sopenharmony_ci if (IS_AGA) { 248662306a36Sopenharmony_ci u_short bplcon3 = par->bplcon3; 248762306a36Sopenharmony_ci VBlankOff(); 248862306a36Sopenharmony_ci custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000); 248962306a36Sopenharmony_ci custom.color[regno & 31] = rgb2hw8_high(red, green, 249062306a36Sopenharmony_ci blue); 249162306a36Sopenharmony_ci custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000) | 249262306a36Sopenharmony_ci BPC3_LOCT; 249362306a36Sopenharmony_ci custom.color[regno & 31] = rgb2hw8_low(red, green, 249462306a36Sopenharmony_ci blue); 249562306a36Sopenharmony_ci custom.bplcon3 = bplcon3; 249662306a36Sopenharmony_ci VBlankOn(); 249762306a36Sopenharmony_ci } else 249862306a36Sopenharmony_ci#endif 249962306a36Sopenharmony_ci#if defined(CONFIG_FB_AMIGA_ECS) 250062306a36Sopenharmony_ci if (par->bplcon0 & BPC0_SHRES) { 250162306a36Sopenharmony_ci u_short color, mask; 250262306a36Sopenharmony_ci int i; 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci mask = 0x3333; 250562306a36Sopenharmony_ci color = rgb2hw2(red, green, blue); 250662306a36Sopenharmony_ci VBlankOff(); 250762306a36Sopenharmony_ci for (i = regno + 12; i >= (int)regno; i -= 4) 250862306a36Sopenharmony_ci custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; 250962306a36Sopenharmony_ci mask <<= 2; color >>= 2; 251062306a36Sopenharmony_ci regno = down16(regno) + mul4(mod4(regno)); 251162306a36Sopenharmony_ci for (i = regno + 3; i >= (int)regno; i--) 251262306a36Sopenharmony_ci custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; 251362306a36Sopenharmony_ci VBlankOn(); 251462306a36Sopenharmony_ci } else 251562306a36Sopenharmony_ci#endif 251662306a36Sopenharmony_ci custom.color[regno] = rgb2hw4(red, green, blue); 251762306a36Sopenharmony_ci } 251862306a36Sopenharmony_ci return 0; 251962306a36Sopenharmony_ci} 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci /* 252362306a36Sopenharmony_ci * Blank the display. 252462306a36Sopenharmony_ci */ 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_cistatic int amifb_blank(int blank, struct fb_info *info) 252762306a36Sopenharmony_ci{ 252862306a36Sopenharmony_ci do_blank = blank ? blank : -1; 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci return 0; 253162306a36Sopenharmony_ci} 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_ci /* 253562306a36Sopenharmony_ci * Pan or Wrap the Display 253662306a36Sopenharmony_ci * 253762306a36Sopenharmony_ci * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag 253862306a36Sopenharmony_ci */ 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_cistatic int amifb_pan_display(struct fb_var_screeninfo *var, 254162306a36Sopenharmony_ci struct fb_info *info) 254262306a36Sopenharmony_ci{ 254362306a36Sopenharmony_ci if (!(var->vmode & FB_VMODE_YWRAP)) { 254462306a36Sopenharmony_ci /* 254562306a36Sopenharmony_ci * TODO: There will be problems when xpan!=1, so some columns 254662306a36Sopenharmony_ci * on the right side will never be seen 254762306a36Sopenharmony_ci */ 254862306a36Sopenharmony_ci if (var->xoffset + info->var.xres > 254962306a36Sopenharmony_ci upx(16 << maxfmode, info->var.xres_virtual)) 255062306a36Sopenharmony_ci return -EINVAL; 255162306a36Sopenharmony_ci } 255262306a36Sopenharmony_ci ami_pan_var(var, info); 255362306a36Sopenharmony_ci return 0; 255462306a36Sopenharmony_ci} 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci#if BITS_PER_LONG == 32 255862306a36Sopenharmony_ci#define BYTES_PER_LONG 4 255962306a36Sopenharmony_ci#define SHIFT_PER_LONG 5 256062306a36Sopenharmony_ci#elif BITS_PER_LONG == 64 256162306a36Sopenharmony_ci#define BYTES_PER_LONG 8 256262306a36Sopenharmony_ci#define SHIFT_PER_LONG 6 256362306a36Sopenharmony_ci#else 256462306a36Sopenharmony_ci#define Please update me 256562306a36Sopenharmony_ci#endif 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci /* 256962306a36Sopenharmony_ci * Compose two values, using a bitmask as decision value 257062306a36Sopenharmony_ci * This is equivalent to (a & mask) | (b & ~mask) 257162306a36Sopenharmony_ci */ 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_cistatic inline unsigned long comp(unsigned long a, unsigned long b, 257462306a36Sopenharmony_ci unsigned long mask) 257562306a36Sopenharmony_ci{ 257662306a36Sopenharmony_ci return ((a ^ b) & mask) ^ b; 257762306a36Sopenharmony_ci} 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_cistatic inline unsigned long xor(unsigned long a, unsigned long b, 258162306a36Sopenharmony_ci unsigned long mask) 258262306a36Sopenharmony_ci{ 258362306a36Sopenharmony_ci return (a & mask) ^ b; 258462306a36Sopenharmony_ci} 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci /* 258862306a36Sopenharmony_ci * Unaligned forward bit copy using 32-bit or 64-bit memory accesses 258962306a36Sopenharmony_ci */ 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_cistatic void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, 259262306a36Sopenharmony_ci int src_idx, u32 n) 259362306a36Sopenharmony_ci{ 259462306a36Sopenharmony_ci unsigned long first, last; 259562306a36Sopenharmony_ci int shift = dst_idx - src_idx, left, right; 259662306a36Sopenharmony_ci unsigned long d0, d1; 259762306a36Sopenharmony_ci int m; 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci if (!n) 260062306a36Sopenharmony_ci return; 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci shift = dst_idx - src_idx; 260362306a36Sopenharmony_ci first = ~0UL >> dst_idx; 260462306a36Sopenharmony_ci last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci if (!shift) { 260762306a36Sopenharmony_ci // Same alignment for source and dest 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci if (dst_idx + n <= BITS_PER_LONG) { 261062306a36Sopenharmony_ci // Single word 261162306a36Sopenharmony_ci if (last) 261262306a36Sopenharmony_ci first &= last; 261362306a36Sopenharmony_ci *dst = comp(*src, *dst, first); 261462306a36Sopenharmony_ci } else { 261562306a36Sopenharmony_ci // Multiple destination words 261662306a36Sopenharmony_ci // Leading bits 261762306a36Sopenharmony_ci if (first) { 261862306a36Sopenharmony_ci *dst = comp(*src, *dst, first); 261962306a36Sopenharmony_ci dst++; 262062306a36Sopenharmony_ci src++; 262162306a36Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 262262306a36Sopenharmony_ci } 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci // Main chunk 262562306a36Sopenharmony_ci n /= BITS_PER_LONG; 262662306a36Sopenharmony_ci while (n >= 8) { 262762306a36Sopenharmony_ci *dst++ = *src++; 262862306a36Sopenharmony_ci *dst++ = *src++; 262962306a36Sopenharmony_ci *dst++ = *src++; 263062306a36Sopenharmony_ci *dst++ = *src++; 263162306a36Sopenharmony_ci *dst++ = *src++; 263262306a36Sopenharmony_ci *dst++ = *src++; 263362306a36Sopenharmony_ci *dst++ = *src++; 263462306a36Sopenharmony_ci *dst++ = *src++; 263562306a36Sopenharmony_ci n -= 8; 263662306a36Sopenharmony_ci } 263762306a36Sopenharmony_ci while (n--) 263862306a36Sopenharmony_ci *dst++ = *src++; 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci // Trailing bits 264162306a36Sopenharmony_ci if (last) 264262306a36Sopenharmony_ci *dst = comp(*src, *dst, last); 264362306a36Sopenharmony_ci } 264462306a36Sopenharmony_ci } else { 264562306a36Sopenharmony_ci // Different alignment for source and dest 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_ci right = shift & (BITS_PER_LONG - 1); 264862306a36Sopenharmony_ci left = -shift & (BITS_PER_LONG - 1); 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci if (dst_idx + n <= BITS_PER_LONG) { 265162306a36Sopenharmony_ci // Single destination word 265262306a36Sopenharmony_ci if (last) 265362306a36Sopenharmony_ci first &= last; 265462306a36Sopenharmony_ci if (shift > 0) { 265562306a36Sopenharmony_ci // Single source word 265662306a36Sopenharmony_ci *dst = comp(*src >> right, *dst, first); 265762306a36Sopenharmony_ci } else if (src_idx + n <= BITS_PER_LONG) { 265862306a36Sopenharmony_ci // Single source word 265962306a36Sopenharmony_ci *dst = comp(*src << left, *dst, first); 266062306a36Sopenharmony_ci } else { 266162306a36Sopenharmony_ci // 2 source words 266262306a36Sopenharmony_ci d0 = *src++; 266362306a36Sopenharmony_ci d1 = *src; 266462306a36Sopenharmony_ci *dst = comp(d0 << left | d1 >> right, *dst, 266562306a36Sopenharmony_ci first); 266662306a36Sopenharmony_ci } 266762306a36Sopenharmony_ci } else { 266862306a36Sopenharmony_ci // Multiple destination words 266962306a36Sopenharmony_ci d0 = *src++; 267062306a36Sopenharmony_ci // Leading bits 267162306a36Sopenharmony_ci if (shift > 0) { 267262306a36Sopenharmony_ci // Single source word 267362306a36Sopenharmony_ci *dst = comp(d0 >> right, *dst, first); 267462306a36Sopenharmony_ci dst++; 267562306a36Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 267662306a36Sopenharmony_ci } else { 267762306a36Sopenharmony_ci // 2 source words 267862306a36Sopenharmony_ci d1 = *src++; 267962306a36Sopenharmony_ci *dst = comp(d0 << left | d1 >> right, *dst, 268062306a36Sopenharmony_ci first); 268162306a36Sopenharmony_ci d0 = d1; 268262306a36Sopenharmony_ci dst++; 268362306a36Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 268462306a36Sopenharmony_ci } 268562306a36Sopenharmony_ci 268662306a36Sopenharmony_ci // Main chunk 268762306a36Sopenharmony_ci m = n % BITS_PER_LONG; 268862306a36Sopenharmony_ci n /= BITS_PER_LONG; 268962306a36Sopenharmony_ci while (n >= 4) { 269062306a36Sopenharmony_ci d1 = *src++; 269162306a36Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 269262306a36Sopenharmony_ci d0 = d1; 269362306a36Sopenharmony_ci d1 = *src++; 269462306a36Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 269562306a36Sopenharmony_ci d0 = d1; 269662306a36Sopenharmony_ci d1 = *src++; 269762306a36Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 269862306a36Sopenharmony_ci d0 = d1; 269962306a36Sopenharmony_ci d1 = *src++; 270062306a36Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 270162306a36Sopenharmony_ci d0 = d1; 270262306a36Sopenharmony_ci n -= 4; 270362306a36Sopenharmony_ci } 270462306a36Sopenharmony_ci while (n--) { 270562306a36Sopenharmony_ci d1 = *src++; 270662306a36Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 270762306a36Sopenharmony_ci d0 = d1; 270862306a36Sopenharmony_ci } 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci // Trailing bits 271162306a36Sopenharmony_ci if (last) { 271262306a36Sopenharmony_ci if (m <= right) { 271362306a36Sopenharmony_ci // Single source word 271462306a36Sopenharmony_ci *dst = comp(d0 << left, *dst, last); 271562306a36Sopenharmony_ci } else { 271662306a36Sopenharmony_ci // 2 source words 271762306a36Sopenharmony_ci d1 = *src; 271862306a36Sopenharmony_ci *dst = comp(d0 << left | d1 >> right, 271962306a36Sopenharmony_ci *dst, last); 272062306a36Sopenharmony_ci } 272162306a36Sopenharmony_ci } 272262306a36Sopenharmony_ci } 272362306a36Sopenharmony_ci } 272462306a36Sopenharmony_ci} 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci /* 272862306a36Sopenharmony_ci * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses 272962306a36Sopenharmony_ci */ 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_cistatic void bitcpy_rev(unsigned long *dst, int dst_idx, 273262306a36Sopenharmony_ci const unsigned long *src, int src_idx, u32 n) 273362306a36Sopenharmony_ci{ 273462306a36Sopenharmony_ci unsigned long first, last; 273562306a36Sopenharmony_ci int shift = dst_idx - src_idx, left, right; 273662306a36Sopenharmony_ci unsigned long d0, d1; 273762306a36Sopenharmony_ci int m; 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci if (!n) 274062306a36Sopenharmony_ci return; 274162306a36Sopenharmony_ci 274262306a36Sopenharmony_ci dst += (n - 1) / BITS_PER_LONG; 274362306a36Sopenharmony_ci src += (n - 1) / BITS_PER_LONG; 274462306a36Sopenharmony_ci if ((n - 1) % BITS_PER_LONG) { 274562306a36Sopenharmony_ci dst_idx += (n - 1) % BITS_PER_LONG; 274662306a36Sopenharmony_ci dst += dst_idx >> SHIFT_PER_LONG; 274762306a36Sopenharmony_ci dst_idx &= BITS_PER_LONG - 1; 274862306a36Sopenharmony_ci src_idx += (n - 1) % BITS_PER_LONG; 274962306a36Sopenharmony_ci src += src_idx >> SHIFT_PER_LONG; 275062306a36Sopenharmony_ci src_idx &= BITS_PER_LONG - 1; 275162306a36Sopenharmony_ci } 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci shift = dst_idx - src_idx; 275462306a36Sopenharmony_ci first = ~0UL << (BITS_PER_LONG - 1 - dst_idx); 275562306a36Sopenharmony_ci last = ~(~0UL << (BITS_PER_LONG - 1 - ((dst_idx - n) % BITS_PER_LONG))); 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci if (!shift) { 275862306a36Sopenharmony_ci // Same alignment for source and dest 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci if ((unsigned long)dst_idx + 1 >= n) { 276162306a36Sopenharmony_ci // Single word 276262306a36Sopenharmony_ci if (last) 276362306a36Sopenharmony_ci first &= last; 276462306a36Sopenharmony_ci *dst = comp(*src, *dst, first); 276562306a36Sopenharmony_ci } else { 276662306a36Sopenharmony_ci // Multiple destination words 276762306a36Sopenharmony_ci // Leading bits 276862306a36Sopenharmony_ci if (first) { 276962306a36Sopenharmony_ci *dst = comp(*src, *dst, first); 277062306a36Sopenharmony_ci dst--; 277162306a36Sopenharmony_ci src--; 277262306a36Sopenharmony_ci n -= dst_idx + 1; 277362306a36Sopenharmony_ci } 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci // Main chunk 277662306a36Sopenharmony_ci n /= BITS_PER_LONG; 277762306a36Sopenharmony_ci while (n >= 8) { 277862306a36Sopenharmony_ci *dst-- = *src--; 277962306a36Sopenharmony_ci *dst-- = *src--; 278062306a36Sopenharmony_ci *dst-- = *src--; 278162306a36Sopenharmony_ci *dst-- = *src--; 278262306a36Sopenharmony_ci *dst-- = *src--; 278362306a36Sopenharmony_ci *dst-- = *src--; 278462306a36Sopenharmony_ci *dst-- = *src--; 278562306a36Sopenharmony_ci *dst-- = *src--; 278662306a36Sopenharmony_ci n -= 8; 278762306a36Sopenharmony_ci } 278862306a36Sopenharmony_ci while (n--) 278962306a36Sopenharmony_ci *dst-- = *src--; 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci // Trailing bits 279262306a36Sopenharmony_ci if (last) 279362306a36Sopenharmony_ci *dst = comp(*src, *dst, last); 279462306a36Sopenharmony_ci } 279562306a36Sopenharmony_ci } else { 279662306a36Sopenharmony_ci // Different alignment for source and dest 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_ci right = shift & (BITS_PER_LONG - 1); 279962306a36Sopenharmony_ci left = -shift & (BITS_PER_LONG - 1); 280062306a36Sopenharmony_ci 280162306a36Sopenharmony_ci if ((unsigned long)dst_idx + 1 >= n) { 280262306a36Sopenharmony_ci // Single destination word 280362306a36Sopenharmony_ci if (last) 280462306a36Sopenharmony_ci first &= last; 280562306a36Sopenharmony_ci if (shift < 0) { 280662306a36Sopenharmony_ci // Single source word 280762306a36Sopenharmony_ci *dst = comp(*src << left, *dst, first); 280862306a36Sopenharmony_ci } else if (1 + (unsigned long)src_idx >= n) { 280962306a36Sopenharmony_ci // Single source word 281062306a36Sopenharmony_ci *dst = comp(*src >> right, *dst, first); 281162306a36Sopenharmony_ci } else { 281262306a36Sopenharmony_ci // 2 source words 281362306a36Sopenharmony_ci d0 = *src--; 281462306a36Sopenharmony_ci d1 = *src; 281562306a36Sopenharmony_ci *dst = comp(d0 >> right | d1 << left, *dst, 281662306a36Sopenharmony_ci first); 281762306a36Sopenharmony_ci } 281862306a36Sopenharmony_ci } else { 281962306a36Sopenharmony_ci // Multiple destination words 282062306a36Sopenharmony_ci d0 = *src--; 282162306a36Sopenharmony_ci // Leading bits 282262306a36Sopenharmony_ci if (shift < 0) { 282362306a36Sopenharmony_ci // Single source word 282462306a36Sopenharmony_ci *dst = comp(d0 << left, *dst, first); 282562306a36Sopenharmony_ci dst--; 282662306a36Sopenharmony_ci n -= dst_idx + 1; 282762306a36Sopenharmony_ci } else { 282862306a36Sopenharmony_ci // 2 source words 282962306a36Sopenharmony_ci d1 = *src--; 283062306a36Sopenharmony_ci *dst = comp(d0 >> right | d1 << left, *dst, 283162306a36Sopenharmony_ci first); 283262306a36Sopenharmony_ci d0 = d1; 283362306a36Sopenharmony_ci dst--; 283462306a36Sopenharmony_ci n -= dst_idx + 1; 283562306a36Sopenharmony_ci } 283662306a36Sopenharmony_ci 283762306a36Sopenharmony_ci // Main chunk 283862306a36Sopenharmony_ci m = n % BITS_PER_LONG; 283962306a36Sopenharmony_ci n /= BITS_PER_LONG; 284062306a36Sopenharmony_ci while (n >= 4) { 284162306a36Sopenharmony_ci d1 = *src--; 284262306a36Sopenharmony_ci *dst-- = d0 >> right | d1 << left; 284362306a36Sopenharmony_ci d0 = d1; 284462306a36Sopenharmony_ci d1 = *src--; 284562306a36Sopenharmony_ci *dst-- = d0 >> right | d1 << left; 284662306a36Sopenharmony_ci d0 = d1; 284762306a36Sopenharmony_ci d1 = *src--; 284862306a36Sopenharmony_ci *dst-- = d0 >> right | d1 << left; 284962306a36Sopenharmony_ci d0 = d1; 285062306a36Sopenharmony_ci d1 = *src--; 285162306a36Sopenharmony_ci *dst-- = d0 >> right | d1 << left; 285262306a36Sopenharmony_ci d0 = d1; 285362306a36Sopenharmony_ci n -= 4; 285462306a36Sopenharmony_ci } 285562306a36Sopenharmony_ci while (n--) { 285662306a36Sopenharmony_ci d1 = *src--; 285762306a36Sopenharmony_ci *dst-- = d0 >> right | d1 << left; 285862306a36Sopenharmony_ci d0 = d1; 285962306a36Sopenharmony_ci } 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci // Trailing bits 286262306a36Sopenharmony_ci if (last) { 286362306a36Sopenharmony_ci if (m <= left) { 286462306a36Sopenharmony_ci // Single source word 286562306a36Sopenharmony_ci *dst = comp(d0 >> right, *dst, last); 286662306a36Sopenharmony_ci } else { 286762306a36Sopenharmony_ci // 2 source words 286862306a36Sopenharmony_ci d1 = *src; 286962306a36Sopenharmony_ci *dst = comp(d0 >> right | d1 << left, 287062306a36Sopenharmony_ci *dst, last); 287162306a36Sopenharmony_ci } 287262306a36Sopenharmony_ci } 287362306a36Sopenharmony_ci } 287462306a36Sopenharmony_ci } 287562306a36Sopenharmony_ci} 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci /* 287962306a36Sopenharmony_ci * Unaligned forward inverting bit copy using 32-bit or 64-bit memory 288062306a36Sopenharmony_ci * accesses 288162306a36Sopenharmony_ci */ 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_cistatic void bitcpy_not(unsigned long *dst, int dst_idx, 288462306a36Sopenharmony_ci const unsigned long *src, int src_idx, u32 n) 288562306a36Sopenharmony_ci{ 288662306a36Sopenharmony_ci unsigned long first, last; 288762306a36Sopenharmony_ci int shift = dst_idx - src_idx, left, right; 288862306a36Sopenharmony_ci unsigned long d0, d1; 288962306a36Sopenharmony_ci int m; 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci if (!n) 289262306a36Sopenharmony_ci return; 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci shift = dst_idx - src_idx; 289562306a36Sopenharmony_ci first = ~0UL >> dst_idx; 289662306a36Sopenharmony_ci last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci if (!shift) { 289962306a36Sopenharmony_ci // Same alignment for source and dest 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_ci if (dst_idx + n <= BITS_PER_LONG) { 290262306a36Sopenharmony_ci // Single word 290362306a36Sopenharmony_ci if (last) 290462306a36Sopenharmony_ci first &= last; 290562306a36Sopenharmony_ci *dst = comp(~*src, *dst, first); 290662306a36Sopenharmony_ci } else { 290762306a36Sopenharmony_ci // Multiple destination words 290862306a36Sopenharmony_ci // Leading bits 290962306a36Sopenharmony_ci if (first) { 291062306a36Sopenharmony_ci *dst = comp(~*src, *dst, first); 291162306a36Sopenharmony_ci dst++; 291262306a36Sopenharmony_ci src++; 291362306a36Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 291462306a36Sopenharmony_ci } 291562306a36Sopenharmony_ci 291662306a36Sopenharmony_ci // Main chunk 291762306a36Sopenharmony_ci n /= BITS_PER_LONG; 291862306a36Sopenharmony_ci while (n >= 8) { 291962306a36Sopenharmony_ci *dst++ = ~*src++; 292062306a36Sopenharmony_ci *dst++ = ~*src++; 292162306a36Sopenharmony_ci *dst++ = ~*src++; 292262306a36Sopenharmony_ci *dst++ = ~*src++; 292362306a36Sopenharmony_ci *dst++ = ~*src++; 292462306a36Sopenharmony_ci *dst++ = ~*src++; 292562306a36Sopenharmony_ci *dst++ = ~*src++; 292662306a36Sopenharmony_ci *dst++ = ~*src++; 292762306a36Sopenharmony_ci n -= 8; 292862306a36Sopenharmony_ci } 292962306a36Sopenharmony_ci while (n--) 293062306a36Sopenharmony_ci *dst++ = ~*src++; 293162306a36Sopenharmony_ci 293262306a36Sopenharmony_ci // Trailing bits 293362306a36Sopenharmony_ci if (last) 293462306a36Sopenharmony_ci *dst = comp(~*src, *dst, last); 293562306a36Sopenharmony_ci } 293662306a36Sopenharmony_ci } else { 293762306a36Sopenharmony_ci // Different alignment for source and dest 293862306a36Sopenharmony_ci 293962306a36Sopenharmony_ci right = shift & (BITS_PER_LONG - 1); 294062306a36Sopenharmony_ci left = -shift & (BITS_PER_LONG - 1); 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci if (dst_idx + n <= BITS_PER_LONG) { 294362306a36Sopenharmony_ci // Single destination word 294462306a36Sopenharmony_ci if (last) 294562306a36Sopenharmony_ci first &= last; 294662306a36Sopenharmony_ci if (shift > 0) { 294762306a36Sopenharmony_ci // Single source word 294862306a36Sopenharmony_ci *dst = comp(~*src >> right, *dst, first); 294962306a36Sopenharmony_ci } else if (src_idx + n <= BITS_PER_LONG) { 295062306a36Sopenharmony_ci // Single source word 295162306a36Sopenharmony_ci *dst = comp(~*src << left, *dst, first); 295262306a36Sopenharmony_ci } else { 295362306a36Sopenharmony_ci // 2 source words 295462306a36Sopenharmony_ci d0 = ~*src++; 295562306a36Sopenharmony_ci d1 = ~*src; 295662306a36Sopenharmony_ci *dst = comp(d0 << left | d1 >> right, *dst, 295762306a36Sopenharmony_ci first); 295862306a36Sopenharmony_ci } 295962306a36Sopenharmony_ci } else { 296062306a36Sopenharmony_ci // Multiple destination words 296162306a36Sopenharmony_ci d0 = ~*src++; 296262306a36Sopenharmony_ci // Leading bits 296362306a36Sopenharmony_ci if (shift > 0) { 296462306a36Sopenharmony_ci // Single source word 296562306a36Sopenharmony_ci *dst = comp(d0 >> right, *dst, first); 296662306a36Sopenharmony_ci dst++; 296762306a36Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 296862306a36Sopenharmony_ci } else { 296962306a36Sopenharmony_ci // 2 source words 297062306a36Sopenharmony_ci d1 = ~*src++; 297162306a36Sopenharmony_ci *dst = comp(d0 << left | d1 >> right, *dst, 297262306a36Sopenharmony_ci first); 297362306a36Sopenharmony_ci d0 = d1; 297462306a36Sopenharmony_ci dst++; 297562306a36Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 297662306a36Sopenharmony_ci } 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_ci // Main chunk 297962306a36Sopenharmony_ci m = n % BITS_PER_LONG; 298062306a36Sopenharmony_ci n /= BITS_PER_LONG; 298162306a36Sopenharmony_ci while (n >= 4) { 298262306a36Sopenharmony_ci d1 = ~*src++; 298362306a36Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 298462306a36Sopenharmony_ci d0 = d1; 298562306a36Sopenharmony_ci d1 = ~*src++; 298662306a36Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 298762306a36Sopenharmony_ci d0 = d1; 298862306a36Sopenharmony_ci d1 = ~*src++; 298962306a36Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 299062306a36Sopenharmony_ci d0 = d1; 299162306a36Sopenharmony_ci d1 = ~*src++; 299262306a36Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 299362306a36Sopenharmony_ci d0 = d1; 299462306a36Sopenharmony_ci n -= 4; 299562306a36Sopenharmony_ci } 299662306a36Sopenharmony_ci while (n--) { 299762306a36Sopenharmony_ci d1 = ~*src++; 299862306a36Sopenharmony_ci *dst++ = d0 << left | d1 >> right; 299962306a36Sopenharmony_ci d0 = d1; 300062306a36Sopenharmony_ci } 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci // Trailing bits 300362306a36Sopenharmony_ci if (last) { 300462306a36Sopenharmony_ci if (m <= right) { 300562306a36Sopenharmony_ci // Single source word 300662306a36Sopenharmony_ci *dst = comp(d0 << left, *dst, last); 300762306a36Sopenharmony_ci } else { 300862306a36Sopenharmony_ci // 2 source words 300962306a36Sopenharmony_ci d1 = ~*src; 301062306a36Sopenharmony_ci *dst = comp(d0 << left | d1 >> right, 301162306a36Sopenharmony_ci *dst, last); 301262306a36Sopenharmony_ci } 301362306a36Sopenharmony_ci } 301462306a36Sopenharmony_ci } 301562306a36Sopenharmony_ci } 301662306a36Sopenharmony_ci} 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci 301962306a36Sopenharmony_ci /* 302062306a36Sopenharmony_ci * Unaligned 32-bit pattern fill using 32/64-bit memory accesses 302162306a36Sopenharmony_ci */ 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_cistatic void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) 302462306a36Sopenharmony_ci{ 302562306a36Sopenharmony_ci unsigned long val = pat; 302662306a36Sopenharmony_ci unsigned long first, last; 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_ci if (!n) 302962306a36Sopenharmony_ci return; 303062306a36Sopenharmony_ci 303162306a36Sopenharmony_ci#if BITS_PER_LONG == 64 303262306a36Sopenharmony_ci val |= val << 32; 303362306a36Sopenharmony_ci#endif 303462306a36Sopenharmony_ci 303562306a36Sopenharmony_ci first = ~0UL >> dst_idx; 303662306a36Sopenharmony_ci last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_ci if (dst_idx + n <= BITS_PER_LONG) { 303962306a36Sopenharmony_ci // Single word 304062306a36Sopenharmony_ci if (last) 304162306a36Sopenharmony_ci first &= last; 304262306a36Sopenharmony_ci *dst = comp(val, *dst, first); 304362306a36Sopenharmony_ci } else { 304462306a36Sopenharmony_ci // Multiple destination words 304562306a36Sopenharmony_ci // Leading bits 304662306a36Sopenharmony_ci if (first) { 304762306a36Sopenharmony_ci *dst = comp(val, *dst, first); 304862306a36Sopenharmony_ci dst++; 304962306a36Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 305062306a36Sopenharmony_ci } 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_ci // Main chunk 305362306a36Sopenharmony_ci n /= BITS_PER_LONG; 305462306a36Sopenharmony_ci while (n >= 8) { 305562306a36Sopenharmony_ci *dst++ = val; 305662306a36Sopenharmony_ci *dst++ = val; 305762306a36Sopenharmony_ci *dst++ = val; 305862306a36Sopenharmony_ci *dst++ = val; 305962306a36Sopenharmony_ci *dst++ = val; 306062306a36Sopenharmony_ci *dst++ = val; 306162306a36Sopenharmony_ci *dst++ = val; 306262306a36Sopenharmony_ci *dst++ = val; 306362306a36Sopenharmony_ci n -= 8; 306462306a36Sopenharmony_ci } 306562306a36Sopenharmony_ci while (n--) 306662306a36Sopenharmony_ci *dst++ = val; 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci // Trailing bits 306962306a36Sopenharmony_ci if (last) 307062306a36Sopenharmony_ci *dst = comp(val, *dst, last); 307162306a36Sopenharmony_ci } 307262306a36Sopenharmony_ci} 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci 307562306a36Sopenharmony_ci /* 307662306a36Sopenharmony_ci * Unaligned 32-bit pattern xor using 32/64-bit memory accesses 307762306a36Sopenharmony_ci */ 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_cistatic void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) 308062306a36Sopenharmony_ci{ 308162306a36Sopenharmony_ci unsigned long val = pat; 308262306a36Sopenharmony_ci unsigned long first, last; 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_ci if (!n) 308562306a36Sopenharmony_ci return; 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci#if BITS_PER_LONG == 64 308862306a36Sopenharmony_ci val |= val << 32; 308962306a36Sopenharmony_ci#endif 309062306a36Sopenharmony_ci 309162306a36Sopenharmony_ci first = ~0UL >> dst_idx; 309262306a36Sopenharmony_ci last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); 309362306a36Sopenharmony_ci 309462306a36Sopenharmony_ci if (dst_idx + n <= BITS_PER_LONG) { 309562306a36Sopenharmony_ci // Single word 309662306a36Sopenharmony_ci if (last) 309762306a36Sopenharmony_ci first &= last; 309862306a36Sopenharmony_ci *dst = xor(val, *dst, first); 309962306a36Sopenharmony_ci } else { 310062306a36Sopenharmony_ci // Multiple destination words 310162306a36Sopenharmony_ci // Leading bits 310262306a36Sopenharmony_ci if (first) { 310362306a36Sopenharmony_ci *dst = xor(val, *dst, first); 310462306a36Sopenharmony_ci dst++; 310562306a36Sopenharmony_ci n -= BITS_PER_LONG - dst_idx; 310662306a36Sopenharmony_ci } 310762306a36Sopenharmony_ci 310862306a36Sopenharmony_ci // Main chunk 310962306a36Sopenharmony_ci n /= BITS_PER_LONG; 311062306a36Sopenharmony_ci while (n >= 4) { 311162306a36Sopenharmony_ci *dst++ ^= val; 311262306a36Sopenharmony_ci *dst++ ^= val; 311362306a36Sopenharmony_ci *dst++ ^= val; 311462306a36Sopenharmony_ci *dst++ ^= val; 311562306a36Sopenharmony_ci n -= 4; 311662306a36Sopenharmony_ci } 311762306a36Sopenharmony_ci while (n--) 311862306a36Sopenharmony_ci *dst++ ^= val; 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci // Trailing bits 312162306a36Sopenharmony_ci if (last) 312262306a36Sopenharmony_ci *dst = xor(val, *dst, last); 312362306a36Sopenharmony_ci } 312462306a36Sopenharmony_ci} 312562306a36Sopenharmony_ci 312662306a36Sopenharmony_cistatic inline void fill_one_line(int bpp, unsigned long next_plane, 312762306a36Sopenharmony_ci unsigned long *dst, int dst_idx, u32 n, 312862306a36Sopenharmony_ci u32 color) 312962306a36Sopenharmony_ci{ 313062306a36Sopenharmony_ci while (1) { 313162306a36Sopenharmony_ci dst += dst_idx >> SHIFT_PER_LONG; 313262306a36Sopenharmony_ci dst_idx &= (BITS_PER_LONG - 1); 313362306a36Sopenharmony_ci bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n); 313462306a36Sopenharmony_ci if (!--bpp) 313562306a36Sopenharmony_ci break; 313662306a36Sopenharmony_ci color >>= 1; 313762306a36Sopenharmony_ci dst_idx += next_plane * 8; 313862306a36Sopenharmony_ci } 313962306a36Sopenharmony_ci} 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_cistatic inline void xor_one_line(int bpp, unsigned long next_plane, 314262306a36Sopenharmony_ci unsigned long *dst, int dst_idx, u32 n, 314362306a36Sopenharmony_ci u32 color) 314462306a36Sopenharmony_ci{ 314562306a36Sopenharmony_ci while (color) { 314662306a36Sopenharmony_ci dst += dst_idx >> SHIFT_PER_LONG; 314762306a36Sopenharmony_ci dst_idx &= (BITS_PER_LONG - 1); 314862306a36Sopenharmony_ci bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n); 314962306a36Sopenharmony_ci if (!--bpp) 315062306a36Sopenharmony_ci break; 315162306a36Sopenharmony_ci color >>= 1; 315262306a36Sopenharmony_ci dst_idx += next_plane * 8; 315362306a36Sopenharmony_ci } 315462306a36Sopenharmony_ci} 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_cistatic void amifb_fillrect(struct fb_info *info, 315862306a36Sopenharmony_ci const struct fb_fillrect *rect) 315962306a36Sopenharmony_ci{ 316062306a36Sopenharmony_ci struct amifb_par *par = info->par; 316162306a36Sopenharmony_ci int dst_idx, x2, y2; 316262306a36Sopenharmony_ci unsigned long *dst; 316362306a36Sopenharmony_ci u32 width, height; 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci if (!rect->width || !rect->height) 316662306a36Sopenharmony_ci return; 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_ci /* 316962306a36Sopenharmony_ci * We could use hardware clipping but on many cards you get around 317062306a36Sopenharmony_ci * hardware clipping by writing to framebuffer directly. 317162306a36Sopenharmony_ci * */ 317262306a36Sopenharmony_ci x2 = rect->dx + rect->width; 317362306a36Sopenharmony_ci y2 = rect->dy + rect->height; 317462306a36Sopenharmony_ci x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; 317562306a36Sopenharmony_ci y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; 317662306a36Sopenharmony_ci width = x2 - rect->dx; 317762306a36Sopenharmony_ci height = y2 - rect->dy; 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_ci dst = (unsigned long *) 318062306a36Sopenharmony_ci ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); 318162306a36Sopenharmony_ci dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; 318262306a36Sopenharmony_ci dst_idx += rect->dy * par->next_line * 8 + rect->dx; 318362306a36Sopenharmony_ci while (height--) { 318462306a36Sopenharmony_ci switch (rect->rop) { 318562306a36Sopenharmony_ci case ROP_COPY: 318662306a36Sopenharmony_ci fill_one_line(info->var.bits_per_pixel, 318762306a36Sopenharmony_ci par->next_plane, dst, dst_idx, width, 318862306a36Sopenharmony_ci rect->color); 318962306a36Sopenharmony_ci break; 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci case ROP_XOR: 319262306a36Sopenharmony_ci xor_one_line(info->var.bits_per_pixel, par->next_plane, 319362306a36Sopenharmony_ci dst, dst_idx, width, rect->color); 319462306a36Sopenharmony_ci break; 319562306a36Sopenharmony_ci } 319662306a36Sopenharmony_ci dst_idx += par->next_line * 8; 319762306a36Sopenharmony_ci } 319862306a36Sopenharmony_ci} 319962306a36Sopenharmony_ci 320062306a36Sopenharmony_cistatic inline void copy_one_line(int bpp, unsigned long next_plane, 320162306a36Sopenharmony_ci unsigned long *dst, int dst_idx, 320262306a36Sopenharmony_ci unsigned long *src, int src_idx, u32 n) 320362306a36Sopenharmony_ci{ 320462306a36Sopenharmony_ci while (1) { 320562306a36Sopenharmony_ci dst += dst_idx >> SHIFT_PER_LONG; 320662306a36Sopenharmony_ci dst_idx &= (BITS_PER_LONG - 1); 320762306a36Sopenharmony_ci src += src_idx >> SHIFT_PER_LONG; 320862306a36Sopenharmony_ci src_idx &= (BITS_PER_LONG - 1); 320962306a36Sopenharmony_ci bitcpy(dst, dst_idx, src, src_idx, n); 321062306a36Sopenharmony_ci if (!--bpp) 321162306a36Sopenharmony_ci break; 321262306a36Sopenharmony_ci dst_idx += next_plane * 8; 321362306a36Sopenharmony_ci src_idx += next_plane * 8; 321462306a36Sopenharmony_ci } 321562306a36Sopenharmony_ci} 321662306a36Sopenharmony_ci 321762306a36Sopenharmony_cistatic inline void copy_one_line_rev(int bpp, unsigned long next_plane, 321862306a36Sopenharmony_ci unsigned long *dst, int dst_idx, 321962306a36Sopenharmony_ci unsigned long *src, int src_idx, u32 n) 322062306a36Sopenharmony_ci{ 322162306a36Sopenharmony_ci while (1) { 322262306a36Sopenharmony_ci dst += dst_idx >> SHIFT_PER_LONG; 322362306a36Sopenharmony_ci dst_idx &= (BITS_PER_LONG - 1); 322462306a36Sopenharmony_ci src += src_idx >> SHIFT_PER_LONG; 322562306a36Sopenharmony_ci src_idx &= (BITS_PER_LONG - 1); 322662306a36Sopenharmony_ci bitcpy_rev(dst, dst_idx, src, src_idx, n); 322762306a36Sopenharmony_ci if (!--bpp) 322862306a36Sopenharmony_ci break; 322962306a36Sopenharmony_ci dst_idx += next_plane * 8; 323062306a36Sopenharmony_ci src_idx += next_plane * 8; 323162306a36Sopenharmony_ci } 323262306a36Sopenharmony_ci} 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_cistatic void amifb_copyarea(struct fb_info *info, 323662306a36Sopenharmony_ci const struct fb_copyarea *area) 323762306a36Sopenharmony_ci{ 323862306a36Sopenharmony_ci struct amifb_par *par = info->par; 323962306a36Sopenharmony_ci int x2, y2; 324062306a36Sopenharmony_ci u32 dx, dy, sx, sy, width, height; 324162306a36Sopenharmony_ci unsigned long *dst, *src; 324262306a36Sopenharmony_ci int dst_idx, src_idx; 324362306a36Sopenharmony_ci int rev_copy = 0; 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_ci /* clip the destination */ 324662306a36Sopenharmony_ci x2 = area->dx + area->width; 324762306a36Sopenharmony_ci y2 = area->dy + area->height; 324862306a36Sopenharmony_ci dx = area->dx > 0 ? area->dx : 0; 324962306a36Sopenharmony_ci dy = area->dy > 0 ? area->dy : 0; 325062306a36Sopenharmony_ci x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; 325162306a36Sopenharmony_ci y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; 325262306a36Sopenharmony_ci width = x2 - dx; 325362306a36Sopenharmony_ci height = y2 - dy; 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci if (area->sx + dx < area->dx || area->sy + dy < area->dy) 325662306a36Sopenharmony_ci return; 325762306a36Sopenharmony_ci 325862306a36Sopenharmony_ci /* update sx,sy */ 325962306a36Sopenharmony_ci sx = area->sx + (dx - area->dx); 326062306a36Sopenharmony_ci sy = area->sy + (dy - area->dy); 326162306a36Sopenharmony_ci 326262306a36Sopenharmony_ci /* the source must be completely inside the virtual screen */ 326362306a36Sopenharmony_ci if (sx + width > info->var.xres_virtual || 326462306a36Sopenharmony_ci sy + height > info->var.yres_virtual) 326562306a36Sopenharmony_ci return; 326662306a36Sopenharmony_ci 326762306a36Sopenharmony_ci if (dy > sy || (dy == sy && dx > sx)) { 326862306a36Sopenharmony_ci dy += height; 326962306a36Sopenharmony_ci sy += height; 327062306a36Sopenharmony_ci rev_copy = 1; 327162306a36Sopenharmony_ci } 327262306a36Sopenharmony_ci dst = (unsigned long *) 327362306a36Sopenharmony_ci ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); 327462306a36Sopenharmony_ci src = dst; 327562306a36Sopenharmony_ci dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; 327662306a36Sopenharmony_ci src_idx = dst_idx; 327762306a36Sopenharmony_ci dst_idx += dy * par->next_line * 8 + dx; 327862306a36Sopenharmony_ci src_idx += sy * par->next_line * 8 + sx; 327962306a36Sopenharmony_ci if (rev_copy) { 328062306a36Sopenharmony_ci while (height--) { 328162306a36Sopenharmony_ci dst_idx -= par->next_line * 8; 328262306a36Sopenharmony_ci src_idx -= par->next_line * 8; 328362306a36Sopenharmony_ci copy_one_line_rev(info->var.bits_per_pixel, 328462306a36Sopenharmony_ci par->next_plane, dst, dst_idx, src, 328562306a36Sopenharmony_ci src_idx, width); 328662306a36Sopenharmony_ci } 328762306a36Sopenharmony_ci } else { 328862306a36Sopenharmony_ci while (height--) { 328962306a36Sopenharmony_ci copy_one_line(info->var.bits_per_pixel, 329062306a36Sopenharmony_ci par->next_plane, dst, dst_idx, src, 329162306a36Sopenharmony_ci src_idx, width); 329262306a36Sopenharmony_ci dst_idx += par->next_line * 8; 329362306a36Sopenharmony_ci src_idx += par->next_line * 8; 329462306a36Sopenharmony_ci } 329562306a36Sopenharmony_ci } 329662306a36Sopenharmony_ci} 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_ci 329962306a36Sopenharmony_cistatic inline void expand_one_line(int bpp, unsigned long next_plane, 330062306a36Sopenharmony_ci unsigned long *dst, int dst_idx, u32 n, 330162306a36Sopenharmony_ci const u8 *data, u32 bgcolor, u32 fgcolor) 330262306a36Sopenharmony_ci{ 330362306a36Sopenharmony_ci const unsigned long *src; 330462306a36Sopenharmony_ci int src_idx; 330562306a36Sopenharmony_ci 330662306a36Sopenharmony_ci while (1) { 330762306a36Sopenharmony_ci dst += dst_idx >> SHIFT_PER_LONG; 330862306a36Sopenharmony_ci dst_idx &= (BITS_PER_LONG - 1); 330962306a36Sopenharmony_ci if ((bgcolor ^ fgcolor) & 1) { 331062306a36Sopenharmony_ci src = (unsigned long *) 331162306a36Sopenharmony_ci ((unsigned long)data & ~(BYTES_PER_LONG - 1)); 331262306a36Sopenharmony_ci src_idx = ((unsigned long)data & (BYTES_PER_LONG - 1)) * 8; 331362306a36Sopenharmony_ci if (fgcolor & 1) 331462306a36Sopenharmony_ci bitcpy(dst, dst_idx, src, src_idx, n); 331562306a36Sopenharmony_ci else 331662306a36Sopenharmony_ci bitcpy_not(dst, dst_idx, src, src_idx, n); 331762306a36Sopenharmony_ci /* set or clear */ 331862306a36Sopenharmony_ci } else 331962306a36Sopenharmony_ci bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n); 332062306a36Sopenharmony_ci if (!--bpp) 332162306a36Sopenharmony_ci break; 332262306a36Sopenharmony_ci bgcolor >>= 1; 332362306a36Sopenharmony_ci fgcolor >>= 1; 332462306a36Sopenharmony_ci dst_idx += next_plane * 8; 332562306a36Sopenharmony_ci } 332662306a36Sopenharmony_ci} 332762306a36Sopenharmony_ci 332862306a36Sopenharmony_ci 332962306a36Sopenharmony_cistatic void amifb_imageblit(struct fb_info *info, const struct fb_image *image) 333062306a36Sopenharmony_ci{ 333162306a36Sopenharmony_ci struct amifb_par *par = info->par; 333262306a36Sopenharmony_ci int x2, y2; 333362306a36Sopenharmony_ci unsigned long *dst; 333462306a36Sopenharmony_ci int dst_idx; 333562306a36Sopenharmony_ci const char *src; 333662306a36Sopenharmony_ci u32 dx, dy, width, height, pitch; 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_ci /* 333962306a36Sopenharmony_ci * We could use hardware clipping but on many cards you get around 334062306a36Sopenharmony_ci * hardware clipping by writing to framebuffer directly like we are 334162306a36Sopenharmony_ci * doing here. 334262306a36Sopenharmony_ci */ 334362306a36Sopenharmony_ci x2 = image->dx + image->width; 334462306a36Sopenharmony_ci y2 = image->dy + image->height; 334562306a36Sopenharmony_ci dx = image->dx; 334662306a36Sopenharmony_ci dy = image->dy; 334762306a36Sopenharmony_ci x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; 334862306a36Sopenharmony_ci y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; 334962306a36Sopenharmony_ci width = x2 - dx; 335062306a36Sopenharmony_ci height = y2 - dy; 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_ci if (image->depth == 1) { 335362306a36Sopenharmony_ci dst = (unsigned long *) 335462306a36Sopenharmony_ci ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); 335562306a36Sopenharmony_ci dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; 335662306a36Sopenharmony_ci dst_idx += dy * par->next_line * 8 + dx; 335762306a36Sopenharmony_ci src = image->data; 335862306a36Sopenharmony_ci pitch = (image->width + 7) / 8; 335962306a36Sopenharmony_ci while (height--) { 336062306a36Sopenharmony_ci expand_one_line(info->var.bits_per_pixel, 336162306a36Sopenharmony_ci par->next_plane, dst, dst_idx, width, 336262306a36Sopenharmony_ci src, image->bg_color, 336362306a36Sopenharmony_ci image->fg_color); 336462306a36Sopenharmony_ci dst_idx += par->next_line * 8; 336562306a36Sopenharmony_ci src += pitch; 336662306a36Sopenharmony_ci } 336762306a36Sopenharmony_ci } else { 336862306a36Sopenharmony_ci c2p_planar(info->screen_base, image->data, dx, dy, width, 336962306a36Sopenharmony_ci height, par->next_line, par->next_plane, 337062306a36Sopenharmony_ci image->width, info->var.bits_per_pixel); 337162306a36Sopenharmony_ci } 337262306a36Sopenharmony_ci} 337362306a36Sopenharmony_ci 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_ci /* 337662306a36Sopenharmony_ci * Amiga Frame Buffer Specific ioctls 337762306a36Sopenharmony_ci */ 337862306a36Sopenharmony_ci 337962306a36Sopenharmony_cistatic int amifb_ioctl(struct fb_info *info, 338062306a36Sopenharmony_ci unsigned int cmd, unsigned long arg) 338162306a36Sopenharmony_ci{ 338262306a36Sopenharmony_ci union { 338362306a36Sopenharmony_ci struct fb_fix_cursorinfo fix; 338462306a36Sopenharmony_ci struct fb_var_cursorinfo var; 338562306a36Sopenharmony_ci struct fb_cursorstate state; 338662306a36Sopenharmony_ci } crsr; 338762306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 338862306a36Sopenharmony_ci int i; 338962306a36Sopenharmony_ci 339062306a36Sopenharmony_ci switch (cmd) { 339162306a36Sopenharmony_ci case FBIOGET_FCURSORINFO: 339262306a36Sopenharmony_ci i = ami_get_fix_cursorinfo(&crsr.fix, info->par); 339362306a36Sopenharmony_ci if (i) 339462306a36Sopenharmony_ci return i; 339562306a36Sopenharmony_ci return copy_to_user(argp, &crsr.fix, 339662306a36Sopenharmony_ci sizeof(crsr.fix)) ? -EFAULT : 0; 339762306a36Sopenharmony_ci 339862306a36Sopenharmony_ci case FBIOGET_VCURSORINFO: 339962306a36Sopenharmony_ci i = ami_get_var_cursorinfo(&crsr.var, 340062306a36Sopenharmony_ci ((struct fb_var_cursorinfo __user *)arg)->data, 340162306a36Sopenharmony_ci info->par); 340262306a36Sopenharmony_ci if (i) 340362306a36Sopenharmony_ci return i; 340462306a36Sopenharmony_ci return copy_to_user(argp, &crsr.var, 340562306a36Sopenharmony_ci sizeof(crsr.var)) ? -EFAULT : 0; 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci case FBIOPUT_VCURSORINFO: 340862306a36Sopenharmony_ci if (copy_from_user(&crsr.var, argp, sizeof(crsr.var))) 340962306a36Sopenharmony_ci return -EFAULT; 341062306a36Sopenharmony_ci return ami_set_var_cursorinfo(&crsr.var, 341162306a36Sopenharmony_ci ((struct fb_var_cursorinfo __user *)arg)->data, 341262306a36Sopenharmony_ci info->par); 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_ci case FBIOGET_CURSORSTATE: 341562306a36Sopenharmony_ci i = ami_get_cursorstate(&crsr.state, info->par); 341662306a36Sopenharmony_ci if (i) 341762306a36Sopenharmony_ci return i; 341862306a36Sopenharmony_ci return copy_to_user(argp, &crsr.state, 341962306a36Sopenharmony_ci sizeof(crsr.state)) ? -EFAULT : 0; 342062306a36Sopenharmony_ci 342162306a36Sopenharmony_ci case FBIOPUT_CURSORSTATE: 342262306a36Sopenharmony_ci if (copy_from_user(&crsr.state, argp, sizeof(crsr.state))) 342362306a36Sopenharmony_ci return -EFAULT; 342462306a36Sopenharmony_ci return ami_set_cursorstate(&crsr.state, info->par); 342562306a36Sopenharmony_ci } 342662306a36Sopenharmony_ci return -EINVAL; 342762306a36Sopenharmony_ci} 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_ci /* 343162306a36Sopenharmony_ci * Flash the cursor (called by VBlank interrupt) 343262306a36Sopenharmony_ci */ 343362306a36Sopenharmony_ci 343462306a36Sopenharmony_cistatic int flash_cursor(void) 343562306a36Sopenharmony_ci{ 343662306a36Sopenharmony_ci static int cursorcount = 1; 343762306a36Sopenharmony_ci 343862306a36Sopenharmony_ci if (cursormode == FB_CURSOR_FLASH) { 343962306a36Sopenharmony_ci if (!--cursorcount) { 344062306a36Sopenharmony_ci cursorstate = -cursorstate; 344162306a36Sopenharmony_ci cursorcount = cursorrate; 344262306a36Sopenharmony_ci if (!is_blanked) 344362306a36Sopenharmony_ci return 1; 344462306a36Sopenharmony_ci } 344562306a36Sopenharmony_ci } 344662306a36Sopenharmony_ci return 0; 344762306a36Sopenharmony_ci} 344862306a36Sopenharmony_ci 344962306a36Sopenharmony_ci /* 345062306a36Sopenharmony_ci * VBlank Display Interrupt 345162306a36Sopenharmony_ci */ 345262306a36Sopenharmony_ci 345362306a36Sopenharmony_cistatic irqreturn_t amifb_interrupt(int irq, void *dev_id) 345462306a36Sopenharmony_ci{ 345562306a36Sopenharmony_ci struct amifb_par *par = dev_id; 345662306a36Sopenharmony_ci 345762306a36Sopenharmony_ci if (do_vmode_pan || do_vmode_full) 345862306a36Sopenharmony_ci ami_update_display(par); 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci if (do_vmode_full) 346162306a36Sopenharmony_ci ami_init_display(par); 346262306a36Sopenharmony_ci 346362306a36Sopenharmony_ci if (do_vmode_pan) { 346462306a36Sopenharmony_ci flash_cursor(); 346562306a36Sopenharmony_ci ami_rebuild_copper(par); 346662306a36Sopenharmony_ci do_cursor = do_vmode_pan = 0; 346762306a36Sopenharmony_ci } else if (do_cursor) { 346862306a36Sopenharmony_ci flash_cursor(); 346962306a36Sopenharmony_ci ami_set_sprite(par); 347062306a36Sopenharmony_ci do_cursor = 0; 347162306a36Sopenharmony_ci } else { 347262306a36Sopenharmony_ci if (flash_cursor()) 347362306a36Sopenharmony_ci ami_set_sprite(par); 347462306a36Sopenharmony_ci } 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_ci if (do_blank) { 347762306a36Sopenharmony_ci ami_do_blank(par); 347862306a36Sopenharmony_ci do_blank = 0; 347962306a36Sopenharmony_ci } 348062306a36Sopenharmony_ci 348162306a36Sopenharmony_ci if (do_vmode_full) { 348262306a36Sopenharmony_ci ami_reinit_copper(par); 348362306a36Sopenharmony_ci do_vmode_full = 0; 348462306a36Sopenharmony_ci } 348562306a36Sopenharmony_ci return IRQ_HANDLED; 348662306a36Sopenharmony_ci} 348762306a36Sopenharmony_ci 348862306a36Sopenharmony_ci 348962306a36Sopenharmony_cistatic const struct fb_ops amifb_ops = { 349062306a36Sopenharmony_ci .owner = THIS_MODULE, 349162306a36Sopenharmony_ci .fb_check_var = amifb_check_var, 349262306a36Sopenharmony_ci .fb_set_par = amifb_set_par, 349362306a36Sopenharmony_ci .fb_setcolreg = amifb_setcolreg, 349462306a36Sopenharmony_ci .fb_blank = amifb_blank, 349562306a36Sopenharmony_ci .fb_pan_display = amifb_pan_display, 349662306a36Sopenharmony_ci .fb_fillrect = amifb_fillrect, 349762306a36Sopenharmony_ci .fb_copyarea = amifb_copyarea, 349862306a36Sopenharmony_ci .fb_imageblit = amifb_imageblit, 349962306a36Sopenharmony_ci .fb_ioctl = amifb_ioctl, 350062306a36Sopenharmony_ci}; 350162306a36Sopenharmony_ci 350262306a36Sopenharmony_ci 350362306a36Sopenharmony_ci /* 350462306a36Sopenharmony_ci * Allocate, Clear and Align a Block of Chip Memory 350562306a36Sopenharmony_ci */ 350662306a36Sopenharmony_ci 350762306a36Sopenharmony_cistatic void *aligned_chipptr; 350862306a36Sopenharmony_ci 350962306a36Sopenharmony_cistatic inline u_long __init chipalloc(u_long size) 351062306a36Sopenharmony_ci{ 351162306a36Sopenharmony_ci aligned_chipptr = amiga_chip_alloc(size, "amifb [RAM]"); 351262306a36Sopenharmony_ci if (!aligned_chipptr) { 351362306a36Sopenharmony_ci pr_err("amifb: No Chip RAM for frame buffer"); 351462306a36Sopenharmony_ci return 0; 351562306a36Sopenharmony_ci } 351662306a36Sopenharmony_ci memset(aligned_chipptr, 0, size); 351762306a36Sopenharmony_ci return (u_long)aligned_chipptr; 351862306a36Sopenharmony_ci} 351962306a36Sopenharmony_ci 352062306a36Sopenharmony_cistatic inline void chipfree(void) 352162306a36Sopenharmony_ci{ 352262306a36Sopenharmony_ci if (aligned_chipptr) 352362306a36Sopenharmony_ci amiga_chip_free(aligned_chipptr); 352462306a36Sopenharmony_ci} 352562306a36Sopenharmony_ci 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci /* 352862306a36Sopenharmony_ci * Initialisation 352962306a36Sopenharmony_ci */ 353062306a36Sopenharmony_ci 353162306a36Sopenharmony_cistatic int __init amifb_probe(struct platform_device *pdev) 353262306a36Sopenharmony_ci{ 353362306a36Sopenharmony_ci struct fb_info *info; 353462306a36Sopenharmony_ci int tag, i, err = 0; 353562306a36Sopenharmony_ci u_long chipptr; 353662306a36Sopenharmony_ci u_int defmode; 353762306a36Sopenharmony_ci 353862306a36Sopenharmony_ci#ifndef MODULE 353962306a36Sopenharmony_ci char *option = NULL; 354062306a36Sopenharmony_ci 354162306a36Sopenharmony_ci if (fb_get_options("amifb", &option)) { 354262306a36Sopenharmony_ci amifb_video_off(); 354362306a36Sopenharmony_ci return -ENODEV; 354462306a36Sopenharmony_ci } 354562306a36Sopenharmony_ci amifb_setup(option); 354662306a36Sopenharmony_ci#endif 354762306a36Sopenharmony_ci custom.dmacon = DMAF_ALL | DMAF_MASTER; 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_ci info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev); 355062306a36Sopenharmony_ci if (!info) 355162306a36Sopenharmony_ci return -ENOMEM; 355262306a36Sopenharmony_ci 355362306a36Sopenharmony_ci strcpy(info->fix.id, "Amiga "); 355462306a36Sopenharmony_ci info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 355562306a36Sopenharmony_ci info->fix.accel = FB_ACCEL_AMIGABLITT; 355662306a36Sopenharmony_ci 355762306a36Sopenharmony_ci switch (amiga_chipset) { 355862306a36Sopenharmony_ci#ifdef CONFIG_FB_AMIGA_OCS 355962306a36Sopenharmony_ci case CS_OCS: 356062306a36Sopenharmony_ci strcat(info->fix.id, "OCS"); 356162306a36Sopenharmony_cidefault_chipset: 356262306a36Sopenharmony_ci chipset = TAG_OCS; 356362306a36Sopenharmony_ci maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ 356462306a36Sopenharmony_ci maxdepth[TAG_HIRES] = 4; 356562306a36Sopenharmony_ci maxdepth[TAG_LORES] = 6; 356662306a36Sopenharmony_ci maxfmode = TAG_FMODE_1; 356762306a36Sopenharmony_ci defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC; 356862306a36Sopenharmony_ci info->fix.smem_len = VIDEOMEMSIZE_OCS; 356962306a36Sopenharmony_ci break; 357062306a36Sopenharmony_ci#endif /* CONFIG_FB_AMIGA_OCS */ 357162306a36Sopenharmony_ci 357262306a36Sopenharmony_ci#ifdef CONFIG_FB_AMIGA_ECS 357362306a36Sopenharmony_ci case CS_ECS: 357462306a36Sopenharmony_ci strcat(info->fix.id, "ECS"); 357562306a36Sopenharmony_ci chipset = TAG_ECS; 357662306a36Sopenharmony_ci maxdepth[TAG_SHRES] = 2; 357762306a36Sopenharmony_ci maxdepth[TAG_HIRES] = 4; 357862306a36Sopenharmony_ci maxdepth[TAG_LORES] = 6; 357962306a36Sopenharmony_ci maxfmode = TAG_FMODE_1; 358062306a36Sopenharmony_ci if (AMIGAHW_PRESENT(AMBER_FF)) 358162306a36Sopenharmony_ci defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL 358262306a36Sopenharmony_ci : DEFMODE_AMBER_NTSC; 358362306a36Sopenharmony_ci else 358462306a36Sopenharmony_ci defmode = amiga_vblank == 50 ? DEFMODE_PAL 358562306a36Sopenharmony_ci : DEFMODE_NTSC; 358662306a36Sopenharmony_ci if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > 358762306a36Sopenharmony_ci VIDEOMEMSIZE_ECS_2M) 358862306a36Sopenharmony_ci info->fix.smem_len = VIDEOMEMSIZE_ECS_2M; 358962306a36Sopenharmony_ci else 359062306a36Sopenharmony_ci info->fix.smem_len = VIDEOMEMSIZE_ECS_1M; 359162306a36Sopenharmony_ci break; 359262306a36Sopenharmony_ci#endif /* CONFIG_FB_AMIGA_ECS */ 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_ci#ifdef CONFIG_FB_AMIGA_AGA 359562306a36Sopenharmony_ci case CS_AGA: 359662306a36Sopenharmony_ci strcat(info->fix.id, "AGA"); 359762306a36Sopenharmony_ci chipset = TAG_AGA; 359862306a36Sopenharmony_ci maxdepth[TAG_SHRES] = 8; 359962306a36Sopenharmony_ci maxdepth[TAG_HIRES] = 8; 360062306a36Sopenharmony_ci maxdepth[TAG_LORES] = 8; 360162306a36Sopenharmony_ci maxfmode = TAG_FMODE_4; 360262306a36Sopenharmony_ci defmode = DEFMODE_AGA; 360362306a36Sopenharmony_ci if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > 360462306a36Sopenharmony_ci VIDEOMEMSIZE_AGA_2M) 360562306a36Sopenharmony_ci info->fix.smem_len = VIDEOMEMSIZE_AGA_2M; 360662306a36Sopenharmony_ci else 360762306a36Sopenharmony_ci info->fix.smem_len = VIDEOMEMSIZE_AGA_1M; 360862306a36Sopenharmony_ci break; 360962306a36Sopenharmony_ci#endif /* CONFIG_FB_AMIGA_AGA */ 361062306a36Sopenharmony_ci 361162306a36Sopenharmony_ci default: 361262306a36Sopenharmony_ci#ifdef CONFIG_FB_AMIGA_OCS 361362306a36Sopenharmony_ci printk("Unknown graphics chipset, defaulting to OCS\n"); 361462306a36Sopenharmony_ci strcat(info->fix.id, "Unknown"); 361562306a36Sopenharmony_ci goto default_chipset; 361662306a36Sopenharmony_ci#else /* CONFIG_FB_AMIGA_OCS */ 361762306a36Sopenharmony_ci err = -ENODEV; 361862306a36Sopenharmony_ci goto release; 361962306a36Sopenharmony_ci#endif /* CONFIG_FB_AMIGA_OCS */ 362062306a36Sopenharmony_ci break; 362162306a36Sopenharmony_ci } 362262306a36Sopenharmony_ci 362362306a36Sopenharmony_ci /* 362462306a36Sopenharmony_ci * Calculate the Pixel Clock Values for this Machine 362562306a36Sopenharmony_ci */ 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci { 362862306a36Sopenharmony_ci u_long tmp = DIVUL(200000000000ULL, amiga_eclock); 362962306a36Sopenharmony_ci 363062306a36Sopenharmony_ci pixclock[TAG_SHRES] = (tmp + 4) / 8; /* SHRES: 35 ns / 28 MHz */ 363162306a36Sopenharmony_ci pixclock[TAG_HIRES] = (tmp + 2) / 4; /* HIRES: 70 ns / 14 MHz */ 363262306a36Sopenharmony_ci pixclock[TAG_LORES] = (tmp + 1) / 2; /* LORES: 140 ns / 7 MHz */ 363362306a36Sopenharmony_ci } 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_ci /* 363662306a36Sopenharmony_ci * Replace the Tag Values with the Real Pixel Clock Values 363762306a36Sopenharmony_ci */ 363862306a36Sopenharmony_ci 363962306a36Sopenharmony_ci for (i = 0; i < NUM_TOTAL_MODES; i++) { 364062306a36Sopenharmony_ci struct fb_videomode *mode = &ami_modedb[i]; 364162306a36Sopenharmony_ci tag = mode->pixclock; 364262306a36Sopenharmony_ci if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) { 364362306a36Sopenharmony_ci mode->pixclock = pixclock[tag]; 364462306a36Sopenharmony_ci } 364562306a36Sopenharmony_ci } 364662306a36Sopenharmony_ci 364762306a36Sopenharmony_ci if (amifb_hfmin) { 364862306a36Sopenharmony_ci info->monspecs.hfmin = amifb_hfmin; 364962306a36Sopenharmony_ci info->monspecs.hfmax = amifb_hfmax; 365062306a36Sopenharmony_ci info->monspecs.vfmin = amifb_vfmin; 365162306a36Sopenharmony_ci info->monspecs.vfmax = amifb_vfmax; 365262306a36Sopenharmony_ci } else { 365362306a36Sopenharmony_ci /* 365462306a36Sopenharmony_ci * These are for a typical Amiga monitor (e.g. A1960) 365562306a36Sopenharmony_ci */ 365662306a36Sopenharmony_ci info->monspecs.hfmin = 15000; 365762306a36Sopenharmony_ci info->monspecs.hfmax = 38000; 365862306a36Sopenharmony_ci info->monspecs.vfmin = 49; 365962306a36Sopenharmony_ci info->monspecs.vfmax = 90; 366062306a36Sopenharmony_ci } 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_ci info->fbops = &amifb_ops; 366362306a36Sopenharmony_ci info->device = &pdev->dev; 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci if (!fb_find_mode(&info->var, info, mode_option, ami_modedb, 366662306a36Sopenharmony_ci NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { 366762306a36Sopenharmony_ci err = -EINVAL; 366862306a36Sopenharmony_ci goto release; 366962306a36Sopenharmony_ci } 367062306a36Sopenharmony_ci 367162306a36Sopenharmony_ci fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES, 367262306a36Sopenharmony_ci &info->modelist); 367362306a36Sopenharmony_ci 367462306a36Sopenharmony_ci round_down_bpp = 0; 367562306a36Sopenharmony_ci chipptr = chipalloc(info->fix.smem_len + SPRITEMEMSIZE + 367662306a36Sopenharmony_ci DUMMYSPRITEMEMSIZE + COPINITSIZE + 367762306a36Sopenharmony_ci 4 * COPLISTSIZE); 367862306a36Sopenharmony_ci if (!chipptr) { 367962306a36Sopenharmony_ci err = -ENOMEM; 368062306a36Sopenharmony_ci goto release; 368162306a36Sopenharmony_ci } 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_ci assignchunk(videomemory, u_long, chipptr, info->fix.smem_len); 368462306a36Sopenharmony_ci assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); 368562306a36Sopenharmony_ci assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); 368662306a36Sopenharmony_ci assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); 368762306a36Sopenharmony_ci assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE); 368862306a36Sopenharmony_ci assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE); 368962306a36Sopenharmony_ci assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE); 369062306a36Sopenharmony_ci assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE); 369162306a36Sopenharmony_ci 369262306a36Sopenharmony_ci /* 369362306a36Sopenharmony_ci * access the videomem with writethrough cache 369462306a36Sopenharmony_ci */ 369562306a36Sopenharmony_ci info->fix.smem_start = (u_long)ZTWO_PADDR(videomemory); 369662306a36Sopenharmony_ci videomemory = (u_long)ioremap_wt(info->fix.smem_start, 369762306a36Sopenharmony_ci info->fix.smem_len); 369862306a36Sopenharmony_ci if (!videomemory) { 369962306a36Sopenharmony_ci dev_warn(&pdev->dev, 370062306a36Sopenharmony_ci "Unable to map videomem cached writethrough\n"); 370162306a36Sopenharmony_ci info->screen_base = ZTWO_VADDR(info->fix.smem_start); 370262306a36Sopenharmony_ci } else 370362306a36Sopenharmony_ci info->screen_base = (char *)videomemory; 370462306a36Sopenharmony_ci 370562306a36Sopenharmony_ci memset(dummysprite, 0, DUMMYSPRITEMEMSIZE); 370662306a36Sopenharmony_ci 370762306a36Sopenharmony_ci /* 370862306a36Sopenharmony_ci * Make sure the Copper has something to do 370962306a36Sopenharmony_ci */ 371062306a36Sopenharmony_ci ami_init_copper(); 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_ci /* 371362306a36Sopenharmony_ci * Enable Display DMA 371462306a36Sopenharmony_ci */ 371562306a36Sopenharmony_ci custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | 371662306a36Sopenharmony_ci DMAF_BLITTER | DMAF_SPRITE; 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_ci err = request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, 371962306a36Sopenharmony_ci "fb vertb handler", info->par); 372062306a36Sopenharmony_ci if (err) 372162306a36Sopenharmony_ci goto disable_dma; 372262306a36Sopenharmony_ci 372362306a36Sopenharmony_ci err = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0); 372462306a36Sopenharmony_ci if (err) 372562306a36Sopenharmony_ci goto free_irq; 372662306a36Sopenharmony_ci 372762306a36Sopenharmony_ci platform_set_drvdata(pdev, info); 372862306a36Sopenharmony_ci 372962306a36Sopenharmony_ci err = register_framebuffer(info); 373062306a36Sopenharmony_ci if (err) 373162306a36Sopenharmony_ci goto unset_drvdata; 373262306a36Sopenharmony_ci 373362306a36Sopenharmony_ci fb_info(info, "%s frame buffer device, using %dK of video memory\n", 373462306a36Sopenharmony_ci info->fix.id, info->fix.smem_len>>10); 373562306a36Sopenharmony_ci 373662306a36Sopenharmony_ci return 0; 373762306a36Sopenharmony_ci 373862306a36Sopenharmony_ciunset_drvdata: 373962306a36Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 374062306a36Sopenharmony_cifree_irq: 374162306a36Sopenharmony_ci free_irq(IRQ_AMIGA_COPPER, info->par); 374262306a36Sopenharmony_cidisable_dma: 374362306a36Sopenharmony_ci custom.dmacon = DMAF_ALL | DMAF_MASTER; 374462306a36Sopenharmony_ci if (videomemory) 374562306a36Sopenharmony_ci iounmap((void *)videomemory); 374662306a36Sopenharmony_ci chipfree(); 374762306a36Sopenharmony_cirelease: 374862306a36Sopenharmony_ci framebuffer_release(info); 374962306a36Sopenharmony_ci return err; 375062306a36Sopenharmony_ci} 375162306a36Sopenharmony_ci 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_cistatic int __exit amifb_remove(struct platform_device *pdev) 375462306a36Sopenharmony_ci{ 375562306a36Sopenharmony_ci struct fb_info *info = platform_get_drvdata(pdev); 375662306a36Sopenharmony_ci 375762306a36Sopenharmony_ci unregister_framebuffer(info); 375862306a36Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 375962306a36Sopenharmony_ci free_irq(IRQ_AMIGA_COPPER, info->par); 376062306a36Sopenharmony_ci custom.dmacon = DMAF_ALL | DMAF_MASTER; 376162306a36Sopenharmony_ci if (videomemory) 376262306a36Sopenharmony_ci iounmap((void *)videomemory); 376362306a36Sopenharmony_ci chipfree(); 376462306a36Sopenharmony_ci framebuffer_release(info); 376562306a36Sopenharmony_ci amifb_video_off(); 376662306a36Sopenharmony_ci return 0; 376762306a36Sopenharmony_ci} 376862306a36Sopenharmony_ci 376962306a36Sopenharmony_cistatic struct platform_driver amifb_driver = { 377062306a36Sopenharmony_ci .remove = __exit_p(amifb_remove), 377162306a36Sopenharmony_ci .driver = { 377262306a36Sopenharmony_ci .name = "amiga-video", 377362306a36Sopenharmony_ci }, 377462306a36Sopenharmony_ci}; 377562306a36Sopenharmony_ci 377662306a36Sopenharmony_cimodule_platform_driver_probe(amifb_driver, amifb_probe); 377762306a36Sopenharmony_ci 377862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 377962306a36Sopenharmony_ciMODULE_ALIAS("platform:amiga-video"); 3780