cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

amifb.c (101775B)


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