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