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, __func__ , ## 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
1139static void amifb_deinit(void);
1140
1141        /*
1142         * Internal routines
1143         */
1144
1145static int flash_cursor(void);
1146static irqreturn_t amifb_interrupt(int irq, void *dev_id);
1147static u_long chipalloc(u_long size);
1148static void chipfree(void);
1149
1150        /*
1151         * Hardware routines
1152         */
1153
1154static int ami_decode_var(struct fb_var_screeninfo *var,
1155                          struct amifb_par *par);
1156static int ami_encode_var(struct fb_var_screeninfo *var,
1157                          struct amifb_par *par);
1158static void ami_pan_var(struct fb_var_screeninfo *var);
1159static int ami_update_par(void);
1160static void ami_update_display(void);
1161static void ami_init_display(void);
1162static void ami_do_blank(void);
1163static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix);
1164static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data);
1165static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data);
1166static int ami_get_cursorstate(struct fb_cursorstate *state);
1167static int ami_set_cursorstate(struct fb_cursorstate *state);
1168static void ami_set_sprite(void);
1169static void ami_init_copper(void);
1170static void ami_reinit_copper(void);
1171static void ami_build_copper(void);
1172static void ami_rebuild_copper(void);
1173
1174
1175static struct fb_ops amifb_ops = {
1176        .owner          = THIS_MODULE,
1177        .fb_check_var   = amifb_check_var,
1178        .fb_set_par     = amifb_set_par,
1179        .fb_setcolreg   = amifb_setcolreg,
1180        .fb_blank       = amifb_blank,
1181        .fb_pan_display = amifb_pan_display,
1182        .fb_fillrect    = amifb_fillrect,
1183        .fb_copyarea    = amifb_copyarea,
1184        .fb_imageblit   = amifb_imageblit,
1185        .fb_ioctl       = amifb_ioctl,
1186};
1187
1188static void __init amifb_setup_mcap(char *spec)
1189{
1190        char *p;
1191        int vmin, vmax, hmin, hmax;
1192
1193        /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
1194         * <V*> vertical freq. in Hz
1195         * <H*> horizontal freq. in kHz
1196         */
1197
1198        if (!(p = strsep(&spec, ";")) || !*p)
1199                return;
1200        vmin = simple_strtoul(p, NULL, 10);
1201        if (vmin <= 0)
1202                return;
1203        if (!(p = strsep(&spec, ";")) || !*p)
1204                return;
1205        vmax = simple_strtoul(p, NULL, 10);
1206        if (vmax <= 0 || vmax <= vmin)
1207                return;
1208        if (!(p = strsep(&spec, ";")) || !*p)
1209                return;
1210        hmin = 1000 * simple_strtoul(p, NULL, 10);
1211        if (hmin <= 0)
1212                return;
1213        if (!(p = strsep(&spec, "")) || !*p)
1214                return;
1215        hmax = 1000 * simple_strtoul(p, NULL, 10);
1216        if (hmax <= 0 || hmax <= hmin)
1217                return;
1218
1219        fb_info.monspecs.vfmin = vmin;
1220        fb_info.monspecs.vfmax = vmax;
1221        fb_info.monspecs.hfmin = hmin;
1222        fb_info.monspecs.hfmax = hmax;
1223}
1224
1225int __init amifb_setup(char *options)
1226{
1227        char *this_opt;
1228
1229        if (!options || !*options)
1230                return 0;
1231
1232        while ((this_opt = strsep(&options, ",")) != NULL) {
1233                if (!*this_opt)
1234                        continue;
1235                if (!strcmp(this_opt, "inverse")) {
1236                        amifb_inverse = 1;
1237                        fb_invert_cmaps();
1238                } else if (!strcmp(this_opt, "ilbm"))
1239                        amifb_ilbm = 1;
1240                else if (!strncmp(this_opt, "monitorcap:", 11))
1241                        amifb_setup_mcap(this_opt+11);
1242                else if (!strncmp(this_opt, "fstart:", 7))
1243                        min_fstrt = simple_strtoul(this_opt+7, NULL, 0);
1244                else
1245                        mode_option = this_opt;
1246        }
1247
1248        if (min_fstrt < 48)
1249                min_fstrt = 48;
1250
1251        return 0;
1252}
1253
1254
1255static int amifb_check_var(struct fb_var_screeninfo *var,
1256                           struct fb_info *info)
1257{
1258        int err;
1259        struct amifb_par par;
1260
1261        /* Validate wanted screen parameters */
1262        if ((err = ami_decode_var(var, &par)))
1263                return err;
1264
1265        /* Encode (possibly rounded) screen parameters */
1266        ami_encode_var(var, &par);
1267        return 0;
1268}
1269
1270
1271static int amifb_set_par(struct fb_info *info)
1272{
1273        struct amifb_par *par = (struct amifb_par *)info->par;
1274
1275        do_vmode_pan = 0;
1276        do_vmode_full = 0;
1277
1278        /* Decode wanted screen parameters */
1279        ami_decode_var(&info->var, par);
1280
1281        /* Set new videomode */
1282        ami_build_copper();
1283
1284        /* Set VBlank trigger */
1285        do_vmode_full = 1;
1286
1287        /* Update fix for new screen parameters */
1288        if (par->bpp == 1) {
1289                info->fix.type = FB_TYPE_PACKED_PIXELS;
1290                info->fix.type_aux = 0;
1291        } else if (amifb_ilbm) {
1292                info->fix.type = FB_TYPE_INTERLEAVED_PLANES;
1293                info->fix.type_aux = par->next_line;
1294        } else {
1295                info->fix.type = FB_TYPE_PLANES;
1296                info->fix.type_aux = 0;
1297        }
1298        info->fix.line_length = div8(upx(16<<maxfmode, par->vxres));
1299
1300        if (par->vmode & FB_VMODE_YWRAP) {
1301                info->fix.ywrapstep = 1;
1302                info->fix.xpanstep = 0;
1303                info->fix.ypanstep = 0;
1304                info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP |
1305                    FBINFO_READS_FAST; /* override SCROLL_REDRAW */
1306        } else {
1307                info->fix.ywrapstep = 0;
1308                if (par->vmode & FB_VMODE_SMOOTH_XPAN)
1309                        info->fix.xpanstep = 1;
1310                else
1311                        info->fix.xpanstep = 16<<maxfmode;
1312                info->fix.ypanstep = 1;
1313                info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1314        }
1315        return 0;
1316}
1317
1318
1319        /*
1320         * Pan or Wrap the Display
1321         *
1322         * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
1323         */
1324
1325static int amifb_pan_display(struct fb_var_screeninfo *var,
1326                             struct fb_info *info)
1327{
1328        if (var->vmode & FB_VMODE_YWRAP) {
1329                if (var->yoffset < 0 ||
1330                    var->yoffset >= info->var.yres_virtual || var->xoffset)
1331                        return -EINVAL;
1332        } else {
1333                /*
1334                 * TODO: There will be problems when xpan!=1, so some columns
1335                 * on the right side will never be seen
1336                 */
1337                if (var->xoffset+info->var.xres > upx(16<<maxfmode, info->var.xres_virtual) ||
1338                    var->yoffset+info->var.yres > info->var.yres_virtual)
1339                        return -EINVAL;
1340        }
1341        ami_pan_var(var);
1342        info->var.xoffset = var->xoffset;
1343        info->var.yoffset = var->yoffset;
1344        if (var->vmode & FB_VMODE_YWRAP)
1345                info->var.vmode |= FB_VMODE_YWRAP;
1346        else
1347                info->var.vmode &= ~FB_VMODE_YWRAP;
1348        return 0;
1349}
1350
1351
1352#if BITS_PER_LONG == 32
1353#define BYTES_PER_LONG  4
1354#define SHIFT_PER_LONG  5
1355#elif BITS_PER_LONG == 64
1356#define BYTES_PER_LONG  8
1357#define SHIFT_PER_LONG  6
1358#else
1359#define Please update me
1360#endif
1361
1362
1363    /*
1364     *  Compose two values, using a bitmask as decision value
1365     *  This is equivalent to (a & mask) | (b & ~mask)
1366     */
1367
1368static inline unsigned long comp(unsigned long a, unsigned long b,
1369                                 unsigned long mask)
1370{
1371        return ((a ^ b) & mask) ^ b;
1372}
1373
1374
1375static inline unsigned long xor(unsigned long a, unsigned long b,
1376                                unsigned long mask)
1377{
1378        return (a & mask) ^ b;
1379}
1380
1381
1382    /*
1383     *  Unaligned forward bit copy using 32-bit or 64-bit memory accesses
1384     */
1385
1386static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
1387                   int src_idx, u32 n)
1388{
1389        unsigned long first, last;
1390        int shift = dst_idx-src_idx, left, right;
1391        unsigned long d0, d1;
1392        int m;
1393
1394        if (!n)
1395                return;
1396
1397        shift = dst_idx-src_idx;
1398        first = ~0UL >> dst_idx;
1399        last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
1400
1401        if (!shift) {
1402                // Same alignment for source and dest
1403
1404                if (dst_idx+n <= BITS_PER_LONG) {
1405                        // Single word
1406                        if (last)
1407                                first &= last;
1408                        *dst = comp(*src, *dst, first);
1409                } else {
1410                        // Multiple destination words
1411                        // Leading bits
1412                        if (first) {
1413                                *dst = comp(*src, *dst, first);
1414                                dst++;
1415                                src++;
1416                                n -= BITS_PER_LONG-dst_idx;
1417                        }
1418
1419                        // Main chunk
1420                        n /= BITS_PER_LONG;
1421                        while (n >= 8) {
1422                                *dst++ = *src++;
1423                                *dst++ = *src++;
1424                                *dst++ = *src++;
1425                                *dst++ = *src++;
1426                                *dst++ = *src++;
1427                                *dst++ = *src++;
1428                                *dst++ = *src++;
1429                                *dst++ = *src++;
1430                                n -= 8;
1431                        }
1432                        while (n--)
1433                                *dst++ = *src++;
1434
1435                        // Trailing bits
1436                        if (last)
1437                                *dst = comp(*src, *dst, last);
1438                }
1439        } else {
1440                // Different alignment for source and dest
1441
1442                right = shift & (BITS_PER_LONG-1);
1443                left = -shift & (BITS_PER_LONG-1);
1444
1445                if (dst_idx+n <= BITS_PER_LONG) {
1446                        // Single destination word
1447                        if (last)
1448                                first &= last;
1449                        if (shift > 0) {
1450                                // Single source word
1451                                *dst = comp(*src >> right, *dst, first);
1452                        } else if (src_idx+n <= BITS_PER_LONG) {
1453                                // Single source word
1454                                *dst = comp(*src << left, *dst, first);
1455                        } else {
1456                                // 2 source words
1457                                d0 = *src++;
1458                                d1 = *src;
1459                                *dst = comp(d0 << left | d1 >> right, *dst,
1460                                            first);
1461                        }
1462                } else {
1463                        // Multiple destination words
1464                        d0 = *src++;
1465                        // Leading bits
1466                        if (shift > 0) {
1467                                // Single source word
1468                                *dst = comp(d0 >> right, *dst, first);
1469                                dst++;
1470                                n -= BITS_PER_LONG-dst_idx;
1471                        } else {
1472                                // 2 source words
1473                                d1 = *src++;
1474                                *dst = comp(d0 << left | d1 >> right, *dst,
1475                                            first);
1476                                d0 = d1;
1477                                dst++;
1478                                n -= BITS_PER_LONG-dst_idx;
1479                        }
1480
1481                        // Main chunk
1482                        m = n % BITS_PER_LONG;
1483                        n /= BITS_PER_LONG;
1484                        while (n >= 4) {
1485                                d1 = *src++;
1486                                *dst++ = d0 << left | d1 >> right;
1487                                d0 = d1;
1488                                d1 = *src++;
1489                                *dst++ = d0 << left | d1 >> right;
1490                                d0 = d1;
1491                                d1 = *src++;
1492                                *dst++ = d0 << left | d1 >> right;
1493                                d0 = d1;
1494                                d1 = *src++;
1495                                *dst++ = d0 << left | d1 >> right;
1496                                d0 = d1;
1497                                n -= 4;
1498                        }
1499                        while (n--) {
1500                                d1 = *src++;
1501                                *dst++ = d0 << left | d1 >> right;
1502                                d0 = d1;
1503                        }
1504
1505                        // Trailing bits
1506                        if (last) {
1507                                if (m <= right) {
1508                                        // Single source word
1509                                        *dst = comp(d0 << left, *dst, last);
1510                                } else {
1511                                        // 2 source words
1512                                        d1 = *src;
1513                                        *dst = comp(d0 << left | d1 >> right,
1514                                                    *dst, last);
1515                                }
1516                        }
1517                }
1518        }
1519}
1520
1521
1522    /*
1523     *  Unaligned reverse bit copy using 32-bit or 64-bit memory accesses
1524     */
1525
1526static void bitcpy_rev(unsigned long *dst, int dst_idx,
1527                       const unsigned long *src, int src_idx, u32 n)
1528{
1529        unsigned long first, last;
1530        int shift = dst_idx-src_idx, left, right;
1531        unsigned long d0, d1;
1532        int m;
1533
1534        if (!n)
1535                return;
1536
1537        dst += (n-1)/BITS_PER_LONG;
1538        src += (n-1)/BITS_PER_LONG;
1539        if ((n-1) % BITS_PER_LONG) {
1540                dst_idx += (n-1) % BITS_PER_LONG;
1541                dst += dst_idx >> SHIFT_PER_LONG;
1542                dst_idx &= BITS_PER_LONG-1;
1543                src_idx += (n-1) % BITS_PER_LONG;
1544                src += src_idx >> SHIFT_PER_LONG;
1545                src_idx &= BITS_PER_LONG-1;
1546        }
1547
1548        shift = dst_idx-src_idx;
1549        first = ~0UL << (BITS_PER_LONG-1-dst_idx);
1550        last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
1551
1552        if (!shift) {
1553                // Same alignment for source and dest
1554
1555                if ((unsigned long)dst_idx+1 >= n) {
1556                        // Single word
1557                        if (last)
1558                                first &= last;
1559                        *dst = comp(*src, *dst, first);
1560                } else {
1561                        // Multiple destination words
1562                        // Leading bits
1563                        if (first) {
1564                                *dst = comp(*src, *dst, first);
1565                                dst--;
1566                                src--;
1567                                n -= dst_idx+1;
1568                        }
1569
1570                        // Main chunk
1571                        n /= BITS_PER_LONG;
1572                        while (n >= 8) {
1573                                *dst-- = *src--;
1574                                *dst-- = *src--;
1575                                *dst-- = *src--;
1576                                *dst-- = *src--;
1577                                *dst-- = *src--;
1578                                *dst-- = *src--;
1579                                *dst-- = *src--;
1580                                *dst-- = *src--;
1581                                n -= 8;
1582                        }
1583                        while (n--)
1584                                *dst-- = *src--;
1585
1586                        // Trailing bits
1587                        if (last)
1588                                *dst = comp(*src, *dst, last);
1589                }
1590        } else {
1591                // Different alignment for source and dest
1592
1593                right = shift & (BITS_PER_LONG-1);
1594                left = -shift & (BITS_PER_LONG-1);
1595
1596                if ((unsigned long)dst_idx+1 >= n) {
1597                        // Single destination word
1598                        if (last)
1599                                first &= last;
1600                        if (shift < 0) {
1601                                // Single source word
1602                                *dst = comp(*src << left, *dst, first);
1603                        } else if (1+(unsigned long)src_idx >= n) {
1604                                // Single source word
1605                                *dst = comp(*src >> right, *dst, first);
1606                        } else {
1607                                // 2 source words
1608                                d0 = *src--;
1609                                d1 = *src;
1610                                *dst = comp(d0 >> right | d1 << left, *dst,
1611                                            first);
1612                        }
1613                } else {
1614                        // Multiple destination words
1615                        d0 = *src--;
1616                        // Leading bits
1617                        if (shift < 0) {
1618                                // Single source word
1619                                *dst = comp(d0 << left, *dst, first);
1620                                dst--;
1621                                n -= dst_idx+1;
1622                        } else {
1623                                // 2 source words
1624                                d1 = *src--;
1625                                *dst = comp(d0 >> right | d1 << left, *dst,
1626                                            first);
1627                                d0 = d1;
1628                                dst--;
1629                                n -= dst_idx+1;
1630                        }
1631
1632                        // Main chunk
1633                        m = n % BITS_PER_LONG;
1634                        n /= BITS_PER_LONG;
1635                        while (n >= 4) {
1636                                d1 = *src--;
1637                                *dst-- = d0 >> right | d1 << left;
1638                                d0 = d1;
1639                                d1 = *src--;
1640                                *dst-- = d0 >> right | d1 << left;
1641                                d0 = d1;
1642                                d1 = *src--;
1643                                *dst-- = d0 >> right | d1 << left;
1644                                d0 = d1;
1645                                d1 = *src--;
1646                                *dst-- = d0 >> right | d1 << left;
1647                                d0 = d1;
1648                                n -= 4;
1649                        }
1650                        while (n--) {
1651                                d1 = *src--;
1652                                *dst-- = d0 >> right | d1 << left;
1653                                d0 = d1;
1654                        }
1655
1656                        // Trailing bits
1657                        if (last) {
1658                                if (m <= left) {
1659                                        // Single source word
1660                                        *dst = comp(d0 >> right, *dst, last);
1661                                } else {
1662                                        // 2 source words
1663                                        d1 = *src;
1664                                        *dst = comp(d0 >> right | d1 << left,
1665                                                    *dst, last);
1666                                }
1667                        }
1668                }
1669        }
1670}
1671
1672
1673    /*
1674     *  Unaligned forward inverting bit copy using 32-bit or 64-bit memory
1675     *  accesses
1676     */
1677
1678static void bitcpy_not(unsigned long *dst, int dst_idx,
1679                       const unsigned long *src, int src_idx, u32 n)
1680{
1681        unsigned long first, last;
1682        int shift = dst_idx-src_idx, left, right;
1683        unsigned long d0, d1;
1684        int m;
1685
1686        if (!n)
1687                return;
1688
1689        shift = dst_idx-src_idx;
1690        first = ~0UL >> dst_idx;
1691        last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
1692
1693        if (!shift) {
1694                // Same alignment for source and dest
1695
1696                if (dst_idx+n <= BITS_PER_LONG) {
1697                        // Single word
1698                        if (last)
1699                                first &= last;
1700                        *dst = comp(~*src, *dst, first);
1701                } else {
1702                        // Multiple destination words
1703                        // Leading bits
1704                        if (first) {
1705                                *dst = comp(~*src, *dst, first);
1706                                dst++;
1707                                src++;
1708                                n -= BITS_PER_LONG-dst_idx;
1709                        }
1710
1711                        // Main chunk
1712                        n /= BITS_PER_LONG;
1713                        while (n >= 8) {
1714                                *dst++ = ~*src++;
1715                                *dst++ = ~*src++;
1716                                *dst++ = ~*src++;
1717                                *dst++ = ~*src++;
1718                                *dst++ = ~*src++;
1719                                *dst++ = ~*src++;
1720                                *dst++ = ~*src++;
1721                                *dst++ = ~*src++;
1722                                n -= 8;
1723                        }
1724                        while (n--)
1725                                *dst++ = ~*src++;
1726
1727                        // Trailing bits
1728                        if (last)
1729                                *dst = comp(~*src, *dst, last);
1730                }
1731        } else {
1732                // Different alignment for source and dest
1733
1734                right = shift & (BITS_PER_LONG-1);
1735                left = -shift & (BITS_PER_LONG-1);
1736
1737                if (dst_idx+n <= BITS_PER_LONG) {
1738                        // Single destination word
1739                        if (last)
1740                                first &= last;
1741                        if (shift > 0) {
1742                                // Single source word
1743                                *dst = comp(~*src >> right, *dst, first);
1744                        } else if (src_idx+n <= BITS_PER_LONG) {
1745                                // Single source word
1746                                *dst = comp(~*src << left, *dst, first);
1747                        } else {
1748                                // 2 source words
1749                                d0 = ~*src++;
1750                                d1 = ~*src;
1751                                *dst = comp(d0 << left | d1 >> right, *dst,
1752                                            first);
1753                        }
1754                } else {
1755                        // Multiple destination words
1756                        d0 = ~*src++;
1757                        // Leading bits
1758                        if (shift > 0) {
1759                                // Single source word
1760                                *dst = comp(d0 >> right, *dst, first);
1761                                dst++;
1762                                n -= BITS_PER_LONG-dst_idx;
1763                        } else {
1764                                // 2 source words
1765                                d1 = ~*src++;
1766                                *dst = comp(d0 << left | d1 >> right, *dst,
1767                                            first);
1768                                d0 = d1;
1769                                dst++;
1770                                n -= BITS_PER_LONG-dst_idx;
1771                        }
1772
1773                        // Main chunk
1774                        m = n % BITS_PER_LONG;
1775                        n /= BITS_PER_LONG;
1776                        while (n >= 4) {
1777                                d1 = ~*src++;
1778                                *dst++ = d0 << left | d1 >> right;
1779                                d0 = d1;
1780                                d1 = ~*src++;
1781                                *dst++ = d0 << left | d1 >> right;
1782                                d0 = d1;
1783                                d1 = ~*src++;
1784                                *dst++ = d0 << left | d1 >> right;
1785                                d0 = d1;
1786                                d1 = ~*src++;
1787                                *dst++ = d0 << left | d1 >> right;
1788                                d0 = d1;
1789                                n -= 4;
1790                        }
1791                        while (n--) {
1792                                d1 = ~*src++;
1793                                *dst++ = d0 << left | d1 >> right;
1794                                d0 = d1;
1795                        }
1796
1797                        // Trailing bits
1798                        if (last) {
1799                                if (m <= right) {
1800                                        // Single source word
1801                                        *dst = comp(d0 << left, *dst, last);
1802                                } else {
1803                                        // 2 source words
1804                                        d1 = ~*src;
1805                                        *dst = comp(d0 << left | d1 >> right,
1806                                                    *dst, last);
1807                                }
1808                        }
1809                }
1810        }
1811}
1812
1813
1814    /*
1815     *  Unaligned 32-bit pattern fill using 32/64-bit memory accesses
1816     */
1817
1818static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
1819{
1820        unsigned long val = pat;
1821        unsigned long first, last;
1822
1823        if (!n)
1824                return;
1825
1826#if BITS_PER_LONG == 64
1827        val |= val << 32;
1828#endif
1829
1830        first = ~0UL >> dst_idx;
1831        last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
1832
1833        if (dst_idx+n <= BITS_PER_LONG) {
1834                // Single word
1835                if (last)
1836                        first &= last;
1837                *dst = comp(val, *dst, first);
1838        } else {
1839                // Multiple destination words
1840                // Leading bits
1841                if (first) {
1842                        *dst = comp(val, *dst, first);
1843                        dst++;
1844                        n -= BITS_PER_LONG-dst_idx;
1845                }
1846
1847                // Main chunk
1848                n /= BITS_PER_LONG;
1849                while (n >= 8) {
1850                        *dst++ = val;
1851                        *dst++ = val;
1852                        *dst++ = val;
1853                        *dst++ = val;
1854                        *dst++ = val;
1855                        *dst++ = val;
1856                        *dst++ = val;
1857                        *dst++ = val;
1858                        n -= 8;
1859                }
1860                while (n--)
1861                        *dst++ = val;
1862
1863                // Trailing bits
1864                if (last)
1865                        *dst = comp(val, *dst, last);
1866        }
1867}
1868
1869
1870    /*
1871     *  Unaligned 32-bit pattern xor using 32/64-bit memory accesses
1872     */
1873
1874static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
1875{
1876        unsigned long val = pat;
1877        unsigned long first, last;
1878
1879        if (!n)
1880                return;
1881
1882#if BITS_PER_LONG == 64
1883        val |= val << 32;
1884#endif
1885
1886        first = ~0UL >> dst_idx;
1887        last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
1888
1889        if (dst_idx+n <= BITS_PER_LONG) {
1890                // Single word
1891                if (last)
1892                        first &= last;
1893                *dst = xor(val, *dst, first);
1894        } else {
1895                // Multiple destination words
1896                // Leading bits
1897                if (first) {
1898                        *dst = xor(val, *dst, first);
1899                        dst++;
1900                        n -= BITS_PER_LONG-dst_idx;
1901                }
1902
1903                // Main chunk
1904                n /= BITS_PER_LONG;
1905                while (n >= 4) {
1906                        *dst++ ^= val;
1907                        *dst++ ^= val;
1908                        *dst++ ^= val;
1909                        *dst++ ^= val;
1910                        n -= 4;
1911                }
1912                while (n--)
1913                        *dst++ ^= val;
1914
1915                // Trailing bits
1916                if (last)
1917                        *dst = xor(val, *dst, last);
1918        }
1919}
1920
1921static inline void fill_one_line(int bpp, unsigned long next_plane,
1922                                 unsigned long *dst, int dst_idx, u32 n,
1923                                 u32 color)
1924{
1925        while (1) {
1926                dst += dst_idx >> SHIFT_PER_LONG;
1927                dst_idx &= (BITS_PER_LONG-1);
1928                bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n);
1929                if (!--bpp)
1930                        break;
1931                color >>= 1;
1932                dst_idx += next_plane*8;
1933        }
1934}
1935
1936static inline void xor_one_line(int bpp, unsigned long next_plane,
1937                                unsigned long *dst, int dst_idx, u32 n,
1938                                u32 color)
1939{
1940        while (color) {
1941                dst += dst_idx >> SHIFT_PER_LONG;
1942                dst_idx &= (BITS_PER_LONG-1);
1943                bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n);
1944                if (!--bpp)
1945                        break;
1946                color >>= 1;
1947                dst_idx += next_plane*8;
1948        }
1949}
1950
1951
1952static void amifb_fillrect(struct fb_info *info,
1953                           const struct fb_fillrect *rect)
1954{
1955        struct amifb_par *par = (struct amifb_par *)info->par;
1956        int dst_idx, x2, y2;
1957        unsigned long *dst;
1958        u32 width, height;
1959
1960        if (!rect->width || !rect->height)
1961                return;
1962
1963        /*
1964         * We could use hardware clipping but on many cards you get around
1965         * hardware clipping by writing to framebuffer directly.
1966         * */
1967        x2 = rect->dx + rect->width;
1968        y2 = rect->dy + rect->height;
1969        x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
1970        y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
1971        width = x2 - rect->dx;
1972        height = y2 - rect->dy;
1973
1974        dst = (unsigned long *)
1975                ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
1976        dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
1977        dst_idx += rect->dy*par->next_line*8+rect->dx;
1978        while (height--) {
1979                switch (rect->rop) {
1980                    case ROP_COPY:
1981                        fill_one_line(info->var.bits_per_pixel,
1982                                      par->next_plane, dst, dst_idx, width,
1983                                      rect->color);
1984                        break;
1985
1986                    case ROP_XOR:
1987                        xor_one_line(info->var.bits_per_pixel, par->next_plane,
1988                                     dst, dst_idx, width, rect->color);
1989                        break;
1990                }
1991                dst_idx += par->next_line*8;
1992        }
1993}
1994
1995static inline void copy_one_line(int bpp, unsigned long next_plane,
1996                                 unsigned long *dst, int dst_idx,
1997                                 unsigned long *src, int src_idx, u32 n)
1998{
1999        while (1) {
2000                dst += dst_idx >> SHIFT_PER_LONG;
2001                dst_idx &= (BITS_PER_LONG-1);
2002                src += src_idx >> SHIFT_PER_LONG;
2003                src_idx &= (BITS_PER_LONG-1);
2004                bitcpy(dst, dst_idx, src, src_idx, n);
2005                if (!--bpp)
2006                        break;
2007                dst_idx += next_plane*8;
2008                src_idx += next_plane*8;
2009        }
2010}
2011
2012static inline void copy_one_line_rev(int bpp, unsigned long next_plane,
2013                                     unsigned long *dst, int dst_idx,
2014                                     unsigned long *src, int src_idx, u32 n)
2015{
2016        while (1) {
2017                dst += dst_idx >> SHIFT_PER_LONG;
2018                dst_idx &= (BITS_PER_LONG-1);
2019                src += src_idx >> SHIFT_PER_LONG;
2020                src_idx &= (BITS_PER_LONG-1);
2021                bitcpy_rev(dst, dst_idx, src, src_idx, n);
2022                if (!--bpp)
2023                        break;
2024                dst_idx += next_plane*8;
2025                src_idx += next_plane*8;
2026        }
2027}
2028
2029
2030static void amifb_copyarea(struct fb_info *info,
2031                           const struct fb_copyarea *area)
2032{
2033        struct amifb_par *par = (struct amifb_par *)info->par;
2034        int x2, y2;
2035        u32 dx, dy, sx, sy, width, height;
2036        unsigned long *dst, *src;
2037        int dst_idx, src_idx;
2038        int rev_copy = 0;
2039
2040        /* clip the destination */
2041        x2 = area->dx + area->width;
2042        y2 = area->dy + area->height;
2043        dx = area->dx > 0 ? area->dx : 0;
2044        dy = area->dy > 0 ? area->dy : 0;
2045        x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
2046        y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
2047        width = x2 - dx;
2048        height = y2 - dy;
2049
2050        if (area->sx + dx < area->dx || area->sy + dy < area->dy)
2051                return;
2052
2053        /* update sx,sy */
2054        sx = area->sx + (dx - area->dx);
2055        sy = area->sy + (dy - area->dy);
2056
2057        /* the source must be completely inside the virtual screen */
2058        if (sx + width > info->var.xres_virtual ||
2059                        sy + height > info->var.yres_virtual)
2060                return;
2061
2062        if (dy > sy || (dy == sy && dx > sx)) {
2063                dy += height;
2064                sy += height;
2065                rev_copy = 1;
2066        }
2067        dst = (unsigned long *)
2068                ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
2069        src = dst;
2070        dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
2071        src_idx = dst_idx;
2072        dst_idx += dy*par->next_line*8+dx;
2073        src_idx += sy*par->next_line*8+sx;
2074        if (rev_copy) {
2075                while (height--) {
2076                        dst_idx -= par->next_line*8;
2077                        src_idx -= par->next_line*8;
2078                        copy_one_line_rev(info->var.bits_per_pixel,
2079                                          par->next_plane, dst, dst_idx, src,
2080                                          src_idx, width);
2081                }
2082        } else {
2083                while (height--) {
2084                        copy_one_line(info->var.bits_per_pixel,
2085                                      par->next_plane, dst, dst_idx, src,
2086                                      src_idx, width);
2087                        dst_idx += par->next_line*8;
2088                        src_idx += par->next_line*8;
2089                }
2090        }
2091}
2092
2093
2094static inline void expand_one_line(int bpp, unsigned long next_plane,
2095                                   unsigned long *dst, int dst_idx, u32 n,
2096                                   const u8 *data, u32 bgcolor, u32 fgcolor)
2097{
2098    const unsigned long *src;
2099    int src_idx;
2100
2101    while (1) {
2102        dst += dst_idx >> SHIFT_PER_LONG;
2103        dst_idx &= (BITS_PER_LONG-1);
2104        if ((bgcolor ^ fgcolor) & 1) {
2105            src = (unsigned long *)((unsigned long)data & ~(BYTES_PER_LONG-1));
2106            src_idx = ((unsigned long)data & (BYTES_PER_LONG-1))*8;
2107            if (fgcolor & 1)
2108                bitcpy(dst, dst_idx, src, src_idx, n);
2109            else
2110                bitcpy_not(dst, dst_idx, src, src_idx, n);
2111            /* set or clear */
2112        } else
2113            bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n);
2114        if (!--bpp)
2115            break;
2116        bgcolor >>= 1;
2117        fgcolor >>= 1;
2118        dst_idx += next_plane*8;
2119    }
2120}
2121
2122
2123static void amifb_imageblit(struct fb_info *info, const struct fb_image *image)
2124{
2125        struct amifb_par *par = (struct amifb_par *)info->par;
2126        int x2, y2;
2127        unsigned long *dst;
2128        int dst_idx;
2129        const char *src;
2130        u32 dx, dy, width, height, pitch;
2131
2132        /*
2133         * We could use hardware clipping but on many cards you get around
2134         * hardware clipping by writing to framebuffer directly like we are
2135         * doing here.
2136         */
2137        x2 = image->dx + image->width;
2138        y2 = image->dy + image->height;
2139        dx = image->dx;
2140        dy = image->dy;
2141        x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
2142        y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
2143        width  = x2 - dx;
2144        height = y2 - dy;
2145
2146        if (image->depth == 1) {
2147                dst = (unsigned long *)
2148                        ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
2149                dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
2150                dst_idx += dy*par->next_line*8+dx;
2151                src = image->data;
2152                pitch = (image->width+7)/8;
2153                while (height--) {
2154                        expand_one_line(info->var.bits_per_pixel,
2155                                        par->next_plane, dst, dst_idx, width,
2156                                        src, image->bg_color,
2157                                        image->fg_color);
2158                        dst_idx += par->next_line*8;
2159                        src += pitch;
2160                }
2161        } else {
2162                c2p_planar(info->screen_base, image->data, dx, dy, width,
2163                           height, par->next_line, par->next_plane,
2164                           image->width, info->var.bits_per_pixel);
2165        }
2166}
2167
2168
2169        /*
2170         * Amiga Frame Buffer Specific ioctls
2171         */
2172
2173static int amifb_ioctl(struct fb_info *info,
2174                       unsigned int cmd, unsigned long arg)
2175{
2176        union {
2177                struct fb_fix_cursorinfo fix;
2178                struct fb_var_cursorinfo var;
2179                struct fb_cursorstate state;
2180        } crsr;
2181        void __user *argp = (void __user *)arg;
2182        int i;
2183
2184        switch (cmd) {
2185                case FBIOGET_FCURSORINFO:
2186                        i = ami_get_fix_cursorinfo(&crsr.fix);
2187                        if (i)
2188                                return i;
2189                        return copy_to_user(argp, &crsr.fix,
2190                                            sizeof(crsr.fix)) ? -EFAULT : 0;
2191
2192                case FBIOGET_VCURSORINFO:
2193                        i = ami_get_var_cursorinfo(&crsr.var,
2194                                ((struct fb_var_cursorinfo __user *)arg)->data);
2195                        if (i)
2196                                return i;
2197                        return copy_to_user(argp, &crsr.var,
2198                                            sizeof(crsr.var)) ? -EFAULT : 0;
2199
2200                case FBIOPUT_VCURSORINFO:
2201                        if (copy_from_user(&crsr.var, argp, sizeof(crsr.var)))
2202                                return -EFAULT;
2203                        return ami_set_var_cursorinfo(&crsr.var,
2204                                ((struct fb_var_cursorinfo __user *)arg)->data);
2205
2206                case FBIOGET_CURSORSTATE:
2207                        i = ami_get_cursorstate(&crsr.state);
2208                        if (i)
2209                                return i;
2210                        return copy_to_user(argp, &crsr.state,
2211                                            sizeof(crsr.state)) ? -EFAULT : 0;
2212
2213                case FBIOPUT_CURSORSTATE:
2214                        if (copy_from_user(&crsr.state, argp,
2215                                           sizeof(crsr.state)))
2216                                return -EFAULT;
2217                        return ami_set_cursorstate(&crsr.state);
2218        }
2219        return -EINVAL;
2220}
2221
2222
2223        /*
2224         * Allocate, Clear and Align a Block of Chip Memory
2225         */
2226
2227static u_long unaligned_chipptr = 0;
2228
2229static inline u_long __init chipalloc(u_long size)
2230{
2231        size += PAGE_SIZE-1;
2232        if (!(unaligned_chipptr = (u_long)amiga_chip_alloc(size,
2233                                                           "amifb [RAM]")))
2234                panic("No Chip RAM for frame buffer");
2235        memset((void *)unaligned_chipptr, 0, size);
2236        return PAGE_ALIGN(unaligned_chipptr);
2237}
2238
2239static inline void chipfree(void)
2240{
2241        if (unaligned_chipptr)
2242                amiga_chip_free((void *)unaligned_chipptr);
2243}
2244
2245
2246        /*
2247         * Initialisation
2248         */
2249
2250static int __init amifb_init(void)
2251{
2252        int tag, i, err = 0;
2253        u_long chipptr;
2254        u_int defmode;
2255
2256#ifndef MODULE
2257        char *option = NULL;
2258
2259        if (fb_get_options("amifb", &option)) {
2260                amifb_video_off();
2261                return -ENODEV;
2262        }
2263        amifb_setup(option);
2264#endif
2265        if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO))
2266                return -ENODEV;
2267
2268        /*
2269         * We request all registers starting from bplpt[0]
2270         */
2271        if (!request_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120,
2272                                "amifb [Denise/Lisa]"))
2273                return -EBUSY;
2274
2275        custom.dmacon = DMAF_ALL | DMAF_MASTER;
2276
2277        switch (amiga_chipset) {
2278#ifdef CONFIG_FB_AMIGA_OCS
2279                case CS_OCS:
2280                        strcat(fb_info.fix.id, "OCS");
2281default_chipset:
2282                        chipset = TAG_OCS;
2283                        maxdepth[TAG_SHRES] = 0;        /* OCS means no SHRES */
2284                        maxdepth[TAG_HIRES] = 4;
2285                        maxdepth[TAG_LORES] = 6;
2286                        maxfmode = TAG_FMODE_1;
2287                        defmode = amiga_vblank == 50 ? DEFMODE_PAL
2288                                                     : DEFMODE_NTSC;
2289                        fb_info.fix.smem_len = VIDEOMEMSIZE_OCS;
2290                        break;
2291#endif /* CONFIG_FB_AMIGA_OCS */
2292
2293#ifdef CONFIG_FB_AMIGA_ECS
2294                case CS_ECS:
2295                        strcat(fb_info.fix.id, "ECS");
2296                        chipset = TAG_ECS;
2297                        maxdepth[TAG_SHRES] = 2;
2298                        maxdepth[TAG_HIRES] = 4;
2299                        maxdepth[TAG_LORES] = 6;
2300                        maxfmode = TAG_FMODE_1;
2301                        if (AMIGAHW_PRESENT(AMBER_FF))
2302                            defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL
2303                                                         : DEFMODE_AMBER_NTSC;
2304                        else
2305                            defmode = amiga_vblank == 50 ? DEFMODE_PAL
2306                                                         : DEFMODE_NTSC;
2307                        if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
2308                            VIDEOMEMSIZE_ECS_1M)
2309                                fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M;
2310                        else
2311                                fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M;
2312                        break;
2313#endif /* CONFIG_FB_AMIGA_ECS */
2314
2315#ifdef CONFIG_FB_AMIGA_AGA
2316                case CS_AGA:
2317                        strcat(fb_info.fix.id, "AGA");
2318                        chipset = TAG_AGA;
2319                        maxdepth[TAG_SHRES] = 8;
2320                        maxdepth[TAG_HIRES] = 8;
2321                        maxdepth[TAG_LORES] = 8;
2322                        maxfmode = TAG_FMODE_4;
2323                        defmode = DEFMODE_AGA;
2324                        if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
2325                            VIDEOMEMSIZE_AGA_1M)
2326                                fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M;
2327                        else
2328                                fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M;
2329                        break;
2330#endif /* CONFIG_FB_AMIGA_AGA */
2331
2332                default:
2333#ifdef CONFIG_FB_AMIGA_OCS
2334                        printk("Unknown graphics chipset, defaulting to OCS\n");
2335                        strcat(fb_info.fix.id, "Unknown");
2336                        goto default_chipset;
2337#else /* CONFIG_FB_AMIGA_OCS */
2338                        err = -ENODEV;
2339                        goto amifb_error;
2340#endif /* CONFIG_FB_AMIGA_OCS */
2341                        break;
2342        }
2343
2344        /*
2345         * Calculate the Pixel Clock Values for this Machine
2346         */
2347
2348        {
2349        u_long tmp = DIVUL(200000000000ULL, amiga_eclock);
2350
2351        pixclock[TAG_SHRES] = (tmp + 4) / 8;    /* SHRES:  35 ns / 28 MHz */
2352        pixclock[TAG_HIRES] = (tmp + 2) / 4;    /* HIRES:  70 ns / 14 MHz */
2353        pixclock[TAG_LORES] = (tmp + 1) / 2;    /* LORES: 140 ns /  7 MHz */
2354        }
2355
2356        /*
2357         * Replace the Tag Values with the Real Pixel Clock Values
2358         */
2359
2360        for (i = 0; i < NUM_TOTAL_MODES; i++) {
2361                struct fb_videomode *mode = &ami_modedb[i];
2362                tag = mode->pixclock;
2363                if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
2364                        mode->pixclock = pixclock[tag];
2365                }
2366        }
2367
2368        /*
2369         *  These monitor specs are for a typical Amiga monitor (e.g. A1960)
2370         */
2371        if (fb_info.monspecs.hfmin == 0) {
2372            fb_info.monspecs.hfmin = 15000;
2373            fb_info.monspecs.hfmax = 38000;
2374            fb_info.monspecs.vfmin = 49;
2375            fb_info.monspecs.vfmax = 90;
2376        }
2377
2378        fb_info.fbops = &amifb_ops;
2379        fb_info.par = &currentpar;
2380        fb_info.flags = FBINFO_DEFAULT;
2381
2382        if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb,
2383                          NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
2384                err = -EINVAL;
2385                goto amifb_error;
2386        }
2387
2388        fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES,
2389                                 &fb_info.modelist);
2390
2391        round_down_bpp = 0;
2392        chipptr = chipalloc(fb_info.fix.smem_len+
2393                            SPRITEMEMSIZE+
2394                            DUMMYSPRITEMEMSIZE+
2395                            COPINITSIZE+
2396                            4*COPLISTSIZE);
2397
2398        assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len);
2399        assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
2400        assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
2401        assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
2402        assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);
2403        assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);
2404        assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);
2405        assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);
2406
2407        /*
2408         * access the videomem with writethrough cache
2409         */
2410        fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory);
2411        videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start,
2412                                                   fb_info.fix.smem_len);
2413        if (!videomemory) {
2414                printk("amifb: WARNING! unable to map videomem cached writethrough\n");
2415                fb_info.screen_base = (char *)ZTWO_VADDR(fb_info.fix.smem_start);
2416        } else
2417                fb_info.screen_base = (char *)videomemory;
2418
2419        memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
2420
2421        /*
2422         * Enable Display DMA
2423         */
2424
2425        custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
2426                        DMAF_BLITTER | DMAF_SPRITE;
2427
2428        /*
2429         * Make sure the Copper has something to do
2430         */
2431
2432        ami_init_copper();
2433
2434        if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,
2435                        "fb vertb handler", &currentpar)) {
2436                err = -EBUSY;
2437                goto amifb_error;
2438        }
2439
2440        err = fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0);
2441        if (err)
2442                goto amifb_error;
2443
2444        if (register_framebuffer(&fb_info) < 0) {
2445                err = -EINVAL;
2446                goto amifb_error;
2447        }
2448
2449        printk("fb%d: %s frame buffer device, using %dK of video memory\n",
2450               fb_info.node, fb_info.fix.id, fb_info.fix.smem_len>>10);
2451
2452        return 0;
2453
2454amifb_error:
2455        amifb_deinit();
2456        return err;
2457}
2458
2459static void amifb_deinit(void)
2460{
2461        if (fb_info.cmap.len)
2462                fb_dealloc_cmap(&fb_info.cmap);
2463        chipfree();
2464        if (videomemory)
2465                iounmap((void*)videomemory);
2466        release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
2467        custom.dmacon = DMAF_ALL | DMAF_MASTER;
2468}
2469
2470
2471        /*
2472         * Blank the display.
2473         */
2474
2475static int amifb_blank(int blank, struct fb_info *info)
2476{
2477        do_blank = blank ? blank : -1;
2478
2479        return 0;
2480}
2481
2482        /*
2483         * Flash the cursor (called by VBlank interrupt)
2484         */
2485
2486static int flash_cursor(void)
2487{
2488        static int cursorcount = 1;
2489
2490        if (cursormode == FB_CURSOR_FLASH) {
2491                if (!--cursorcount) {
2492                        cursorstate = -cursorstate;
2493                        cursorcount = cursorrate;
2494                        if (!is_blanked)
2495                                return 1;
2496                }
2497        }
2498        return 0;
2499}
2500
2501        /*
2502         * VBlank Display Interrupt
2503         */
2504
2505static irqreturn_t amifb_interrupt(int irq, void *dev_id)
2506{
2507        if (do_vmode_pan || do_vmode_full)
2508                ami_update_display();
2509
2510        if (do_vmode_full)
2511                ami_init_display();
2512
2513        if (do_vmode_pan) {
2514                flash_cursor();
2515                ami_rebuild_copper();
2516                do_cursor = do_vmode_pan = 0;
2517        } else if (do_cursor) {
2518                flash_cursor();
2519                ami_set_sprite();
2520                do_cursor = 0;
2521        } else {
2522                if (flash_cursor())
2523                        ami_set_sprite();
2524        }
2525
2526        if (do_blank) {
2527                ami_do_blank();
2528                do_blank = 0;
2529        }
2530
2531        if (do_vmode_full) {
2532                ami_reinit_copper();
2533                do_vmode_full = 0;
2534        }
2535        return IRQ_HANDLED;
2536}
2537
2538/* --------------------------- Hardware routines --------------------------- */
2539
2540        /*
2541         * Get the video params out of `var'. If a value doesn't fit, round
2542         * it up, if it's too big, return -EINVAL.
2543         */
2544
2545static int ami_decode_var(struct fb_var_screeninfo *var,
2546                          struct amifb_par *par)
2547{
2548        u_short clk_shift, line_shift;
2549        u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;
2550        u_int htotal, vtotal;
2551
2552        /*
2553         * Find a matching Pixel Clock
2554         */
2555
2556        for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++)
2557                if (var->pixclock <= pixclock[clk_shift])
2558                        break;
2559        if (clk_shift > TAG_LORES) {
2560                DPRINTK("pixclock too high\n");
2561                return -EINVAL;
2562        }
2563        par->clk_shift = clk_shift;
2564
2565        /*
2566         * Check the Geometry Values
2567         */
2568
2569        if ((par->xres = var->xres) < 64)
2570                par->xres = 64;
2571        if ((par->yres = var->yres) < 64)
2572                par->yres = 64;
2573        if ((par->vxres = var->xres_virtual) < par->xres)
2574                par->vxres = par->xres;
2575        if ((par->vyres = var->yres_virtual) < par->yres)
2576                par->vyres = par->yres;
2577
2578        par->bpp = var->bits_per_pixel;
2579        if (!var->nonstd) {
2580                if (par->bpp < 1)
2581                        par->bpp = 1;
2582                if (par->bpp > maxdepth[clk_shift]) {
2583                        if (round_down_bpp && maxdepth[clk_shift])
2584                                par->bpp = maxdepth[clk_shift];
2585                        else {
2586                                DPRINTK("invalid bpp\n");
2587                                return -EINVAL;
2588                        }
2589                }
2590        } else if (var->nonstd == FB_NONSTD_HAM) {
2591                if (par->bpp < 6)
2592                        par->bpp = 6;
2593                if (par->bpp != 6) {
2594                        if (par->bpp < 8)
2595                                par->bpp = 8;
2596                        if (par->bpp != 8 || !IS_AGA) {
2597                                DPRINTK("invalid bpp for ham mode\n");
2598                                return -EINVAL;
2599                        }
2600                }
2601        } else {
2602                DPRINTK("unknown nonstd mode\n");
2603                return -EINVAL;
2604        }
2605
2606        /*
2607         * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
2608         * checks failed and smooth scrolling is not possible
2609         */
2610
2611        par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN;
2612        switch (par->vmode & FB_VMODE_MASK) {
2613                case FB_VMODE_INTERLACED:
2614                        line_shift = 0;
2615                        break;
2616                case FB_VMODE_NONINTERLACED:
2617                        line_shift = 1;
2618                        break;
2619                case FB_VMODE_DOUBLE:
2620                        if (!IS_AGA) {
2621                                DPRINTK("double mode only possible with aga\n");
2622                                return -EINVAL;
2623                        }
2624                        line_shift = 2;
2625                        break;
2626                default:
2627                        DPRINTK("unknown video mode\n");
2628                        return -EINVAL;
2629                        break;
2630        }
2631        par->line_shift = line_shift;
2632
2633        /*
2634         * Vertical and Horizontal Timings
2635         */
2636
2637        xres_n = par->xres<<clk_shift;
2638        yres_n = par->yres<<line_shift;
2639        par->htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<<clk_shift);
2640        par->vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<<line_shift)+1);
2641
2642        if (IS_AGA)
2643                par->bplcon3 = sprpixmode[clk_shift];
2644        else
2645                par->bplcon3 = 0;
2646        if (var->sync & FB_SYNC_BROADCAST) {
2647                par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<<clk_shift);
2648                if (IS_AGA)
2649                        par->diwstop_h += mod4(var->hsync_len);
2650                else
2651                        par->diwstop_h = down4(par->diwstop_h);
2652
2653                par->diwstrt_h = par->diwstop_h - xres_n;
2654                par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<<line_shift);
2655                par->diwstrt_v = par->diwstop_v - yres_n;
2656                if (par->diwstop_h >= par->htotal+8) {
2657                        DPRINTK("invalid diwstop_h\n");
2658                        return -EINVAL;
2659                }
2660                if (par->diwstop_v > par->vtotal) {
2661                        DPRINTK("invalid diwstop_v\n");
2662                        return -EINVAL;
2663                }
2664
2665                if (!IS_OCS) {
2666                        /* Initialize sync with some reasonable values for pwrsave */
2667                        par->hsstrt = 160;
2668                        par->hsstop = 320;
2669                        par->vsstrt = 30;
2670                        par->vsstop = 34;
2671                } else {
2672                        par->hsstrt = 0;
2673                        par->hsstop = 0;
2674                        par->vsstrt = 0;
2675                        par->vsstop = 0;
2676                }
2677                if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) {
2678                        /* PAL video mode */
2679                        if (par->htotal != PAL_HTOTAL) {
2680                                DPRINTK("htotal invalid for pal\n");
2681                                return -EINVAL;
2682                        }
2683                        if (par->diwstrt_h < PAL_DIWSTRT_H) {
2684                                DPRINTK("diwstrt_h too low for pal\n");
2685                                return -EINVAL;
2686                        }
2687                        if (par->diwstrt_v < PAL_DIWSTRT_V) {
2688                                DPRINTK("diwstrt_v too low for pal\n");
2689                                return -EINVAL;
2690                        }
2691                        htotal = PAL_HTOTAL>>clk_shift;
2692                        vtotal = PAL_VTOTAL>>1;
2693                        if (!IS_OCS) {
2694                                par->beamcon0 = BMC0_PAL;
2695                                par->bplcon3 |= BPC3_BRDRBLNK;
2696                        } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
2697                                   AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
2698                                par->beamcon0 = BMC0_PAL;
2699                                par->hsstop = 1;
2700                        } else if (amiga_vblank != 50) {
2701                                DPRINTK("pal not supported by this chipset\n");
2702                                return -EINVAL;
2703                        }
2704                } else {
2705                        /* NTSC video mode
2706                         * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK
2707                         * and NTSC activated, so than better let diwstop_h <= 1812
2708                         */
2709                        if (par->htotal != NTSC_HTOTAL) {
2710                                DPRINTK("htotal invalid for ntsc\n");
2711                                return -EINVAL;
2712                        }
2713                        if (par->diwstrt_h < NTSC_DIWSTRT_H) {
2714                                DPRINTK("diwstrt_h too low for ntsc\n");
2715                                return -EINVAL;
2716                        }
2717                        if (par->diwstrt_v < NTSC_DIWSTRT_V) {
2718                                DPRINTK("diwstrt_v too low for ntsc\n");
2719                                return -EINVAL;
2720                        }
2721                        htotal = NTSC_HTOTAL>>clk_shift;
2722                        vtotal = NTSC_VTOTAL>>1;
2723                        if (!IS_OCS) {
2724                                par->beamcon0 = 0;
2725                                par->bplcon3 |= BPC3_BRDRBLNK;
2726                        } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
2727                                   AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
2728                                par->beamcon0 = 0;
2729                                par->hsstop = 1;
2730                        } else if (amiga_vblank != 60) {
2731                                DPRINTK("ntsc not supported by this chipset\n");
2732                                return -EINVAL;
2733                        }
2734                }
2735                if (IS_OCS) {
2736                        if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 ||
2737                            par->diwstrt_v >=  512 || par->diwstop_v <  256) {
2738                                DPRINTK("invalid position for display on ocs\n");
2739                                return -EINVAL;
2740                        }
2741                }
2742        } else if (!IS_OCS) {
2743                /* Programmable video mode */
2744                par->hsstrt = var->right_margin<<clk_shift;
2745                par->hsstop = (var->right_margin+var->hsync_len)<<clk_shift;
2746                par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift);
2747                if (!IS_AGA)
2748                        par->diwstop_h = down4(par->diwstop_h) - 16;
2749                par->diwstrt_h = par->diwstop_h - xres_n;
2750                par->hbstop = par->diwstrt_h + 4;
2751                par->hbstrt = par->diwstop_h + 4;
2752                if (par->hbstrt >= par->htotal + 8)
2753                        par->hbstrt -= par->htotal;
2754                par->hcenter = par->hsstrt + (par->htotal >> 1);
2755                par->vsstrt = var->lower_margin<<line_shift;
2756                par->vsstop = (var->lower_margin+var->vsync_len)<<line_shift;
2757                par->diwstop_v = par->vtotal;
2758                if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
2759                        par->diwstop_v -= 2;
2760                par->diwstrt_v = par->diwstop_v - yres_n;
2761                par->vbstop = par->diwstrt_v - 2;
2762                par->vbstrt = par->diwstop_v - 2;
2763                if (par->vtotal > 2048) {
2764                        DPRINTK("vtotal too high\n");
2765                        return -EINVAL;
2766                }
2767                if (par->htotal > 2048) {
2768                        DPRINTK("htotal too high\n");
2769                        return -EINVAL;
2770                }
2771                par->bplcon3 |= BPC3_EXTBLKEN;
2772                par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
2773                                BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
2774                                BMC0_PAL | BMC0_VARCSYEN;
2775                if (var->sync & FB_SYNC_HOR_HIGH_ACT)
2776                        par->beamcon0 |= BMC0_HSYTRUE;
2777                if (var->sync & FB_SYNC_VERT_HIGH_ACT)
2778                        par->beamcon0 |= BMC0_VSYTRUE;
2779                if (var->sync & FB_SYNC_COMP_HIGH_ACT)
2780                        par->beamcon0 |= BMC0_CSYTRUE;
2781                htotal = par->htotal>>clk_shift;
2782                vtotal = par->vtotal>>1;
2783        } else {
2784                DPRINTK("only broadcast modes possible for ocs\n");
2785                return -EINVAL;
2786        }
2787
2788        /*
2789         * Checking the DMA timing
2790         */
2791
2792        fconst = 16<<maxfmode<<clk_shift;
2793
2794        /*
2795         * smallest window start value without turn off other dma cycles
2796         * than sprite1-7, unless you change min_fstrt
2797         */
2798
2799
2800        fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64);
2801        fstrt = downx(fconst, par->diwstrt_h-4) - fsize;
2802        if (fstrt < min_fstrt) {
2803                DPRINTK("fetch start too low\n");
2804                return -EINVAL;
2805        }
2806
2807        /*
2808         * smallest window start value where smooth scrolling is possible
2809         */
2810
2811        fstrt = downx(fconst, par->diwstrt_h-fconst+(1<<clk_shift)-4) - fsize;
2812        if (fstrt < min_fstrt)
2813                par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2814
2815        maxfetchstop = down16(par->htotal - 80);
2816
2817        fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst;
2818        fsize = upx(fconst, xres_n + modx(fconst, downx(1<<clk_shift, par->diwstrt_h-4)));
2819        if (fstrt + fsize > maxfetchstop)
2820                par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2821
2822        fsize = upx(fconst, xres_n);
2823        if (fstrt + fsize > maxfetchstop) {
2824                DPRINTK("fetch stop too high\n");
2825                return -EINVAL;
2826        }
2827
2828        if (maxfmode + clk_shift <= 1) {
2829                fsize = up64(xres_n + fconst - 1);
2830                if (min_fstrt + fsize - 64 > maxfetchstop)
2831                        par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2832
2833                fsize = up64(xres_n);
2834                if (min_fstrt + fsize - 64 > maxfetchstop) {
2835                        DPRINTK("fetch size too high\n");
2836                        return -EINVAL;
2837                }
2838
2839                fsize -= 64;
2840        } else
2841                fsize -= fconst;
2842
2843        /*
2844         * Check if there is enough time to update the bitplane pointers for ywrap
2845         */
2846
2847        if (par->htotal-fsize-64 < par->bpp*64)
2848                par->vmode &= ~FB_VMODE_YWRAP;
2849
2850        /*
2851         * Bitplane calculations and check the Memory Requirements
2852         */
2853
2854        if (amifb_ilbm) {
2855                par->next_plane = div8(upx(16<<maxfmode, par->vxres));
2856                par->next_line = par->bpp*par->next_plane;
2857                if (par->next_line * par->vyres > fb_info.fix.smem_len) {
2858                        DPRINTK("too few video mem\n");
2859                        return -EINVAL;
2860                }
2861        } else {
2862                par->next_line = div8(upx(16<<maxfmode, par->vxres));
2863                par->next_plane = par->vyres*par->next_line;
2864                if (par->next_plane * par->bpp > fb_info.fix.smem_len) {
2865                        DPRINTK("too few video mem\n");
2866                        return -EINVAL;
2867                }
2868        }
2869
2870        /*
2871         * Hardware Register Values
2872         */
2873
2874        par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift];
2875        if (!IS_OCS)
2876                par->bplcon0 |= BPC0_ECSENA;
2877        if (par->bpp == 8)
2878                par->bplcon0 |= BPC0_BPU3;
2879        else
2880                par->bplcon0 |= par->bpp<<12;
2881        if (var->nonstd == FB_NONSTD_HAM)
2882                par->bplcon0 |= BPC0_HAM;
2883        if (var->sync & FB_SYNC_EXT)
2884                par->bplcon0 |= BPC0_ERSY;
2885
2886        if (IS_AGA)
2887                par->fmode = bplfetchmode[maxfmode];
2888
2889        switch (par->vmode & FB_VMODE_MASK) {
2890                case FB_VMODE_INTERLACED:
2891                        par->bplcon0 |= BPC0_LACE;
2892                        break;
2893                case FB_VMODE_DOUBLE:
2894                        if (IS_AGA)
2895                                par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
2896                        break;
2897        }
2898
2899        if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {
2900                par->xoffset = var->xoffset;
2901                par->yoffset = var->yoffset;
2902                if (par->vmode & FB_VMODE_YWRAP) {
2903                        if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres)
2904                                par->xoffset = par->yoffset = 0;
2905                } else {
2906                        if (par->xoffset < 0 || par->xoffset > upx(16<<maxfmode, par->vxres-par->xres) ||
2907                            par->yoffset < 0 || par->yoffset > par->vyres-par->yres)
2908                                par->xoffset = par->yoffset = 0;
2909                }
2910        } else
2911                par->xoffset = par->yoffset = 0;
2912
2913        par->crsr.crsr_x = par->crsr.crsr_y = 0;
2914        par->crsr.spot_x = par->crsr.spot_y = 0;
2915        par->crsr.height = par->crsr.width = 0;
2916
2917        return 0;
2918}
2919
2920        /*
2921         * Fill the `var' structure based on the values in `par' and maybe
2922         * other values read out of the hardware.
2923         */
2924
2925static int ami_encode_var(struct fb_var_screeninfo *var,
2926                          struct amifb_par *par)
2927{
2928        u_short clk_shift, line_shift;
2929
2930        memset(var, 0, sizeof(struct fb_var_screeninfo));
2931
2932        clk_shift = par->clk_shift;
2933        line_shift = par->line_shift;
2934
2935        var->xres = par->xres;
2936        var->yres = par->yres;
2937        var->xres_virtual = par->vxres;
2938        var->yres_virtual = par->vyres;
2939        var->xoffset = par->xoffset;
2940        var->yoffset = par->yoffset;
2941
2942        var->bits_per_pixel = par->bpp;
2943        var->grayscale = 0;
2944
2945        var->red.offset = 0;
2946        var->red.msb_right = 0;
2947        var->red.length = par->bpp;
2948        if (par->bplcon0 & BPC0_HAM)
2949            var->red.length -= 2;
2950        var->blue = var->green = var->red;
2951        var->transp.offset = 0;
2952        var->transp.length = 0;
2953        var->transp.msb_right = 0;
2954
2955        if (par->bplcon0 & BPC0_HAM)
2956                var->nonstd = FB_NONSTD_HAM;
2957        else
2958                var->nonstd = 0;
2959        var->activate = 0;
2960
2961        var->height = -1;
2962        var->width = -1;
2963
2964        var->pixclock = pixclock[clk_shift];
2965
2966        if (IS_AGA && par->fmode & FMODE_BSCAN2)
2967                var->vmode = FB_VMODE_DOUBLE;
2968        else if (par->bplcon0 & BPC0_LACE)
2969                var->vmode = FB_VMODE_INTERLACED;
2970        else
2971                var->vmode = FB_VMODE_NONINTERLACED;
2972
2973        if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) {
2974                var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift;
2975                var->right_margin = par->hsstrt>>clk_shift;
2976                var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
2977                var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift;
2978                var->lower_margin = par->vsstrt>>line_shift;
2979                var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len;
2980                var->sync = 0;
2981                if (par->beamcon0 & BMC0_HSYTRUE)
2982                        var->sync |= FB_SYNC_HOR_HIGH_ACT;
2983                if (par->beamcon0 & BMC0_VSYTRUE)
2984                        var->sync |= FB_SYNC_VERT_HIGH_ACT;
2985                if (par->beamcon0 & BMC0_CSYTRUE)
2986                        var->sync |= FB_SYNC_COMP_HIGH_ACT;
2987        } else {
2988                var->sync = FB_SYNC_BROADCAST;
2989                var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h);
2990                var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len;
2991                var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
2992                var->vsync_len = 4>>line_shift;
2993                var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len;
2994                var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres -
2995                                    var->lower_margin - var->vsync_len;
2996        }
2997
2998        if (par->bplcon0 & BPC0_ERSY)
2999                var->sync |= FB_SYNC_EXT;
3000        if (par->vmode & FB_VMODE_YWRAP)
3001                var->vmode |= FB_VMODE_YWRAP;
3002
3003        return 0;
3004}
3005
3006
3007        /*
3008         * Pan or Wrap the Display
3009         *
3010         * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
3011         * in `var'.
3012         */
3013
3014static void ami_pan_var(struct fb_var_screeninfo *var)
3015{
3016        struct amifb_par *par = &currentpar;
3017
3018        par->xoffset = var->xoffset;
3019        par->yoffset = var->yoffset;
3020        if (var->vmode & FB_VMODE_YWRAP)
3021                par->vmode |= FB_VMODE_YWRAP;
3022        else
3023                par->vmode &= ~FB_VMODE_YWRAP;
3024
3025        do_vmode_pan = 0;
3026        ami_update_par();
3027        do_vmode_pan = 1;
3028}
3029
3030        /*
3031         * Update hardware
3032         */
3033
3034static int ami_update_par(void)
3035{
3036        struct amifb_par *par = &currentpar;
3037        short clk_shift, vshift, fstrt, fsize, fstop, fconst,  shift, move, mod;
3038
3039        clk_shift = par->clk_shift;
3040
3041        if (!(par->vmode & FB_VMODE_SMOOTH_XPAN))
3042                par->xoffset = upx(16<<maxfmode, par->xoffset);
3043
3044        fconst = 16<<maxfmode<<clk_shift;
3045        vshift = modx(16<<maxfmode, par->xoffset);
3046        fstrt = par->diwstrt_h - (vshift<<clk_shift) - 4;
3047        fsize = (par->xres+vshift)<<clk_shift;
3048        shift = modx(fconst, fstrt);
3049        move = downx(2<<maxfmode, div8(par->xoffset));
3050        if (maxfmode + clk_shift > 1) {
3051                fstrt = downx(fconst, fstrt) - 64;
3052                fsize = upx(fconst, fsize);
3053                fstop = fstrt + fsize - fconst;
3054        } else {
3055                mod = fstrt = downx(fconst, fstrt) - fconst;
3056                fstop = fstrt + upx(fconst, fsize) - 64;
3057                fsize = up64(fsize);
3058                fstrt = fstop - fsize + 64;
3059                if (fstrt < min_fstrt) {
3060                        fstop += min_fstrt - fstrt;
3061                        fstrt = min_fstrt;
3062                }
3063                move = move - div8((mod-fstrt)>>clk_shift);
3064        }
3065        mod = par->next_line - div8(fsize>>clk_shift);
3066        par->ddfstrt = fstrt;
3067        par->ddfstop = fstop;
3068        par->bplcon1 = hscroll2hw(shift);
3069        par->bpl2mod = mod;
3070        if (par->bplcon0 & BPC0_LACE)
3071                par->bpl2mod += par->next_line;
3072        if (IS_AGA && (par->fmode & FMODE_BSCAN2))
3073                par->bpl1mod = -div8(fsize>>clk_shift);
3074        else
3075                par->bpl1mod = par->bpl2mod;
3076
3077        if (par->yoffset) {
3078                par->bplpt0 = fb_info.fix.smem_start + par->next_line*par->yoffset + move;
3079                if (par->vmode & FB_VMODE_YWRAP) {
3080                        if (par->yoffset > par->vyres-par->yres) {
3081                                par->bplpt0wrap = fb_info.fix.smem_start + move;
3082                                if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset))
3083                                        par->bplpt0wrap += par->next_line;
3084                        }
3085                }
3086        } else
3087                par->bplpt0 = fb_info.fix.smem_start + move;
3088
3089        if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
3090                par->bplpt0 += par->next_line;
3091
3092        return 0;
3093}
3094
3095
3096        /*
3097         * Set a single color register. The values supplied are already
3098         * rounded down to the hardware's capabilities (according to the
3099         * entries in the var structure). Return != 0 for invalid regno.
3100         */
3101
3102static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
3103                           u_int transp, struct fb_info *info)
3104{
3105        if (IS_AGA) {
3106                if (regno > 255)
3107                        return 1;
3108        } else if (currentpar.bplcon0 & BPC0_SHRES) {
3109                if (regno > 3)
3110                        return 1;
3111        } else {
3112                if (regno > 31)
3113                        return 1;
3114        }
3115        red >>= 8;
3116        green >>= 8;
3117        blue >>= 8;
3118        if (!regno) {
3119                red0 = red;
3120                green0 = green;
3121                blue0 = blue;
3122        }
3123
3124        /*
3125         * Update the corresponding Hardware Color Register, unless it's Color
3126         * Register 0 and the screen is blanked.
3127         *
3128         * VBlank is switched off to protect bplcon3 or ecs_palette[] from
3129         * being changed by ami_do_blank() during the VBlank.
3130         */
3131
3132        if (regno || !is_blanked) {
3133#if defined(CONFIG_FB_AMIGA_AGA)
3134                if (IS_AGA) {
3135                        u_short bplcon3 = currentpar.bplcon3;
3136                        VBlankOff();
3137                        custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000);
3138                        custom.color[regno&31] = rgb2hw8_high(red, green, blue);
3139                        custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT;
3140                        custom.color[regno&31] = rgb2hw8_low(red, green, blue);
3141                        custom.bplcon3 = bplcon3;
3142                        VBlankOn();
3143                } else
3144#endif
3145#if defined(CONFIG_FB_AMIGA_ECS)
3146                if (currentpar.bplcon0 & BPC0_SHRES) {
3147                        u_short color, mask;
3148                        int i;
3149
3150                        mask = 0x3333;
3151                        color = rgb2hw2(red, green, blue);
3152                        VBlankOff();
3153                        for (i = regno+12; i >= (int)regno; i -= 4)
3154                                custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3155                        mask <<=2; color >>= 2;
3156                        regno = down16(regno)+mul4(mod4(regno));
3157                        for (i = regno+3; i >= (int)regno; i--)
3158                                custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3159                        VBlankOn();
3160                } else
3161#endif
3162                        custom.color[regno] = rgb2hw4(red, green, blue);
3163        }
3164        return 0;
3165}
3166
3167static void ami_update_display(void)
3168{
3169        struct amifb_par *par = &currentpar;
3170
3171        custom.bplcon1 = par->bplcon1;
3172        custom.bpl1mod = par->bpl1mod;
3173        custom.bpl2mod = par->bpl2mod;
3174        custom.ddfstrt = ddfstrt2hw(par->ddfstrt);
3175        custom.ddfstop = ddfstop2hw(par->ddfstop);
3176}
3177
3178        /*
3179         * Change the video mode (called by VBlank interrupt)
3180         */
3181
3182static void ami_init_display(void)
3183{
3184        struct amifb_par *par = &currentpar;
3185        int i;
3186
3187        custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
3188        custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
3189        if (!IS_OCS) {
3190                custom.bplcon3 = par->bplcon3;
3191                if (IS_AGA)
3192                        custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
3193                if (par->beamcon0 & BMC0_VARBEAMEN) {
3194                        custom.htotal = htotal2hw(par->htotal);
3195                        custom.hbstrt = hbstrt2hw(par->hbstrt);
3196                        custom.hbstop = hbstop2hw(par->hbstop);
3197                        custom.hsstrt = hsstrt2hw(par->hsstrt);
3198                        custom.hsstop = hsstop2hw(par->hsstop);
3199                        custom.hcenter = hcenter2hw(par->hcenter);
3200                        custom.vtotal = vtotal2hw(par->vtotal);
3201                        custom.vbstrt = vbstrt2hw(par->vbstrt);
3202                        custom.vbstop = vbstop2hw(par->vbstop);
3203                        custom.vsstrt = vsstrt2hw(par->vsstrt);
3204                        custom.vsstop = vsstop2hw(par->vsstop);
3205                }
3206        }
3207        if (!IS_OCS || par->hsstop)
3208                custom.beamcon0 = par->beamcon0;
3209        if (IS_AGA)
3210                custom.fmode = par->fmode;
3211
3212        /*
3213         * The minimum period for audio depends on htotal
3214         */
3215
3216        amiga_audio_min_period = div16(par->htotal);
3217
3218        is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
3219#if 1
3220        if (is_lace) {
3221                i = custom.vposr >> 15;
3222        } else {
3223                custom.vposw = custom.vposr | 0x8000;
3224                i = 1;
3225        }
3226#else
3227        i = 1;
3228        custom.vposw = custom.vposr | 0x8000;
3229#endif
3230        custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]);
3231}
3232
3233        /*
3234         * (Un)Blank the screen (called by VBlank interrupt)
3235         */
3236
3237static void ami_do_blank(void)
3238{
3239        struct amifb_par *par = &currentpar;
3240#if defined(CONFIG_FB_AMIGA_AGA)
3241        u_short bplcon3 = par->bplcon3;
3242#endif
3243        u_char red, green, blue;
3244
3245        if (do_blank > 0) {
3246                custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
3247                red = green = blue = 0;
3248                if (!IS_OCS && do_blank > 1) {
3249                        switch (do_blank) {
3250                                case FB_BLANK_VSYNC_SUSPEND:
3251                                        custom.hsstrt = hsstrt2hw(par->hsstrt);
3252                                        custom.hsstop = hsstop2hw(par->hsstop);
3253                                        custom.vsstrt = vsstrt2hw(par->vtotal+4);
3254                                        custom.vsstop = vsstop2hw(par->vtotal+4);
3255                                        break;
3256                                case FB_BLANK_HSYNC_SUSPEND:
3257                                        custom.hsstrt = hsstrt2hw(par->htotal+16);
3258                                        custom.hsstop = hsstop2hw(par->htotal+16);
3259                                        custom.vsstrt = vsstrt2hw(par->vsstrt);
3260                                        custom.vsstop = vsstrt2hw(par->vsstop);
3261                                        break;
3262                                case FB_BLANK_POWERDOWN:
3263                                        custom.hsstrt = hsstrt2hw(par->htotal+16);
3264                                        custom.hsstop = hsstop2hw(par->htotal+16);
3265                                        custom.vsstrt = vsstrt2hw(par->vtotal+4);
3266                                        custom.vsstop = vsstop2hw(par->vtotal+4);
3267                                        break;
3268                        }
3269                        if (!(par->beamcon0 & BMC0_VARBEAMEN)) {
3270                                custom.htotal = htotal2hw(par->htotal);
3271                                custom.vtotal = vtotal2hw(par->vtotal);
3272                                custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN |
3273                                                  BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN;
3274                        }
3275                }
3276        } else {
3277                custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
3278                red = red0;
3279                green = green0;
3280                blue = blue0;
3281                if (!IS_OCS) {
3282                        custom.hsstrt = hsstrt2hw(par->hsstrt);
3283                        custom.hsstop = hsstop2hw(par->hsstop);
3284                        custom.vsstrt = vsstrt2hw(par->vsstrt);
3285                        custom.vsstop = vsstop2hw(par->vsstop);
3286                        custom.beamcon0 = par->beamcon0;
3287                }
3288        }
3289#if defined(CONFIG_FB_AMIGA_AGA)
3290        if (IS_AGA) {
3291                custom.bplcon3 = bplcon3;
3292                custom.color[0] = rgb2hw8_high(red, green, blue);
3293                custom.bplcon3 = bplcon3 | BPC3_LOCT;
3294                custom.color[0] = rgb2hw8_low(red, green, blue);
3295                custom.bplcon3 = bplcon3;
3296        } else
3297#endif
3298#if defined(CONFIG_FB_AMIGA_ECS)
3299        if (par->bplcon0 & BPC0_SHRES) {
3300                u_short color, mask;
3301                int i;
3302
3303                mask = 0x3333;
3304                color = rgb2hw2(red, green, blue);
3305                for (i = 12; i >= 0; i -= 4)
3306                        custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3307                mask <<=2; color >>= 2;
3308                for (i = 3; i >= 0; i--)
3309                        custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3310        } else
3311#endif
3312                custom.color[0] = rgb2hw4(red, green, blue);
3313        is_blanked = do_blank > 0 ? do_blank : 0;
3314}
3315
3316static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix)
3317{
3318        struct amifb_par *par = &currentpar;
3319
3320        fix->crsr_width = fix->crsr_xsize = par->crsr.width;
3321        fix->crsr_height = fix->crsr_ysize = par->crsr.height;
3322        fix->crsr_color1 = 17;
3323        fix->crsr_color2 = 18;
3324        return 0;
3325}
3326
3327static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data)
3328{
3329        struct amifb_par *par = &currentpar;
3330        register u_short *lspr, *sspr;
3331#ifdef __mc68000__
3332        register u_long datawords asm ("d2");
3333#else
3334        register u_long datawords;
3335#endif
3336        register short delta;
3337        register u_char color;
3338        short height, width, bits, words;
3339        int size, alloc;
3340
3341        size = par->crsr.height*par->crsr.width;
3342        alloc = var->height*var->width;
3343        var->height = par->crsr.height;
3344        var->width = par->crsr.width;
3345        var->xspot = par->crsr.spot_x;
3346        var->yspot = par->crsr.spot_y;
3347        if (size > var->height*var->width)
3348                return -ENAMETOOLONG;
3349        if (!access_ok(VERIFY_WRITE, data, size))
3350                return -EFAULT;
3351        delta = 1<<par->crsr.fmode;
3352        lspr = lofsprite + (delta<<1);
3353        if (par->bplcon0 & BPC0_LACE)
3354                sspr = shfsprite + (delta<<1);
3355        else
3356                sspr = NULL;
3357        for (height = (short)var->height-1; height >= 0; height--) {
3358                bits = 0; words = delta; datawords = 0;
3359                for (width = (short)var->width-1; width >= 0; width--) {
3360                        if (bits == 0) {
3361                                bits = 16; --words;
3362#ifdef __mc68000__
3363                                asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0"
3364                                        : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta));
3365#else
3366                                datawords = (*(lspr+delta) << 16) | (*lspr++);
3367#endif
3368                        }
3369                        --bits;
3370#ifdef __mc68000__
3371                        asm volatile (
3372                                "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; "
3373                                "swap %1 ; lslw #1,%1 ; roxlb #1,%0"
3374                                : "=d" (color), "=d" (datawords) : "1" (datawords));
3375#else
3376                        color = (((datawords >> 30) & 2)
3377                                 | ((datawords >> 15) & 1));
3378                        datawords <<= 1;
3379#endif
3380                        put_user(color, data++);
3381                }
3382                if (bits > 0) {
3383                        --words; ++lspr;
3384                }
3385                while (--words >= 0)
3386                        ++lspr;
3387#ifdef __mc68000__
3388                asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
3389                        : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
3390#else
3391                lspr += delta;
3392                if (sspr) {
3393                        u_short *tmp = lspr;
3394                        lspr = sspr;
3395                        sspr = tmp;
3396                }
3397#endif
3398        }
3399        return 0;
3400}
3401
3402static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data)
3403{
3404        struct amifb_par *par = &currentpar;
3405        register u_short *lspr, *sspr;
3406#ifdef __mc68000__
3407        register u_long datawords asm ("d2");
3408#else
3409        register u_long datawords;
3410#endif
3411        register short delta;
3412        u_short fmode;
3413        short height, width, bits, words;
3414
3415        if (!var->width)
3416                return -EINVAL;
3417        else if (var->width <= 16)
3418                fmode = TAG_FMODE_1;
3419        else if (var->width <= 32)
3420                fmode = TAG_FMODE_2;
3421        else if (var->width <= 64)
3422                fmode = TAG_FMODE_4;
3423        else
3424                return -EINVAL;
3425        if (fmode > maxfmode)
3426                return -EINVAL;
3427        if (!var->height)
3428                return -EINVAL;
3429        if (!access_ok(VERIFY_READ, data, var->width*var->height))
3430                return -EFAULT;
3431        delta = 1<<fmode;
3432        lofsprite = shfsprite = (u_short *)spritememory;
3433        lspr = lofsprite + (delta<<1);
3434        if (par->bplcon0 & BPC0_LACE) {
3435                if (((var->height+4)<<fmode<<2) > SPRITEMEMSIZE)
3436                        return -EINVAL;
3437                memset(lspr, 0, (var->height+4)<<fmode<<2);
3438                shfsprite += ((var->height+5)&-2)<<fmode;
3439                sspr = shfsprite + (delta<<1);
3440        } else {
3441                if (((var->height+2)<<fmode<<2) > SPRITEMEMSIZE)
3442                        return -EINVAL;
3443                memset(lspr, 0, (var->height+2)<<fmode<<2);
3444                sspr = NULL;
3445        }
3446        for (height = (short)var->height-1; height >= 0; height--) {
3447                bits = 16; words = delta; datawords = 0;
3448                for (width = (short)var->width-1; width >= 0; width--) {
3449                        unsigned long tdata = 0;
3450                        get_user(tdata, data);
3451                        data++;
3452#ifdef __mc68000__
3453                        asm volatile (
3454                                "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; "
3455                                "lsrb #1,%2 ; roxlw #1,%0 ; swap %0"
3456                                : "=d" (datawords)
3457                                : "0" (datawords), "d" (tdata));
3458#else
3459                        datawords = ((datawords << 1) & 0xfffefffe);
3460                        datawords |= tdata & 1;
3461                        datawords |= (tdata & 2) << (16-1);
3462#endif
3463                        if (--bits == 0) {
3464                                bits = 16; --words;
3465#ifdef __mc68000__
3466                                asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+"
3467                                        : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta));
3468#else
3469                                *(lspr+delta) = (u_short) (datawords >> 16);
3470                                *lspr++ = (u_short) (datawords & 0xffff);
3471#endif
3472                        }
3473                }
3474                if (bits < 16) {
3475                        --words;
3476#ifdef __mc68000__
3477                        asm volatile (
3478                                "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; "
3479                                "swap %2 ; lslw %4,%2 ; movew %2,%0@+"
3480                                : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits));
3481#else
3482                        *(lspr+delta) = (u_short) (datawords >> (16+bits));
3483                        *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits);
3484#endif
3485                }
3486                while (--words >= 0) {
3487#ifdef __mc68000__
3488                        asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+"
3489                                : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0");
3490#else
3491                        *(lspr+delta) = 0;
3492                        *lspr++ = 0;
3493#endif
3494                }
3495#ifdef __mc68000__
3496                asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
3497                        : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
3498#else
3499                lspr += delta;
3500                if (sspr) {
3501                        u_short *tmp = lspr;
3502                        lspr = sspr;
3503                        sspr = tmp;
3504                }
3505#endif
3506        }
3507        par->crsr.height = var->height;
3508        par->crsr.width = var->width;
3509        par->crsr.spot_x = var->xspot;
3510        par->crsr.spot_y = var->yspot;
3511        par->crsr.fmode = fmode;
3512        if (IS_AGA) {
3513                par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32);
3514                par->fmode |= sprfetchmode[fmode];
3515                custom.fmode = par->fmode;
3516        }
3517        return 0;
3518}
3519
3520static int ami_get_cursorstate(struct fb_cursorstate *state)
3521{
3522        struct amifb_par *par = &currentpar;
3523
3524        state->xoffset = par->crsr.crsr_x;
3525        state->yoffset = par->crsr.crsr_y;
3526        state->mode = cursormode;
3527        return 0;
3528}
3529
3530static int ami_set_cursorstate(struct fb_cursorstate *state)
3531{
3532        struct amifb_par *par = &currentpar;
3533
3534        par->crsr.crsr_x = state->xoffset;
3535        par->crsr.crsr_y = state->yoffset;
3536        if ((cursormode = state->mode) == FB_CURSOR_OFF)
3537                cursorstate = -1;
3538        do_cursor = 1;
3539        return 0;
3540}
3541
3542static void ami_set_sprite(void)
3543{
3544        struct amifb_par *par = &currentpar;
3545        copins *copl, *cops;
3546        u_short hs, vs, ve;
3547        u_long pl, ps, pt;
3548        short mx, my;
3549
3550        cops = copdisplay.list[currentcop][0];
3551        copl = copdisplay.list[currentcop][1];
3552        ps = pl = ZTWO_PADDR(dummysprite);
3553        mx = par->crsr.crsr_x-par->crsr.spot_x;
3554        my = par->crsr.crsr_y-par->crsr.spot_y;
3555        if (!(par->vmode & FB_VMODE_YWRAP)) {
3556                mx -= par->xoffset;
3557                my -= par->yoffset;
3558        }
3559        if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 &&
3560            mx > -(short)par->crsr.width && mx < par->xres &&
3561            my > -(short)par->crsr.height && my < par->yres) {
3562                pl = ZTWO_PADDR(lofsprite);
3563                hs = par->diwstrt_h + (mx<<par->clk_shift) - 4;
3564                vs = par->diwstrt_v + (my<<par->line_shift);
3565                ve = vs + (par->crsr.height<<par->line_shift);
3566                if (par->bplcon0 & BPC0_LACE) {
3567                        ps = ZTWO_PADDR(shfsprite);
3568                        lofsprite[0] = spr2hw_pos(vs, hs);
3569                        shfsprite[0] = spr2hw_pos(vs+1, hs);
3570                        if (mod2(vs)) {
3571                                lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
3572                                shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1);
3573                                pt = pl; pl = ps; ps = pt;
3574                        } else {
3575                                lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve+1);
3576                                shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve);
3577                        }
3578                } else {
3579                        lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0);
3580                        lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
3581                }
3582        }
3583        copl[cop_spr0ptrh].w[1] = highw(pl);
3584        copl[cop_spr0ptrl].w[1] = loww(pl);
3585        if (par->bplcon0 & BPC0_LACE) {
3586                cops[cop_spr0ptrh].w[1] = highw(ps);
3587                cops[cop_spr0ptrl].w[1] = loww(ps);
3588        }
3589}
3590
3591
3592        /*
3593         * Initialise the Copper Initialisation List
3594         */
3595
3596static void __init ami_init_copper(void)
3597{
3598        copins *cop = copdisplay.init;
3599        u_long p;
3600        int i;
3601
3602        if (!IS_OCS) {
3603                (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
3604                (cop++)->l = CMOVE(0x0181, diwstrt);
3605                (cop++)->l = CMOVE(0x0281, diwstop);
3606                (cop++)->l = CMOVE(0x0000, diwhigh);
3607        } else
3608                (cop++)->l = CMOVE(BPC0_COLOR, bplcon0);
3609        p = ZTWO_PADDR(dummysprite);
3610        for (i = 0; i < 8; i++) {
3611                (cop++)->l = CMOVE(0, spr[i].pos);
3612                (cop++)->l = CMOVE(highw(p), sprpt[i]);
3613                (cop++)->l = CMOVE2(loww(p), sprpt[i]);
3614        }
3615
3616        (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);
3617        copdisplay.wait = cop;
3618        (cop++)->l = CEND;
3619        (cop++)->l = CMOVE(0, copjmp2);
3620        cop->l = CEND;
3621
3622        custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);
3623        custom.copjmp1 = 0;
3624}
3625
3626static void ami_reinit_copper(void)
3627{
3628        struct amifb_par *par = &currentpar;
3629
3630        copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0;
3631        copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4);
3632}
3633
3634        /*
3635         * Build the Copper List
3636         */
3637
3638static void ami_build_copper(void)
3639{
3640        struct amifb_par *par = &currentpar;
3641        copins *copl, *cops;
3642        u_long p;
3643
3644        currentcop = 1 - currentcop;
3645
3646        copl = copdisplay.list[currentcop][1];
3647
3648        (copl++)->l = CWAIT(0, 10);
3649        (copl++)->l = CMOVE(par->bplcon0, bplcon0);
3650        (copl++)->l = CMOVE(0, sprpt[0]);
3651        (copl++)->l = CMOVE2(0, sprpt[0]);
3652
3653        if (par->bplcon0 & BPC0_LACE) {
3654                cops = copdisplay.list[currentcop][0];
3655
3656                (cops++)->l = CWAIT(0, 10);
3657                (cops++)->l = CMOVE(par->bplcon0, bplcon0);
3658                (cops++)->l = CMOVE(0, sprpt[0]);
3659                (cops++)->l = CMOVE2(0, sprpt[0]);
3660
3661                (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt);
3662                (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop);
3663                (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
3664                (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
3665                if (!IS_OCS) {
3666                        (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1,
3667                                            par->diwstop_h, par->diwstop_v+1), diwhigh);
3668                        (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
3669                                            par->diwstop_h, par->diwstop_v), diwhigh);
3670#if 0
3671                        if (par->beamcon0 & BMC0_VARBEAMEN) {
3672                                (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3673                                (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt);
3674                                (copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop);
3675                                (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3676                                (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
3677                                (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
3678                        }
3679#endif
3680                }
3681                p = ZTWO_PADDR(copdisplay.list[currentcop][0]);
3682                (copl++)->l = CMOVE(highw(p), cop2lc);
3683                (copl++)->l = CMOVE2(loww(p), cop2lc);
3684                p = ZTWO_PADDR(copdisplay.list[currentcop][1]);
3685                (cops++)->l = CMOVE(highw(p), cop2lc);
3686                (cops++)->l = CMOVE2(loww(p), cop2lc);
3687                copdisplay.rebuild[0] = cops;
3688        } else {
3689                (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
3690                (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
3691                if (!IS_OCS) {
3692                        (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
3693                                            par->diwstop_h, par->diwstop_v), diwhigh);
3694#if 0
3695                        if (par->beamcon0 & BMC0_VARBEAMEN) {
3696                                (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3697                                (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
3698                                (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
3699                        }
3700#endif
3701                }
3702        }
3703        copdisplay.rebuild[1] = copl;
3704
3705        ami_update_par();
3706        ami_rebuild_copper();
3707}
3708
3709        /*
3710         * Rebuild the Copper List
3711         *
3712         * We only change the things that are not static
3713         */
3714
3715static void ami_rebuild_copper(void)
3716{
3717        struct amifb_par *par = &currentpar;
3718        copins *copl, *cops;
3719        u_short line, h_end1, h_end2;
3720        short i;
3721        u_long p;
3722
3723        if (IS_AGA && maxfmode + par->clk_shift == 0)
3724                h_end1 = par->diwstrt_h-64;
3725        else
3726                h_end1 = par->htotal-32;
3727        h_end2 = par->ddfstop+64;
3728
3729        ami_set_sprite();
3730
3731        copl = copdisplay.rebuild[1];
3732        p = par->bplpt0;
3733        if (par->vmode & FB_VMODE_YWRAP) {
3734                if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) {
3735                        if (par->yoffset > par->vyres-par->yres) {
3736                                for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3737                                        (copl++)->l = CMOVE(highw(p), bplpt[i]);
3738                                        (copl++)->l = CMOVE2(loww(p), bplpt[i]);
3739                                }
3740                                line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 1;
3741                                while (line >= 512) {
3742                                        (copl++)->l = CWAIT(h_end1, 510);
3743                                        line -= 512;
3744                                }
3745                                if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0)
3746                                        (copl++)->l = CWAIT(h_end1, line);
3747                                else
3748                                        (copl++)->l = CWAIT(h_end2, line);
3749                                p = par->bplpt0wrap;
3750                        }
3751                } else p = par->bplpt0wrap;
3752        }
3753        for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3754                (copl++)->l = CMOVE(highw(p), bplpt[i]);
3755                (copl++)->l = CMOVE2(loww(p), bplpt[i]);
3756        }
3757        copl->l = CEND;
3758
3759        if (par->bplcon0 & BPC0_LACE) {
3760                cops = copdisplay.rebuild[0];
3761                p = par->bplpt0;
3762                if (mod2(par->diwstrt_v))
3763                        p -= par->next_line;
3764                else
3765                        p += par->next_line;
3766                if (par->vmode & FB_VMODE_YWRAP) {
3767                        if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) {
3768                                if (par->yoffset > par->vyres-par->yres+1) {
3769                                        for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3770                                                (cops++)->l = CMOVE(highw(p), bplpt[i]);
3771                                                (cops++)->l = CMOVE2(loww(p), bplpt[i]);
3772                                        }
3773                                        line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 2;
3774                                        while (line >= 512) {
3775                                                (cops++)->l = CWAIT(h_end1, 510);
3776                                                line -= 512;
3777                                        }
3778                                        if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0)
3779                                                (cops++)->l = CWAIT(h_end1, line);
3780                                        else
3781                                                (cops++)->l = CWAIT(h_end2, line);
3782                                        p = par->bplpt0wrap;
3783                                        if (mod2(par->diwstrt_v+par->vyres-par->yoffset))
3784                                                p -= par->next_line;
3785                                        else
3786                                                p += par->next_line;
3787                                }
3788                        } else p = par->bplpt0wrap - par->next_line;
3789                }
3790                for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3791                        (cops++)->l = CMOVE(highw(p), bplpt[i]);
3792                        (cops++)->l = CMOVE2(loww(p), bplpt[i]);
3793                }
3794                cops->l = CEND;
3795        }
3796}
3797
3798static void __exit amifb_exit(void)
3799{
3800        unregister_framebuffer(&fb_info);
3801        amifb_deinit();
3802        amifb_video_off();
3803}
3804
3805module_init(amifb_init);
3806module_exit(amifb_exit);
3807
3808MODULE_LICENSE("GPL");
3809