2 * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device
4 * Copyright (C) 1995-2003 Geert Uytterhoeven
6 * with work by Roman Zippel
9 * This file is based on the Atari frame buffer device (atafb.c):
11 * Copyright (C) 1994 Martin Schaller
14 * with work by Andreas Schwab
17 * and on the original Amiga console driver (amicon.c):
19 * Copyright (C) 1993 Hamish Macdonald
21 * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
23 * with work by William Rucklidge (wjr@cs.cornell.edu)
25 * Jes Sorensen (jds@kom.auc.dk)
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
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
43 #include <linux/module.h>
44 #include <linux/kernel.h>
45 #include <linux/errno.h>
46 #include <linux/string.h>
48 #include <linux/tty.h>
49 #include <linux/slab.h>
50 #include <linux/delay.h>
51 #include <linux/config.h>
52 #include <linux/interrupt.h>
54 #include <linux/init.h>
55 #include <linux/ioport.h>
57 #include <asm/uaccess.h>
58 #include <asm/system.h>
60 #include <asm/amigahw.h>
61 #include <asm/amigaints.h>
62 #include <asm/setup.h>
69 #if !defined(CONFIG_FB_AMIGA_OCS) && !defined(CONFIG_FB_AMIGA_ECS) && !defined(CONFIG_FB_AMIGA_AGA)
70 #define CONFIG_FB_AMIGA_OCS /* define at least one fb driver, this will change later */
73 #if !defined(CONFIG_FB_AMIGA_OCS)
75 #elif defined(CONFIG_FB_AMIGA_ECS) || defined(CONFIG_FB_AMIGA_AGA)
76 # define IS_OCS (chipset == TAG_OCS)
78 # define CONFIG_FB_AMIGA_OCS_ONLY
82 #if !defined(CONFIG_FB_AMIGA_ECS)
84 #elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_AGA)
85 # define IS_ECS (chipset == TAG_ECS)
87 # define CONFIG_FB_AMIGA_ECS_ONLY
91 #if !defined(CONFIG_FB_AMIGA_AGA)
93 #elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_ECS)
94 # define IS_AGA (chipset == TAG_AGA)
96 # define CONFIG_FB_AMIGA_AGA_ONLY
101 # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
103 # define DPRINTK(fmt, args...)
106 /*******************************************************************************
109 Generic video timings
110 ---------------------
112 Timings used by the frame buffer interface:
114 +----------+---------------------------------------------+----------+-------+
116 | | |upper_margin | | |
118 +----------###############################################----------+-------+
123 | left # | # right | hsync |
124 | margin # | xres # margin | len |
125 |<-------->#<---------------+--------------------------->#<-------->|<----->|
139 +----------###############################################----------+-------+
141 | | |lower_margin | | |
143 +----------+---------------------------------------------+----------+-------+
147 +----------+---------------------------------------------+----------+-------+
153 The Amiga native chipsets uses another timing scheme:
155 - hsstrt: Start of horizontal synchronization pulse
156 - hsstop: End of horizontal synchronization pulse
157 - htotal: Last value on the line (i.e. line length = htotal+1)
158 - vsstrt: Start of vertical synchronization pulse
159 - vsstop: End of vertical synchronization pulse
160 - vtotal: Last line value (i.e. number of lines = vtotal+1)
161 - hcenter: Start of vertical retrace for interlace
163 You can specify the blanking timings independently. Currently I just set
164 them equal to the respective synchronization values:
166 - hbstrt: Start of horizontal blank
167 - hbstop: End of horizontal blank
168 - vbstrt: Start of vertical blank
169 - vbstop: End of vertical blank
171 Horizontal values are in color clock cycles (280 ns), vertical values are in
174 (0, 0) is somewhere in the upper-left corner :-)
177 Amiga visible window definitions
178 --------------------------------
180 Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to
181 make corrections and/or additions.
183 Within the above synchronization specifications, the visible window is
184 defined by the following parameters (actual register resolutions may be
185 different; all horizontal values are normalized with respect to the pixel
188 - diwstrt_h: Horizontal start of the visible window
189 - diwstop_h: Horizontal stop+1(*) of the visible window
190 - diwstrt_v: Vertical start of the visible window
191 - diwstop_v: Vertical stop of the visible window
192 - ddfstrt: Horizontal start of display DMA
193 - ddfstop: Horizontal stop of display DMA
194 - hscroll: Horizontal display output delay
198 - sprstrt_h: Horizontal start-4 of sprite
199 - sprstrt_v: Vertical start of sprite
201 (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1.
203 Horizontal values are in dotclock cycles (35 ns), vertical values are in
206 (0, 0) is somewhere in the upper-left corner :-)
209 Dependencies (AGA, SHRES (35 ns dotclock))
210 -------------------------------------------
212 Since there are much more parameters for the Amiga display than for the
213 frame buffer interface, there must be some dependencies among the Amiga
214 display parameters. Here's what I found out:
216 - ddfstrt and ddfstop are best aligned to 64 pixels.
217 - the chipset needs 64+4 horizontal pixels after the DMA start before the
218 first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to
219 display the first pixel on the line too. Increase diwstrt_h for virtual
221 - the display DMA always fetches 64 pixels at a time (fmode = 3).
222 - ddfstop is ddfstrt+#pixels-64.
223 - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1
225 - hscroll simply adds a delay to the display output. Smooth horizontal
226 panning needs an extra 64 pixels on the left to prefetch the pixels that
227 `fall off' on the left.
228 - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane
229 DMA, so it's best to make the DMA start as late as possible.
230 - you really don't want to make ddfstrt < 128, since this will steal DMA
231 cycles from the other DMA channels (audio, floppy and Chip RAM refresh).
232 - I make diwstop_h and diwstop_v as large as possible.
237 - all values are SHRES pixel (35ns)
239 table 1:fetchstart table 2:prefetch table 3:fetchsize
240 ------------------ ---------------- -----------------
241 Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES
242 -------------#------+-----+------#------+-----+------#------+-----+------
243 Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64
244 Bus width 2x # 32 | 64 | 128 # 32 | 64 | 64 # 64 | 64 | 128
245 Bus width 4x # 64 | 128 | 256 # 64 | 64 | 64 # 64 | 128 | 256
247 - chipset needs 4 pixels before the first pixel is output
248 - ddfstrt must be aligned to fetchstart (table 1)
249 - chipset needs also prefetch (table 2) to get first pixel data, so
250 ddfstrt = ((diwstrt_h-4) & -fetchstart) - prefetch
251 - for horizontal panning decrease diwstrt_h
252 - the length of a fetchline must be aligned to fetchsize (table 3)
253 - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit
254 moved to optimize use of dma (useful for OCS/ECS overscan displays)
255 - ddfstop is ddfstrt+ddfsize-fetchsize
256 - If C= didn't change anything for AGA, then at following positions the
257 dma bus is already used:
258 ddfstrt < 48 -> memory refresh
261 < 192 -> sprite 0 dma
262 < 416 -> sprite dma (32 per sprite)
263 - in accordance with the hardware reference manual a hardware stop is at
264 192, but AGA (ECS?) can go below this.
269 Since there are limits on the earliest start value for display DMA and the
270 display of sprites, I use the following policy on horizontal panning and
273 - if you want to start display DMA too early, you lose the ability to
274 do smooth horizontal panning (xpanstep 1 -> 64).
275 - if you want to go even further, you lose the hardware cursor too.
277 IMHO a hardware cursor is more important for X than horizontal scrolling,
278 so that's my motivation.
284 ami_decode_var() converts the frame buffer values to the Amiga values. It's
285 just a `straightforward' implementation of the above rules.
291 xres yres left right upper lower hsync vsync
292 ---- ---- ---- ----- ----- ----- ----- -----
293 80x25 720 400 27 45 35 12 108 2
294 80x30 720 480 27 45 30 9 108 2
296 These were taken from a XFree86 configuration file, recalculated for a 28 MHz
297 dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer
300 As a comparison, graphics/monitor.h suggests the following:
302 xres yres left right upper lower hsync vsync
303 ---- ---- ---- ----- ----- ----- ----- -----
305 VGA 640 480 52 112 24 19 112 - 2 +
306 VGA70 640 400 52 112 27 21 112 - 2 -
312 VSYNC HSYNC Vertical size Vertical total
313 ----- ----- ------------- --------------
314 + + Reserved Reserved
319 Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992
322 Broadcast video timings
323 -----------------------
325 According to the CCIR and RETMA specifications, we have the following values:
330 - a scanline is 64 µs long, of which 52.48 µs are visible. This is about
331 736 visible 70 ns pixels per line.
332 - we have 625 scanlines, of which 575 are visible (interlaced); after
333 rounding this becomes 576.
338 - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about
339 736 visible 70 ns pixels per line.
340 - we have 525 scanlines, of which 485 are visible (interlaced); after
341 rounding this becomes 484.
343 Thus if you want a PAL compatible display, you have to do the following:
345 - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast
346 timings are to be used.
347 - make sure upper_margin+yres+lower_margin+vsync_len = 625 for an
348 interlaced, 312 for a non-interlaced and 156 for a doublescanned
350 - make sure left_margin+xres+right_margin+hsync_len = 1816 for a SHRES,
351 908 for a HIRES and 454 for a LORES display.
352 - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90),
353 left_margin+2*hsync_len must be greater or equal.
354 - the upper visible part begins at 48 (interlaced; non-interlaced:24,
355 doublescanned:12), upper_margin+2*vsync_len must be greater or equal.
356 - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync
359 The settings for a NTSC compatible display are straightforward.
361 Note that in a strict sense the PAL and NTSC standards only define the
362 encoding of the color part (chrominance) of the video signal and don't say
363 anything about horizontal/vertical synchronization nor refresh rates.
368 *******************************************************************************/
372 * Custom Chipset Definitions
375 #define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld)
378 * BPLCON0 -- Bitplane Control Register 0
381 #define BPC0_HIRES (0x8000)
382 #define BPC0_BPU2 (0x4000) /* Bit plane used count */
383 #define BPC0_BPU1 (0x2000)
384 #define BPC0_BPU0 (0x1000)
385 #define BPC0_HAM (0x0800) /* HAM mode */
386 #define BPC0_DPF (0x0400) /* Double playfield */
387 #define BPC0_COLOR (0x0200) /* Enable colorburst */
388 #define BPC0_GAUD (0x0100) /* Genlock audio enable */
389 #define BPC0_UHRES (0x0080) /* Ultrahi res enable */
390 #define BPC0_SHRES (0x0040) /* Super hi res mode */
391 #define BPC0_BYPASS (0x0020) /* Bypass LUT - AGA */
392 #define BPC0_BPU3 (0x0010) /* AGA */
393 #define BPC0_LPEN (0x0008) /* Light pen enable */
394 #define BPC0_LACE (0x0004) /* Interlace */
395 #define BPC0_ERSY (0x0002) /* External resync */
396 #define BPC0_ECSENA (0x0001) /* ECS enable */
399 * BPLCON2 -- Bitplane Control Register 2
402 #define BPC2_ZDBPSEL2 (0x4000) /* Bitplane to be used for ZD - AGA */
403 #define BPC2_ZDBPSEL1 (0x2000)
404 #define BPC2_ZDBPSEL0 (0x1000)
405 #define BPC2_ZDBPEN (0x0800) /* Enable ZD with ZDBPSELx - AGA */
406 #define BPC2_ZDCTEN (0x0400) /* Enable ZD with palette bit #31 - AGA */
407 #define BPC2_KILLEHB (0x0200) /* Kill EHB mode - AGA */
408 #define BPC2_RDRAM (0x0100) /* Color table accesses read, not write - AGA */
409 #define BPC2_SOGEN (0x0080) /* SOG output pin high - AGA */
410 #define BPC2_PF2PRI (0x0040) /* PF2 priority over PF1 */
411 #define BPC2_PF2P2 (0x0020) /* PF2 priority wrt sprites */
412 #define BPC2_PF2P1 (0x0010)
413 #define BPC2_PF2P0 (0x0008)
414 #define BPC2_PF1P2 (0x0004) /* ditto PF1 */
415 #define BPC2_PF1P1 (0x0002)
416 #define BPC2_PF1P0 (0x0001)
419 * BPLCON3 -- Bitplane Control Register 3 (AGA)
422 #define BPC3_BANK2 (0x8000) /* Bits to select color register bank */
423 #define BPC3_BANK1 (0x4000)
424 #define BPC3_BANK0 (0x2000)
425 #define BPC3_PF2OF2 (0x1000) /* Bits for color table offset when PF2 */
426 #define BPC3_PF2OF1 (0x0800)
427 #define BPC3_PF2OF0 (0x0400)
428 #define BPC3_LOCT (0x0200) /* Color register writes go to low bits */
429 #define BPC3_SPRES1 (0x0080) /* Sprite resolution bits */
430 #define BPC3_SPRES0 (0x0040)
431 #define BPC3_BRDRBLNK (0x0020) /* Border blanked? */
432 #define BPC3_BRDRTRAN (0x0010) /* Border transparent? */
433 #define BPC3_ZDCLKEN (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */
434 #define BPC3_BRDRSPRT (0x0002) /* Sprites in border? */
435 #define BPC3_EXTBLKEN (0x0001) /* BLANK programmable */
438 * BPLCON4 -- Bitplane Control Register 4 (AGA)
441 #define BPC4_BPLAM7 (0x8000) /* bitplane color XOR field */
442 #define BPC4_BPLAM6 (0x4000)
443 #define BPC4_BPLAM5 (0x2000)
444 #define BPC4_BPLAM4 (0x1000)
445 #define BPC4_BPLAM3 (0x0800)
446 #define BPC4_BPLAM2 (0x0400)
447 #define BPC4_BPLAM1 (0x0200)
448 #define BPC4_BPLAM0 (0x0100)
449 #define BPC4_ESPRM7 (0x0080) /* 4 high bits for even sprite colors */
450 #define BPC4_ESPRM6 (0x0040)
451 #define BPC4_ESPRM5 (0x0020)
452 #define BPC4_ESPRM4 (0x0010)
453 #define BPC4_OSPRM7 (0x0008) /* 4 high bits for odd sprite colors */
454 #define BPC4_OSPRM6 (0x0004)
455 #define BPC4_OSPRM5 (0x0002)
456 #define BPC4_OSPRM4 (0x0001)
459 * BEAMCON0 -- Beam Control Register
462 #define BMC0_HARDDIS (0x4000) /* Disable hardware limits */
463 #define BMC0_LPENDIS (0x2000) /* Disable light pen latch */
464 #define BMC0_VARVBEN (0x1000) /* Enable variable vertical blank */
465 #define BMC0_LOLDIS (0x0800) /* Disable long/short line toggle */
466 #define BMC0_CSCBEN (0x0400) /* Composite sync/blank */
467 #define BMC0_VARVSYEN (0x0200) /* Enable variable vertical sync */
468 #define BMC0_VARHSYEN (0x0100) /* Enable variable horizontal sync */
469 #define BMC0_VARBEAMEN (0x0080) /* Enable variable beam counters */
470 #define BMC0_DUAL (0x0040) /* Enable alternate horizontal beam counter */
471 #define BMC0_PAL (0x0020) /* Set decodes for PAL */
472 #define BMC0_VARCSYEN (0x0010) /* Enable variable composite sync */
473 #define BMC0_BLANKEN (0x0008) /* Blank enable (no longer used on AGA) */
474 #define BMC0_CSYTRUE (0x0004) /* CSY polarity */
475 #define BMC0_VSYTRUE (0x0002) /* VSY polarity */
476 #define BMC0_HSYTRUE (0x0001) /* HSY polarity */
480 * FMODE -- Fetch Mode Control Register (AGA)
483 #define FMODE_SSCAN2 (0x8000) /* Sprite scan-doubling */
484 #define FMODE_BSCAN2 (0x4000) /* Use PF2 modulus every other line */
485 #define FMODE_SPAGEM (0x0008) /* Sprite page mode */
486 #define FMODE_SPR32 (0x0004) /* Sprite 32 bit fetch */
487 #define FMODE_BPAGEM (0x0002) /* Bitplane page mode */
488 #define FMODE_BPL32 (0x0001) /* Bitplane 32 bit fetch */
491 * Tags used to indicate a specific Pixel Clock
493 * clk_shift is the shift value to get the timings in 35 ns units
496 enum { TAG_SHRES, TAG_HIRES, TAG_LORES };
499 * Tags used to indicate the specific chipset
502 enum { TAG_OCS, TAG_ECS, TAG_AGA };
505 * Tags used to indicate the memory bandwidth
508 enum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 };
512 * Clock Definitions, Maximum Display Depth
514 * These depend on the E-Clock or the Chipset, so they are filled in
518 static u_long pixclock[3]; /* SHRES/HIRES/LORES: index = clk_shift */
519 static u_short maxdepth[3]; /* SHRES/HIRES/LORES: index = clk_shift */
520 static u_short maxfmode, chipset;
524 * Broadcast Video Timings
526 * Horizontal values are in 35 ns (SHRES) units
527 * Vertical values are in interlaced scanlines
530 #define PAL_DIWSTRT_H (360) /* PAL Window Limits */
531 #define PAL_DIWSTRT_V (48)
532 #define PAL_HTOTAL (1816)
533 #define PAL_VTOTAL (625)
535 #define NTSC_DIWSTRT_H (360) /* NTSC Window Limits */
536 #define NTSC_DIWSTRT_V (40)
537 #define NTSC_HTOTAL (1816)
538 #define NTSC_VTOTAL (525)
545 #define up2(v) (((v)+1) & -2)
546 #define down2(v) ((v) & -2)
547 #define div2(v) ((v)>>1)
548 #define mod2(v) ((v) & 1)
550 #define up4(v) (((v)+3) & -4)
551 #define down4(v) ((v) & -4)
552 #define mul4(v) ((v)<<2)
553 #define div4(v) ((v)>>2)
554 #define mod4(v) ((v) & 3)
556 #define up8(v) (((v)+7) & -8)
557 #define down8(v) ((v) & -8)
558 #define div8(v) ((v)>>3)
559 #define mod8(v) ((v) & 7)
561 #define up16(v) (((v)+15) & -16)
562 #define down16(v) ((v) & -16)
563 #define div16(v) ((v)>>4)
564 #define mod16(v) ((v) & 15)
566 #define up32(v) (((v)+31) & -32)
567 #define down32(v) ((v) & -32)
568 #define div32(v) ((v)>>5)
569 #define mod32(v) ((v) & 31)
571 #define up64(v) (((v)+63) & -64)
572 #define down64(v) ((v) & -64)
573 #define div64(v) ((v)>>6)
574 #define mod64(v) ((v) & 63)
576 #define upx(x,v) (((v)+(x)-1) & -(x))
577 #define downx(x,v) ((v) & -(x))
578 #define modx(x,v) ((v) & ((x)-1))
580 /* if x1 is not a constant, this macro won't make real sense :-) */
582 #define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \
583 "d" (x2), "d" ((long)((x1)/0x100000000ULL)), "0" ((long)(x1))); res;})
585 /* We know a bit about the numbers, so we can do it this way */
586 #define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \
587 ((((long)((unsigned long long)x1 >> 8) % x2) << 8) / x2))
590 #define highw(x) ((u_long)(x)>>16 & 0xffff)
591 #define loww(x) ((u_long)(x) & 0xffff)
593 #define custom amiga_custom
595 #define VBlankOn() custom.intena = IF_SETCLR|IF_COPER
596 #define VBlankOff() custom.intena = IF_COPER
600 * Chip RAM we reserve for the Frame Buffer
602 * This defines the Maximum Virtual Screen Size
603 * (Setable per kernel options?)
606 #define VIDEOMEMSIZE_AGA_2M (1310720) /* AGA (2MB) : max 1280*1024*256 */
607 #define VIDEOMEMSIZE_AGA_1M (786432) /* AGA (1MB) : max 1024*768*256 */
608 #define VIDEOMEMSIZE_ECS_2M (655360) /* ECS (2MB) : max 1280*1024*16 */
609 #define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */
610 #define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */
612 #define SPRITEMEMSIZE (64*64/4) /* max 64*64*4 */
613 #define DUMMYSPRITEMEMSIZE (8)
614 static u_long spritememory;
616 #define CHIPRAM_SAFETY_LIMIT (16384)
618 static u_long videomemory;
621 * This is the earliest allowed start of fetching display data.
622 * Only if you really want no hardware cursor and audio,
623 * set this to 128, but let it better at 192
626 static u_long min_fstrt = 192;
628 #define assignchunk(name, type, ptr, size) \
630 (name) = (type)(ptr); \
636 * Copper Instructions
639 #define CMOVE(val, reg) (CUSTOM_OFS(reg)<<16 | (val))
640 #define CMOVE2(val, reg) ((CUSTOM_OFS(reg)+2)<<16 | (val))
641 #define CWAIT(x, y) (((y) & 0x1fe)<<23 | ((x) & 0x7f0)<<13 | 0x0001fffe)
642 #define CEND (0xfffffffe)
650 static struct copdisplay {
657 static u_short currentcop = 0;
660 * Hardware Cursor API Definitions
661 * These used to be in linux/fb.h, but were preliminary and used by
665 #define FBIOGET_FCURSORINFO 0x4607
666 #define FBIOGET_VCURSORINFO 0x4608
667 #define FBIOPUT_VCURSORINFO 0x4609
668 #define FBIOGET_CURSORSTATE 0x460A
669 #define FBIOPUT_CURSORSTATE 0x460B
672 struct fb_fix_cursorinfo {
673 __u16 crsr_width; /* width and height of the cursor in */
674 __u16 crsr_height; /* pixels (zero if no cursor) */
675 __u16 crsr_xsize; /* cursor size in display pixels */
677 __u16 crsr_color1; /* colormap entry for cursor color1 */
678 __u16 crsr_color2; /* colormap entry for cursor color2 */
681 struct fb_var_cursorinfo {
686 __u8 data[1]; /* field with [height][width] */
689 struct fb_cursorstate {
695 #define FB_CURSOR_OFF 0
696 #define FB_CURSOR_ON 1
697 #define FB_CURSOR_FLASH 2
704 static int cursorrate = 20; /* Number of frames/flash toggle */
705 static u_short cursorstate = -1;
706 static u_short cursormode = FB_CURSOR_OFF;
708 static u_short *lofsprite, *shfsprite, *dummysprite;
714 static struct amifb_par {
718 int xres; /* vmode */
719 int yres; /* vmode */
720 int vxres; /* vmode */
721 int vyres; /* vmode */
722 int xoffset; /* vmode */
723 int yoffset; /* vmode */
724 u_short bpp; /* vmode */
725 u_short clk_shift; /* vmode */
726 u_short line_shift; /* vmode */
727 int vmode; /* vmode */
728 u_short diwstrt_h; /* vmode */
729 u_short diwstop_h; /* vmode */
730 u_short diwstrt_v; /* vmode */
731 u_short diwstop_v; /* vmode */
732 u_long next_line; /* modulo for next line */
733 u_long next_plane; /* modulo for next plane */
738 short crsr_x; /* movecursor */
739 short crsr_y; /* movecursor */
747 /* OCS Hardware Registers */
749 u_long bplpt0; /* vmode, pan (Note: physical address) */
750 u_long bplpt0wrap; /* vmode, pan (Note: physical address) */
755 u_short bplcon0; /* vmode */
756 u_short bplcon1; /* vmode */
757 u_short htotal; /* vmode */
758 u_short vtotal; /* vmode */
760 /* Additional ECS Hardware Registers */
762 u_short bplcon3; /* vmode */
763 u_short beamcon0; /* vmode */
764 u_short hsstrt; /* vmode */
765 u_short hsstop; /* vmode */
766 u_short hbstrt; /* vmode */
767 u_short hbstop; /* vmode */
768 u_short vsstrt; /* vmode */
769 u_short vsstop; /* vmode */
770 u_short vbstrt; /* vmode */
771 u_short vbstop; /* vmode */
772 u_short hcenter; /* vmode */
774 /* Additional AGA Hardware Registers */
776 u_short fmode; /* vmode */
780 static struct fb_info fb_info = {
783 .visual = FB_VISUAL_PSEUDOCOLOR,
784 .accel = FB_ACCEL_AMIGABLITT
790 * Saved color entry 0 so we can restore it when unblanking
793 static u_char red0, green0, blue0;
796 #if defined(CONFIG_FB_AMIGA_ECS)
797 static u_short ecs_palette[32];
802 * Latches for Display Changes during VBlank
805 static u_short do_vmode_full = 0; /* Change the Video Mode */
806 static u_short do_vmode_pan = 0; /* Update the Video Mode */
807 static short do_blank = 0; /* (Un)Blank the Screen (±1) */
808 static u_short do_cursor = 0; /* Move the Cursor */
815 static u_short is_blanked = 0; /* Screen is Blanked */
816 static u_short is_lace = 0; /* Screen is laced */
819 * Predefined Video Modes
823 static struct fb_videomode ami_modedb[] __initdata = {
826 * AmigaOS Video Modes
828 * If you change these, make sure to update DEFMODE_* as well!
832 /* 640x200, 15 kHz, 60 Hz (NTSC) */
833 "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2,
834 FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
836 /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
837 "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4,
838 FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
840 /* 640x256, 15 kHz, 50 Hz (PAL) */
841 "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2,
842 FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
844 /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
845 "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4,
846 FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
848 /* 640x480, 29 kHz, 57 Hz */
849 "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8,
850 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
852 /* 640x960, 29 kHz, 57 Hz interlaced */
853 "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, 16,
854 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
856 /* 640x200, 15 kHz, 72 Hz */
857 "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5,
858 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
860 /* 640x400, 15 kHz, 72 Hz interlaced */
861 "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, 10,
862 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
864 /* 640x400, 29 kHz, 68 Hz */
865 "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8,
866 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
868 /* 640x800, 29 kHz, 68 Hz interlaced */
869 "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, 16,
870 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
872 /* 800x300, 23 kHz, 70 Hz */
873 "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7,
874 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
876 /* 800x600, 23 kHz, 70 Hz interlaced */
877 "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, 14,
878 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
880 /* 640x200, 27 kHz, 57 Hz doublescan */
881 "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4,
882 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
884 /* 640x400, 27 kHz, 57 Hz */
885 "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7,
886 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
888 /* 640x800, 27 kHz, 57 Hz interlaced */
889 "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, 14,
890 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
892 /* 640x256, 27 kHz, 47 Hz doublescan */
893 "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4,
894 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
896 /* 640x512, 27 kHz, 47 Hz */
897 "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7,
898 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
900 /* 640x1024, 27 kHz, 47 Hz interlaced */
901 "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, 14,
902 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
910 /* 640x480, 31 kHz, 60 Hz (VGA) */
911 "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2,
912 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
914 /* 640x400, 31 kHz, 70 Hz (VGA) */
915 "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2,
916 FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
923 * These modes don't work yet because there's no A2024 driver.
927 /* 1024x800, 10 Hz */
928 "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,
929 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
931 /* 1024x800, 15 Hz */
932 "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,
933 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
938 #define NUM_TOTAL_MODES ARRAY_SIZE(ami_modedb)
940 static char *mode_option __initdata = NULL;
941 static int round_down_bpp = 1; /* for mode probing */
948 #define DEFMODE_PAL 2 /* "pal" for PAL OCS/ECS */
949 #define DEFMODE_NTSC 0 /* "ntsc" for NTSC OCS/ECS */
950 #define DEFMODE_AMBER_PAL 3 /* "pal-lace" for flicker fixed PAL (A3000) */
951 #define DEFMODE_AMBER_NTSC 1 /* "ntsc-lace" for flicker fixed NTSC (A3000) */
952 #define DEFMODE_AGA 19 /* "vga70" for AGA */
955 static int amifb_ilbm = 0; /* interleaved or normal bitplanes */
956 static int amifb_inverse = 0;
960 * Macros for the conversion from real world values to hardware register
963 * This helps us to keep our attention on the real stuff...
965 * Hardware limits for AGA:
967 * parameter min max step
968 * --------- --- ---- ----
990 * Horizontal values are in 35 ns (SHRES) pixels
991 * Vertical values are in half scanlines
994 /* bplcon1 (smooth scrolling) */
996 #define hscroll2hw(hscroll) \
997 (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \
998 ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))
1000 /* diwstrt/diwstop/diwhigh (visible display window) */
1002 #define diwstrt2hw(diwstrt_h, diwstrt_v) \
1003 (((diwstrt_v)<<7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
1004 #define diwstop2hw(diwstop_h, diwstop_v) \
1005 (((diwstop_v)<<7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
1006 #define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \
1007 (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \
1008 ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \
1009 ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007))
1011 /* ddfstrt/ddfstop (display DMA) */
1013 #define ddfstrt2hw(ddfstrt) div8(ddfstrt)
1014 #define ddfstop2hw(ddfstop) div8(ddfstop)
1016 /* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */
1018 #define hsstrt2hw(hsstrt) (div8(hsstrt))
1019 #define hsstop2hw(hsstop) (div8(hsstop))
1020 #define htotal2hw(htotal) (div8(htotal)-1)
1021 #define vsstrt2hw(vsstrt) (div2(vsstrt))
1022 #define vsstop2hw(vsstop) (div2(vsstop))
1023 #define vtotal2hw(vtotal) (div2(vtotal)-1)
1024 #define hcenter2hw(htotal) (div8(htotal))
1026 /* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
1028 #define hbstrt2hw(hbstrt) (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))
1029 #define hbstop2hw(hbstop) (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff))
1030 #define vbstrt2hw(vbstrt) (div2(vbstrt))
1031 #define vbstop2hw(vbstop) (div2(vbstop))
1035 #define rgb2hw8_high(red, green, blue) \
1036 (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4))
1037 #define rgb2hw8_low(red, green, blue) \
1038 (((red & 0x0f)<<8) | ((green & 0x0f)<<4) | (blue & 0x0f))
1039 #define rgb2hw4(red, green, blue) \
1040 (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4))
1041 #define rgb2hw2(red, green, blue) \
1042 (((red & 0xc0)<<4) | (green & 0xc0) | ((blue & 0xc0)>>4))
1044 /* sprpos/sprctl (sprite positioning) */
1046 #define spr2hw_pos(start_v, start_h) \
1047 (((start_v)<<7&0xff00) | ((start_h)>>3&0x00ff))
1048 #define spr2hw_ctl(start_v, start_h, stop_v) \
1049 (((stop_v)<<7&0xff00) | ((start_v)>>4&0x0040) | ((stop_v)>>5&0x0020) | \
1050 ((start_h)<<3&0x0018) | ((start_v)>>7&0x0004) | ((stop_v)>>8&0x0002) | \
1051 ((start_h)>>2&0x0001))
1053 /* get current vertical position of beam */
1054 #define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe))
1057 * Copper Initialisation List
1060 #define COPINITSIZE (sizeof(copins)*40)
1067 * Long Frame/Short Frame Copper List
1068 * Don't change the order, build_copper()/rebuild_copper() rely on this
1071 #define COPLISTSIZE (sizeof(copins)*64)
1074 cop_wait, cop_bplcon0,
1075 cop_spr0ptrh, cop_spr0ptrl,
1076 cop_diwstrt, cop_diwstop,
1081 * Pixel modes for Bitplanes and Sprites
1084 static u_short bplpixmode[3] = {
1085 BPC0_SHRES, /* 35 ns */
1086 BPC0_HIRES, /* 70 ns */
1090 static u_short sprpixmode[3] = {
1091 BPC3_SPRES1 | BPC3_SPRES0, /* 35 ns */
1092 BPC3_SPRES1, /* 70 ns */
1093 BPC3_SPRES0 /* 140 ns */
1097 * Fetch modes for Bitplanes and Sprites
1100 static u_short bplfetchmode[3] = {
1102 FMODE_BPL32, /* 2x */
1103 FMODE_BPAGEM | FMODE_BPL32 /* 4x */
1106 static u_short sprfetchmode[3] = {
1108 FMODE_SPR32, /* 2x */
1109 FMODE_SPAGEM | FMODE_SPR32 /* 4x */
1114 * Interface used by the world
1117 int amifb_setup(char*);
1119 static int amifb_check_var(struct fb_var_screeninfo *var,
1120 struct fb_info *info);
1121 static int amifb_set_par(struct fb_info *info);
1122 static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green,
1123 unsigned blue, unsigned transp,
1124 struct fb_info *info);
1125 static int amifb_blank(int blank, struct fb_info *info);
1126 static int amifb_pan_display(struct fb_var_screeninfo *var,
1127 struct fb_info *info);
1128 static void amifb_fillrect(struct fb_info *info,
1129 const struct fb_fillrect *rect);
1130 static void amifb_copyarea(struct fb_info *info,
1131 const struct fb_copyarea *region);
1132 static void amifb_imageblit(struct fb_info *info,
1133 const struct fb_image *image);
1134 static int amifb_ioctl(struct inode *inode, struct file *file,
1135 unsigned int cmd, unsigned long arg,
1136 struct fb_info *info);
1140 * Interface to the low level console driver
1143 int amifb_init(void);
1144 static void amifb_deinit(void);
1150 static int flash_cursor(void);
1151 static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
1152 static u_long chipalloc(u_long size);
1153 static void chipfree(void);
1159 static int ami_decode_var(struct fb_var_screeninfo *var,
1160 struct amifb_par *par);
1161 static int ami_encode_var(struct fb_var_screeninfo *var,
1162 struct amifb_par *par);
1163 static void ami_pan_var(struct fb_var_screeninfo *var);
1164 static int ami_update_par(void);
1165 static void ami_update_display(void);
1166 static void ami_init_display(void);
1167 static void ami_do_blank(void);
1168 static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix);
1169 static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data);
1170 static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data);
1171 static int ami_get_cursorstate(struct fb_cursorstate *state);
1172 static int ami_set_cursorstate(struct fb_cursorstate *state);
1173 static void ami_set_sprite(void);
1174 static void ami_init_copper(void);
1175 static void ami_reinit_copper(void);
1176 static void ami_build_copper(void);
1177 static void ami_rebuild_copper(void);
1180 static struct fb_ops amifb_ops = {
1181 .owner = THIS_MODULE,
1182 .fb_check_var = amifb_check_var,
1183 .fb_set_par = amifb_set_par,
1184 .fb_setcolreg = amifb_setcolreg,
1185 .fb_blank = amifb_blank,
1186 .fb_pan_display = amifb_pan_display,
1187 .fb_fillrect = amifb_fillrect,
1188 .fb_copyarea = amifb_copyarea,
1189 .fb_imageblit = amifb_imageblit,
1190 .fb_ioctl = amifb_ioctl,
1193 static void __init amifb_setup_mcap(char *spec)
1196 int vmin, vmax, hmin, hmax;
1198 /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
1199 * <V*> vertical freq. in Hz
1200 * <H*> horizontal freq. in kHz
1203 if (!(p = strsep(&spec, ";")) || !*p)
1205 vmin = simple_strtoul(p, NULL, 10);
1208 if (!(p = strsep(&spec, ";")) || !*p)
1210 vmax = simple_strtoul(p, NULL, 10);
1211 if (vmax <= 0 || vmax <= vmin)
1213 if (!(p = strsep(&spec, ";")) || !*p)
1215 hmin = 1000 * simple_strtoul(p, NULL, 10);
1218 if (!(p = strsep(&spec, "")) || !*p)
1220 hmax = 1000 * simple_strtoul(p, NULL, 10);
1221 if (hmax <= 0 || hmax <= hmin)
1224 fb_info.monspecs.vfmin = vmin;
1225 fb_info.monspecs.vfmax = vmax;
1226 fb_info.monspecs.hfmin = hmin;
1227 fb_info.monspecs.hfmax = hmax;
1230 int __init amifb_setup(char *options)
1234 if (!options || !*options)
1237 while ((this_opt = strsep(&options, ",")) != NULL) {
1240 if (!strcmp(this_opt, "inverse")) {
1243 } else if (!strcmp(this_opt, "ilbm"))
1245 else if (!strncmp(this_opt, "monitorcap:", 11))
1246 amifb_setup_mcap(this_opt+11);
1247 else if (!strncmp(this_opt, "fstart:", 7))
1248 min_fstrt = simple_strtoul(this_opt+7, NULL, 0);
1250 mode_option = this_opt;
1260 static int amifb_check_var(struct fb_var_screeninfo *var,
1261 struct fb_info *info)
1264 struct amifb_par par;
1266 /* Validate wanted screen parameters */
1267 if ((err = ami_decode_var(var, &par)))
1270 /* Encode (possibly rounded) screen parameters */
1271 ami_encode_var(var, &par);
1276 static int amifb_set_par(struct fb_info *info)
1278 struct amifb_par *par = (struct amifb_par *)info->par;
1283 /* Decode wanted screen parameters */
1284 ami_decode_var(&info->var, par);
1286 /* Set new videomode */
1289 /* Set VBlank trigger */
1292 /* Update fix for new screen parameters */
1293 if (par->bpp == 1) {
1294 info->fix.type = FB_TYPE_PACKED_PIXELS;
1295 info->fix.type_aux = 0;
1296 } else if (amifb_ilbm) {
1297 info->fix.type = FB_TYPE_INTERLEAVED_PLANES;
1298 info->fix.type_aux = par->next_line;
1300 info->fix.type = FB_TYPE_PLANES;
1301 info->fix.type_aux = 0;
1303 info->fix.line_length = div8(upx(16<<maxfmode, par->vxres));
1305 if (par->vmode & FB_VMODE_YWRAP) {
1306 info->fix.ywrapstep = 1;
1307 info->fix.xpanstep = 0;
1308 info->fix.ypanstep = 0;
1309 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP |
1310 FBINFO_READS_FAST; /* override SCROLL_REDRAW */
1312 info->fix.ywrapstep = 0;
1313 if (par->vmode & FB_VMODE_SMOOTH_XPAN)
1314 info->fix.xpanstep = 1;
1316 info->fix.xpanstep = 16<<maxfmode;
1317 info->fix.ypanstep = 1;
1318 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1325 * Pan or Wrap the Display
1327 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
1330 static int amifb_pan_display(struct fb_var_screeninfo *var,
1331 struct fb_info *info)
1333 if (var->vmode & FB_VMODE_YWRAP) {
1334 if (var->yoffset < 0 ||
1335 var->yoffset >= info->var.yres_virtual || var->xoffset)
1339 * TODO: There will be problems when xpan!=1, so some columns
1340 * on the right side will never be seen
1342 if (var->xoffset+info->var.xres > upx(16<<maxfmode, info->var.xres_virtual) ||
1343 var->yoffset+info->var.yres > info->var.yres_virtual)
1347 info->var.xoffset = var->xoffset;
1348 info->var.yoffset = var->yoffset;
1349 if (var->vmode & FB_VMODE_YWRAP)
1350 info->var.vmode |= FB_VMODE_YWRAP;
1352 info->var.vmode &= ~FB_VMODE_YWRAP;
1357 #if BITS_PER_LONG == 32
1358 #define BYTES_PER_LONG 4
1359 #define SHIFT_PER_LONG 5
1360 #elif BITS_PER_LONG == 64
1361 #define BYTES_PER_LONG 8
1362 #define SHIFT_PER_LONG 6
1364 #define Please update me
1369 * Compose two values, using a bitmask as decision value
1370 * This is equivalent to (a & mask) | (b & ~mask)
1373 static inline unsigned long comp(unsigned long a, unsigned long b,
1376 return ((a ^ b) & mask) ^ b;
1380 static inline unsigned long xor(unsigned long a, unsigned long b,
1383 return (a & mask) ^ b;
1388 * Unaligned forward bit copy using 32-bit or 64-bit memory accesses
1391 static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
1394 unsigned long first, last;
1395 int shift = dst_idx-src_idx, left, right;
1396 unsigned long d0, d1;
1402 shift = dst_idx-src_idx;
1403 first = ~0UL >> dst_idx;
1404 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
1407 // Same alignment for source and dest
1409 if (dst_idx+n <= BITS_PER_LONG) {
1413 *dst = comp(*src, *dst, first);
1415 // Multiple destination words
1418 *dst = comp(*src, *dst, first);
1421 n -= BITS_PER_LONG-dst_idx;
1442 *dst = comp(*src, *dst, last);
1445 // Different alignment for source and dest
1447 right = shift & (BITS_PER_LONG-1);
1448 left = -shift & (BITS_PER_LONG-1);
1450 if (dst_idx+n <= BITS_PER_LONG) {
1451 // Single destination word
1455 // Single source word
1456 *dst = comp(*src >> right, *dst, first);
1457 } else if (src_idx+n <= BITS_PER_LONG) {
1458 // Single source word
1459 *dst = comp(*src << left, *dst, first);
1464 *dst = comp(d0 << left | d1 >> right, *dst,
1468 // Multiple destination words
1472 // Single source word
1473 *dst = comp(d0 >> right, *dst, first);
1475 n -= BITS_PER_LONG-dst_idx;
1479 *dst = comp(d0 << left | d1 >> right, *dst,
1483 n -= BITS_PER_LONG-dst_idx;
1487 m = n % BITS_PER_LONG;
1491 *dst++ = d0 << left | d1 >> right;
1494 *dst++ = d0 << left | d1 >> right;
1497 *dst++ = d0 << left | d1 >> right;
1500 *dst++ = d0 << left | d1 >> right;
1506 *dst++ = d0 << left | d1 >> right;
1513 // Single source word
1514 *dst = comp(d0 << left, *dst, last);
1518 *dst = comp(d0 << left | d1 >> right,
1528 * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses
1531 static void bitcpy_rev(unsigned long *dst, int dst_idx,
1532 const unsigned long *src, int src_idx, u32 n)
1534 unsigned long first, last;
1535 int shift = dst_idx-src_idx, left, right;
1536 unsigned long d0, d1;
1542 dst += (n-1)/BITS_PER_LONG;
1543 src += (n-1)/BITS_PER_LONG;
1544 if ((n-1) % BITS_PER_LONG) {
1545 dst_idx += (n-1) % BITS_PER_LONG;
1546 dst += dst_idx >> SHIFT_PER_LONG;
1547 dst_idx &= BITS_PER_LONG-1;
1548 src_idx += (n-1) % BITS_PER_LONG;
1549 src += src_idx >> SHIFT_PER_LONG;
1550 src_idx &= BITS_PER_LONG-1;
1553 shift = dst_idx-src_idx;
1554 first = ~0UL << (BITS_PER_LONG-1-dst_idx);
1555 last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
1558 // Same alignment for source and dest
1560 if ((unsigned long)dst_idx+1 >= n) {
1564 *dst = comp(*src, *dst, first);
1566 // Multiple destination words
1569 *dst = comp(*src, *dst, first);
1593 *dst = comp(*src, *dst, last);
1596 // Different alignment for source and dest
1598 right = shift & (BITS_PER_LONG-1);
1599 left = -shift & (BITS_PER_LONG-1);
1601 if ((unsigned long)dst_idx+1 >= n) {
1602 // Single destination word
1606 // Single source word
1607 *dst = comp(*src << left, *dst, first);
1608 } else if (1+(unsigned long)src_idx >= n) {
1609 // Single source word
1610 *dst = comp(*src >> right, *dst, first);
1615 *dst = comp(d0 >> right | d1 << left, *dst,
1619 // Multiple destination words
1623 // Single source word
1624 *dst = comp(d0 << left, *dst, first);
1630 *dst = comp(d0 >> right | d1 << left, *dst,
1638 m = n % BITS_PER_LONG;
1642 *dst-- = d0 >> right | d1 << left;
1645 *dst-- = d0 >> right | d1 << left;
1648 *dst-- = d0 >> right | d1 << left;
1651 *dst-- = d0 >> right | d1 << left;
1657 *dst-- = d0 >> right | d1 << left;
1664 // Single source word
1665 *dst = comp(d0 >> right, *dst, last);
1669 *dst = comp(d0 >> right | d1 << left,
1679 * Unaligned forward inverting bit copy using 32-bit or 64-bit memory
1683 static void bitcpy_not(unsigned long *dst, int dst_idx,
1684 const unsigned long *src, int src_idx, u32 n)
1686 unsigned long first, last;
1687 int shift = dst_idx-src_idx, left, right;
1688 unsigned long d0, d1;
1694 shift = dst_idx-src_idx;
1695 first = ~0UL >> dst_idx;
1696 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
1699 // Same alignment for source and dest
1701 if (dst_idx+n <= BITS_PER_LONG) {
1705 *dst = comp(~*src, *dst, first);
1707 // Multiple destination words
1710 *dst = comp(~*src, *dst, first);
1713 n -= BITS_PER_LONG-dst_idx;
1734 *dst = comp(~*src, *dst, last);
1737 // Different alignment for source and dest
1739 right = shift & (BITS_PER_LONG-1);
1740 left = -shift & (BITS_PER_LONG-1);
1742 if (dst_idx+n <= BITS_PER_LONG) {
1743 // Single destination word
1747 // Single source word
1748 *dst = comp(~*src >> right, *dst, first);
1749 } else if (src_idx+n <= BITS_PER_LONG) {
1750 // Single source word
1751 *dst = comp(~*src << left, *dst, first);
1756 *dst = comp(d0 << left | d1 >> right, *dst,
1760 // Multiple destination words
1764 // Single source word
1765 *dst = comp(d0 >> right, *dst, first);
1767 n -= BITS_PER_LONG-dst_idx;
1771 *dst = comp(d0 << left | d1 >> right, *dst,
1775 n -= BITS_PER_LONG-dst_idx;
1779 m = n % BITS_PER_LONG;
1783 *dst++ = d0 << left | d1 >> right;
1786 *dst++ = d0 << left | d1 >> right;
1789 *dst++ = d0 << left | d1 >> right;
1792 *dst++ = d0 << left | d1 >> right;
1798 *dst++ = d0 << left | d1 >> right;
1805 // Single source word
1806 *dst = comp(d0 << left, *dst, last);
1810 *dst = comp(d0 << left | d1 >> right,
1820 * Unaligned 32-bit pattern fill using 32/64-bit memory accesses
1823 static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
1825 unsigned long val = pat;
1826 unsigned long first, last;
1831 #if BITS_PER_LONG == 64
1835 first = ~0UL >> dst_idx;
1836 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
1838 if (dst_idx+n <= BITS_PER_LONG) {
1842 *dst = comp(val, *dst, first);
1844 // Multiple destination words
1847 *dst = comp(val, *dst, first);
1849 n -= BITS_PER_LONG-dst_idx;
1870 *dst = comp(val, *dst, last);
1876 * Unaligned 32-bit pattern xor using 32/64-bit memory accesses
1879 static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
1881 unsigned long val = pat;
1882 unsigned long first, last;
1887 #if BITS_PER_LONG == 64
1891 first = ~0UL >> dst_idx;
1892 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
1894 if (dst_idx+n <= BITS_PER_LONG) {
1898 *dst = xor(val, *dst, first);
1900 // Multiple destination words
1903 *dst = xor(val, *dst, first);
1905 n -= BITS_PER_LONG-dst_idx;
1922 *dst = xor(val, *dst, last);
1926 static inline void fill_one_line(int bpp, unsigned long next_plane,
1927 unsigned long *dst, int dst_idx, u32 n,
1931 dst += dst_idx >> SHIFT_PER_LONG;
1932 dst_idx &= (BITS_PER_LONG-1);
1933 bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n);
1937 dst_idx += next_plane*8;
1941 static inline void xor_one_line(int bpp, unsigned long next_plane,
1942 unsigned long *dst, int dst_idx, u32 n,
1946 dst += dst_idx >> SHIFT_PER_LONG;
1947 dst_idx &= (BITS_PER_LONG-1);
1948 bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n);
1952 dst_idx += next_plane*8;
1957 static void amifb_fillrect(struct fb_info *info,
1958 const struct fb_fillrect *rect)
1960 struct amifb_par *par = (struct amifb_par *)info->par;
1961 int dst_idx, x2, y2;
1965 if (!rect->width || !rect->height)
1969 * We could use hardware clipping but on many cards you get around
1970 * hardware clipping by writing to framebuffer directly.
1972 x2 = rect->dx + rect->width;
1973 y2 = rect->dy + rect->height;
1974 x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
1975 y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
1976 width = x2 - rect->dx;
1977 height = y2 - rect->dy;
1979 dst = (unsigned long *)
1980 ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
1981 dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
1982 dst_idx += rect->dy*par->next_line*8+rect->dx;
1984 switch (rect->rop) {
1986 fill_one_line(info->var.bits_per_pixel,
1987 par->next_plane, dst, dst_idx, width,
1992 xor_one_line(info->var.bits_per_pixel, par->next_plane,
1993 dst, dst_idx, width, rect->color);
1996 dst_idx += par->next_line*8;
2000 static inline void copy_one_line(int bpp, unsigned long next_plane,
2001 unsigned long *dst, int dst_idx,
2002 unsigned long *src, int src_idx, u32 n)
2005 dst += dst_idx >> SHIFT_PER_LONG;
2006 dst_idx &= (BITS_PER_LONG-1);
2007 src += src_idx >> SHIFT_PER_LONG;
2008 src_idx &= (BITS_PER_LONG-1);
2009 bitcpy(dst, dst_idx, src, src_idx, n);
2012 dst_idx += next_plane*8;
2013 src_idx += next_plane*8;
2017 static inline void copy_one_line_rev(int bpp, unsigned long next_plane,
2018 unsigned long *dst, int dst_idx,
2019 unsigned long *src, int src_idx, u32 n)
2022 dst += dst_idx >> SHIFT_PER_LONG;
2023 dst_idx &= (BITS_PER_LONG-1);
2024 src += src_idx >> SHIFT_PER_LONG;
2025 src_idx &= (BITS_PER_LONG-1);
2026 bitcpy_rev(dst, dst_idx, src, src_idx, n);
2029 dst_idx += next_plane*8;
2030 src_idx += next_plane*8;
2035 static void amifb_copyarea(struct fb_info *info,
2036 const struct fb_copyarea *area)
2038 struct amifb_par *par = (struct amifb_par *)info->par;
2040 u32 dx, dy, sx, sy, width, height;
2041 unsigned long *dst, *src;
2042 int dst_idx, src_idx;
2045 /* clip the destination */
2046 x2 = area->dx + area->width;
2047 y2 = area->dy + area->height;
2048 dx = area->dx > 0 ? area->dx : 0;
2049 dy = area->dy > 0 ? area->dy : 0;
2050 x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
2051 y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
2056 sx = area->sx + (dx - area->dx);
2057 sy = area->sy + (dy - area->dy);
2059 /* the source must be completely inside the virtual screen */
2060 if (sx < 0 || sy < 0 || (sx + width) > info->var.xres_virtual ||
2061 (sy + height) > info->var.yres_virtual)
2064 if (dy > sy || (dy == sy && dx > sx)) {
2069 dst = (unsigned long *)
2070 ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
2072 dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
2074 dst_idx += dy*par->next_line*8+dx;
2075 src_idx += sy*par->next_line*8+sx;
2078 dst_idx -= par->next_line*8;
2079 src_idx -= par->next_line*8;
2080 copy_one_line_rev(info->var.bits_per_pixel,
2081 par->next_plane, dst, dst_idx, src,
2086 copy_one_line(info->var.bits_per_pixel,
2087 par->next_plane, dst, dst_idx, src,
2089 dst_idx += par->next_line*8;
2090 src_idx += par->next_line*8;
2096 static inline void expand_one_line(int bpp, unsigned long next_plane,
2097 unsigned long *dst, int dst_idx, u32 n,
2098 const u8 *data, u32 bgcolor, u32 fgcolor)
2100 const unsigned long *src;
2104 dst += dst_idx >> SHIFT_PER_LONG;
2105 dst_idx &= (BITS_PER_LONG-1);
2106 if ((bgcolor ^ fgcolor) & 1) {
2107 src = (unsigned long *)((unsigned long)data & ~(BYTES_PER_LONG-1));
2108 src_idx = ((unsigned long)data & (BYTES_PER_LONG-1))*8;
2110 bitcpy(dst, dst_idx, src, src_idx, n);
2112 bitcpy_not(dst, dst_idx, src, src_idx, n);
2115 bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n);
2120 dst_idx += next_plane*8;
2125 static void amifb_imageblit(struct fb_info *info, const struct fb_image *image)
2127 struct amifb_par *par = (struct amifb_par *)info->par;
2132 u32 dx, dy, width, height, pitch;
2135 * We could use hardware clipping but on many cards you get around
2136 * hardware clipping by writing to framebuffer directly like we are
2139 x2 = image->dx + image->width;
2140 y2 = image->dy + image->height;
2143 x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
2144 y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
2148 if (image->depth == 1) {
2149 dst = (unsigned long *)
2150 ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
2151 dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
2152 dst_idx += dy*par->next_line*8+dx;
2154 pitch = (image->width+7)/8;
2156 expand_one_line(info->var.bits_per_pixel,
2157 par->next_plane, dst, dst_idx, width,
2158 src, image->bg_color,
2160 dst_idx += par->next_line*8;
2164 c2p(info->screen_base, image->data, dx, dy, width, height,
2165 par->next_line, par->next_plane, image->width,
2166 info->var.bits_per_pixel);
2172 * Amiga Frame Buffer Specific ioctls
2175 static int amifb_ioctl(struct inode *inode, struct file *file,
2176 unsigned int cmd, unsigned long arg,
2177 struct fb_info *info)
2180 struct fb_fix_cursorinfo fix;
2181 struct fb_var_cursorinfo var;
2182 struct fb_cursorstate state;
2184 void __user *argp = (void __user *)arg;
2188 case FBIOGET_FCURSORINFO:
2189 i = ami_get_fix_cursorinfo(&crsr.fix);
2192 return copy_to_user(argp, &crsr.fix,
2193 sizeof(crsr.fix)) ? -EFAULT : 0;
2195 case FBIOGET_VCURSORINFO:
2196 i = ami_get_var_cursorinfo(&crsr.var,
2197 ((struct fb_var_cursorinfo __user *)arg)->data);
2200 return copy_to_user(argp, &crsr.var,
2201 sizeof(crsr.var)) ? -EFAULT : 0;
2203 case FBIOPUT_VCURSORINFO:
2204 if (copy_from_user(&crsr.var, argp, sizeof(crsr.var)))
2206 return ami_set_var_cursorinfo(&crsr.var,
2207 ((struct fb_var_cursorinfo __user *)arg)->data);
2209 case FBIOGET_CURSORSTATE:
2210 i = ami_get_cursorstate(&crsr.state);
2213 return copy_to_user(argp, &crsr.state,
2214 sizeof(crsr.state)) ? -EFAULT : 0;
2216 case FBIOPUT_CURSORSTATE:
2217 if (copy_from_user(&crsr.state, argp,
2218 sizeof(crsr.state)))
2220 return ami_set_cursorstate(&crsr.state);
2227 * Allocate, Clear and Align a Block of Chip Memory
2230 static u_long unaligned_chipptr = 0;
2232 static inline u_long __init chipalloc(u_long size)
2234 size += PAGE_SIZE-1;
2235 if (!(unaligned_chipptr = (u_long)amiga_chip_alloc(size,
2237 panic("No Chip RAM for frame buffer");
2238 memset((void *)unaligned_chipptr, 0, size);
2239 return PAGE_ALIGN(unaligned_chipptr);
2242 static inline void chipfree(void)
2244 if (unaligned_chipptr)
2245 amiga_chip_free((void *)unaligned_chipptr);
2253 int __init amifb_init(void)
2255 int tag, i, err = 0;
2260 char *option = NULL;
2262 if (fb_get_options("amifb", &option)) {
2266 amifb_setup(option);
2268 if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO))
2272 * We request all registers starting from bplpt[0]
2274 if (!request_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120,
2275 "amifb [Denise/Lisa]"))
2278 custom.dmacon = DMAF_ALL | DMAF_MASTER;
2280 switch (amiga_chipset) {
2281 #ifdef CONFIG_FB_AMIGA_OCS
2283 strcat(fb_info.fix.id, "OCS");
2286 maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */
2287 maxdepth[TAG_HIRES] = 4;
2288 maxdepth[TAG_LORES] = 6;
2289 maxfmode = TAG_FMODE_1;
2290 defmode = amiga_vblank == 50 ? DEFMODE_PAL
2292 fb_info.fix.smem_len = VIDEOMEMSIZE_OCS;
2294 #endif /* CONFIG_FB_AMIGA_OCS */
2296 #ifdef CONFIG_FB_AMIGA_ECS
2298 strcat(fb_info.fix.id, "ECS");
2300 maxdepth[TAG_SHRES] = 2;
2301 maxdepth[TAG_HIRES] = 4;
2302 maxdepth[TAG_LORES] = 6;
2303 maxfmode = TAG_FMODE_1;
2304 if (AMIGAHW_PRESENT(AMBER_FF))
2305 defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL
2306 : DEFMODE_AMBER_NTSC;
2308 defmode = amiga_vblank == 50 ? DEFMODE_PAL
2310 if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
2311 VIDEOMEMSIZE_ECS_1M)
2312 fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M;
2314 fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M;
2316 #endif /* CONFIG_FB_AMIGA_ECS */
2318 #ifdef CONFIG_FB_AMIGA_AGA
2320 strcat(fb_info.fix.id, "AGA");
2322 maxdepth[TAG_SHRES] = 8;
2323 maxdepth[TAG_HIRES] = 8;
2324 maxdepth[TAG_LORES] = 8;
2325 maxfmode = TAG_FMODE_4;
2326 defmode = DEFMODE_AGA;
2327 if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
2328 VIDEOMEMSIZE_AGA_1M)
2329 fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M;
2331 fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M;
2333 #endif /* CONFIG_FB_AMIGA_AGA */
2336 #ifdef CONFIG_FB_AMIGA_OCS
2337 printk("Unknown graphics chipset, defaulting to OCS\n");
2338 strcat(fb_info.fix.id, "Unknown");
2339 goto default_chipset;
2340 #else /* CONFIG_FB_AMIGA_OCS */
2343 #endif /* CONFIG_FB_AMIGA_OCS */
2348 * Calculate the Pixel Clock Values for this Machine
2352 u_long tmp = DIVUL(200000000000ULL, amiga_eclock);
2354 pixclock[TAG_SHRES] = (tmp + 4) / 8; /* SHRES: 35 ns / 28 MHz */
2355 pixclock[TAG_HIRES] = (tmp + 2) / 4; /* HIRES: 70 ns / 14 MHz */
2356 pixclock[TAG_LORES] = (tmp + 1) / 2; /* LORES: 140 ns / 7 MHz */
2360 * Replace the Tag Values with the Real Pixel Clock Values
2363 for (i = 0; i < NUM_TOTAL_MODES; i++) {
2364 struct fb_videomode *mode = &ami_modedb[i];
2365 tag = mode->pixclock;
2366 if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
2367 mode->pixclock = pixclock[tag];
2372 * These monitor specs are for a typical Amiga monitor (e.g. A1960)
2374 if (fb_info.monspecs.hfmin == 0) {
2375 fb_info.monspecs.hfmin = 15000;
2376 fb_info.monspecs.hfmax = 38000;
2377 fb_info.monspecs.vfmin = 49;
2378 fb_info.monspecs.vfmax = 90;
2381 fb_info.fbops = &amifb_ops;
2382 fb_info.par = ¤tpar;
2383 fb_info.flags = FBINFO_DEFAULT;
2385 if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb,
2386 NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
2392 chipptr = chipalloc(fb_info.fix.smem_len+
2398 assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len);
2399 assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
2400 assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
2401 assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
2402 assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);
2403 assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);
2404 assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);
2405 assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);
2408 * access the videomem with writethrough cache
2410 fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory);
2411 videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start,
2412 fb_info.fix.smem_len);
2414 printk("amifb: WARNING! unable to map videomem cached writethrough\n");
2415 videomemory = ZTWO_VADDR(fb_info.fix.smem_start);
2418 fb_info.screen_base = (char *)videomemory;
2419 memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
2422 * Enable Display DMA
2425 custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
2426 DMAF_BLITTER | DMAF_SPRITE;
2429 * Make sure the Copper has something to do
2434 if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,
2435 "fb vertb handler", ¤tpar)) {
2440 fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0);
2442 if (register_framebuffer(&fb_info) < 0) {
2447 printk("fb%d: %s frame buffer device, using %dK of video memory\n",
2448 fb_info.node, fb_info.fix.id, fb_info.fix.smem_len>>10);
2457 static void amifb_deinit(void)
2459 fb_dealloc_cmap(&fb_info.cmap);
2461 release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
2462 custom.dmacon = DMAF_ALL | DMAF_MASTER;
2467 * Blank the display.
2470 static int amifb_blank(int blank, struct fb_info *info)
2472 do_blank = blank ? blank : -1;
2478 * Flash the cursor (called by VBlank interrupt)
2481 static int flash_cursor(void)
2483 static int cursorcount = 1;
2485 if (cursormode == FB_CURSOR_FLASH) {
2486 if (!--cursorcount) {
2487 cursorstate = -cursorstate;
2488 cursorcount = cursorrate;
2497 * VBlank Display Interrupt
2500 static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
2502 if (do_vmode_pan || do_vmode_full)
2503 ami_update_display();
2510 ami_rebuild_copper();
2511 do_cursor = do_vmode_pan = 0;
2512 } else if (do_cursor) {
2526 if (do_vmode_full) {
2527 ami_reinit_copper();
2533 /* --------------------------- Hardware routines --------------------------- */
2536 * Get the video params out of `var'. If a value doesn't fit, round
2537 * it up, if it's too big, return -EINVAL.
2540 static int ami_decode_var(struct fb_var_screeninfo *var,
2541 struct amifb_par *par)
2543 u_short clk_shift, line_shift;
2544 u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;
2545 u_int htotal, vtotal;
2548 * Find a matching Pixel Clock
2551 for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++)
2552 if (var->pixclock <= pixclock[clk_shift])
2554 if (clk_shift > TAG_LORES) {
2555 DPRINTK("pixclock too high\n");
2558 par->clk_shift = clk_shift;
2561 * Check the Geometry Values
2564 if ((par->xres = var->xres) < 64)
2566 if ((par->yres = var->yres) < 64)
2568 if ((par->vxres = var->xres_virtual) < par->xres)
2569 par->vxres = par->xres;
2570 if ((par->vyres = var->yres_virtual) < par->yres)
2571 par->vyres = par->yres;
2573 par->bpp = var->bits_per_pixel;
2577 if (par->bpp > maxdepth[clk_shift]) {
2578 if (round_down_bpp && maxdepth[clk_shift])
2579 par->bpp = maxdepth[clk_shift];
2581 DPRINTK("invalid bpp\n");
2585 } else if (var->nonstd == FB_NONSTD_HAM) {
2588 if (par->bpp != 6) {
2591 if (par->bpp != 8 || !IS_AGA) {
2592 DPRINTK("invalid bpp for ham mode\n");
2597 DPRINTK("unknown nonstd mode\n");
2602 * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
2603 * checks failed and smooth scrolling is not possible
2606 par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN;
2607 switch (par->vmode & FB_VMODE_MASK) {
2608 case FB_VMODE_INTERLACED:
2611 case FB_VMODE_NONINTERLACED:
2614 case FB_VMODE_DOUBLE:
2616 DPRINTK("double mode only possible with aga\n");
2622 DPRINTK("unknown video mode\n");
2626 par->line_shift = line_shift;
2629 * Vertical and Horizontal Timings
2632 xres_n = par->xres<<clk_shift;
2633 yres_n = par->yres<<line_shift;
2634 par->htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<<clk_shift);
2635 par->vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<<line_shift)+1);
2638 par->bplcon3 = sprpixmode[clk_shift];
2641 if (var->sync & FB_SYNC_BROADCAST) {
2642 par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<<clk_shift);
2644 par->diwstop_h += mod4(var->hsync_len);
2646 par->diwstop_h = down4(par->diwstop_h);
2648 par->diwstrt_h = par->diwstop_h - xres_n;
2649 par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<<line_shift);
2650 par->diwstrt_v = par->diwstop_v - yres_n;
2651 if (par->diwstop_h >= par->htotal+8) {
2652 DPRINTK("invalid diwstop_h\n");
2655 if (par->diwstop_v > par->vtotal) {
2656 DPRINTK("invalid diwstop_v\n");
2661 /* Initialize sync with some reasonable values for pwrsave */
2672 if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) {
2673 /* PAL video mode */
2674 if (par->htotal != PAL_HTOTAL) {
2675 DPRINTK("htotal invalid for pal\n");
2678 if (par->diwstrt_h < PAL_DIWSTRT_H) {
2679 DPRINTK("diwstrt_h too low for pal\n");
2682 if (par->diwstrt_v < PAL_DIWSTRT_V) {
2683 DPRINTK("diwstrt_v too low for pal\n");
2686 htotal = PAL_HTOTAL>>clk_shift;
2687 vtotal = PAL_VTOTAL>>1;
2689 par->beamcon0 = BMC0_PAL;
2690 par->bplcon3 |= BPC3_BRDRBLNK;
2691 } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
2692 AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
2693 par->beamcon0 = BMC0_PAL;
2695 } else if (amiga_vblank != 50) {
2696 DPRINTK("pal not supported by this chipset\n");
2701 * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK
2702 * and NTSC activated, so than better let diwstop_h <= 1812
2704 if (par->htotal != NTSC_HTOTAL) {
2705 DPRINTK("htotal invalid for ntsc\n");
2708 if (par->diwstrt_h < NTSC_DIWSTRT_H) {
2709 DPRINTK("diwstrt_h too low for ntsc\n");
2712 if (par->diwstrt_v < NTSC_DIWSTRT_V) {
2713 DPRINTK("diwstrt_v too low for ntsc\n");
2716 htotal = NTSC_HTOTAL>>clk_shift;
2717 vtotal = NTSC_VTOTAL>>1;
2720 par->bplcon3 |= BPC3_BRDRBLNK;
2721 } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
2722 AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
2725 } else if (amiga_vblank != 60) {
2726 DPRINTK("ntsc not supported by this chipset\n");
2731 if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 ||
2732 par->diwstrt_v >= 512 || par->diwstop_v < 256) {
2733 DPRINTK("invalid position for display on ocs\n");
2737 } else if (!IS_OCS) {
2738 /* Programmable video mode */
2739 par->hsstrt = var->right_margin<<clk_shift;
2740 par->hsstop = (var->right_margin+var->hsync_len)<<clk_shift;
2741 par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift);
2743 par->diwstop_h = down4(par->diwstop_h) - 16;
2744 par->diwstrt_h = par->diwstop_h - xres_n;
2745 par->hbstop = par->diwstrt_h + 4;
2746 par->hbstrt = par->diwstop_h + 4;
2747 if (par->hbstrt >= par->htotal + 8)
2748 par->hbstrt -= par->htotal;
2749 par->hcenter = par->hsstrt + (par->htotal >> 1);
2750 par->vsstrt = var->lower_margin<<line_shift;
2751 par->vsstop = (var->lower_margin+var->vsync_len)<<line_shift;
2752 par->diwstop_v = par->vtotal;
2753 if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
2754 par->diwstop_v -= 2;
2755 par->diwstrt_v = par->diwstop_v - yres_n;
2756 par->vbstop = par->diwstrt_v - 2;
2757 par->vbstrt = par->diwstop_v - 2;
2758 if (par->vtotal > 2048) {
2759 DPRINTK("vtotal too high\n");
2762 if (par->htotal > 2048) {
2763 DPRINTK("htotal too high\n");
2766 par->bplcon3 |= BPC3_EXTBLKEN;
2767 par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
2768 BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
2769 BMC0_PAL | BMC0_VARCSYEN;
2770 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
2771 par->beamcon0 |= BMC0_HSYTRUE;
2772 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
2773 par->beamcon0 |= BMC0_VSYTRUE;
2774 if (var->sync & FB_SYNC_COMP_HIGH_ACT)
2775 par->beamcon0 |= BMC0_CSYTRUE;
2776 htotal = par->htotal>>clk_shift;
2777 vtotal = par->vtotal>>1;
2779 DPRINTK("only broadcast modes possible for ocs\n");
2784 * Checking the DMA timing
2787 fconst = 16<<maxfmode<<clk_shift;
2790 * smallest window start value without turn off other dma cycles
2791 * than sprite1-7, unless you change min_fstrt
2795 fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64);
2796 fstrt = downx(fconst, par->diwstrt_h-4) - fsize;
2797 if (fstrt < min_fstrt) {
2798 DPRINTK("fetch start too low\n");
2803 * smallest window start value where smooth scrolling is possible
2806 fstrt = downx(fconst, par->diwstrt_h-fconst+(1<<clk_shift)-4) - fsize;
2807 if (fstrt < min_fstrt)
2808 par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2810 maxfetchstop = down16(par->htotal - 80);
2812 fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst;
2813 fsize = upx(fconst, xres_n + modx(fconst, downx(1<<clk_shift, par->diwstrt_h-4)));
2814 if (fstrt + fsize > maxfetchstop)
2815 par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2817 fsize = upx(fconst, xres_n);
2818 if (fstrt + fsize > maxfetchstop) {
2819 DPRINTK("fetch stop too high\n");
2823 if (maxfmode + clk_shift <= 1) {
2824 fsize = up64(xres_n + fconst - 1);
2825 if (min_fstrt + fsize - 64 > maxfetchstop)
2826 par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2828 fsize = up64(xres_n);
2829 if (min_fstrt + fsize - 64 > maxfetchstop) {
2830 DPRINTK("fetch size too high\n");
2839 * Check if there is enough time to update the bitplane pointers for ywrap
2842 if (par->htotal-fsize-64 < par->bpp*64)
2843 par->vmode &= ~FB_VMODE_YWRAP;
2846 * Bitplane calculations and check the Memory Requirements
2850 par->next_plane = div8(upx(16<<maxfmode, par->vxres));
2851 par->next_line = par->bpp*par->next_plane;
2852 if (par->next_line * par->vyres > fb_info.fix.smem_len) {
2853 DPRINTK("too few video mem\n");
2857 par->next_line = div8(upx(16<<maxfmode, par->vxres));
2858 par->next_plane = par->vyres*par->next_line;
2859 if (par->next_plane * par->bpp > fb_info.fix.smem_len) {
2860 DPRINTK("too few video mem\n");
2866 * Hardware Register Values
2869 par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift];
2871 par->bplcon0 |= BPC0_ECSENA;
2873 par->bplcon0 |= BPC0_BPU3;
2875 par->bplcon0 |= par->bpp<<12;
2876 if (var->nonstd == FB_NONSTD_HAM)
2877 par->bplcon0 |= BPC0_HAM;
2878 if (var->sync & FB_SYNC_EXT)
2879 par->bplcon0 |= BPC0_ERSY;
2882 par->fmode = bplfetchmode[maxfmode];
2884 switch (par->vmode & FB_VMODE_MASK) {
2885 case FB_VMODE_INTERLACED:
2886 par->bplcon0 |= BPC0_LACE;
2888 case FB_VMODE_DOUBLE:
2890 par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
2894 if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {
2895 par->xoffset = var->xoffset;
2896 par->yoffset = var->yoffset;
2897 if (par->vmode & FB_VMODE_YWRAP) {
2898 if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres)
2899 par->xoffset = par->yoffset = 0;
2901 if (par->xoffset < 0 || par->xoffset > upx(16<<maxfmode, par->vxres-par->xres) ||
2902 par->yoffset < 0 || par->yoffset > par->vyres-par->yres)
2903 par->xoffset = par->yoffset = 0;
2906 par->xoffset = par->yoffset = 0;
2908 par->crsr.crsr_x = par->crsr.crsr_y = 0;
2909 par->crsr.spot_x = par->crsr.spot_y = 0;
2910 par->crsr.height = par->crsr.width = 0;
2912 #if 0 /* fbmon not done. uncomment for 2.5.x -brad */
2913 if (!fbmon_valid_timings(pixclock[clk_shift], htotal, vtotal,
2915 DPRINTK("mode doesn't fit for monitor\n");
2924 * Fill the `var' structure based on the values in `par' and maybe
2925 * other values read out of the hardware.
2928 static int ami_encode_var(struct fb_var_screeninfo *var,
2929 struct amifb_par *par)
2931 u_short clk_shift, line_shift;
2933 memset(var, 0, sizeof(struct fb_var_screeninfo));
2935 clk_shift = par->clk_shift;
2936 line_shift = par->line_shift;
2938 var->xres = par->xres;
2939 var->yres = par->yres;
2940 var->xres_virtual = par->vxres;
2941 var->yres_virtual = par->vyres;
2942 var->xoffset = par->xoffset;
2943 var->yoffset = par->yoffset;
2945 var->bits_per_pixel = par->bpp;
2948 var->red.offset = 0;
2949 var->red.msb_right = 0;
2950 var->red.length = par->bpp;
2951 if (par->bplcon0 & BPC0_HAM)
2952 var->red.length -= 2;
2953 var->blue = var->green = var->red;
2954 var->transp.offset = 0;
2955 var->transp.length = 0;
2956 var->transp.msb_right = 0;
2958 if (par->bplcon0 & BPC0_HAM)
2959 var->nonstd = FB_NONSTD_HAM;
2967 var->pixclock = pixclock[clk_shift];
2969 if (IS_AGA && par->fmode & FMODE_BSCAN2)
2970 var->vmode = FB_VMODE_DOUBLE;
2971 else if (par->bplcon0 & BPC0_LACE)
2972 var->vmode = FB_VMODE_INTERLACED;
2974 var->vmode = FB_VMODE_NONINTERLACED;
2976 if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) {
2977 var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift;
2978 var->right_margin = par->hsstrt>>clk_shift;
2979 var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
2980 var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift;
2981 var->lower_margin = par->vsstrt>>line_shift;
2982 var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len;
2984 if (par->beamcon0 & BMC0_HSYTRUE)
2985 var->sync |= FB_SYNC_HOR_HIGH_ACT;
2986 if (par->beamcon0 & BMC0_VSYTRUE)
2987 var->sync |= FB_SYNC_VERT_HIGH_ACT;
2988 if (par->beamcon0 & BMC0_CSYTRUE)
2989 var->sync |= FB_SYNC_COMP_HIGH_ACT;
2991 var->sync = FB_SYNC_BROADCAST;
2992 var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h);
2993 var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len;
2994 var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
2995 var->vsync_len = 4>>line_shift;
2996 var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len;
2997 var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres -
2998 var->lower_margin - var->vsync_len;
3001 if (par->bplcon0 & BPC0_ERSY)
3002 var->sync |= FB_SYNC_EXT;
3003 if (par->vmode & FB_VMODE_YWRAP)
3004 var->vmode |= FB_VMODE_YWRAP;
3011 * Pan or Wrap the Display
3013 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
3017 static void ami_pan_var(struct fb_var_screeninfo *var)
3019 struct amifb_par *par = ¤tpar;
3021 par->xoffset = var->xoffset;
3022 par->yoffset = var->yoffset;
3023 if (var->vmode & FB_VMODE_YWRAP)
3024 par->vmode |= FB_VMODE_YWRAP;
3026 par->vmode &= ~FB_VMODE_YWRAP;
3037 static int ami_update_par(void)
3039 struct amifb_par *par = ¤tpar;
3040 short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod;
3042 clk_shift = par->clk_shift;
3044 if (!(par->vmode & FB_VMODE_SMOOTH_XPAN))
3045 par->xoffset = upx(16<<maxfmode, par->xoffset);
3047 fconst = 16<<maxfmode<<clk_shift;
3048 vshift = modx(16<<maxfmode, par->xoffset);
3049 fstrt = par->diwstrt_h - (vshift<<clk_shift) - 4;
3050 fsize = (par->xres+vshift)<<clk_shift;
3051 shift = modx(fconst, fstrt);
3052 move = downx(2<<maxfmode, div8(par->xoffset));
3053 if (maxfmode + clk_shift > 1) {
3054 fstrt = downx(fconst, fstrt) - 64;
3055 fsize = upx(fconst, fsize);
3056 fstop = fstrt + fsize - fconst;
3058 mod = fstrt = downx(fconst, fstrt) - fconst;
3059 fstop = fstrt + upx(fconst, fsize) - 64;
3060 fsize = up64(fsize);
3061 fstrt = fstop - fsize + 64;
3062 if (fstrt < min_fstrt) {
3063 fstop += min_fstrt - fstrt;
3066 move = move - div8((mod-fstrt)>>clk_shift);
3068 mod = par->next_line - div8(fsize>>clk_shift);
3069 par->ddfstrt = fstrt;
3070 par->ddfstop = fstop;
3071 par->bplcon1 = hscroll2hw(shift);
3073 if (par->bplcon0 & BPC0_LACE)
3074 par->bpl2mod += par->next_line;
3075 if (IS_AGA && (par->fmode & FMODE_BSCAN2))
3076 par->bpl1mod = -div8(fsize>>clk_shift);
3078 par->bpl1mod = par->bpl2mod;
3081 par->bplpt0 = fb_info.fix.smem_start + par->next_line*par->yoffset + move;
3082 if (par->vmode & FB_VMODE_YWRAP) {
3083 if (par->yoffset > par->vyres-par->yres) {
3084 par->bplpt0wrap = fb_info.fix.smem_start + move;
3085 if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset))
3086 par->bplpt0wrap += par->next_line;
3090 par->bplpt0 = fb_info.fix.smem_start + move;
3092 if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
3093 par->bplpt0 += par->next_line;
3100 * Set a single color register. The values supplied are already
3101 * rounded down to the hardware's capabilities (according to the
3102 * entries in the var structure). Return != 0 for invalid regno.
3105 static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
3106 u_int transp, struct fb_info *info)
3111 } else if (currentpar.bplcon0 & BPC0_SHRES) {
3128 * Update the corresponding Hardware Color Register, unless it's Color
3129 * Register 0 and the screen is blanked.
3131 * VBlank is switched off to protect bplcon3 or ecs_palette[] from
3132 * being changed by ami_do_blank() during the VBlank.
3135 if (regno || !is_blanked) {
3136 #if defined(CONFIG_FB_AMIGA_AGA)
3138 u_short bplcon3 = currentpar.bplcon3;
3140 custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000);
3141 custom.color[regno&31] = rgb2hw8_high(red, green, blue);
3142 custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT;
3143 custom.color[regno&31] = rgb2hw8_low(red, green, blue);
3144 custom.bplcon3 = bplcon3;
3148 #if defined(CONFIG_FB_AMIGA_ECS)
3149 if (currentpar.bplcon0 & BPC0_SHRES) {
3150 u_short color, mask;
3154 color = rgb2hw2(red, green, blue);
3156 for (i = regno+12; i >= (int)regno; i -= 4)
3157 custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3158 mask <<=2; color >>= 2;
3159 regno = down16(regno)+mul4(mod4(regno));
3160 for (i = regno+3; i >= (int)regno; i--)
3161 custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3165 custom.color[regno] = rgb2hw4(red, green, blue);
3170 static void ami_update_display(void)
3172 struct amifb_par *par = ¤tpar;
3174 custom.bplcon1 = par->bplcon1;
3175 custom.bpl1mod = par->bpl1mod;
3176 custom.bpl2mod = par->bpl2mod;
3177 custom.ddfstrt = ddfstrt2hw(par->ddfstrt);
3178 custom.ddfstop = ddfstop2hw(par->ddfstop);
3182 * Change the video mode (called by VBlank interrupt)
3185 static void ami_init_display(void)
3187 struct amifb_par *par = ¤tpar;
3190 custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
3191 custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
3193 custom.bplcon3 = par->bplcon3;
3195 custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
3196 if (par->beamcon0 & BMC0_VARBEAMEN) {
3197 custom.htotal = htotal2hw(par->htotal);
3198 custom.hbstrt = hbstrt2hw(par->hbstrt);
3199 custom.hbstop = hbstop2hw(par->hbstop);
3200 custom.hsstrt = hsstrt2hw(par->hsstrt);
3201 custom.hsstop = hsstop2hw(par->hsstop);
3202 custom.hcenter = hcenter2hw(par->hcenter);
3203 custom.vtotal = vtotal2hw(par->vtotal);
3204 custom.vbstrt = vbstrt2hw(par->vbstrt);
3205 custom.vbstop = vbstop2hw(par->vbstop);
3206 custom.vsstrt = vsstrt2hw(par->vsstrt);
3207 custom.vsstop = vsstop2hw(par->vsstop);
3210 if (!IS_OCS || par->hsstop)
3211 custom.beamcon0 = par->beamcon0;
3213 custom.fmode = par->fmode;
3216 * The minimum period for audio depends on htotal
3219 amiga_audio_min_period = div16(par->htotal);
3221 is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
3224 i = custom.vposr >> 15;
3226 custom.vposw = custom.vposr | 0x8000;
3231 custom.vposw = custom.vposr | 0x8000;
3233 custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]);
3237 * (Un)Blank the screen (called by VBlank interrupt)
3240 static void ami_do_blank(void)
3242 struct amifb_par *par = ¤tpar;
3243 #if defined(CONFIG_FB_AMIGA_AGA)
3244 u_short bplcon3 = par->bplcon3;
3246 u_char red, green, blue;
3249 custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
3250 red = green = blue = 0;
3251 if (!IS_OCS && do_blank > 1) {
3253 case FB_BLANK_VSYNC_SUSPEND:
3254 custom.hsstrt = hsstrt2hw(par->hsstrt);
3255 custom.hsstop = hsstop2hw(par->hsstop);
3256 custom.vsstrt = vsstrt2hw(par->vtotal+4);
3257 custom.vsstop = vsstop2hw(par->vtotal+4);
3259 case FB_BLANK_HSYNC_SUSPEND:
3260 custom.hsstrt = hsstrt2hw(par->htotal+16);
3261 custom.hsstop = hsstop2hw(par->htotal+16);
3262 custom.vsstrt = vsstrt2hw(par->vsstrt);
3263 custom.vsstop = vsstrt2hw(par->vsstop);
3265 case FB_BLANK_POWERDOWN:
3266 custom.hsstrt = hsstrt2hw(par->htotal+16);
3267 custom.hsstop = hsstop2hw(par->htotal+16);
3268 custom.vsstrt = vsstrt2hw(par->vtotal+4);
3269 custom.vsstop = vsstop2hw(par->vtotal+4);
3272 if (!(par->beamcon0 & BMC0_VARBEAMEN)) {
3273 custom.htotal = htotal2hw(par->htotal);
3274 custom.vtotal = vtotal2hw(par->vtotal);
3275 custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN |
3276 BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN;
3280 custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
3285 custom.hsstrt = hsstrt2hw(par->hsstrt);
3286 custom.hsstop = hsstop2hw(par->hsstop);
3287 custom.vsstrt = vsstrt2hw(par->vsstrt);
3288 custom.vsstop = vsstop2hw(par->vsstop);
3289 custom.beamcon0 = par->beamcon0;
3292 #if defined(CONFIG_FB_AMIGA_AGA)
3294 custom.bplcon3 = bplcon3;
3295 custom.color[0] = rgb2hw8_high(red, green, blue);
3296 custom.bplcon3 = bplcon3 | BPC3_LOCT;
3297 custom.color[0] = rgb2hw8_low(red, green, blue);
3298 custom.bplcon3 = bplcon3;
3301 #if defined(CONFIG_FB_AMIGA_ECS)
3302 if (par->bplcon0 & BPC0_SHRES) {
3303 u_short color, mask;
3307 color = rgb2hw2(red, green, blue);
3308 for (i = 12; i >= 0; i -= 4)
3309 custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3310 mask <<=2; color >>= 2;
3311 for (i = 3; i >= 0; i--)
3312 custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3315 custom.color[0] = rgb2hw4(red, green, blue);
3316 is_blanked = do_blank > 0 ? do_blank : 0;
3319 static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix)
3321 struct amifb_par *par = ¤tpar;
3323 fix->crsr_width = fix->crsr_xsize = par->crsr.width;
3324 fix->crsr_height = fix->crsr_ysize = par->crsr.height;
3325 fix->crsr_color1 = 17;
3326 fix->crsr_color2 = 18;
3330 static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data)
3332 struct amifb_par *par = ¤tpar;
3333 register u_short *lspr, *sspr;
3335 register u_long datawords asm ("d2");
3337 register u_long datawords;
3339 register short delta;
3340 register u_char color;
3341 short height, width, bits, words;
3344 size = par->crsr.height*par->crsr.width;
3345 alloc = var->height*var->width;
3346 var->height = par->crsr.height;
3347 var->width = par->crsr.width;
3348 var->xspot = par->crsr.spot_x;
3349 var->yspot = par->crsr.spot_y;
3350 if (size > var->height*var->width)
3351 return -ENAMETOOLONG;
3352 if (!access_ok(VERIFY_WRITE, data, size))
3354 delta = 1<<par->crsr.fmode;
3355 lspr = lofsprite + (delta<<1);
3356 if (par->bplcon0 & BPC0_LACE)
3357 sspr = shfsprite + (delta<<1);
3360 for (height = (short)var->height-1; height >= 0; height--) {
3361 bits = 0; words = delta; datawords = 0;
3362 for (width = (short)var->width-1; width >= 0; width--) {
3366 asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0"
3367 : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta));
3369 datawords = (*(lspr+delta) << 16) | (*lspr++);
3375 "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; "
3376 "swap %1 ; lslw #1,%1 ; roxlb #1,%0"
3377 : "=d" (color), "=d" (datawords) : "1" (datawords));
3379 color = (((datawords >> 30) & 2)
3380 | ((datawords >> 15) & 1));
3383 put_user(color, data++);
3388 while (--words >= 0)
3391 asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
3392 : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
3396 u_short *tmp = lspr;
3405 static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data)
3407 struct amifb_par *par = ¤tpar;
3408 register u_short *lspr, *sspr;
3410 register u_long datawords asm ("d2");
3412 register u_long datawords;
3414 register short delta;
3416 short height, width, bits, words;
3420 else if (var->width <= 16)
3421 fmode = TAG_FMODE_1;
3422 else if (var->width <= 32)
3423 fmode = TAG_FMODE_2;
3424 else if (var->width <= 64)
3425 fmode = TAG_FMODE_4;
3428 if (fmode > maxfmode)
3432 if (!access_ok(VERIFY_READ, data, var->width*var->height))
3435 lofsprite = shfsprite = (u_short *)spritememory;
3436 lspr = lofsprite + (delta<<1);
3437 if (par->bplcon0 & BPC0_LACE) {
3438 if (((var->height+4)<<fmode<<2) > SPRITEMEMSIZE)
3440 memset(lspr, 0, (var->height+4)<<fmode<<2);
3441 shfsprite += ((var->height+5)&-2)<<fmode;
3442 sspr = shfsprite + (delta<<1);
3444 if (((var->height+2)<<fmode<<2) > SPRITEMEMSIZE)
3446 memset(lspr, 0, (var->height+2)<<fmode<<2);
3449 for (height = (short)var->height-1; height >= 0; height--) {
3450 bits = 16; words = delta; datawords = 0;
3451 for (width = (short)var->width-1; width >= 0; width--) {
3452 unsigned long tdata = 0;
3453 get_user(tdata, data);
3457 "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; "
3458 "lsrb #1,%2 ; roxlw #1,%0 ; swap %0"
3460 : "0" (datawords), "d" (tdata));
3462 datawords = ((datawords << 1) & 0xfffefffe);
3463 datawords |= tdata & 1;
3464 datawords |= (tdata & 2) << (16-1);
3469 asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+"
3470 : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta));
3472 *(lspr+delta) = (u_short) (datawords >> 16);
3473 *lspr++ = (u_short) (datawords & 0xffff);
3481 "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; "
3482 "swap %2 ; lslw %4,%2 ; movew %2,%0@+"
3483 : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits));
3485 *(lspr+delta) = (u_short) (datawords >> (16+bits));
3486 *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits);
3489 while (--words >= 0) {
3491 asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+"
3492 : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0");
3499 asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
3500 : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
3504 u_short *tmp = lspr;
3510 par->crsr.height = var->height;
3511 par->crsr.width = var->width;
3512 par->crsr.spot_x = var->xspot;
3513 par->crsr.spot_y = var->yspot;
3514 par->crsr.fmode = fmode;
3516 par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32);
3517 par->fmode |= sprfetchmode[fmode];
3518 custom.fmode = par->fmode;
3523 static int ami_get_cursorstate(struct fb_cursorstate *state)
3525 struct amifb_par *par = ¤tpar;
3527 state->xoffset = par->crsr.crsr_x;
3528 state->yoffset = par->crsr.crsr_y;
3529 state->mode = cursormode;
3533 static int ami_set_cursorstate(struct fb_cursorstate *state)
3535 struct amifb_par *par = ¤tpar;
3537 par->crsr.crsr_x = state->xoffset;
3538 par->crsr.crsr_y = state->yoffset;
3539 if ((cursormode = state->mode) == FB_CURSOR_OFF)
3545 static void ami_set_sprite(void)
3547 struct amifb_par *par = ¤tpar;
3548 copins *copl, *cops;
3553 cops = copdisplay.list[currentcop][0];
3554 copl = copdisplay.list[currentcop][1];
3555 ps = pl = ZTWO_PADDR(dummysprite);
3556 mx = par->crsr.crsr_x-par->crsr.spot_x;
3557 my = par->crsr.crsr_y-par->crsr.spot_y;
3558 if (!(par->vmode & FB_VMODE_YWRAP)) {
3562 if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 &&
3563 mx > -(short)par->crsr.width && mx < par->xres &&
3564 my > -(short)par->crsr.height && my < par->yres) {
3565 pl = ZTWO_PADDR(lofsprite);
3566 hs = par->diwstrt_h + (mx<<par->clk_shift) - 4;
3567 vs = par->diwstrt_v + (my<<par->line_shift);
3568 ve = vs + (par->crsr.height<<par->line_shift);
3569 if (par->bplcon0 & BPC0_LACE) {
3570 ps = ZTWO_PADDR(shfsprite);
3571 lofsprite[0] = spr2hw_pos(vs, hs);
3572 shfsprite[0] = spr2hw_pos(vs+1, hs);
3574 lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
3575 shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1);
3576 pt = pl; pl = ps; ps = pt;
3578 lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve+1);
3579 shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve);
3582 lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0);
3583 lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
3586 copl[cop_spr0ptrh].w[1] = highw(pl);
3587 copl[cop_spr0ptrl].w[1] = loww(pl);
3588 if (par->bplcon0 & BPC0_LACE) {
3589 cops[cop_spr0ptrh].w[1] = highw(ps);
3590 cops[cop_spr0ptrl].w[1] = loww(ps);
3596 * Initialise the Copper Initialisation List
3599 static void __init ami_init_copper(void)
3601 copins *cop = copdisplay.init;
3606 (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
3607 (cop++)->l = CMOVE(0x0181, diwstrt);
3608 (cop++)->l = CMOVE(0x0281, diwstop);
3609 (cop++)->l = CMOVE(0x0000, diwhigh);
3611 (cop++)->l = CMOVE(BPC0_COLOR, bplcon0);
3612 p = ZTWO_PADDR(dummysprite);
3613 for (i = 0; i < 8; i++) {
3614 (cop++)->l = CMOVE(0, spr[i].pos);
3615 (cop++)->l = CMOVE(highw(p), sprpt[i]);
3616 (cop++)->l = CMOVE2(loww(p), sprpt[i]);
3619 (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);
3620 copdisplay.wait = cop;
3622 (cop++)->l = CMOVE(0, copjmp2);
3625 custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);
3629 static void ami_reinit_copper(void)
3631 struct amifb_par *par = ¤tpar;
3633 copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0;
3634 copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4);
3638 * Build the Copper List
3641 static void ami_build_copper(void)
3643 struct amifb_par *par = ¤tpar;
3644 copins *copl, *cops;
3647 currentcop = 1 - currentcop;
3649 copl = copdisplay.list[currentcop][1];
3651 (copl++)->l = CWAIT(0, 10);
3652 (copl++)->l = CMOVE(par->bplcon0, bplcon0);
3653 (copl++)->l = CMOVE(0, sprpt[0]);
3654 (copl++)->l = CMOVE2(0, sprpt[0]);
3656 if (par->bplcon0 & BPC0_LACE) {
3657 cops = copdisplay.list[currentcop][0];
3659 (cops++)->l = CWAIT(0, 10);
3660 (cops++)->l = CMOVE(par->bplcon0, bplcon0);
3661 (cops++)->l = CMOVE(0, sprpt[0]);
3662 (cops++)->l = CMOVE2(0, sprpt[0]);
3664 (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt);
3665 (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop);
3666 (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
3667 (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
3669 (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1,
3670 par->diwstop_h, par->diwstop_v+1), diwhigh);
3671 (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
3672 par->diwstop_h, par->diwstop_v), diwhigh);
3674 if (par->beamcon0 & BMC0_VARBEAMEN) {
3675 (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3676 (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt);
3677 (copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop);
3678 (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3679 (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
3680 (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
3684 p = ZTWO_PADDR(copdisplay.list[currentcop][0]);
3685 (copl++)->l = CMOVE(highw(p), cop2lc);
3686 (copl++)->l = CMOVE2(loww(p), cop2lc);
3687 p = ZTWO_PADDR(copdisplay.list[currentcop][1]);
3688 (cops++)->l = CMOVE(highw(p), cop2lc);
3689 (cops++)->l = CMOVE2(loww(p), cop2lc);
3690 copdisplay.rebuild[0] = cops;
3692 (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
3693 (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
3695 (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
3696 par->diwstop_h, par->diwstop_v), diwhigh);
3698 if (par->beamcon0 & BMC0_VARBEAMEN) {
3699 (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3700 (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
3701 (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
3706 copdisplay.rebuild[1] = copl;
3709 ami_rebuild_copper();
3713 * Rebuild the Copper List
3715 * We only change the things that are not static
3718 static void ami_rebuild_copper(void)
3720 struct amifb_par *par = ¤tpar;
3721 copins *copl, *cops;
3722 u_short line, h_end1, h_end2;
3726 if (IS_AGA && maxfmode + par->clk_shift == 0)
3727 h_end1 = par->diwstrt_h-64;
3729 h_end1 = par->htotal-32;
3730 h_end2 = par->ddfstop+64;
3734 copl = copdisplay.rebuild[1];
3736 if (par->vmode & FB_VMODE_YWRAP) {
3737 if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) {
3738 if (par->yoffset > par->vyres-par->yres) {
3739 for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3740 (copl++)->l = CMOVE(highw(p), bplpt[i]);
3741 (copl++)->l = CMOVE2(loww(p), bplpt[i]);
3743 line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 1;
3744 while (line >= 512) {
3745 (copl++)->l = CWAIT(h_end1, 510);
3748 if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0)
3749 (copl++)->l = CWAIT(h_end1, line);
3751 (copl++)->l = CWAIT(h_end2, line);
3752 p = par->bplpt0wrap;
3754 } else p = par->bplpt0wrap;
3756 for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3757 (copl++)->l = CMOVE(highw(p), bplpt[i]);
3758 (copl++)->l = CMOVE2(loww(p), bplpt[i]);
3762 if (par->bplcon0 & BPC0_LACE) {
3763 cops = copdisplay.rebuild[0];
3765 if (mod2(par->diwstrt_v))
3766 p -= par->next_line;
3768 p += par->next_line;
3769 if (par->vmode & FB_VMODE_YWRAP) {
3770 if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) {
3771 if (par->yoffset > par->vyres-par->yres+1) {
3772 for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3773 (cops++)->l = CMOVE(highw(p), bplpt[i]);
3774 (cops++)->l = CMOVE2(loww(p), bplpt[i]);
3776 line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 2;
3777 while (line >= 512) {
3778 (cops++)->l = CWAIT(h_end1, 510);
3781 if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0)
3782 (cops++)->l = CWAIT(h_end1, line);
3784 (cops++)->l = CWAIT(h_end2, line);
3785 p = par->bplpt0wrap;
3786 if (mod2(par->diwstrt_v+par->vyres-par->yoffset))
3787 p -= par->next_line;
3789 p += par->next_line;
3791 } else p = par->bplpt0wrap - par->next_line;
3793 for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3794 (cops++)->l = CMOVE(highw(p), bplpt[i]);
3795 (cops++)->l = CMOVE2(loww(p), bplpt[i]);
3802 module_init(amifb_init);
3805 MODULE_LICENSE("GPL");
3807 void cleanup_module(void)
3809 unregister_framebuffer(&fb_info);