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/delay.h>
  49#include <linux/interrupt.h>
  50#include <linux/fb.h>
  51#include <linux/init.h>
  52#include <linux/ioport.h>
  53#include <linux/platform_device.h>
  54#include <linux/uaccess.h>
  55
  56#include <asm/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(struct platform_device *pdev);
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_probe(struct platform_device *pdev)
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        custom.dmacon = DMAF_ALL | DMAF_MASTER;
2266
2267        switch (amiga_chipset) {
2268#ifdef CONFIG_FB_AMIGA_OCS
2269                case CS_OCS:
2270                        strcat(fb_info.fix.id, "OCS");
2271default_chipset:
2272                        chipset = TAG_OCS;
2273                        maxdepth[TAG_SHRES] = 0;        /* OCS means no SHRES */
2274                        maxdepth[TAG_HIRES] = 4;
2275                        maxdepth[TAG_LORES] = 6;
2276                        maxfmode = TAG_FMODE_1;
2277                        defmode = amiga_vblank == 50 ? DEFMODE_PAL
2278                                                     : DEFMODE_NTSC;
2279                        fb_info.fix.smem_len = VIDEOMEMSIZE_OCS;
2280                        break;
2281#endif /* CONFIG_FB_AMIGA_OCS */
2282
2283#ifdef CONFIG_FB_AMIGA_ECS
2284                case CS_ECS:
2285                        strcat(fb_info.fix.id, "ECS");
2286                        chipset = TAG_ECS;
2287                        maxdepth[TAG_SHRES] = 2;
2288                        maxdepth[TAG_HIRES] = 4;
2289                        maxdepth[TAG_LORES] = 6;
2290                        maxfmode = TAG_FMODE_1;
2291                        if (AMIGAHW_PRESENT(AMBER_FF))
2292                            defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL
2293                                                         : DEFMODE_AMBER_NTSC;
2294                        else
2295                            defmode = amiga_vblank == 50 ? DEFMODE_PAL
2296                                                         : DEFMODE_NTSC;
2297                        if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
2298                            VIDEOMEMSIZE_ECS_1M)
2299                                fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M;
2300                        else
2301                                fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M;
2302                        break;
2303#endif /* CONFIG_FB_AMIGA_ECS */
2304
2305#ifdef CONFIG_FB_AMIGA_AGA
2306                case CS_AGA:
2307                        strcat(fb_info.fix.id, "AGA");
2308                        chipset = TAG_AGA;
2309                        maxdepth[TAG_SHRES] = 8;
2310                        maxdepth[TAG_HIRES] = 8;
2311                        maxdepth[TAG_LORES] = 8;
2312                        maxfmode = TAG_FMODE_4;
2313                        defmode = DEFMODE_AGA;
2314                        if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
2315                            VIDEOMEMSIZE_AGA_1M)
2316                                fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M;
2317                        else
2318                                fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M;
2319                        break;
2320#endif /* CONFIG_FB_AMIGA_AGA */
2321
2322                default:
2323#ifdef CONFIG_FB_AMIGA_OCS
2324                        printk("Unknown graphics chipset, defaulting to OCS\n");
2325                        strcat(fb_info.fix.id, "Unknown");
2326                        goto default_chipset;
2327#else /* CONFIG_FB_AMIGA_OCS */
2328                        err = -ENODEV;
2329                        goto amifb_error;
2330#endif /* CONFIG_FB_AMIGA_OCS */
2331                        break;
2332        }
2333
2334        /*
2335         * Calculate the Pixel Clock Values for this Machine
2336         */
2337
2338        {
2339        u_long tmp = DIVUL(200000000000ULL, amiga_eclock);
2340
2341        pixclock[TAG_SHRES] = (tmp + 4) / 8;    /* SHRES:  35 ns / 28 MHz */
2342        pixclock[TAG_HIRES] = (tmp + 2) / 4;    /* HIRES:  70 ns / 14 MHz */
2343        pixclock[TAG_LORES] = (tmp + 1) / 2;    /* LORES: 140 ns /  7 MHz */
2344        }
2345
2346        /*
2347         * Replace the Tag Values with the Real Pixel Clock Values
2348         */
2349
2350        for (i = 0; i < NUM_TOTAL_MODES; i++) {
2351                struct fb_videomode *mode = &ami_modedb[i];
2352                tag = mode->pixclock;
2353                if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
2354                        mode->pixclock = pixclock[tag];
2355                }
2356        }
2357
2358        /*
2359         *  These monitor specs are for a typical Amiga monitor (e.g. A1960)
2360         */
2361        if (fb_info.monspecs.hfmin == 0) {
2362            fb_info.monspecs.hfmin = 15000;
2363            fb_info.monspecs.hfmax = 38000;
2364            fb_info.monspecs.vfmin = 49;
2365            fb_info.monspecs.vfmax = 90;
2366        }
2367
2368        fb_info.fbops = &amifb_ops;
2369        fb_info.par = &currentpar;
2370        fb_info.flags = FBINFO_DEFAULT;
2371        fb_info.device = &pdev->dev;
2372
2373        if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb,
2374                          NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
2375                err = -EINVAL;
2376                goto amifb_error;
2377        }
2378
2379        fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES,
2380                                 &fb_info.modelist);
2381
2382        round_down_bpp = 0;
2383        chipptr = chipalloc(fb_info.fix.smem_len+
2384                            SPRITEMEMSIZE+
2385                            DUMMYSPRITEMEMSIZE+
2386                            COPINITSIZE+
2387                            4*COPLISTSIZE);
2388
2389        assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len);
2390        assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
2391        assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
2392        assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
2393        assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);
2394        assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);
2395        assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);
2396        assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);
2397
2398        /*
2399         * access the videomem with writethrough cache
2400         */
2401        fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory);
2402        videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start,
2403                                                   fb_info.fix.smem_len);
2404        if (!videomemory) {
2405                printk("amifb: WARNING! unable to map videomem cached writethrough\n");
2406                fb_info.screen_base = (char *)ZTWO_VADDR(fb_info.fix.smem_start);
2407        } else
2408                fb_info.screen_base = (char *)videomemory;
2409
2410        memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
2411
2412        /*
2413         * Enable Display DMA
2414         */
2415
2416        custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
2417                        DMAF_BLITTER | DMAF_SPRITE;
2418
2419        /*
2420         * Make sure the Copper has something to do
2421         */
2422
2423        ami_init_copper();
2424
2425        if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,
2426                        "fb vertb handler", &currentpar)) {
2427                err = -EBUSY;
2428                goto amifb_error;
2429        }
2430
2431        err = fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0);
2432        if (err)
2433                goto amifb_error;
2434
2435        if (register_framebuffer(&fb_info) < 0) {
2436                err = -EINVAL;
2437                goto amifb_error;
2438        }
2439
2440        printk("fb%d: %s frame buffer device, using %dK of video memory\n",
2441               fb_info.node, fb_info.fix.id, fb_info.fix.smem_len>>10);
2442
2443        return 0;
2444
2445amifb_error:
2446        amifb_deinit(pdev);
2447        return err;
2448}
2449
2450static void amifb_deinit(struct platform_device *pdev)
2451{
2452        if (fb_info.cmap.len)
2453                fb_dealloc_cmap(&fb_info.cmap);
2454        fb_dealloc_cmap(&fb_info.cmap);
2455        chipfree();
2456        if (videomemory)
2457                iounmap((void*)videomemory);
2458        custom.dmacon = DMAF_ALL | DMAF_MASTER;
2459}
2460
2461
2462        /*
2463         * Blank the display.
2464         */
2465
2466static int amifb_blank(int blank, struct fb_info *info)
2467{
2468        do_blank = blank ? blank : -1;
2469
2470        return 0;
2471}
2472
2473        /*
2474         * Flash the cursor (called by VBlank interrupt)
2475         */
2476
2477static int flash_cursor(void)
2478{
2479        static int cursorcount = 1;
2480
2481        if (cursormode == FB_CURSOR_FLASH) {
2482                if (!--cursorcount) {
2483                        cursorstate = -cursorstate;
2484                        cursorcount = cursorrate;
2485                        if (!is_blanked)
2486                                return 1;
2487                }
2488        }
2489        return 0;
2490}
2491
2492        /*
2493         * VBlank Display Interrupt
2494         */
2495
2496static irqreturn_t amifb_interrupt(int irq, void *dev_id)
2497{
2498        if (do_vmode_pan || do_vmode_full)
2499                ami_update_display();
2500
2501        if (do_vmode_full)
2502                ami_init_display();
2503
2504        if (do_vmode_pan) {
2505                flash_cursor();
2506                ami_rebuild_copper();
2507                do_cursor = do_vmode_pan = 0;
2508        } else if (do_cursor) {
2509                flash_cursor();
2510                ami_set_sprite();
2511                do_cursor = 0;
2512        } else {
2513                if (flash_cursor())
2514                        ami_set_sprite();
2515        }
2516
2517        if (do_blank) {
2518                ami_do_blank();
2519                do_blank = 0;
2520        }
2521
2522        if (do_vmode_full) {
2523                ami_reinit_copper();
2524                do_vmode_full = 0;
2525        }
2526        return IRQ_HANDLED;
2527}
2528
2529/* --------------------------- Hardware routines --------------------------- */
2530
2531        /*
2532         * Get the video params out of `var'. If a value doesn't fit, round
2533         * it up, if it's too big, return -EINVAL.
2534         */
2535
2536static int ami_decode_var(struct fb_var_screeninfo *var,
2537                          struct amifb_par *par)
2538{
2539        u_short clk_shift, line_shift;
2540        u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;
2541        u_int htotal, vtotal;
2542
2543        /*
2544         * Find a matching Pixel Clock
2545         */
2546
2547        for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++)
2548                if (var->pixclock <= pixclock[clk_shift])
2549                        break;
2550        if (clk_shift > TAG_LORES) {
2551                DPRINTK("pixclock too high\n");
2552                return -EINVAL;
2553        }
2554        par->clk_shift = clk_shift;
2555
2556        /*
2557         * Check the Geometry Values
2558         */
2559
2560        if ((par->xres = var->xres) < 64)
2561                par->xres = 64;
2562        if ((par->yres = var->yres) < 64)
2563                par->yres = 64;
2564        if ((par->vxres = var->xres_virtual) < par->xres)
2565                par->vxres = par->xres;
2566        if ((par->vyres = var->yres_virtual) < par->yres)
2567                par->vyres = par->yres;
2568
2569        par->bpp = var->bits_per_pixel;
2570        if (!var->nonstd) {
2571                if (par->bpp < 1)
2572                        par->bpp = 1;
2573                if (par->bpp > maxdepth[clk_shift]) {
2574                        if (round_down_bpp && maxdepth[clk_shift])
2575                                par->bpp = maxdepth[clk_shift];
2576                        else {
2577                                DPRINTK("invalid bpp\n");
2578                                return -EINVAL;
2579                        }
2580                }
2581        } else if (var->nonstd == FB_NONSTD_HAM) {
2582                if (par->bpp < 6)
2583                        par->bpp = 6;
2584                if (par->bpp != 6) {
2585                        if (par->bpp < 8)
2586                                par->bpp = 8;
2587                        if (par->bpp != 8 || !IS_AGA) {
2588                                DPRINTK("invalid bpp for ham mode\n");
2589                                return -EINVAL;
2590                        }
2591                }
2592        } else {
2593                DPRINTK("unknown nonstd mode\n");
2594                return -EINVAL;
2595        }
2596
2597        /*
2598         * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
2599         * checks failed and smooth scrolling is not possible
2600         */
2601
2602        par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN;
2603        switch (par->vmode & FB_VMODE_MASK) {
2604                case FB_VMODE_INTERLACED:
2605                        line_shift = 0;
2606                        break;
2607                case FB_VMODE_NONINTERLACED:
2608                        line_shift = 1;
2609                        break;
2610                case FB_VMODE_DOUBLE:
2611                        if (!IS_AGA) {
2612                                DPRINTK("double mode only possible with aga\n");
2613                                return -EINVAL;
2614                        }
2615                        line_shift = 2;
2616                        break;
2617                default:
2618                        DPRINTK("unknown video mode\n");
2619                        return -EINVAL;
2620                        break;
2621        }
2622        par->line_shift = line_shift;
2623
2624        /*
2625         * Vertical and Horizontal Timings
2626         */
2627
2628        xres_n = par->xres<<clk_shift;
2629        yres_n = par->yres<<line_shift;
2630        par->htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<<clk_shift);
2631        par->vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<<line_shift)+1);
2632
2633        if (IS_AGA)
2634                par->bplcon3 = sprpixmode[clk_shift];
2635        else
2636                par->bplcon3 = 0;
2637        if (var->sync & FB_SYNC_BROADCAST) {
2638                par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<<clk_shift);
2639                if (IS_AGA)
2640                        par->diwstop_h += mod4(var->hsync_len);
2641                else
2642                        par->diwstop_h = down4(par->diwstop_h);
2643
2644                par->diwstrt_h = par->diwstop_h - xres_n;
2645                par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<<line_shift);
2646                par->diwstrt_v = par->diwstop_v - yres_n;
2647                if (par->diwstop_h >= par->htotal+8) {
2648                        DPRINTK("invalid diwstop_h\n");
2649                        return -EINVAL;
2650                }
2651                if (par->diwstop_v > par->vtotal) {
2652                        DPRINTK("invalid diwstop_v\n");
2653                        return -EINVAL;
2654                }
2655
2656                if (!IS_OCS) {
2657                        /* Initialize sync with some reasonable values for pwrsave */
2658                        par->hsstrt = 160;
2659                        par->hsstop = 320;
2660                        par->vsstrt = 30;
2661                        par->vsstop = 34;
2662                } else {
2663                        par->hsstrt = 0;
2664                        par->hsstop = 0;
2665                        par->vsstrt = 0;
2666                        par->vsstop = 0;
2667                }
2668                if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) {
2669                        /* PAL video mode */
2670                        if (par->htotal != PAL_HTOTAL) {
2671                                DPRINTK("htotal invalid for pal\n");
2672                                return -EINVAL;
2673                        }
2674                        if (par->diwstrt_h < PAL_DIWSTRT_H) {
2675                                DPRINTK("diwstrt_h too low for pal\n");
2676                                return -EINVAL;
2677                        }
2678                        if (par->diwstrt_v < PAL_DIWSTRT_V) {
2679                                DPRINTK("diwstrt_v too low for pal\n");
2680                                return -EINVAL;
2681                        }
2682                        htotal = PAL_HTOTAL>>clk_shift;
2683                        vtotal = PAL_VTOTAL>>1;
2684                        if (!IS_OCS) {
2685                                par->beamcon0 = BMC0_PAL;
2686                                par->bplcon3 |= BPC3_BRDRBLNK;
2687                        } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
2688                                   AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
2689                                par->beamcon0 = BMC0_PAL;
2690                                par->hsstop = 1;
2691                        } else if (amiga_vblank != 50) {
2692                                DPRINTK("pal not supported by this chipset\n");
2693                                return -EINVAL;
2694                        }
2695                } else {
2696                        /* NTSC video mode
2697                         * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK
2698                         * and NTSC activated, so than better let diwstop_h <= 1812
2699                         */
2700                        if (par->htotal != NTSC_HTOTAL) {
2701                                DPRINTK("htotal invalid for ntsc\n");
2702                                return -EINVAL;
2703                        }
2704                        if (par->diwstrt_h < NTSC_DIWSTRT_H) {
2705                                DPRINTK("diwstrt_h too low for ntsc\n");
2706                                return -EINVAL;
2707                        }
2708                        if (par->diwstrt_v < NTSC_DIWSTRT_V) {
2709                                DPRINTK("diwstrt_v too low for ntsc\n");
2710                                return -EINVAL;
2711                        }
2712                        htotal = NTSC_HTOTAL>>clk_shift;
2713                        vtotal = NTSC_VTOTAL>>1;
2714                        if (!IS_OCS) {
2715                                par->beamcon0 = 0;
2716                                par->bplcon3 |= BPC3_BRDRBLNK;
2717                        } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
2718                                   AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
2719                                par->beamcon0 = 0;
2720                                par->hsstop = 1;
2721                        } else if (amiga_vblank != 60) {
2722                                DPRINTK("ntsc not supported by this chipset\n");
2723                                return -EINVAL;
2724                        }
2725                }
2726                if (IS_OCS) {
2727                        if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 ||
2728                            par->diwstrt_v >=  512 || par->diwstop_v <  256) {
2729                                DPRINTK("invalid position for display on ocs\n");
2730                                return -EINVAL;
2731                        }
2732                }
2733        } else if (!IS_OCS) {
2734                /* Programmable video mode */
2735                par->hsstrt = var->right_margin<<clk_shift;
2736                par->hsstop = (var->right_margin+var->hsync_len)<<clk_shift;
2737                par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift);
2738                if (!IS_AGA)
2739                        par->diwstop_h = down4(par->diwstop_h) - 16;
2740                par->diwstrt_h = par->diwstop_h - xres_n;
2741                par->hbstop = par->diwstrt_h + 4;
2742                par->hbstrt = par->diwstop_h + 4;
2743                if (par->hbstrt >= par->htotal + 8)
2744                        par->hbstrt -= par->htotal;
2745                par->hcenter = par->hsstrt + (par->htotal >> 1);
2746                par->vsstrt = var->lower_margin<<line_shift;
2747                par->vsstop = (var->lower_margin+var->vsync_len)<<line_shift;
2748                par->diwstop_v = par->vtotal;
2749                if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
2750                        par->diwstop_v -= 2;
2751                par->diwstrt_v = par->diwstop_v - yres_n;
2752                par->vbstop = par->diwstrt_v - 2;
2753                par->vbstrt = par->diwstop_v - 2;
2754                if (par->vtotal > 2048) {
2755                        DPRINTK("vtotal too high\n");
2756                        return -EINVAL;
2757                }
2758                if (par->htotal > 2048) {
2759                        DPRINTK("htotal too high\n");
2760                        return -EINVAL;
2761                }
2762                par->bplcon3 |= BPC3_EXTBLKEN;
2763                par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
2764                                BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
2765                                BMC0_PAL | BMC0_VARCSYEN;
2766                if (var->sync & FB_SYNC_HOR_HIGH_ACT)
2767                        par->beamcon0 |= BMC0_HSYTRUE;
2768                if (var->sync & FB_SYNC_VERT_HIGH_ACT)
2769                        par->beamcon0 |= BMC0_VSYTRUE;
2770                if (var->sync & FB_SYNC_COMP_HIGH_ACT)
2771                        par->beamcon0 |= BMC0_CSYTRUE;
2772                htotal = par->htotal>>clk_shift;
2773                vtotal = par->vtotal>>1;
2774        } else {
2775                DPRINTK("only broadcast modes possible for ocs\n");
2776                return -EINVAL;
2777        }
2778
2779        /*
2780         * Checking the DMA timing
2781         */
2782
2783        fconst = 16<<maxfmode<<clk_shift;
2784
2785        /*
2786         * smallest window start value without turn off other dma cycles
2787         * than sprite1-7, unless you change min_fstrt
2788         */
2789
2790
2791        fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64);
2792        fstrt = downx(fconst, par->diwstrt_h-4) - fsize;
2793        if (fstrt < min_fstrt) {
2794                DPRINTK("fetch start too low\n");
2795                return -EINVAL;
2796        }
2797
2798        /*
2799         * smallest window start value where smooth scrolling is possible
2800         */
2801
2802        fstrt = downx(fconst, par->diwstrt_h-fconst+(1<<clk_shift)-4) - fsize;
2803        if (fstrt < min_fstrt)
2804                par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2805
2806        maxfetchstop = down16(par->htotal - 80);
2807
2808        fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst;
2809        fsize = upx(fconst, xres_n + modx(fconst, downx(1<<clk_shift, par->diwstrt_h-4)));
2810        if (fstrt + fsize > maxfetchstop)
2811                par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2812
2813        fsize = upx(fconst, xres_n);
2814        if (fstrt + fsize > maxfetchstop) {
2815                DPRINTK("fetch stop too high\n");
2816                return -EINVAL;
2817        }
2818
2819        if (maxfmode + clk_shift <= 1) {
2820                fsize = up64(xres_n + fconst - 1);
2821                if (min_fstrt + fsize - 64 > maxfetchstop)
2822                        par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2823
2824                fsize = up64(xres_n);
2825                if (min_fstrt + fsize - 64 > maxfetchstop) {
2826                        DPRINTK("fetch size too high\n");
2827                        return -EINVAL;
2828                }
2829
2830                fsize -= 64;
2831        } else
2832                fsize -= fconst;
2833
2834        /*
2835         * Check if there is enough time to update the bitplane pointers for ywrap
2836         */
2837
2838        if (par->htotal-fsize-64 < par->bpp*64)
2839                par->vmode &= ~FB_VMODE_YWRAP;
2840
2841        /*
2842         * Bitplane calculations and check the Memory Requirements
2843         */
2844
2845        if (amifb_ilbm) {
2846                par->next_plane = div8(upx(16<<maxfmode, par->vxres));
2847                par->next_line = par->bpp*par->next_plane;
2848                if (par->next_line * par->vyres > fb_info.fix.smem_len) {
2849                        DPRINTK("too few video mem\n");
2850                        return -EINVAL;
2851                }
2852        } else {
2853                par->next_line = div8(upx(16<<maxfmode, par->vxres));
2854                par->next_plane = par->vyres*par->next_line;
2855                if (par->next_plane * par->bpp > fb_info.fix.smem_len) {
2856                        DPRINTK("too few video mem\n");
2857                        return -EINVAL;
2858                }
2859        }
2860
2861        /*
2862         * Hardware Register Values
2863         */
2864
2865        par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift];
2866        if (!IS_OCS)
2867                par->bplcon0 |= BPC0_ECSENA;
2868        if (par->bpp == 8)
2869                par->bplcon0 |= BPC0_BPU3;
2870        else
2871                par->bplcon0 |= par->bpp<<12;
2872        if (var->nonstd == FB_NONSTD_HAM)
2873                par->bplcon0 |= BPC0_HAM;
2874        if (var->sync & FB_SYNC_EXT)
2875                par->bplcon0 |= BPC0_ERSY;
2876
2877        if (IS_AGA)
2878                par->fmode = bplfetchmode[maxfmode];
2879
2880        switch (par->vmode & FB_VMODE_MASK) {
2881                case FB_VMODE_INTERLACED:
2882                        par->bplcon0 |= BPC0_LACE;
2883                        break;
2884                case FB_VMODE_DOUBLE:
2885                        if (IS_AGA)
2886                                par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
2887                        break;
2888        }
2889
2890        if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {
2891                par->xoffset = var->xoffset;
2892                par->yoffset = var->yoffset;
2893                if (par->vmode & FB_VMODE_YWRAP) {
2894                        if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres)
2895                                par->xoffset = par->yoffset = 0;
2896                } else {
2897                        if (par->xoffset < 0 || par->xoffset > upx(16<<maxfmode, par->vxres-par->xres) ||
2898                            par->yoffset < 0 || par->yoffset > par->vyres-par->yres)
2899                                par->xoffset = par->yoffset = 0;
2900                }
2901        } else
2902                par->xoffset = par->yoffset = 0;
2903
2904        par->crsr.crsr_x = par->crsr.crsr_y = 0;
2905        par->crsr.spot_x = par->crsr.spot_y = 0;
2906        par->crsr.height = par->crsr.width = 0;
2907
2908        return 0;
2909}
2910
2911        /*
2912         * Fill the `var' structure based on the values in `par' and maybe
2913         * other values read out of the hardware.
2914         */
2915
2916static int ami_encode_var(struct fb_var_screeninfo *var,
2917                          struct amifb_par *par)
2918{
2919        u_short clk_shift, line_shift;
2920
2921        memset(var, 0, sizeof(struct fb_var_screeninfo));
2922
2923        clk_shift = par->clk_shift;
2924        line_shift = par->line_shift;
2925
2926        var->xres = par->xres;
2927        var->yres = par->yres;
2928        var->xres_virtual = par->vxres;
2929        var->yres_virtual = par->vyres;
2930        var->xoffset = par->xoffset;
2931        var->yoffset = par->yoffset;
2932
2933        var->bits_per_pixel = par->bpp;
2934        var->grayscale = 0;
2935
2936        var->red.offset = 0;
2937        var->red.msb_right = 0;
2938        var->red.length = par->bpp;
2939        if (par->bplcon0 & BPC0_HAM)
2940            var->red.length -= 2;
2941        var->blue = var->green = var->red;
2942        var->transp.offset = 0;
2943        var->transp.length = 0;
2944        var->transp.msb_right = 0;
2945
2946        if (par->bplcon0 & BPC0_HAM)
2947                var->nonstd = FB_NONSTD_HAM;
2948        else
2949                var->nonstd = 0;
2950        var->activate = 0;
2951
2952        var->height = -1;
2953        var->width = -1;
2954
2955        var->pixclock = pixclock[clk_shift];
2956
2957        if (IS_AGA && par->fmode & FMODE_BSCAN2)
2958                var->vmode = FB_VMODE_DOUBLE;
2959        else if (par->bplcon0 & BPC0_LACE)
2960                var->vmode = FB_VMODE_INTERLACED;
2961        else
2962                var->vmode = FB_VMODE_NONINTERLACED;
2963
2964        if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) {
2965                var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift;
2966                var->right_margin = par->hsstrt>>clk_shift;
2967                var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
2968                var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift;
2969                var->lower_margin = par->vsstrt>>line_shift;
2970                var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len;
2971                var->sync = 0;
2972                if (par->beamcon0 & BMC0_HSYTRUE)
2973                        var->sync |= FB_SYNC_HOR_HIGH_ACT;
2974                if (par->beamcon0 & BMC0_VSYTRUE)
2975                        var->sync |= FB_SYNC_VERT_HIGH_ACT;
2976                if (par->beamcon0 & BMC0_CSYTRUE)
2977                        var->sync |= FB_SYNC_COMP_HIGH_ACT;
2978        } else {
2979                var->sync = FB_SYNC_BROADCAST;
2980                var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h);
2981                var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len;
2982                var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
2983                var->vsync_len = 4>>line_shift;
2984                var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len;
2985                var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres -
2986                                    var->lower_margin - var->vsync_len;
2987        }
2988
2989        if (par->bplcon0 & BPC0_ERSY)
2990                var->sync |= FB_SYNC_EXT;
2991        if (par->vmode & FB_VMODE_YWRAP)
2992                var->vmode |= FB_VMODE_YWRAP;
2993
2994        return 0;
2995}
2996
2997
2998        /*
2999         * Pan or Wrap the Display
3000         *
3001         * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
3002         * in `var'.
3003         */
3004
3005static void ami_pan_var(struct fb_var_screeninfo *var)
3006{
3007        struct amifb_par *par = &currentpar;
3008
3009        par->xoffset = var->xoffset;
3010        par->yoffset = var->yoffset;
3011        if (var->vmode & FB_VMODE_YWRAP)
3012                par->vmode |= FB_VMODE_YWRAP;
3013        else
3014                par->vmode &= ~FB_VMODE_YWRAP;
3015
3016        do_vmode_pan = 0;
3017        ami_update_par();
3018        do_vmode_pan = 1;
3019}
3020
3021        /*
3022         * Update hardware
3023         */
3024
3025static int ami_update_par(void)
3026{
3027        struct amifb_par *par = &currentpar;
3028        short clk_shift, vshift, fstrt, fsize, fstop, fconst,  shift, move, mod;
3029
3030        clk_shift = par->clk_shift;
3031
3032        if (!(par->vmode & FB_VMODE_SMOOTH_XPAN))
3033                par->xoffset = upx(16<<maxfmode, par->xoffset);
3034
3035        fconst = 16<<maxfmode<<clk_shift;
3036        vshift = modx(16<<maxfmode, par->xoffset);
3037        fstrt = par->diwstrt_h - (vshift<<clk_shift) - 4;
3038        fsize = (par->xres+vshift)<<clk_shift;
3039        shift = modx(fconst, fstrt);
3040        move = downx(2<<maxfmode, div8(par->xoffset));
3041        if (maxfmode + clk_shift > 1) {
3042                fstrt = downx(fconst, fstrt) - 64;
3043                fsize = upx(fconst, fsize);
3044                fstop = fstrt + fsize - fconst;
3045        } else {
3046                mod = fstrt = downx(fconst, fstrt) - fconst;
3047                fstop = fstrt + upx(fconst, fsize) - 64;
3048                fsize = up64(fsize);
3049                fstrt = fstop - fsize + 64;
3050                if (fstrt < min_fstrt) {
3051                        fstop += min_fstrt - fstrt;
3052                        fstrt = min_fstrt;
3053                }
3054                move = move - div8((mod-fstrt)>>clk_shift);
3055        }
3056        mod = par->next_line - div8(fsize>>clk_shift);
3057        par->ddfstrt = fstrt;
3058        par->ddfstop = fstop;
3059        par->bplcon1 = hscroll2hw(shift);
3060        par->bpl2mod = mod;
3061        if (par->bplcon0 & BPC0_LACE)
3062                par->bpl2mod += par->next_line;
3063        if (IS_AGA && (par->fmode & FMODE_BSCAN2))
3064                par->bpl1mod = -div8(fsize>>clk_shift);
3065        else
3066                par->bpl1mod = par->bpl2mod;
3067
3068        if (par->yoffset) {
3069                par->bplpt0 = fb_info.fix.smem_start + par->next_line*par->yoffset + move;
3070                if (par->vmode & FB_VMODE_YWRAP) {
3071                        if (par->yoffset > par->vyres-par->yres) {
3072                                par->bplpt0wrap = fb_info.fix.smem_start + move;
3073                                if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset))
3074                                        par->bplpt0wrap += par->next_line;
3075                        }
3076                }
3077        } else
3078                par->bplpt0 = fb_info.fix.smem_start + move;
3079
3080        if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
3081                par->bplpt0 += par->next_line;
3082
3083        return 0;
3084}
3085
3086
3087        /*
3088         * Set a single color register. The values supplied are already
3089         * rounded down to the hardware's capabilities (according to the
3090         * entries in the var structure). Return != 0 for invalid regno.
3091         */
3092
3093static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
3094                           u_int transp, struct fb_info *info)
3095{
3096        if (IS_AGA) {
3097                if (regno > 255)
3098                        return 1;
3099        } else if (currentpar.bplcon0 & BPC0_SHRES) {
3100                if (regno > 3)
3101                        return 1;
3102        } else {
3103                if (regno > 31)
3104                        return 1;
3105        }
3106        red >>= 8;
3107        green >>= 8;
3108        blue >>= 8;
3109        if (!regno) {
3110                red0 = red;
3111                green0 = green;
3112                blue0 = blue;
3113        }
3114
3115        /*
3116         * Update the corresponding Hardware Color Register, unless it's Color
3117         * Register 0 and the screen is blanked.
3118         *
3119         * VBlank is switched off to protect bplcon3 or ecs_palette[] from
3120         * being changed by ami_do_blank() during the VBlank.
3121         */
3122
3123        if (regno || !is_blanked) {
3124#if defined(CONFIG_FB_AMIGA_AGA)
3125                if (IS_AGA) {
3126                        u_short bplcon3 = currentpar.bplcon3;
3127                        VBlankOff();
3128                        custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000);
3129                        custom.color[regno&31] = rgb2hw8_high(red, green, blue);
3130                        custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT;
3131                        custom.color[regno&31] = rgb2hw8_low(red, green, blue);
3132                        custom.bplcon3 = bplcon3;
3133                        VBlankOn();
3134                } else
3135#endif
3136#if defined(CONFIG_FB_AMIGA_ECS)
3137                if (currentpar.bplcon0 & BPC0_SHRES) {
3138                        u_short color, mask;
3139                        int i;
3140
3141                        mask = 0x3333;
3142                        color = rgb2hw2(red, green, blue);
3143                        VBlankOff();
3144                        for (i = regno+12; i >= (int)regno; i -= 4)
3145                                custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3146                        mask <<=2; color >>= 2;
3147                        regno = down16(regno)+mul4(mod4(regno));
3148                        for (i = regno+3; i >= (int)regno; i--)
3149                                custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3150                        VBlankOn();
3151                } else
3152#endif
3153                        custom.color[regno] = rgb2hw4(red, green, blue);
3154        }
3155        return 0;
3156}
3157
3158static void ami_update_display(void)
3159{
3160        struct amifb_par *par = &currentpar;
3161
3162        custom.bplcon1 = par->bplcon1;
3163        custom.bpl1mod = par->bpl1mod;
3164        custom.bpl2mod = par->bpl2mod;
3165        custom.ddfstrt = ddfstrt2hw(par->ddfstrt);
3166        custom.ddfstop = ddfstop2hw(par->ddfstop);
3167}
3168
3169        /*
3170         * Change the video mode (called by VBlank interrupt)
3171         */
3172
3173static void ami_init_display(void)
3174{
3175        struct amifb_par *par = &currentpar;
3176        int i;
3177
3178        custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
3179        custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
3180        if (!IS_OCS) {
3181                custom.bplcon3 = par->bplcon3;
3182                if (IS_AGA)
3183                        custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
3184                if (par->beamcon0 & BMC0_VARBEAMEN) {
3185                        custom.htotal = htotal2hw(par->htotal);
3186                        custom.hbstrt = hbstrt2hw(par->hbstrt);
3187                        custom.hbstop = hbstop2hw(par->hbstop);
3188                        custom.hsstrt = hsstrt2hw(par->hsstrt);
3189                        custom.hsstop = hsstop2hw(par->hsstop);
3190                        custom.hcenter = hcenter2hw(par->hcenter);
3191                        custom.vtotal = vtotal2hw(par->vtotal);
3192                        custom.vbstrt = vbstrt2hw(par->vbstrt);
3193                        custom.vbstop = vbstop2hw(par->vbstop);
3194                        custom.vsstrt = vsstrt2hw(par->vsstrt);
3195                        custom.vsstop = vsstop2hw(par->vsstop);
3196                }
3197        }
3198        if (!IS_OCS || par->hsstop)
3199                custom.beamcon0 = par->beamcon0;
3200        if (IS_AGA)
3201                custom.fmode = par->fmode;
3202
3203        /*
3204         * The minimum period for audio depends on htotal
3205         */
3206
3207        amiga_audio_min_period = div16(par->htotal);
3208
3209        is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
3210#if 1
3211        if (is_lace) {
3212                i = custom.vposr >> 15;
3213        } else {
3214                custom.vposw = custom.vposr | 0x8000;
3215                i = 1;
3216        }
3217#else
3218        i = 1;
3219        custom.vposw = custom.vposr | 0x8000;
3220#endif
3221        custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]);
3222}
3223
3224        /*
3225         * (Un)Blank the screen (called by VBlank interrupt)
3226         */
3227
3228static void ami_do_blank(void)
3229{
3230        struct amifb_par *par = &currentpar;
3231#if defined(CONFIG_FB_AMIGA_AGA)
3232        u_short bplcon3 = par->bplcon3;
3233#endif
3234        u_char red, green, blue;
3235
3236        if (do_blank > 0) {
3237                custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
3238                red = green = blue = 0;
3239                if (!IS_OCS && do_blank > 1) {
3240                        switch (do_blank) {
3241                                case FB_BLANK_VSYNC_SUSPEND:
3242                                        custom.hsstrt = hsstrt2hw(par->hsstrt);
3243                                        custom.hsstop = hsstop2hw(par->hsstop);
3244                                        custom.vsstrt = vsstrt2hw(par->vtotal+4);
3245                                        custom.vsstop = vsstop2hw(par->vtotal+4);
3246                                        break;
3247                                case FB_BLANK_HSYNC_SUSPEND:
3248                                        custom.hsstrt = hsstrt2hw(par->htotal+16);
3249                                        custom.hsstop = hsstop2hw(par->htotal+16);
3250                                        custom.vsstrt = vsstrt2hw(par->vsstrt);
3251                                        custom.vsstop = vsstrt2hw(par->vsstop);
3252                                        break;
3253                                case FB_BLANK_POWERDOWN:
3254                                        custom.hsstrt = hsstrt2hw(par->htotal+16);
3255                                        custom.hsstop = hsstop2hw(par->htotal+16);
3256                                        custom.vsstrt = vsstrt2hw(par->vtotal+4);
3257                                        custom.vsstop = vsstop2hw(par->vtotal+4);
3258                                        break;
3259                        }
3260                        if (!(par->beamcon0 & BMC0_VARBEAMEN)) {
3261                                custom.htotal = htotal2hw(par->htotal);
3262                                custom.vtotal = vtotal2hw(par->vtotal);
3263                                custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN |
3264                                                  BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN;
3265                        }
3266                }
3267        } else {
3268                custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
3269                red = red0;
3270                green = green0;
3271                blue = blue0;
3272                if (!IS_OCS) {
3273                        custom.hsstrt = hsstrt2hw(par->hsstrt);
3274                        custom.hsstop = hsstop2hw(par->hsstop);
3275                        custom.vsstrt = vsstrt2hw(par->vsstrt);
3276                        custom.vsstop = vsstop2hw(par->vsstop);
3277                        custom.beamcon0 = par->beamcon0;
3278                }
3279        }
3280#if defined(CONFIG_FB_AMIGA_AGA)
3281        if (IS_AGA) {
3282                custom.bplcon3 = bplcon3;
3283                custom.color[0] = rgb2hw8_high(red, green, blue);
3284                custom.bplcon3 = bplcon3 | BPC3_LOCT;
3285                custom.color[0] = rgb2hw8_low(red, green, blue);
3286                custom.bplcon3 = bplcon3;
3287        } else
3288#endif
3289#if defined(CONFIG_FB_AMIGA_ECS)
3290        if (par->bplcon0 & BPC0_SHRES) {
3291                u_short color, mask;
3292                int i;
3293
3294                mask = 0x3333;
3295                color = rgb2hw2(red, green, blue);
3296                for (i = 12; i >= 0; i -= 4)
3297                        custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3298                mask <<=2; color >>= 2;
3299                for (i = 3; i >= 0; i--)
3300                        custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3301        } else
3302#endif
3303                custom.color[0] = rgb2hw4(red, green, blue);
3304        is_blanked = do_blank > 0 ? do_blank : 0;
3305}
3306
3307static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix)
3308{
3309        struct amifb_par *par = &currentpar;
3310
3311        fix->crsr_width = fix->crsr_xsize = par->crsr.width;
3312        fix->crsr_height = fix->crsr_ysize = par->crsr.height;
3313        fix->crsr_color1 = 17;
3314        fix->crsr_color2 = 18;
3315        return 0;
3316}
3317
3318static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data)
3319{
3320        struct amifb_par *par = &currentpar;
3321        register u_short *lspr, *sspr;
3322#ifdef __mc68000__
3323        register u_long datawords asm ("d2");
3324#else
3325        register u_long datawords;
3326#endif
3327        register short delta;
3328        register u_char color;
3329        short height, width, bits, words;
3330        int size, alloc;
3331
3332        size = par->crsr.height*par->crsr.width;
3333        alloc = var->height*var->width;
3334        var->height = par->crsr.height;
3335        var->width = par->crsr.width;
3336        var->xspot = par->crsr.spot_x;
3337        var->yspot = par->crsr.spot_y;
3338        if (size > var->height*var->width)
3339                return -ENAMETOOLONG;
3340        if (!access_ok(VERIFY_WRITE, data, size))
3341                return -EFAULT;
3342        delta = 1<<par->crsr.fmode;
3343        lspr = lofsprite + (delta<<1);
3344        if (par->bplcon0 & BPC0_LACE)
3345                sspr = shfsprite + (delta<<1);
3346        else
3347                sspr = NULL;
3348        for (height = (short)var->height-1; height >= 0; height--) {
3349                bits = 0; words = delta; datawords = 0;
3350                for (width = (short)var->width-1; width >= 0; width--) {
3351                        if (bits == 0) {
3352                                bits = 16; --words;
3353#ifdef __mc68000__
3354                                asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0"
3355                                        : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta));
3356#else
3357                                datawords = (*(lspr+delta) << 16) | (*lspr++);
3358#endif
3359                        }
3360                        --bits;
3361#ifdef __mc68000__
3362                        asm volatile (
3363                                "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; "
3364                                "swap %1 ; lslw #1,%1 ; roxlb #1,%0"
3365                                : "=d" (color), "=d" (datawords) : "1" (datawords));
3366#else
3367                        color = (((datawords >> 30) & 2)
3368                                 | ((datawords >> 15) & 1));
3369                        datawords <<= 1;
3370#endif
3371                        put_user(color, data++);
3372                }
3373                if (bits > 0) {
3374                        --words; ++lspr;
3375                }
3376                while (--words >= 0)
3377                        ++lspr;
3378#ifdef __mc68000__
3379                asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
3380                        : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
3381#else
3382                lspr += delta;
3383                if (sspr) {
3384                        u_short *tmp = lspr;
3385                        lspr = sspr;
3386                        sspr = tmp;
3387                }
3388#endif
3389        }
3390        return 0;
3391}
3392
3393static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data)
3394{
3395        struct amifb_par *par = &currentpar;
3396        register u_short *lspr, *sspr;
3397#ifdef __mc68000__
3398        register u_long datawords asm ("d2");
3399#else
3400        register u_long datawords;
3401#endif
3402        register short delta;
3403        u_short fmode;
3404        short height, width, bits, words;
3405
3406        if (!var->width)
3407                return -EINVAL;
3408        else if (var->width <= 16)
3409                fmode = TAG_FMODE_1;
3410        else if (var->width <= 32)
3411                fmode = TAG_FMODE_2;
3412        else if (var->width <= 64)
3413                fmode = TAG_FMODE_4;
3414        else
3415                return -EINVAL;
3416        if (fmode > maxfmode)
3417                return -EINVAL;
3418        if (!var->height)
3419                return -EINVAL;
3420        if (!access_ok(VERIFY_READ, data, var->width*var->height))
3421                return -EFAULT;
3422        delta = 1<<fmode;
3423        lofsprite = shfsprite = (u_short *)spritememory;
3424        lspr = lofsprite + (delta<<1);
3425        if (par->bplcon0 & BPC0_LACE) {
3426                if (((var->height+4)<<fmode<<2) > SPRITEMEMSIZE)
3427                        return -EINVAL;
3428                memset(lspr, 0, (var->height+4)<<fmode<<2);
3429                shfsprite += ((var->height+5)&-2)<<fmode;
3430                sspr = shfsprite + (delta<<1);
3431        } else {
3432                if (((var->height+2)<<fmode<<2) > SPRITEMEMSIZE)
3433                        return -EINVAL;
3434                memset(lspr, 0, (var->height+2)<<fmode<<2);
3435                sspr = NULL;
3436        }
3437        for (height = (short)var->height-1; height >= 0; height--) {
3438                bits = 16; words = delta; datawords = 0;
3439                for (width = (short)var->width-1; width >= 0; width--) {
3440                        unsigned long tdata = 0;
3441                        get_user(tdata, data);
3442                        data++;
3443#ifdef __mc68000__
3444                        asm volatile (
3445                                "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; "
3446                                "lsrb #1,%2 ; roxlw #1,%0 ; swap %0"
3447                                : "=d" (datawords)
3448                                : "0" (datawords), "d" (tdata));
3449#else
3450                        datawords = ((datawords << 1) & 0xfffefffe);
3451                        datawords |= tdata & 1;
3452                        datawords |= (tdata & 2) << (16-1);
3453#endif
3454                        if (--bits == 0) {
3455                                bits = 16; --words;
3456#ifdef __mc68000__
3457                                asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+"
3458                                        : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta));
3459#else
3460                                *(lspr+delta) = (u_short) (datawords >> 16);
3461                                *lspr++ = (u_short) (datawords & 0xffff);
3462#endif
3463                        }
3464                }
3465                if (bits < 16) {
3466                        --words;
3467#ifdef __mc68000__
3468                        asm volatile (
3469                                "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; "
3470                                "swap %2 ; lslw %4,%2 ; movew %2,%0@+"
3471                                : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits));
3472#else
3473                        *(lspr+delta) = (u_short) (datawords >> (16+bits));
3474                        *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits);
3475#endif
3476                }
3477                while (--words >= 0) {
3478#ifdef __mc68000__
3479                        asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+"
3480                                : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0");
3481#else
3482                        *(lspr+delta) = 0;
3483                        *lspr++ = 0;
3484#endif
3485                }
3486#ifdef __mc68000__
3487                asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
3488                        : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
3489#else
3490                lspr += delta;
3491                if (sspr) {
3492                        u_short *tmp = lspr;
3493                        lspr = sspr;
3494                        sspr = tmp;
3495                }
3496#endif
3497        }
3498        par->crsr.height = var->height;
3499        par->crsr.width = var->width;
3500        par->crsr.spot_x = var->xspot;
3501        par->crsr.spot_y = var->yspot;
3502        par->crsr.fmode = fmode;
3503        if (IS_AGA) {
3504                par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32);
3505                par->fmode |= sprfetchmode[fmode];
3506                custom.fmode = par->fmode;
3507        }
3508        return 0;
3509}
3510
3511static int ami_get_cursorstate(struct fb_cursorstate *state)
3512{
3513        struct amifb_par *par = &currentpar;
3514
3515        state->xoffset = par->crsr.crsr_x;
3516        state->yoffset = par->crsr.crsr_y;
3517        state->mode = cursormode;
3518        return 0;
3519}
3520
3521static int ami_set_cursorstate(struct fb_cursorstate *state)
3522{
3523        struct amifb_par *par = &currentpar;
3524
3525        par->crsr.crsr_x = state->xoffset;
3526        par->crsr.crsr_y = state->yoffset;
3527        if ((cursormode = state->mode) == FB_CURSOR_OFF)
3528                cursorstate = -1;
3529        do_cursor = 1;
3530        return 0;
3531}
3532
3533static void ami_set_sprite(void)
3534{
3535        struct amifb_par *par = &currentpar;
3536        copins *copl, *cops;
3537        u_short hs, vs, ve;
3538        u_long pl, ps, pt;
3539        short mx, my;
3540
3541        cops = copdisplay.list[currentcop][0];
3542        copl = copdisplay.list[currentcop][1];
3543        ps = pl = ZTWO_PADDR(dummysprite);
3544        mx = par->crsr.crsr_x-par->crsr.spot_x;
3545        my = par->crsr.crsr_y-par->crsr.spot_y;
3546        if (!(par->vmode & FB_VMODE_YWRAP)) {
3547                mx -= par->xoffset;
3548                my -= par->yoffset;
3549        }
3550        if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 &&
3551            mx > -(short)par->crsr.width && mx < par->xres &&
3552            my > -(short)par->crsr.height && my < par->yres) {
3553                pl = ZTWO_PADDR(lofsprite);
3554                hs = par->diwstrt_h + (mx<<par->clk_shift) - 4;
3555                vs = par->diwstrt_v + (my<<par->line_shift);
3556                ve = vs + (par->crsr.height<<par->line_shift);
3557                if (par->bplcon0 & BPC0_LACE) {
3558                        ps = ZTWO_PADDR(shfsprite);
3559                        lofsprite[0] = spr2hw_pos(vs, hs);
3560                        shfsprite[0] = spr2hw_pos(vs+1, hs);
3561                        if (mod2(vs)) {
3562                                lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
3563                                shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1);
3564                                pt = pl; pl = ps; ps = pt;
3565                        } else {
3566                                lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve+1);
3567                                shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve);
3568                        }
3569                } else {
3570                        lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0);
3571                        lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
3572                }
3573        }
3574        copl[cop_spr0ptrh].w[1] = highw(pl);
3575        copl[cop_spr0ptrl].w[1] = loww(pl);
3576        if (par->bplcon0 & BPC0_LACE) {
3577                cops[cop_spr0ptrh].w[1] = highw(ps);
3578                cops[cop_spr0ptrl].w[1] = loww(ps);
3579        }
3580}
3581
3582
3583        /*
3584         * Initialise the Copper Initialisation List
3585         */
3586
3587static void __init ami_init_copper(void)
3588{
3589        copins *cop = copdisplay.init;
3590        u_long p;
3591        int i;
3592
3593        if (!IS_OCS) {
3594                (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
3595                (cop++)->l = CMOVE(0x0181, diwstrt);
3596                (cop++)->l = CMOVE(0x0281, diwstop);
3597                (cop++)->l = CMOVE(0x0000, diwhigh);
3598        } else
3599                (cop++)->l = CMOVE(BPC0_COLOR, bplcon0);
3600        p = ZTWO_PADDR(dummysprite);
3601        for (i = 0; i < 8; i++) {
3602                (cop++)->l = CMOVE(0, spr[i].pos);
3603                (cop++)->l = CMOVE(highw(p), sprpt[i]);
3604                (cop++)->l = CMOVE2(loww(p), sprpt[i]);
3605        }
3606
3607        (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);
3608        copdisplay.wait = cop;
3609        (cop++)->l = CEND;
3610        (cop++)->l = CMOVE(0, copjmp2);
3611        cop->l = CEND;
3612
3613        custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);
3614        custom.copjmp1 = 0;
3615}
3616
3617static void ami_reinit_copper(void)
3618{
3619        struct amifb_par *par = &currentpar;
3620
3621        copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0;
3622        copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4);
3623}
3624
3625        /*
3626         * Build the Copper List
3627         */
3628
3629static void ami_build_copper(void)
3630{
3631        struct amifb_par *par = &currentpar;
3632        copins *copl, *cops;
3633        u_long p;
3634
3635        currentcop = 1 - currentcop;
3636
3637        copl = copdisplay.list[currentcop][1];
3638
3639        (copl++)->l = CWAIT(0, 10);
3640        (copl++)->l = CMOVE(par->bplcon0, bplcon0);
3641        (copl++)->l = CMOVE(0, sprpt[0]);
3642        (copl++)->l = CMOVE2(0, sprpt[0]);
3643
3644        if (par->bplcon0 & BPC0_LACE) {
3645                cops = copdisplay.list[currentcop][0];
3646
3647                (cops++)->l = CWAIT(0, 10);
3648                (cops++)->l = CMOVE(par->bplcon0, bplcon0);
3649                (cops++)->l = CMOVE(0, sprpt[0]);
3650                (cops++)->l = CMOVE2(0, sprpt[0]);
3651
3652                (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt);
3653                (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop);
3654                (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
3655                (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
3656                if (!IS_OCS) {
3657                        (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1,
3658                                            par->diwstop_h, par->diwstop_v+1), diwhigh);
3659                        (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
3660                                            par->diwstop_h, par->diwstop_v), diwhigh);
3661#if 0
3662                        if (par->beamcon0 & BMC0_VARBEAMEN) {
3663                                (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3664                                (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt);
3665                                (copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop);
3666                                (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3667                                (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
3668                                (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
3669                        }
3670#endif
3671                }
3672                p = ZTWO_PADDR(copdisplay.list[currentcop][0]);
3673                (copl++)->l = CMOVE(highw(p), cop2lc);
3674                (copl++)->l = CMOVE2(loww(p), cop2lc);
3675                p = ZTWO_PADDR(copdisplay.list[currentcop][1]);
3676                (cops++)->l = CMOVE(highw(p), cop2lc);
3677                (cops++)->l = CMOVE2(loww(p), cop2lc);
3678                copdisplay.rebuild[0] = cops;
3679        } else {
3680                (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
3681                (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
3682                if (!IS_OCS) {
3683                        (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
3684                                            par->diwstop_h, par->diwstop_v), diwhigh);
3685#if 0
3686                        if (par->beamcon0 & BMC0_VARBEAMEN) {
3687                                (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3688                                (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
3689                                (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
3690                        }
3691#endif
3692                }
3693        }
3694        copdisplay.rebuild[1] = copl;
3695
3696        ami_update_par();
3697        ami_rebuild_copper();
3698}
3699
3700        /*
3701         * Rebuild the Copper List
3702         *
3703         * We only change the things that are not static
3704         */
3705
3706static void ami_rebuild_copper(void)
3707{
3708        struct amifb_par *par = &currentpar;
3709        copins *copl, *cops;
3710        u_short line, h_end1, h_end2;
3711        short i;
3712        u_long p;
3713
3714        if (IS_AGA && maxfmode + par->clk_shift == 0)
3715                h_end1 = par->diwstrt_h-64;
3716        else
3717                h_end1 = par->htotal-32;
3718        h_end2 = par->ddfstop+64;
3719
3720        ami_set_sprite();
3721
3722        copl = copdisplay.rebuild[1];
3723        p = par->bplpt0;
3724        if (par->vmode & FB_VMODE_YWRAP) {
3725                if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) {
3726                        if (par->yoffset > par->vyres-par->yres) {
3727                                for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3728                                        (copl++)->l = CMOVE(highw(p), bplpt[i]);
3729                                        (copl++)->l = CMOVE2(loww(p), bplpt[i]);
3730                                }
3731                                line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 1;
3732                                while (line >= 512) {
3733                                        (copl++)->l = CWAIT(h_end1, 510);
3734                                        line -= 512;
3735                                }
3736                                if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0)
3737                                        (copl++)->l = CWAIT(h_end1, line);
3738                                else
3739                                        (copl++)->l = CWAIT(h_end2, line);
3740                                p = par->bplpt0wrap;
3741                        }
3742                } else p = par->bplpt0wrap;
3743        }
3744        for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3745                (copl++)->l = CMOVE(highw(p), bplpt[i]);
3746                (copl++)->l = CMOVE2(loww(p), bplpt[i]);
3747        }
3748        copl->l = CEND;
3749
3750        if (par->bplcon0 & BPC0_LACE) {
3751                cops = copdisplay.rebuild[0];
3752                p = par->bplpt0;
3753                if (mod2(par->diwstrt_v))
3754                        p -= par->next_line;
3755                else
3756                        p += par->next_line;
3757                if (par->vmode & FB_VMODE_YWRAP) {
3758                        if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) {
3759                                if (par->yoffset > par->vyres-par->yres+1) {
3760                                        for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3761                                                (cops++)->l = CMOVE(highw(p), bplpt[i]);
3762                                                (cops++)->l = CMOVE2(loww(p), bplpt[i]);
3763                                        }
3764                                        line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 2;
3765                                        while (line >= 512) {
3766                                                (cops++)->l = CWAIT(h_end1, 510);
3767                                                line -= 512;
3768                                        }
3769                                        if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0)
3770                                                (cops++)->l = CWAIT(h_end1, line);
3771                                        else
3772                                                (cops++)->l = CWAIT(h_end2, line);
3773                                        p = par->bplpt0wrap;
3774                                        if (mod2(par->diwstrt_v+par->vyres-par->yoffset))
3775                                                p -= par->next_line;
3776                                        else
3777                                                p += par->next_line;
3778                                }
3779                        } else p = par->bplpt0wrap - par->next_line;
3780                }
3781                for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3782                        (cops++)->l = CMOVE(highw(p), bplpt[i]);
3783                        (cops++)->l = CMOVE2(loww(p), bplpt[i]);
3784                }
3785                cops->l = CEND;
3786        }
3787}
3788
3789static int __exit amifb_remove(struct platform_device *pdev)
3790{
3791        unregister_framebuffer(&fb_info);
3792        amifb_deinit(pdev);
3793        amifb_video_off();
3794        return 0;
3795}
3796
3797static struct platform_driver amifb_driver = {
3798        .remove = __exit_p(amifb_remove),
3799        .driver   = {
3800                .name   = "amiga-video",
3801                .owner  = THIS_MODULE,
3802        },
3803};
3804
3805static int __init amifb_init(void)
3806{
3807        return platform_driver_probe(&amifb_driver, amifb_probe);
3808}
3809
3810module_init(amifb_init);
3811
3812static void __exit amifb_exit(void)
3813{
3814        platform_driver_unregister(&amifb_driver);
3815}
3816
3817module_exit(amifb_exit);
3818
3819MODULE_LICENSE("GPL");
3820MODULE_ALIAS("platform:amiga-video");
3821