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