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