xref: /openbmc/linux/drivers/video/fbdev/amifb.c (revision 43a1120c)
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 
494 enum { TAG_SHRES, TAG_HIRES, TAG_LORES };
495 
496 	/*
497 	 * Tags used to indicate the specific chipset
498 	 */
499 
500 enum { TAG_OCS, TAG_ECS, TAG_AGA };
501 
502 	/*
503 	 * Tags used to indicate the memory bandwidth
504 	 */
505 
506 enum { 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 
516 static u_long pixclock[3];	/* SHRES/HIRES/LORES: index = clk_shift */
517 static u_short maxdepth[3];	/* SHRES/HIRES/LORES: index = clk_shift */
518 static 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)
618 static u_long spritememory;
619 
620 #define CHIPRAM_SAFETY_LIMIT	(16384)
621 
622 static 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 
630 static 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 
649 typedef union {
650 	u_long l;
651 	u_short w[2];
652 } copins;
653 
654 static struct copdisplay {
655 	copins *init;
656 	copins *wait;
657 	copins *list[2][2];
658 	copins *rebuild[2];
659 } copdisplay;
660 
661 static 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 
676 struct 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 
685 struct fb_var_cursorinfo {
686 	__u16 width;
687 	__u16 height;
688 	__u16 xspot;
689 	__u16 yspot;
690 	DECLARE_FLEX_ARRAY(__u8, data);	/* field with [height][width]        */
691 };
692 
693 struct 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 
708 static int cursorrate = 20;	/* Number of frames/flash toggle */
709 static u_short cursorstate = -1;
710 static u_short cursormode = FB_CURSOR_OFF;
711 
712 static u_short *lofsprite, *shfsprite, *dummysprite;
713 
714 	/*
715 	 * Current Video Mode
716 	 */
717 
718 struct 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 
788 static u_char red0, green0, blue0;
789 
790 
791 #if defined(CONFIG_FB_AMIGA_ECS)
792 static u_short ecs_palette[32];
793 #endif
794 
795 
796 	/*
797 	 * Latches for Display Changes during VBlank
798 	 */
799 
800 static u_short do_vmode_full = 0;	/* Change the Video Mode */
801 static u_short do_vmode_pan = 0;	/* Update the Video Mode */
802 static short do_blank = 0;		/* (Un)Blank the Screen (±1) */
803 static u_short do_cursor = 0;		/* Move the Cursor */
804 
805 
806 	/*
807 	 * Various Flags
808 	 */
809 
810 static u_short is_blanked = 0;		/* Screen is Blanked */
811 static u_short is_lace = 0;		/* Screen is laced */
812 
813 	/*
814 	 * Predefined Video Modes
815 	 *
816 	 */
817 
818 static 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 
942 static char *mode_option __initdata = NULL;
943 static 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 
957 static int amifb_ilbm = 0;	/* interleaved or normal bitplanes */
958 
959 static u32 amifb_hfmin __initdata;	/* monitor hfreq lower limit (Hz) */
960 static u32 amifb_hfmax __initdata;	/* monitor hfreq upper limit (Hz) */
961 static u16 amifb_vfmin __initdata;	/* monitor vfreq lower limit (Hz) */
962 static 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 
1070 enum {
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 
1081 enum {
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 
1092 static u_short bplpixmode[3] = {
1093 	BPC0_SHRES,			/*  35 ns */
1094 	BPC0_HIRES,			/*  70 ns */
1095 	0				/* 140 ns */
1096 };
1097 
1098 static 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 
1108 static u_short bplfetchmode[3] = {
1109 	0,				/* 1x */
1110 	FMODE_BPL32,			/* 2x */
1111 	FMODE_BPAGEM | FMODE_BPL32	/* 4x */
1112 };
1113 
1114 static 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 
ami_decode_var(struct fb_var_screeninfo * var,struct amifb_par * par,const struct fb_info * info)1128 static 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 
ami_encode_var(struct fb_var_screeninfo * var,struct amifb_par * par)1515 static 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 
ami_update_par(struct fb_info * info)1599 static 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 
ami_pan_var(struct fb_var_screeninfo * var,struct fb_info * info)1669 static 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 
ami_update_display(const struct amifb_par * par)1686 static 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 
ami_init_display(const struct amifb_par * par)1699 static 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 
ami_do_blank(const struct amifb_par * par)1753 static 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 
ami_get_fix_cursorinfo(struct fb_fix_cursorinfo * fix,const struct amifb_par * par)1831 static 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 
ami_get_var_cursorinfo(struct fb_var_cursorinfo * var,u_char __user * data,const struct amifb_par * par)1841 static 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 
ami_set_var_cursorinfo(struct fb_var_cursorinfo * var,u_char __user * data,struct amifb_par * par)1916 static 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 
ami_get_cursorstate(struct fb_cursorstate * state,const struct amifb_par * par)2033 static 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 
ami_set_cursorstate(struct fb_cursorstate * state,struct amifb_par * par)2042 static 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 
ami_set_sprite(const struct amifb_par * par)2053 static 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 
ami_init_copper(void)2106 static 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 
ami_reinit_copper(const struct amifb_par * par)2136 static 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 
ami_rebuild_copper(const struct amifb_par * par)2149 static 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 
ami_build_copper(struct fb_info * info)2239 static 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
amifb_setup_mcap(char * spec)2311 static 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 
amifb_setup(char * options)2348 static 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 
amifb_check_var(struct fb_var_screeninfo * var,struct fb_info * info)2377 static 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 
amifb_set_par(struct fb_info * info)2394 static 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_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_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 
amifb_setcolreg(u_int regno,u_int red,u_int green,u_int blue,u_int transp,struct fb_info * info)2451 static 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 
amifb_blank(int blank,struct fb_info * info)2526 static 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 
amifb_pan_display(struct fb_var_screeninfo * var,struct fb_info * info)2540 static 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 
comp(unsigned long a,unsigned long b,unsigned long mask)2573 static inline unsigned long comp(unsigned long a, unsigned long b,
2574 				 unsigned long mask)
2575 {
2576 	return ((a ^ b) & mask) ^ b;
2577 }
2578 
2579 
xor(unsigned long a,unsigned long b,unsigned long mask)2580 static 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 
bitcpy(unsigned long * dst,int dst_idx,const unsigned long * src,int src_idx,u32 n)2591 static 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 
bitcpy_rev(unsigned long * dst,int dst_idx,const unsigned long * src,int src_idx,u32 n)2731 static 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 
bitcpy_not(unsigned long * dst,int dst_idx,const unsigned long * src,int src_idx,u32 n)2883 static 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 
bitfill32(unsigned long * dst,int dst_idx,u32 pat,u32 n)3023 static 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 
bitxor32(unsigned long * dst,int dst_idx,u32 pat,u32 n)3079 static 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 
fill_one_line(int bpp,unsigned long next_plane,unsigned long * dst,int dst_idx,u32 n,u32 color)3126 static 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 
xor_one_line(int bpp,unsigned long next_plane,unsigned long * dst,int dst_idx,u32 n,u32 color)3141 static 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 
amifb_fillrect(struct fb_info * info,const struct fb_fillrect * rect)3157 static 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 
copy_one_line(int bpp,unsigned long next_plane,unsigned long * dst,int dst_idx,unsigned long * src,int src_idx,u32 n)3200 static 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 
copy_one_line_rev(int bpp,unsigned long next_plane,unsigned long * dst,int dst_idx,unsigned long * src,int src_idx,u32 n)3217 static 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 
amifb_copyarea(struct fb_info * info,const struct fb_copyarea * area)3235 static 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 
expand_one_line(int bpp,unsigned long next_plane,unsigned long * dst,int dst_idx,u32 n,const u8 * data,u32 bgcolor,u32 fgcolor)3299 static 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 
amifb_imageblit(struct fb_info * info,const struct fb_image * image)3329 static 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 
amifb_ioctl(struct fb_info * info,unsigned int cmd,unsigned long arg)3379 static 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 
flash_cursor(void)3434 static 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 
amifb_interrupt(int irq,void * dev_id)3453 static 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 
3489 static 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 
3507 static void *aligned_chipptr;
3508 
chipalloc(u_long size)3509 static 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 
chipfree(void)3520 static inline void chipfree(void)
3521 {
3522 	if (aligned_chipptr)
3523 		amiga_chip_free(aligned_chipptr);
3524 }
3525 
3526 
3527 	/*
3528 	 * Initialisation
3529 	 */
3530 
amifb_probe(struct platform_device * pdev)3531 static 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");
3561 default_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->device = &pdev->dev;
3664 
3665 	if (!fb_find_mode(&info->var, info, mode_option, ami_modedb,
3666 			  NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
3667 		err = -EINVAL;
3668 		goto release;
3669 	}
3670 
3671 	fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES,
3672 				 &info->modelist);
3673 
3674 	round_down_bpp = 0;
3675 	chipptr = chipalloc(info->fix.smem_len + SPRITEMEMSIZE +
3676 			    DUMMYSPRITEMEMSIZE + COPINITSIZE +
3677 			    4 * COPLISTSIZE);
3678 	if (!chipptr) {
3679 		err = -ENOMEM;
3680 		goto release;
3681 	}
3682 
3683 	assignchunk(videomemory, u_long, chipptr, info->fix.smem_len);
3684 	assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
3685 	assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
3686 	assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
3687 	assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);
3688 	assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);
3689 	assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);
3690 	assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);
3691 
3692 	/*
3693 	 * access the videomem with writethrough cache
3694 	 */
3695 	info->fix.smem_start = (u_long)ZTWO_PADDR(videomemory);
3696 	videomemory = (u_long)ioremap_wt(info->fix.smem_start,
3697 					 info->fix.smem_len);
3698 	if (!videomemory) {
3699 		dev_warn(&pdev->dev,
3700 			 "Unable to map videomem cached writethrough\n");
3701 		info->screen_base = ZTWO_VADDR(info->fix.smem_start);
3702 	} else
3703 		info->screen_base = (char *)videomemory;
3704 
3705 	memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
3706 
3707 	/*
3708 	 * Make sure the Copper has something to do
3709 	 */
3710 	ami_init_copper();
3711 
3712 	/*
3713 	 * Enable Display DMA
3714 	 */
3715 	custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
3716 			DMAF_BLITTER | DMAF_SPRITE;
3717 
3718 	err = request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,
3719 			  "fb vertb handler", info->par);
3720 	if (err)
3721 		goto disable_dma;
3722 
3723 	err = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0);
3724 	if (err)
3725 		goto free_irq;
3726 
3727 	platform_set_drvdata(pdev, info);
3728 
3729 	err = register_framebuffer(info);
3730 	if (err)
3731 		goto unset_drvdata;
3732 
3733 	fb_info(info, "%s frame buffer device, using %dK of video memory\n",
3734 		info->fix.id, info->fix.smem_len>>10);
3735 
3736 	return 0;
3737 
3738 unset_drvdata:
3739 	fb_dealloc_cmap(&info->cmap);
3740 free_irq:
3741 	free_irq(IRQ_AMIGA_COPPER, info->par);
3742 disable_dma:
3743 	custom.dmacon = DMAF_ALL | DMAF_MASTER;
3744 	if (videomemory)
3745 		iounmap((void *)videomemory);
3746 	chipfree();
3747 release:
3748 	framebuffer_release(info);
3749 	return err;
3750 }
3751 
3752 
amifb_remove(struct platform_device * pdev)3753 static int __exit amifb_remove(struct platform_device *pdev)
3754 {
3755 	struct fb_info *info = platform_get_drvdata(pdev);
3756 
3757 	unregister_framebuffer(info);
3758 	fb_dealloc_cmap(&info->cmap);
3759 	free_irq(IRQ_AMIGA_COPPER, info->par);
3760 	custom.dmacon = DMAF_ALL | DMAF_MASTER;
3761 	if (videomemory)
3762 		iounmap((void *)videomemory);
3763 	chipfree();
3764 	framebuffer_release(info);
3765 	amifb_video_off();
3766 	return 0;
3767 }
3768 
3769 static struct platform_driver amifb_driver = {
3770 	.remove = __exit_p(amifb_remove),
3771 	.driver   = {
3772 		.name	= "amiga-video",
3773 	},
3774 };
3775 
3776 module_platform_driver_probe(amifb_driver, amifb_probe);
3777 
3778 MODULE_LICENSE("GPL");
3779 MODULE_ALIAS("platform:amiga-video");
3780