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