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