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