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