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