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