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