2 * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device
4 * Copyright (C) 1995 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/console.h>
56 #include <linux/ioport.h>
58 #include <asm/uaccess.h>
59 #include <asm/system.h>
61 #include <asm/amigahw.h>
62 #include <asm/amigaints.h>
63 #include <asm/setup.h>
65 #include <video/fbcon.h>
66 #include <video/fbcon-afb.h>
67 #include <video/fbcon-ilbm.h>
68 #include <video/fbcon-mfb.h>
73 #if !defined(CONFIG_FB_AMIGA_OCS) && !defined(CONFIG_FB_AMIGA_ECS) && !defined(CONFIG_FB_AMIGA_AGA)
74 #define CONFIG_FB_AMIGA_OCS /* define at least one fb driver, this will change later */
77 #if !defined(CONFIG_FB_AMIGA_OCS)
79 #elif defined(CONFIG_FB_AMIGA_ECS) || defined(CONFIG_FB_AMIGA_AGA)
80 # define IS_OCS (chipset == TAG_OCS)
82 # define CONFIG_FB_AMIGA_OCS_ONLY
86 #if !defined(CONFIG_FB_AMIGA_ECS)
88 #elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_AGA)
89 # define IS_ECS (chipset == TAG_ECS)
91 # define CONFIG_FB_AMIGA_ECS_ONLY
95 #if !defined(CONFIG_FB_AMIGA_AGA)
97 #elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_ECS)
98 # define IS_AGA (chipset == TAG_AGA)
100 # define CONFIG_FB_AMIGA_AGA_ONLY
105 # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
107 # define DPRINTK(fmt, args...)
110 /*******************************************************************************
113 Generic video timings
114 ---------------------
116 Timings used by the frame buffer interface:
118 +----------+---------------------------------------------+----------+-------+
120 | | |upper_margin | | |
122 +----------###############################################----------+-------+
127 | left # | # right | hsync |
128 | margin # | xres # margin | len |
129 |<-------->#<---------------+--------------------------->#<-------->|<----->|
143 +----------###############################################----------+-------+
145 | | |lower_margin | | |
147 +----------+---------------------------------------------+----------+-------+
151 +----------+---------------------------------------------+----------+-------+
157 The Amiga native chipsets uses another timing scheme:
159 - hsstrt: Start of horizontal synchronization pulse
160 - hsstop: End of horizontal synchronization pulse
161 - htotal: Last value on the line (i.e. line length = htotal+1)
162 - vsstrt: Start of vertical synchronization pulse
163 - vsstop: End of vertical synchronization pulse
164 - vtotal: Last line value (i.e. number of lines = vtotal+1)
165 - hcenter: Start of vertical retrace for interlace
167 You can specify the blanking timings independently. Currently I just set
168 them equal to the respective synchronization values:
170 - hbstrt: Start of horizontal blank
171 - hbstop: End of horizontal blank
172 - vbstrt: Start of vertical blank
173 - vbstop: End of vertical blank
175 Horizontal values are in color clock cycles (280 ns), vertical values are in
178 (0, 0) is somewhere in the upper-left corner :-)
181 Amiga visible window definitions
182 --------------------------------
184 Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to
185 make corrections and/or additions.
187 Within the above synchronization specifications, the visible window is
188 defined by the following parameters (actual register resolutions may be
189 different; all horizontal values are normalized with respect to the pixel
192 - diwstrt_h: Horizontal start of the visible window
193 - diwstop_h: Horizontal stop+1(*) of the visible window
194 - diwstrt_v: Vertical start of the visible window
195 - diwstop_v: Vertical stop of the visible window
196 - ddfstrt: Horizontal start of display DMA
197 - ddfstop: Horizontal stop of display DMA
198 - hscroll: Horizontal display output delay
202 - sprstrt_h: Horizontal start-4 of sprite
203 - sprstrt_v: Vertical start of sprite
205 (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1.
207 Horizontal values are in dotclock cycles (35 ns), vertical values are in
210 (0, 0) is somewhere in the upper-left corner :-)
213 Dependencies (AGA, SHRES (35 ns dotclock))
214 -------------------------------------------
216 Since there are much more parameters for the Amiga display than for the
217 frame buffer interface, there must be some dependencies among the Amiga
218 display parameters. Here's what I found out:
220 - ddfstrt and ddfstop are best aligned to 64 pixels.
221 - the chipset needs 64+4 horizontal pixels after the DMA start before the
222 first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to
223 display the first pixel on the line too. Increase diwstrt_h for virtual
225 - the display DMA always fetches 64 pixels at a time (fmode = 3).
226 - ddfstop is ddfstrt+#pixels-64.
227 - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1
229 - hscroll simply adds a delay to the display output. Smooth horizontal
230 panning needs an extra 64 pixels on the left to prefetch the pixels that
231 `fall off' on the left.
232 - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane
233 DMA, so it's best to make the DMA start as late as possible.
234 - you really don't want to make ddfstrt < 128, since this will steal DMA
235 cycles from the other DMA channels (audio, floppy and Chip RAM refresh).
236 - I make diwstop_h and diwstop_v as large as possible.
241 - all values are SHRES pixel (35ns)
243 table 1:fetchstart table 2:prefetch table 3:fetchsize
244 ------------------ ---------------- -----------------
245 Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES
246 -------------#------+-----+------#------+-----+------#------+-----+------
247 Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64
248 Bus width 2x # 32 | 64 | 128 # 32 | 64 | 64 # 64 | 64 | 128
249 Bus width 4x # 64 | 128 | 256 # 64 | 64 | 64 # 64 | 128 | 256
251 - chipset needs 4 pixels before the first pixel is output
252 - ddfstrt must be aligned to fetchstart (table 1)
253 - chipset needs also prefetch (table 2) to get first pixel data, so
254 ddfstrt = ((diwstrt_h-4) & -fetchstart) - prefetch
255 - for horizontal panning decrease diwstrt_h
256 - the length of a fetchline must be aligned to fetchsize (table 3)
257 - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit
258 moved to optimize use of dma (useful for OCS/ECS overscan displays)
259 - ddfstop is ddfstrt+ddfsize-fetchsize
260 - If C= didn't change anything for AGA, then at following positions the
261 dma bus is allready used:
262 ddfstrt < 48 -> memory refresh
265 < 192 -> sprite 0 dma
266 < 416 -> sprite dma (32 per sprite)
267 - in accordance with the hardware reference manual a hardware stop is at
268 192, but AGA (ECS?) can go below this.
273 Since there are limits on the earliest start value for display DMA and the
274 display of sprites, I use the following policy on horizontal panning and
277 - if you want to start display DMA too early, you loose the ability to
278 do smooth horizontal panning (xpanstep 1 -> 64).
279 - if you want to go even further, you loose the hardware cursor too.
281 IMHO a hardware cursor is more important for X than horizontal scrolling,
282 so that's my motivation.
288 ami_decode_var() converts the frame buffer values to the Amiga values. It's
289 just a `straightforward' implementation of the above rules.
295 xres yres left right upper lower hsync vsync
296 ---- ---- ---- ----- ----- ----- ----- -----
297 80x25 720 400 27 45 35 12 108 2
298 80x30 720 480 27 45 30 9 108 2
300 These were taken from a XFree86 configuration file, recalculated for a 28 MHz
301 dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer
304 As a comparison, graphics/monitor.h suggests the following:
306 xres yres left right upper lower hsync vsync
307 ---- ---- ---- ----- ----- ----- ----- -----
309 VGA 640 480 52 112 24 19 112 - 2 +
310 VGA70 640 400 52 112 27 21 112 - 2 -
316 VSYNC HSYNC Vertical size Vertical total
317 ----- ----- ------------- --------------
318 + + Reserved Reserved
323 Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992
326 Broadcast video timings
327 -----------------------
329 According to the CCIR and RETMA specifications, we have the following values:
334 - a scanline is 64 µs long, of which 52.48 µs are visible. This is about
335 736 visible 70 ns pixels per line.
336 - we have 625 scanlines, of which 575 are visible (interlaced); after
337 rounding this becomes 576.
342 - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about
343 736 visible 70 ns pixels per line.
344 - we have 525 scanlines, of which 485 are visible (interlaced); after
345 rounding this becomes 484.
347 Thus if you want a PAL compatible display, you have to do the following:
349 - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast
350 timings are to be used.
351 - make sure upper_margin+yres+lower_margin+vsync_len = 625 for an
352 interlaced, 312 for a non-interlaced and 156 for a doublescanned
354 - make sure left_margin+xres+right_margin+hsync_len = 1816 for a SHRES,
355 908 for a HIRES and 454 for a LORES display.
356 - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90),
357 left_margin+2*hsync_len must be greater or equal.
358 - the upper visible part begins at 48 (interlaced; non-interlaced:24,
359 doublescanned:12), upper_margin+2*vsync_len must be greater or equal.
360 - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync
363 The settings for a NTSC compatible display are straightforward.
365 Note that in a strict sense the PAL and NTSC standards only define the
366 encoding of the color part (chrominance) of the video signal and don't say
367 anything about horizontal/vertical synchronization nor refresh rates.
372 *******************************************************************************/
376 * Custom Chipset Definitions
379 #define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld)
382 * BPLCON0 -- Bitplane Control Register 0
385 #define BPC0_HIRES (0x8000)
386 #define BPC0_BPU2 (0x4000) /* Bit plane used count */
387 #define BPC0_BPU1 (0x2000)
388 #define BPC0_BPU0 (0x1000)
389 #define BPC0_HAM (0x0800) /* HAM mode */
390 #define BPC0_DPF (0x0400) /* Double playfield */
391 #define BPC0_COLOR (0x0200) /* Enable colorburst */
392 #define BPC0_GAUD (0x0100) /* Genlock audio enable */
393 #define BPC0_UHRES (0x0080) /* Ultrahi res enable */
394 #define BPC0_SHRES (0x0040) /* Super hi res mode */
395 #define BPC0_BYPASS (0x0020) /* Bypass LUT - AGA */
396 #define BPC0_BPU3 (0x0010) /* AGA */
397 #define BPC0_LPEN (0x0008) /* Light pen enable */
398 #define BPC0_LACE (0x0004) /* Interlace */
399 #define BPC0_ERSY (0x0002) /* External resync */
400 #define BPC0_ECSENA (0x0001) /* ECS enable */
403 * BPLCON2 -- Bitplane Control Register 2
406 #define BPC2_ZDBPSEL2 (0x4000) /* Bitplane to be used for ZD - AGA */
407 #define BPC2_ZDBPSEL1 (0x2000)
408 #define BPC2_ZDBPSEL0 (0x1000)
409 #define BPC2_ZDBPEN (0x0800) /* Enable ZD with ZDBPSELx - AGA */
410 #define BPC2_ZDCTEN (0x0400) /* Enable ZD with palette bit #31 - AGA */
411 #define BPC2_KILLEHB (0x0200) /* Kill EHB mode - AGA */
412 #define BPC2_RDRAM (0x0100) /* Color table accesses read, not write - AGA */
413 #define BPC2_SOGEN (0x0080) /* SOG output pin high - AGA */
414 #define BPC2_PF2PRI (0x0040) /* PF2 priority over PF1 */
415 #define BPC2_PF2P2 (0x0020) /* PF2 priority wrt sprites */
416 #define BPC2_PF2P1 (0x0010)
417 #define BPC2_PF2P0 (0x0008)
418 #define BPC2_PF1P2 (0x0004) /* ditto PF1 */
419 #define BPC2_PF1P1 (0x0002)
420 #define BPC2_PF1P0 (0x0001)
423 * BPLCON3 -- Bitplane Control Register 3 (AGA)
426 #define BPC3_BANK2 (0x8000) /* Bits to select color register bank */
427 #define BPC3_BANK1 (0x4000)
428 #define BPC3_BANK0 (0x2000)
429 #define BPC3_PF2OF2 (0x1000) /* Bits for color table offset when PF2 */
430 #define BPC3_PF2OF1 (0x0800)
431 #define BPC3_PF2OF0 (0x0400)
432 #define BPC3_LOCT (0x0200) /* Color register writes go to low bits */
433 #define BPC3_SPRES1 (0x0080) /* Sprite resolution bits */
434 #define BPC3_SPRES0 (0x0040)
435 #define BPC3_BRDRBLNK (0x0020) /* Border blanked? */
436 #define BPC3_BRDRTRAN (0x0010) /* Border transparent? */
437 #define BPC3_ZDCLKEN (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */
438 #define BPC3_BRDRSPRT (0x0002) /* Sprites in border? */
439 #define BPC3_EXTBLKEN (0x0001) /* BLANK programmable */
442 * BPLCON4 -- Bitplane Control Register 4 (AGA)
445 #define BPC4_BPLAM7 (0x8000) /* bitplane color XOR field */
446 #define BPC4_BPLAM6 (0x4000)
447 #define BPC4_BPLAM5 (0x2000)
448 #define BPC4_BPLAM4 (0x1000)
449 #define BPC4_BPLAM3 (0x0800)
450 #define BPC4_BPLAM2 (0x0400)
451 #define BPC4_BPLAM1 (0x0200)
452 #define BPC4_BPLAM0 (0x0100)
453 #define BPC4_ESPRM7 (0x0080) /* 4 high bits for even sprite colors */
454 #define BPC4_ESPRM6 (0x0040)
455 #define BPC4_ESPRM5 (0x0020)
456 #define BPC4_ESPRM4 (0x0010)
457 #define BPC4_OSPRM7 (0x0008) /* 4 high bits for odd sprite colors */
458 #define BPC4_OSPRM6 (0x0004)
459 #define BPC4_OSPRM5 (0x0002)
460 #define BPC4_OSPRM4 (0x0001)
463 * BEAMCON0 -- Beam Control Register
466 #define BMC0_HARDDIS (0x4000) /* Disable hardware limits */
467 #define BMC0_LPENDIS (0x2000) /* Disable light pen latch */
468 #define BMC0_VARVBEN (0x1000) /* Enable variable vertical blank */
469 #define BMC0_LOLDIS (0x0800) /* Disable long/short line toggle */
470 #define BMC0_CSCBEN (0x0400) /* Composite sync/blank */
471 #define BMC0_VARVSYEN (0x0200) /* Enable variable vertical sync */
472 #define BMC0_VARHSYEN (0x0100) /* Enable variable horizontal sync */
473 #define BMC0_VARBEAMEN (0x0080) /* Enable variable beam counters */
474 #define BMC0_DUAL (0x0040) /* Enable alternate horizontal beam counter */
475 #define BMC0_PAL (0x0020) /* Set decodes for PAL */
476 #define BMC0_VARCSYEN (0x0010) /* Enable variable composite sync */
477 #define BMC0_BLANKEN (0x0008) /* Blank enable (no longer used on AGA) */
478 #define BMC0_CSYTRUE (0x0004) /* CSY polarity */
479 #define BMC0_VSYTRUE (0x0002) /* VSY polarity */
480 #define BMC0_HSYTRUE (0x0001) /* HSY polarity */
484 * FMODE -- Fetch Mode Control Register (AGA)
487 #define FMODE_SSCAN2 (0x8000) /* Sprite scan-doubling */
488 #define FMODE_BSCAN2 (0x4000) /* Use PF2 modulus every other line */
489 #define FMODE_SPAGEM (0x0008) /* Sprite page mode */
490 #define FMODE_SPR32 (0x0004) /* Sprite 32 bit fetch */
491 #define FMODE_BPAGEM (0x0002) /* Bitplane page mode */
492 #define FMODE_BPL32 (0x0001) /* Bitplane 32 bit fetch */
495 * Tags used to indicate a specific Pixel Clock
497 * clk_shift is the shift value to get the timings in 35 ns units
500 enum { TAG_SHRES, TAG_HIRES, TAG_LORES };
503 * Tags used to indicate the specific chipset
506 enum { TAG_OCS, TAG_ECS, TAG_AGA };
509 * Tags used to indicate the memory bandwidth
512 enum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 };
516 * Clock Definitions, Maximum Display Depth
518 * These depend on the E-Clock or the Chipset, so they are filled in
522 static u_long pixclock[3]; /* SHRES/HIRES/LORES: index = clk_shift */
523 static u_short maxdepth[3]; /* SHRES/HIRES/LORES: index = clk_shift */
524 static u_short maxfmode, chipset;
528 * Broadcast Video Timings
530 * Horizontal values are in 35 ns (SHRES) units
531 * Vertical values are in interlaced scanlines
534 #define PAL_DIWSTRT_H (360) /* PAL Window Limits */
535 #define PAL_DIWSTRT_V (48)
536 #define PAL_HTOTAL (1816)
537 #define PAL_VTOTAL (625)
539 #define NTSC_DIWSTRT_H (360) /* NTSC Window Limits */
540 #define NTSC_DIWSTRT_V (40)
541 #define NTSC_HTOTAL (1816)
542 #define NTSC_VTOTAL (525)
549 #define up2(v) (((v)+1) & -2)
550 #define down2(v) ((v) & -2)
551 #define div2(v) ((v)>>1)
552 #define mod2(v) ((v) & 1)
554 #define up4(v) (((v)+3) & -4)
555 #define down4(v) ((v) & -4)
556 #define mul4(v) ((v)<<2)
557 #define div4(v) ((v)>>2)
558 #define mod4(v) ((v) & 3)
560 #define up8(v) (((v)+7) & -8)
561 #define down8(v) ((v) & -8)
562 #define div8(v) ((v)>>3)
563 #define mod8(v) ((v) & 7)
565 #define up16(v) (((v)+15) & -16)
566 #define down16(v) ((v) & -16)
567 #define div16(v) ((v)>>4)
568 #define mod16(v) ((v) & 15)
570 #define up32(v) (((v)+31) & -32)
571 #define down32(v) ((v) & -32)
572 #define div32(v) ((v)>>5)
573 #define mod32(v) ((v) & 31)
575 #define up64(v) (((v)+63) & -64)
576 #define down64(v) ((v) & -64)
577 #define div64(v) ((v)>>6)
578 #define mod64(v) ((v) & 63)
580 #define upx(x,v) (((v)+(x)-1) & -(x))
581 #define downx(x,v) ((v) & -(x))
582 #define modx(x,v) ((v) & ((x)-1))
584 /* if x1 is not a constant, this macro won't make real sense :-) */
586 #define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \
587 "d" (x2), "d" ((long)((x1)/0x100000000ULL)), "0" ((long)(x1))); res;})
589 /* We know a bit about the numbers, so we can do it this way */
590 #define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \
591 ((((long)((unsigned long long)x1 >> 8) % x2) << 8) / x2))
594 #define highw(x) ((u_long)(x)>>16 & 0xffff)
595 #define loww(x) ((u_long)(x) & 0xffff)
597 #define VBlankOn() custom.intena = IF_SETCLR|IF_COPER
598 #define VBlankOff() custom.intena = IF_COPER
602 * Chip RAM we reserve for the Frame Buffer
604 * This defines the Maximum Virtual Screen Size
605 * (Setable per kernel options?)
608 #define VIDEOMEMSIZE_AGA_2M (1310720) /* AGA (2MB) : max 1280*1024*256 */
609 #define VIDEOMEMSIZE_AGA_1M (786432) /* AGA (1MB) : max 1024*768*256 */
610 #define VIDEOMEMSIZE_ECS_2M (655360) /* ECS (2MB) : max 1280*1024*16 */
611 #define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */
612 #define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */
614 #define SPRITEMEMSIZE (64*64/4) /* max 64*64*4 */
615 #define DUMMYSPRITEMEMSIZE (8)
617 #define CHIPRAM_SAFETY_LIMIT (16384)
619 static u_long videomemory, spritememory;
620 static u_long videomemorysize;
621 static u_long videomemory_phys;
624 * This is the earliest allowed start of fetching display data.
625 * Only if you really want no hardware cursor and audio,
626 * set this to 128, but let it better at 192
629 static u_long min_fstrt = 192;
631 #define assignchunk(name, type, ptr, size) \
633 (name) = (type)(ptr); \
639 * Copper Instructions
642 #define CMOVE(val, reg) (CUSTOM_OFS(reg)<<16 | (val))
643 #define CMOVE2(val, reg) ((CUSTOM_OFS(reg)+2)<<16 | (val))
644 #define CWAIT(x, y) (((y) & 0x1fe)<<23 | ((x) & 0x7f0)<<13 | 0x0001fffe)
645 #define CEND (0xfffffffe)
653 static struct copdisplay {
660 static u_short currentcop = 0;
666 static int cursorrate = 20; /* Number of frames/flash toggle */
667 static u_short cursorstate = -1;
668 static u_short cursormode = FB_CURSOR_OFF;
670 static u_short *lofsprite, *shfsprite, *dummysprite;
676 static struct amifb_par {
680 int xres; /* vmode */
681 int yres; /* vmode */
682 int vxres; /* vmode */
683 int vyres; /* vmode */
684 int xoffset; /* vmode */
685 int yoffset; /* vmode */
686 u_short bpp; /* vmode */
687 u_short clk_shift; /* vmode */
688 u_short line_shift; /* vmode */
689 int vmode; /* vmode */
690 u_short diwstrt_h; /* vmode */
691 u_short diwstop_h; /* vmode */
692 u_short diwstrt_v; /* vmode */
693 u_short diwstop_v; /* vmode */
694 u_long next_line; /* modulo for next line */
695 u_long next_plane; /* modulo for next plane */
700 short crsr_x; /* movecursor */
701 short crsr_y; /* movecursor */
709 /* OCS Hardware Registers */
711 u_long bplpt0; /* vmode, pan (Note: physical address) */
712 u_long bplpt0wrap; /* vmode, pan (Note: physical address) */
717 u_short bplcon0; /* vmode */
718 u_short bplcon1; /* vmode */
719 u_short htotal; /* vmode */
720 u_short vtotal; /* vmode */
722 /* Additional ECS Hardware Registers */
724 u_short bplcon3; /* vmode */
725 u_short beamcon0; /* vmode */
726 u_short hsstrt; /* vmode */
727 u_short hsstop; /* vmode */
728 u_short hbstrt; /* vmode */
729 u_short hbstop; /* vmode */
730 u_short vsstrt; /* vmode */
731 u_short vsstop; /* vmode */
732 u_short vbstrt; /* vmode */
733 u_short vbstop; /* vmode */
734 u_short hcenter; /* vmode */
736 /* Additional AGA Hardware Registers */
738 u_short fmode; /* vmode */
741 static int currcon = 0;
743 static struct display disp;
745 static struct fb_info fb_info;
749 * Since we can't read the palette on OCS/ECS, and since reading one
750 * single color palette entry requires 5 expensive custom chip bus accesses
751 * on AGA, we keep a copy of the current palette.
752 * Note that the entries are always 24 bit!
755 #if defined(CONFIG_FB_AMIGA_AGA)
756 static struct { u_char red, green, blue, pad; } palette[256];
758 static struct { u_char red, green, blue, pad; } palette[32];
761 #if defined(CONFIG_FB_AMIGA_ECS)
762 static u_short ecs_palette[32];
766 * Latches for Display Changes during VBlank
769 static u_short do_vmode_full = 0; /* Change the Video Mode */
770 static u_short do_vmode_pan = 0; /* Update the Video Mode */
771 static short do_blank = 0; /* (Un)Blank the Screen (±1) */
772 static u_short do_cursor = 0; /* Move the Cursor */
779 static u_short is_blanked = 0; /* Screen is Blanked */
780 static u_short is_lace = 0; /* Screen is laced */
785 * The rest of the name is filled in during initialization
788 static char amifb_name[16] = "Amiga ";
792 * Predefined Video Modes
796 static struct fb_videomode ami_modedb[] __initdata = {
799 * AmigaOS Video Modes
801 * If you change these, make sure to update DEFMODE_* as well!
805 /* 640x200, 15 kHz, 60 Hz (NTSC) */
806 "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2,
807 FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
809 /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
810 "ntsc-lace", 60, 640, TAG_HIRES, 106, 86, 88, 33, 76, 4,
811 FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
813 /* 640x256, 15 kHz, 50 Hz (PAL) */
814 "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2,
815 FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
817 /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
818 "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4,
819 FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
821 /* 640x480, 29 kHz, 57 Hz */
822 "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8,
823 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
825 /* 640x960, 29 kHz, 57 Hz interlaced */
826 "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, 16,
827 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
829 /* 640x200, 15 kHz, 72 Hz */
830 "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5,
831 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
833 /* 640x400, 15 kHz, 72 Hz interlaced */
834 "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, 10,
835 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
837 /* 640x400, 29 kHz, 68 Hz */
838 "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8,
839 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
841 /* 640x800, 29 kHz, 68 Hz interlaced */
842 "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, 16,
843 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
845 /* 800x300, 23 kHz, 70 Hz */
846 "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7,
847 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
849 /* 800x600, 23 kHz, 70 Hz interlaced */
850 "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, 14,
851 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
853 /* 640x200, 27 kHz, 57 Hz doublescan */
854 "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4,
855 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
857 /* 640x400, 27 kHz, 57 Hz */
858 "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7,
859 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
861 /* 640x800, 27 kHz, 57 Hz interlaced */
862 "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, 14,
863 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
865 /* 640x256, 27 kHz, 47 Hz doublescan */
866 "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4,
867 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
869 /* 640x512, 27 kHz, 47 Hz */
870 "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7,
871 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
873 /* 640x1024, 27 kHz, 47 Hz interlaced */
874 "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, 14,
875 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
883 /* 640x480, 31 kHz, 60 Hz (VGA) */
884 "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2,
885 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
887 /* 640x400, 31 kHz, 70 Hz (VGA) */
888 "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2,
889 FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
896 * These modes don't work yet because there's no A2024 driver.
900 /* 1024x800, 10 Hz */
901 "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,
902 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
904 /* 1024x800, 15 Hz */
905 "a2024-15", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,
906 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
911 #define NUM_TOTAL_MODES ARRAY_SIZE(ami_modedb)
913 static char *mode_option __initdata = NULL;
914 static int round_down_bpp = 1; /* for mode probing */
921 #define DEFMODE_PAL 2 /* "pal" for PAL OCS/ECS */
922 #define DEFMODE_NTSC 0 /* "ntsc" for NTSC OCS/ECS */
923 #define DEFMODE_AMBER_PAL 3 /* "pal-lace" for flicker fixed PAL (A3000) */
924 #define DEFMODE_AMBER_NTSC 1 /* "ntsc-lace" for flicker fixed NTSC (A3000) */
925 #define DEFMODE_AGA 19 /* "vga70" for AGA */
928 static int amifb_ilbm = 0; /* interleaved or normal bitplanes */
929 static int amifb_inverse = 0;
933 * Macros for the conversion from real world values to hardware register
936 * This helps us to keep our attention on the real stuff...
938 * Hardware limits for AGA:
940 * parameter min max step
941 * --------- --- ---- ----
963 * Horizontal values are in 35 ns (SHRES) pixels
964 * Vertical values are in half scanlines
967 /* bplcon1 (smooth scrolling) */
969 #define hscroll2hw(hscroll) \
970 (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \
971 ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))
973 /* diwstrt/diwstop/diwhigh (visible display window) */
975 #define diwstrt2hw(diwstrt_h, diwstrt_v) \
976 (((diwstrt_v)<<7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
977 #define diwstop2hw(diwstop_h, diwstop_v) \
978 (((diwstop_v)<<7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
979 #define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \
980 (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \
981 ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \
982 ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007))
984 /* ddfstrt/ddfstop (display DMA) */
986 #define ddfstrt2hw(ddfstrt) div8(ddfstrt)
987 #define ddfstop2hw(ddfstop) div8(ddfstop)
989 /* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */
991 #define hsstrt2hw(hsstrt) (div8(hsstrt))
992 #define hsstop2hw(hsstop) (div8(hsstop))
993 #define htotal2hw(htotal) (div8(htotal)-1)
994 #define vsstrt2hw(vsstrt) (div2(vsstrt))
995 #define vsstop2hw(vsstop) (div2(vsstop))
996 #define vtotal2hw(vtotal) (div2(vtotal)-1)
997 #define hcenter2hw(htotal) (div8(htotal))
999 /* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
1001 #define hbstrt2hw(hbstrt) (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))
1002 #define hbstop2hw(hbstop) (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff))
1003 #define vbstrt2hw(vbstrt) (div2(vbstrt))
1004 #define vbstop2hw(vbstop) (div2(vbstop))
1008 #define rgb2hw8_high(red, green, blue) \
1009 (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4))
1010 #define rgb2hw8_low(red, green, blue) \
1011 (((red & 0x0f)<<8) | ((green & 0x0f)<<4) | (blue & 0x0f))
1012 #define rgb2hw4(red, green, blue) \
1013 (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4))
1014 #define rgb2hw2(red, green, blue) \
1015 (((red & 0xc0)<<4) | (green & 0xc0) | ((blue & 0xc0)>>4))
1017 /* sprpos/sprctl (sprite positioning) */
1019 #define spr2hw_pos(start_v, start_h) \
1020 (((start_v)<<7&0xff00) | ((start_h)>>3&0x00ff))
1021 #define spr2hw_ctl(start_v, start_h, stop_v) \
1022 (((stop_v)<<7&0xff00) | ((start_v)>>4&0x0040) | ((stop_v)>>5&0x0020) | \
1023 ((start_h)<<3&0x0018) | ((start_v)>>7&0x0004) | ((stop_v)>>8&0x0002) | \
1024 ((start_h)>>2&0x0001))
1026 /* get current vertical position of beam */
1027 #define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe))
1030 * Copper Initialisation List
1033 #define COPINITSIZE (sizeof(copins)*40)
1040 * Long Frame/Short Frame Copper List
1041 * Don't change the order, build_copper()/rebuild_copper() rely on this
1044 #define COPLISTSIZE (sizeof(copins)*64)
1047 cop_wait, cop_bplcon0,
1048 cop_spr0ptrh, cop_spr0ptrl,
1049 cop_diwstrt, cop_diwstop,
1054 * Pixel modes for Bitplanes and Sprites
1057 static u_short bplpixmode[3] = {
1058 BPC0_SHRES, /* 35 ns */
1059 BPC0_HIRES, /* 70 ns */
1063 static u_short sprpixmode[3] = {
1064 BPC3_SPRES1 | BPC3_SPRES0, /* 35 ns */
1065 BPC3_SPRES1, /* 70 ns */
1066 BPC3_SPRES0 /* 140 ns */
1070 * Fetch modes for Bitplanes and Sprites
1073 static u_short bplfetchmode[3] = {
1075 FMODE_BPL32, /* 2x */
1076 FMODE_BPAGEM | FMODE_BPL32 /* 4x */
1079 static u_short sprfetchmode[3] = {
1081 FMODE_SPR32, /* 2x */
1082 FMODE_SPAGEM | FMODE_SPR32 /* 4x */
1087 * Interface used by the world
1090 int amifb_setup(char*);
1092 static int amifb_get_fix(struct fb_fix_screeninfo *fix, int con,
1093 struct fb_info *info);
1094 static int amifb_get_var(struct fb_var_screeninfo *var, int con,
1095 struct fb_info *info);
1096 static int amifb_set_var(struct fb_var_screeninfo *var, int con,
1097 struct fb_info *info);
1098 static int amifb_pan_display(struct fb_var_screeninfo *var, int con,
1099 struct fb_info *info);
1100 static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
1101 struct fb_info *info);
1102 static int amifb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
1103 struct fb_info *info);
1104 static int amifb_ioctl(struct inode *inode, struct file *file, u_int cmd,
1105 u_long arg, int con, struct fb_info *info);
1107 static int amifb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
1108 static int amifb_get_var_cursorinfo(struct fb_var_cursorinfo *var,
1109 u_char *data, int con);
1110 static int amifb_set_var_cursorinfo(struct fb_var_cursorinfo *var,
1111 u_char *data, int con);
1112 static int amifb_get_cursorstate(struct fb_cursorstate *state, int con);
1113 static int amifb_set_cursorstate(struct fb_cursorstate *state, int con);
1116 * Interface to the low level console driver
1119 int amifb_init(void);
1120 static void amifb_deinit(void);
1121 static int amifbcon_switch(int con, struct fb_info *info);
1122 static int amifbcon_updatevar(int con, struct fb_info *info);
1123 static void amifbcon_blank(int blank, struct fb_info *info);
1129 static void do_install_cmap(int con, struct fb_info *info);
1130 static int flash_cursor(void);
1131 static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
1132 static u_long chipalloc(u_long size);
1133 static void chipfree(void);
1134 static char *strtoke(char *s,const char *ct);
1140 static int ami_encode_fix(struct fb_fix_screeninfo *fix,
1141 struct amifb_par *par);
1142 static int ami_decode_var(struct fb_var_screeninfo *var,
1143 struct amifb_par *par);
1144 static int ami_encode_var(struct fb_var_screeninfo *var,
1145 struct amifb_par *par);
1146 static void ami_get_par(struct amifb_par *par);
1147 static void ami_set_var(struct fb_var_screeninfo *var);
1149 static void ami_set_par(struct amifb_par *par);
1151 static void ami_pan_var(struct fb_var_screeninfo *var);
1152 static int ami_update_par(void);
1153 static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
1154 u_int *transp, struct fb_info *info);
1155 static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
1156 u_int transp, struct fb_info *info);
1157 static void ami_update_display(void);
1158 static void ami_init_display(void);
1159 static void ami_do_blank(void);
1160 static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
1161 static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
1162 static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
1163 static int ami_get_cursorstate(struct fb_cursorstate *state, int con);
1164 static int ami_set_cursorstate(struct fb_cursorstate *state, int con);
1165 static void ami_set_sprite(void);
1166 static void ami_init_copper(void);
1167 static void ami_reinit_copper(void);
1168 static void ami_build_copper(void);
1169 static void ami_rebuild_copper(void);
1172 static struct fb_ops amifb_ops = {
1174 fb_get_fix: amifb_get_fix,
1175 fb_get_var: amifb_get_var,
1176 fb_set_var: amifb_set_var,
1177 fb_get_cmap: amifb_get_cmap,
1178 fb_set_cmap: amifb_set_cmap,
1179 fb_pan_display: amifb_pan_display,
1180 fb_ioctl: amifb_ioctl,
1183 int __init amifb_setup(char *options)
1188 mcap_spec[0] = '\0';
1189 fb_info.fontname[0] = '\0';
1191 if (!options || !*options)
1194 while ((this_opt = strsep(&options, ",")) != NULL) {
1197 if (!strcmp(this_opt, "inverse")) {
1200 } else if (!strcmp(this_opt, "off")) {
1202 } else if (!strcmp(this_opt, "ilbm"))
1204 else if (!strncmp(this_opt, "monitorcap:", 11))
1205 strcpy(mcap_spec, this_opt+11);
1206 else if (!strncmp(this_opt, "font:", 5))
1207 strcpy(fb_info.fontname, this_opt+5);
1208 else if (!strncmp(this_opt, "fstart:", 7))
1209 min_fstrt = simple_strtoul(this_opt+7, NULL, 0);
1211 mode_option = this_opt;
1219 int vmin, vmax, hmin, hmax;
1221 /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
1222 * <V*> vertical freq. in Hz
1223 * <H*> horizontal freq. in kHz
1226 if (!(p = strtoke(mcap_spec, ";")) || !*p)
1228 vmin = simple_strtoul(p, NULL, 10);
1231 if (!(p = strtoke(NULL, ";")) || !*p)
1233 vmax = simple_strtoul(p, NULL, 10);
1234 if (vmax <= 0 || vmax <= vmin)
1236 if (!(p = strtoke(NULL, ";")) || !*p)
1238 hmin = 1000 * simple_strtoul(p, NULL, 10);
1241 if (!(p = strtoke(NULL, "")) || !*p)
1243 hmax = 1000 * simple_strtoul(p, NULL, 10);
1244 if (hmax <= 0 || hmax <= hmin)
1247 fb_info.monspecs.vfmin = vmin;
1248 fb_info.monspecs.vfmax = vmax;
1249 fb_info.monspecs.hfmin = hmin;
1250 fb_info.monspecs.hfmax = hmax;
1258 * Get the Fixed Part of the Display
1261 static int amifb_get_fix(struct fb_fix_screeninfo *fix, int con,
1262 struct fb_info *info)
1264 struct amifb_par par;
1271 if ((err = ami_decode_var(&fb_display[con].var, &par)))
1274 return ami_encode_fix(fix, &par);
1278 * Get the User Defined Part of the Display
1281 static int amifb_get_var(struct fb_var_screeninfo *var, int con,
1282 struct fb_info *info)
1287 struct amifb_par par;
1290 err = ami_encode_var(var, &par);
1292 *var = fb_display[con].var;
1297 * Set the User Defined Part of the Display
1300 static int amifb_set_var(struct fb_var_screeninfo *var, int con,
1301 struct fb_info *info)
1303 int err, activate = var->activate;
1304 int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
1305 struct amifb_par par;
1307 struct display *display;
1309 display = &fb_display[con];
1311 display = &disp; /* used during initialization */
1314 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
1315 * as FB_VMODE_SMOOTH_XPAN is only used internally
1318 if (var->vmode & FB_VMODE_CONUPDATE) {
1319 var->vmode |= FB_VMODE_YWRAP;
1320 var->xoffset = display->var.xoffset;
1321 var->yoffset = display->var.yoffset;
1323 if ((err = ami_decode_var(var, &par)))
1325 ami_encode_var(var, &par);
1326 if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
1327 oldxres = display->var.xres;
1328 oldyres = display->var.yres;
1329 oldvxres = display->var.xres_virtual;
1330 oldvyres = display->var.yres_virtual;
1331 oldbpp = display->var.bits_per_pixel;
1332 display->var = *var;
1333 if (oldxres != var->xres || oldyres != var->yres ||
1334 oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
1335 oldbpp != var->bits_per_pixel) {
1336 struct fb_fix_screeninfo fix;
1338 ami_encode_fix(&fix, &par);
1339 display->screen_base = (char *)videomemory;
1340 display->visual = fix.visual;
1341 display->type = fix.type;
1342 display->type_aux = fix.type_aux;
1343 display->ypanstep = fix.ypanstep;
1344 display->ywrapstep = fix.ywrapstep;
1345 display->line_length = fix.line_length;
1346 display->can_soft_blank = 1;
1347 display->inverse = amifb_inverse;
1349 #ifdef FBCON_HAS_ILBM
1350 case FB_TYPE_INTERLEAVED_PLANES:
1351 display->dispsw = &fbcon_ilbm;
1354 #ifdef FBCON_HAS_AFB
1355 case FB_TYPE_PLANES:
1356 display->dispsw = &fbcon_afb;
1359 #ifdef FBCON_HAS_MFB
1360 case FB_TYPE_PACKED_PIXELS: /* depth == 1 */
1361 display->dispsw = &fbcon_mfb;
1365 display->dispsw = &fbcon_dummy;
1367 if (fb_info.changevar)
1368 (*fb_info.changevar)(con);
1370 if (oldbpp != var->bits_per_pixel) {
1371 if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
1373 do_install_cmap(con, info);
1376 ami_set_var(&display->var);
1382 * Pan or Wrap the Display
1384 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
1387 static int amifb_pan_display(struct fb_var_screeninfo *var, int con,
1388 struct fb_info *info)
1390 if (var->vmode & FB_VMODE_YWRAP) {
1391 if (var->yoffset<0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
1395 * TODO: There will be problems when xpan!=1, so some columns
1396 * on the right side will never be seen
1398 if (var->xoffset+fb_display[con].var.xres > upx(16<<maxfmode, fb_display[con].var.xres_virtual) ||
1399 var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
1404 fb_display[con].var.xoffset = var->xoffset;
1405 fb_display[con].var.yoffset = var->yoffset;
1406 if (var->vmode & FB_VMODE_YWRAP)
1407 fb_display[con].var.vmode |= FB_VMODE_YWRAP;
1409 fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
1417 static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
1418 struct fb_info *info)
1420 if (con == currcon) /* current console? */
1421 return fb_get_cmap(cmap, kspc, ami_getcolreg, info);
1422 else if (fb_display[con].cmap.len) /* non default colormap? */
1423 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
1425 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
1426 cmap, kspc ? 0 : 2);
1434 static int amifb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
1435 struct fb_info *info)
1439 if (!fb_display[con].cmap.len) { /* no colormap allocated? */
1440 if ((err = fb_alloc_cmap(&fb_display[con].cmap,
1441 1<<fb_display[con].var.bits_per_pixel,
1445 if (con == currcon) /* current console? */
1446 return fb_set_cmap(cmap, kspc, ami_setcolreg, info);
1448 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
1453 * Amiga Frame Buffer Specific ioctls
1456 static int amifb_ioctl(struct inode *inode, struct file *file,
1457 u_int cmd, u_long arg, int con, struct fb_info *info)
1462 case FBIOGET_FCURSORINFO : {
1463 struct fb_fix_cursorinfo crsrfix;
1465 i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix));
1467 i = amifb_get_fix_cursorinfo(&crsrfix, con);
1468 copy_to_user((void *)arg, &crsrfix, sizeof(crsrfix));
1472 case FBIOGET_VCURSORINFO : {
1473 struct fb_var_cursorinfo crsrvar;
1475 i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar));
1477 i = amifb_get_var_cursorinfo(&crsrvar,
1478 ((struct fb_var_cursorinfo *)arg)->data, con);
1479 copy_to_user((void *)arg, &crsrvar, sizeof(crsrvar));
1483 case FBIOPUT_VCURSORINFO : {
1484 struct fb_var_cursorinfo crsrvar;
1486 i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar));
1488 copy_from_user(&crsrvar, (void *)arg, sizeof(crsrvar));
1489 i = amifb_set_var_cursorinfo(&crsrvar,
1490 ((struct fb_var_cursorinfo *)arg)->data, con);
1494 case FBIOGET_CURSORSTATE : {
1495 struct fb_cursorstate crsrstate;
1497 i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate));
1499 i = amifb_get_cursorstate(&crsrstate, con);
1500 copy_to_user((void *)arg, &crsrstate, sizeof(crsrstate));
1504 case FBIOPUT_CURSORSTATE : {
1505 struct fb_cursorstate crsrstate;
1507 i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate));
1509 copy_from_user(&crsrstate, (void *)arg, sizeof(crsrstate));
1510 i = amifb_set_cursorstate(&crsrstate, con);
1515 case FBCMD_GET_CURRENTPAR : {
1516 struct amifb_par par;
1518 i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct amifb_par));
1521 copy_to_user((void *)arg, &par, sizeof(struct amifb_par));
1525 case FBCMD_SET_CURRENTPAR : {
1526 struct amifb_par par;
1528 i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct amifb_par));
1530 copy_from_user(&par, (void *)arg, sizeof(struct amifb_par));
1544 static int amifb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
1546 return ami_get_fix_cursorinfo(fix, con);
1549 static int amifb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
1551 return ami_get_var_cursorinfo(var, data, con);
1554 static int amifb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
1556 return ami_set_var_cursorinfo(var, data, con);
1559 static int amifb_get_cursorstate(struct fb_cursorstate *state, int con)
1561 return ami_get_cursorstate(state, con);
1564 static int amifb_set_cursorstate(struct fb_cursorstate *state, int con)
1566 return ami_set_cursorstate(state, con);
1571 * Allocate, Clear and Align a Block of Chip Memory
1574 static u_long unaligned_chipptr = 0;
1576 static inline u_long __init chipalloc(u_long size)
1578 size += PAGE_SIZE-1;
1579 if (!(unaligned_chipptr = (u_long)amiga_chip_alloc(size,
1581 panic("No Chip RAM for frame buffer");
1582 memset((void *)unaligned_chipptr, 0, size);
1583 return PAGE_ALIGN(unaligned_chipptr);
1586 static inline void chipfree(void)
1588 if (unaligned_chipptr)
1589 amiga_chip_free((void *)unaligned_chipptr);
1597 int __init amifb_init(void)
1599 int tag, i, err = 0;
1602 struct fb_var_screeninfo var;
1604 if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO))
1608 * TODO: where should we put this? The DMI Resolver doesn't have a
1609 * frame buffer accessible by the CPU
1612 #ifdef CONFIG_GSP_RESOLVER
1613 if (amifb_resolver){
1614 custom.dmacon = DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
1615 DMAF_BLITTER | DMAF_SPRITE;
1621 * We request all registers starting from bplpt[0]
1623 if (!request_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120,
1624 "amifb [Denise/Lisa]"))
1627 custom.dmacon = DMAF_ALL | DMAF_MASTER;
1629 switch (amiga_chipset) {
1630 #ifdef CONFIG_FB_AMIGA_OCS
1632 strcat(amifb_name, "OCS");
1635 maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */
1636 maxdepth[TAG_HIRES] = 4;
1637 maxdepth[TAG_LORES] = 6;
1638 maxfmode = TAG_FMODE_1;
1639 defmode = amiga_vblank == 50 ? DEFMODE_PAL
1641 videomemorysize = VIDEOMEMSIZE_OCS;
1643 #endif /* CONFIG_FB_AMIGA_OCS */
1645 #ifdef CONFIG_FB_AMIGA_ECS
1647 strcat(amifb_name, "ECS");
1649 maxdepth[TAG_SHRES] = 2;
1650 maxdepth[TAG_HIRES] = 4;
1651 maxdepth[TAG_LORES] = 6;
1652 maxfmode = TAG_FMODE_1;
1653 if (AMIGAHW_PRESENT(AMBER_FF))
1654 defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL
1655 : DEFMODE_AMBER_NTSC;
1657 defmode = amiga_vblank == 50 ? DEFMODE_PAL
1659 if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
1660 VIDEOMEMSIZE_ECS_1M)
1661 videomemorysize = VIDEOMEMSIZE_ECS_2M;
1663 videomemorysize = VIDEOMEMSIZE_ECS_1M;
1665 #endif /* CONFIG_FB_AMIGA_ECS */
1667 #ifdef CONFIG_FB_AMIGA_AGA
1669 strcat(amifb_name, "AGA");
1671 maxdepth[TAG_SHRES] = 8;
1672 maxdepth[TAG_HIRES] = 8;
1673 maxdepth[TAG_LORES] = 8;
1674 maxfmode = TAG_FMODE_4;
1675 defmode = DEFMODE_AGA;
1676 if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
1677 VIDEOMEMSIZE_AGA_1M)
1678 videomemorysize = VIDEOMEMSIZE_AGA_2M;
1680 videomemorysize = VIDEOMEMSIZE_AGA_1M;
1682 #endif /* CONFIG_FB_AMIGA_AGA */
1685 #ifdef CONFIG_FB_AMIGA_OCS
1686 printk("Unknown graphics chipset, defaulting to OCS\n");
1687 strcat(amifb_name, "Unknown");
1688 goto default_chipset;
1689 #else /* CONFIG_FB_AMIGA_OCS */
1692 #endif /* CONFIG_FB_AMIGA_OCS */
1697 * Calculate the Pixel Clock Values for this Machine
1701 u_long tmp = DIVUL(200E9, amiga_eclock);
1703 pixclock[TAG_SHRES] = (tmp + 4) / 8; /* SHRES: 35 ns / 28 MHz */
1704 pixclock[TAG_HIRES] = (tmp + 2) / 4; /* HIRES: 70 ns / 14 MHz */
1705 pixclock[TAG_LORES] = (tmp + 1) / 2; /* LORES: 140 ns / 7 MHz */
1709 * Replace the Tag Values with the Real Pixel Clock Values
1712 for (i = 0; i < NUM_TOTAL_MODES; i++) {
1713 struct fb_videomode *mode = &ami_modedb[i];
1714 tag = mode->pixclock;
1715 if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
1716 mode->pixclock = pixclock[tag];
1721 * These monitor specs are for a typical Amiga monitor (e.g. A1960)
1723 if (fb_info.monspecs.hfmin == 0) {
1724 fb_info.monspecs.hfmin = 15000;
1725 fb_info.monspecs.hfmax = 38000;
1726 fb_info.monspecs.vfmin = 49;
1727 fb_info.monspecs.vfmax = 90;
1730 strcpy(fb_info.modename, amifb_name);
1731 fb_info.changevar = NULL;
1733 fb_info.fbops = &amifb_ops;
1734 fb_info.disp = &disp;
1735 fb_info.switch_con = &amifbcon_switch;
1736 fb_info.updatevar = &amifbcon_updatevar;
1737 fb_info.blank = &amifbcon_blank;
1738 fb_info.flags = FBINFO_FLAG_DEFAULT;
1739 memset(&var, 0, sizeof(var));
1741 if (!fb_find_mode(&var, &fb_info, mode_option, ami_modedb,
1742 NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
1748 chipptr = chipalloc(videomemorysize+
1754 assignchunk(videomemory, u_long, chipptr, videomemorysize);
1755 assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
1756 assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
1757 assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
1758 assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);
1759 assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);
1760 assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);
1761 assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);
1764 * access the videomem with writethrough cache
1766 videomemory_phys = (u_long)ZTWO_PADDR(videomemory);
1767 videomemory = (u_long)ioremap_writethrough(videomemory_phys, videomemorysize);
1769 printk("amifb: WARNING! unable to map videomem cached writethrough\n");
1770 videomemory = ZTWO_VADDR(videomemory_phys);
1773 memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
1776 * Enable Display DMA
1779 custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
1780 DMAF_BLITTER | DMAF_SPRITE;
1783 * Make sure the Copper has something to do
1788 if (request_irq(IRQ_AMIGA_VERTB, amifb_interrupt, 0,
1789 "fb vertb handler", ¤tpar)) {
1794 amifb_set_var(&var, -1, &fb_info);
1796 if (register_framebuffer(&fb_info) < 0) {
1801 printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
1802 GET_FB_IDX(fb_info.node), fb_info.modename,
1803 videomemorysize>>10);
1812 static void amifb_deinit(void)
1815 release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
1816 custom.dmacon = DMAF_ALL | DMAF_MASTER;
1819 static int amifbcon_switch(int con, struct fb_info *info)
1821 /* Do we have to save the colormap? */
1822 if (fb_display[currcon].cmap.len)
1823 fb_get_cmap(&fb_display[currcon].cmap, 1, ami_getcolreg, info);
1826 ami_set_var(&fb_display[con].var);
1827 /* Install new colormap */
1828 do_install_cmap(con, info);
1833 * Update the `var' structure (called by fbcon.c)
1836 static int amifbcon_updatevar(int con, struct fb_info *info)
1838 ami_pan_var(&fb_display[con].var);
1843 * Blank the display.
1846 static void amifbcon_blank(int blank, struct fb_info *info)
1848 do_blank = blank ? blank : -1;
1855 static void do_install_cmap(int con, struct fb_info *info)
1859 if (fb_display[con].cmap.len)
1860 fb_set_cmap(&fb_display[con].cmap, 1, ami_setcolreg, info);
1862 fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
1863 1, ami_setcolreg, info);
1866 static int flash_cursor(void)
1868 static int cursorcount = 1;
1870 if (cursormode == FB_CURSOR_FLASH) {
1871 if (!--cursorcount) {
1872 cursorstate = -cursorstate;
1873 cursorcount = cursorrate;
1882 * VBlank Display Interrupt
1885 static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
1887 if (do_vmode_pan || do_vmode_full)
1888 ami_update_display();
1895 ami_rebuild_copper();
1896 do_cursor = do_vmode_pan = 0;
1897 } else if (do_cursor) {
1911 if (do_vmode_full) {
1912 ami_reinit_copper();
1918 * A strtok which returns empty strings, too
1921 static char __init *strtoke(char *s,const char *ct)
1923 char *sbegin, *send;
1924 static char *ssave = NULL;
1926 sbegin = s ? s : ssave;
1929 if (*sbegin == '\0') {
1933 send = strpbrk(sbegin, ct);
1934 if (send && *send != '\0')
1940 /* --------------------------- Hardware routines --------------------------- */
1943 * This function should fill in the `fix' structure based on the
1944 * values in the `par' structure.
1947 static int ami_encode_fix(struct fb_fix_screeninfo *fix,
1948 struct amifb_par *par)
1950 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1951 strcpy(fix->id, amifb_name);
1952 fix->smem_start = videomemory_phys;
1953 fix->smem_len = videomemorysize;
1955 #ifdef FBCON_HAS_MFB
1956 if (par->bpp == 1) {
1957 fix->type = FB_TYPE_PACKED_PIXELS;
1962 fix->type = FB_TYPE_INTERLEAVED_PLANES;
1963 fix->type_aux = par->next_line;
1965 fix->type = FB_TYPE_PLANES;
1968 fix->line_length = div8(upx(16<<maxfmode, par->vxres));
1969 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1971 if (par->vmode & FB_VMODE_YWRAP) {
1973 fix->xpanstep = fix->ypanstep = 0;
1976 if (par->vmode &= FB_VMODE_SMOOTH_XPAN)
1979 fix->xpanstep = 16<<maxfmode;
1982 fix->accel = FB_ACCEL_AMIGABLITT;
1987 * Get the video params out of `var'. If a value doesn't fit, round
1988 * it up, if it's too big, return -EINVAL.
1991 static int ami_decode_var(struct fb_var_screeninfo *var,
1992 struct amifb_par *par)
1994 u_short clk_shift, line_shift;
1995 u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;
1996 u_int htotal, vtotal;
1999 * Find a matching Pixel Clock
2002 for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++)
2003 if (var->pixclock <= pixclock[clk_shift])
2005 if (clk_shift > TAG_LORES) {
2006 DPRINTK("pixclock too high\n");
2009 par->clk_shift = clk_shift;
2012 * Check the Geometry Values
2015 if ((par->xres = var->xres) < 64)
2017 if ((par->yres = var->yres) < 64)
2019 if ((par->vxres = var->xres_virtual) < par->xres)
2020 par->vxres = par->xres;
2021 if ((par->vyres = var->yres_virtual) < par->yres)
2022 par->vyres = par->yres;
2024 par->bpp = var->bits_per_pixel;
2028 if (par->bpp > maxdepth[clk_shift]) {
2029 if (round_down_bpp && maxdepth[clk_shift])
2030 par->bpp = maxdepth[clk_shift];
2032 DPRINTK("invalid bpp\n");
2036 } else if (var->nonstd == FB_NONSTD_HAM) {
2039 if (par->bpp != 6) {
2042 if (par->bpp != 8 || !IS_AGA) {
2043 DPRINTK("invalid bpp for ham mode\n");
2048 DPRINTK("unknown nonstd mode\n");
2053 * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
2054 * checks failed and smooth scrolling is not possible
2057 par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN;
2058 switch (par->vmode & FB_VMODE_MASK) {
2059 case FB_VMODE_INTERLACED:
2062 case FB_VMODE_NONINTERLACED:
2065 case FB_VMODE_DOUBLE:
2067 DPRINTK("double mode only possible with aga\n");
2073 DPRINTK("unknown video mode\n");
2077 par->line_shift = line_shift;
2080 * Vertical and Horizontal Timings
2083 xres_n = par->xres<<clk_shift;
2084 yres_n = par->yres<<line_shift;
2085 par->htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<<clk_shift);
2086 par->vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<<line_shift)+1);
2089 par->bplcon3 = sprpixmode[clk_shift];
2092 if (var->sync & FB_SYNC_BROADCAST) {
2093 par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<<clk_shift);
2095 par->diwstop_h += mod4(var->hsync_len);
2097 par->diwstop_h = down4(par->diwstop_h);
2099 par->diwstrt_h = par->diwstop_h - xres_n;
2100 par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<<line_shift);
2101 par->diwstrt_v = par->diwstop_v - yres_n;
2102 if (par->diwstop_h >= par->htotal+8) {
2103 DPRINTK("invalid diwstop_h\n");
2106 if (par->diwstop_v > par->vtotal) {
2107 DPRINTK("invalid diwstop_v\n");
2112 /* Initialize sync with some reasonable values for pwrsave */
2123 if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) {
2124 /* PAL video mode */
2125 if (par->htotal != PAL_HTOTAL) {
2126 DPRINTK("htotal invalid for pal\n");
2129 if (par->diwstrt_h < PAL_DIWSTRT_H) {
2130 DPRINTK("diwstrt_h too low for pal\n");
2133 if (par->diwstrt_v < PAL_DIWSTRT_V) {
2134 DPRINTK("diwstrt_v too low for pal\n");
2137 htotal = PAL_HTOTAL>>clk_shift;
2138 vtotal = PAL_VTOTAL>>1;
2140 par->beamcon0 = BMC0_PAL;
2141 par->bplcon3 |= BPC3_BRDRBLNK;
2142 } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
2143 AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
2144 par->beamcon0 = BMC0_PAL;
2146 } else if (amiga_vblank != 50) {
2147 DPRINTK("pal not supported by this chipset\n");
2152 * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK
2153 * and NTSC activated, so than better let diwstop_h <= 1812
2155 if (par->htotal != NTSC_HTOTAL) {
2156 DPRINTK("htotal invalid for ntsc\n");
2159 if (par->diwstrt_h < NTSC_DIWSTRT_H) {
2160 DPRINTK("diwstrt_h too low for ntsc\n");
2163 if (par->diwstrt_v < NTSC_DIWSTRT_V) {
2164 DPRINTK("diwstrt_v too low for ntsc\n");
2167 htotal = NTSC_HTOTAL>>clk_shift;
2168 vtotal = NTSC_VTOTAL>>1;
2171 par->bplcon3 |= BPC3_BRDRBLNK;
2172 } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
2173 AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
2176 } else if (amiga_vblank != 60) {
2177 DPRINTK("ntsc not supported by this chipset\n");
2182 if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 ||
2183 par->diwstrt_v >= 512 || par->diwstop_v < 256) {
2184 DPRINTK("invalid position for display on ocs\n");
2188 } else if (!IS_OCS) {
2189 /* Programmable video mode */
2190 par->hsstrt = var->right_margin<<clk_shift;
2191 par->hsstop = (var->right_margin+var->hsync_len)<<clk_shift;
2192 par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift);
2194 par->diwstop_h = down4(par->diwstop_h) - 16;
2195 par->diwstrt_h = par->diwstop_h - xres_n;
2196 par->hbstop = par->diwstrt_h + 4;
2197 par->hbstrt = par->diwstop_h + 4;
2198 if (par->hbstrt >= par->htotal + 8)
2199 par->hbstrt -= par->htotal;
2200 par->hcenter = par->hsstrt + (par->htotal >> 1);
2201 par->vsstrt = var->lower_margin<<line_shift;
2202 par->vsstop = (var->lower_margin+var->vsync_len)<<line_shift;
2203 par->diwstop_v = par->vtotal;
2204 if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
2205 par->diwstop_v -= 2;
2206 par->diwstrt_v = par->diwstop_v - yres_n;
2207 par->vbstop = par->diwstrt_v - 2;
2208 par->vbstrt = par->diwstop_v - 2;
2209 if (par->vtotal > 2048) {
2210 DPRINTK("vtotal too high\n");
2213 if (par->htotal > 2048) {
2214 DPRINTK("htotal too high\n");
2217 par->bplcon3 |= BPC3_EXTBLKEN;
2218 par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
2219 BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
2220 BMC0_PAL | BMC0_VARCSYEN;
2221 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
2222 par->beamcon0 |= BMC0_HSYTRUE;
2223 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
2224 par->beamcon0 |= BMC0_VSYTRUE;
2225 if (var->sync & FB_SYNC_COMP_HIGH_ACT)
2226 par->beamcon0 |= BMC0_CSYTRUE;
2227 htotal = par->htotal>>clk_shift;
2228 vtotal = par->vtotal>>1;
2230 DPRINTK("only broadcast modes possible for ocs\n");
2235 * Checking the DMA timing
2238 fconst = 16<<maxfmode<<clk_shift;
2241 * smallest window start value without turn off other dma cycles
2242 * than sprite1-7, unless you change min_fstrt
2246 fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64);
2247 fstrt = downx(fconst, par->diwstrt_h-4) - fsize;
2248 if (fstrt < min_fstrt) {
2249 DPRINTK("fetch start too low\n");
2254 * smallest window start value where smooth scrolling is possible
2257 fstrt = downx(fconst, par->diwstrt_h-fconst+(1<<clk_shift)-4) - fsize;
2258 if (fstrt < min_fstrt)
2259 par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2261 maxfetchstop = down16(par->htotal - 80);
2263 fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst;
2264 fsize = upx(fconst, xres_n + modx(fconst, downx(1<<clk_shift, par->diwstrt_h-4)));
2265 if (fstrt + fsize > maxfetchstop)
2266 par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2268 fsize = upx(fconst, xres_n);
2269 if (fstrt + fsize > maxfetchstop) {
2270 DPRINTK("fetch stop too high\n");
2274 if (maxfmode + clk_shift <= 1) {
2275 fsize = up64(xres_n + fconst - 1);
2276 if (min_fstrt + fsize - 64 > maxfetchstop)
2277 par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2279 fsize = up64(xres_n);
2280 if (min_fstrt + fsize - 64 > maxfetchstop) {
2281 DPRINTK("fetch size too high\n");
2290 * Check if there is enough time to update the bitplane pointers for ywrap
2293 if (par->htotal-fsize-64 < par->bpp*64)
2294 par->vmode &= ~FB_VMODE_YWRAP;
2297 * Bitplane calculations and check the Memory Requirements
2301 par->next_plane = div8(upx(16<<maxfmode, par->vxres));
2302 par->next_line = par->bpp*par->next_plane;
2303 if (par->next_line * par->vyres > videomemorysize) {
2304 DPRINTK("too few video mem\n");
2308 par->next_line = div8(upx(16<<maxfmode, par->vxres));
2309 par->next_plane = par->vyres*par->next_line;
2310 if (par->next_plane * par->bpp > videomemorysize) {
2311 DPRINTK("too few video mem\n");
2317 * Hardware Register Values
2320 par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift];
2322 par->bplcon0 |= BPC0_ECSENA;
2324 par->bplcon0 |= BPC0_BPU3;
2326 par->bplcon0 |= par->bpp<<12;
2327 if (var->nonstd == FB_NONSTD_HAM)
2328 par->bplcon0 |= BPC0_HAM;
2329 if (var->sync & FB_SYNC_EXT)
2330 par->bplcon0 |= BPC0_ERSY;
2333 par->fmode = bplfetchmode[maxfmode];
2335 switch (par->vmode & FB_VMODE_MASK) {
2336 case FB_VMODE_INTERLACED:
2337 par->bplcon0 |= BPC0_LACE;
2339 case FB_VMODE_DOUBLE:
2341 par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
2345 if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {
2346 par->xoffset = var->xoffset;
2347 par->yoffset = var->yoffset;
2348 if (par->vmode & FB_VMODE_YWRAP) {
2349 if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres)
2350 par->xoffset = par->yoffset = 0;
2352 if (par->xoffset < 0 || par->xoffset > upx(16<<maxfmode, par->vxres-par->xres) ||
2353 par->yoffset < 0 || par->yoffset > par->vyres-par->yres)
2354 par->xoffset = par->yoffset = 0;
2357 par->xoffset = par->yoffset = 0;
2359 par->crsr.crsr_x = par->crsr.crsr_y = 0;
2360 par->crsr.spot_x = par->crsr.spot_y = 0;
2361 par->crsr.height = par->crsr.width = 0;
2363 #if 0 /* fbmon not done. uncomment for 2.5.x -brad */
2364 if (!fbmon_valid_timings(pixclock[clk_shift], htotal, vtotal,
2366 DPRINTK("mode doesn't fit for monitor\n");
2375 * Fill the `var' structure based on the values in `par' and maybe
2376 * other values read out of the hardware.
2379 static int ami_encode_var(struct fb_var_screeninfo *var,
2380 struct amifb_par *par)
2382 u_short clk_shift, line_shift;
2384 memset(var, 0, sizeof(struct fb_var_screeninfo));
2386 clk_shift = par->clk_shift;
2387 line_shift = par->line_shift;
2389 var->xres = par->xres;
2390 var->yres = par->yres;
2391 var->xres_virtual = par->vxres;
2392 var->yres_virtual = par->vyres;
2393 var->xoffset = par->xoffset;
2394 var->yoffset = par->yoffset;
2396 var->bits_per_pixel = par->bpp;
2400 var->red.offset = 0;
2401 var->red.length = 8;
2402 var->red.msb_right = 0;
2404 if (clk_shift == TAG_SHRES) {
2405 var->red.offset = 0;
2406 var->red.length = 2;
2407 var->red.msb_right = 0;
2409 var->red.offset = 0;
2410 var->red.length = 4;
2411 var->red.msb_right = 0;
2414 var->blue = var->green = var->red;
2415 var->transp.offset = 0;
2416 var->transp.length = 0;
2417 var->transp.msb_right = 0;
2419 if (par->bplcon0 & BPC0_HAM)
2420 var->nonstd = FB_NONSTD_HAM;
2428 var->pixclock = pixclock[clk_shift];
2430 if (IS_AGA && par->fmode & FMODE_BSCAN2)
2431 var->vmode = FB_VMODE_DOUBLE;
2432 else if (par->bplcon0 & BPC0_LACE)
2433 var->vmode = FB_VMODE_INTERLACED;
2435 var->vmode = FB_VMODE_NONINTERLACED;
2437 if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) {
2438 var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift;
2439 var->right_margin = par->hsstrt>>clk_shift;
2440 var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
2441 var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift;
2442 var->lower_margin = par->vsstrt>>line_shift;
2443 var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len;
2445 if (par->beamcon0 & BMC0_HSYTRUE)
2446 var->sync |= FB_SYNC_HOR_HIGH_ACT;
2447 if (par->beamcon0 & BMC0_VSYTRUE)
2448 var->sync |= FB_SYNC_VERT_HIGH_ACT;
2449 if (par->beamcon0 & BMC0_CSYTRUE)
2450 var->sync |= FB_SYNC_COMP_HIGH_ACT;
2452 var->sync = FB_SYNC_BROADCAST;
2453 var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h);
2454 var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len;
2455 var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
2456 var->vsync_len = 4>>line_shift;
2457 var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len;
2458 var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres -
2459 var->lower_margin - var->vsync_len;
2462 if (par->bplcon0 & BPC0_ERSY)
2463 var->sync |= FB_SYNC_EXT;
2464 if (par->vmode & FB_VMODE_YWRAP)
2465 var->vmode |= FB_VMODE_YWRAP;
2471 * Get current hardware setting
2474 static void ami_get_par(struct amifb_par *par)
2483 static void ami_set_var(struct fb_var_screeninfo *var)
2487 ami_decode_var(var, ¤tpar);
2493 static void ami_set_par(struct amifb_par *par)
2504 * Pan or Wrap the Display
2506 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
2510 static void ami_pan_var(struct fb_var_screeninfo *var)
2512 struct amifb_par *par = ¤tpar;
2514 par->xoffset = var->xoffset;
2515 par->yoffset = var->yoffset;
2516 if (var->vmode & FB_VMODE_YWRAP)
2517 par->vmode |= FB_VMODE_YWRAP;
2519 par->vmode &= ~FB_VMODE_YWRAP;
2530 static int ami_update_par(void)
2532 struct amifb_par *par = ¤tpar;
2533 short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod;
2535 clk_shift = par->clk_shift;
2537 if (!(par->vmode & FB_VMODE_SMOOTH_XPAN))
2538 par->xoffset = upx(16<<maxfmode, par->xoffset);
2540 fconst = 16<<maxfmode<<clk_shift;
2541 vshift = modx(16<<maxfmode, par->xoffset);
2542 fstrt = par->diwstrt_h - (vshift<<clk_shift) - 4;
2543 fsize = (par->xres+vshift)<<clk_shift;
2544 shift = modx(fconst, fstrt);
2545 move = downx(2<<maxfmode, div8(par->xoffset));
2546 if (maxfmode + clk_shift > 1) {
2547 fstrt = downx(fconst, fstrt) - 64;
2548 fsize = upx(fconst, fsize);
2549 fstop = fstrt + fsize - fconst;
2551 mod = fstrt = downx(fconst, fstrt) - fconst;
2552 fstop = fstrt + upx(fconst, fsize) - 64;
2553 fsize = up64(fsize);
2554 fstrt = fstop - fsize + 64;
2555 if (fstrt < min_fstrt) {
2556 fstop += min_fstrt - fstrt;
2559 move = move - div8((mod-fstrt)>>clk_shift);
2561 mod = par->next_line - div8(fsize>>clk_shift);
2562 par->ddfstrt = fstrt;
2563 par->ddfstop = fstop;
2564 par->bplcon1 = hscroll2hw(shift);
2566 if (par->bplcon0 & BPC0_LACE)
2567 par->bpl2mod += par->next_line;
2568 if (IS_AGA && (par->fmode & FMODE_BSCAN2))
2569 par->bpl1mod = -div8(fsize>>clk_shift);
2571 par->bpl1mod = par->bpl2mod;
2574 par->bplpt0 = videomemory_phys + par->next_line*par->yoffset + move;
2575 if (par->vmode & FB_VMODE_YWRAP) {
2576 if (par->yoffset > par->vyres-par->yres) {
2577 par->bplpt0wrap = videomemory_phys + move;
2578 if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset))
2579 par->bplpt0wrap += par->next_line;
2583 par->bplpt0 = videomemory_phys + move;
2585 if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
2586 par->bplpt0 += par->next_line;
2592 * Read a single color register and split it into
2593 * colors/transparent. Return != 0 for invalid regno.
2596 static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
2597 u_int *transp, struct fb_info *info)
2599 int len, tr, tg, tb;
2605 } else if (currentpar.bplcon0 & BPC0_SHRES) {
2614 tr = palette[regno].red>>(8-len);
2615 tg = palette[regno].green>>(8-len);
2616 tb = palette[regno].blue>>(8-len);
2632 * Set a single color register. The values supplied are already
2633 * rounded down to the hardware's capabilities (according to the
2634 * entries in the var structure). Return != 0 for invalid regno.
2637 static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
2638 u_int transp, struct fb_info *info)
2643 } else if (currentpar.bplcon0 & BPC0_SHRES) {
2653 palette[regno].red = red;
2654 palette[regno].green = green;
2655 palette[regno].blue = blue;
2658 * Update the corresponding Hardware Color Register, unless it's Color
2659 * Register 0 and the screen is blanked.
2661 * VBlank is switched off to protect bplcon3 or ecs_palette[] from
2662 * being changed by ami_do_blank() during the VBlank.
2665 if (regno || !is_blanked) {
2666 #if defined(CONFIG_FB_AMIGA_AGA)
2668 u_short bplcon3 = currentpar.bplcon3;
2670 custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000);
2671 custom.color[regno&31] = rgb2hw8_high(red, green, blue);
2672 custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT;
2673 custom.color[regno&31] = rgb2hw8_low(red, green, blue);
2674 custom.bplcon3 = bplcon3;
2678 #if defined(CONFIG_FB_AMIGA_ECS)
2679 if (currentpar.bplcon0 & BPC0_SHRES) {
2680 u_short color, mask;
2684 color = rgb2hw2(red, green, blue);
2686 for (i = regno+12; i >= (int)regno; i -= 4)
2687 custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
2688 mask <<=2; color >>= 2;
2689 regno = down16(regno)+mul4(mod4(regno));
2690 for (i = regno+3; i >= (int)regno; i--)
2691 custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
2695 custom.color[regno] = rgb2hw4(red, green, blue);
2700 static void ami_update_display(void)
2702 struct amifb_par *par = ¤tpar;
2704 custom.bplcon1 = par->bplcon1;
2705 custom.bpl1mod = par->bpl1mod;
2706 custom.bpl2mod = par->bpl2mod;
2707 custom.ddfstrt = ddfstrt2hw(par->ddfstrt);
2708 custom.ddfstop = ddfstop2hw(par->ddfstop);
2712 * Change the video mode (called by VBlank interrupt)
2715 static void ami_init_display(void)
2717 struct amifb_par *par = ¤tpar;
2719 custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
2720 custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
2722 custom.bplcon3 = par->bplcon3;
2724 custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
2725 if (par->beamcon0 & BMC0_VARBEAMEN) {
2726 custom.htotal = htotal2hw(par->htotal);
2727 custom.hbstrt = hbstrt2hw(par->hbstrt);
2728 custom.hbstop = hbstop2hw(par->hbstop);
2729 custom.hsstrt = hsstrt2hw(par->hsstrt);
2730 custom.hsstop = hsstop2hw(par->hsstop);
2731 custom.hcenter = hcenter2hw(par->hcenter);
2732 custom.vtotal = vtotal2hw(par->vtotal);
2733 custom.vbstrt = vbstrt2hw(par->vbstrt);
2734 custom.vbstop = vbstop2hw(par->vbstop);
2735 custom.vsstrt = vsstrt2hw(par->vsstrt);
2736 custom.vsstop = vsstop2hw(par->vsstop);
2739 if (!IS_OCS || par->hsstop)
2740 custom.beamcon0 = par->beamcon0;
2742 custom.fmode = par->fmode;
2745 * The minimum period for audio depends on htotal
2748 amiga_audio_min_period = div16(par->htotal);
2750 is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
2753 if (custom.vposr & 0x8000)
2754 custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
2756 custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][0]);
2758 custom.vposw = custom.vposr | 0x8000;
2759 custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
2762 custom.vposw = custom.vposr | 0x8000;
2763 custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
2768 * (Un)Blank the screen (called by VBlank interrupt)
2771 static void ami_do_blank(void)
2773 struct amifb_par *par = ¤tpar;
2774 #if defined(CONFIG_FB_AMIGA_AGA)
2775 u_short bplcon3 = par->bplcon3;
2777 u_char red, green, blue;
2780 custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
2781 red = green = blue = 0;
2782 if (!IS_OCS && do_blank > 1) {
2783 switch (do_blank-1) {
2784 case VESA_VSYNC_SUSPEND:
2785 custom.hsstrt = hsstrt2hw(par->hsstrt);
2786 custom.hsstop = hsstop2hw(par->hsstop);
2787 custom.vsstrt = vsstrt2hw(par->vtotal+4);
2788 custom.vsstop = vsstop2hw(par->vtotal+4);
2790 case VESA_HSYNC_SUSPEND:
2791 custom.hsstrt = hsstrt2hw(par->htotal+16);
2792 custom.hsstop = hsstop2hw(par->htotal+16);
2793 custom.vsstrt = vsstrt2hw(par->vsstrt);
2794 custom.vsstop = vsstrt2hw(par->vsstop);
2796 case VESA_POWERDOWN:
2797 custom.hsstrt = hsstrt2hw(par->htotal+16);
2798 custom.hsstop = hsstop2hw(par->htotal+16);
2799 custom.vsstrt = vsstrt2hw(par->vtotal+4);
2800 custom.vsstop = vsstop2hw(par->vtotal+4);
2803 if (!(par->beamcon0 & BMC0_VARBEAMEN)) {
2804 custom.htotal = htotal2hw(par->htotal);
2805 custom.vtotal = vtotal2hw(par->vtotal);
2806 custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN |
2807 BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN;
2811 custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
2812 red = palette[0].red;
2813 green = palette[0].green;
2814 blue = palette[0].blue;
2816 custom.hsstrt = hsstrt2hw(par->hsstrt);
2817 custom.hsstop = hsstop2hw(par->hsstop);
2818 custom.vsstrt = vsstrt2hw(par->vsstrt);
2819 custom.vsstop = vsstop2hw(par->vsstop);
2820 custom.beamcon0 = par->beamcon0;
2823 #if defined(CONFIG_FB_AMIGA_AGA)
2825 custom.bplcon3 = bplcon3;
2826 custom.color[0] = rgb2hw8_high(red, green, blue);
2827 custom.bplcon3 = bplcon3 | BPC3_LOCT;
2828 custom.color[0] = rgb2hw8_low(red, green, blue);
2829 custom.bplcon3 = bplcon3;
2832 #if defined(CONFIG_FB_AMIGA_ECS)
2833 if (par->bplcon0 & BPC0_SHRES) {
2834 u_short color, mask;
2838 color = rgb2hw2(red, green, blue);
2839 for (i = 12; i >= 0; i -= 4)
2840 custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
2841 mask <<=2; color >>= 2;
2842 for (i = 3; i >= 0; i--)
2843 custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
2846 custom.color[0] = rgb2hw4(red, green, blue);
2847 is_blanked = do_blank > 0 ? do_blank : 0;
2851 * Flash the cursor (called by VBlank interrupt)
2854 static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
2856 struct amifb_par *par = ¤tpar;
2858 fix->crsr_width = fix->crsr_xsize = par->crsr.width;
2859 fix->crsr_height = fix->crsr_ysize = par->crsr.height;
2860 fix->crsr_color1 = 17;
2861 fix->crsr_color2 = 18;
2865 static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
2867 struct amifb_par *par = ¤tpar;
2868 register u_short *lspr, *sspr;
2870 register u_long datawords asm ("d2");
2872 register u_long datawords;
2874 register short delta;
2875 register u_char color;
2876 short height, width, bits, words;
2879 size = par->crsr.height*par->crsr.width;
2880 alloc = var->height*var->width;
2881 var->height = par->crsr.height;
2882 var->width = par->crsr.width;
2883 var->xspot = par->crsr.spot_x;
2884 var->yspot = par->crsr.spot_y;
2885 if (size > var->height*var->width)
2886 return -ENAMETOOLONG;
2887 if ((i = verify_area(VERIFY_WRITE, (void *)data, size)))
2889 delta = 1<<par->crsr.fmode;
2890 lspr = lofsprite + (delta<<1);
2891 if (par->bplcon0 & BPC0_LACE)
2892 sspr = shfsprite + (delta<<1);
2895 for (height = (short)var->height-1; height >= 0; height--) {
2896 bits = 0; words = delta; datawords = 0;
2897 for (width = (short)var->width-1; width >= 0; width--) {
2901 asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0"
2902 : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta));
2904 datawords = (*(lspr+delta) << 16) | (*lspr++);
2910 "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; "
2911 "swap %1 ; lslw #1,%1 ; roxlb #1,%0"
2912 : "=d" (color), "=d" (datawords) : "1" (datawords));
2914 color = (((datawords >> 30) & 2)
2915 | ((datawords >> 15) & 1));
2918 put_user(color, data++);
2923 while (--words >= 0)
2926 asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
2927 : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
2931 u_short *tmp = lspr;
2940 static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
2942 struct amifb_par *par = ¤tpar;
2943 register u_short *lspr, *sspr;
2945 register u_long datawords asm ("d2");
2947 register u_long datawords;
2949 register short delta;
2951 short height, width, bits, words;
2956 else if (var->width <= 16)
2957 fmode = TAG_FMODE_1;
2958 else if (var->width <= 32)
2959 fmode = TAG_FMODE_2;
2960 else if (var->width <= 64)
2961 fmode = TAG_FMODE_4;
2964 if (fmode > maxfmode)
2968 if ((i = verify_area(VERIFY_READ, (void *)data, var->width*var->height)))
2971 lofsprite = shfsprite = (u_short *)spritememory;
2972 lspr = lofsprite + (delta<<1);
2973 if (par->bplcon0 & BPC0_LACE) {
2974 if (((var->height+4)<<fmode<<2) > SPRITEMEMSIZE)
2976 memset(lspr, 0, (var->height+4)<<fmode<<2);
2977 shfsprite += ((var->height+5)&-2)<<fmode;
2978 sspr = shfsprite + (delta<<1);
2980 if (((var->height+2)<<fmode<<2) > SPRITEMEMSIZE)
2982 memset(lspr, 0, (var->height+2)<<fmode<<2);
2985 for (height = (short)var->height-1; height >= 0; height--) {
2986 bits = 16; words = delta; datawords = 0;
2987 for (width = (short)var->width-1; width >= 0; width--) {
2988 unsigned long tdata = 0;
2989 get_user(tdata, (char *)data);
2993 "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; "
2994 "lsrb #1,%2 ; roxlw #1,%0 ; swap %0"
2996 : "0" (datawords), "d" (tdata));
2998 datawords = ((datawords << 1) & 0xfffefffe);
2999 datawords |= tdata & 1;
3000 datawords |= (tdata & 2) << (16-1);
3005 asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+"
3006 : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta));
3008 *(lspr+delta) = (u_short) (datawords >> 16);
3009 *lspr++ = (u_short) (datawords & 0xffff);
3017 "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; "
3018 "swap %2 ; lslw %4,%2 ; movew %2,%0@+"
3019 : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits));
3021 *(lspr+delta) = (u_short) (datawords >> (16+bits));
3022 *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits);
3025 while (--words >= 0) {
3027 asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+"
3028 : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0");
3035 asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
3036 : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
3040 u_short *tmp = lspr;
3046 par->crsr.height = var->height;
3047 par->crsr.width = var->width;
3048 par->crsr.spot_x = var->xspot;
3049 par->crsr.spot_y = var->yspot;
3050 par->crsr.fmode = fmode;
3052 par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32);
3053 par->fmode |= sprfetchmode[fmode];
3054 custom.fmode = par->fmode;
3059 static int ami_get_cursorstate(struct fb_cursorstate *state, int con)
3061 struct amifb_par *par = ¤tpar;
3063 state->xoffset = par->crsr.crsr_x;
3064 state->yoffset = par->crsr.crsr_y;
3065 state->mode = cursormode;
3069 static int ami_set_cursorstate(struct fb_cursorstate *state, int con)
3071 struct amifb_par *par = ¤tpar;
3073 par->crsr.crsr_x = state->xoffset;
3074 par->crsr.crsr_y = state->yoffset;
3075 if ((cursormode = state->mode) == FB_CURSOR_OFF)
3081 static void ami_set_sprite(void)
3083 struct amifb_par *par = ¤tpar;
3084 copins *copl, *cops;
3089 cops = copdisplay.list[currentcop][0];
3090 copl = copdisplay.list[currentcop][1];
3091 ps = pl = ZTWO_PADDR(dummysprite);
3092 mx = par->crsr.crsr_x-par->crsr.spot_x;
3093 my = par->crsr.crsr_y-par->crsr.spot_y;
3094 if (!(par->vmode & FB_VMODE_YWRAP)) {
3098 if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 &&
3099 mx > -(short)par->crsr.width && mx < par->xres &&
3100 my > -(short)par->crsr.height && my < par->yres) {
3101 pl = ZTWO_PADDR(lofsprite);
3102 hs = par->diwstrt_h + (mx<<par->clk_shift) - 4;
3103 vs = par->diwstrt_v + (my<<par->line_shift);
3104 ve = vs + (par->crsr.height<<par->line_shift);
3105 if (par->bplcon0 & BPC0_LACE) {
3106 ps = ZTWO_PADDR(shfsprite);
3107 lofsprite[0] = spr2hw_pos(vs, hs);
3108 shfsprite[0] = spr2hw_pos(vs+1, hs);
3110 lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
3111 shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1);
3112 pt = pl; pl = ps; ps = pt;
3114 lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve+1);
3115 shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve);
3118 lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0);
3119 lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
3122 copl[cop_spr0ptrh].w[1] = highw(pl);
3123 copl[cop_spr0ptrl].w[1] = loww(pl);
3124 if (par->bplcon0 & BPC0_LACE) {
3125 cops[cop_spr0ptrh].w[1] = highw(ps);
3126 cops[cop_spr0ptrl].w[1] = loww(ps);
3131 * Initialise the Copper Initialisation List
3134 static void __init ami_init_copper(void)
3136 copins *cop = copdisplay.init;
3141 (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
3142 (cop++)->l = CMOVE(0x0181, diwstrt);
3143 (cop++)->l = CMOVE(0x0281, diwstop);
3144 (cop++)->l = CMOVE(0x0000, diwhigh);
3146 (cop++)->l = CMOVE(BPC0_COLOR, bplcon0);
3147 p = ZTWO_PADDR(dummysprite);
3148 for (i = 0; i < 8; i++) {
3149 (cop++)->l = CMOVE(0, spr[i].pos);
3150 (cop++)->l = CMOVE(highw(p), sprpt[i]);
3151 (cop++)->l = CMOVE2(loww(p), sprpt[i]);
3154 (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);
3155 copdisplay.wait = cop;
3157 (cop++)->l = CMOVE(0, copjmp2);
3160 custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);
3164 static void ami_reinit_copper(void)
3166 struct amifb_par *par = ¤tpar;
3168 copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0;
3169 copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4);
3173 * Build the Copper List
3176 static void ami_build_copper(void)
3178 struct amifb_par *par = ¤tpar;
3179 copins *copl, *cops;
3182 currentcop = 1 - currentcop;
3184 copl = copdisplay.list[currentcop][1];
3186 (copl++)->l = CWAIT(0, 10);
3187 (copl++)->l = CMOVE(par->bplcon0, bplcon0);
3188 (copl++)->l = CMOVE(0, sprpt[0]);
3189 (copl++)->l = CMOVE2(0, sprpt[0]);
3191 if (par->bplcon0 & BPC0_LACE) {
3192 cops = copdisplay.list[currentcop][0];
3194 (cops++)->l = CWAIT(0, 10);
3195 (cops++)->l = CMOVE(par->bplcon0, bplcon0);
3196 (cops++)->l = CMOVE(0, sprpt[0]);
3197 (cops++)->l = CMOVE2(0, sprpt[0]);
3199 (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt);
3200 (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop);
3201 (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
3202 (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
3204 (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1,
3205 par->diwstop_h, par->diwstop_v+1), diwhigh);
3206 (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
3207 par->diwstop_h, par->diwstop_v), diwhigh);
3209 if (par->beamcon0 & BMC0_VARBEAMEN) {
3210 (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3211 (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt);
3212 (copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop);
3213 (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3214 (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
3215 (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
3219 p = ZTWO_PADDR(copdisplay.list[currentcop][0]);
3220 (copl++)->l = CMOVE(highw(p), cop2lc);
3221 (copl++)->l = CMOVE2(loww(p), cop2lc);
3222 p = ZTWO_PADDR(copdisplay.list[currentcop][1]);
3223 (cops++)->l = CMOVE(highw(p), cop2lc);
3224 (cops++)->l = CMOVE2(loww(p), cop2lc);
3225 copdisplay.rebuild[0] = cops;
3227 (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
3228 (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
3230 (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
3231 par->diwstop_h, par->diwstop_v), diwhigh);
3233 if (par->beamcon0 & BMC0_VARBEAMEN) {
3234 (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3235 (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
3236 (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
3241 copdisplay.rebuild[1] = copl;
3244 ami_rebuild_copper();
3248 * Rebuild the Copper List
3250 * We only change the things that are not static
3253 static void ami_rebuild_copper(void)
3255 struct amifb_par *par = ¤tpar;
3256 copins *copl, *cops;
3257 u_short line, h_end1, h_end2;
3261 if (IS_AGA && maxfmode + par->clk_shift == 0)
3262 h_end1 = par->diwstrt_h-64;
3264 h_end1 = par->htotal-32;
3265 h_end2 = par->ddfstop+64;
3269 copl = copdisplay.rebuild[1];
3271 if (par->vmode & FB_VMODE_YWRAP) {
3272 if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) {
3273 if (par->yoffset > par->vyres-par->yres) {
3274 for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3275 (copl++)->l = CMOVE(highw(p), bplpt[i]);
3276 (copl++)->l = CMOVE2(loww(p), bplpt[i]);
3278 line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 1;
3279 while (line >= 512) {
3280 (copl++)->l = CWAIT(h_end1, 510);
3283 if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0)
3284 (copl++)->l = CWAIT(h_end1, line);
3286 (copl++)->l = CWAIT(h_end2, line);
3287 p = par->bplpt0wrap;
3289 } else p = par->bplpt0wrap;
3291 for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3292 (copl++)->l = CMOVE(highw(p), bplpt[i]);
3293 (copl++)->l = CMOVE2(loww(p), bplpt[i]);
3297 if (par->bplcon0 & BPC0_LACE) {
3298 cops = copdisplay.rebuild[0];
3300 if (mod2(par->diwstrt_v))
3301 p -= par->next_line;
3303 p += par->next_line;
3304 if (par->vmode & FB_VMODE_YWRAP) {
3305 if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) {
3306 if (par->yoffset > par->vyres-par->yres+1) {
3307 for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3308 (cops++)->l = CMOVE(highw(p), bplpt[i]);
3309 (cops++)->l = CMOVE2(loww(p), bplpt[i]);
3311 line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 2;
3312 while (line >= 512) {
3313 (cops++)->l = CWAIT(h_end1, 510);
3316 if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0)
3317 (cops++)->l = CWAIT(h_end1, line);
3319 (cops++)->l = CWAIT(h_end2, line);
3320 p = par->bplpt0wrap;
3321 if (mod2(par->diwstrt_v+par->vyres-par->yoffset))
3322 p -= par->next_line;
3324 p += par->next_line;
3326 } else p = par->bplpt0wrap - par->next_line;
3328 for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3329 (cops++)->l = CMOVE(highw(p), bplpt[i]);
3330 (cops++)->l = CMOVE2(loww(p), bplpt[i]);
3338 MODULE_LICENSE("GPL");
3340 int init_module(void)
3342 return amifb_init();
3345 void cleanup_module(void)
3347 unregister_framebuffer(&fb_info);