blob: 2c42a812655a14a977e963a7aeb7bb0898afec01 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device
3 *
4 * Copyright (C) 1995-2003 Geert Uytterhoeven
5 *
6 * with work by Roman Zippel
7 *
8 *
9 * This file is based on the Atari frame buffer device (atafb.c):
10 *
11 * Copyright (C) 1994 Martin Schaller
12 * Roman Hodek
13 *
14 * with work by Andreas Schwab
15 * Guenther Kelleter
16 *
17 * and on the original Amiga console driver (amicon.c):
18 *
19 * Copyright (C) 1993 Hamish Macdonald
20 * Greg Harp
21 * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
22 *
23 * with work by William Rucklidge (wjr@cs.cornell.edu)
24 * Geert Uytterhoeven
25 * Jes Sorensen (jds@kom.auc.dk)
26 *
27 *
28 * History:
29 *
30 * - 24 Jul 96: Copper generates now vblank interrupt and
31 * VESA Power Saving Protocol is fully implemented
32 * - 14 Jul 96: Rework and hopefully last ECS bugs fixed
33 * - 7 Mar 96: Hardware sprite support by Roman Zippel
34 * - 18 Feb 96: OCS and ECS support by Roman Zippel
35 * Hardware functions completely rewritten
36 * - 2 Dec 95: AGA version by Geert Uytterhoeven
37 *
38 * This file is subject to the terms and conditions of the GNU General Public
39 * License. See the file COPYING in the main directory of this archive
40 * for more details.
41 */
42
43#include <linux/module.h>
44#include <linux/kernel.h>
45#include <linux/errno.h>
46#include <linux/string.h>
47#include <linux/mm.h>
48#include <linux/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>
56
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>
63
64#include "c2p.h"
65
66
67#define DEBUG
68
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
72
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
81
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
90
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
99
100#ifdef DEBUG
101# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
102#else
103# define DPRINTK(fmt, args...)
104#endif
105
106/*******************************************************************************
107
108
109 Generic video timings
110 ---------------------
111
112 Timings used by the frame buffer interface:
113
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 +----------+---------------------------------------------+----------+-------+
148
149
150 Amiga video timings
151 -------------------
152
153 The Amiga native chipsets uses another timing scheme:
154
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
162
163 You can specify the blanking timings independently. Currently I just set
164 them equal to the respective synchronization values:
165
166 - hbstrt: Start of horizontal blank
167 - hbstop: End of horizontal blank
168 - vbstrt: Start of vertical blank
169 - vbstop: End of vertical blank
170
171 Horizontal values are in color clock cycles (280 ns), vertical values are in
172 scanlines.
173
174 (0, 0) is somewhere in the upper-left corner :-)
175
176
177 Amiga visible window definitions
178 --------------------------------
179
180 Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to
181 make corrections and/or additions.
182
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):
187
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
195
196 Sprite positioning:
197
198 - sprstrt_h: Horizontal start-4 of sprite
199 - sprstrt_v: Vertical start of sprite
200
201 (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1.
202
203 Horizontal values are in dotclock cycles (35 ns), vertical values are in
204 scanlines.
205
206 (0, 0) is somewhere in the upper-left corner :-)
207
208
209 Dependencies (AGA, SHRES (35 ns dotclock))
210 -------------------------------------------
211
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:
215
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.
233
234 General dependencies
235 --------------------
236
237 - all values are SHRES pixel (35ns)
238
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
246
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.
265
266 DMA priorities
267 --------------
268
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:
272
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.
276
277 IMHO a hardware cursor is more important for X than horizontal scrolling,
278 so that's my motivation.
279
280
281 Implementation
282 --------------
283
284 ami_decode_var() converts the frame buffer values to the Amiga values. It's
285 just a `straightforward' implementation of the above rules.
286
287
288 Standard VGA timings
289 --------------------
290
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
295
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.
299
300 As a comparison, graphics/monitor.h suggests the following:
301
302 xres yres left right upper lower hsync vsync
303 ---- ---- ---- ----- ----- ----- ----- -----
304
305 VGA 640 480 52 112 24 19 112 - 2 +
306 VGA70 640 400 52 112 27 21 112 - 2 -
307
308
309 Sync polarities
310 ---------------
311
312 VSYNC HSYNC Vertical size Vertical total
313 ----- ----- ------------- --------------
314 + + Reserved Reserved
315 + - 400 414
316 - + 350 362
317 - - 480 496
318
319 Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992
320
321
322 Broadcast video timings
323 -----------------------
324
325 According to the CCIR and RETMA specifications, we have the following values:
326
327 CCIR -> PAL
328 -----------
329
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.
334
335 RETMA -> NTSC
336 -------------
337
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.
342
343 Thus if you want a PAL compatible display, you have to do the following:
344
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
358
359 The settings for a NTSC compatible display are straightforward.
360
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.
364
365
366 -- Geert --
367
368*******************************************************************************/
369
370
371 /*
372 * Custom Chipset Definitions
373 */
374
375#define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld)
376
377 /*
378 * BPLCON0 -- Bitplane Control Register 0
379 */
380
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 */
397
398 /*
399 * BPLCON2 -- Bitplane Control Register 2
400 */
401
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)
417
418 /*
419 * BPLCON3 -- Bitplane Control Register 3 (AGA)
420 */
421
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 */
436
437 /*
438 * BPLCON4 -- Bitplane Control Register 4 (AGA)
439 */
440
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)
457
458 /*
459 * BEAMCON0 -- Beam Control Register
460 */
461
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 */
477
478
479 /*
480 * FMODE -- Fetch Mode Control Register (AGA)
481 */
482
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 */
489
490 /*
491 * Tags used to indicate a specific Pixel Clock
492 *
493 * clk_shift is the shift value to get the timings in 35 ns units
494 */
495
496enum { TAG_SHRES, TAG_HIRES, TAG_LORES };
497
498 /*
499 * Tags used to indicate the specific chipset
500 */
501
502enum { TAG_OCS, TAG_ECS, TAG_AGA };
503
504 /*
505 * Tags used to indicate the memory bandwidth
506 */
507
508enum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 };
509
510
511 /*
512 * Clock Definitions, Maximum Display Depth
513 *
514 * These depend on the E-Clock or the Chipset, so they are filled in
515 * dynamically
516 */
517
518static u_long pixclock[3]; /* SHRES/HIRES/LORES: index = clk_shift */
519static u_short maxdepth[3]; /* SHRES/HIRES/LORES: index = clk_shift */
520static u_short maxfmode, chipset;
521
522
523 /*
524 * Broadcast Video Timings
525 *
526 * Horizontal values are in 35 ns (SHRES) units
527 * Vertical values are in interlaced scanlines
528 */
529
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)
534
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)
539
540
541 /*
542 * Various macros
543 */
544
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)
549
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)
555
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)
560
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)
565
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)
570
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)
575
576#define upx(x,v) (((v)+(x)-1) & -(x))
577#define downx(x,v) ((v) & -(x))
578#define modx(x,v) ((v) & ((x)-1))
579
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
589
590#define highw(x) ((u_long)(x)>>16 & 0xffff)
591#define loww(x) ((u_long)(x) & 0xffff)
592
Al Virob4290a22006-01-12 01:06:12 -0800593#define custom amiga_custom
594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595#define VBlankOn() custom.intena = IF_SETCLR|IF_COPER
596#define VBlankOff() custom.intena = IF_COPER
597
598
599 /*
600 * Chip RAM we reserve for the Frame Buffer
601 *
602 * This defines the Maximum Virtual Screen Size
603 * (Setable per kernel options?)
604 */
605
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 */
611
612#define SPRITEMEMSIZE (64*64/4) /* max 64*64*4 */
613#define DUMMYSPRITEMEMSIZE (8)
614static u_long spritememory;
615
616#define CHIPRAM_SAFETY_LIMIT (16384)
617
618static u_long videomemory;
619
620 /*
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
624 */
625
626static u_long min_fstrt = 192;
627
628#define assignchunk(name, type, ptr, size) \
629{ \
630 (name) = (type)(ptr); \
631 ptr += size; \
632}
633
634
635 /*
636 * Copper Instructions
637 */
638
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)
643
644
645typedef union {
646 u_long l;
647 u_short w[2];
648} copins;
649
650static struct copdisplay {
651 copins *init;
652 copins *wait;
653 copins *list[2][2];
654 copins *rebuild[2];
655} copdisplay;
656
657static u_short currentcop = 0;
658
659 /*
660 * Hardware Cursor API Definitions
661 * These used to be in linux/fb.h, but were preliminary and used by
662 * amifb only anyway
663 */
664
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
670
671
672struct 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 */
679};
680
681struct fb_var_cursorinfo {
682 __u16 width;
683 __u16 height;
684 __u16 xspot;
685 __u16 yspot;
686 __u8 data[1]; /* field with [height][width] */
687};
688
689struct fb_cursorstate {
690 __s16 xoffset;
691 __s16 yoffset;
692 __u16 mode;
693};
694
695#define FB_CURSOR_OFF 0
696#define FB_CURSOR_ON 1
697#define FB_CURSOR_FLASH 2
698
699
700 /*
701 * Hardware Cursor
702 */
703
704static int cursorrate = 20; /* Number of frames/flash toggle */
705static u_short cursorstate = -1;
706static u_short cursormode = FB_CURSOR_OFF;
707
708static u_short *lofsprite, *shfsprite, *dummysprite;
709
710 /*
711 * Current Video Mode
712 */
713
714static struct amifb_par {
715
716 /* General Values */
717
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 */
734
735 /* Cursor Values */
736
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;
746
747 /* OCS Hardware Registers */
748
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 */
759
760 /* Additional ECS Hardware Registers */
761
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 */
773
774 /* Additional AGA Hardware Registers */
775
776 u_short fmode; /* vmode */
777} currentpar;
778
779
780static struct fb_info fb_info = {
781 .fix = {
782 .id = "Amiga ",
783 .visual = FB_VISUAL_PSEUDOCOLOR,
784 .accel = FB_ACCEL_AMIGABLITT
785 }
786};
787
788
789 /*
790 * Saved color entry 0 so we can restore it when unblanking
791 */
792
793static u_char red0, green0, blue0;
794
795
796#if defined(CONFIG_FB_AMIGA_ECS)
797static u_short ecs_palette[32];
798#endif
799
800
801 /*
802 * Latches for Display Changes during VBlank
803 */
804
805static u_short do_vmode_full = 0; /* Change the Video Mode */
806static u_short do_vmode_pan = 0; /* Update the Video Mode */
807static short do_blank = 0; /* (Un)Blank the Screen (±1) */
808static u_short do_cursor = 0; /* Move the Cursor */
809
810
811 /*
812 * Various Flags
813 */
814
815static u_short is_blanked = 0; /* Screen is Blanked */
816static u_short is_lace = 0; /* Screen is laced */
817
818 /*
819 * Predefined Video Modes
820 *
821 */
822
823static struct fb_videomode ami_modedb[] __initdata = {
824
825 /*
826 * AmigaOS Video Modes
827 *
828 * If you change these, make sure to update DEFMODE_* as well!
829 */
830
831 {
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
903 },
904
905 /*
906 * VGA Video Modes
907 */
908
909 {
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
917 },
918
919#if 0
920
921 /*
922 * A2024 video modes
923 * These modes don't work yet because there's no A2024 driver.
924 */
925
926 {
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
934 }
935#endif
936};
937
938#define NUM_TOTAL_MODES ARRAY_SIZE(ami_modedb)
939
940static char *mode_option __initdata = NULL;
941static int round_down_bpp = 1; /* for mode probing */
942
943 /*
944 * Some default modes
945 */
946
947
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 */
953
954
955static int amifb_ilbm = 0; /* interleaved or normal bitplanes */
956static int amifb_inverse = 0;
957
958
959 /*
960 * Macros for the conversion from real world values to hardware register
961 * values
962 *
963 * This helps us to keep our attention on the real stuff...
964 *
965 * Hardware limits for AGA:
966 *
967 * parameter min max step
968 * --------- --- ---- ----
969 * diwstrt_h 0 2047 1
970 * diwstrt_v 0 2047 1
971 * diwstop_h 0 4095 1
972 * diwstop_v 0 4095 1
973 *
974 * ddfstrt 0 2032 16
975 * ddfstop 0 2032 16
976 *
977 * htotal 8 2048 8
978 * hsstrt 0 2040 8
979 * hsstop 0 2040 8
980 * vtotal 1 4096 1
981 * vsstrt 0 4095 1
982 * vsstop 0 4095 1
983 * hcenter 0 2040 8
984 *
985 * hbstrt 0 2047 1
986 * hbstop 0 2047 1
987 * vbstrt 0 4095 1
988 * vbstop 0 4095 1
989 *
990 * Horizontal values are in 35 ns (SHRES) pixels
991 * Vertical values are in half scanlines
992 */
993
994/* bplcon1 (smooth scrolling) */
995
996#define hscroll2hw(hscroll) \
997 (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \
998 ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))
999
1000/* diwstrt/diwstop/diwhigh (visible display window) */
1001
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))
1010
1011/* ddfstrt/ddfstop (display DMA) */
1012
1013#define ddfstrt2hw(ddfstrt) div8(ddfstrt)
1014#define ddfstop2hw(ddfstop) div8(ddfstop)
1015
1016/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */
1017
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))
1025
1026/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
1027
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))
1032
1033/* colour */
1034
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))
1043
1044/* sprpos/sprctl (sprite positioning) */
1045
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))
1052
1053/* get current vertical position of beam */
1054#define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe))
1055
1056 /*
1057 * Copper Initialisation List
1058 */
1059
1060#define COPINITSIZE (sizeof(copins)*40)
1061
1062enum {
1063 cip_bplcon0
1064};
1065
1066 /*
1067 * Long Frame/Short Frame Copper List
1068 * Don't change the order, build_copper()/rebuild_copper() rely on this
1069 */
1070
1071#define COPLISTSIZE (sizeof(copins)*64)
1072
1073enum {
1074 cop_wait, cop_bplcon0,
1075 cop_spr0ptrh, cop_spr0ptrl,
1076 cop_diwstrt, cop_diwstop,
1077 cop_diwhigh,
1078};
1079
1080 /*
1081 * Pixel modes for Bitplanes and Sprites
1082 */
1083
1084static u_short bplpixmode[3] = {
1085 BPC0_SHRES, /* 35 ns */
1086 BPC0_HIRES, /* 70 ns */
1087 0 /* 140 ns */
1088};
1089
1090static u_short sprpixmode[3] = {
1091 BPC3_SPRES1 | BPC3_SPRES0, /* 35 ns */
1092 BPC3_SPRES1, /* 70 ns */
1093 BPC3_SPRES0 /* 140 ns */
1094};
1095
1096 /*
1097 * Fetch modes for Bitplanes and Sprites
1098 */
1099
1100static u_short bplfetchmode[3] = {
1101 0, /* 1x */
1102 FMODE_BPL32, /* 2x */
1103 FMODE_BPAGEM | FMODE_BPL32 /* 4x */
1104};
1105
1106static u_short sprfetchmode[3] = {
1107 0, /* 1x */
1108 FMODE_SPR32, /* 2x */
1109 FMODE_SPAGEM | FMODE_SPR32 /* 4x */
1110};
1111
1112
1113 /*
1114 * Interface used by the world
1115 */
1116
1117int amifb_setup(char*);
1118
1119static int amifb_check_var(struct fb_var_screeninfo *var,
1120 struct fb_info *info);
1121static int amifb_set_par(struct fb_info *info);
1122static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green,
1123 unsigned blue, unsigned transp,
1124 struct fb_info *info);
1125static int amifb_blank(int blank, struct fb_info *info);
1126static int amifb_pan_display(struct fb_var_screeninfo *var,
1127 struct fb_info *info);
1128static void amifb_fillrect(struct fb_info *info,
1129 const struct fb_fillrect *rect);
1130static void amifb_copyarea(struct fb_info *info,
1131 const struct fb_copyarea *region);
1132static void amifb_imageblit(struct fb_info *info,
1133 const struct fb_image *image);
1134static int amifb_ioctl(struct inode *inode, struct file *file,
1135 unsigned int cmd, unsigned long arg,
1136 struct fb_info *info);
1137
1138
1139 /*
1140 * Interface to the low level console driver
1141 */
1142
1143int amifb_init(void);
1144static void amifb_deinit(void);
1145
1146 /*
1147 * Internal routines
1148 */
1149
1150static int flash_cursor(void);
1151static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
1152static u_long chipalloc(u_long size);
1153static void chipfree(void);
1154
1155 /*
1156 * Hardware routines
1157 */
1158
1159static int ami_decode_var(struct fb_var_screeninfo *var,
1160 struct amifb_par *par);
1161static int ami_encode_var(struct fb_var_screeninfo *var,
1162 struct amifb_par *par);
1163static void ami_pan_var(struct fb_var_screeninfo *var);
1164static int ami_update_par(void);
1165static void ami_update_display(void);
1166static void ami_init_display(void);
1167static void ami_do_blank(void);
1168static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix);
Al Viro3728d252006-01-12 01:06:31 -08001169static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data);
1170static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171static int ami_get_cursorstate(struct fb_cursorstate *state);
1172static int ami_set_cursorstate(struct fb_cursorstate *state);
1173static void ami_set_sprite(void);
1174static void ami_init_copper(void);
1175static void ami_reinit_copper(void);
1176static void ami_build_copper(void);
1177static void ami_rebuild_copper(void);
1178
1179
1180static 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,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 .fb_ioctl = amifb_ioctl,
1191};
1192
1193static void __init amifb_setup_mcap(char *spec)
1194{
1195 char *p;
1196 int vmin, vmax, hmin, hmax;
1197
1198 /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
1199 * <V*> vertical freq. in Hz
1200 * <H*> horizontal freq. in kHz
1201 */
1202
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;
1223
1224 fb_info.monspecs.vfmin = vmin;
1225 fb_info.monspecs.vfmax = vmax;
1226 fb_info.monspecs.hfmin = hmin;
1227 fb_info.monspecs.hfmax = hmax;
1228}
1229
1230int __init amifb_setup(char *options)
1231{
1232 char *this_opt;
1233
1234 if (!options || !*options)
1235 return 0;
1236
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;
1251 }
1252
1253 if (min_fstrt < 48)
1254 min_fstrt = 48;
1255
1256 return 0;
1257}
1258
1259
1260static int amifb_check_var(struct fb_var_screeninfo *var,
1261 struct fb_info *info)
1262{
1263 int err;
1264 struct amifb_par par;
1265
1266 /* Validate wanted screen parameters */
1267 if ((err = ami_decode_var(var, &par)))
1268 return err;
1269
1270 /* Encode (possibly rounded) screen parameters */
1271 ami_encode_var(var, &par);
1272 return 0;
1273}
1274
1275
1276static int amifb_set_par(struct fb_info *info)
1277{
1278 struct amifb_par *par = (struct amifb_par *)info->par;
1279
1280 do_vmode_pan = 0;
1281 do_vmode_full = 0;
1282
1283 /* Decode wanted screen parameters */
1284 ami_decode_var(&info->var, par);
1285
1286 /* Set new videomode */
1287 ami_build_copper();
1288
1289 /* Set VBlank trigger */
1290 do_vmode_full = 1;
1291
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;
1302 }
1303 info->fix.line_length = div8(upx(16<<maxfmode, par->vxres));
1304
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;
1319 }
1320 return 0;
1321}
1322
1323
1324 /*
1325 * Pan or Wrap the Display
1326 *
1327 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
1328 */
1329
1330static int amifb_pan_display(struct fb_var_screeninfo *var,
1331 struct fb_info *info)
1332{
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 {
1338 /*
1339 * TODO: There will be problems when xpan!=1, so some columns
1340 * on the right side will never be seen
1341 */
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;
1345 }
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;
1354}
1355
1356
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
1366
1367
1368 /*
1369 * Compose two values, using a bitmask as decision value
1370 * This is equivalent to (a & mask) | (b & ~mask)
1371 */
1372
1373static inline unsigned long comp(unsigned long a, unsigned long b,
1374 unsigned long mask)
1375{
1376 return ((a ^ b) & mask) ^ b;
1377}
1378
1379
1380static inline unsigned long xor(unsigned long a, unsigned long b,
1381 unsigned long mask)
1382{
1383 return (a & mask) ^ b;
1384}
1385
1386
1387 /*
1388 * Unaligned forward bit copy using 32-bit or 64-bit memory accesses
1389 */
1390
1391static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
1392 int src_idx, u32 n)
1393{
1394 unsigned long first, last;
1395 int shift = dst_idx-src_idx, left, right;
1396 unsigned long d0, d1;
1397 int m;
1398
1399 if (!n)
1400 return;
1401
1402 shift = dst_idx-src_idx;
1403 first = ~0UL >> dst_idx;
1404 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
1405
1406 if (!shift) {
1407 // Same alignment for source and dest
1408
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;
1422 }
1423
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;
1436 }
1437 while (n--)
1438 *dst++ = *src++;
1439
1440 // Trailing bits
1441 if (last)
1442 *dst = comp(*src, *dst, last);
1443 }
1444 } else {
1445 // Different alignment for source and dest
1446
1447 right = shift & (BITS_PER_LONG-1);
1448 left = -shift & (BITS_PER_LONG-1);
1449
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);
1466 }
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;
1484 }
1485
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;
1503 }
1504 while (n--) {
1505 d1 = *src++;
1506 *dst++ = d0 << left | d1 >> right;
1507 d0 = d1;
1508 }
1509
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);
1520 }
1521 }
1522 }
1523 }
1524}
1525
1526
1527 /*
1528 * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses
1529 */
1530
1531static void bitcpy_rev(unsigned long *dst, int dst_idx,
1532 const unsigned long *src, int src_idx, u32 n)
1533{
1534 unsigned long first, last;
1535 int shift = dst_idx-src_idx, left, right;
1536 unsigned long d0, d1;
1537 int m;
1538
1539 if (!n)
1540 return;
1541
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;
1551 }
1552
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)));
1556
1557 if (!shift) {
1558 // Same alignment for source and dest
1559
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;
1573 }
1574
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;
1587 }
1588 while (n--)
1589 *dst-- = *src--;
1590
1591 // Trailing bits
1592 if (last)
1593 *dst = comp(*src, *dst, last);
1594 }
1595 } else {
1596 // Different alignment for source and dest
1597
1598 right = shift & (BITS_PER_LONG-1);
1599 left = -shift & (BITS_PER_LONG-1);
1600
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);
1617 }
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;
1635 }
1636
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;
1654 }
1655 while (n--) {
1656 d1 = *src--;
1657 *dst-- = d0 >> right | d1 << left;
1658 d0 = d1;
1659 }
1660
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);
1671 }
1672 }
1673 }
1674 }
1675}
1676
1677
1678 /*
1679 * Unaligned forward inverting bit copy using 32-bit or 64-bit memory
1680 * accesses
1681 */
1682
1683static void bitcpy_not(unsigned long *dst, int dst_idx,
1684 const unsigned long *src, int src_idx, u32 n)
1685{
1686 unsigned long first, last;
1687 int shift = dst_idx-src_idx, left, right;
1688 unsigned long d0, d1;
1689 int m;
1690
1691 if (!n)
1692 return;
1693
1694 shift = dst_idx-src_idx;
1695 first = ~0UL >> dst_idx;
1696 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
1697
1698 if (!shift) {
1699 // Same alignment for source and dest
1700
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;
1714 }
1715
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;
1728 }
1729 while (n--)
1730 *dst++ = ~*src++;
1731
1732 // Trailing bits
1733 if (last)
1734 *dst = comp(~*src, *dst, last);
1735 }
1736 } else {
1737 // Different alignment for source and dest
1738
1739 right = shift & (BITS_PER_LONG-1);
1740 left = -shift & (BITS_PER_LONG-1);
1741
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);
1758 }
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;
1776 }
1777
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;
1795 }
1796 while (n--) {
1797 d1 = ~*src++;
1798 *dst++ = d0 << left | d1 >> right;
1799 d0 = d1;
1800 }
1801
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);
1812 }
1813 }
1814 }
1815 }
1816}
1817
1818
1819 /*
1820 * Unaligned 32-bit pattern fill using 32/64-bit memory accesses
1821 */
1822
1823static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
1824{
1825 unsigned long val = pat;
1826 unsigned long first, last;
1827
1828 if (!n)
1829 return;
1830
1831#if BITS_PER_LONG == 64
1832 val |= val << 32;
1833#endif
1834
1835 first = ~0UL >> dst_idx;
1836 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
1837
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;
1850 }
1851
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;
1864 }
1865 while (n--)
1866 *dst++ = val;
1867
1868 // Trailing bits
1869 if (last)
1870 *dst = comp(val, *dst, last);
1871 }
1872}
1873
1874
1875 /*
1876 * Unaligned 32-bit pattern xor using 32/64-bit memory accesses
1877 */
1878
1879static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
1880{
1881 unsigned long val = pat;
1882 unsigned long first, last;
1883
1884 if (!n)
1885 return;
1886
1887#if BITS_PER_LONG == 64
1888 val |= val << 32;
1889#endif
1890
1891 first = ~0UL >> dst_idx;
1892 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
1893
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;
1906 }
1907
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;
1916 }
1917 while (n--)
1918 *dst++ ^= val;
1919
1920 // Trailing bits
1921 if (last)
1922 *dst = xor(val, *dst, last);
1923 }
1924}
1925
1926static inline void fill_one_line(int bpp, unsigned long next_plane,
1927 unsigned long *dst, int dst_idx, u32 n,
1928 u32 color)
1929{
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;
1938 }
1939}
1940
1941static inline void xor_one_line(int bpp, unsigned long next_plane,
1942 unsigned long *dst, int dst_idx, u32 n,
1943 u32 color)
1944{
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;
1953 }
1954}
1955
1956
1957static void amifb_fillrect(struct fb_info *info,
1958 const struct fb_fillrect *rect)
1959{
1960 struct amifb_par *par = (struct amifb_par *)info->par;
1961 int dst_idx, x2, y2;
1962 unsigned long *dst;
1963 u32 width, height;
1964
1965 if (!rect->width || !rect->height)
1966 return;
1967
1968 /*
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;
1978
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;
1990
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;
1995 }
1996 dst_idx += par->next_line*8;
1997 }
1998}
1999
2000static 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)
2003{
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;
2014 }
2015}
2016
2017static 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)
2020{
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;
2031 }
2032}
2033
2034
2035static void amifb_copyarea(struct fb_info *info,
2036 const struct fb_copyarea *area)
2037{
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;
2044
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;
2054
2055 /* update sx,sy */
2056 sx = area->sx + (dx - area->dx);
2057 sy = area->sy + (dy - area->dy);
2058
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;
2063
2064 if (dy > sy || (dy == sy && dx > sx)) {
2065 dy += height;
2066 sy += height;
2067 rev_copy = 1;
2068 }
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);
2083 }
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;
2091 }
2092 }
2093}
2094
2095
2096static 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)
2099{
2100 const unsigned long *src;
2101 int src_idx;
2102
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;
2121 }
2122}
2123
2124
2125static void amifb_imageblit(struct fb_info *info, const struct fb_image *image)
2126{
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;
2133
2134 /*
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.
2138 */
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;
2147
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;
2162 }
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);
2167 }
2168}
2169
2170
2171 /*
2172 * Amiga Frame Buffer Specific ioctls
2173 */
2174
2175static int amifb_ioctl(struct inode *inode, struct file *file,
2176 unsigned int cmd, unsigned long arg,
2177 struct fb_info *info)
2178{
2179 union {
2180 struct fb_fix_cursorinfo fix;
2181 struct fb_var_cursorinfo var;
2182 struct fb_cursorstate state;
2183 } crsr;
Al Viro3728d252006-01-12 01:06:31 -08002184 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 int i;
2186
2187 switch (cmd) {
2188 case FBIOGET_FCURSORINFO:
2189 i = ami_get_fix_cursorinfo(&crsr.fix);
2190 if (i)
2191 return i;
Al Viro3728d252006-01-12 01:06:31 -08002192 return copy_to_user(argp, &crsr.fix,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 sizeof(crsr.fix)) ? -EFAULT : 0;
2194
2195 case FBIOGET_VCURSORINFO:
2196 i = ami_get_var_cursorinfo(&crsr.var,
Al Viro3728d252006-01-12 01:06:31 -08002197 ((struct fb_var_cursorinfo __user *)arg)->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 if (i)
2199 return i;
Al Viro3728d252006-01-12 01:06:31 -08002200 return copy_to_user(argp, &crsr.var,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 sizeof(crsr.var)) ? -EFAULT : 0;
2202
2203 case FBIOPUT_VCURSORINFO:
Al Viro3728d252006-01-12 01:06:31 -08002204 if (copy_from_user(&crsr.var, argp, sizeof(crsr.var)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 return -EFAULT;
2206 return ami_set_var_cursorinfo(&crsr.var,
Al Viro3728d252006-01-12 01:06:31 -08002207 ((struct fb_var_cursorinfo __user *)arg)->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208
2209 case FBIOGET_CURSORSTATE:
2210 i = ami_get_cursorstate(&crsr.state);
2211 if (i)
2212 return i;
Al Viro3728d252006-01-12 01:06:31 -08002213 return copy_to_user(argp, &crsr.state,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 sizeof(crsr.state)) ? -EFAULT : 0;
2215
2216 case FBIOPUT_CURSORSTATE:
Al Viro3728d252006-01-12 01:06:31 -08002217 if (copy_from_user(&crsr.state, argp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 sizeof(crsr.state)))
2219 return -EFAULT;
2220 return ami_set_cursorstate(&crsr.state);
2221 }
2222 return -EINVAL;
2223}
2224
2225
2226 /*
2227 * Allocate, Clear and Align a Block of Chip Memory
2228 */
2229
2230static u_long unaligned_chipptr = 0;
2231
2232static inline u_long __init chipalloc(u_long size)
2233{
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);
2240}
2241
2242static inline void chipfree(void)
2243{
2244 if (unaligned_chipptr)
2245 amiga_chip_free((void *)unaligned_chipptr);
2246}
2247
2248
2249 /*
2250 * Initialisation
2251 */
2252
2253int __init amifb_init(void)
2254{
2255 int tag, i, err = 0;
2256 u_long chipptr;
2257 u_int defmode;
2258
2259#ifndef MODULE
2260 char *option = NULL;
2261
2262 if (fb_get_options("amifb", &option)) {
2263 amifb_video_off();
2264 return -ENODEV;
2265 }
2266 amifb_setup(option);
2267#endif
2268 if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO))
2269 return -ENXIO;
2270
2271 /*
2272 * We request all registers starting from bplpt[0]
2273 */
2274 if (!request_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120,
2275 "amifb [Denise/Lisa]"))
2276 return -EBUSY;
2277
2278 custom.dmacon = DMAF_ALL | DMAF_MASTER;
2279
2280 switch (amiga_chipset) {
2281#ifdef CONFIG_FB_AMIGA_OCS
2282 case CS_OCS:
2283 strcat(fb_info.fix.id, "OCS");
2284default_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 */
2295
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 */
2317
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 */
2334
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;
2345 }
2346
2347 /*
2348 * Calculate the Pixel Clock Values for this Machine
2349 */
2350
2351 {
2352 u_long tmp = DIVUL(200000000000ULL, amiga_eclock);
2353
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 */
2357 }
2358
2359 /*
2360 * Replace the Tag Values with the Real Pixel Clock Values
2361 */
2362
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];
2368 }
2369 }
2370
2371 /*
2372 * These monitor specs are for a typical Amiga monitor (e.g. A1960)
2373 */
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;
2379 }
2380
2381 fb_info.fbops = &amifb_ops;
2382 fb_info.par = &currentpar;
2383 fb_info.flags = FBINFO_DEFAULT;
2384
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;
2389 }
2390
2391 round_down_bpp = 0;
2392 chipptr = chipalloc(fb_info.fix.smem_len+
2393 SPRITEMEMSIZE+
2394 DUMMYSPRITEMEMSIZE+
2395 COPINITSIZE+
2396 4*COPLISTSIZE);
2397
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);
2406
2407 /*
2408 * access the videomem with writethrough cache
2409 */
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);
2416 }
2417
2418 fb_info.screen_base = (char *)videomemory;
2419 memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
2420
2421 /*
2422 * Enable Display DMA
2423 */
2424
2425 custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
2426 DMAF_BLITTER | DMAF_SPRITE;
2427
2428 /*
2429 * Make sure the Copper has something to do
2430 */
2431
2432 ami_init_copper();
2433
2434 if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,
2435 "fb vertb handler", &currentpar)) {
2436 err = -EBUSY;
2437 goto amifb_error;
2438 }
2439
2440 fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0);
2441
2442 if (register_framebuffer(&fb_info) < 0) {
2443 err = -EINVAL;
2444 goto amifb_error;
2445 }
2446
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);
2449
2450 return 0;
2451
2452amifb_error:
2453 amifb_deinit();
2454 return err;
2455}
2456
2457static void amifb_deinit(void)
2458{
2459 fb_dealloc_cmap(&fb_info.cmap);
2460 chipfree();
2461 release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
2462 custom.dmacon = DMAF_ALL | DMAF_MASTER;
2463}
2464
2465
2466 /*
2467 * Blank the display.
2468 */
2469
2470static int amifb_blank(int blank, struct fb_info *info)
2471{
2472 do_blank = blank ? blank : -1;
2473
2474 return 0;
2475}
2476
2477 /*
2478 * Flash the cursor (called by VBlank interrupt)
2479 */
2480
2481static int flash_cursor(void)
2482{
2483 static int cursorcount = 1;
2484
2485 if (cursormode == FB_CURSOR_FLASH) {
2486 if (!--cursorcount) {
2487 cursorstate = -cursorstate;
2488 cursorcount = cursorrate;
2489 if (!is_blanked)
2490 return 1;
2491 }
2492 }
2493 return 0;
2494}
2495
2496 /*
2497 * VBlank Display Interrupt
2498 */
2499
2500static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
2501{
2502 if (do_vmode_pan || do_vmode_full)
2503 ami_update_display();
2504
2505 if (do_vmode_full)
2506 ami_init_display();
2507
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();
2519 }
2520
2521 if (do_blank) {
2522 ami_do_blank();
2523 do_blank = 0;
2524 }
2525
2526 if (do_vmode_full) {
2527 ami_reinit_copper();
2528 do_vmode_full = 0;
2529 }
2530 return IRQ_HANDLED;
2531}
2532
2533/* --------------------------- Hardware routines --------------------------- */
2534
2535 /*
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.
2538 */
2539
2540static int ami_decode_var(struct fb_var_screeninfo *var,
2541 struct amifb_par *par)
2542{
2543 u_short clk_shift, line_shift;
2544 u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;
2545 u_int htotal, vtotal;
2546
2547 /*
2548 * Find a matching Pixel Clock
2549 */
2550
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;
2557 }
2558 par->clk_shift = clk_shift;
2559
2560 /*
2561 * Check the Geometry Values
2562 */
2563
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;
2572
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;
2583 }
2584 }
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;
2594 }
2595 }
2596 } else {
2597 DPRINTK("unknown nonstd mode\n");
2598 return -EINVAL;
2599 }
2600
2601 /*
2602 * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
2603 * checks failed and smooth scrolling is not possible
2604 */
2605
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;
2618 }
2619 line_shift = 2;
2620 break;
2621 default:
2622 DPRINTK("unknown video mode\n");
2623 return -EINVAL;
2624 break;
2625 }
2626 par->line_shift = line_shift;
2627
2628 /*
2629 * Vertical and Horizontal Timings
2630 */
2631
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);
2636
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);
2647
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;
2654 }
2655 if (par->diwstop_v > par->vtotal) {
2656 DPRINTK("invalid diwstop_v\n");
2657 return -EINVAL;
2658 }
2659
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;
2671 }
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;
2677 }
2678 if (par->diwstrt_h < PAL_DIWSTRT_H) {
2679 DPRINTK("diwstrt_h too low for pal\n");
2680 return -EINVAL;
2681 }
2682 if (par->diwstrt_v < PAL_DIWSTRT_V) {
2683 DPRINTK("diwstrt_v too low for pal\n");
2684 return -EINVAL;
2685 }
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;
2698 }
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
2703 */
2704 if (par->htotal != NTSC_HTOTAL) {
2705 DPRINTK("htotal invalid for ntsc\n");
2706 return -EINVAL;
2707 }
2708 if (par->diwstrt_h < NTSC_DIWSTRT_H) {
2709 DPRINTK("diwstrt_h too low for ntsc\n");
2710 return -EINVAL;
2711 }
2712 if (par->diwstrt_v < NTSC_DIWSTRT_V) {
2713 DPRINTK("diwstrt_v too low for ntsc\n");
2714 return -EINVAL;
2715 }
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;
2728 }
2729 }
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;
2735 }
2736 }
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;
2761 }
2762 if (par->htotal > 2048) {
2763 DPRINTK("htotal too high\n");
2764 return -EINVAL;
2765 }
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;
2781 }
2782
2783 /*
2784 * Checking the DMA timing
2785 */
2786
2787 fconst = 16<<maxfmode<<clk_shift;
2788
2789 /*
2790 * smallest window start value without turn off other dma cycles
2791 * than sprite1-7, unless you change min_fstrt
2792 */
2793
2794
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;
2800 }
2801
2802 /*
2803 * smallest window start value where smooth scrolling is possible
2804 */
2805
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;
2809
2810 maxfetchstop = down16(par->htotal - 80);
2811
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;
2816
2817 fsize = upx(fconst, xres_n);
2818 if (fstrt + fsize > maxfetchstop) {
2819 DPRINTK("fetch stop too high\n");
2820 return -EINVAL;
2821 }
2822
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;
2827
2828 fsize = up64(xres_n);
2829 if (min_fstrt + fsize - 64 > maxfetchstop) {
2830 DPRINTK("fetch size too high\n");
2831 return -EINVAL;
2832 }
2833
2834 fsize -= 64;
2835 } else
2836 fsize -= fconst;
2837
2838 /*
2839 * Check if there is enough time to update the bitplane pointers for ywrap
2840 */
2841
2842 if (par->htotal-fsize-64 < par->bpp*64)
2843 par->vmode &= ~FB_VMODE_YWRAP;
2844
2845 /*
2846 * Bitplane calculations and check the Memory Requirements
2847 */
2848
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;
2855 }
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;
2862 }
2863 }
2864
2865 /*
2866 * Hardware Register Values
2867 */
2868
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;
2880
2881 if (IS_AGA)
2882 par->fmode = bplfetchmode[maxfmode];
2883
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;
2892 }
2893
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;
2904 }
2905 } else
2906 par->xoffset = par->yoffset = 0;
2907
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;
2911
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;
2917 }
2918#endif
2919
2920 return 0;
2921}
2922
2923 /*
2924 * Fill the `var' structure based on the values in `par' and maybe
2925 * other values read out of the hardware.
2926 */
2927
2928static int ami_encode_var(struct fb_var_screeninfo *var,
2929 struct amifb_par *par)
2930{
2931 u_short clk_shift, line_shift;
2932
2933 memset(var, 0, sizeof(struct fb_var_screeninfo));
2934
2935 clk_shift = par->clk_shift;
2936 line_shift = par->line_shift;
2937
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;
2944
2945 var->bits_per_pixel = par->bpp;
2946 var->grayscale = 0;
2947
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;
2957
2958 if (par->bplcon0 & BPC0_HAM)
2959 var->nonstd = FB_NONSTD_HAM;
2960 else
2961 var->nonstd = 0;
2962 var->activate = 0;
2963
2964 var->height = -1;
2965 var->width = -1;
2966
2967 var->pixclock = pixclock[clk_shift];
2968
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;
2975
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;
2999 }
3000
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;
3005
3006 return 0;
3007}
3008
3009
3010 /*
3011 * Pan or Wrap the Display
3012 *
3013 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
3014 * in `var'.
3015 */
3016
3017static void ami_pan_var(struct fb_var_screeninfo *var)
3018{
3019 struct amifb_par *par = &currentpar;
3020
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;
3027
3028 do_vmode_pan = 0;
3029 ami_update_par();
3030 do_vmode_pan = 1;
3031}
3032
3033 /*
3034 * Update hardware
3035 */
3036
3037static int ami_update_par(void)
3038{
3039 struct amifb_par *par = &currentpar;
3040 short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod;
3041
3042 clk_shift = par->clk_shift;
3043
3044 if (!(par->vmode & FB_VMODE_SMOOTH_XPAN))
3045 par->xoffset = upx(16<<maxfmode, par->xoffset);
3046
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;
3065 }
3066 move = move - div8((mod-fstrt)>>clk_shift);
3067 }
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;
3079
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;
3087 }
3088 }
3089 } else
3090 par->bplpt0 = fb_info.fix.smem_start + move;
3091
3092 if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
3093 par->bplpt0 += par->next_line;
3094
3095 return 0;
3096}
3097
3098
3099 /*
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.
3103 */
3104
3105static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
3106 u_int transp, struct fb_info *info)
3107{
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;
3117 }
3118 red >>= 8;
3119 green >>= 8;
3120 blue >>= 8;
3121 if (!regno) {
3122 red0 = red;
3123 green0 = green;
3124 blue0 = blue;
3125 }
3126
3127 /*
3128 * Update the corresponding Hardware Color Register, unless it's Color
3129 * Register 0 and the screen is blanked.
3130 *
3131 * VBlank is switched off to protect bplcon3 or ecs_palette[] from
3132 * being changed by ami_do_blank() during the VBlank.
3133 */
3134
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;
3152
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);
3166 }
3167 return 0;
3168}
3169
3170static void ami_update_display(void)
3171{
3172 struct amifb_par *par = &currentpar;
3173
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);
3179}
3180
3181 /*
3182 * Change the video mode (called by VBlank interrupt)
3183 */
3184
3185static void ami_init_display(void)
3186{
3187 struct amifb_par *par = &currentpar;
3188 int i;
3189
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);
3208 }
3209 }
3210 if (!IS_OCS || par->hsstop)
3211 custom.beamcon0 = par->beamcon0;
3212 if (IS_AGA)
3213 custom.fmode = par->fmode;
3214
3215 /*
3216 * The minimum period for audio depends on htotal
3217 */
3218
3219 amiga_audio_min_period = div16(par->htotal);
3220
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;
3228 }
3229#else
3230 i = 1;
3231 custom.vposw = custom.vposr | 0x8000;
3232#endif
3233 custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]);
3234}
3235
3236 /*
3237 * (Un)Blank the screen (called by VBlank interrupt)
3238 */
3239
3240static void ami_do_blank(void)
3241{
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;
3247
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;
3271 }
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;
3277 }
3278 }
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;
3290 }
3291 }
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;
3305
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;
3317}
3318
3319static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix)
3320{
3321 struct amifb_par *par = &currentpar;
3322
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;
3328}
3329
Al Viro3728d252006-01-12 01:06:31 -08003330static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331{
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;
3343
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;
Al Viro3728d252006-01-12 01:06:31 -08003352 if (!access_ok(VERIFY_WRITE, data, size))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 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
Al Viro3728d252006-01-12 01:06:31 -08003359 sspr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 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
3371 }
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++);
3384 }
3385 if (bits > 0) {
3386 --words; ++lspr;
3387 }
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;
3399 }
3400#endif
3401 }
3402 return 0;
3403}
3404
Al Viro3728d252006-01-12 01:06:31 -08003405static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406{
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;
3417
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;
Al Viro3728d252006-01-12 01:06:31 -08003432 if (!access_ok(VERIFY_READ, data, var->width*var->height))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 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);
Al Viro3728d252006-01-12 01:06:31 -08003447 sspr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 }
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;
Al Viro3728d252006-01-12 01:06:31 -08003453 get_user(tdata, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 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
3475 }
3476 }
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
3488 }
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
3497 }
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;
3507 }
3508#endif
3509 }
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;
3519 }
3520 return 0;
3521}
3522
3523static int ami_get_cursorstate(struct fb_cursorstate *state)
3524{
3525 struct amifb_par *par = &currentpar;
3526
3527 state->xoffset = par->crsr.crsr_x;
3528 state->yoffset = par->crsr.crsr_y;
3529 state->mode = cursormode;
3530 return 0;
3531}
3532
3533static int ami_set_cursorstate(struct fb_cursorstate *state)
3534{
3535 struct amifb_par *par = &currentpar;
3536
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;
3543}
3544
3545static void ami_set_sprite(void)
3546{
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;
3552
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;
3561 }
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);
3580 }
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);
3584 }
3585 }
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);
3591 }
3592}
3593
3594
3595 /*
3596 * Initialise the Copper Initialisation List
3597 */
3598
3599static void __init ami_init_copper(void)
3600{
3601 copins *cop = copdisplay.init;
3602 u_long p;
3603 int i;
3604
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]);
3617 }
3618
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;
3624
3625 custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);
3626 custom.copjmp1 = 0;
3627}
3628
3629static void ami_reinit_copper(void)
3630{
3631 struct amifb_par *par = &currentpar;
3632
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);
3635}
3636
3637 /*
3638 * Build the Copper List
3639 */
3640
3641static void ami_build_copper(void)
3642{
3643 struct amifb_par *par = &currentpar;
3644 copins *copl, *cops;
3645 u_long p;
3646
3647 currentcop = 1 - currentcop;
3648
3649 copl = copdisplay.list[currentcop][1];
3650
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]);
3655
3656 if (par->bplcon0 & BPC0_LACE) {
3657 cops = copdisplay.list[currentcop][0];
3658
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]);
3663
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);
3681 }
3682#endif
3683 }
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);
3702 }
3703#endif
3704 }
3705 }
3706 copdisplay.rebuild[1] = copl;
3707
3708 ami_update_par();
3709 ami_rebuild_copper();
3710}
3711
3712 /*
3713 * Rebuild the Copper List
3714 *
3715 * We only change the things that are not static
3716 */
3717
3718static void ami_rebuild_copper(void)
3719{
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;
3725
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;
3731
3732 ami_set_sprite();
3733
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]);
3742 }
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;
3747 }
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;
3753 }
3754 } else p = par->bplpt0wrap;
3755 }
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]);
3759 }
3760 copl->l = CEND;
3761
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]);
3775 }
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;
3780 }
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;
3790 }
3791 } else p = par->bplpt0wrap - par->next_line;
3792 }
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]);
3796 }
3797 cops->l = CEND;
3798 }
3799}
3800
3801
3802module_init(amifb_init);
3803
3804#ifdef MODULE
3805MODULE_LICENSE("GPL");
3806
3807void cleanup_module(void)
3808{
3809 unregister_framebuffer(&fb_info);
3810 amifb_deinit();
3811 amifb_video_off();
3812}
3813#endif /* MODULE */