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