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/delay.h>
49 #include <linux/interrupt.h>
51 #include <linux/init.h>
52 #include <linux/ioport.h>
53 #include <linux/platform_device.h>
54 #include <linux/uaccess.h>
56 #include <asm/system.h>
58 #include <asm/amigahw.h>
59 #include <asm/amigaints.h>
60 #include <asm/setup.h>
67 #if !defined(CONFIG_FB_AMIGA_OCS) && !defined(CONFIG_FB_AMIGA_ECS) && !defined(CONFIG_FB_AMIGA_AGA)
68 #define CONFIG_FB_AMIGA_OCS /* define at least one fb driver, this will change later */
71 #if !defined(CONFIG_FB_AMIGA_OCS)
73 #elif defined(CONFIG_FB_AMIGA_ECS) || defined(CONFIG_FB_AMIGA_AGA)
74 # define IS_OCS (chipset == TAG_OCS)
76 # define CONFIG_FB_AMIGA_OCS_ONLY
80 #if !defined(CONFIG_FB_AMIGA_ECS)
82 #elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_AGA)
83 # define IS_ECS (chipset == TAG_ECS)
85 # define CONFIG_FB_AMIGA_ECS_ONLY
89 #if !defined(CONFIG_FB_AMIGA_AGA)
91 #elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_ECS)
92 # define IS_AGA (chipset == TAG_AGA)
94 # define CONFIG_FB_AMIGA_AGA_ONLY
99 # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
101 # define DPRINTK(fmt, args...)
104 /*******************************************************************************
107 Generic video timings
108 ---------------------
110 Timings used by the frame buffer interface:
112 +----------+---------------------------------------------+----------+-------+
114 | | |upper_margin | | |
116 +----------###############################################----------+-------+
121 | left # | # right | hsync |
122 | margin # | xres # margin | len |
123 |<-------->#<---------------+--------------------------->#<-------->|<----->|
137 +----------###############################################----------+-------+
139 | | |lower_margin | | |
141 +----------+---------------------------------------------+----------+-------+
145 +----------+---------------------------------------------+----------+-------+
151 The Amiga native chipsets uses another timing scheme:
153 - hsstrt: Start of horizontal synchronization pulse
154 - hsstop: End of horizontal synchronization pulse
155 - htotal: Last value on the line (i.e. line length = htotal + 1)
156 - vsstrt: Start of vertical synchronization pulse
157 - vsstop: End of vertical synchronization pulse
158 - vtotal: Last line value (i.e. number of lines = vtotal + 1)
159 - hcenter: Start of vertical retrace for interlace
161 You can specify the blanking timings independently. Currently I just set
162 them equal to the respective synchronization values:
164 - hbstrt: Start of horizontal blank
165 - hbstop: End of horizontal blank
166 - vbstrt: Start of vertical blank
167 - vbstop: End of vertical blank
169 Horizontal values are in color clock cycles (280 ns), vertical values are in
172 (0, 0) is somewhere in the upper-left corner :-)
175 Amiga visible window definitions
176 --------------------------------
178 Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to
179 make corrections and/or additions.
181 Within the above synchronization specifications, the visible window is
182 defined by the following parameters (actual register resolutions may be
183 different; all horizontal values are normalized with respect to the pixel
186 - diwstrt_h: Horizontal start of the visible window
187 - diwstop_h: Horizontal stop + 1(*) of the visible window
188 - diwstrt_v: Vertical start of the visible window
189 - diwstop_v: Vertical stop of the visible window
190 - ddfstrt: Horizontal start of display DMA
191 - ddfstop: Horizontal stop of display DMA
192 - hscroll: Horizontal display output delay
196 - sprstrt_h: Horizontal start - 4 of sprite
197 - sprstrt_v: Vertical start of sprite
199 (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1.
201 Horizontal values are in dotclock cycles (35 ns), vertical values are in
204 (0, 0) is somewhere in the upper-left corner :-)
207 Dependencies (AGA, SHRES (35 ns dotclock))
208 -------------------------------------------
210 Since there are much more parameters for the Amiga display than for the
211 frame buffer interface, there must be some dependencies among the Amiga
212 display parameters. Here's what I found out:
214 - ddfstrt and ddfstop are best aligned to 64 pixels.
215 - the chipset needs 64 + 4 horizontal pixels after the DMA start before
216 the first pixel is output, so diwstrt_h = ddfstrt + 64 + 4 if you want
217 to display the first pixel on the line too. Increase diwstrt_h for
218 virtual screen panning.
219 - the display DMA always fetches 64 pixels at a time (fmode = 3).
220 - ddfstop is ddfstrt+#pixels - 64.
221 - diwstop_h = diwstrt_h + xres + 1. Because of the additional 1 this can
222 be 1 more than htotal.
223 - hscroll simply adds a delay to the display output. Smooth horizontal
224 panning needs an extra 64 pixels on the left to prefetch the pixels that
225 `fall off' on the left.
226 - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane
227 DMA, so it's best to make the DMA start as late as possible.
228 - you really don't want to make ddfstrt < 128, since this will steal DMA
229 cycles from the other DMA channels (audio, floppy and Chip RAM refresh).
230 - I make diwstop_h and diwstop_v as large as possible.
235 - all values are SHRES pixel (35ns)
237 table 1:fetchstart table 2:prefetch table 3:fetchsize
238 ------------------ ---------------- -----------------
239 Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES
240 -------------#------+-----+------#------+-----+------#------+-----+------
241 Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64
242 Bus width 2x # 32 | 64 | 128 # 32 | 64 | 64 # 64 | 64 | 128
243 Bus width 4x # 64 | 128 | 256 # 64 | 64 | 64 # 64 | 128 | 256
245 - chipset needs 4 pixels before the first pixel is output
246 - ddfstrt must be aligned to fetchstart (table 1)
247 - chipset needs also prefetch (table 2) to get first pixel data, so
248 ddfstrt = ((diwstrt_h - 4) & -fetchstart) - prefetch
249 - for horizontal panning decrease diwstrt_h
250 - the length of a fetchline must be aligned to fetchsize (table 3)
251 - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit
252 moved to optimize use of dma (useful for OCS/ECS overscan displays)
253 - ddfstop is ddfstrt + ddfsize - fetchsize
254 - If C= didn't change anything for AGA, then at following positions the
255 dma bus is already used:
256 ddfstrt < 48 -> memory refresh
259 < 192 -> sprite 0 dma
260 < 416 -> sprite dma (32 per sprite)
261 - in accordance with the hardware reference manual a hardware stop is at
262 192, but AGA (ECS?) can go below this.
267 Since there are limits on the earliest start value for display DMA and the
268 display of sprites, I use the following policy on horizontal panning and
271 - if you want to start display DMA too early, you lose the ability to
272 do smooth horizontal panning (xpanstep 1 -> 64).
273 - if you want to go even further, you lose the hardware cursor too.
275 IMHO a hardware cursor is more important for X than horizontal scrolling,
276 so that's my motivation.
282 ami_decode_var() converts the frame buffer values to the Amiga values. It's
283 just a `straightforward' implementation of the above rules.
289 xres yres left right upper lower hsync vsync
290 ---- ---- ---- ----- ----- ----- ----- -----
291 80x25 720 400 27 45 35 12 108 2
292 80x30 720 480 27 45 30 9 108 2
294 These were taken from a XFree86 configuration file, recalculated for a 28 MHz
295 dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer
298 As a comparison, graphics/monitor.h suggests the following:
300 xres yres left right upper lower hsync vsync
301 ---- ---- ---- ----- ----- ----- ----- -----
303 VGA 640 480 52 112 24 19 112 - 2 +
304 VGA70 640 400 52 112 27 21 112 - 2 -
310 VSYNC HSYNC Vertical size Vertical total
311 ----- ----- ------------- --------------
312 + + Reserved Reserved
317 Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992
320 Broadcast video timings
321 -----------------------
323 According to the CCIR and RETMA specifications, we have the following values:
328 - a scanline is 64 µs long, of which 52.48 µs are visible. This is about
329 736 visible 70 ns pixels per line.
330 - we have 625 scanlines, of which 575 are visible (interlaced); after
331 rounding this becomes 576.
336 - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about
337 736 visible 70 ns pixels per line.
338 - we have 525 scanlines, of which 485 are visible (interlaced); after
339 rounding this becomes 484.
341 Thus if you want a PAL compatible display, you have to do the following:
343 - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast
344 timings are to be used.
345 - make sure upper_margin + yres + lower_margin + vsync_len = 625 for an
346 interlaced, 312 for a non-interlaced and 156 for a doublescanned
348 - make sure left_margin + xres + right_margin + hsync_len = 1816 for a
349 SHRES, 908 for a HIRES and 454 for a LORES display.
350 - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90),
351 left_margin + 2 * hsync_len must be greater or equal.
352 - the upper visible part begins at 48 (interlaced; non-interlaced:24,
353 doublescanned:12), upper_margin + 2 * vsync_len must be greater or
355 - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync
358 The settings for a NTSC compatible display are straightforward.
360 Note that in a strict sense the PAL and NTSC standards only define the
361 encoding of the color part (chrominance) of the video signal and don't say
362 anything about horizontal/vertical synchronization nor refresh rates.
367 *******************************************************************************/
371 * Custom Chipset Definitions
374 #define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld)
377 * BPLCON0 -- Bitplane Control Register 0
380 #define BPC0_HIRES (0x8000)
381 #define BPC0_BPU2 (0x4000) /* Bit plane used count */
382 #define BPC0_BPU1 (0x2000)
383 #define BPC0_BPU0 (0x1000)
384 #define BPC0_HAM (0x0800) /* HAM mode */
385 #define BPC0_DPF (0x0400) /* Double playfield */
386 #define BPC0_COLOR (0x0200) /* Enable colorburst */
387 #define BPC0_GAUD (0x0100) /* Genlock audio enable */
388 #define BPC0_UHRES (0x0080) /* Ultrahi res enable */
389 #define BPC0_SHRES (0x0040) /* Super hi res mode */
390 #define BPC0_BYPASS (0x0020) /* Bypass LUT - AGA */
391 #define BPC0_BPU3 (0x0010) /* AGA */
392 #define BPC0_LPEN (0x0008) /* Light pen enable */
393 #define BPC0_LACE (0x0004) /* Interlace */
394 #define BPC0_ERSY (0x0002) /* External resync */
395 #define BPC0_ECSENA (0x0001) /* ECS enable */
398 * BPLCON2 -- Bitplane Control Register 2
401 #define BPC2_ZDBPSEL2 (0x4000) /* Bitplane to be used for ZD - AGA */
402 #define BPC2_ZDBPSEL1 (0x2000)
403 #define BPC2_ZDBPSEL0 (0x1000)
404 #define BPC2_ZDBPEN (0x0800) /* Enable ZD with ZDBPSELx - AGA */
405 #define BPC2_ZDCTEN (0x0400) /* Enable ZD with palette bit #31 - AGA */
406 #define BPC2_KILLEHB (0x0200) /* Kill EHB mode - AGA */
407 #define BPC2_RDRAM (0x0100) /* Color table accesses read, not write - AGA */
408 #define BPC2_SOGEN (0x0080) /* SOG output pin high - AGA */
409 #define BPC2_PF2PRI (0x0040) /* PF2 priority over PF1 */
410 #define BPC2_PF2P2 (0x0020) /* PF2 priority wrt sprites */
411 #define BPC2_PF2P1 (0x0010)
412 #define BPC2_PF2P0 (0x0008)
413 #define BPC2_PF1P2 (0x0004) /* ditto PF1 */
414 #define BPC2_PF1P1 (0x0002)
415 #define BPC2_PF1P0 (0x0001)
418 * BPLCON3 -- Bitplane Control Register 3 (AGA)
421 #define BPC3_BANK2 (0x8000) /* Bits to select color register bank */
422 #define BPC3_BANK1 (0x4000)
423 #define BPC3_BANK0 (0x2000)
424 #define BPC3_PF2OF2 (0x1000) /* Bits for color table offset when PF2 */
425 #define BPC3_PF2OF1 (0x0800)
426 #define BPC3_PF2OF0 (0x0400)
427 #define BPC3_LOCT (0x0200) /* Color register writes go to low bits */
428 #define BPC3_SPRES1 (0x0080) /* Sprite resolution bits */
429 #define BPC3_SPRES0 (0x0040)
430 #define BPC3_BRDRBLNK (0x0020) /* Border blanked? */
431 #define BPC3_BRDRTRAN (0x0010) /* Border transparent? */
432 #define BPC3_ZDCLKEN (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */
433 #define BPC3_BRDRSPRT (0x0002) /* Sprites in border? */
434 #define BPC3_EXTBLKEN (0x0001) /* BLANK programmable */
437 * BPLCON4 -- Bitplane Control Register 4 (AGA)
440 #define BPC4_BPLAM7 (0x8000) /* bitplane color XOR field */
441 #define BPC4_BPLAM6 (0x4000)
442 #define BPC4_BPLAM5 (0x2000)
443 #define BPC4_BPLAM4 (0x1000)
444 #define BPC4_BPLAM3 (0x0800)
445 #define BPC4_BPLAM2 (0x0400)
446 #define BPC4_BPLAM1 (0x0200)
447 #define BPC4_BPLAM0 (0x0100)
448 #define BPC4_ESPRM7 (0x0080) /* 4 high bits for even sprite colors */
449 #define BPC4_ESPRM6 (0x0040)
450 #define BPC4_ESPRM5 (0x0020)
451 #define BPC4_ESPRM4 (0x0010)
452 #define BPC4_OSPRM7 (0x0008) /* 4 high bits for odd sprite colors */
453 #define BPC4_OSPRM6 (0x0004)
454 #define BPC4_OSPRM5 (0x0002)
455 #define BPC4_OSPRM4 (0x0001)
458 * BEAMCON0 -- Beam Control Register
461 #define BMC0_HARDDIS (0x4000) /* Disable hardware limits */
462 #define BMC0_LPENDIS (0x2000) /* Disable light pen latch */
463 #define BMC0_VARVBEN (0x1000) /* Enable variable vertical blank */
464 #define BMC0_LOLDIS (0x0800) /* Disable long/short line toggle */
465 #define BMC0_CSCBEN (0x0400) /* Composite sync/blank */
466 #define BMC0_VARVSYEN (0x0200) /* Enable variable vertical sync */
467 #define BMC0_VARHSYEN (0x0100) /* Enable variable horizontal sync */
468 #define BMC0_VARBEAMEN (0x0080) /* Enable variable beam counters */
469 #define BMC0_DUAL (0x0040) /* Enable alternate horizontal beam counter */
470 #define BMC0_PAL (0x0020) /* Set decodes for PAL */
471 #define BMC0_VARCSYEN (0x0010) /* Enable variable composite sync */
472 #define BMC0_BLANKEN (0x0008) /* Blank enable (no longer used on AGA) */
473 #define BMC0_CSYTRUE (0x0004) /* CSY polarity */
474 #define BMC0_VSYTRUE (0x0002) /* VSY polarity */
475 #define BMC0_HSYTRUE (0x0001) /* HSY polarity */
479 * FMODE -- Fetch Mode Control Register (AGA)
482 #define FMODE_SSCAN2 (0x8000) /* Sprite scan-doubling */
483 #define FMODE_BSCAN2 (0x4000) /* Use PF2 modulus every other line */
484 #define FMODE_SPAGEM (0x0008) /* Sprite page mode */
485 #define FMODE_SPR32 (0x0004) /* Sprite 32 bit fetch */
486 #define FMODE_BPAGEM (0x0002) /* Bitplane page mode */
487 #define FMODE_BPL32 (0x0001) /* Bitplane 32 bit fetch */
490 * Tags used to indicate a specific Pixel Clock
492 * clk_shift is the shift value to get the timings in 35 ns units
495 enum { TAG_SHRES
, TAG_HIRES
, TAG_LORES
};
498 * Tags used to indicate the specific chipset
501 enum { TAG_OCS
, TAG_ECS
, TAG_AGA
};
504 * Tags used to indicate the memory bandwidth
507 enum { TAG_FMODE_1
, TAG_FMODE_2
, TAG_FMODE_4
};
511 * Clock Definitions, Maximum Display Depth
513 * These depend on the E-Clock or the Chipset, so they are filled in
517 static u_long pixclock
[3]; /* SHRES/HIRES/LORES: index = clk_shift */
518 static u_short maxdepth
[3]; /* SHRES/HIRES/LORES: index = clk_shift */
519 static u_short maxfmode
, chipset
;
523 * Broadcast Video Timings
525 * Horizontal values are in 35 ns (SHRES) units
526 * Vertical values are in interlaced scanlines
529 #define PAL_DIWSTRT_H (360) /* PAL Window Limits */
530 #define PAL_DIWSTRT_V (48)
531 #define PAL_HTOTAL (1816)
532 #define PAL_VTOTAL (625)
534 #define NTSC_DIWSTRT_H (360) /* NTSC Window Limits */
535 #define NTSC_DIWSTRT_V (40)
536 #define NTSC_HTOTAL (1816)
537 #define NTSC_VTOTAL (525)
544 #define up2(v) (((v) + 1) & -2)
545 #define down2(v) ((v) & -2)
546 #define div2(v) ((v)>>1)
547 #define mod2(v) ((v) & 1)
549 #define up4(v) (((v) + 3) & -4)
550 #define down4(v) ((v) & -4)
551 #define mul4(v) ((v) << 2)
552 #define div4(v) ((v)>>2)
553 #define mod4(v) ((v) & 3)
555 #define up8(v) (((v) + 7) & -8)
556 #define down8(v) ((v) & -8)
557 #define div8(v) ((v)>>3)
558 #define mod8(v) ((v) & 7)
560 #define up16(v) (((v) + 15) & -16)
561 #define down16(v) ((v) & -16)
562 #define div16(v) ((v)>>4)
563 #define mod16(v) ((v) & 15)
565 #define up32(v) (((v) + 31) & -32)
566 #define down32(v) ((v) & -32)
567 #define div32(v) ((v)>>5)
568 #define mod32(v) ((v) & 31)
570 #define up64(v) (((v) + 63) & -64)
571 #define down64(v) ((v) & -64)
572 #define div64(v) ((v)>>6)
573 #define mod64(v) ((v) & 63)
575 #define upx(x, v) (((v) + (x) - 1) & -(x))
576 #define downx(x, v) ((v) & -(x))
577 #define modx(x, v) ((v) & ((x) - 1))
579 /* if x1 is not a constant, this macro won't make real sense :-) */
581 #define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \
582 "d" (x2), "d" ((long)((x1) / 0x100000000ULL)), "0" ((long)(x1))); res;})
584 /* We know a bit about the numbers, so we can do it this way */
585 #define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \
586 ((((long)((unsigned long long)x1 >> 8) % x2) << 8) / x2))
589 #define highw(x) ((u_long)(x)>>16 & 0xffff)
590 #define loww(x) ((u_long)(x) & 0xffff)
592 #define custom amiga_custom
594 #define VBlankOn() custom.intena = IF_SETCLR|IF_COPER
595 #define VBlankOff() custom.intena = IF_COPER
599 * Chip RAM we reserve for the Frame Buffer
601 * This defines the Maximum Virtual Screen Size
602 * (Setable per kernel options?)
605 #define VIDEOMEMSIZE_AGA_2M (1310720) /* AGA (2MB) : max 1280*1024*256 */
606 #define VIDEOMEMSIZE_AGA_1M (786432) /* AGA (1MB) : max 1024*768*256 */
607 #define VIDEOMEMSIZE_ECS_2M (655360) /* ECS (2MB) : max 1280*1024*16 */
608 #define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */
609 #define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */
611 #define SPRITEMEMSIZE (64 * 64 / 4) /* max 64*64*4 */
612 #define DUMMYSPRITEMEMSIZE (8)
613 static u_long spritememory
;
615 #define CHIPRAM_SAFETY_LIMIT (16384)
617 static u_long videomemory
;
620 * This is the earliest allowed start of fetching display data.
621 * Only if you really want no hardware cursor and audio,
622 * set this to 128, but let it better at 192
625 static u_long min_fstrt
= 192;
627 #define assignchunk(name, type, ptr, size) \
629 (name) = (type)(ptr); \
635 * Copper Instructions
638 #define CMOVE(val, reg) (CUSTOM_OFS(reg) << 16 | (val))
639 #define CMOVE2(val, reg) ((CUSTOM_OFS(reg) + 2) << 16 | (val))
640 #define CWAIT(x, y) (((y) & 0x1fe) << 23 | ((x) & 0x7f0) << 13 | 0x0001fffe)
641 #define CEND (0xfffffffe)
649 static struct copdisplay
{
656 static u_short currentcop
= 0;
659 * Hardware Cursor API Definitions
660 * These used to be in linux/fb.h, but were preliminary and used by
664 #define FBIOGET_FCURSORINFO 0x4607
665 #define FBIOGET_VCURSORINFO 0x4608
666 #define FBIOPUT_VCURSORINFO 0x4609
667 #define FBIOGET_CURSORSTATE 0x460A
668 #define FBIOPUT_CURSORSTATE 0x460B
671 struct fb_fix_cursorinfo
{
672 __u16 crsr_width
; /* width and height of the cursor in */
673 __u16 crsr_height
; /* pixels (zero if no cursor) */
674 __u16 crsr_xsize
; /* cursor size in display pixels */
676 __u16 crsr_color1
; /* colormap entry for cursor color1 */
677 __u16 crsr_color2
; /* colormap entry for cursor color2 */
680 struct fb_var_cursorinfo
{
685 __u8 data
[1]; /* field with [height][width] */
688 struct fb_cursorstate
{
694 #define FB_CURSOR_OFF 0
695 #define FB_CURSOR_ON 1
696 #define FB_CURSOR_FLASH 2
703 static int cursorrate
= 20; /* Number of frames/flash toggle */
704 static u_short cursorstate
= -1;
705 static u_short cursormode
= FB_CURSOR_OFF
;
707 static u_short
*lofsprite
, *shfsprite
, *dummysprite
;
717 int xres
; /* vmode */
718 int yres
; /* vmode */
719 int vxres
; /* vmode */
720 int vyres
; /* vmode */
721 int xoffset
; /* vmode */
722 int yoffset
; /* vmode */
723 u_short bpp
; /* vmode */
724 u_short clk_shift
; /* vmode */
725 u_short line_shift
; /* vmode */
726 int vmode
; /* vmode */
727 u_short diwstrt_h
; /* vmode */
728 u_short diwstop_h
; /* vmode */
729 u_short diwstrt_v
; /* vmode */
730 u_short diwstop_v
; /* vmode */
731 u_long next_line
; /* modulo for next line */
732 u_long next_plane
; /* modulo for next plane */
737 short crsr_x
; /* movecursor */
738 short crsr_y
; /* movecursor */
746 /* OCS Hardware Registers */
748 u_long bplpt0
; /* vmode, pan (Note: physical address) */
749 u_long bplpt0wrap
; /* vmode, pan (Note: physical address) */
754 u_short bplcon0
; /* vmode */
755 u_short bplcon1
; /* vmode */
756 u_short htotal
; /* vmode */
757 u_short vtotal
; /* vmode */
759 /* Additional ECS Hardware Registers */
761 u_short bplcon3
; /* vmode */
762 u_short beamcon0
; /* vmode */
763 u_short hsstrt
; /* vmode */
764 u_short hsstop
; /* vmode */
765 u_short hbstrt
; /* vmode */
766 u_short hbstop
; /* vmode */
767 u_short vsstrt
; /* vmode */
768 u_short vsstop
; /* vmode */
769 u_short vbstrt
; /* vmode */
770 u_short vbstop
; /* vmode */
771 u_short hcenter
; /* vmode */
773 /* Additional AGA Hardware Registers */
775 u_short fmode
; /* vmode */
780 * Saved color entry 0 so we can restore it when unblanking
783 static u_char red0
, green0
, blue0
;
786 #if defined(CONFIG_FB_AMIGA_ECS)
787 static u_short ecs_palette
[32];
792 * Latches for Display Changes during VBlank
795 static u_short do_vmode_full
= 0; /* Change the Video Mode */
796 static u_short do_vmode_pan
= 0; /* Update the Video Mode */
797 static short do_blank
= 0; /* (Un)Blank the Screen (±1) */
798 static u_short do_cursor
= 0; /* Move the Cursor */
805 static u_short is_blanked
= 0; /* Screen is Blanked */
806 static u_short is_lace
= 0; /* Screen is laced */
809 * Predefined Video Modes
813 static struct fb_videomode ami_modedb
[] __initdata
= {
816 * AmigaOS Video Modes
818 * If you change these, make sure to update DEFMODE_* as well!
822 /* 640x200, 15 kHz, 60 Hz (NTSC) */
823 "ntsc", 60, 640, 200, TAG_HIRES
, 106, 86, 44, 16, 76, 2,
824 FB_SYNC_BROADCAST
, FB_VMODE_NONINTERLACED
| FB_VMODE_YWRAP
826 /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
827 "ntsc-lace", 60, 640, 400, TAG_HIRES
, 106, 86, 88, 33, 76, 4,
828 FB_SYNC_BROADCAST
, FB_VMODE_INTERLACED
| FB_VMODE_YWRAP
830 /* 640x256, 15 kHz, 50 Hz (PAL) */
831 "pal", 50, 640, 256, TAG_HIRES
, 106, 86, 40, 14, 76, 2,
832 FB_SYNC_BROADCAST
, FB_VMODE_NONINTERLACED
| FB_VMODE_YWRAP
834 /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
835 "pal-lace", 50, 640, 512, TAG_HIRES
, 106, 86, 80, 29, 76, 4,
836 FB_SYNC_BROADCAST
, FB_VMODE_INTERLACED
| FB_VMODE_YWRAP
838 /* 640x480, 29 kHz, 57 Hz */
839 "multiscan", 57, 640, 480, TAG_SHRES
, 96, 112, 29, 8, 72, 8,
840 0, FB_VMODE_NONINTERLACED
| FB_VMODE_YWRAP
842 /* 640x960, 29 kHz, 57 Hz interlaced */
843 "multiscan-lace", 57, 640, 960, TAG_SHRES
, 96, 112, 58, 16, 72,
845 0, FB_VMODE_INTERLACED
| FB_VMODE_YWRAP
847 /* 640x200, 15 kHz, 72 Hz */
848 "euro36", 72, 640, 200, TAG_HIRES
, 92, 124, 6, 6, 52, 5,
849 0, FB_VMODE_NONINTERLACED
| FB_VMODE_YWRAP
851 /* 640x400, 15 kHz, 72 Hz interlaced */
852 "euro36-lace", 72, 640, 400, TAG_HIRES
, 92, 124, 12, 12, 52,
854 0, FB_VMODE_INTERLACED
| FB_VMODE_YWRAP
856 /* 640x400, 29 kHz, 68 Hz */
857 "euro72", 68, 640, 400, TAG_SHRES
, 164, 92, 9, 9, 80, 8,
858 0, FB_VMODE_NONINTERLACED
| FB_VMODE_YWRAP
860 /* 640x800, 29 kHz, 68 Hz interlaced */
861 "euro72-lace", 68, 640, 800, TAG_SHRES
, 164, 92, 18, 18, 80,
863 0, FB_VMODE_INTERLACED
| FB_VMODE_YWRAP
865 /* 800x300, 23 kHz, 70 Hz */
866 "super72", 70, 800, 300, TAG_SHRES
, 212, 140, 10, 11, 80, 7,
867 0, FB_VMODE_NONINTERLACED
| FB_VMODE_YWRAP
869 /* 800x600, 23 kHz, 70 Hz interlaced */
870 "super72-lace", 70, 800, 600, TAG_SHRES
, 212, 140, 20, 22, 80,
872 0, FB_VMODE_INTERLACED
| FB_VMODE_YWRAP
874 /* 640x200, 27 kHz, 57 Hz doublescan */
875 "dblntsc", 57, 640, 200, TAG_SHRES
, 196, 124, 18, 17, 80, 4,
876 0, FB_VMODE_DOUBLE
| FB_VMODE_YWRAP
878 /* 640x400, 27 kHz, 57 Hz */
879 "dblntsc-ff", 57, 640, 400, TAG_SHRES
, 196, 124, 36, 35, 80, 7,
880 0, FB_VMODE_NONINTERLACED
| FB_VMODE_YWRAP
882 /* 640x800, 27 kHz, 57 Hz interlaced */
883 "dblntsc-lace", 57, 640, 800, TAG_SHRES
, 196, 124, 72, 70, 80,
885 0, FB_VMODE_INTERLACED
| FB_VMODE_YWRAP
887 /* 640x256, 27 kHz, 47 Hz doublescan */
888 "dblpal", 47, 640, 256, TAG_SHRES
, 196, 124, 14, 13, 80, 4,
889 0, FB_VMODE_DOUBLE
| FB_VMODE_YWRAP
891 /* 640x512, 27 kHz, 47 Hz */
892 "dblpal-ff", 47, 640, 512, TAG_SHRES
, 196, 124, 28, 27, 80, 7,
893 0, FB_VMODE_NONINTERLACED
| FB_VMODE_YWRAP
895 /* 640x1024, 27 kHz, 47 Hz interlaced */
896 "dblpal-lace", 47, 640, 1024, TAG_SHRES
, 196, 124, 56, 54, 80,
898 0, FB_VMODE_INTERLACED
| FB_VMODE_YWRAP
906 /* 640x480, 31 kHz, 60 Hz (VGA) */
907 "vga", 60, 640, 480, TAG_SHRES
, 64, 96, 30, 9, 112, 2,
908 0, FB_VMODE_NONINTERLACED
| FB_VMODE_YWRAP
910 /* 640x400, 31 kHz, 70 Hz (VGA) */
911 "vga70", 70, 640, 400, TAG_SHRES
, 64, 96, 35, 12, 112, 2,
912 FB_SYNC_VERT_HIGH_ACT
| FB_SYNC_COMP_HIGH_ACT
,
913 FB_VMODE_NONINTERLACED
| FB_VMODE_YWRAP
920 * These modes don't work yet because there's no A2024 driver.
924 /* 1024x800, 10 Hz */
925 "a2024-10", 10, 1024, 800, TAG_HIRES
, 0, 0, 0, 0, 0, 0,
926 0, FB_VMODE_NONINTERLACED
| FB_VMODE_YWRAP
928 /* 1024x800, 15 Hz */
929 "a2024-15", 15, 1024, 800, TAG_HIRES
, 0, 0, 0, 0, 0, 0,
930 0, FB_VMODE_NONINTERLACED
| FB_VMODE_YWRAP
935 #define NUM_TOTAL_MODES ARRAY_SIZE(ami_modedb)
937 static char *mode_option __initdata
= NULL
;
938 static int round_down_bpp
= 1; /* for mode probing */
945 #define DEFMODE_PAL 2 /* "pal" for PAL OCS/ECS */
946 #define DEFMODE_NTSC 0 /* "ntsc" for NTSC OCS/ECS */
947 #define DEFMODE_AMBER_PAL 3 /* "pal-lace" for flicker fixed PAL (A3000) */
948 #define DEFMODE_AMBER_NTSC 1 /* "ntsc-lace" for flicker fixed NTSC (A3000) */
949 #define DEFMODE_AGA 19 /* "vga70" for AGA */
952 static int amifb_ilbm
= 0; /* interleaved or normal bitplanes */
953 static int amifb_inverse
= 0;
955 static u32 amifb_hfmin __initdata
; /* monitor hfreq lower limit (Hz) */
956 static u32 amifb_hfmax __initdata
; /* monitor hfreq upper limit (Hz) */
957 static u16 amifb_vfmin __initdata
; /* monitor vfreq lower limit (Hz) */
958 static u16 amifb_vfmax __initdata
; /* monitor vfreq upper limit (Hz) */
962 * Macros for the conversion from real world values to hardware register
965 * This helps us to keep our attention on the real stuff...
967 * Hardware limits for AGA:
969 * parameter min max step
970 * --------- --- ---- ----
992 * Horizontal values are in 35 ns (SHRES) pixels
993 * Vertical values are in half scanlines
996 /* bplcon1 (smooth scrolling) */
998 #define hscroll2hw(hscroll) \
999 (((hscroll) << 12 & 0x3000) | ((hscroll) << 8 & 0xc300) | \
1000 ((hscroll) << 4 & 0x0c00) | ((hscroll) << 2 & 0x00f0) | \
1001 ((hscroll)>>2 & 0x000f))
1003 /* diwstrt/diwstop/diwhigh (visible display window) */
1005 #define diwstrt2hw(diwstrt_h, diwstrt_v) \
1006 (((diwstrt_v) << 7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
1007 #define diwstop2hw(diwstop_h, diwstop_v) \
1008 (((diwstop_v) << 7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
1009 #define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \
1010 (((diwstop_h) << 3 & 0x2000) | ((diwstop_h) << 11 & 0x1800) | \
1011 ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \
1012 ((diwstrt_h) << 3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007))
1014 /* ddfstrt/ddfstop (display DMA) */
1016 #define ddfstrt2hw(ddfstrt) div8(ddfstrt)
1017 #define ddfstop2hw(ddfstop) div8(ddfstop)
1019 /* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */
1021 #define hsstrt2hw(hsstrt) (div8(hsstrt))
1022 #define hsstop2hw(hsstop) (div8(hsstop))
1023 #define htotal2hw(htotal) (div8(htotal) - 1)
1024 #define vsstrt2hw(vsstrt) (div2(vsstrt))
1025 #define vsstop2hw(vsstop) (div2(vsstop))
1026 #define vtotal2hw(vtotal) (div2(vtotal) - 1)
1027 #define hcenter2hw(htotal) (div8(htotal))
1029 /* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
1031 #define hbstrt2hw(hbstrt) (((hbstrt) << 8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))
1032 #define hbstop2hw(hbstop) (((hbstop) << 8 & 0x0700) | ((hbstop)>>3 & 0x00ff))
1033 #define vbstrt2hw(vbstrt) (div2(vbstrt))
1034 #define vbstop2hw(vbstop) (div2(vbstop))
1038 #define rgb2hw8_high(red, green, blue) \
1039 (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4))
1040 #define rgb2hw8_low(red, green, blue) \
1041 (((red & 0x0f) << 8) | ((green & 0x0f) << 4) | (blue & 0x0f))
1042 #define rgb2hw4(red, green, blue) \
1043 (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4))
1044 #define rgb2hw2(red, green, blue) \
1045 (((red & 0xc0) << 4) | (green & 0xc0) | ((blue & 0xc0)>>4))
1047 /* sprpos/sprctl (sprite positioning) */
1049 #define spr2hw_pos(start_v, start_h) \
1050 (((start_v) << 7 & 0xff00) | ((start_h)>>3 & 0x00ff))
1051 #define spr2hw_ctl(start_v, start_h, stop_v) \
1052 (((stop_v) << 7 & 0xff00) | ((start_v)>>4 & 0x0040) | \
1053 ((stop_v)>>5 & 0x0020) | ((start_h) << 3 & 0x0018) | \
1054 ((start_v)>>7 & 0x0004) | ((stop_v)>>8 & 0x0002) | \
1055 ((start_h)>>2 & 0x0001))
1057 /* get current vertical position of beam */
1058 #define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe))
1061 * Copper Initialisation List
1064 #define COPINITSIZE (sizeof(copins) * 40)
1071 * Long Frame/Short Frame Copper List
1072 * Don't change the order, build_copper()/rebuild_copper() rely on this
1075 #define COPLISTSIZE (sizeof(copins) * 64)
1078 cop_wait
, cop_bplcon0
,
1079 cop_spr0ptrh
, cop_spr0ptrl
,
1080 cop_diwstrt
, cop_diwstop
,
1085 * Pixel modes for Bitplanes and Sprites
1088 static u_short bplpixmode
[3] = {
1089 BPC0_SHRES
, /* 35 ns */
1090 BPC0_HIRES
, /* 70 ns */
1094 static u_short sprpixmode
[3] = {
1095 BPC3_SPRES1
| BPC3_SPRES0
, /* 35 ns */
1096 BPC3_SPRES1
, /* 70 ns */
1097 BPC3_SPRES0
/* 140 ns */
1101 * Fetch modes for Bitplanes and Sprites
1104 static u_short bplfetchmode
[3] = {
1106 FMODE_BPL32
, /* 2x */
1107 FMODE_BPAGEM
| FMODE_BPL32
/* 4x */
1110 static u_short sprfetchmode
[3] = {
1112 FMODE_SPR32
, /* 2x */
1113 FMODE_SPAGEM
| FMODE_SPR32
/* 4x */
1117 /* --------------------------- Hardware routines --------------------------- */
1120 * Get the video params out of `var'. If a value doesn't fit, round
1121 * it up, if it's too big, return -EINVAL.
1124 static int ami_decode_var(struct fb_var_screeninfo
*var
, struct amifb_par
*par
,
1125 const struct fb_info
*info
)
1127 u_short clk_shift
, line_shift
;
1128 u_long maxfetchstop
, fstrt
, fsize
, fconst
, xres_n
, yres_n
;
1129 u_int htotal
, vtotal
;
1132 * Find a matching Pixel Clock
1135 for (clk_shift
= TAG_SHRES
; clk_shift
<= TAG_LORES
; clk_shift
++)
1136 if (var
->pixclock
<= pixclock
[clk_shift
])
1138 if (clk_shift
> TAG_LORES
) {
1139 DPRINTK("pixclock too high\n");
1142 par
->clk_shift
= clk_shift
;
1145 * Check the Geometry Values
1148 if ((par
->xres
= var
->xres
) < 64)
1150 if ((par
->yres
= var
->yres
) < 64)
1152 if ((par
->vxres
= var
->xres_virtual
) < par
->xres
)
1153 par
->vxres
= par
->xres
;
1154 if ((par
->vyres
= var
->yres_virtual
) < par
->yres
)
1155 par
->vyres
= par
->yres
;
1157 par
->bpp
= var
->bits_per_pixel
;
1161 if (par
->bpp
> maxdepth
[clk_shift
]) {
1162 if (round_down_bpp
&& maxdepth
[clk_shift
])
1163 par
->bpp
= maxdepth
[clk_shift
];
1165 DPRINTK("invalid bpp\n");
1169 } else if (var
->nonstd
== FB_NONSTD_HAM
) {
1172 if (par
->bpp
!= 6) {
1175 if (par
->bpp
!= 8 || !IS_AGA
) {
1176 DPRINTK("invalid bpp for ham mode\n");
1181 DPRINTK("unknown nonstd mode\n");
1186 * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
1187 * checks failed and smooth scrolling is not possible
1190 par
->vmode
= var
->vmode
| FB_VMODE_SMOOTH_XPAN
;
1191 switch (par
->vmode
& FB_VMODE_MASK
) {
1192 case FB_VMODE_INTERLACED
:
1195 case FB_VMODE_NONINTERLACED
:
1198 case FB_VMODE_DOUBLE
:
1200 DPRINTK("double mode only possible with aga\n");
1206 DPRINTK("unknown video mode\n");
1210 par
->line_shift
= line_shift
;
1213 * Vertical and Horizontal Timings
1216 xres_n
= par
->xres
<< clk_shift
;
1217 yres_n
= par
->yres
<< line_shift
;
1218 par
->htotal
= down8((var
->left_margin
+ par
->xres
+ var
->right_margin
+
1219 var
->hsync_len
) << clk_shift
);
1221 down2(((var
->upper_margin
+ par
->yres
+ var
->lower_margin
+
1222 var
->vsync_len
) << line_shift
) + 1);
1225 par
->bplcon3
= sprpixmode
[clk_shift
];
1228 if (var
->sync
& FB_SYNC_BROADCAST
) {
1229 par
->diwstop_h
= par
->htotal
-
1230 ((var
->right_margin
- var
->hsync_len
) << clk_shift
);
1232 par
->diwstop_h
+= mod4(var
->hsync_len
);
1234 par
->diwstop_h
= down4(par
->diwstop_h
);
1236 par
->diwstrt_h
= par
->diwstop_h
- xres_n
;
1237 par
->diwstop_v
= par
->vtotal
-
1238 ((var
->lower_margin
- var
->vsync_len
) << line_shift
);
1239 par
->diwstrt_v
= par
->diwstop_v
- yres_n
;
1240 if (par
->diwstop_h
>= par
->htotal
+ 8) {
1241 DPRINTK("invalid diwstop_h\n");
1244 if (par
->diwstop_v
> par
->vtotal
) {
1245 DPRINTK("invalid diwstop_v\n");
1250 /* Initialize sync with some reasonable values for pwrsave */
1261 if (par
->vtotal
> (PAL_VTOTAL
+ NTSC_VTOTAL
) / 2) {
1262 /* PAL video mode */
1263 if (par
->htotal
!= PAL_HTOTAL
) {
1264 DPRINTK("htotal invalid for pal\n");
1267 if (par
->diwstrt_h
< PAL_DIWSTRT_H
) {
1268 DPRINTK("diwstrt_h too low for pal\n");
1271 if (par
->diwstrt_v
< PAL_DIWSTRT_V
) {
1272 DPRINTK("diwstrt_v too low for pal\n");
1275 htotal
= PAL_HTOTAL
>>clk_shift
;
1276 vtotal
= PAL_VTOTAL
>>1;
1278 par
->beamcon0
= BMC0_PAL
;
1279 par
->bplcon3
|= BPC3_BRDRBLNK
;
1280 } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL
) ||
1281 AMIGAHW_PRESENT(AGNUS_HR_NTSC
)) {
1282 par
->beamcon0
= BMC0_PAL
;
1284 } else if (amiga_vblank
!= 50) {
1285 DPRINTK("pal not supported by this chipset\n");
1290 * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK
1291 * and NTSC activated, so than better let diwstop_h <= 1812
1293 if (par
->htotal
!= NTSC_HTOTAL
) {
1294 DPRINTK("htotal invalid for ntsc\n");
1297 if (par
->diwstrt_h
< NTSC_DIWSTRT_H
) {
1298 DPRINTK("diwstrt_h too low for ntsc\n");
1301 if (par
->diwstrt_v
< NTSC_DIWSTRT_V
) {
1302 DPRINTK("diwstrt_v too low for ntsc\n");
1305 htotal
= NTSC_HTOTAL
>>clk_shift
;
1306 vtotal
= NTSC_VTOTAL
>>1;
1309 par
->bplcon3
|= BPC3_BRDRBLNK
;
1310 } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL
) ||
1311 AMIGAHW_PRESENT(AGNUS_HR_NTSC
)) {
1314 } else if (amiga_vblank
!= 60) {
1315 DPRINTK("ntsc not supported by this chipset\n");
1320 if (par
->diwstrt_h
>= 1024 || par
->diwstop_h
< 1024 ||
1321 par
->diwstrt_v
>= 512 || par
->diwstop_v
< 256) {
1322 DPRINTK("invalid position for display on ocs\n");
1326 } else if (!IS_OCS
) {
1327 /* Programmable video mode */
1328 par
->hsstrt
= var
->right_margin
<< clk_shift
;
1329 par
->hsstop
= (var
->right_margin
+ var
->hsync_len
) << clk_shift
;
1330 par
->diwstop_h
= par
->htotal
- mod8(par
->hsstrt
) + 8 - (1 << clk_shift
);
1332 par
->diwstop_h
= down4(par
->diwstop_h
) - 16;
1333 par
->diwstrt_h
= par
->diwstop_h
- xres_n
;
1334 par
->hbstop
= par
->diwstrt_h
+ 4;
1335 par
->hbstrt
= par
->diwstop_h
+ 4;
1336 if (par
->hbstrt
>= par
->htotal
+ 8)
1337 par
->hbstrt
-= par
->htotal
;
1338 par
->hcenter
= par
->hsstrt
+ (par
->htotal
>> 1);
1339 par
->vsstrt
= var
->lower_margin
<< line_shift
;
1340 par
->vsstop
= (var
->lower_margin
+ var
->vsync_len
) << line_shift
;
1341 par
->diwstop_v
= par
->vtotal
;
1342 if ((par
->vmode
& FB_VMODE_MASK
) == FB_VMODE_INTERLACED
)
1343 par
->diwstop_v
-= 2;
1344 par
->diwstrt_v
= par
->diwstop_v
- yres_n
;
1345 par
->vbstop
= par
->diwstrt_v
- 2;
1346 par
->vbstrt
= par
->diwstop_v
- 2;
1347 if (par
->vtotal
> 2048) {
1348 DPRINTK("vtotal too high\n");
1351 if (par
->htotal
> 2048) {
1352 DPRINTK("htotal too high\n");
1355 par
->bplcon3
|= BPC3_EXTBLKEN
;
1356 par
->beamcon0
= BMC0_HARDDIS
| BMC0_VARVBEN
| BMC0_LOLDIS
|
1357 BMC0_VARVSYEN
| BMC0_VARHSYEN
| BMC0_VARBEAMEN
|
1358 BMC0_PAL
| BMC0_VARCSYEN
;
1359 if (var
->sync
& FB_SYNC_HOR_HIGH_ACT
)
1360 par
->beamcon0
|= BMC0_HSYTRUE
;
1361 if (var
->sync
& FB_SYNC_VERT_HIGH_ACT
)
1362 par
->beamcon0
|= BMC0_VSYTRUE
;
1363 if (var
->sync
& FB_SYNC_COMP_HIGH_ACT
)
1364 par
->beamcon0
|= BMC0_CSYTRUE
;
1365 htotal
= par
->htotal
>>clk_shift
;
1366 vtotal
= par
->vtotal
>>1;
1368 DPRINTK("only broadcast modes possible for ocs\n");
1373 * Checking the DMA timing
1376 fconst
= 16 << maxfmode
<< clk_shift
;
1379 * smallest window start value without turn off other dma cycles
1380 * than sprite1-7, unless you change min_fstrt
1384 fsize
= ((maxfmode
+ clk_shift
<= 1) ? fconst
: 64);
1385 fstrt
= downx(fconst
, par
->diwstrt_h
- 4) - fsize
;
1386 if (fstrt
< min_fstrt
) {
1387 DPRINTK("fetch start too low\n");
1392 * smallest window start value where smooth scrolling is possible
1395 fstrt
= downx(fconst
, par
->diwstrt_h
- fconst
+ (1 << clk_shift
) - 4) -
1397 if (fstrt
< min_fstrt
)
1398 par
->vmode
&= ~FB_VMODE_SMOOTH_XPAN
;
1400 maxfetchstop
= down16(par
->htotal
- 80);
1402 fstrt
= downx(fconst
, par
->diwstrt_h
- 4) - 64 - fconst
;
1403 fsize
= upx(fconst
, xres_n
+
1404 modx(fconst
, downx(1 << clk_shift
, par
->diwstrt_h
- 4)));
1405 if (fstrt
+ fsize
> maxfetchstop
)
1406 par
->vmode
&= ~FB_VMODE_SMOOTH_XPAN
;
1408 fsize
= upx(fconst
, xres_n
);
1409 if (fstrt
+ fsize
> maxfetchstop
) {
1410 DPRINTK("fetch stop too high\n");
1414 if (maxfmode
+ clk_shift
<= 1) {
1415 fsize
= up64(xres_n
+ fconst
- 1);
1416 if (min_fstrt
+ fsize
- 64 > maxfetchstop
)
1417 par
->vmode
&= ~FB_VMODE_SMOOTH_XPAN
;
1419 fsize
= up64(xres_n
);
1420 if (min_fstrt
+ fsize
- 64 > maxfetchstop
) {
1421 DPRINTK("fetch size too high\n");
1430 * Check if there is enough time to update the bitplane pointers for ywrap
1433 if (par
->htotal
- fsize
- 64 < par
->bpp
* 64)
1434 par
->vmode
&= ~FB_VMODE_YWRAP
;
1437 * Bitplane calculations and check the Memory Requirements
1441 par
->next_plane
= div8(upx(16 << maxfmode
, par
->vxres
));
1442 par
->next_line
= par
->bpp
* par
->next_plane
;
1443 if (par
->next_line
* par
->vyres
> info
->fix
.smem_len
) {
1444 DPRINTK("too few video mem\n");
1448 par
->next_line
= div8(upx(16 << maxfmode
, par
->vxres
));
1449 par
->next_plane
= par
->vyres
* par
->next_line
;
1450 if (par
->next_plane
* par
->bpp
> info
->fix
.smem_len
) {
1451 DPRINTK("too few video mem\n");
1457 * Hardware Register Values
1460 par
->bplcon0
= BPC0_COLOR
| bplpixmode
[clk_shift
];
1462 par
->bplcon0
|= BPC0_ECSENA
;
1464 par
->bplcon0
|= BPC0_BPU3
;
1466 par
->bplcon0
|= par
->bpp
<< 12;
1467 if (var
->nonstd
== FB_NONSTD_HAM
)
1468 par
->bplcon0
|= BPC0_HAM
;
1469 if (var
->sync
& FB_SYNC_EXT
)
1470 par
->bplcon0
|= BPC0_ERSY
;
1473 par
->fmode
= bplfetchmode
[maxfmode
];
1475 switch (par
->vmode
& FB_VMODE_MASK
) {
1476 case FB_VMODE_INTERLACED
:
1477 par
->bplcon0
|= BPC0_LACE
;
1479 case FB_VMODE_DOUBLE
:
1481 par
->fmode
|= FMODE_SSCAN2
| FMODE_BSCAN2
;
1485 if (!((par
->vmode
^ var
->vmode
) & FB_VMODE_YWRAP
)) {
1486 par
->xoffset
= var
->xoffset
;
1487 par
->yoffset
= var
->yoffset
;
1488 if (par
->vmode
& FB_VMODE_YWRAP
) {
1489 if (par
->xoffset
|| par
->yoffset
< 0 ||
1490 par
->yoffset
>= par
->vyres
)
1491 par
->xoffset
= par
->yoffset
= 0;
1493 if (par
->xoffset
< 0 ||
1494 par
->xoffset
> upx(16 << maxfmode
, par
->vxres
- par
->xres
) ||
1495 par
->yoffset
< 0 || par
->yoffset
> par
->vyres
- par
->yres
)
1496 par
->xoffset
= par
->yoffset
= 0;
1499 par
->xoffset
= par
->yoffset
= 0;
1501 par
->crsr
.crsr_x
= par
->crsr
.crsr_y
= 0;
1502 par
->crsr
.spot_x
= par
->crsr
.spot_y
= 0;
1503 par
->crsr
.height
= par
->crsr
.width
= 0;
1509 * Fill the `var' structure based on the values in `par' and maybe
1510 * other values read out of the hardware.
1513 static void ami_encode_var(struct fb_var_screeninfo
*var
,
1514 struct amifb_par
*par
)
1516 u_short clk_shift
, line_shift
;
1518 memset(var
, 0, sizeof(struct fb_var_screeninfo
));
1520 clk_shift
= par
->clk_shift
;
1521 line_shift
= par
->line_shift
;
1523 var
->xres
= par
->xres
;
1524 var
->yres
= par
->yres
;
1525 var
->xres_virtual
= par
->vxres
;
1526 var
->yres_virtual
= par
->vyres
;
1527 var
->xoffset
= par
->xoffset
;
1528 var
->yoffset
= par
->yoffset
;
1530 var
->bits_per_pixel
= par
->bpp
;
1533 var
->red
.offset
= 0;
1534 var
->red
.msb_right
= 0;
1535 var
->red
.length
= par
->bpp
;
1536 if (par
->bplcon0
& BPC0_HAM
)
1537 var
->red
.length
-= 2;
1538 var
->blue
= var
->green
= var
->red
;
1539 var
->transp
.offset
= 0;
1540 var
->transp
.length
= 0;
1541 var
->transp
.msb_right
= 0;
1543 if (par
->bplcon0
& BPC0_HAM
)
1544 var
->nonstd
= FB_NONSTD_HAM
;
1552 var
->pixclock
= pixclock
[clk_shift
];
1554 if (IS_AGA
&& par
->fmode
& FMODE_BSCAN2
)
1555 var
->vmode
= FB_VMODE_DOUBLE
;
1556 else if (par
->bplcon0
& BPC0_LACE
)
1557 var
->vmode
= FB_VMODE_INTERLACED
;
1559 var
->vmode
= FB_VMODE_NONINTERLACED
;
1561 if (!IS_OCS
&& par
->beamcon0
& BMC0_VARBEAMEN
) {
1562 var
->hsync_len
= (par
->hsstop
- par
->hsstrt
)>>clk_shift
;
1563 var
->right_margin
= par
->hsstrt
>>clk_shift
;
1564 var
->left_margin
= (par
->htotal
>>clk_shift
) - var
->xres
- var
->right_margin
- var
->hsync_len
;
1565 var
->vsync_len
= (par
->vsstop
- par
->vsstrt
)>>line_shift
;
1566 var
->lower_margin
= par
->vsstrt
>>line_shift
;
1567 var
->upper_margin
= (par
->vtotal
>>line_shift
) - var
->yres
- var
->lower_margin
- var
->vsync_len
;
1569 if (par
->beamcon0
& BMC0_HSYTRUE
)
1570 var
->sync
|= FB_SYNC_HOR_HIGH_ACT
;
1571 if (par
->beamcon0
& BMC0_VSYTRUE
)
1572 var
->sync
|= FB_SYNC_VERT_HIGH_ACT
;
1573 if (par
->beamcon0
& BMC0_CSYTRUE
)
1574 var
->sync
|= FB_SYNC_COMP_HIGH_ACT
;
1576 var
->sync
= FB_SYNC_BROADCAST
;
1577 var
->hsync_len
= (152>>clk_shift
) + mod4(par
->diwstop_h
);
1578 var
->right_margin
= ((par
->htotal
- down4(par
->diwstop_h
))>>clk_shift
) + var
->hsync_len
;
1579 var
->left_margin
= (par
->htotal
>>clk_shift
) - var
->xres
- var
->right_margin
- var
->hsync_len
;
1580 var
->vsync_len
= 4>>line_shift
;
1581 var
->lower_margin
= ((par
->vtotal
- par
->diwstop_v
)>>line_shift
) + var
->vsync_len
;
1582 var
->upper_margin
= (((par
->vtotal
- 2)>>line_shift
) + 1) - var
->yres
-
1583 var
->lower_margin
- var
->vsync_len
;
1586 if (par
->bplcon0
& BPC0_ERSY
)
1587 var
->sync
|= FB_SYNC_EXT
;
1588 if (par
->vmode
& FB_VMODE_YWRAP
)
1589 var
->vmode
|= FB_VMODE_YWRAP
;
1597 static void ami_update_par(struct fb_info
*info
)
1599 struct amifb_par
*par
= info
->par
;
1600 short clk_shift
, vshift
, fstrt
, fsize
, fstop
, fconst
, shift
, move
, mod
;
1602 clk_shift
= par
->clk_shift
;
1604 if (!(par
->vmode
& FB_VMODE_SMOOTH_XPAN
))
1605 par
->xoffset
= upx(16 << maxfmode
, par
->xoffset
);
1607 fconst
= 16 << maxfmode
<< clk_shift
;
1608 vshift
= modx(16 << maxfmode
, par
->xoffset
);
1609 fstrt
= par
->diwstrt_h
- (vshift
<< clk_shift
) - 4;
1610 fsize
= (par
->xres
+ vshift
) << clk_shift
;
1611 shift
= modx(fconst
, fstrt
);
1612 move
= downx(2 << maxfmode
, div8(par
->xoffset
));
1613 if (maxfmode
+ clk_shift
> 1) {
1614 fstrt
= downx(fconst
, fstrt
) - 64;
1615 fsize
= upx(fconst
, fsize
);
1616 fstop
= fstrt
+ fsize
- fconst
;
1618 mod
= fstrt
= downx(fconst
, fstrt
) - fconst
;
1619 fstop
= fstrt
+ upx(fconst
, fsize
) - 64;
1620 fsize
= up64(fsize
);
1621 fstrt
= fstop
- fsize
+ 64;
1622 if (fstrt
< min_fstrt
) {
1623 fstop
+= min_fstrt
- fstrt
;
1626 move
= move
- div8((mod
- fstrt
)>>clk_shift
);
1628 mod
= par
->next_line
- div8(fsize
>>clk_shift
);
1629 par
->ddfstrt
= fstrt
;
1630 par
->ddfstop
= fstop
;
1631 par
->bplcon1
= hscroll2hw(shift
);
1633 if (par
->bplcon0
& BPC0_LACE
)
1634 par
->bpl2mod
+= par
->next_line
;
1635 if (IS_AGA
&& (par
->fmode
& FMODE_BSCAN2
))
1636 par
->bpl1mod
= -div8(fsize
>>clk_shift
);
1638 par
->bpl1mod
= par
->bpl2mod
;
1641 par
->bplpt0
= info
->fix
.smem_start
+
1642 par
->next_line
* par
->yoffset
+ move
;
1643 if (par
->vmode
& FB_VMODE_YWRAP
) {
1644 if (par
->yoffset
> par
->vyres
- par
->yres
) {
1645 par
->bplpt0wrap
= info
->fix
.smem_start
+ move
;
1646 if (par
->bplcon0
& BPC0_LACE
&&
1647 mod2(par
->diwstrt_v
+ par
->vyres
-
1649 par
->bplpt0wrap
+= par
->next_line
;
1653 par
->bplpt0
= info
->fix
.smem_start
+ move
;
1655 if (par
->bplcon0
& BPC0_LACE
&& mod2(par
->diwstrt_v
))
1656 par
->bplpt0
+= par
->next_line
;
1661 * Pan or Wrap the Display
1663 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
1667 static void ami_pan_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
1669 struct amifb_par
*par
= info
->par
;
1671 par
->xoffset
= var
->xoffset
;
1672 par
->yoffset
= var
->yoffset
;
1673 if (var
->vmode
& FB_VMODE_YWRAP
)
1674 par
->vmode
|= FB_VMODE_YWRAP
;
1676 par
->vmode
&= ~FB_VMODE_YWRAP
;
1679 ami_update_par(info
);
1684 static void ami_update_display(const struct amifb_par
*par
)
1686 custom
.bplcon1
= par
->bplcon1
;
1687 custom
.bpl1mod
= par
->bpl1mod
;
1688 custom
.bpl2mod
= par
->bpl2mod
;
1689 custom
.ddfstrt
= ddfstrt2hw(par
->ddfstrt
);
1690 custom
.ddfstop
= ddfstop2hw(par
->ddfstop
);
1694 * Change the video mode (called by VBlank interrupt)
1697 static void ami_init_display(const struct amifb_par
*par
)
1701 custom
.bplcon0
= par
->bplcon0
& ~BPC0_LACE
;
1702 custom
.bplcon2
= (IS_OCS
? 0 : BPC2_KILLEHB
) | BPC2_PF2P2
| BPC2_PF1P2
;
1704 custom
.bplcon3
= par
->bplcon3
;
1706 custom
.bplcon4
= BPC4_ESPRM4
| BPC4_OSPRM4
;
1707 if (par
->beamcon0
& BMC0_VARBEAMEN
) {
1708 custom
.htotal
= htotal2hw(par
->htotal
);
1709 custom
.hbstrt
= hbstrt2hw(par
->hbstrt
);
1710 custom
.hbstop
= hbstop2hw(par
->hbstop
);
1711 custom
.hsstrt
= hsstrt2hw(par
->hsstrt
);
1712 custom
.hsstop
= hsstop2hw(par
->hsstop
);
1713 custom
.hcenter
= hcenter2hw(par
->hcenter
);
1714 custom
.vtotal
= vtotal2hw(par
->vtotal
);
1715 custom
.vbstrt
= vbstrt2hw(par
->vbstrt
);
1716 custom
.vbstop
= vbstop2hw(par
->vbstop
);
1717 custom
.vsstrt
= vsstrt2hw(par
->vsstrt
);
1718 custom
.vsstop
= vsstop2hw(par
->vsstop
);
1721 if (!IS_OCS
|| par
->hsstop
)
1722 custom
.beamcon0
= par
->beamcon0
;
1724 custom
.fmode
= par
->fmode
;
1727 * The minimum period for audio depends on htotal
1730 amiga_audio_min_period
= div16(par
->htotal
);
1732 is_lace
= par
->bplcon0
& BPC0_LACE
? 1 : 0;
1735 i
= custom
.vposr
>> 15;
1737 custom
.vposw
= custom
.vposr
| 0x8000;
1742 custom
.vposw
= custom
.vposr
| 0x8000;
1744 custom
.cop2lc
= (u_short
*)ZTWO_PADDR(copdisplay
.list
[currentcop
][i
]);
1748 * (Un)Blank the screen (called by VBlank interrupt)
1751 static void ami_do_blank(const struct amifb_par
*par
)
1753 #if defined(CONFIG_FB_AMIGA_AGA)
1754 u_short bplcon3
= par
->bplcon3
;
1756 u_char red
, green
, blue
;
1759 custom
.dmacon
= DMAF_RASTER
| DMAF_SPRITE
;
1760 red
= green
= blue
= 0;
1761 if (!IS_OCS
&& do_blank
> 1) {
1763 case FB_BLANK_VSYNC_SUSPEND
:
1764 custom
.hsstrt
= hsstrt2hw(par
->hsstrt
);
1765 custom
.hsstop
= hsstop2hw(par
->hsstop
);
1766 custom
.vsstrt
= vsstrt2hw(par
->vtotal
+ 4);
1767 custom
.vsstop
= vsstop2hw(par
->vtotal
+ 4);
1769 case FB_BLANK_HSYNC_SUSPEND
:
1770 custom
.hsstrt
= hsstrt2hw(par
->htotal
+ 16);
1771 custom
.hsstop
= hsstop2hw(par
->htotal
+ 16);
1772 custom
.vsstrt
= vsstrt2hw(par
->vsstrt
);
1773 custom
.vsstop
= vsstrt2hw(par
->vsstop
);
1775 case FB_BLANK_POWERDOWN
:
1776 custom
.hsstrt
= hsstrt2hw(par
->htotal
+ 16);
1777 custom
.hsstop
= hsstop2hw(par
->htotal
+ 16);
1778 custom
.vsstrt
= vsstrt2hw(par
->vtotal
+ 4);
1779 custom
.vsstop
= vsstop2hw(par
->vtotal
+ 4);
1782 if (!(par
->beamcon0
& BMC0_VARBEAMEN
)) {
1783 custom
.htotal
= htotal2hw(par
->htotal
);
1784 custom
.vtotal
= vtotal2hw(par
->vtotal
);
1785 custom
.beamcon0
= BMC0_HARDDIS
| BMC0_VARBEAMEN
|
1786 BMC0_VARVSYEN
| BMC0_VARHSYEN
| BMC0_VARCSYEN
;
1790 custom
.dmacon
= DMAF_SETCLR
| DMAF_RASTER
| DMAF_SPRITE
;
1795 custom
.hsstrt
= hsstrt2hw(par
->hsstrt
);
1796 custom
.hsstop
= hsstop2hw(par
->hsstop
);
1797 custom
.vsstrt
= vsstrt2hw(par
->vsstrt
);
1798 custom
.vsstop
= vsstop2hw(par
->vsstop
);
1799 custom
.beamcon0
= par
->beamcon0
;
1802 #if defined(CONFIG_FB_AMIGA_AGA)
1804 custom
.bplcon3
= bplcon3
;
1805 custom
.color
[0] = rgb2hw8_high(red
, green
, blue
);
1806 custom
.bplcon3
= bplcon3
| BPC3_LOCT
;
1807 custom
.color
[0] = rgb2hw8_low(red
, green
, blue
);
1808 custom
.bplcon3
= bplcon3
;
1811 #if defined(CONFIG_FB_AMIGA_ECS)
1812 if (par
->bplcon0
& BPC0_SHRES
) {
1813 u_short color
, mask
;
1817 color
= rgb2hw2(red
, green
, blue
);
1818 for (i
= 12; i
>= 0; i
-= 4)
1819 custom
.color
[i
] = ecs_palette
[i
] = (ecs_palette
[i
] & mask
) | color
;
1820 mask
<<= 2; color
>>= 2;
1821 for (i
= 3; i
>= 0; i
--)
1822 custom
.color
[i
] = ecs_palette
[i
] = (ecs_palette
[i
] & mask
) | color
;
1825 custom
.color
[0] = rgb2hw4(red
, green
, blue
);
1826 is_blanked
= do_blank
> 0 ? do_blank
: 0;
1829 static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo
*fix
,
1830 const struct amifb_par
*par
)
1832 fix
->crsr_width
= fix
->crsr_xsize
= par
->crsr
.width
;
1833 fix
->crsr_height
= fix
->crsr_ysize
= par
->crsr
.height
;
1834 fix
->crsr_color1
= 17;
1835 fix
->crsr_color2
= 18;
1839 static int ami_get_var_cursorinfo(struct fb_var_cursorinfo
*var
,
1840 u_char __user
*data
,
1841 const struct amifb_par
*par
)
1843 register u_short
*lspr
, *sspr
;
1845 register u_long datawords
asm ("d2");
1847 register u_long datawords
;
1849 register short delta
;
1850 register u_char color
;
1851 short height
, width
, bits
, words
;
1854 size
= par
->crsr
.height
* par
->crsr
.width
;
1855 alloc
= var
->height
* var
->width
;
1856 var
->height
= par
->crsr
.height
;
1857 var
->width
= par
->crsr
.width
;
1858 var
->xspot
= par
->crsr
.spot_x
;
1859 var
->yspot
= par
->crsr
.spot_y
;
1860 if (size
> var
->height
* var
->width
)
1861 return -ENAMETOOLONG
;
1862 if (!access_ok(VERIFY_WRITE
, data
, size
))
1864 delta
= 1 << par
->crsr
.fmode
;
1865 lspr
= lofsprite
+ (delta
<< 1);
1866 if (par
->bplcon0
& BPC0_LACE
)
1867 sspr
= shfsprite
+ (delta
<< 1);
1870 for (height
= (short)var
->height
- 1; height
>= 0; height
--) {
1871 bits
= 0; words
= delta
; datawords
= 0;
1872 for (width
= (short)var
->width
- 1; width
>= 0; width
--) {
1876 asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0"
1877 : "=d" (datawords
), "=a" (lspr
) : "1" (lspr
), "d" (delta
));
1879 datawords
= (*(lspr
+ delta
) << 16) | (*lspr
++);
1885 "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; "
1886 "swap %1 ; lslw #1,%1 ; roxlb #1,%0"
1887 : "=d" (color
), "=d" (datawords
) : "1" (datawords
));
1889 color
= (((datawords
>> 30) & 2)
1890 | ((datawords
>> 15) & 1));
1893 put_user(color
, data
++);
1898 while (--words
>= 0)
1901 asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
1902 : "=a" (lspr
), "=a" (sspr
) : "0" (lspr
), "1" (sspr
), "d" (delta
));
1906 u_short
*tmp
= lspr
;
1915 static int ami_set_var_cursorinfo(struct fb_var_cursorinfo
*var
,
1916 u_char __user
*data
, struct amifb_par
*par
)
1918 register u_short
*lspr
, *sspr
;
1920 register u_long datawords
asm ("d2");
1922 register u_long datawords
;
1924 register short delta
;
1926 short height
, width
, bits
, words
;
1930 else if (var
->width
<= 16)
1931 fmode
= TAG_FMODE_1
;
1932 else if (var
->width
<= 32)
1933 fmode
= TAG_FMODE_2
;
1934 else if (var
->width
<= 64)
1935 fmode
= TAG_FMODE_4
;
1938 if (fmode
> maxfmode
)
1942 if (!access_ok(VERIFY_READ
, data
, var
->width
* var
->height
))
1945 lofsprite
= shfsprite
= (u_short
*)spritememory
;
1946 lspr
= lofsprite
+ (delta
<< 1);
1947 if (par
->bplcon0
& BPC0_LACE
) {
1948 if (((var
->height
+ 4) << fmode
<< 2) > SPRITEMEMSIZE
)
1950 memset(lspr
, 0, (var
->height
+ 4) << fmode
<< 2);
1951 shfsprite
+= ((var
->height
+ 5)&-2) << fmode
;
1952 sspr
= shfsprite
+ (delta
<< 1);
1954 if (((var
->height
+ 2) << fmode
<< 2) > SPRITEMEMSIZE
)
1956 memset(lspr
, 0, (var
->height
+ 2) << fmode
<< 2);
1959 for (height
= (short)var
->height
- 1; height
>= 0; height
--) {
1960 bits
= 16; words
= delta
; datawords
= 0;
1961 for (width
= (short)var
->width
- 1; width
>= 0; width
--) {
1962 unsigned long tdata
= 0;
1963 get_user(tdata
, data
);
1967 "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; "
1968 "lsrb #1,%2 ; roxlw #1,%0 ; swap %0"
1970 : "0" (datawords
), "d" (tdata
));
1972 datawords
= ((datawords
<< 1) & 0xfffefffe);
1973 datawords
|= tdata
& 1;
1974 datawords
|= (tdata
& 2) << (16 - 1);
1979 asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+"
1980 : "=a" (lspr
) : "0" (lspr
), "d" (datawords
), "d" (delta
));
1982 *(lspr
+ delta
) = (u_short
) (datawords
>> 16);
1983 *lspr
++ = (u_short
) (datawords
& 0xffff);
1991 "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; "
1992 "swap %2 ; lslw %4,%2 ; movew %2,%0@+"
1993 : "=a" (lspr
) : "0" (lspr
), "d" (datawords
), "d" (delta
), "d" (bits
));
1995 *(lspr
+ delta
) = (u_short
) (datawords
>> (16 + bits
));
1996 *lspr
++ = (u_short
) ((datawords
& 0x0000ffff) >> bits
);
1999 while (--words
>= 0) {
2001 asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+"
2002 : "=a" (lspr
) : "0" (lspr
), "d" (delta
) : "d0");
2004 *(lspr
+ delta
) = 0;
2009 asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
2010 : "=a" (lspr
), "=a" (sspr
) : "0" (lspr
), "1" (sspr
), "d" (delta
));
2014 u_short
*tmp
= lspr
;
2020 par
->crsr
.height
= var
->height
;
2021 par
->crsr
.width
= var
->width
;
2022 par
->crsr
.spot_x
= var
->xspot
;
2023 par
->crsr
.spot_y
= var
->yspot
;
2024 par
->crsr
.fmode
= fmode
;
2026 par
->fmode
&= ~(FMODE_SPAGEM
| FMODE_SPR32
);
2027 par
->fmode
|= sprfetchmode
[fmode
];
2028 custom
.fmode
= par
->fmode
;
2033 static int ami_get_cursorstate(struct fb_cursorstate
*state
,
2034 const struct amifb_par
*par
)
2036 state
->xoffset
= par
->crsr
.crsr_x
;
2037 state
->yoffset
= par
->crsr
.crsr_y
;
2038 state
->mode
= cursormode
;
2042 static int ami_set_cursorstate(struct fb_cursorstate
*state
,
2043 struct amifb_par
*par
)
2045 par
->crsr
.crsr_x
= state
->xoffset
;
2046 par
->crsr
.crsr_y
= state
->yoffset
;
2047 if ((cursormode
= state
->mode
) == FB_CURSOR_OFF
)
2053 static void ami_set_sprite(const struct amifb_par
*par
)
2055 copins
*copl
, *cops
;
2060 cops
= copdisplay
.list
[currentcop
][0];
2061 copl
= copdisplay
.list
[currentcop
][1];
2062 ps
= pl
= ZTWO_PADDR(dummysprite
);
2063 mx
= par
->crsr
.crsr_x
- par
->crsr
.spot_x
;
2064 my
= par
->crsr
.crsr_y
- par
->crsr
.spot_y
;
2065 if (!(par
->vmode
& FB_VMODE_YWRAP
)) {
2069 if (!is_blanked
&& cursorstate
> 0 && par
->crsr
.height
> 0 &&
2070 mx
> -(short)par
->crsr
.width
&& mx
< par
->xres
&&
2071 my
> -(short)par
->crsr
.height
&& my
< par
->yres
) {
2072 pl
= ZTWO_PADDR(lofsprite
);
2073 hs
= par
->diwstrt_h
+ (mx
<< par
->clk_shift
) - 4;
2074 vs
= par
->diwstrt_v
+ (my
<< par
->line_shift
);
2075 ve
= vs
+ (par
->crsr
.height
<< par
->line_shift
);
2076 if (par
->bplcon0
& BPC0_LACE
) {
2077 ps
= ZTWO_PADDR(shfsprite
);
2078 lofsprite
[0] = spr2hw_pos(vs
, hs
);
2079 shfsprite
[0] = spr2hw_pos(vs
+ 1, hs
);
2081 lofsprite
[1 << par
->crsr
.fmode
] = spr2hw_ctl(vs
, hs
, ve
);
2082 shfsprite
[1 << par
->crsr
.fmode
] = spr2hw_ctl(vs
+ 1, hs
, ve
+ 1);
2083 pt
= pl
; pl
= ps
; ps
= pt
;
2085 lofsprite
[1 << par
->crsr
.fmode
] = spr2hw_ctl(vs
, hs
, ve
+ 1);
2086 shfsprite
[1 << par
->crsr
.fmode
] = spr2hw_ctl(vs
+ 1, hs
, ve
);
2089 lofsprite
[0] = spr2hw_pos(vs
, hs
) | (IS_AGA
&& (par
->fmode
& FMODE_BSCAN2
) ? 0x80 : 0);
2090 lofsprite
[1 << par
->crsr
.fmode
] = spr2hw_ctl(vs
, hs
, ve
);
2093 copl
[cop_spr0ptrh
].w
[1] = highw(pl
);
2094 copl
[cop_spr0ptrl
].w
[1] = loww(pl
);
2095 if (par
->bplcon0
& BPC0_LACE
) {
2096 cops
[cop_spr0ptrh
].w
[1] = highw(ps
);
2097 cops
[cop_spr0ptrl
].w
[1] = loww(ps
);
2103 * Initialise the Copper Initialisation List
2106 static void __init
ami_init_copper(void)
2108 copins
*cop
= copdisplay
.init
;
2113 (cop
++)->l
= CMOVE(BPC0_COLOR
| BPC0_SHRES
| BPC0_ECSENA
, bplcon0
);
2114 (cop
++)->l
= CMOVE(0x0181, diwstrt
);
2115 (cop
++)->l
= CMOVE(0x0281, diwstop
);
2116 (cop
++)->l
= CMOVE(0x0000, diwhigh
);
2118 (cop
++)->l
= CMOVE(BPC0_COLOR
, bplcon0
);
2119 p
= ZTWO_PADDR(dummysprite
);
2120 for (i
= 0; i
< 8; i
++) {
2121 (cop
++)->l
= CMOVE(0, spr
[i
].pos
);
2122 (cop
++)->l
= CMOVE(highw(p
), sprpt
[i
]);
2123 (cop
++)->l
= CMOVE2(loww(p
), sprpt
[i
]);
2126 (cop
++)->l
= CMOVE(IF_SETCLR
| IF_COPER
, intreq
);
2127 copdisplay
.wait
= cop
;
2129 (cop
++)->l
= CMOVE(0, copjmp2
);
2132 custom
.cop1lc
= (u_short
*)ZTWO_PADDR(copdisplay
.init
);
2136 static void ami_reinit_copper(const struct amifb_par
*par
)
2138 copdisplay
.init
[cip_bplcon0
].w
[1] = ~(BPC0_BPU3
| BPC0_BPU2
| BPC0_BPU1
| BPC0_BPU0
) & par
->bplcon0
;
2139 copdisplay
.wait
->l
= CWAIT(32, par
->diwstrt_v
- 4);
2144 * Rebuild the Copper List
2146 * We only change the things that are not static
2149 static void ami_rebuild_copper(const struct amifb_par
*par
)
2151 copins
*copl
, *cops
;
2152 u_short line
, h_end1
, h_end2
;
2156 if (IS_AGA
&& maxfmode
+ par
->clk_shift
== 0)
2157 h_end1
= par
->diwstrt_h
- 64;
2159 h_end1
= par
->htotal
- 32;
2160 h_end2
= par
->ddfstop
+ 64;
2162 ami_set_sprite(par
);
2164 copl
= copdisplay
.rebuild
[1];
2166 if (par
->vmode
& FB_VMODE_YWRAP
) {
2167 if ((par
->vyres
- par
->yoffset
) != 1 || !mod2(par
->diwstrt_v
)) {
2168 if (par
->yoffset
> par
->vyres
- par
->yres
) {
2169 for (i
= 0; i
< (short)par
->bpp
; i
++, p
+= par
->next_plane
) {
2170 (copl
++)->l
= CMOVE(highw(p
), bplpt
[i
]);
2171 (copl
++)->l
= CMOVE2(loww(p
), bplpt
[i
]);
2173 line
= par
->diwstrt_v
+ ((par
->vyres
- par
->yoffset
) << par
->line_shift
) - 1;
2174 while (line
>= 512) {
2175 (copl
++)->l
= CWAIT(h_end1
, 510);
2178 if (line
>= 510 && IS_AGA
&& maxfmode
+ par
->clk_shift
== 0)
2179 (copl
++)->l
= CWAIT(h_end1
, line
);
2181 (copl
++)->l
= CWAIT(h_end2
, line
);
2182 p
= par
->bplpt0wrap
;
2185 p
= par
->bplpt0wrap
;
2187 for (i
= 0; i
< (short)par
->bpp
; i
++, p
+= par
->next_plane
) {
2188 (copl
++)->l
= CMOVE(highw(p
), bplpt
[i
]);
2189 (copl
++)->l
= CMOVE2(loww(p
), bplpt
[i
]);
2193 if (par
->bplcon0
& BPC0_LACE
) {
2194 cops
= copdisplay
.rebuild
[0];
2196 if (mod2(par
->diwstrt_v
))
2197 p
-= par
->next_line
;
2199 p
+= par
->next_line
;
2200 if (par
->vmode
& FB_VMODE_YWRAP
) {
2201 if ((par
->vyres
- par
->yoffset
) != 1 || mod2(par
->diwstrt_v
)) {
2202 if (par
->yoffset
> par
->vyres
- par
->yres
+ 1) {
2203 for (i
= 0; i
< (short)par
->bpp
; i
++, p
+= par
->next_plane
) {
2204 (cops
++)->l
= CMOVE(highw(p
), bplpt
[i
]);
2205 (cops
++)->l
= CMOVE2(loww(p
), bplpt
[i
]);
2207 line
= par
->diwstrt_v
+ ((par
->vyres
- par
->yoffset
) << par
->line_shift
) - 2;
2208 while (line
>= 512) {
2209 (cops
++)->l
= CWAIT(h_end1
, 510);
2212 if (line
> 510 && IS_AGA
&& maxfmode
+ par
->clk_shift
== 0)
2213 (cops
++)->l
= CWAIT(h_end1
, line
);
2215 (cops
++)->l
= CWAIT(h_end2
, line
);
2216 p
= par
->bplpt0wrap
;
2217 if (mod2(par
->diwstrt_v
+ par
->vyres
-
2219 p
-= par
->next_line
;
2221 p
+= par
->next_line
;
2224 p
= par
->bplpt0wrap
- par
->next_line
;
2226 for (i
= 0; i
< (short)par
->bpp
; i
++, p
+= par
->next_plane
) {
2227 (cops
++)->l
= CMOVE(highw(p
), bplpt
[i
]);
2228 (cops
++)->l
= CMOVE2(loww(p
), bplpt
[i
]);
2236 * Build the Copper List
2239 static void ami_build_copper(struct fb_info
*info
)
2241 struct amifb_par
*par
= info
->par
;
2242 copins
*copl
, *cops
;
2245 currentcop
= 1 - currentcop
;
2247 copl
= copdisplay
.list
[currentcop
][1];
2249 (copl
++)->l
= CWAIT(0, 10);
2250 (copl
++)->l
= CMOVE(par
->bplcon0
, bplcon0
);
2251 (copl
++)->l
= CMOVE(0, sprpt
[0]);
2252 (copl
++)->l
= CMOVE2(0, sprpt
[0]);
2254 if (par
->bplcon0
& BPC0_LACE
) {
2255 cops
= copdisplay
.list
[currentcop
][0];
2257 (cops
++)->l
= CWAIT(0, 10);
2258 (cops
++)->l
= CMOVE(par
->bplcon0
, bplcon0
);
2259 (cops
++)->l
= CMOVE(0, sprpt
[0]);
2260 (cops
++)->l
= CMOVE2(0, sprpt
[0]);
2262 (copl
++)->l
= CMOVE(diwstrt2hw(par
->diwstrt_h
, par
->diwstrt_v
+ 1), diwstrt
);
2263 (copl
++)->l
= CMOVE(diwstop2hw(par
->diwstop_h
, par
->diwstop_v
+ 1), diwstop
);
2264 (cops
++)->l
= CMOVE(diwstrt2hw(par
->diwstrt_h
, par
->diwstrt_v
), diwstrt
);
2265 (cops
++)->l
= CMOVE(diwstop2hw(par
->diwstop_h
, par
->diwstop_v
), diwstop
);
2267 (copl
++)->l
= CMOVE(diwhigh2hw(par
->diwstrt_h
, par
->diwstrt_v
+ 1,
2268 par
->diwstop_h
, par
->diwstop_v
+ 1), diwhigh
);
2269 (cops
++)->l
= CMOVE(diwhigh2hw(par
->diwstrt_h
, par
->diwstrt_v
,
2270 par
->diwstop_h
, par
->diwstop_v
), diwhigh
);
2272 if (par
->beamcon0
& BMC0_VARBEAMEN
) {
2273 (copl
++)->l
= CMOVE(vtotal2hw(par
->vtotal
), vtotal
);
2274 (copl
++)->l
= CMOVE(vbstrt2hw(par
->vbstrt
+ 1), vbstrt
);
2275 (copl
++)->l
= CMOVE(vbstop2hw(par
->vbstop
+ 1), vbstop
);
2276 (cops
++)->l
= CMOVE(vtotal2hw(par
->vtotal
), vtotal
);
2277 (cops
++)->l
= CMOVE(vbstrt2hw(par
->vbstrt
), vbstrt
);
2278 (cops
++)->l
= CMOVE(vbstop2hw(par
->vbstop
), vbstop
);
2282 p
= ZTWO_PADDR(copdisplay
.list
[currentcop
][0]);
2283 (copl
++)->l
= CMOVE(highw(p
), cop2lc
);
2284 (copl
++)->l
= CMOVE2(loww(p
), cop2lc
);
2285 p
= ZTWO_PADDR(copdisplay
.list
[currentcop
][1]);
2286 (cops
++)->l
= CMOVE(highw(p
), cop2lc
);
2287 (cops
++)->l
= CMOVE2(loww(p
), cop2lc
);
2288 copdisplay
.rebuild
[0] = cops
;
2290 (copl
++)->l
= CMOVE(diwstrt2hw(par
->diwstrt_h
, par
->diwstrt_v
), diwstrt
);
2291 (copl
++)->l
= CMOVE(diwstop2hw(par
->diwstop_h
, par
->diwstop_v
), diwstop
);
2293 (copl
++)->l
= CMOVE(diwhigh2hw(par
->diwstrt_h
, par
->diwstrt_v
,
2294 par
->diwstop_h
, par
->diwstop_v
), diwhigh
);
2296 if (par
->beamcon0
& BMC0_VARBEAMEN
) {
2297 (copl
++)->l
= CMOVE(vtotal2hw(par
->vtotal
), vtotal
);
2298 (copl
++)->l
= CMOVE(vbstrt2hw(par
->vbstrt
), vbstrt
);
2299 (copl
++)->l
= CMOVE(vbstop2hw(par
->vbstop
), vbstop
);
2304 copdisplay
.rebuild
[1] = copl
;
2306 ami_update_par(info
);
2307 ami_rebuild_copper(info
->par
);
2311 static void __init
amifb_setup_mcap(char *spec
)
2314 int vmin
, vmax
, hmin
, hmax
;
2316 /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
2317 * <V*> vertical freq. in Hz
2318 * <H*> horizontal freq. in kHz
2321 if (!(p
= strsep(&spec
, ";")) || !*p
)
2323 vmin
= simple_strtoul(p
, NULL
, 10);
2326 if (!(p
= strsep(&spec
, ";")) || !*p
)
2328 vmax
= simple_strtoul(p
, NULL
, 10);
2329 if (vmax
<= 0 || vmax
<= vmin
)
2331 if (!(p
= strsep(&spec
, ";")) || !*p
)
2333 hmin
= 1000 * simple_strtoul(p
, NULL
, 10);
2336 if (!(p
= strsep(&spec
, "")) || !*p
)
2338 hmax
= 1000 * simple_strtoul(p
, NULL
, 10);
2339 if (hmax
<= 0 || hmax
<= hmin
)
2348 static int __init
amifb_setup(char *options
)
2352 if (!options
|| !*options
)
2355 while ((this_opt
= strsep(&options
, ",")) != NULL
) {
2358 if (!strcmp(this_opt
, "inverse")) {
2361 } else if (!strcmp(this_opt
, "ilbm"))
2363 else if (!strncmp(this_opt
, "monitorcap:", 11))
2364 amifb_setup_mcap(this_opt
+ 11);
2365 else if (!strncmp(this_opt
, "fstart:", 7))
2366 min_fstrt
= simple_strtoul(this_opt
+ 7, NULL
, 0);
2368 mode_option
= this_opt
;
2378 static int amifb_check_var(struct fb_var_screeninfo
*var
,
2379 struct fb_info
*info
)
2382 struct amifb_par par
;
2384 /* Validate wanted screen parameters */
2385 err
= ami_decode_var(var
, &par
, info
);
2389 /* Encode (possibly rounded) screen parameters */
2390 ami_encode_var(var
, &par
);
2395 static int amifb_set_par(struct fb_info
*info
)
2397 struct amifb_par
*par
= info
->par
;
2403 /* Decode wanted screen parameters */
2404 error
= ami_decode_var(&info
->var
, par
, info
);
2408 /* Set new videomode */
2409 ami_build_copper(info
);
2411 /* Set VBlank trigger */
2414 /* Update fix for new screen parameters */
2415 if (par
->bpp
== 1) {
2416 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
2417 info
->fix
.type_aux
= 0;
2418 } else if (amifb_ilbm
) {
2419 info
->fix
.type
= FB_TYPE_INTERLEAVED_PLANES
;
2420 info
->fix
.type_aux
= par
->next_line
;
2422 info
->fix
.type
= FB_TYPE_PLANES
;
2423 info
->fix
.type_aux
= 0;
2425 info
->fix
.line_length
= div8(upx(16 << maxfmode
, par
->vxres
));
2427 if (par
->vmode
& FB_VMODE_YWRAP
) {
2428 info
->fix
.ywrapstep
= 1;
2429 info
->fix
.xpanstep
= 0;
2430 info
->fix
.ypanstep
= 0;
2431 info
->flags
= FBINFO_DEFAULT
| FBINFO_HWACCEL_YWRAP
|
2432 FBINFO_READS_FAST
; /* override SCROLL_REDRAW */
2434 info
->fix
.ywrapstep
= 0;
2435 if (par
->vmode
& FB_VMODE_SMOOTH_XPAN
)
2436 info
->fix
.xpanstep
= 1;
2438 info
->fix
.xpanstep
= 16 << maxfmode
;
2439 info
->fix
.ypanstep
= 1;
2440 info
->flags
= FBINFO_DEFAULT
| FBINFO_HWACCEL_YPAN
;
2447 * Set a single color register. The values supplied are already
2448 * rounded down to the hardware's capabilities (according to the
2449 * entries in the var structure). Return != 0 for invalid regno.
2452 static int amifb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
2453 u_int transp
, struct fb_info
*info
)
2455 const struct amifb_par
*par
= info
->par
;
2460 } else if (par
->bplcon0
& BPC0_SHRES
) {
2477 * Update the corresponding Hardware Color Register, unless it's Color
2478 * Register 0 and the screen is blanked.
2480 * VBlank is switched off to protect bplcon3 or ecs_palette[] from
2481 * being changed by ami_do_blank() during the VBlank.
2484 if (regno
|| !is_blanked
) {
2485 #if defined(CONFIG_FB_AMIGA_AGA)
2487 u_short bplcon3
= par
->bplcon3
;
2489 custom
.bplcon3
= bplcon3
| (regno
<< 8 & 0xe000);
2490 custom
.color
[regno
& 31] = rgb2hw8_high(red
, green
,
2492 custom
.bplcon3
= bplcon3
| (regno
<< 8 & 0xe000) |
2494 custom
.color
[regno
& 31] = rgb2hw8_low(red
, green
,
2496 custom
.bplcon3
= bplcon3
;
2500 #if defined(CONFIG_FB_AMIGA_ECS)
2501 if (par
->bplcon0
& BPC0_SHRES
) {
2502 u_short color
, mask
;
2506 color
= rgb2hw2(red
, green
, blue
);
2508 for (i
= regno
+ 12; i
>= (int)regno
; i
-= 4)
2509 custom
.color
[i
] = ecs_palette
[i
] = (ecs_palette
[i
] & mask
) | color
;
2510 mask
<<= 2; color
>>= 2;
2511 regno
= down16(regno
) + mul4(mod4(regno
));
2512 for (i
= regno
+ 3; i
>= (int)regno
; i
--)
2513 custom
.color
[i
] = ecs_palette
[i
] = (ecs_palette
[i
] & mask
) | color
;
2517 custom
.color
[regno
] = rgb2hw4(red
, green
, blue
);
2524 * Blank the display.
2527 static int amifb_blank(int blank
, struct fb_info
*info
)
2529 do_blank
= blank
? blank
: -1;
2536 * Pan or Wrap the Display
2538 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
2541 static int amifb_pan_display(struct fb_var_screeninfo
*var
,
2542 struct fb_info
*info
)
2544 if (var
->vmode
& FB_VMODE_YWRAP
) {
2545 if (var
->yoffset
< 0 ||
2546 var
->yoffset
>= info
->var
.yres_virtual
|| var
->xoffset
)
2550 * TODO: There will be problems when xpan!=1, so some columns
2551 * on the right side will never be seen
2553 if (var
->xoffset
+ info
->var
.xres
>
2554 upx(16 << maxfmode
, info
->var
.xres_virtual
) ||
2555 var
->yoffset
+ info
->var
.yres
> info
->var
.yres_virtual
)
2558 ami_pan_var(var
, info
);
2559 info
->var
.xoffset
= var
->xoffset
;
2560 info
->var
.yoffset
= var
->yoffset
;
2561 if (var
->vmode
& FB_VMODE_YWRAP
)
2562 info
->var
.vmode
|= FB_VMODE_YWRAP
;
2564 info
->var
.vmode
&= ~FB_VMODE_YWRAP
;
2569 #if BITS_PER_LONG == 32
2570 #define BYTES_PER_LONG 4
2571 #define SHIFT_PER_LONG 5
2572 #elif BITS_PER_LONG == 64
2573 #define BYTES_PER_LONG 8
2574 #define SHIFT_PER_LONG 6
2576 #define Please update me
2581 * Compose two values, using a bitmask as decision value
2582 * This is equivalent to (a & mask) | (b & ~mask)
2585 static inline unsigned long comp(unsigned long a
, unsigned long b
,
2588 return ((a
^ b
) & mask
) ^ b
;
2592 static inline unsigned long xor(unsigned long a
, unsigned long b
,
2595 return (a
& mask
) ^ b
;
2600 * Unaligned forward bit copy using 32-bit or 64-bit memory accesses
2603 static void bitcpy(unsigned long *dst
, int dst_idx
, const unsigned long *src
,
2606 unsigned long first
, last
;
2607 int shift
= dst_idx
- src_idx
, left
, right
;
2608 unsigned long d0
, d1
;
2614 shift
= dst_idx
- src_idx
;
2615 first
= ~0UL >> dst_idx
;
2616 last
= ~(~0UL >> ((dst_idx
+ n
) % BITS_PER_LONG
));
2619 // Same alignment for source and dest
2621 if (dst_idx
+ n
<= BITS_PER_LONG
) {
2625 *dst
= comp(*src
, *dst
, first
);
2627 // Multiple destination words
2630 *dst
= comp(*src
, *dst
, first
);
2633 n
-= BITS_PER_LONG
- dst_idx
;
2654 *dst
= comp(*src
, *dst
, last
);
2657 // Different alignment for source and dest
2659 right
= shift
& (BITS_PER_LONG
- 1);
2660 left
= -shift
& (BITS_PER_LONG
- 1);
2662 if (dst_idx
+ n
<= BITS_PER_LONG
) {
2663 // Single destination word
2667 // Single source word
2668 *dst
= comp(*src
>> right
, *dst
, first
);
2669 } else if (src_idx
+ n
<= BITS_PER_LONG
) {
2670 // Single source word
2671 *dst
= comp(*src
<< left
, *dst
, first
);
2676 *dst
= comp(d0
<< left
| d1
>> right
, *dst
,
2680 // Multiple destination words
2684 // Single source word
2685 *dst
= comp(d0
>> right
, *dst
, first
);
2687 n
-= BITS_PER_LONG
- dst_idx
;
2691 *dst
= comp(d0
<< left
| d1
>> right
, *dst
,
2695 n
-= BITS_PER_LONG
- dst_idx
;
2699 m
= n
% BITS_PER_LONG
;
2703 *dst
++ = d0
<< left
| d1
>> right
;
2706 *dst
++ = d0
<< left
| d1
>> right
;
2709 *dst
++ = d0
<< left
| d1
>> right
;
2712 *dst
++ = d0
<< left
| d1
>> right
;
2718 *dst
++ = d0
<< left
| d1
>> right
;
2725 // Single source word
2726 *dst
= comp(d0
<< left
, *dst
, last
);
2730 *dst
= comp(d0
<< left
| d1
>> right
,
2740 * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses
2743 static void bitcpy_rev(unsigned long *dst
, int dst_idx
,
2744 const unsigned long *src
, int src_idx
, u32 n
)
2746 unsigned long first
, last
;
2747 int shift
= dst_idx
- src_idx
, left
, right
;
2748 unsigned long d0
, d1
;
2754 dst
+= (n
- 1) / BITS_PER_LONG
;
2755 src
+= (n
- 1) / BITS_PER_LONG
;
2756 if ((n
- 1) % BITS_PER_LONG
) {
2757 dst_idx
+= (n
- 1) % BITS_PER_LONG
;
2758 dst
+= dst_idx
>> SHIFT_PER_LONG
;
2759 dst_idx
&= BITS_PER_LONG
- 1;
2760 src_idx
+= (n
- 1) % BITS_PER_LONG
;
2761 src
+= src_idx
>> SHIFT_PER_LONG
;
2762 src_idx
&= BITS_PER_LONG
- 1;
2765 shift
= dst_idx
- src_idx
;
2766 first
= ~0UL << (BITS_PER_LONG
- 1 - dst_idx
);
2767 last
= ~(~0UL << (BITS_PER_LONG
- 1 - ((dst_idx
- n
) % BITS_PER_LONG
)));
2770 // Same alignment for source and dest
2772 if ((unsigned long)dst_idx
+ 1 >= n
) {
2776 *dst
= comp(*src
, *dst
, first
);
2778 // Multiple destination words
2781 *dst
= comp(*src
, *dst
, first
);
2805 *dst
= comp(*src
, *dst
, last
);
2808 // Different alignment for source and dest
2810 right
= shift
& (BITS_PER_LONG
- 1);
2811 left
= -shift
& (BITS_PER_LONG
- 1);
2813 if ((unsigned long)dst_idx
+ 1 >= n
) {
2814 // Single destination word
2818 // Single source word
2819 *dst
= comp(*src
<< left
, *dst
, first
);
2820 } else if (1 + (unsigned long)src_idx
>= n
) {
2821 // Single source word
2822 *dst
= comp(*src
>> right
, *dst
, first
);
2827 *dst
= comp(d0
>> right
| d1
<< left
, *dst
,
2831 // Multiple destination words
2835 // Single source word
2836 *dst
= comp(d0
<< left
, *dst
, first
);
2842 *dst
= comp(d0
>> right
| d1
<< left
, *dst
,
2850 m
= n
% BITS_PER_LONG
;
2854 *dst
-- = d0
>> right
| d1
<< left
;
2857 *dst
-- = d0
>> right
| d1
<< left
;
2860 *dst
-- = d0
>> right
| d1
<< left
;
2863 *dst
-- = d0
>> right
| d1
<< left
;
2869 *dst
-- = d0
>> right
| d1
<< left
;
2876 // Single source word
2877 *dst
= comp(d0
>> right
, *dst
, last
);
2881 *dst
= comp(d0
>> right
| d1
<< left
,
2891 * Unaligned forward inverting bit copy using 32-bit or 64-bit memory
2895 static void bitcpy_not(unsigned long *dst
, int dst_idx
,
2896 const unsigned long *src
, int src_idx
, u32 n
)
2898 unsigned long first
, last
;
2899 int shift
= dst_idx
- src_idx
, left
, right
;
2900 unsigned long d0
, d1
;
2906 shift
= dst_idx
- src_idx
;
2907 first
= ~0UL >> dst_idx
;
2908 last
= ~(~0UL >> ((dst_idx
+ n
) % BITS_PER_LONG
));
2911 // Same alignment for source and dest
2913 if (dst_idx
+ n
<= BITS_PER_LONG
) {
2917 *dst
= comp(~*src
, *dst
, first
);
2919 // Multiple destination words
2922 *dst
= comp(~*src
, *dst
, first
);
2925 n
-= BITS_PER_LONG
- dst_idx
;
2946 *dst
= comp(~*src
, *dst
, last
);
2949 // Different alignment for source and dest
2951 right
= shift
& (BITS_PER_LONG
- 1);
2952 left
= -shift
& (BITS_PER_LONG
- 1);
2954 if (dst_idx
+ n
<= BITS_PER_LONG
) {
2955 // Single destination word
2959 // Single source word
2960 *dst
= comp(~*src
>> right
, *dst
, first
);
2961 } else if (src_idx
+ n
<= BITS_PER_LONG
) {
2962 // Single source word
2963 *dst
= comp(~*src
<< left
, *dst
, first
);
2968 *dst
= comp(d0
<< left
| d1
>> right
, *dst
,
2972 // Multiple destination words
2976 // Single source word
2977 *dst
= comp(d0
>> right
, *dst
, first
);
2979 n
-= BITS_PER_LONG
- dst_idx
;
2983 *dst
= comp(d0
<< left
| d1
>> right
, *dst
,
2987 n
-= BITS_PER_LONG
- dst_idx
;
2991 m
= n
% BITS_PER_LONG
;
2995 *dst
++ = d0
<< left
| d1
>> right
;
2998 *dst
++ = d0
<< left
| d1
>> right
;
3001 *dst
++ = d0
<< left
| d1
>> right
;
3004 *dst
++ = d0
<< left
| d1
>> right
;
3010 *dst
++ = d0
<< left
| d1
>> right
;
3017 // Single source word
3018 *dst
= comp(d0
<< left
, *dst
, last
);
3022 *dst
= comp(d0
<< left
| d1
>> right
,
3032 * Unaligned 32-bit pattern fill using 32/64-bit memory accesses
3035 static void bitfill32(unsigned long *dst
, int dst_idx
, u32 pat
, u32 n
)
3037 unsigned long val
= pat
;
3038 unsigned long first
, last
;
3043 #if BITS_PER_LONG == 64
3047 first
= ~0UL >> dst_idx
;
3048 last
= ~(~0UL >> ((dst_idx
+ n
) % BITS_PER_LONG
));
3050 if (dst_idx
+ n
<= BITS_PER_LONG
) {
3054 *dst
= comp(val
, *dst
, first
);
3056 // Multiple destination words
3059 *dst
= comp(val
, *dst
, first
);
3061 n
-= BITS_PER_LONG
- dst_idx
;
3082 *dst
= comp(val
, *dst
, last
);
3088 * Unaligned 32-bit pattern xor using 32/64-bit memory accesses
3091 static void bitxor32(unsigned long *dst
, int dst_idx
, u32 pat
, u32 n
)
3093 unsigned long val
= pat
;
3094 unsigned long first
, last
;
3099 #if BITS_PER_LONG == 64
3103 first
= ~0UL >> dst_idx
;
3104 last
= ~(~0UL >> ((dst_idx
+ n
) % BITS_PER_LONG
));
3106 if (dst_idx
+ n
<= BITS_PER_LONG
) {
3110 *dst
= xor(val
, *dst
, first
);
3112 // Multiple destination words
3115 *dst
= xor(val
, *dst
, first
);
3117 n
-= BITS_PER_LONG
- dst_idx
;
3134 *dst
= xor(val
, *dst
, last
);
3138 static inline void fill_one_line(int bpp
, unsigned long next_plane
,
3139 unsigned long *dst
, int dst_idx
, u32 n
,
3143 dst
+= dst_idx
>> SHIFT_PER_LONG
;
3144 dst_idx
&= (BITS_PER_LONG
- 1);
3145 bitfill32(dst
, dst_idx
, color
& 1 ? ~0 : 0, n
);
3149 dst_idx
+= next_plane
* 8;
3153 static inline void xor_one_line(int bpp
, unsigned long next_plane
,
3154 unsigned long *dst
, int dst_idx
, u32 n
,
3158 dst
+= dst_idx
>> SHIFT_PER_LONG
;
3159 dst_idx
&= (BITS_PER_LONG
- 1);
3160 bitxor32(dst
, dst_idx
, color
& 1 ? ~0 : 0, n
);
3164 dst_idx
+= next_plane
* 8;
3169 static void amifb_fillrect(struct fb_info
*info
,
3170 const struct fb_fillrect
*rect
)
3172 struct amifb_par
*par
= info
->par
;
3173 int dst_idx
, x2
, y2
;
3177 if (!rect
->width
|| !rect
->height
)
3181 * We could use hardware clipping but on many cards you get around
3182 * hardware clipping by writing to framebuffer directly.
3184 x2
= rect
->dx
+ rect
->width
;
3185 y2
= rect
->dy
+ rect
->height
;
3186 x2
= x2
< info
->var
.xres_virtual
? x2
: info
->var
.xres_virtual
;
3187 y2
= y2
< info
->var
.yres_virtual
? y2
: info
->var
.yres_virtual
;
3188 width
= x2
- rect
->dx
;
3189 height
= y2
- rect
->dy
;
3191 dst
= (unsigned long *)
3192 ((unsigned long)info
->screen_base
& ~(BYTES_PER_LONG
- 1));
3193 dst_idx
= ((unsigned long)info
->screen_base
& (BYTES_PER_LONG
- 1)) * 8;
3194 dst_idx
+= rect
->dy
* par
->next_line
* 8 + rect
->dx
;
3196 switch (rect
->rop
) {
3198 fill_one_line(info
->var
.bits_per_pixel
,
3199 par
->next_plane
, dst
, dst_idx
, width
,
3204 xor_one_line(info
->var
.bits_per_pixel
, par
->next_plane
,
3205 dst
, dst_idx
, width
, rect
->color
);
3208 dst_idx
+= par
->next_line
* 8;
3212 static inline void copy_one_line(int bpp
, unsigned long next_plane
,
3213 unsigned long *dst
, int dst_idx
,
3214 unsigned long *src
, int src_idx
, u32 n
)
3217 dst
+= dst_idx
>> SHIFT_PER_LONG
;
3218 dst_idx
&= (BITS_PER_LONG
- 1);
3219 src
+= src_idx
>> SHIFT_PER_LONG
;
3220 src_idx
&= (BITS_PER_LONG
- 1);
3221 bitcpy(dst
, dst_idx
, src
, src_idx
, n
);
3224 dst_idx
+= next_plane
* 8;
3225 src_idx
+= next_plane
* 8;
3229 static inline void copy_one_line_rev(int bpp
, unsigned long next_plane
,
3230 unsigned long *dst
, int dst_idx
,
3231 unsigned long *src
, int src_idx
, u32 n
)
3234 dst
+= dst_idx
>> SHIFT_PER_LONG
;
3235 dst_idx
&= (BITS_PER_LONG
- 1);
3236 src
+= src_idx
>> SHIFT_PER_LONG
;
3237 src_idx
&= (BITS_PER_LONG
- 1);
3238 bitcpy_rev(dst
, dst_idx
, src
, src_idx
, n
);
3241 dst_idx
+= next_plane
* 8;
3242 src_idx
+= next_plane
* 8;
3247 static void amifb_copyarea(struct fb_info
*info
,
3248 const struct fb_copyarea
*area
)
3250 struct amifb_par
*par
= info
->par
;
3252 u32 dx
, dy
, sx
, sy
, width
, height
;
3253 unsigned long *dst
, *src
;
3254 int dst_idx
, src_idx
;
3257 /* clip the destination */
3258 x2
= area
->dx
+ area
->width
;
3259 y2
= area
->dy
+ area
->height
;
3260 dx
= area
->dx
> 0 ? area
->dx
: 0;
3261 dy
= area
->dy
> 0 ? area
->dy
: 0;
3262 x2
= x2
< info
->var
.xres_virtual
? x2
: info
->var
.xres_virtual
;
3263 y2
= y2
< info
->var
.yres_virtual
? y2
: info
->var
.yres_virtual
;
3267 if (area
->sx
+ dx
< area
->dx
|| area
->sy
+ dy
< area
->dy
)
3271 sx
= area
->sx
+ (dx
- area
->dx
);
3272 sy
= area
->sy
+ (dy
- area
->dy
);
3274 /* the source must be completely inside the virtual screen */
3275 if (sx
+ width
> info
->var
.xres_virtual
||
3276 sy
+ height
> info
->var
.yres_virtual
)
3279 if (dy
> sy
|| (dy
== sy
&& dx
> sx
)) {
3284 dst
= (unsigned long *)
3285 ((unsigned long)info
->screen_base
& ~(BYTES_PER_LONG
- 1));
3287 dst_idx
= ((unsigned long)info
->screen_base
& (BYTES_PER_LONG
- 1)) * 8;
3289 dst_idx
+= dy
* par
->next_line
* 8 + dx
;
3290 src_idx
+= sy
* par
->next_line
* 8 + sx
;
3293 dst_idx
-= par
->next_line
* 8;
3294 src_idx
-= par
->next_line
* 8;
3295 copy_one_line_rev(info
->var
.bits_per_pixel
,
3296 par
->next_plane
, dst
, dst_idx
, src
,
3301 copy_one_line(info
->var
.bits_per_pixel
,
3302 par
->next_plane
, dst
, dst_idx
, src
,
3304 dst_idx
+= par
->next_line
* 8;
3305 src_idx
+= par
->next_line
* 8;
3311 static inline void expand_one_line(int bpp
, unsigned long next_plane
,
3312 unsigned long *dst
, int dst_idx
, u32 n
,
3313 const u8
*data
, u32 bgcolor
, u32 fgcolor
)
3315 const unsigned long *src
;
3319 dst
+= dst_idx
>> SHIFT_PER_LONG
;
3320 dst_idx
&= (BITS_PER_LONG
- 1);
3321 if ((bgcolor
^ fgcolor
) & 1) {
3322 src
= (unsigned long *)
3323 ((unsigned long)data
& ~(BYTES_PER_LONG
- 1));
3324 src_idx
= ((unsigned long)data
& (BYTES_PER_LONG
- 1)) * 8;
3326 bitcpy(dst
, dst_idx
, src
, src_idx
, n
);
3328 bitcpy_not(dst
, dst_idx
, src
, src_idx
, n
);
3331 bitfill32(dst
, dst_idx
, fgcolor
& 1 ? ~0 : 0, n
);
3336 dst_idx
+= next_plane
* 8;
3341 static void amifb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
3343 struct amifb_par
*par
= info
->par
;
3348 u32 dx
, dy
, width
, height
, pitch
;
3351 * We could use hardware clipping but on many cards you get around
3352 * hardware clipping by writing to framebuffer directly like we are
3355 x2
= image
->dx
+ image
->width
;
3356 y2
= image
->dy
+ image
->height
;
3359 x2
= x2
< info
->var
.xres_virtual
? x2
: info
->var
.xres_virtual
;
3360 y2
= y2
< info
->var
.yres_virtual
? y2
: info
->var
.yres_virtual
;
3364 if (image
->depth
== 1) {
3365 dst
= (unsigned long *)
3366 ((unsigned long)info
->screen_base
& ~(BYTES_PER_LONG
- 1));
3367 dst_idx
= ((unsigned long)info
->screen_base
& (BYTES_PER_LONG
- 1)) * 8;
3368 dst_idx
+= dy
* par
->next_line
* 8 + dx
;
3370 pitch
= (image
->width
+ 7) / 8;
3372 expand_one_line(info
->var
.bits_per_pixel
,
3373 par
->next_plane
, dst
, dst_idx
, width
,
3374 src
, image
->bg_color
,
3376 dst_idx
+= par
->next_line
* 8;
3380 c2p_planar(info
->screen_base
, image
->data
, dx
, dy
, width
,
3381 height
, par
->next_line
, par
->next_plane
,
3382 image
->width
, info
->var
.bits_per_pixel
);
3388 * Amiga Frame Buffer Specific ioctls
3391 static int amifb_ioctl(struct fb_info
*info
,
3392 unsigned int cmd
, unsigned long arg
)
3395 struct fb_fix_cursorinfo fix
;
3396 struct fb_var_cursorinfo var
;
3397 struct fb_cursorstate state
;
3399 void __user
*argp
= (void __user
*)arg
;
3403 case FBIOGET_FCURSORINFO
:
3404 i
= ami_get_fix_cursorinfo(&crsr
.fix
, info
->par
);
3407 return copy_to_user(argp
, &crsr
.fix
,
3408 sizeof(crsr
.fix
)) ? -EFAULT
: 0;
3410 case FBIOGET_VCURSORINFO
:
3411 i
= ami_get_var_cursorinfo(&crsr
.var
,
3412 ((struct fb_var_cursorinfo __user
*)arg
)->data
,
3416 return copy_to_user(argp
, &crsr
.var
,
3417 sizeof(crsr
.var
)) ? -EFAULT
: 0;
3419 case FBIOPUT_VCURSORINFO
:
3420 if (copy_from_user(&crsr
.var
, argp
, sizeof(crsr
.var
)))
3422 return ami_set_var_cursorinfo(&crsr
.var
,
3423 ((struct fb_var_cursorinfo __user
*)arg
)->data
,
3426 case FBIOGET_CURSORSTATE
:
3427 i
= ami_get_cursorstate(&crsr
.state
, info
->par
);
3430 return copy_to_user(argp
, &crsr
.state
,
3431 sizeof(crsr
.state
)) ? -EFAULT
: 0;
3433 case FBIOPUT_CURSORSTATE
:
3434 if (copy_from_user(&crsr
.state
, argp
, sizeof(crsr
.state
)))
3436 return ami_set_cursorstate(&crsr
.state
, info
->par
);
3443 * Flash the cursor (called by VBlank interrupt)
3446 static int flash_cursor(void)
3448 static int cursorcount
= 1;
3450 if (cursormode
== FB_CURSOR_FLASH
) {
3451 if (!--cursorcount
) {
3452 cursorstate
= -cursorstate
;
3453 cursorcount
= cursorrate
;
3462 * VBlank Display Interrupt
3465 static irqreturn_t
amifb_interrupt(int irq
, void *dev_id
)
3467 struct amifb_par
*par
= dev_id
;
3469 if (do_vmode_pan
|| do_vmode_full
)
3470 ami_update_display(par
);
3473 ami_init_display(par
);
3477 ami_rebuild_copper(par
);
3478 do_cursor
= do_vmode_pan
= 0;
3479 } else if (do_cursor
) {
3481 ami_set_sprite(par
);
3485 ami_set_sprite(par
);
3493 if (do_vmode_full
) {
3494 ami_reinit_copper(par
);
3501 static struct fb_ops amifb_ops
= {
3502 .owner
= THIS_MODULE
,
3503 .fb_check_var
= amifb_check_var
,
3504 .fb_set_par
= amifb_set_par
,
3505 .fb_setcolreg
= amifb_setcolreg
,
3506 .fb_blank
= amifb_blank
,
3507 .fb_pan_display
= amifb_pan_display
,
3508 .fb_fillrect
= amifb_fillrect
,
3509 .fb_copyarea
= amifb_copyarea
,
3510 .fb_imageblit
= amifb_imageblit
,
3511 .fb_ioctl
= amifb_ioctl
,
3516 * Allocate, Clear and Align a Block of Chip Memory
3519 static void *aligned_chipptr
;
3521 static inline u_long __init
chipalloc(u_long size
)
3523 aligned_chipptr
= amiga_chip_alloc(size
, "amifb [RAM]");
3524 if (!aligned_chipptr
) {
3525 pr_err("amifb: No Chip RAM for frame buffer");
3528 memset(aligned_chipptr
, 0, size
);
3529 return (u_long
)aligned_chipptr
;
3532 static inline void chipfree(void)
3534 if (aligned_chipptr
)
3535 amiga_chip_free(aligned_chipptr
);
3543 static int __init
amifb_probe(struct platform_device
*pdev
)
3545 struct fb_info
*info
;
3546 int tag
, i
, err
= 0;
3551 char *option
= NULL
;
3553 if (fb_get_options("amifb", &option
)) {
3557 amifb_setup(option
);
3559 custom
.dmacon
= DMAF_ALL
| DMAF_MASTER
;
3561 info
= framebuffer_alloc(sizeof(struct amifb_par
), &pdev
->dev
);
3563 dev_err(&pdev
->dev
, "framebuffer_alloc failed\n");
3567 strcpy(info
->fix
.id
, "Amiga ");
3568 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
3569 info
->fix
.accel
= FB_ACCEL_AMIGABLITT
;
3571 switch (amiga_chipset
) {
3572 #ifdef CONFIG_FB_AMIGA_OCS
3574 strcat(info
->fix
.id
, "OCS");
3577 maxdepth
[TAG_SHRES
] = 0; /* OCS means no SHRES */
3578 maxdepth
[TAG_HIRES
] = 4;
3579 maxdepth
[TAG_LORES
] = 6;
3580 maxfmode
= TAG_FMODE_1
;
3581 defmode
= amiga_vblank
== 50 ? DEFMODE_PAL
: DEFMODE_NTSC
;
3582 info
->fix
.smem_len
= VIDEOMEMSIZE_OCS
;
3584 #endif /* CONFIG_FB_AMIGA_OCS */
3586 #ifdef CONFIG_FB_AMIGA_ECS
3588 strcat(info
->fix
.id
, "ECS");
3590 maxdepth
[TAG_SHRES
] = 2;
3591 maxdepth
[TAG_HIRES
] = 4;
3592 maxdepth
[TAG_LORES
] = 6;
3593 maxfmode
= TAG_FMODE_1
;
3594 if (AMIGAHW_PRESENT(AMBER_FF
))
3595 defmode
= amiga_vblank
== 50 ? DEFMODE_AMBER_PAL
3596 : DEFMODE_AMBER_NTSC
;
3598 defmode
= amiga_vblank
== 50 ? DEFMODE_PAL
3600 if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT
>
3601 VIDEOMEMSIZE_ECS_2M
)
3602 info
->fix
.smem_len
= VIDEOMEMSIZE_ECS_2M
;
3604 info
->fix
.smem_len
= VIDEOMEMSIZE_ECS_1M
;
3606 #endif /* CONFIG_FB_AMIGA_ECS */
3608 #ifdef CONFIG_FB_AMIGA_AGA
3610 strcat(info
->fix
.id
, "AGA");
3612 maxdepth
[TAG_SHRES
] = 8;
3613 maxdepth
[TAG_HIRES
] = 8;
3614 maxdepth
[TAG_LORES
] = 8;
3615 maxfmode
= TAG_FMODE_4
;
3616 defmode
= DEFMODE_AGA
;
3617 if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT
>
3618 VIDEOMEMSIZE_AGA_2M
)
3619 info
->fix
.smem_len
= VIDEOMEMSIZE_AGA_2M
;
3621 info
->fix
.smem_len
= VIDEOMEMSIZE_AGA_1M
;
3623 #endif /* CONFIG_FB_AMIGA_AGA */
3626 #ifdef CONFIG_FB_AMIGA_OCS
3627 printk("Unknown graphics chipset, defaulting to OCS\n");
3628 strcat(info
->fix
.id
, "Unknown");
3629 goto default_chipset
;
3630 #else /* CONFIG_FB_AMIGA_OCS */
3633 #endif /* CONFIG_FB_AMIGA_OCS */
3638 * Calculate the Pixel Clock Values for this Machine
3642 u_long tmp
= DIVUL(200000000000ULL, amiga_eclock
);
3644 pixclock
[TAG_SHRES
] = (tmp
+ 4) / 8; /* SHRES: 35 ns / 28 MHz */
3645 pixclock
[TAG_HIRES
] = (tmp
+ 2) / 4; /* HIRES: 70 ns / 14 MHz */
3646 pixclock
[TAG_LORES
] = (tmp
+ 1) / 2; /* LORES: 140 ns / 7 MHz */
3650 * Replace the Tag Values with the Real Pixel Clock Values
3653 for (i
= 0; i
< NUM_TOTAL_MODES
; i
++) {
3654 struct fb_videomode
*mode
= &ami_modedb
[i
];
3655 tag
= mode
->pixclock
;
3656 if (tag
== TAG_SHRES
|| tag
== TAG_HIRES
|| tag
== TAG_LORES
) {
3657 mode
->pixclock
= pixclock
[tag
];
3662 info
->monspecs
.hfmin
= amifb_hfmin
;
3663 info
->monspecs
.hfmax
= amifb_hfmax
;
3664 info
->monspecs
.vfmin
= amifb_vfmin
;
3665 info
->monspecs
.vfmax
= amifb_vfmax
;
3668 * These are for a typical Amiga monitor (e.g. A1960)
3670 info
->monspecs
.hfmin
= 15000;
3671 info
->monspecs
.hfmax
= 38000;
3672 info
->monspecs
.vfmin
= 49;
3673 info
->monspecs
.vfmax
= 90;
3676 info
->fbops
= &amifb_ops
;
3677 info
->flags
= FBINFO_DEFAULT
;
3678 info
->device
= &pdev
->dev
;
3680 if (!fb_find_mode(&info
->var
, info
, mode_option
, ami_modedb
,
3681 NUM_TOTAL_MODES
, &ami_modedb
[defmode
], 4)) {
3686 fb_videomode_to_modelist(ami_modedb
, NUM_TOTAL_MODES
,
3690 chipptr
= chipalloc(info
->fix
.smem_len
+ SPRITEMEMSIZE
+
3691 DUMMYSPRITEMEMSIZE
+ COPINITSIZE
+
3698 assignchunk(videomemory
, u_long
, chipptr
, info
->fix
.smem_len
);
3699 assignchunk(spritememory
, u_long
, chipptr
, SPRITEMEMSIZE
);
3700 assignchunk(dummysprite
, u_short
*, chipptr
, DUMMYSPRITEMEMSIZE
);
3701 assignchunk(copdisplay
.init
, copins
*, chipptr
, COPINITSIZE
);
3702 assignchunk(copdisplay
.list
[0][0], copins
*, chipptr
, COPLISTSIZE
);
3703 assignchunk(copdisplay
.list
[0][1], copins
*, chipptr
, COPLISTSIZE
);
3704 assignchunk(copdisplay
.list
[1][0], copins
*, chipptr
, COPLISTSIZE
);
3705 assignchunk(copdisplay
.list
[1][1], copins
*, chipptr
, COPLISTSIZE
);
3708 * access the videomem with writethrough cache
3710 info
->fix
.smem_start
= (u_long
)ZTWO_PADDR(videomemory
);
3711 videomemory
= (u_long
)ioremap_writethrough(info
->fix
.smem_start
,
3712 info
->fix
.smem_len
);
3714 dev_warn(&pdev
->dev
,
3715 "Unable to map videomem cached writethrough\n");
3716 info
->screen_base
= (char *)ZTWO_VADDR(info
->fix
.smem_start
);
3718 info
->screen_base
= (char *)videomemory
;
3720 memset(dummysprite
, 0, DUMMYSPRITEMEMSIZE
);
3723 * Make sure the Copper has something to do
3728 * Enable Display DMA
3730 custom
.dmacon
= DMAF_SETCLR
| DMAF_MASTER
| DMAF_RASTER
| DMAF_COPPER
|
3731 DMAF_BLITTER
| DMAF_SPRITE
;
3733 err
= request_irq(IRQ_AMIGA_COPPER
, amifb_interrupt
, 0,
3734 "fb vertb handler", info
->par
);
3738 err
= fb_alloc_cmap(&info
->cmap
, 1 << info
->var
.bits_per_pixel
, 0);
3742 dev_set_drvdata(&pdev
->dev
, info
);
3744 err
= register_framebuffer(info
);
3748 printk("fb%d: %s frame buffer device, using %dK of video memory\n",
3749 info
->node
, info
->fix
.id
, info
->fix
.smem_len
>>10);
3754 dev_set_drvdata(&pdev
->dev
, NULL
);
3755 fb_dealloc_cmap(&info
->cmap
);
3757 free_irq(IRQ_AMIGA_COPPER
, info
->par
);
3759 custom
.dmacon
= DMAF_ALL
| DMAF_MASTER
;
3761 iounmap((void *)videomemory
);
3764 framebuffer_release(info
);
3769 static int __exit
amifb_remove(struct platform_device
*pdev
)
3771 struct fb_info
*info
= dev_get_drvdata(&pdev
->dev
);
3773 unregister_framebuffer(info
);
3774 dev_set_drvdata(&pdev
->dev
, NULL
);
3775 fb_dealloc_cmap(&info
->cmap
);
3776 free_irq(IRQ_AMIGA_COPPER
, info
->par
);
3777 custom
.dmacon
= DMAF_ALL
| DMAF_MASTER
;
3779 iounmap((void *)videomemory
);
3781 framebuffer_release(info
);
3786 static struct platform_driver amifb_driver
= {
3787 .remove
= __exit_p(amifb_remove
),
3789 .name
= "amiga-video",
3790 .owner
= THIS_MODULE
,
3794 static int __init
amifb_init(void)
3796 return platform_driver_probe(&amifb_driver
, amifb_probe
);
3799 module_init(amifb_init
);
3801 static void __exit
amifb_exit(void)
3803 platform_driver_unregister(&amifb_driver
);
3806 module_exit(amifb_exit
);
3808 MODULE_LICENSE("GPL");
3809 MODULE_ALIAS("platform:amiga-video");