brintos

brintos / linux-shallow public Read only

0
0
Text · 99.4 KiB · 1116a07 Raw
3788 lines · c
1/*2 * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device3 *4 *    Copyright (C) 1995-2003 Geert Uytterhoeven5 *6 *          with work by Roman Zippel7 *8 *9 * This file is based on the Atari frame buffer device (atafb.c):10 *11 *    Copyright (C) 1994 Martin Schaller12 *                       Roman Hodek13 *14 *          with work by Andreas Schwab15 *                       Guenther Kelleter16 *17 * and on the original Amiga console driver (amicon.c):18 *19 *    Copyright (C) 1993 Hamish Macdonald20 *                       Greg Harp21 *    Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]22 *23 *          with work by William Rucklidge (wjr@cs.cornell.edu)24 *                       Geert Uytterhoeven25 *                       Jes Sorensen (jds@kom.auc.dk)26 *27 *28 * History:29 *30 *   - 24 Jul 96: Copper generates now vblank interrupt and31 *                VESA Power Saving Protocol is fully implemented32 *   - 14 Jul 96: Rework and hopefully last ECS bugs fixed33 *   -  7 Mar 96: Hardware sprite support by Roman Zippel34 *   - 18 Feb 96: OCS and ECS support by Roman Zippel35 *                Hardware functions completely rewritten36 *   -  2 Dec 95: AGA version by Geert Uytterhoeven37 *38 * This file is subject to the terms and conditions of the GNU General Public39 * License. See the file COPYING in the main directory of this archive40 * for more details.41 */42 43#include <linux/module.h>44#include <linux/kernel.h>45#include <linux/errno.h>46#include <linux/string.h>47#include <linux/mm.h>48#include <linux/delay.h>49#include <linux/interrupt.h>50#include <linux/fb.h>51#include <linux/init.h>52#include <linux/ioport.h>53#include <linux/platform_device.h>54#include <linux/uaccess.h>55 56#include <asm/irq.h>57#include <asm/amigahw.h>58#include <asm/amigaints.h>59#include <asm/setup.h>60 61#include "c2p.h"62 63 64#define DEBUG65 66#if !defined(CONFIG_FB_AMIGA_OCS) && !defined(CONFIG_FB_AMIGA_ECS) && !defined(CONFIG_FB_AMIGA_AGA)67#define CONFIG_FB_AMIGA_OCS   /* define at least one fb driver, this will change later */68#endif69 70#if !defined(CONFIG_FB_AMIGA_OCS)71#  define IS_OCS (0)72#elif defined(CONFIG_FB_AMIGA_ECS) || defined(CONFIG_FB_AMIGA_AGA)73#  define IS_OCS (chipset == TAG_OCS)74#else75#  define CONFIG_FB_AMIGA_OCS_ONLY76#  define IS_OCS (1)77#endif78 79#if !defined(CONFIG_FB_AMIGA_ECS)80#  define IS_ECS (0)81#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_AGA)82#  define IS_ECS (chipset == TAG_ECS)83#else84#  define CONFIG_FB_AMIGA_ECS_ONLY85#  define IS_ECS (1)86#endif87 88#if !defined(CONFIG_FB_AMIGA_AGA)89#  define IS_AGA (0)90#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_ECS)91#  define IS_AGA (chipset == TAG_AGA)92#else93#  define CONFIG_FB_AMIGA_AGA_ONLY94#  define IS_AGA (1)95#endif96 97#ifdef DEBUG98#  define DPRINTK(fmt, args...)	printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)99#else100#  define DPRINTK(fmt, args...)101#endif102 103/*******************************************************************************104 105 106   Generic video timings107   ---------------------108 109   Timings used by the frame buffer interface:110 111   +----------+---------------------------------------------+----------+-------+112   |          |                ^                            |          |       |113   |          |                |upper_margin                |          |       |114   |          |                v                            |          |       |115   +----------###############################################----------+-------+116   |          #                ^                            #          |       |117   |          #                |                            #          |       |118   |          #                |                            #          |       |119   |          #                |                            #          |       |120   |   left   #                |                            #  right   | hsync |121   |  margin  #                |       xres                 #  margin  |  len  |122   |<-------->#<---------------+--------------------------->#<-------->|<----->|123   |          #                |                            #          |       |124   |          #                |                            #          |       |125   |          #                |                            #          |       |126   |          #                |yres                        #          |       |127   |          #                |                            #          |       |128   |          #                |                            #          |       |129   |          #                |                            #          |       |130   |          #                |                            #          |       |131   |          #                |                            #          |       |132   |          #                |                            #          |       |133   |          #                |                            #          |       |134   |          #                |                            #          |       |135   |          #                v                            #          |       |136   +----------###############################################----------+-------+137   |          |                ^                            |          |       |138   |          |                |lower_margin                |          |       |139   |          |                v                            |          |       |140   +----------+---------------------------------------------+----------+-------+141   |          |                ^                            |          |       |142   |          |                |vsync_len                   |          |       |143   |          |                v                            |          |       |144   +----------+---------------------------------------------+----------+-------+145 146 147   Amiga video timings148   -------------------149 150   The Amiga native chipsets uses another timing scheme:151 152      - hsstrt:   Start of horizontal synchronization pulse153      - hsstop:   End of horizontal synchronization pulse154      - htotal:   Last value on the line (i.e. line length = htotal + 1)155      - vsstrt:   Start of vertical synchronization pulse156      - vsstop:   End of vertical synchronization pulse157      - vtotal:   Last line value (i.e. number of lines = vtotal + 1)158      - hcenter:  Start of vertical retrace for interlace159 160   You can specify the blanking timings independently. Currently I just set161   them equal to the respective synchronization values:162 163      - hbstrt:   Start of horizontal blank164      - hbstop:   End of horizontal blank165      - vbstrt:   Start of vertical blank166      - vbstop:   End of vertical blank167 168   Horizontal values are in color clock cycles (280 ns), vertical values are in169   scanlines.170 171   (0, 0) is somewhere in the upper-left corner :-)172 173 174   Amiga visible window definitions175   --------------------------------176 177   Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to178   make corrections and/or additions.179 180   Within the above synchronization specifications, the visible window is181   defined by the following parameters (actual register resolutions may be182   different; all horizontal values are normalized with respect to the pixel183   clock):184 185      - diwstrt_h:   Horizontal start of the visible window186      - diwstop_h:   Horizontal stop + 1(*) of the visible window187      - diwstrt_v:   Vertical start of the visible window188      - diwstop_v:   Vertical stop of the visible window189      - ddfstrt:     Horizontal start of display DMA190      - ddfstop:     Horizontal stop of display DMA191      - hscroll:     Horizontal display output delay192 193   Sprite positioning:194 195      - sprstrt_h:   Horizontal start - 4 of sprite196      - sprstrt_v:   Vertical start of sprite197 198   (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1.199 200   Horizontal values are in dotclock cycles (35 ns), vertical values are in201   scanlines.202 203   (0, 0) is somewhere in the upper-left corner :-)204 205 206   Dependencies (AGA, SHRES (35 ns dotclock))207   -------------------------------------------208 209   Since there are much more parameters for the Amiga display than for the210   frame buffer interface, there must be some dependencies among the Amiga211   display parameters. Here's what I found out:212 213      - ddfstrt and ddfstop are best aligned to 64 pixels.214      - the chipset needs 64 + 4 horizontal pixels after the DMA start before215	the first pixel is output, so diwstrt_h = ddfstrt + 64 + 4 if you want216	to display the first pixel on the line too. Increase diwstrt_h for217	virtual screen panning.218      - the display DMA always fetches 64 pixels at a time (fmode = 3).219      - ddfstop is ddfstrt+#pixels - 64.220      - diwstop_h = diwstrt_h + xres + 1. Because of the additional 1 this can221	be 1 more than htotal.222      - hscroll simply adds a delay to the display output. Smooth horizontal223	panning needs an extra 64 pixels on the left to prefetch the pixels that224	`fall off' on the left.225      - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane226	DMA, so it's best to make the DMA start as late as possible.227      - you really don't want to make ddfstrt < 128, since this will steal DMA228	cycles from the other DMA channels (audio, floppy and Chip RAM refresh).229      - I make diwstop_h and diwstop_v as large as possible.230 231   General dependencies232   --------------------233 234      - all values are SHRES pixel (35ns)235 236		  table 1:fetchstart  table 2:prefetch    table 3:fetchsize237		  ------------------  ----------------    -----------------238   Pixclock     # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES239   -------------#------+-----+------#------+-----+------#------+-----+------240   Bus width 1x #   16 |  32 |  64  #   16 |  32 |  64  #   64 |  64 |  64241   Bus width 2x #   32 |  64 | 128  #   32 |  64 |  64  #   64 |  64 | 128242   Bus width 4x #   64 | 128 | 256  #   64 |  64 |  64  #   64 | 128 | 256243 244      - chipset needs 4 pixels before the first pixel is output245      - ddfstrt must be aligned to fetchstart (table 1)246      - chipset needs also prefetch (table 2) to get first pixel data, so247	ddfstrt = ((diwstrt_h - 4) & -fetchstart) - prefetch248      - for horizontal panning decrease diwstrt_h249      - the length of a fetchline must be aligned to fetchsize (table 3)250      - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit251	moved to optimize use of dma (useful for OCS/ECS overscan displays)252      - ddfstop is ddfstrt + ddfsize - fetchsize253      - If C= didn't change anything for AGA, then at following positions the254	dma bus is already used:255	ddfstrt <  48 -> memory refresh256		<  96 -> disk dma257		< 160 -> audio dma258		< 192 -> sprite 0 dma259		< 416 -> sprite dma (32 per sprite)260      - in accordance with the hardware reference manual a hardware stop is at261	192, but AGA (ECS?) can go below this.262 263   DMA priorities264   --------------265 266   Since there are limits on the earliest start value for display DMA and the267   display of sprites, I use the following policy on horizontal panning and268   the hardware cursor:269 270      - if you want to start display DMA too early, you lose the ability to271	do smooth horizontal panning (xpanstep 1 -> 64).272      - if you want to go even further, you lose the hardware cursor too.273 274   IMHO a hardware cursor is more important for X than horizontal scrolling,275   so that's my motivation.276 277 278   Implementation279   --------------280 281   ami_decode_var() converts the frame buffer values to the Amiga values. It's282   just a `straightforward' implementation of the above rules.283 284 285   Standard VGA timings286   --------------------287 288	       xres  yres    left  right  upper  lower    hsync    vsync289	       ----  ----    ----  -----  -----  -----    -----    -----290      80x25     720   400      27     45     35     12      108        2291      80x30     720   480      27     45     30      9      108        2292 293   These were taken from a XFree86 configuration file, recalculated for a 28 MHz294   dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer295   generic timings.296 297   As a comparison, graphics/monitor.h suggests the following:298 299	       xres  yres    left  right  upper  lower    hsync    vsync300	       ----  ----    ----  -----  -----  -----    -----    -----301 302      VGA       640   480      52    112     24     19    112 -      2 +303      VGA70     640   400      52    112     27     21    112 -      2 -304 305 306   Sync polarities307   ---------------308 309      VSYNC    HSYNC    Vertical size    Vertical total310      -----    -----    -------------    --------------311	+        +           Reserved          Reserved312	+        -                400               414313	-        +                350               362314	-        -                480               496315 316   Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992317 318 319   Broadcast video timings320   -----------------------321 322   According to the CCIR and RETMA specifications, we have the following values:323 324   CCIR -> PAL325   -----------326 327      - a scanline is 64 µs long, of which 52.48 µs are visible. This is about328	736 visible 70 ns pixels per line.329      - we have 625 scanlines, of which 575 are visible (interlaced); after330	rounding this becomes 576.331 332   RETMA -> NTSC333   -------------334 335      - a scanline is 63.5 µs long, of which 53.5 µs are visible.  This is about336	736 visible 70 ns pixels per line.337      - we have 525 scanlines, of which 485 are visible (interlaced); after338	rounding this becomes 484.339 340   Thus if you want a PAL compatible display, you have to do the following:341 342      - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast343	timings are to be used.344      - make sure upper_margin + yres + lower_margin + vsync_len = 625 for an345	interlaced, 312 for a non-interlaced and 156 for a doublescanned346	display.347      - make sure left_margin + xres + right_margin + hsync_len = 1816 for a348	SHRES, 908 for a HIRES and 454 for a LORES display.349      - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90),350	left_margin + 2 * hsync_len must be greater or equal.351      - the upper visible part begins at 48 (interlaced; non-interlaced:24,352	doublescanned:12), upper_margin + 2 * vsync_len must be greater or353	equal.354      - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync355	of 4 scanlines356 357   The settings for a NTSC compatible display are straightforward.358 359   Note that in a strict sense the PAL and NTSC standards only define the360   encoding of the color part (chrominance) of the video signal and don't say361   anything about horizontal/vertical synchronization nor refresh rates.362 363 364							    -- Geert --365 366*******************************************************************************/367 368 369	/*370	 * Custom Chipset Definitions371	 */372 373#define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld)374 375	/*376	 * BPLCON0 -- Bitplane Control Register 0377	 */378 379#define BPC0_HIRES	(0x8000)380#define BPC0_BPU2	(0x4000) /* Bit plane used count */381#define BPC0_BPU1	(0x2000)382#define BPC0_BPU0	(0x1000)383#define BPC0_HAM	(0x0800) /* HAM mode */384#define BPC0_DPF	(0x0400) /* Double playfield */385#define BPC0_COLOR	(0x0200) /* Enable colorburst */386#define BPC0_GAUD	(0x0100) /* Genlock audio enable */387#define BPC0_UHRES	(0x0080) /* Ultrahi res enable */388#define BPC0_SHRES	(0x0040) /* Super hi res mode */389#define BPC0_BYPASS	(0x0020) /* Bypass LUT - AGA */390#define BPC0_BPU3	(0x0010) /* AGA */391#define BPC0_LPEN	(0x0008) /* Light pen enable */392#define BPC0_LACE	(0x0004) /* Interlace */393#define BPC0_ERSY	(0x0002) /* External resync */394#define BPC0_ECSENA	(0x0001) /* ECS enable */395 396	/*397	 * BPLCON2 -- Bitplane Control Register 2398	 */399 400#define BPC2_ZDBPSEL2	(0x4000) /* Bitplane to be used for ZD - AGA */401#define BPC2_ZDBPSEL1	(0x2000)402#define BPC2_ZDBPSEL0	(0x1000)403#define BPC2_ZDBPEN	(0x0800) /* Enable ZD with ZDBPSELx - AGA */404#define BPC2_ZDCTEN	(0x0400) /* Enable ZD with palette bit #31 - AGA */405#define BPC2_KILLEHB	(0x0200) /* Kill EHB mode - AGA */406#define BPC2_RDRAM	(0x0100) /* Color table accesses read, not write - AGA */407#define BPC2_SOGEN	(0x0080) /* SOG output pin high - AGA */408#define BPC2_PF2PRI	(0x0040) /* PF2 priority over PF1 */409#define BPC2_PF2P2	(0x0020) /* PF2 priority wrt sprites */410#define BPC2_PF2P1	(0x0010)411#define BPC2_PF2P0	(0x0008)412#define BPC2_PF1P2	(0x0004) /* ditto PF1 */413#define BPC2_PF1P1	(0x0002)414#define BPC2_PF1P0	(0x0001)415 416	/*417	 * BPLCON3 -- Bitplane Control Register 3 (AGA)418	 */419 420#define BPC3_BANK2	(0x8000) /* Bits to select color register bank */421#define BPC3_BANK1	(0x4000)422#define BPC3_BANK0	(0x2000)423#define BPC3_PF2OF2	(0x1000) /* Bits for color table offset when PF2 */424#define BPC3_PF2OF1	(0x0800)425#define BPC3_PF2OF0	(0x0400)426#define BPC3_LOCT	(0x0200) /* Color register writes go to low bits */427#define BPC3_SPRES1	(0x0080) /* Sprite resolution bits */428#define BPC3_SPRES0	(0x0040)429#define BPC3_BRDRBLNK	(0x0020) /* Border blanked? */430#define BPC3_BRDRTRAN	(0x0010) /* Border transparent? */431#define BPC3_ZDCLKEN	(0x0004) /* ZD pin is 14 MHz (HIRES) clock output */432#define BPC3_BRDRSPRT	(0x0002) /* Sprites in border? */433#define BPC3_EXTBLKEN	(0x0001) /* BLANK programmable */434 435	/*436	 * BPLCON4 -- Bitplane Control Register 4 (AGA)437	 */438 439#define BPC4_BPLAM7	(0x8000) /* bitplane color XOR field */440#define BPC4_BPLAM6	(0x4000)441#define BPC4_BPLAM5	(0x2000)442#define BPC4_BPLAM4	(0x1000)443#define BPC4_BPLAM3	(0x0800)444#define BPC4_BPLAM2	(0x0400)445#define BPC4_BPLAM1	(0x0200)446#define BPC4_BPLAM0	(0x0100)447#define BPC4_ESPRM7	(0x0080) /* 4 high bits for even sprite colors */448#define BPC4_ESPRM6	(0x0040)449#define BPC4_ESPRM5	(0x0020)450#define BPC4_ESPRM4	(0x0010)451#define BPC4_OSPRM7	(0x0008) /* 4 high bits for odd sprite colors */452#define BPC4_OSPRM6	(0x0004)453#define BPC4_OSPRM5	(0x0002)454#define BPC4_OSPRM4	(0x0001)455 456	/*457	 * BEAMCON0 -- Beam Control Register458	 */459 460#define BMC0_HARDDIS	(0x4000) /* Disable hardware limits */461#define BMC0_LPENDIS	(0x2000) /* Disable light pen latch */462#define BMC0_VARVBEN	(0x1000) /* Enable variable vertical blank */463#define BMC0_LOLDIS	(0x0800) /* Disable long/short line toggle */464#define BMC0_CSCBEN	(0x0400) /* Composite sync/blank */465#define BMC0_VARVSYEN	(0x0200) /* Enable variable vertical sync */466#define BMC0_VARHSYEN	(0x0100) /* Enable variable horizontal sync */467#define BMC0_VARBEAMEN	(0x0080) /* Enable variable beam counters */468#define BMC0_DUAL	(0x0040) /* Enable alternate horizontal beam counter */469#define BMC0_PAL	(0x0020) /* Set decodes for PAL */470#define BMC0_VARCSYEN	(0x0010) /* Enable variable composite sync */471#define BMC0_BLANKEN	(0x0008) /* Blank enable (no longer used on AGA) */472#define BMC0_CSYTRUE	(0x0004) /* CSY polarity */473#define BMC0_VSYTRUE	(0x0002) /* VSY polarity */474#define BMC0_HSYTRUE	(0x0001) /* HSY polarity */475 476 477	/*478	 * FMODE -- Fetch Mode Control Register (AGA)479	 */480 481#define FMODE_SSCAN2	(0x8000) /* Sprite scan-doubling */482#define FMODE_BSCAN2	(0x4000) /* Use PF2 modulus every other line */483#define FMODE_SPAGEM	(0x0008) /* Sprite page mode */484#define FMODE_SPR32	(0x0004) /* Sprite 32 bit fetch */485#define FMODE_BPAGEM	(0x0002) /* Bitplane page mode */486#define FMODE_BPL32	(0x0001) /* Bitplane 32 bit fetch */487 488	/*489	 * Tags used to indicate a specific Pixel Clock490	 *491	 * clk_shift is the shift value to get the timings in 35 ns units492	 */493 494enum { TAG_SHRES, TAG_HIRES, TAG_LORES };495 496	/*497	 * Tags used to indicate the specific chipset498	 */499 500enum { TAG_OCS, TAG_ECS, TAG_AGA };501 502	/*503	 * Tags used to indicate the memory bandwidth504	 */505 506enum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 };507 508 509	/*510	 * Clock Definitions, Maximum Display Depth511	 *512	 * These depend on the E-Clock or the Chipset, so they are filled in513	 * dynamically514	 */515 516static u_long pixclock[3];	/* SHRES/HIRES/LORES: index = clk_shift */517static u_short maxdepth[3];	/* SHRES/HIRES/LORES: index = clk_shift */518static u_short maxfmode, chipset;519 520 521	/*522	 * Broadcast Video Timings523	 *524	 * Horizontal values are in 35 ns (SHRES) units525	 * Vertical values are in interlaced scanlines526	 */527 528#define PAL_DIWSTRT_H	(360)	/* PAL Window Limits */529#define PAL_DIWSTRT_V	(48)530#define PAL_HTOTAL	(1816)531#define PAL_VTOTAL	(625)532 533#define NTSC_DIWSTRT_H	(360)	/* NTSC Window Limits */534#define NTSC_DIWSTRT_V	(40)535#define NTSC_HTOTAL	(1816)536#define NTSC_VTOTAL	(525)537 538 539	/*540	 * Various macros541	 */542 543#define up2(v)		(((v) + 1) & -2)544#define down2(v)	((v) & -2)545#define div2(v)		((v)>>1)546#define mod2(v)		((v) & 1)547 548#define up4(v)		(((v) + 3) & -4)549#define down4(v)	((v) & -4)550#define mul4(v)		((v) << 2)551#define div4(v)		((v)>>2)552#define mod4(v)		((v) & 3)553 554#define up8(v)		(((v) + 7) & -8)555#define down8(v)	((v) & -8)556#define div8(v)		((v)>>3)557#define mod8(v)		((v) & 7)558 559#define up16(v)		(((v) + 15) & -16)560#define down16(v)	((v) & -16)561#define div16(v)	((v)>>4)562#define mod16(v)	((v) & 15)563 564#define up32(v)		(((v) + 31) & -32)565#define down32(v)	((v) & -32)566#define div32(v)	((v)>>5)567#define mod32(v)	((v) & 31)568 569#define up64(v)		(((v) + 63) & -64)570#define down64(v)	((v) & -64)571#define div64(v)	((v)>>6)572#define mod64(v)	((v) & 63)573 574#define upx(x, v)	(((v) + (x) - 1) & -(x))575#define downx(x, v)	((v) & -(x))576#define modx(x, v)	((v) & ((x) - 1))577 578/*579 * FIXME: Use C variants of the code marked with #ifdef __mc68000__580 * in the driver. It shouldn't negatively affect the performance and581 * is required for APUS support (once it is re-added to the kernel).582 * Needs to be tested on the hardware though..583 */584/* if x1 is not a constant, this macro won't make real sense :-) */585#ifdef __mc68000__586#define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \587	"d" (x2), "d" ((long)((x1) / 0x100000000ULL)), "0" ((long)(x1))); res;})588#else589/* We know a bit about the numbers, so we can do it this way */590#define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \591	((((long)((unsigned long long)x1 >> 8) % x2) << 8) / x2))592#endif593 594#define highw(x)	((u_long)(x)>>16 & 0xffff)595#define loww(x)		((u_long)(x) & 0xffff)596 597#define custom		amiga_custom598 599#define VBlankOn()	custom.intena = IF_SETCLR|IF_COPER600#define VBlankOff()	custom.intena = IF_COPER601 602 603	/*604	 * Chip RAM we reserve for the Frame Buffer605	 *606	 * This defines the Maximum Virtual Screen Size607	 * (Setable per kernel options?)608	 */609 610#define VIDEOMEMSIZE_AGA_2M	(1310720) /* AGA (2MB) : max 1280*1024*256  */611#define VIDEOMEMSIZE_AGA_1M	(786432)  /* AGA (1MB) : max 1024*768*256   */612#define VIDEOMEMSIZE_ECS_2M	(655360)  /* ECS (2MB) : max 1280*1024*16   */613#define VIDEOMEMSIZE_ECS_1M	(393216)  /* ECS (1MB) : max 1024*768*16    */614#define VIDEOMEMSIZE_OCS	(262144)  /* OCS       : max ca. 800*600*16 */615 616#define SPRITEMEMSIZE		(64 * 64 / 4) /* max 64*64*4 */617#define DUMMYSPRITEMEMSIZE	(8)618static u_long spritememory;619 620#define CHIPRAM_SAFETY_LIMIT	(16384)621 622static u_long videomemory;623 624	/*625	 * This is the earliest allowed start of fetching display data.626	 * Only if you really want no hardware cursor and audio,627	 * set this to 128, but let it better at 192628	 */629 630static u_long min_fstrt = 192;631 632#define assignchunk(name, type, ptr, size) \633{ \634	(name) = (type)(ptr); \635	ptr += size; \636}637 638 639	/*640	 * Copper Instructions641	 */642 643#define CMOVE(val, reg)		(CUSTOM_OFS(reg) << 16 | (val))644#define CMOVE2(val, reg)	((CUSTOM_OFS(reg) + 2) << 16 | (val))645#define CWAIT(x, y)		(((y) & 0x1fe) << 23 | ((x) & 0x7f0) << 13 | 0x0001fffe)646#define CEND			(0xfffffffe)647 648 649typedef union {650	u_long l;651	u_short w[2];652} copins;653 654static struct copdisplay {655	copins *init;656	copins *wait;657	copins *list[2][2];658	copins *rebuild[2];659} copdisplay;660 661static u_short currentcop = 0;662 663	/*664	 * Hardware Cursor API Definitions665	 * These used to be in linux/fb.h, but were preliminary and used by666	 * amifb only anyway667	 */668 669#define FBIOGET_FCURSORINFO     0x4607670#define FBIOGET_VCURSORINFO     0x4608671#define FBIOPUT_VCURSORINFO     0x4609672#define FBIOGET_CURSORSTATE     0x460A673#define FBIOPUT_CURSORSTATE     0x460B674 675 676struct fb_fix_cursorinfo {677	__u16 crsr_width;		/* width and height of the cursor in */678	__u16 crsr_height;		/* pixels (zero if no cursor)	*/679	__u16 crsr_xsize;		/* cursor size in display pixels */680	__u16 crsr_ysize;681	__u16 crsr_color1;		/* colormap entry for cursor color1 */682	__u16 crsr_color2;		/* colormap entry for cursor color2 */683};684 685struct fb_var_cursorinfo {686	__u16 width;687	__u16 height;688	__u16 xspot;689	__u16 yspot;690	DECLARE_FLEX_ARRAY(__u8, data);	/* field with [height][width]        */691};692 693struct fb_cursorstate {694	__s16 xoffset;695	__s16 yoffset;696	__u16 mode;697};698 699#define FB_CURSOR_OFF		0700#define FB_CURSOR_ON		1701#define FB_CURSOR_FLASH		2702 703 704	/*705	 * Hardware Cursor706	 */707 708static int cursorrate = 20;	/* Number of frames/flash toggle */709static u_short cursorstate = -1;710static u_short cursormode = FB_CURSOR_OFF;711 712static u_short *lofsprite, *shfsprite, *dummysprite;713 714	/*715	 * Current Video Mode716	 */717 718struct amifb_par {719 720	/* General Values */721 722	int xres;		/* vmode */723	int yres;		/* vmode */724	int vxres;		/* vmode */725	int vyres;		/* vmode */726	int xoffset;		/* vmode */727	int yoffset;		/* vmode */728	u_short bpp;		/* vmode */729	u_short clk_shift;	/* vmode */730	u_short line_shift;	/* vmode */731	int vmode;		/* vmode */732	u_short diwstrt_h;	/* vmode */733	u_short diwstop_h;	/* vmode */734	u_short diwstrt_v;	/* vmode */735	u_short diwstop_v;	/* vmode */736	u_long next_line;	/* modulo for next line */737	u_long next_plane;	/* modulo for next plane */738 739	/* Cursor Values */740 741	struct {742		short crsr_x;	/* movecursor */743		short crsr_y;	/* movecursor */744		short spot_x;745		short spot_y;746		u_short height;747		u_short width;748		u_short fmode;749	} crsr;750 751	/* OCS Hardware Registers */752 753	u_long bplpt0;		/* vmode, pan (Note: physical address) */754	u_long bplpt0wrap;	/* vmode, pan (Note: physical address) */755	u_short ddfstrt;756	u_short ddfstop;757	u_short bpl1mod;758	u_short bpl2mod;759	u_short bplcon0;	/* vmode */760	u_short bplcon1;	/* vmode */761	u_short htotal;		/* vmode */762	u_short vtotal;		/* vmode */763 764	/* Additional ECS Hardware Registers */765 766	u_short bplcon3;	/* vmode */767	u_short beamcon0;	/* vmode */768	u_short hsstrt;		/* vmode */769	u_short hsstop;		/* vmode */770	u_short hbstrt;		/* vmode */771	u_short hbstop;		/* vmode */772	u_short vsstrt;		/* vmode */773	u_short vsstop;		/* vmode */774	u_short vbstrt;		/* vmode */775	u_short vbstop;		/* vmode */776	u_short hcenter;	/* vmode */777 778	/* Additional AGA Hardware Registers */779 780	u_short fmode;		/* vmode */781};782 783 784	/*785	 *  Saved color entry 0 so we can restore it when unblanking786	 */787 788static u_char red0, green0, blue0;789 790 791#if defined(CONFIG_FB_AMIGA_ECS)792static u_short ecs_palette[32];793#endif794 795 796	/*797	 * Latches for Display Changes during VBlank798	 */799 800static u_short do_vmode_full = 0;	/* Change the Video Mode */801static u_short do_vmode_pan = 0;	/* Update the Video Mode */802static short do_blank = 0;		/* (Un)Blank the Screen (±1) */803static u_short do_cursor = 0;		/* Move the Cursor */804 805 806	/*807	 * Various Flags808	 */809 810static u_short is_blanked = 0;		/* Screen is Blanked */811static u_short is_lace = 0;		/* Screen is laced */812 813	/*814	 * Predefined Video Modes815	 *816	 */817 818static struct fb_videomode ami_modedb[] __initdata = {819 820	/*821	 *  AmigaOS Video Modes822	 *823	 *  If you change these, make sure to update DEFMODE_* as well!824	 */825 826	{827		/* 640x200, 15 kHz, 60 Hz (NTSC) */828		"ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2,829		FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP830	}, {831		/* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */832		"ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4,833		FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP834	}, {835		/* 640x256, 15 kHz, 50 Hz (PAL) */836		"pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2,837		FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP838	}, {839		/* 640x512, 15 kHz, 50 Hz interlaced (PAL) */840		"pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4,841		FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP842	}, {843		/* 640x480, 29 kHz, 57 Hz */844		"multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8,845		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP846	}, {847		/* 640x960, 29 kHz, 57 Hz interlaced */848		"multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72,849		16,850		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP851	}, {852		/* 640x200, 15 kHz, 72 Hz */853		"euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5,854		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP855	}, {856		/* 640x400, 15 kHz, 72 Hz interlaced */857		"euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52,858		10,859		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP860	}, {861		/* 640x400, 29 kHz, 68 Hz */862		"euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8,863		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP864	}, {865		/* 640x800, 29 kHz, 68 Hz interlaced */866		"euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80,867		16,868		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP869	}, {870		/* 800x300, 23 kHz, 70 Hz */871		"super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7,872		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP873	}, {874		/* 800x600, 23 kHz, 70 Hz interlaced */875		"super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80,876		14,877		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP878	}, {879		/* 640x200, 27 kHz, 57 Hz doublescan */880		"dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4,881		0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP882	}, {883		/* 640x400, 27 kHz, 57 Hz */884		"dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7,885		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP886	}, {887		/* 640x800, 27 kHz, 57 Hz interlaced */888		"dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80,889		14,890		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP891	}, {892		/* 640x256, 27 kHz, 47 Hz doublescan */893		"dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4,894		0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP895	}, {896		/* 640x512, 27 kHz, 47 Hz */897		"dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7,898		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP899	}, {900		/* 640x1024, 27 kHz, 47 Hz interlaced */901		"dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80,902		14,903		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP904	},905 906	/*907	 *  VGA Video Modes908	 */909 910	{911		/* 640x480, 31 kHz, 60 Hz (VGA) */912		"vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2,913		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP914	}, {915		/* 640x400, 31 kHz, 70 Hz (VGA) */916		"vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2,917		FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT,918		FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP919	},920 921#if 0922 923	/*924	 *  A2024 video modes925	 *  These modes don't work yet because there's no A2024 driver.926	 */927 928	{929		/* 1024x800, 10 Hz */930		"a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,931		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP932	}, {933		/* 1024x800, 15 Hz */934		"a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,935		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP936	}937#endif938};939 940#define NUM_TOTAL_MODES  ARRAY_SIZE(ami_modedb)941 942static char *mode_option __initdata = NULL;943static int round_down_bpp = 1;	/* for mode probing */944 945	/*946	 * Some default modes947	 */948 949 950#define DEFMODE_PAL	    2	/* "pal" for PAL OCS/ECS */951#define DEFMODE_NTSC	    0	/* "ntsc" for NTSC OCS/ECS */952#define DEFMODE_AMBER_PAL   3	/* "pal-lace" for flicker fixed PAL (A3000) */953#define DEFMODE_AMBER_NTSC  1	/* "ntsc-lace" for flicker fixed NTSC (A3000) */954#define DEFMODE_AGA	    19	/* "vga70" for AGA */955 956 957static int amifb_ilbm = 0;	/* interleaved or normal bitplanes */958 959static u32 amifb_hfmin __initdata;	/* monitor hfreq lower limit (Hz) */960static u32 amifb_hfmax __initdata;	/* monitor hfreq upper limit (Hz) */961static u16 amifb_vfmin __initdata;	/* monitor vfreq lower limit (Hz) */962static u16 amifb_vfmax __initdata;	/* monitor vfreq upper limit (Hz) */963 964 965	/*966	 * Macros for the conversion from real world values to hardware register967	 * values968	 *969	 * This helps us to keep our attention on the real stuff...970	 *971	 * Hardware limits for AGA:972	 *973	 *	parameter  min    max  step974	 *	---------  ---   ----  ----975	 *	diwstrt_h    0   2047     1976	 *	diwstrt_v    0   2047     1977	 *	diwstop_h    0   4095     1978	 *	diwstop_v    0   4095     1979	 *980	 *	ddfstrt      0   2032    16981	 *	ddfstop      0   2032    16982	 *983	 *	htotal       8   2048     8984	 *	hsstrt       0   2040     8985	 *	hsstop       0   2040     8986	 *	vtotal       1   4096     1987	 *	vsstrt       0   4095     1988	 *	vsstop       0   4095     1989	 *	hcenter      0   2040     8990	 *991	 *	hbstrt       0   2047     1992	 *	hbstop       0   2047     1993	 *	vbstrt       0   4095     1994	 *	vbstop       0   4095     1995	 *996	 * Horizontal values are in 35 ns (SHRES) pixels997	 * Vertical values are in half scanlines998	 */999 1000/* bplcon1 (smooth scrolling) */1001 1002#define hscroll2hw(hscroll) \1003	(((hscroll) << 12 & 0x3000) | ((hscroll) << 8 & 0xc300) | \1004	 ((hscroll) << 4 & 0x0c00) | ((hscroll) << 2 & 0x00f0) | \1005	 ((hscroll)>>2 & 0x000f))1006 1007/* diwstrt/diwstop/diwhigh (visible display window) */1008 1009#define diwstrt2hw(diwstrt_h, diwstrt_v) \1010	(((diwstrt_v) << 7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))1011#define diwstop2hw(diwstop_h, diwstop_v) \1012	(((diwstop_v) << 7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))1013#define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \1014	(((diwstop_h) << 3 & 0x2000) | ((diwstop_h) << 11 & 0x1800) | \1015	 ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \1016	 ((diwstrt_h) << 3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007))1017 1018/* ddfstrt/ddfstop (display DMA) */1019 1020#define ddfstrt2hw(ddfstrt)	div8(ddfstrt)1021#define ddfstop2hw(ddfstop)	div8(ddfstop)1022 1023/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */1024 1025#define hsstrt2hw(hsstrt)	(div8(hsstrt))1026#define hsstop2hw(hsstop)	(div8(hsstop))1027#define htotal2hw(htotal)	(div8(htotal) - 1)1028#define vsstrt2hw(vsstrt)	(div2(vsstrt))1029#define vsstop2hw(vsstop)	(div2(vsstop))1030#define vtotal2hw(vtotal)	(div2(vtotal) - 1)1031#define hcenter2hw(htotal)	(div8(htotal))1032 1033/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */1034 1035#define hbstrt2hw(hbstrt)	(((hbstrt) << 8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))1036#define hbstop2hw(hbstop)	(((hbstop) << 8 & 0x0700) | ((hbstop)>>3 & 0x00ff))1037#define vbstrt2hw(vbstrt)	(div2(vbstrt))1038#define vbstop2hw(vbstop)	(div2(vbstop))1039 1040/* colour */1041 1042#define rgb2hw8_high(red, green, blue) \1043	(((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4))1044#define rgb2hw8_low(red, green, blue) \1045	(((red & 0x0f) << 8) | ((green & 0x0f) << 4) | (blue & 0x0f))1046#define rgb2hw4(red, green, blue) \1047	(((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4))1048#define rgb2hw2(red, green, blue) \1049	(((red & 0xc0) << 4) | (green & 0xc0) | ((blue & 0xc0)>>4))1050 1051/* sprpos/sprctl (sprite positioning) */1052 1053#define spr2hw_pos(start_v, start_h) \1054	(((start_v) << 7 & 0xff00) | ((start_h)>>3 & 0x00ff))1055#define spr2hw_ctl(start_v, start_h, stop_v) \1056	(((stop_v) << 7 & 0xff00) | ((start_v)>>4 & 0x0040) | \1057	 ((stop_v)>>5 & 0x0020) | ((start_h) << 3 & 0x0018) | \1058	 ((start_v)>>7 & 0x0004) | ((stop_v)>>8 & 0x0002) | \1059	 ((start_h)>>2 & 0x0001))1060 1061/* get current vertical position of beam */1062#define get_vbpos()	((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe))1063 1064	/*1065	 * Copper Initialisation List1066	 */1067 1068#define COPINITSIZE (sizeof(copins) * 40)1069 1070enum {1071	cip_bplcon01072};1073 1074	/*1075	 * Long Frame/Short Frame Copper List1076	 * Don't change the order, build_copper()/rebuild_copper() rely on this1077	 */1078 1079#define COPLISTSIZE (sizeof(copins) * 64)1080 1081enum {1082	cop_wait, cop_bplcon0,1083	cop_spr0ptrh, cop_spr0ptrl,1084	cop_diwstrt, cop_diwstop,1085	cop_diwhigh,1086};1087 1088	/*1089	 * Pixel modes for Bitplanes and Sprites1090	 */1091 1092static u_short bplpixmode[3] = {1093	BPC0_SHRES,			/*  35 ns */1094	BPC0_HIRES,			/*  70 ns */1095	0				/* 140 ns */1096};1097 1098static u_short sprpixmode[3] = {1099	BPC3_SPRES1 | BPC3_SPRES0,	/*  35 ns */1100	BPC3_SPRES1,			/*  70 ns */1101	BPC3_SPRES0			/* 140 ns */1102};1103 1104	/*1105	 * Fetch modes for Bitplanes and Sprites1106	 */1107 1108static u_short bplfetchmode[3] = {1109	0,				/* 1x */1110	FMODE_BPL32,			/* 2x */1111	FMODE_BPAGEM | FMODE_BPL32	/* 4x */1112};1113 1114static u_short sprfetchmode[3] = {1115	0,				/* 1x */1116	FMODE_SPR32,			/* 2x */1117	FMODE_SPAGEM | FMODE_SPR32	/* 4x */1118};1119 1120 1121/* --------------------------- Hardware routines --------------------------- */1122 1123	/*1124	 * Get the video params out of `var'. If a value doesn't fit, round1125	 * it up, if it's too big, return -EINVAL.1126	 */1127 1128static int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par,1129			  const struct fb_info *info)1130{1131	u_short clk_shift, line_shift;1132	u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;1133	u_int htotal, vtotal;1134 1135	/*1136	 * Find a matching Pixel Clock1137	 */1138 1139	for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++)1140		if (var->pixclock <= pixclock[clk_shift])1141			break;1142	if (clk_shift > TAG_LORES) {1143		DPRINTK("pixclock too high\n");1144		return -EINVAL;1145	}1146	par->clk_shift = clk_shift;1147 1148	/*1149	 * Check the Geometry Values1150	 */1151 1152	if ((par->xres = var->xres) < 64)1153		par->xres = 64;1154	if ((par->yres = var->yres) < 64)1155		par->yres = 64;1156	if ((par->vxres = var->xres_virtual) < par->xres)1157		par->vxres = par->xres;1158	if ((par->vyres = var->yres_virtual) < par->yres)1159		par->vyres = par->yres;1160 1161	par->bpp = var->bits_per_pixel;1162	if (!var->nonstd) {1163		if (par->bpp < 1)1164			par->bpp = 1;1165		if (par->bpp > maxdepth[clk_shift]) {1166			if (round_down_bpp && maxdepth[clk_shift])1167				par->bpp = maxdepth[clk_shift];1168			else {1169				DPRINTK("invalid bpp\n");1170				return -EINVAL;1171			}1172		}1173	} else if (var->nonstd == FB_NONSTD_HAM) {1174		if (par->bpp < 6)1175			par->bpp = 6;1176		if (par->bpp != 6) {1177			if (par->bpp < 8)1178				par->bpp = 8;1179			if (par->bpp != 8 || !IS_AGA) {1180				DPRINTK("invalid bpp for ham mode\n");1181				return -EINVAL;1182			}1183		}1184	} else {1185		DPRINTK("unknown nonstd mode\n");1186		return -EINVAL;1187	}1188 1189	/*1190	 * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the following1191	 * checks failed and smooth scrolling is not possible1192	 */1193 1194	par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN;1195	switch (par->vmode & FB_VMODE_MASK) {1196	case FB_VMODE_INTERLACED:1197		line_shift = 0;1198		break;1199	case FB_VMODE_NONINTERLACED:1200		line_shift = 1;1201		break;1202	case FB_VMODE_DOUBLE:1203		if (!IS_AGA) {1204			DPRINTK("double mode only possible with aga\n");1205			return -EINVAL;1206		}1207		line_shift = 2;1208		break;1209	default:1210		DPRINTK("unknown video mode\n");1211		return -EINVAL;1212		break;1213	}1214	par->line_shift = line_shift;1215 1216	/*1217	 * Vertical and Horizontal Timings1218	 */1219 1220	xres_n = par->xres << clk_shift;1221	yres_n = par->yres << line_shift;1222	par->htotal = down8((var->left_margin + par->xres + var->right_margin +1223			     var->hsync_len) << clk_shift);1224	par->vtotal =1225		down2(((var->upper_margin + par->yres + var->lower_margin +1226			var->vsync_len) << line_shift) + 1);1227 1228	if (IS_AGA)1229		par->bplcon3 = sprpixmode[clk_shift];1230	else1231		par->bplcon3 = 0;1232	if (var->sync & FB_SYNC_BROADCAST) {1233		par->diwstop_h = par->htotal -1234			((var->right_margin - var->hsync_len) << clk_shift);1235		if (IS_AGA)1236			par->diwstop_h += mod4(var->hsync_len);1237		else1238			par->diwstop_h = down4(par->diwstop_h);1239 1240		par->diwstrt_h = par->diwstop_h - xres_n;1241		par->diwstop_v = par->vtotal -1242			((var->lower_margin - var->vsync_len) << line_shift);1243		par->diwstrt_v = par->diwstop_v - yres_n;1244		if (par->diwstop_h >= par->htotal + 8) {1245			DPRINTK("invalid diwstop_h\n");1246			return -EINVAL;1247		}1248		if (par->diwstop_v > par->vtotal) {1249			DPRINTK("invalid diwstop_v\n");1250			return -EINVAL;1251		}1252 1253		if (!IS_OCS) {1254			/* Initialize sync with some reasonable values for pwrsave */1255			par->hsstrt = 160;1256			par->hsstop = 320;1257			par->vsstrt = 30;1258			par->vsstop = 34;1259		} else {1260			par->hsstrt = 0;1261			par->hsstop = 0;1262			par->vsstrt = 0;1263			par->vsstop = 0;1264		}1265		if (par->vtotal > (PAL_VTOTAL + NTSC_VTOTAL) / 2) {1266			/* PAL video mode */1267			if (par->htotal != PAL_HTOTAL) {1268				DPRINTK("htotal invalid for pal\n");1269				return -EINVAL;1270			}1271			if (par->diwstrt_h < PAL_DIWSTRT_H) {1272				DPRINTK("diwstrt_h too low for pal\n");1273				return -EINVAL;1274			}1275			if (par->diwstrt_v < PAL_DIWSTRT_V) {1276				DPRINTK("diwstrt_v too low for pal\n");1277				return -EINVAL;1278			}1279			htotal = PAL_HTOTAL>>clk_shift;1280			vtotal = PAL_VTOTAL>>1;1281			if (!IS_OCS) {1282				par->beamcon0 = BMC0_PAL;1283				par->bplcon3 |= BPC3_BRDRBLNK;1284			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||1285				   AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {1286				par->beamcon0 = BMC0_PAL;1287				par->hsstop = 1;1288			} else if (amiga_vblank != 50) {1289				DPRINTK("pal not supported by this chipset\n");1290				return -EINVAL;1291			}1292		} else {1293			/* NTSC video mode1294			 * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK1295			 * and NTSC activated, so than better let diwstop_h <= 18121296			 */1297			if (par->htotal != NTSC_HTOTAL) {1298				DPRINTK("htotal invalid for ntsc\n");1299				return -EINVAL;1300			}1301			if (par->diwstrt_h < NTSC_DIWSTRT_H) {1302				DPRINTK("diwstrt_h too low for ntsc\n");1303				return -EINVAL;1304			}1305			if (par->diwstrt_v < NTSC_DIWSTRT_V) {1306				DPRINTK("diwstrt_v too low for ntsc\n");1307				return -EINVAL;1308			}1309			htotal = NTSC_HTOTAL>>clk_shift;1310			vtotal = NTSC_VTOTAL>>1;1311			if (!IS_OCS) {1312				par->beamcon0 = 0;1313				par->bplcon3 |= BPC3_BRDRBLNK;1314			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||1315				   AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {1316				par->beamcon0 = 0;1317				par->hsstop = 1;1318			} else if (amiga_vblank != 60) {1319				DPRINTK("ntsc not supported by this chipset\n");1320				return -EINVAL;1321			}1322		}1323		if (IS_OCS) {1324			if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 ||1325			    par->diwstrt_v >=  512 || par->diwstop_v <  256) {1326				DPRINTK("invalid position for display on ocs\n");1327				return -EINVAL;1328			}1329		}1330	} else if (!IS_OCS) {1331		/* Programmable video mode */1332		par->hsstrt = var->right_margin << clk_shift;1333		par->hsstop = (var->right_margin + var->hsync_len) << clk_shift;1334		par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift);1335		if (!IS_AGA)1336			par->diwstop_h = down4(par->diwstop_h) - 16;1337		par->diwstrt_h = par->diwstop_h - xres_n;1338		par->hbstop = par->diwstrt_h + 4;1339		par->hbstrt = par->diwstop_h + 4;1340		if (par->hbstrt >= par->htotal + 8)1341			par->hbstrt -= par->htotal;1342		par->hcenter = par->hsstrt + (par->htotal >> 1);1343		par->vsstrt = var->lower_margin << line_shift;1344		par->vsstop = (var->lower_margin + var->vsync_len) << line_shift;1345		par->diwstop_v = par->vtotal;1346		if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)1347			par->diwstop_v -= 2;1348		par->diwstrt_v = par->diwstop_v - yres_n;1349		par->vbstop = par->diwstrt_v - 2;1350		par->vbstrt = par->diwstop_v - 2;1351		if (par->vtotal > 2048) {1352			DPRINTK("vtotal too high\n");1353			return -EINVAL;1354		}1355		if (par->htotal > 2048) {1356			DPRINTK("htotal too high\n");1357			return -EINVAL;1358		}1359		par->bplcon3 |= BPC3_EXTBLKEN;1360		par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |1361				BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |1362				BMC0_PAL | BMC0_VARCSYEN;1363		if (var->sync & FB_SYNC_HOR_HIGH_ACT)1364			par->beamcon0 |= BMC0_HSYTRUE;1365		if (var->sync & FB_SYNC_VERT_HIGH_ACT)1366			par->beamcon0 |= BMC0_VSYTRUE;1367		if (var->sync & FB_SYNC_COMP_HIGH_ACT)1368			par->beamcon0 |= BMC0_CSYTRUE;1369		htotal = par->htotal>>clk_shift;1370		vtotal = par->vtotal>>1;1371	} else {1372		DPRINTK("only broadcast modes possible for ocs\n");1373		return -EINVAL;1374	}1375 1376	/*1377	 * Checking the DMA timing1378	 */1379 1380	fconst = 16 << maxfmode << clk_shift;1381 1382	/*1383	 * smallest window start value without turn off other dma cycles1384	 * than sprite1-7, unless you change min_fstrt1385	 */1386 1387 1388	fsize = ((maxfmode + clk_shift <= 1) ? fconst : 64);1389	fstrt = downx(fconst, par->diwstrt_h - 4) - fsize;1390	if (fstrt < min_fstrt) {1391		DPRINTK("fetch start too low\n");1392		return -EINVAL;1393	}1394 1395	/*1396	 * smallest window start value where smooth scrolling is possible1397	 */1398 1399	fstrt = downx(fconst, par->diwstrt_h - fconst + (1 << clk_shift) - 4) -1400		fsize;1401	if (fstrt < min_fstrt)1402		par->vmode &= ~FB_VMODE_SMOOTH_XPAN;1403 1404	maxfetchstop = down16(par->htotal - 80);1405 1406	fstrt = downx(fconst, par->diwstrt_h - 4) - 64 - fconst;1407	fsize = upx(fconst, xres_n +1408		    modx(fconst, downx(1 << clk_shift, par->diwstrt_h - 4)));1409	if (fstrt + fsize > maxfetchstop)1410		par->vmode &= ~FB_VMODE_SMOOTH_XPAN;1411 1412	fsize = upx(fconst, xres_n);1413	if (fstrt + fsize > maxfetchstop) {1414		DPRINTK("fetch stop too high\n");1415		return -EINVAL;1416	}1417 1418	if (maxfmode + clk_shift <= 1) {1419		fsize = up64(xres_n + fconst - 1);1420		if (min_fstrt + fsize - 64 > maxfetchstop)1421			par->vmode &= ~FB_VMODE_SMOOTH_XPAN;1422 1423		fsize = up64(xres_n);1424		if (min_fstrt + fsize - 64 > maxfetchstop) {1425			DPRINTK("fetch size too high\n");1426			return -EINVAL;1427		}1428 1429		fsize -= 64;1430	} else1431		fsize -= fconst;1432 1433	/*1434	 * Check if there is enough time to update the bitplane pointers for ywrap1435	 */1436 1437	if (par->htotal - fsize - 64 < par->bpp * 64)1438		par->vmode &= ~FB_VMODE_YWRAP;1439 1440	/*1441	 * Bitplane calculations and check the Memory Requirements1442	 */1443 1444	if (amifb_ilbm) {1445		par->next_plane = div8(upx(16 << maxfmode, par->vxres));1446		par->next_line = par->bpp * par->next_plane;1447		if (par->next_line * par->vyres > info->fix.smem_len) {1448			DPRINTK("too few video mem\n");1449			return -EINVAL;1450		}1451	} else {1452		par->next_line = div8(upx(16 << maxfmode, par->vxres));1453		par->next_plane = par->vyres * par->next_line;1454		if (par->next_plane * par->bpp > info->fix.smem_len) {1455			DPRINTK("too few video mem\n");1456			return -EINVAL;1457		}1458	}1459 1460	/*1461	 * Hardware Register Values1462	 */1463 1464	par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift];1465	if (!IS_OCS)1466		par->bplcon0 |= BPC0_ECSENA;1467	if (par->bpp == 8)1468		par->bplcon0 |= BPC0_BPU3;1469	else1470		par->bplcon0 |= par->bpp << 12;1471	if (var->nonstd == FB_NONSTD_HAM)1472		par->bplcon0 |= BPC0_HAM;1473	if (var->sync & FB_SYNC_EXT)1474		par->bplcon0 |= BPC0_ERSY;1475 1476	if (IS_AGA)1477		par->fmode = bplfetchmode[maxfmode];1478 1479	switch (par->vmode & FB_VMODE_MASK) {1480	case FB_VMODE_INTERLACED:1481		par->bplcon0 |= BPC0_LACE;1482		break;1483	case FB_VMODE_DOUBLE:1484		if (IS_AGA)1485			par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;1486		break;1487	}1488 1489	if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {1490		par->xoffset = var->xoffset;1491		par->yoffset = var->yoffset;1492		if (par->vmode & FB_VMODE_YWRAP) {1493			if (par->yoffset >= par->vyres)1494				par->xoffset = par->yoffset = 0;1495		} else {1496			if (par->xoffset > upx(16 << maxfmode, par->vxres - par->xres) ||1497			    par->yoffset > par->vyres - par->yres)1498				par->xoffset = par->yoffset = 0;1499		}1500	} else1501		par->xoffset = par->yoffset = 0;1502 1503	par->crsr.crsr_x = par->crsr.crsr_y = 0;1504	par->crsr.spot_x = par->crsr.spot_y = 0;1505	par->crsr.height = par->crsr.width = 0;1506 1507	return 0;1508}1509 1510	/*1511	 * Fill the `var' structure based on the values in `par' and maybe1512	 * other values read out of the hardware.1513	 */1514 1515static void ami_encode_var(struct fb_var_screeninfo *var,1516			   struct amifb_par *par)1517{1518	u_short clk_shift, line_shift;1519 1520	memset(var, 0, sizeof(struct fb_var_screeninfo));1521 1522	clk_shift = par->clk_shift;1523	line_shift = par->line_shift;1524 1525	var->xres = par->xres;1526	var->yres = par->yres;1527	var->xres_virtual = par->vxres;1528	var->yres_virtual = par->vyres;1529	var->xoffset = par->xoffset;1530	var->yoffset = par->yoffset;1531 1532	var->bits_per_pixel = par->bpp;1533	var->grayscale = 0;1534 1535	var->red.offset = 0;1536	var->red.msb_right = 0;1537	var->red.length = par->bpp;1538	if (par->bplcon0 & BPC0_HAM)1539		var->red.length -= 2;1540	var->blue = var->green = var->red;1541	var->transp.offset = 0;1542	var->transp.length = 0;1543	var->transp.msb_right = 0;1544 1545	if (par->bplcon0 & BPC0_HAM)1546		var->nonstd = FB_NONSTD_HAM;1547	else1548		var->nonstd = 0;1549	var->activate = 0;1550 1551	var->height = -1;1552	var->width = -1;1553 1554	var->pixclock = pixclock[clk_shift];1555 1556	if (IS_AGA && par->fmode & FMODE_BSCAN2)1557		var->vmode = FB_VMODE_DOUBLE;1558	else if (par->bplcon0 & BPC0_LACE)1559		var->vmode = FB_VMODE_INTERLACED;1560	else1561		var->vmode = FB_VMODE_NONINTERLACED;1562 1563	if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) {1564		var->hsync_len = (par->hsstop - par->hsstrt)>>clk_shift;1565		var->right_margin = par->hsstrt>>clk_shift;1566		var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;1567		var->vsync_len = (par->vsstop - par->vsstrt)>>line_shift;1568		var->lower_margin = par->vsstrt>>line_shift;1569		var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len;1570		var->sync = 0;1571		if (par->beamcon0 & BMC0_HSYTRUE)1572			var->sync |= FB_SYNC_HOR_HIGH_ACT;1573		if (par->beamcon0 & BMC0_VSYTRUE)1574			var->sync |= FB_SYNC_VERT_HIGH_ACT;1575		if (par->beamcon0 & BMC0_CSYTRUE)1576			var->sync |= FB_SYNC_COMP_HIGH_ACT;1577	} else {1578		var->sync = FB_SYNC_BROADCAST;1579		var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h);1580		var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len;1581		var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;1582		var->vsync_len = 4>>line_shift;1583		var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len;1584		var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres -1585				    var->lower_margin - var->vsync_len;1586	}1587 1588	if (par->bplcon0 & BPC0_ERSY)1589		var->sync |= FB_SYNC_EXT;1590	if (par->vmode & FB_VMODE_YWRAP)1591		var->vmode |= FB_VMODE_YWRAP;1592}1593 1594 1595	/*1596	 * Update hardware1597	 */1598 1599static void ami_update_par(struct fb_info *info)1600{1601	struct amifb_par *par = info->par;1602	short clk_shift, vshift, fstrt, fsize, fstop, fconst,  shift, move, mod;1603 1604	clk_shift = par->clk_shift;1605 1606	if (!(par->vmode & FB_VMODE_SMOOTH_XPAN))1607		par->xoffset = upx(16 << maxfmode, par->xoffset);1608 1609	fconst = 16 << maxfmode << clk_shift;1610	vshift = modx(16 << maxfmode, par->xoffset);1611	fstrt = par->diwstrt_h - (vshift << clk_shift) - 4;1612	fsize = (par->xres + vshift) << clk_shift;1613	shift = modx(fconst, fstrt);1614	move = downx(2 << maxfmode, div8(par->xoffset));1615	if (maxfmode + clk_shift > 1) {1616		fstrt = downx(fconst, fstrt) - 64;1617		fsize = upx(fconst, fsize);1618		fstop = fstrt + fsize - fconst;1619	} else {1620		mod = fstrt = downx(fconst, fstrt) - fconst;1621		fstop = fstrt + upx(fconst, fsize) - 64;1622		fsize = up64(fsize);1623		fstrt = fstop - fsize + 64;1624		if (fstrt < min_fstrt) {1625			fstop += min_fstrt - fstrt;1626			fstrt = min_fstrt;1627		}1628		move = move - div8((mod - fstrt)>>clk_shift);1629	}1630	mod = par->next_line - div8(fsize>>clk_shift);1631	par->ddfstrt = fstrt;1632	par->ddfstop = fstop;1633	par->bplcon1 = hscroll2hw(shift);1634	par->bpl2mod = mod;1635	if (par->bplcon0 & BPC0_LACE)1636		par->bpl2mod += par->next_line;1637	if (IS_AGA && (par->fmode & FMODE_BSCAN2))1638		par->bpl1mod = -div8(fsize>>clk_shift);1639	else1640		par->bpl1mod = par->bpl2mod;1641 1642	if (par->yoffset) {1643		par->bplpt0 = info->fix.smem_start +1644			      par->next_line * par->yoffset + move;1645		if (par->vmode & FB_VMODE_YWRAP) {1646			if (par->yoffset > par->vyres - par->yres) {1647				par->bplpt0wrap = info->fix.smem_start + move;1648				if (par->bplcon0 & BPC0_LACE &&1649				    mod2(par->diwstrt_v + par->vyres -1650					 par->yoffset))1651					par->bplpt0wrap += par->next_line;1652			}1653		}1654	} else1655		par->bplpt0 = info->fix.smem_start + move;1656 1657	if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))1658		par->bplpt0 += par->next_line;1659}1660 1661 1662	/*1663	 * Pan or Wrap the Display1664	 *1665	 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag1666	 * in `var'.1667	 */1668 1669static void ami_pan_var(struct fb_var_screeninfo *var, struct fb_info *info)1670{1671	struct amifb_par *par = info->par;1672 1673	par->xoffset = var->xoffset;1674	par->yoffset = var->yoffset;1675	if (var->vmode & FB_VMODE_YWRAP)1676		par->vmode |= FB_VMODE_YWRAP;1677	else1678		par->vmode &= ~FB_VMODE_YWRAP;1679 1680	do_vmode_pan = 0;1681	ami_update_par(info);1682	do_vmode_pan = 1;1683}1684 1685 1686static void ami_update_display(const struct amifb_par *par)1687{1688	custom.bplcon1 = par->bplcon1;1689	custom.bpl1mod = par->bpl1mod;1690	custom.bpl2mod = par->bpl2mod;1691	custom.ddfstrt = ddfstrt2hw(par->ddfstrt);1692	custom.ddfstop = ddfstop2hw(par->ddfstop);1693}1694 1695	/*1696	 * Change the video mode (called by VBlank interrupt)1697	 */1698 1699static void ami_init_display(const struct amifb_par *par)1700{1701	int i;1702 1703	custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;1704	custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;1705	if (!IS_OCS) {1706		custom.bplcon3 = par->bplcon3;1707		if (IS_AGA)1708			custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;1709		if (par->beamcon0 & BMC0_VARBEAMEN) {1710			custom.htotal = htotal2hw(par->htotal);1711			custom.hbstrt = hbstrt2hw(par->hbstrt);1712			custom.hbstop = hbstop2hw(par->hbstop);1713			custom.hsstrt = hsstrt2hw(par->hsstrt);1714			custom.hsstop = hsstop2hw(par->hsstop);1715			custom.hcenter = hcenter2hw(par->hcenter);1716			custom.vtotal = vtotal2hw(par->vtotal);1717			custom.vbstrt = vbstrt2hw(par->vbstrt);1718			custom.vbstop = vbstop2hw(par->vbstop);1719			custom.vsstrt = vsstrt2hw(par->vsstrt);1720			custom.vsstop = vsstop2hw(par->vsstop);1721		}1722	}1723	if (!IS_OCS || par->hsstop)1724		custom.beamcon0 = par->beamcon0;1725	if (IS_AGA)1726		custom.fmode = par->fmode;1727 1728	/*1729	 * The minimum period for audio depends on htotal1730	 */1731 1732	amiga_audio_min_period = div16(par->htotal);1733 1734	is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;1735#if 11736	if (is_lace) {1737		i = custom.vposr >> 15;1738	} else {1739		custom.vposw = custom.vposr | 0x8000;1740		i = 1;1741	}1742#else1743	i = 1;1744	custom.vposw = custom.vposr | 0x8000;1745#endif1746	custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]);1747}1748 1749	/*1750	 * (Un)Blank the screen (called by VBlank interrupt)1751	 */1752 1753static void ami_do_blank(const struct amifb_par *par)1754{1755#if defined(CONFIG_FB_AMIGA_AGA)1756	u_short bplcon3 = par->bplcon3;1757#endif1758	u_char red, green, blue;1759 1760	if (do_blank > 0) {1761		custom.dmacon = DMAF_RASTER | DMAF_SPRITE;1762		red = green = blue = 0;1763		if (!IS_OCS && do_blank > 1) {1764			switch (do_blank) {1765			case FB_BLANK_VSYNC_SUSPEND:1766				custom.hsstrt = hsstrt2hw(par->hsstrt);1767				custom.hsstop = hsstop2hw(par->hsstop);1768				custom.vsstrt = vsstrt2hw(par->vtotal + 4);1769				custom.vsstop = vsstop2hw(par->vtotal + 4);1770				break;1771			case FB_BLANK_HSYNC_SUSPEND:1772				custom.hsstrt = hsstrt2hw(par->htotal + 16);1773				custom.hsstop = hsstop2hw(par->htotal + 16);1774				custom.vsstrt = vsstrt2hw(par->vsstrt);1775				custom.vsstop = vsstrt2hw(par->vsstop);1776				break;1777			case FB_BLANK_POWERDOWN:1778				custom.hsstrt = hsstrt2hw(par->htotal + 16);1779				custom.hsstop = hsstop2hw(par->htotal + 16);1780				custom.vsstrt = vsstrt2hw(par->vtotal + 4);1781				custom.vsstop = vsstop2hw(par->vtotal + 4);1782				break;1783			}1784			if (!(par->beamcon0 & BMC0_VARBEAMEN)) {1785				custom.htotal = htotal2hw(par->htotal);1786				custom.vtotal = vtotal2hw(par->vtotal);1787				custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN |1788						  BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN;1789			}1790		}1791	} else {1792		custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;1793		red = red0;1794		green = green0;1795		blue = blue0;1796		if (!IS_OCS) {1797			custom.hsstrt = hsstrt2hw(par->hsstrt);1798			custom.hsstop = hsstop2hw(par->hsstop);1799			custom.vsstrt = vsstrt2hw(par->vsstrt);1800			custom.vsstop = vsstop2hw(par->vsstop);1801			custom.beamcon0 = par->beamcon0;1802		}1803	}1804#if defined(CONFIG_FB_AMIGA_AGA)1805	if (IS_AGA) {1806		custom.bplcon3 = bplcon3;1807		custom.color[0] = rgb2hw8_high(red, green, blue);1808		custom.bplcon3 = bplcon3 | BPC3_LOCT;1809		custom.color[0] = rgb2hw8_low(red, green, blue);1810		custom.bplcon3 = bplcon3;1811	} else1812#endif1813#if defined(CONFIG_FB_AMIGA_ECS)1814	if (par->bplcon0 & BPC0_SHRES) {1815		u_short color, mask;1816		int i;1817 1818		mask = 0x3333;1819		color = rgb2hw2(red, green, blue);1820		for (i = 12; i >= 0; i -= 4)1821			custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;1822		mask <<= 2; color >>= 2;1823		for (i = 3; i >= 0; i--)1824			custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;1825	} else1826#endif1827		custom.color[0] = rgb2hw4(red, green, blue);1828	is_blanked = do_blank > 0 ? do_blank : 0;1829}1830 1831static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix,1832				  const struct amifb_par *par)1833{1834	fix->crsr_width = fix->crsr_xsize = par->crsr.width;1835	fix->crsr_height = fix->crsr_ysize = par->crsr.height;1836	fix->crsr_color1 = 17;1837	fix->crsr_color2 = 18;1838	return 0;1839}1840 1841static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var,1842				  u_char __user *data,1843				  const struct amifb_par *par)1844{1845	register u_short *lspr, *sspr;1846#ifdef __mc68000__1847	register u_long datawords asm ("d2");1848#else1849	register u_long datawords;1850#endif1851	register short delta;1852	register u_char color;1853	short height, width, bits, words;1854	int size, alloc;1855 1856	size = par->crsr.height * par->crsr.width;1857	alloc = var->height * var->width;1858	var->height = par->crsr.height;1859	var->width = par->crsr.width;1860	var->xspot = par->crsr.spot_x;1861	var->yspot = par->crsr.spot_y;1862	if (size > var->height * var->width)1863		return -ENAMETOOLONG;1864	delta = 1 << par->crsr.fmode;1865	lspr = lofsprite + (delta << 1);1866	if (par->bplcon0 & BPC0_LACE)1867		sspr = shfsprite + (delta << 1);1868	else1869		sspr = NULL;1870	for (height = (short)var->height - 1; height >= 0; height--) {1871		bits = 0; words = delta; datawords = 0;1872		for (width = (short)var->width - 1; width >= 0; width--) {1873			if (bits == 0) {1874				bits = 16; --words;1875#ifdef __mc68000__1876				asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0"1877					: "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta));1878#else1879				datawords = (*(lspr + delta) << 16) | (*lspr++);1880#endif1881			}1882			--bits;1883#ifdef __mc68000__1884			asm volatile (1885				"clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; "1886				"swap %1 ; lslw #1,%1 ; roxlb #1,%0"1887				: "=d" (color), "=d" (datawords) : "1" (datawords));1888#else1889			color = (((datawords >> 30) & 2)1890				 | ((datawords >> 15) & 1));1891			datawords <<= 1;1892#endif1893			/* FIXME: check the return value + test the change */1894			put_user(color, data++);1895		}1896		if (bits > 0) {1897			--words; ++lspr;1898		}1899		while (--words >= 0)1900			++lspr;1901#ifdef __mc68000__1902		asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"1903			: "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));1904#else1905		lspr += delta;1906		if (sspr) {1907			u_short *tmp = lspr;1908			lspr = sspr;1909			sspr = tmp;1910		}1911#endif1912	}1913	return 0;1914}1915 1916static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var,1917				  u_char __user *data, struct amifb_par *par)1918{1919	register u_short *lspr, *sspr;1920#ifdef __mc68000__1921	register u_long datawords asm ("d2");1922#else1923	register u_long datawords;1924#endif1925	register short delta;1926	u_short fmode;1927	short height, width, bits, words;1928 1929	if (!var->width)1930		return -EINVAL;1931	else if (var->width <= 16)1932		fmode = TAG_FMODE_1;1933	else if (var->width <= 32)1934		fmode = TAG_FMODE_2;1935	else if (var->width <= 64)1936		fmode = TAG_FMODE_4;1937	else1938		return -EINVAL;1939	if (fmode > maxfmode)1940		return -EINVAL;1941	if (!var->height)1942		return -EINVAL;1943	delta = 1 << fmode;1944	lofsprite = shfsprite = (u_short *)spritememory;1945	lspr = lofsprite + (delta << 1);1946	if (par->bplcon0 & BPC0_LACE) {1947		if (((var->height + 4) << fmode << 2) > SPRITEMEMSIZE)1948			return -EINVAL;1949		memset(lspr, 0, (var->height + 4) << fmode << 2);1950		shfsprite += ((var->height + 5)&-2) << fmode;1951		sspr = shfsprite + (delta << 1);1952	} else {1953		if (((var->height + 2) << fmode << 2) > SPRITEMEMSIZE)1954			return -EINVAL;1955		memset(lspr, 0, (var->height + 2) << fmode << 2);1956		sspr = NULL;1957	}1958	for (height = (short)var->height - 1; height >= 0; height--) {1959		bits = 16; words = delta; datawords = 0;1960		for (width = (short)var->width - 1; width >= 0; width--) {1961			unsigned long tdata = 0;1962			/* FIXME: check the return value + test the change */1963			get_user(tdata, data);1964			data++;1965#ifdef __mc68000__1966			asm volatile (1967				"lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; "1968				"lsrb #1,%2 ; roxlw #1,%0 ; swap %0"1969				: "=d" (datawords)1970				: "0" (datawords), "d" (tdata));1971#else1972			datawords = ((datawords << 1) & 0xfffefffe);1973			datawords |= tdata & 1;1974			datawords |= (tdata & 2) << (16 - 1);1975#endif1976			if (--bits == 0) {1977				bits = 16; --words;1978#ifdef __mc68000__1979				asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+"1980					: "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta));1981#else1982				*(lspr + delta) = (u_short) (datawords >> 16);1983				*lspr++ = (u_short) (datawords & 0xffff);1984#endif1985			}1986		}1987		if (bits < 16) {1988			--words;1989#ifdef __mc68000__1990			asm volatile (1991				"swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; "1992				"swap %2 ; lslw %4,%2 ; movew %2,%0@+"1993				: "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits));1994#else1995			*(lspr + delta) = (u_short) (datawords >> (16 + bits));1996			*lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits);1997#endif1998		}1999		while (--words >= 0) {2000#ifdef __mc68000__2001			asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+"2002				: "=a" (lspr) : "0" (lspr), "d" (delta) : "d0");2003#else2004			*(lspr + delta) = 0;2005			*lspr++ = 0;2006#endif2007		}2008#ifdef __mc68000__2009		asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"2010			: "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));2011#else2012		lspr += delta;2013		if (sspr) {2014			u_short *tmp = lspr;2015			lspr = sspr;2016			sspr = tmp;2017		}2018#endif2019	}2020	par->crsr.height = var->height;2021	par->crsr.width = var->width;2022	par->crsr.spot_x = var->xspot;2023	par->crsr.spot_y = var->yspot;2024	par->crsr.fmode = fmode;2025	if (IS_AGA) {2026		par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32);2027		par->fmode |= sprfetchmode[fmode];2028		custom.fmode = par->fmode;2029	}2030	return 0;2031}2032 2033static int ami_get_cursorstate(struct fb_cursorstate *state,2034			       const struct amifb_par *par)2035{2036	state->xoffset = par->crsr.crsr_x;2037	state->yoffset = par->crsr.crsr_y;2038	state->mode = cursormode;2039	return 0;2040}2041 2042static int ami_set_cursorstate(struct fb_cursorstate *state,2043			       struct amifb_par *par)2044{2045	par->crsr.crsr_x = state->xoffset;2046	par->crsr.crsr_y = state->yoffset;2047	if ((cursormode = state->mode) == FB_CURSOR_OFF)2048		cursorstate = -1;2049	do_cursor = 1;2050	return 0;2051}2052 2053static void ami_set_sprite(const struct amifb_par *par)2054{2055	copins *copl, *cops;2056	u_short hs, vs, ve;2057	u_long pl, ps;2058	short mx, my;2059 2060	cops = copdisplay.list[currentcop][0];2061	copl = copdisplay.list[currentcop][1];2062	ps = pl = ZTWO_PADDR(dummysprite);2063	mx = par->crsr.crsr_x - par->crsr.spot_x;2064	my = par->crsr.crsr_y - par->crsr.spot_y;2065	if (!(par->vmode & FB_VMODE_YWRAP)) {2066		mx -= par->xoffset;2067		my -= par->yoffset;2068	}2069	if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 &&2070	    mx > -(short)par->crsr.width && mx < par->xres &&2071	    my > -(short)par->crsr.height && my < par->yres) {2072		pl = ZTWO_PADDR(lofsprite);2073		hs = par->diwstrt_h + (mx << par->clk_shift) - 4;2074		vs = par->diwstrt_v + (my << par->line_shift);2075		ve = vs + (par->crsr.height << par->line_shift);2076		if (par->bplcon0 & BPC0_LACE) {2077			ps = ZTWO_PADDR(shfsprite);2078			lofsprite[0] = spr2hw_pos(vs, hs);2079			shfsprite[0] = spr2hw_pos(vs + 1, hs);2080			if (mod2(vs)) {2081				lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);2082				shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve + 1);2083				swap(pl, ps);2084			} else {2085				lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve + 1);2086				shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve);2087			}2088		} else {2089			lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0);2090			lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);2091		}2092	}2093	copl[cop_spr0ptrh].w[1] = highw(pl);2094	copl[cop_spr0ptrl].w[1] = loww(pl);2095	if (par->bplcon0 & BPC0_LACE) {2096		cops[cop_spr0ptrh].w[1] = highw(ps);2097		cops[cop_spr0ptrl].w[1] = loww(ps);2098	}2099}2100 2101 2102	/*2103	 * Initialise the Copper Initialisation List2104	 */2105 2106static void __init ami_init_copper(void)2107{2108	copins *cop = copdisplay.init;2109	u_long p;2110	int i;2111 2112	if (!IS_OCS) {2113		(cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);2114		(cop++)->l = CMOVE(0x0181, diwstrt);2115		(cop++)->l = CMOVE(0x0281, diwstop);2116		(cop++)->l = CMOVE(0x0000, diwhigh);2117	} else2118		(cop++)->l = CMOVE(BPC0_COLOR, bplcon0);2119	p = ZTWO_PADDR(dummysprite);2120	for (i = 0; i < 8; i++) {2121		(cop++)->l = CMOVE(0, spr[i].pos);2122		(cop++)->l = CMOVE(highw(p), sprpt[i]);2123		(cop++)->l = CMOVE2(loww(p), sprpt[i]);2124	}2125 2126	(cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);2127	copdisplay.wait = cop;2128	(cop++)->l = CEND;2129	(cop++)->l = CMOVE(0, copjmp2);2130	cop->l = CEND;2131 2132	custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);2133	custom.copjmp1 = 0;2134}2135 2136static void ami_reinit_copper(const struct amifb_par *par)2137{2138	copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0;2139	copdisplay.wait->l = CWAIT(32, par->diwstrt_v - 4);2140}2141 2142 2143	/*2144	 * Rebuild the Copper List2145	 *2146	 * We only change the things that are not static2147	 */2148 2149static void ami_rebuild_copper(const struct amifb_par *par)2150{2151	copins *copl, *cops;2152	u_short line, h_end1, h_end2;2153	short i;2154	u_long p;2155 2156	if (IS_AGA && maxfmode + par->clk_shift == 0)2157		h_end1 = par->diwstrt_h - 64;2158	else2159		h_end1 = par->htotal - 32;2160	h_end2 = par->ddfstop + 64;2161 2162	ami_set_sprite(par);2163 2164	copl = copdisplay.rebuild[1];2165	p = par->bplpt0;2166	if (par->vmode & FB_VMODE_YWRAP) {2167		if ((par->vyres - par->yoffset) != 1 || !mod2(par->diwstrt_v)) {2168			if (par->yoffset > par->vyres - par->yres) {2169				for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {2170					(copl++)->l = CMOVE(highw(p), bplpt[i]);2171					(copl++)->l = CMOVE2(loww(p), bplpt[i]);2172				}2173				line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 1;2174				while (line >= 512) {2175					(copl++)->l = CWAIT(h_end1, 510);2176					line -= 512;2177				}2178				if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0)2179					(copl++)->l = CWAIT(h_end1, line);2180				else2181					(copl++)->l = CWAIT(h_end2, line);2182				p = par->bplpt0wrap;2183			}2184		} else2185			p = par->bplpt0wrap;2186	}2187	for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {2188		(copl++)->l = CMOVE(highw(p), bplpt[i]);2189		(copl++)->l = CMOVE2(loww(p), bplpt[i]);2190	}2191	copl->l = CEND;2192 2193	if (par->bplcon0 & BPC0_LACE) {2194		cops = copdisplay.rebuild[0];2195		p = par->bplpt0;2196		if (mod2(par->diwstrt_v))2197			p -= par->next_line;2198		else2199			p += par->next_line;2200		if (par->vmode & FB_VMODE_YWRAP) {2201			if ((par->vyres - par->yoffset) != 1 || mod2(par->diwstrt_v)) {2202				if (par->yoffset > par->vyres - par->yres + 1) {2203					for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {2204						(cops++)->l = CMOVE(highw(p), bplpt[i]);2205						(cops++)->l = CMOVE2(loww(p), bplpt[i]);2206					}2207					line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 2;2208					while (line >= 512) {2209						(cops++)->l = CWAIT(h_end1, 510);2210						line -= 512;2211					}2212					if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0)2213						(cops++)->l = CWAIT(h_end1, line);2214					else2215						(cops++)->l = CWAIT(h_end2, line);2216					p = par->bplpt0wrap;2217					if (mod2(par->diwstrt_v + par->vyres -2218					    par->yoffset))2219						p -= par->next_line;2220					else2221						p += par->next_line;2222				}2223			} else2224				p = par->bplpt0wrap - par->next_line;2225		}2226		for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {2227			(cops++)->l = CMOVE(highw(p), bplpt[i]);2228			(cops++)->l = CMOVE2(loww(p), bplpt[i]);2229		}2230		cops->l = CEND;2231	}2232}2233 2234 2235	/*2236	 * Build the Copper List2237	 */2238 2239static void ami_build_copper(struct fb_info *info)2240{2241	struct amifb_par *par = info->par;2242	copins *copl, *cops;2243	u_long p;2244 2245	currentcop = 1 - currentcop;2246 2247	copl = copdisplay.list[currentcop][1];2248 2249	(copl++)->l = CWAIT(0, 10);2250	(copl++)->l = CMOVE(par->bplcon0, bplcon0);2251	(copl++)->l = CMOVE(0, sprpt[0]);2252	(copl++)->l = CMOVE2(0, sprpt[0]);2253 2254	if (par->bplcon0 & BPC0_LACE) {2255		cops = copdisplay.list[currentcop][0];2256 2257		(cops++)->l = CWAIT(0, 10);2258		(cops++)->l = CMOVE(par->bplcon0, bplcon0);2259		(cops++)->l = CMOVE(0, sprpt[0]);2260		(cops++)->l = CMOVE2(0, sprpt[0]);2261 2262		(copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v + 1), diwstrt);2263		(copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v + 1), diwstop);2264		(cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);2265		(cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);2266		if (!IS_OCS) {2267			(copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v + 1,2268					    par->diwstop_h, par->diwstop_v + 1), diwhigh);2269			(cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,2270					    par->diwstop_h, par->diwstop_v), diwhigh);2271#if 02272			if (par->beamcon0 & BMC0_VARBEAMEN) {2273				(copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);2274				(copl++)->l = CMOVE(vbstrt2hw(par->vbstrt + 1), vbstrt);2275				(copl++)->l = CMOVE(vbstop2hw(par->vbstop + 1), vbstop);2276				(cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);2277				(cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);2278				(cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);2279			}2280#endif2281		}2282		p = ZTWO_PADDR(copdisplay.list[currentcop][0]);2283		(copl++)->l = CMOVE(highw(p), cop2lc);2284		(copl++)->l = CMOVE2(loww(p), cop2lc);2285		p = ZTWO_PADDR(copdisplay.list[currentcop][1]);2286		(cops++)->l = CMOVE(highw(p), cop2lc);2287		(cops++)->l = CMOVE2(loww(p), cop2lc);2288		copdisplay.rebuild[0] = cops;2289	} else {2290		(copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);2291		(copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);2292		if (!IS_OCS) {2293			(copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,2294					    par->diwstop_h, par->diwstop_v), diwhigh);2295#if 02296			if (par->beamcon0 & BMC0_VARBEAMEN) {2297				(copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);2298				(copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);2299				(copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);2300			}2301#endif2302		}2303	}2304	copdisplay.rebuild[1] = copl;2305 2306	ami_update_par(info);2307	ami_rebuild_copper(info->par);2308}2309 2310#ifndef MODULE2311static void __init amifb_setup_mcap(char *spec)2312{2313	char *p;2314	int vmin, vmax, hmin, hmax;2315 2316	/* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>2317	 * <V*> vertical freq. in Hz2318	 * <H*> horizontal freq. in kHz2319	 */2320 2321	if (!(p = strsep(&spec, ";")) || !*p)2322		return;2323	vmin = simple_strtoul(p, NULL, 10);2324	if (vmin <= 0)2325		return;2326	if (!(p = strsep(&spec, ";")) || !*p)2327		return;2328	vmax = simple_strtoul(p, NULL, 10);2329	if (vmax <= 0 || vmax <= vmin)2330		return;2331	if (!(p = strsep(&spec, ";")) || !*p)2332		return;2333	hmin = 1000 * simple_strtoul(p, NULL, 10);2334	if (hmin <= 0)2335		return;2336	if (!(p = strsep(&spec, "")) || !*p)2337		return;2338	hmax = 1000 * simple_strtoul(p, NULL, 10);2339	if (hmax <= 0 || hmax <= hmin)2340		return;2341 2342	amifb_hfmin = hmin;2343	amifb_hfmax = hmax;2344	amifb_vfmin = vmin;2345	amifb_vfmax = vmax;2346}2347 2348static int __init amifb_setup(char *options)2349{2350	char *this_opt;2351 2352	if (!options || !*options)2353		return 0;2354 2355	while ((this_opt = strsep(&options, ",")) != NULL) {2356		if (!*this_opt)2357			continue;2358		if (!strcmp(this_opt, "inverse")) {2359			fb_invert_cmaps();2360		} else if (!strcmp(this_opt, "ilbm"))2361			amifb_ilbm = 1;2362		else if (!strncmp(this_opt, "monitorcap:", 11))2363			amifb_setup_mcap(this_opt + 11);2364		else if (!strncmp(this_opt, "fstart:", 7))2365			min_fstrt = simple_strtoul(this_opt + 7, NULL, 0);2366		else2367			mode_option = this_opt;2368	}2369 2370	if (min_fstrt < 48)2371		min_fstrt = 48;2372 2373	return 0;2374}2375#endif2376 2377static int amifb_check_var(struct fb_var_screeninfo *var,2378			   struct fb_info *info)2379{2380	int err;2381	struct amifb_par par;2382 2383	/* Validate wanted screen parameters */2384	err = ami_decode_var(var, &par, info);2385	if (err)2386		return err;2387 2388	/* Encode (possibly rounded) screen parameters */2389	ami_encode_var(var, &par);2390	return 0;2391}2392 2393 2394static int amifb_set_par(struct fb_info *info)2395{2396	struct amifb_par *par = info->par;2397	int error;2398 2399	do_vmode_pan = 0;2400	do_vmode_full = 0;2401 2402	/* Decode wanted screen parameters */2403	error = ami_decode_var(&info->var, par, info);2404	if (error)2405		return error;2406 2407	/* Set new videomode */2408	ami_build_copper(info);2409 2410	/* Set VBlank trigger */2411	do_vmode_full = 1;2412 2413	/* Update fix for new screen parameters */2414	if (par->bpp == 1) {2415		info->fix.type = FB_TYPE_PACKED_PIXELS;2416		info->fix.type_aux = 0;2417	} else if (amifb_ilbm) {2418		info->fix.type = FB_TYPE_INTERLEAVED_PLANES;2419		info->fix.type_aux = par->next_line;2420	} else {2421		info->fix.type = FB_TYPE_PLANES;2422		info->fix.type_aux = 0;2423	}2424	info->fix.line_length = div8(upx(16 << maxfmode, par->vxres));2425 2426	if (par->vmode & FB_VMODE_YWRAP) {2427		info->fix.ywrapstep = 1;2428		info->fix.xpanstep = 0;2429		info->fix.ypanstep = 0;2430		info->flags = FBINFO_HWACCEL_YWRAP |2431			FBINFO_READS_FAST; /* override SCROLL_REDRAW */2432	} else {2433		info->fix.ywrapstep = 0;2434		if (par->vmode & FB_VMODE_SMOOTH_XPAN)2435			info->fix.xpanstep = 1;2436		else2437			info->fix.xpanstep = 16 << maxfmode;2438		info->fix.ypanstep = 1;2439		info->flags = FBINFO_HWACCEL_YPAN;2440	}2441	return 0;2442}2443 2444 2445	/*2446	 * Set a single color register. The values supplied are already2447	 * rounded down to the hardware's capabilities (according to the2448	 * entries in the var structure). Return != 0 for invalid regno.2449	 */2450 2451static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,2452			   u_int transp, struct fb_info *info)2453{2454	const struct amifb_par *par = info->par;2455 2456	if (IS_AGA) {2457		if (regno > 255)2458			return 1;2459	} else if (par->bplcon0 & BPC0_SHRES) {2460		if (regno > 3)2461			return 1;2462	} else {2463		if (regno > 31)2464			return 1;2465	}2466	red >>= 8;2467	green >>= 8;2468	blue >>= 8;2469	if (!regno) {2470		red0 = red;2471		green0 = green;2472		blue0 = blue;2473	}2474 2475	/*2476	 * Update the corresponding Hardware Color Register, unless it's Color2477	 * Register 0 and the screen is blanked.2478	 *2479	 * VBlank is switched off to protect bplcon3 or ecs_palette[] from2480	 * being changed by ami_do_blank() during the VBlank.2481	 */2482 2483	if (regno || !is_blanked) {2484#if defined(CONFIG_FB_AMIGA_AGA)2485		if (IS_AGA) {2486			u_short bplcon3 = par->bplcon3;2487			VBlankOff();2488			custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000);2489			custom.color[regno & 31] = rgb2hw8_high(red, green,2490								blue);2491			custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000) |2492					 BPC3_LOCT;2493			custom.color[regno & 31] = rgb2hw8_low(red, green,2494							       blue);2495			custom.bplcon3 = bplcon3;2496			VBlankOn();2497		} else2498#endif2499#if defined(CONFIG_FB_AMIGA_ECS)2500		if (par->bplcon0 & BPC0_SHRES) {2501			u_short color, mask;2502			int i;2503 2504			mask = 0x3333;2505			color = rgb2hw2(red, green, blue);2506			VBlankOff();2507			for (i = regno + 12; i >= (int)regno; i -= 4)2508				custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;2509			mask <<= 2; color >>= 2;2510			regno = down16(regno) + mul4(mod4(regno));2511			for (i = regno + 3; i >= (int)regno; i--)2512				custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;2513			VBlankOn();2514		} else2515#endif2516			custom.color[regno] = rgb2hw4(red, green, blue);2517	}2518	return 0;2519}2520 2521 2522	/*2523	 * Blank the display.2524	 */2525 2526static int amifb_blank(int blank, struct fb_info *info)2527{2528	do_blank = blank ? blank : -1;2529 2530	return 0;2531}2532 2533 2534	/*2535	 * Pan or Wrap the Display2536	 *2537	 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag2538	 */2539 2540static int amifb_pan_display(struct fb_var_screeninfo *var,2541			     struct fb_info *info)2542{2543	if (!(var->vmode & FB_VMODE_YWRAP)) {2544		/*2545		 * TODO: There will be problems when xpan!=1, so some columns2546		 * on the right side will never be seen2547		 */2548		if (var->xoffset + info->var.xres >2549		    upx(16 << maxfmode, info->var.xres_virtual))2550			return -EINVAL;2551	}2552	ami_pan_var(var, info);2553	return 0;2554}2555 2556 2557#if BITS_PER_LONG == 322558#define BYTES_PER_LONG	42559#define SHIFT_PER_LONG	52560#elif BITS_PER_LONG == 642561#define BYTES_PER_LONG	82562#define SHIFT_PER_LONG	62563#else2564#define Please update me2565#endif2566 2567 2568	/*2569	 *  Compose two values, using a bitmask as decision value2570	 *  This is equivalent to (a & mask) | (b & ~mask)2571	 */2572 2573static inline unsigned long comp(unsigned long a, unsigned long b,2574				 unsigned long mask)2575{2576	return ((a ^ b) & mask) ^ b;2577}2578 2579 2580static inline unsigned long xor(unsigned long a, unsigned long b,2581				unsigned long mask)2582{2583	return (a & mask) ^ b;2584}2585 2586 2587	/*2588	 *  Unaligned forward bit copy using 32-bit or 64-bit memory accesses2589	 */2590 2591static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,2592		   int src_idx, u32 n)2593{2594	unsigned long first, last;2595	int shift = dst_idx - src_idx, left, right;2596	unsigned long d0, d1;2597	int m;2598 2599	if (!n)2600		return;2601 2602	shift = dst_idx - src_idx;2603	first = ~0UL >> dst_idx;2604	last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG));2605 2606	if (!shift) {2607		// Same alignment for source and dest2608 2609		if (dst_idx + n <= BITS_PER_LONG) {2610			// Single word2611			if (last)2612				first &= last;2613			*dst = comp(*src, *dst, first);2614		} else {2615			// Multiple destination words2616			// Leading bits2617			if (first) {2618				*dst = comp(*src, *dst, first);2619				dst++;2620				src++;2621				n -= BITS_PER_LONG - dst_idx;2622			}2623 2624			// Main chunk2625			n /= BITS_PER_LONG;2626			while (n >= 8) {2627				*dst++ = *src++;2628				*dst++ = *src++;2629				*dst++ = *src++;2630				*dst++ = *src++;2631				*dst++ = *src++;2632				*dst++ = *src++;2633				*dst++ = *src++;2634				*dst++ = *src++;2635				n -= 8;2636			}2637			while (n--)2638				*dst++ = *src++;2639 2640			// Trailing bits2641			if (last)2642				*dst = comp(*src, *dst, last);2643		}2644	} else {2645		// Different alignment for source and dest2646 2647		right = shift & (BITS_PER_LONG - 1);2648		left = -shift & (BITS_PER_LONG - 1);2649 2650		if (dst_idx + n <= BITS_PER_LONG) {2651			// Single destination word2652			if (last)2653				first &= last;2654			if (shift > 0) {2655				// Single source word2656				*dst = comp(*src >> right, *dst, first);2657			} else if (src_idx + n <= BITS_PER_LONG) {2658				// Single source word2659				*dst = comp(*src << left, *dst, first);2660			} else {2661				// 2 source words2662				d0 = *src++;2663				d1 = *src;2664				*dst = comp(d0 << left | d1 >> right, *dst,2665					    first);2666			}2667		} else {2668			// Multiple destination words2669			d0 = *src++;2670			// Leading bits2671			if (shift > 0) {2672				// Single source word2673				*dst = comp(d0 >> right, *dst, first);2674				dst++;2675				n -= BITS_PER_LONG - dst_idx;2676			} else {2677				// 2 source words2678				d1 = *src++;2679				*dst = comp(d0 << left | d1 >> right, *dst,2680					    first);2681				d0 = d1;2682				dst++;2683				n -= BITS_PER_LONG - dst_idx;2684			}2685 2686			// Main chunk2687			m = n % BITS_PER_LONG;2688			n /= BITS_PER_LONG;2689			while (n >= 4) {2690				d1 = *src++;2691				*dst++ = d0 << left | d1 >> right;2692				d0 = d1;2693				d1 = *src++;2694				*dst++ = d0 << left | d1 >> right;2695				d0 = d1;2696				d1 = *src++;2697				*dst++ = d0 << left | d1 >> right;2698				d0 = d1;2699				d1 = *src++;2700				*dst++ = d0 << left | d1 >> right;2701				d0 = d1;2702				n -= 4;2703			}2704			while (n--) {2705				d1 = *src++;2706				*dst++ = d0 << left | d1 >> right;2707				d0 = d1;2708			}2709 2710			// Trailing bits2711			if (last) {2712				if (m <= right) {2713					// Single source word2714					*dst = comp(d0 << left, *dst, last);2715				} else {2716					// 2 source words2717					d1 = *src;2718					*dst = comp(d0 << left | d1 >> right,2719						    *dst, last);2720				}2721			}2722		}2723	}2724}2725 2726 2727	/*2728	 *  Unaligned reverse bit copy using 32-bit or 64-bit memory accesses2729	 */2730 2731static void bitcpy_rev(unsigned long *dst, int dst_idx,2732		       const unsigned long *src, int src_idx, u32 n)2733{2734	unsigned long first, last;2735	int shift = dst_idx - src_idx, left, right;2736	unsigned long d0, d1;2737	int m;2738 2739	if (!n)2740		return;2741 2742	dst += (n - 1) / BITS_PER_LONG;2743	src += (n - 1) / BITS_PER_LONG;2744	if ((n - 1) % BITS_PER_LONG) {2745		dst_idx += (n - 1) % BITS_PER_LONG;2746		dst += dst_idx >> SHIFT_PER_LONG;2747		dst_idx &= BITS_PER_LONG - 1;2748		src_idx += (n - 1) % BITS_PER_LONG;2749		src += src_idx >> SHIFT_PER_LONG;2750		src_idx &= BITS_PER_LONG - 1;2751	}2752 2753	shift = dst_idx - src_idx;2754	first = ~0UL << (BITS_PER_LONG - 1 - dst_idx);2755	last = ~(~0UL << (BITS_PER_LONG - 1 - ((dst_idx - n) % BITS_PER_LONG)));2756 2757	if (!shift) {2758		// Same alignment for source and dest2759 2760		if ((unsigned long)dst_idx + 1 >= n) {2761			// Single word2762			if (last)2763				first &= last;2764			*dst = comp(*src, *dst, first);2765		} else {2766			// Multiple destination words2767			// Leading bits2768			if (first) {2769				*dst = comp(*src, *dst, first);2770				dst--;2771				src--;2772				n -= dst_idx + 1;2773			}2774 2775			// Main chunk2776			n /= BITS_PER_LONG;2777			while (n >= 8) {2778				*dst-- = *src--;2779				*dst-- = *src--;2780				*dst-- = *src--;2781				*dst-- = *src--;2782				*dst-- = *src--;2783				*dst-- = *src--;2784				*dst-- = *src--;2785				*dst-- = *src--;2786				n -= 8;2787			}2788			while (n--)2789				*dst-- = *src--;2790 2791			// Trailing bits2792			if (last)2793				*dst = comp(*src, *dst, last);2794		}2795	} else {2796		// Different alignment for source and dest2797 2798		right = shift & (BITS_PER_LONG - 1);2799		left = -shift & (BITS_PER_LONG - 1);2800 2801		if ((unsigned long)dst_idx + 1 >= n) {2802			// Single destination word2803			if (last)2804				first &= last;2805			if (shift < 0) {2806				// Single source word2807				*dst = comp(*src << left, *dst, first);2808			} else if (1 + (unsigned long)src_idx >= n) {2809				// Single source word2810				*dst = comp(*src >> right, *dst, first);2811			} else {2812				// 2 source words2813				d0 = *src--;2814				d1 = *src;2815				*dst = comp(d0 >> right | d1 << left, *dst,2816					    first);2817			}2818		} else {2819			// Multiple destination words2820			d0 = *src--;2821			// Leading bits2822			if (shift < 0) {2823				// Single source word2824				*dst = comp(d0 << left, *dst, first);2825				dst--;2826				n -= dst_idx + 1;2827			} else {2828				// 2 source words2829				d1 = *src--;2830				*dst = comp(d0 >> right | d1 << left, *dst,2831					    first);2832				d0 = d1;2833				dst--;2834				n -= dst_idx + 1;2835			}2836 2837			// Main chunk2838			m = n % BITS_PER_LONG;2839			n /= BITS_PER_LONG;2840			while (n >= 4) {2841				d1 = *src--;2842				*dst-- = d0 >> right | d1 << left;2843				d0 = d1;2844				d1 = *src--;2845				*dst-- = d0 >> right | d1 << left;2846				d0 = d1;2847				d1 = *src--;2848				*dst-- = d0 >> right | d1 << left;2849				d0 = d1;2850				d1 = *src--;2851				*dst-- = d0 >> right | d1 << left;2852				d0 = d1;2853				n -= 4;2854			}2855			while (n--) {2856				d1 = *src--;2857				*dst-- = d0 >> right | d1 << left;2858				d0 = d1;2859			}2860 2861			// Trailing bits2862			if (last) {2863				if (m <= left) {2864					// Single source word2865					*dst = comp(d0 >> right, *dst, last);2866				} else {2867					// 2 source words2868					d1 = *src;2869					*dst = comp(d0 >> right | d1 << left,2870						    *dst, last);2871				}2872			}2873		}2874	}2875}2876 2877 2878	/*2879	 *  Unaligned forward inverting bit copy using 32-bit or 64-bit memory2880	 *  accesses2881	 */2882 2883static void bitcpy_not(unsigned long *dst, int dst_idx,2884		       const unsigned long *src, int src_idx, u32 n)2885{2886	unsigned long first, last;2887	int shift = dst_idx - src_idx, left, right;2888	unsigned long d0, d1;2889	int m;2890 2891	if (!n)2892		return;2893 2894	shift = dst_idx - src_idx;2895	first = ~0UL >> dst_idx;2896	last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG));2897 2898	if (!shift) {2899		// Same alignment for source and dest2900 2901		if (dst_idx + n <= BITS_PER_LONG) {2902			// Single word2903			if (last)2904				first &= last;2905			*dst = comp(~*src, *dst, first);2906		} else {2907			// Multiple destination words2908			// Leading bits2909			if (first) {2910				*dst = comp(~*src, *dst, first);2911				dst++;2912				src++;2913				n -= BITS_PER_LONG - dst_idx;2914			}2915 2916			// Main chunk2917			n /= BITS_PER_LONG;2918			while (n >= 8) {2919				*dst++ = ~*src++;2920				*dst++ = ~*src++;2921				*dst++ = ~*src++;2922				*dst++ = ~*src++;2923				*dst++ = ~*src++;2924				*dst++ = ~*src++;2925				*dst++ = ~*src++;2926				*dst++ = ~*src++;2927				n -= 8;2928			}2929			while (n--)2930				*dst++ = ~*src++;2931 2932			// Trailing bits2933			if (last)2934				*dst = comp(~*src, *dst, last);2935		}2936	} else {2937		// Different alignment for source and dest2938 2939		right = shift & (BITS_PER_LONG - 1);2940		left = -shift & (BITS_PER_LONG - 1);2941 2942		if (dst_idx + n <= BITS_PER_LONG) {2943			// Single destination word2944			if (last)2945				first &= last;2946			if (shift > 0) {2947				// Single source word2948				*dst = comp(~*src >> right, *dst, first);2949			} else if (src_idx + n <= BITS_PER_LONG) {2950				// Single source word2951				*dst = comp(~*src << left, *dst, first);2952			} else {2953				// 2 source words2954				d0 = ~*src++;2955				d1 = ~*src;2956				*dst = comp(d0 << left | d1 >> right, *dst,2957					    first);2958			}2959		} else {2960			// Multiple destination words2961			d0 = ~*src++;2962			// Leading bits2963			if (shift > 0) {2964				// Single source word2965				*dst = comp(d0 >> right, *dst, first);2966				dst++;2967				n -= BITS_PER_LONG - dst_idx;2968			} else {2969				// 2 source words2970				d1 = ~*src++;2971				*dst = comp(d0 << left | d1 >> right, *dst,2972					    first);2973				d0 = d1;2974				dst++;2975				n -= BITS_PER_LONG - dst_idx;2976			}2977 2978			// Main chunk2979			m = n % BITS_PER_LONG;2980			n /= BITS_PER_LONG;2981			while (n >= 4) {2982				d1 = ~*src++;2983				*dst++ = d0 << left | d1 >> right;2984				d0 = d1;2985				d1 = ~*src++;2986				*dst++ = d0 << left | d1 >> right;2987				d0 = d1;2988				d1 = ~*src++;2989				*dst++ = d0 << left | d1 >> right;2990				d0 = d1;2991				d1 = ~*src++;2992				*dst++ = d0 << left | d1 >> right;2993				d0 = d1;2994				n -= 4;2995			}2996			while (n--) {2997				d1 = ~*src++;2998				*dst++ = d0 << left | d1 >> right;2999				d0 = d1;3000			}3001 3002			// Trailing bits3003			if (last) {3004				if (m <= right) {3005					// Single source word3006					*dst = comp(d0 << left, *dst, last);3007				} else {3008					// 2 source words3009					d1 = ~*src;3010					*dst = comp(d0 << left | d1 >> right,3011						    *dst, last);3012				}3013			}3014		}3015	}3016}3017 3018 3019	/*3020	 *  Unaligned 32-bit pattern fill using 32/64-bit memory accesses3021	 */3022 3023static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)3024{3025	unsigned long val = pat;3026	unsigned long first, last;3027 3028	if (!n)3029		return;3030 3031#if BITS_PER_LONG == 643032	val |= val << 32;3033#endif3034 3035	first = ~0UL >> dst_idx;3036	last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG));3037 3038	if (dst_idx + n <= BITS_PER_LONG) {3039		// Single word3040		if (last)3041			first &= last;3042		*dst = comp(val, *dst, first);3043	} else {3044		// Multiple destination words3045		// Leading bits3046		if (first) {3047			*dst = comp(val, *dst, first);3048			dst++;3049			n -= BITS_PER_LONG - dst_idx;3050		}3051 3052		// Main chunk3053		n /= BITS_PER_LONG;3054		while (n >= 8) {3055			*dst++ = val;3056			*dst++ = val;3057			*dst++ = val;3058			*dst++ = val;3059			*dst++ = val;3060			*dst++ = val;3061			*dst++ = val;3062			*dst++ = val;3063			n -= 8;3064		}3065		while (n--)3066			*dst++ = val;3067 3068		// Trailing bits3069		if (last)3070			*dst = comp(val, *dst, last);3071	}3072}3073 3074 3075	/*3076	 *  Unaligned 32-bit pattern xor using 32/64-bit memory accesses3077	 */3078 3079static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n)3080{3081	unsigned long val = pat;3082	unsigned long first, last;3083 3084	if (!n)3085		return;3086 3087#if BITS_PER_LONG == 643088	val |= val << 32;3089#endif3090 3091	first = ~0UL >> dst_idx;3092	last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG));3093 3094	if (dst_idx + n <= BITS_PER_LONG) {3095		// Single word3096		if (last)3097			first &= last;3098		*dst = xor(val, *dst, first);3099	} else {3100		// Multiple destination words3101		// Leading bits3102		if (first) {3103			*dst = xor(val, *dst, first);3104			dst++;3105			n -= BITS_PER_LONG - dst_idx;3106		}3107 3108		// Main chunk3109		n /= BITS_PER_LONG;3110		while (n >= 4) {3111			*dst++ ^= val;3112			*dst++ ^= val;3113			*dst++ ^= val;3114			*dst++ ^= val;3115			n -= 4;3116		}3117		while (n--)3118			*dst++ ^= val;3119 3120		// Trailing bits3121		if (last)3122			*dst = xor(val, *dst, last);3123	}3124}3125 3126static inline void fill_one_line(int bpp, unsigned long next_plane,3127				 unsigned long *dst, int dst_idx, u32 n,3128				 u32 color)3129{3130	while (1) {3131		dst += dst_idx >> SHIFT_PER_LONG;3132		dst_idx &= (BITS_PER_LONG - 1);3133		bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n);3134		if (!--bpp)3135			break;3136		color >>= 1;3137		dst_idx += next_plane * 8;3138	}3139}3140 3141static inline void xor_one_line(int bpp, unsigned long next_plane,3142				unsigned long *dst, int dst_idx, u32 n,3143				u32 color)3144{3145	while (color) {3146		dst += dst_idx >> SHIFT_PER_LONG;3147		dst_idx &= (BITS_PER_LONG - 1);3148		bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n);3149		if (!--bpp)3150			break;3151		color >>= 1;3152		dst_idx += next_plane * 8;3153	}3154}3155 3156 3157static void amifb_fillrect(struct fb_info *info,3158			   const struct fb_fillrect *rect)3159{3160	struct amifb_par *par = info->par;3161	int dst_idx, x2, y2;3162	unsigned long *dst;3163	u32 width, height;3164 3165	if (!rect->width || !rect->height)3166		return;3167 3168	/*3169	 * We could use hardware clipping but on many cards you get around3170	 * hardware clipping by writing to framebuffer directly.3171	 * */3172	x2 = rect->dx + rect->width;3173	y2 = rect->dy + rect->height;3174	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;3175	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;3176	width = x2 - rect->dx;3177	height = y2 - rect->dy;3178 3179	dst = (unsigned long *)3180		((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));3181	dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;3182	dst_idx += rect->dy * par->next_line * 8 + rect->dx;3183	while (height--) {3184		switch (rect->rop) {3185		case ROP_COPY:3186			fill_one_line(info->var.bits_per_pixel,3187				      par->next_plane, dst, dst_idx, width,3188				      rect->color);3189			break;3190 3191		case ROP_XOR:3192			xor_one_line(info->var.bits_per_pixel, par->next_plane,3193				     dst, dst_idx, width, rect->color);3194			break;3195		}3196		dst_idx += par->next_line * 8;3197	}3198}3199 3200static inline void copy_one_line(int bpp, unsigned long next_plane,3201				 unsigned long *dst, int dst_idx,3202				 unsigned long *src, int src_idx, u32 n)3203{3204	while (1) {3205		dst += dst_idx >> SHIFT_PER_LONG;3206		dst_idx &= (BITS_PER_LONG - 1);3207		src += src_idx >> SHIFT_PER_LONG;3208		src_idx &= (BITS_PER_LONG - 1);3209		bitcpy(dst, dst_idx, src, src_idx, n);3210		if (!--bpp)3211			break;3212		dst_idx += next_plane * 8;3213		src_idx += next_plane * 8;3214	}3215}3216 3217static inline void copy_one_line_rev(int bpp, unsigned long next_plane,3218				     unsigned long *dst, int dst_idx,3219				     unsigned long *src, int src_idx, u32 n)3220{3221	while (1) {3222		dst += dst_idx >> SHIFT_PER_LONG;3223		dst_idx &= (BITS_PER_LONG - 1);3224		src += src_idx >> SHIFT_PER_LONG;3225		src_idx &= (BITS_PER_LONG - 1);3226		bitcpy_rev(dst, dst_idx, src, src_idx, n);3227		if (!--bpp)3228			break;3229		dst_idx += next_plane * 8;3230		src_idx += next_plane * 8;3231	}3232}3233 3234 3235static void amifb_copyarea(struct fb_info *info,3236			   const struct fb_copyarea *area)3237{3238	struct amifb_par *par = info->par;3239	int x2, y2;3240	u32 dx, dy, sx, sy, width, height;3241	unsigned long *dst, *src;3242	int dst_idx, src_idx;3243	int rev_copy = 0;3244 3245	/* clip the destination */3246	x2 = area->dx + area->width;3247	y2 = area->dy + area->height;3248	dx = area->dx > 0 ? area->dx : 0;3249	dy = area->dy > 0 ? area->dy : 0;3250	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;3251	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;3252	width = x2 - dx;3253	height = y2 - dy;3254 3255	if (area->sx + dx < area->dx || area->sy + dy < area->dy)3256		return;3257 3258	/* update sx,sy */3259	sx = area->sx + (dx - area->dx);3260	sy = area->sy + (dy - area->dy);3261 3262	/* the source must be completely inside the virtual screen */3263	if (sx + width > info->var.xres_virtual ||3264			sy + height > info->var.yres_virtual)3265		return;3266 3267	if (dy > sy || (dy == sy && dx > sx)) {3268		dy += height;3269		sy += height;3270		rev_copy = 1;3271	}3272	dst = (unsigned long *)3273		((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));3274	src = dst;3275	dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;3276	src_idx = dst_idx;3277	dst_idx += dy * par->next_line * 8 + dx;3278	src_idx += sy * par->next_line * 8 + sx;3279	if (rev_copy) {3280		while (height--) {3281			dst_idx -= par->next_line * 8;3282			src_idx -= par->next_line * 8;3283			copy_one_line_rev(info->var.bits_per_pixel,3284					  par->next_plane, dst, dst_idx, src,3285					  src_idx, width);3286		}3287	} else {3288		while (height--) {3289			copy_one_line(info->var.bits_per_pixel,3290				      par->next_plane, dst, dst_idx, src,3291				      src_idx, width);3292			dst_idx += par->next_line * 8;3293			src_idx += par->next_line * 8;3294		}3295	}3296}3297 3298 3299static inline void expand_one_line(int bpp, unsigned long next_plane,3300				   unsigned long *dst, int dst_idx, u32 n,3301				   const u8 *data, u32 bgcolor, u32 fgcolor)3302{3303	const unsigned long *src;3304	int src_idx;3305 3306	while (1) {3307		dst += dst_idx >> SHIFT_PER_LONG;3308		dst_idx &= (BITS_PER_LONG - 1);3309		if ((bgcolor ^ fgcolor) & 1) {3310			src = (unsigned long *)3311				((unsigned long)data & ~(BYTES_PER_LONG - 1));3312			src_idx = ((unsigned long)data & (BYTES_PER_LONG - 1)) * 8;3313			if (fgcolor & 1)3314				bitcpy(dst, dst_idx, src, src_idx, n);3315			else3316				bitcpy_not(dst, dst_idx, src, src_idx, n);3317			/* set or clear */3318		} else3319			bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n);3320		if (!--bpp)3321			break;3322		bgcolor >>= 1;3323		fgcolor >>= 1;3324		dst_idx += next_plane * 8;3325	}3326}3327 3328 3329static void amifb_imageblit(struct fb_info *info, const struct fb_image *image)3330{3331	struct amifb_par *par = info->par;3332	int x2, y2;3333	unsigned long *dst;3334	int dst_idx;3335	const char *src;3336	u32 dx, dy, width, height, pitch;3337 3338	/*3339	 * We could use hardware clipping but on many cards you get around3340	 * hardware clipping by writing to framebuffer directly like we are3341	 * doing here.3342	 */3343	x2 = image->dx + image->width;3344	y2 = image->dy + image->height;3345	dx = image->dx;3346	dy = image->dy;3347	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;3348	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;3349	width  = x2 - dx;3350	height = y2 - dy;3351 3352	if (image->depth == 1) {3353		dst = (unsigned long *)3354			((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));3355		dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;3356		dst_idx += dy * par->next_line * 8 + dx;3357		src = image->data;3358		pitch = (image->width + 7) / 8;3359		while (height--) {3360			expand_one_line(info->var.bits_per_pixel,3361					par->next_plane, dst, dst_idx, width,3362					src, image->bg_color,3363					image->fg_color);3364			dst_idx += par->next_line * 8;3365			src += pitch;3366		}3367	} else {3368		c2p_planar(info->screen_base, image->data, dx, dy, width,3369			   height, par->next_line, par->next_plane,3370			   image->width, info->var.bits_per_pixel);3371	}3372}3373 3374 3375	/*3376	 * Amiga Frame Buffer Specific ioctls3377	 */3378 3379static int amifb_ioctl(struct fb_info *info,3380		       unsigned int cmd, unsigned long arg)3381{3382	union {3383		struct fb_fix_cursorinfo fix;3384		struct fb_var_cursorinfo var;3385		struct fb_cursorstate state;3386	} crsr;3387	void __user *argp = (void __user *)arg;3388	int i;3389 3390	switch (cmd) {3391	case FBIOGET_FCURSORINFO:3392		i = ami_get_fix_cursorinfo(&crsr.fix, info->par);3393		if (i)3394			return i;3395		return copy_to_user(argp, &crsr.fix,3396				    sizeof(crsr.fix)) ? -EFAULT : 0;3397 3398	case FBIOGET_VCURSORINFO:3399		i = ami_get_var_cursorinfo(&crsr.var,3400			((struct fb_var_cursorinfo __user *)arg)->data,3401			info->par);3402		if (i)3403			return i;3404		return copy_to_user(argp, &crsr.var,3405				    sizeof(crsr.var)) ? -EFAULT : 0;3406 3407	case FBIOPUT_VCURSORINFO:3408		if (copy_from_user(&crsr.var, argp, sizeof(crsr.var)))3409			return -EFAULT;3410		return ami_set_var_cursorinfo(&crsr.var,3411			((struct fb_var_cursorinfo __user *)arg)->data,3412			info->par);3413 3414	case FBIOGET_CURSORSTATE:3415		i = ami_get_cursorstate(&crsr.state, info->par);3416		if (i)3417			return i;3418		return copy_to_user(argp, &crsr.state,3419				    sizeof(crsr.state)) ? -EFAULT : 0;3420 3421	case FBIOPUT_CURSORSTATE:3422		if (copy_from_user(&crsr.state, argp, sizeof(crsr.state)))3423			return -EFAULT;3424		return ami_set_cursorstate(&crsr.state, info->par);3425	}3426	return -EINVAL;3427}3428 3429 3430	/*3431	 * Flash the cursor (called by VBlank interrupt)3432	 */3433 3434static int flash_cursor(void)3435{3436	static int cursorcount = 1;3437 3438	if (cursormode == FB_CURSOR_FLASH) {3439		if (!--cursorcount) {3440			cursorstate = -cursorstate;3441			cursorcount = cursorrate;3442			if (!is_blanked)3443				return 1;3444		}3445	}3446	return 0;3447}3448 3449	/*3450	 * VBlank Display Interrupt3451	 */3452 3453static irqreturn_t amifb_interrupt(int irq, void *dev_id)3454{3455	struct amifb_par *par = dev_id;3456 3457	if (do_vmode_pan || do_vmode_full)3458		ami_update_display(par);3459 3460	if (do_vmode_full)3461		ami_init_display(par);3462 3463	if (do_vmode_pan) {3464		flash_cursor();3465		ami_rebuild_copper(par);3466		do_cursor = do_vmode_pan = 0;3467	} else if (do_cursor) {3468		flash_cursor();3469		ami_set_sprite(par);3470		do_cursor = 0;3471	} else {3472		if (flash_cursor())3473			ami_set_sprite(par);3474	}3475 3476	if (do_blank) {3477		ami_do_blank(par);3478		do_blank = 0;3479	}3480 3481	if (do_vmode_full) {3482		ami_reinit_copper(par);3483		do_vmode_full = 0;3484	}3485	return IRQ_HANDLED;3486}3487 3488 3489static const struct fb_ops amifb_ops = {3490	.owner		= THIS_MODULE,3491	__FB_DEFAULT_IOMEM_OPS_RDWR,3492	.fb_check_var	= amifb_check_var,3493	.fb_set_par	= amifb_set_par,3494	.fb_setcolreg	= amifb_setcolreg,3495	.fb_blank	= amifb_blank,3496	.fb_pan_display	= amifb_pan_display,3497	.fb_fillrect	= amifb_fillrect,3498	.fb_copyarea	= amifb_copyarea,3499	.fb_imageblit	= amifb_imageblit,3500	.fb_ioctl	= amifb_ioctl,3501	__FB_DEFAULT_IOMEM_OPS_MMAP,3502};3503 3504 3505	/*3506	 * Allocate, Clear and Align a Block of Chip Memory3507	 */3508 3509static void *aligned_chipptr;3510 3511static inline u_long __init chipalloc(u_long size)3512{3513	aligned_chipptr = amiga_chip_alloc(size, "amifb [RAM]");3514	if (!aligned_chipptr) {3515		pr_err("amifb: No Chip RAM for frame buffer");3516		return 0;3517	}3518	memset(aligned_chipptr, 0, size);3519	return (u_long)aligned_chipptr;3520}3521 3522static inline void chipfree(void)3523{3524	if (aligned_chipptr)3525		amiga_chip_free(aligned_chipptr);3526}3527 3528 3529	/*3530	 * Initialisation3531	 */3532 3533static int __init amifb_probe(struct platform_device *pdev)3534{3535	struct fb_info *info;3536	int tag, i, err = 0;3537	u_long chipptr;3538	u_int defmode;3539 3540#ifndef MODULE3541	char *option = NULL;3542 3543	if (fb_get_options("amifb", &option)) {3544		amifb_video_off();3545		return -ENODEV;3546	}3547	amifb_setup(option);3548#endif3549	custom.dmacon = DMAF_ALL | DMAF_MASTER;3550 3551	info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev);3552	if (!info)3553		return -ENOMEM;3554 3555	strcpy(info->fix.id, "Amiga ");3556	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;3557	info->fix.accel = FB_ACCEL_AMIGABLITT;3558 3559	switch (amiga_chipset) {3560#ifdef CONFIG_FB_AMIGA_OCS3561	case CS_OCS:3562		strcat(info->fix.id, "OCS");3563default_chipset:3564		chipset = TAG_OCS;3565		maxdepth[TAG_SHRES] = 0;	/* OCS means no SHRES */3566		maxdepth[TAG_HIRES] = 4;3567		maxdepth[TAG_LORES] = 6;3568		maxfmode = TAG_FMODE_1;3569		defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC;3570		info->fix.smem_len = VIDEOMEMSIZE_OCS;3571		break;3572#endif /* CONFIG_FB_AMIGA_OCS */3573 3574#ifdef CONFIG_FB_AMIGA_ECS3575	case CS_ECS:3576		strcat(info->fix.id, "ECS");3577		chipset = TAG_ECS;3578		maxdepth[TAG_SHRES] = 2;3579		maxdepth[TAG_HIRES] = 4;3580		maxdepth[TAG_LORES] = 6;3581		maxfmode = TAG_FMODE_1;3582		if (AMIGAHW_PRESENT(AMBER_FF))3583			defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL3584						     : DEFMODE_AMBER_NTSC;3585		else3586			defmode = amiga_vblank == 50 ? DEFMODE_PAL3587						     : DEFMODE_NTSC;3588		if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT >3589		    VIDEOMEMSIZE_ECS_2M)3590			info->fix.smem_len = VIDEOMEMSIZE_ECS_2M;3591		else3592			info->fix.smem_len = VIDEOMEMSIZE_ECS_1M;3593		break;3594#endif /* CONFIG_FB_AMIGA_ECS */3595 3596#ifdef CONFIG_FB_AMIGA_AGA3597	case CS_AGA:3598		strcat(info->fix.id, "AGA");3599		chipset = TAG_AGA;3600		maxdepth[TAG_SHRES] = 8;3601		maxdepth[TAG_HIRES] = 8;3602		maxdepth[TAG_LORES] = 8;3603		maxfmode = TAG_FMODE_4;3604		defmode = DEFMODE_AGA;3605		if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT >3606		    VIDEOMEMSIZE_AGA_2M)3607			info->fix.smem_len = VIDEOMEMSIZE_AGA_2M;3608		else3609			info->fix.smem_len = VIDEOMEMSIZE_AGA_1M;3610		break;3611#endif /* CONFIG_FB_AMIGA_AGA */3612 3613	default:3614#ifdef CONFIG_FB_AMIGA_OCS3615		printk("Unknown graphics chipset, defaulting to OCS\n");3616		strcat(info->fix.id, "Unknown");3617		goto default_chipset;3618#else /* CONFIG_FB_AMIGA_OCS */3619		err = -ENODEV;3620		goto release;3621#endif /* CONFIG_FB_AMIGA_OCS */3622		break;3623	}3624 3625	/*3626	 * Calculate the Pixel Clock Values for this Machine3627	 */3628 3629	{3630	u_long tmp = DIVUL(200000000000ULL, amiga_eclock);3631 3632	pixclock[TAG_SHRES] = (tmp + 4) / 8;	/* SHRES:  35 ns / 28 MHz */3633	pixclock[TAG_HIRES] = (tmp + 2) / 4;	/* HIRES:  70 ns / 14 MHz */3634	pixclock[TAG_LORES] = (tmp + 1) / 2;	/* LORES: 140 ns /  7 MHz */3635	}3636 3637	/*3638	 * Replace the Tag Values with the Real Pixel Clock Values3639	 */3640 3641	for (i = 0; i < NUM_TOTAL_MODES; i++) {3642		struct fb_videomode *mode = &ami_modedb[i];3643		tag = mode->pixclock;3644		if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {3645			mode->pixclock = pixclock[tag];3646		}3647	}3648 3649	if (amifb_hfmin) {3650		info->monspecs.hfmin = amifb_hfmin;3651		info->monspecs.hfmax = amifb_hfmax;3652		info->monspecs.vfmin = amifb_vfmin;3653		info->monspecs.vfmax = amifb_vfmax;3654	} else {3655		/*3656		 *  These are for a typical Amiga monitor (e.g. A1960)3657		 */3658		info->monspecs.hfmin = 15000;3659		info->monspecs.hfmax = 38000;3660		info->monspecs.vfmin = 49;3661		info->monspecs.vfmax = 90;3662	}3663 3664	info->fbops = &amifb_ops;3665	info->device = &pdev->dev;3666 3667	if (!fb_find_mode(&info->var, info, mode_option, ami_modedb,3668			  NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {3669		err = -EINVAL;3670		goto release;3671	}3672 3673	fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES,3674				 &info->modelist);3675 3676	round_down_bpp = 0;3677	chipptr = chipalloc(info->fix.smem_len + SPRITEMEMSIZE +3678			    DUMMYSPRITEMEMSIZE + COPINITSIZE +3679			    4 * COPLISTSIZE);3680	if (!chipptr) {3681		err = -ENOMEM;3682		goto release;3683	}3684 3685	assignchunk(videomemory, u_long, chipptr, info->fix.smem_len);3686	assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);3687	assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);3688	assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);3689	assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);3690	assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);3691	assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);3692	assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);3693 3694	/*3695	 * access the videomem with writethrough cache3696	 */3697	info->fix.smem_start = (u_long)ZTWO_PADDR(videomemory);3698	videomemory = (u_long)ioremap_wt(info->fix.smem_start,3699					 info->fix.smem_len);3700	if (!videomemory) {3701		dev_warn(&pdev->dev,3702			 "Unable to map videomem cached writethrough\n");3703		info->screen_base = ZTWO_VADDR(info->fix.smem_start);3704	} else3705		info->screen_base = (char *)videomemory;3706 3707	memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);3708 3709	/*3710	 * Make sure the Copper has something to do3711	 */3712	ami_init_copper();3713 3714	/*3715	 * Enable Display DMA3716	 */3717	custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |3718			DMAF_BLITTER | DMAF_SPRITE;3719 3720	err = request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,3721			  "fb vertb handler", info->par);3722	if (err)3723		goto disable_dma;3724 3725	err = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0);3726	if (err)3727		goto free_irq;3728 3729	platform_set_drvdata(pdev, info);3730 3731	err = register_framebuffer(info);3732	if (err)3733		goto unset_drvdata;3734 3735	fb_info(info, "%s frame buffer device, using %dK of video memory\n",3736		info->fix.id, info->fix.smem_len>>10);3737 3738	return 0;3739 3740unset_drvdata:3741	fb_dealloc_cmap(&info->cmap);3742free_irq:3743	free_irq(IRQ_AMIGA_COPPER, info->par);3744disable_dma:3745	custom.dmacon = DMAF_ALL | DMAF_MASTER;3746	if (videomemory)3747		iounmap((void *)videomemory);3748	chipfree();3749release:3750	framebuffer_release(info);3751	return err;3752}3753 3754 3755static void __exit amifb_remove(struct platform_device *pdev)3756{3757	struct fb_info *info = platform_get_drvdata(pdev);3758 3759	unregister_framebuffer(info);3760	fb_dealloc_cmap(&info->cmap);3761	free_irq(IRQ_AMIGA_COPPER, info->par);3762	custom.dmacon = DMAF_ALL | DMAF_MASTER;3763	if (videomemory)3764		iounmap((void *)videomemory);3765	chipfree();3766	framebuffer_release(info);3767	amifb_video_off();3768}3769 3770/*3771 * amifb_remove() lives in .exit.text. For drivers registered via3772 * module_platform_driver_probe() this ok because they cannot get unboud at3773 * runtime. The driver needs to be marked with __refdata, otherwise modpost3774 * triggers a section mismatch warning.3775 */3776static struct platform_driver amifb_driver __refdata = {3777	.remove = __exit_p(amifb_remove),3778	.driver = {3779		.name	= "amiga-video",3780	},3781};3782 3783module_platform_driver_probe(amifb_driver, amifb_probe);3784 3785MODULE_DESCRIPTION("Amiga builtin chipset frame buffer driver");3786MODULE_LICENSE("GPL");3787MODULE_ALIAS("platform:amiga-video");3788