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