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