fbdev/amifb: Fix double free
[deliverable/linux.git] / drivers / video / amifb.c
CommitLineData
1da177e4
LT
1/*
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>
1da177e4 48#include <linux/delay.h>
1da177e4
LT
49#include <linux/interrupt.h>
50#include <linux/fb.h>
51#include <linux/init.h>
52#include <linux/ioport.h>
fa6688e1 53#include <linux/platform_device.h>
84902b7a 54#include <linux/uaccess.h>
fa6688e1 55
1da177e4
LT
56#include <asm/system.h>
57#include <asm/irq.h>
58#include <asm/amigahw.h>
59#include <asm/amigaints.h>
60#include <asm/setup.h>
61
62#include "c2p.h"
63
64
65#define DEBUG
66
67#if !defined(CONFIG_FB_AMIGA_OCS) && !defined(CONFIG_FB_AMIGA_ECS) && !defined(CONFIG_FB_AMIGA_AGA)
68#define CONFIG_FB_AMIGA_OCS /* define at least one fb driver, this will change later */
69#endif
70
71#if !defined(CONFIG_FB_AMIGA_OCS)
72# define IS_OCS (0)
73#elif defined(CONFIG_FB_AMIGA_ECS) || defined(CONFIG_FB_AMIGA_AGA)
74# define IS_OCS (chipset == TAG_OCS)
75#else
76# define CONFIG_FB_AMIGA_OCS_ONLY
77# define IS_OCS (1)
78#endif
79
80#if !defined(CONFIG_FB_AMIGA_ECS)
81# define IS_ECS (0)
82#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_AGA)
83# define IS_ECS (chipset == TAG_ECS)
84#else
85# define CONFIG_FB_AMIGA_ECS_ONLY
86# define IS_ECS (1)
87#endif
88
89#if !defined(CONFIG_FB_AMIGA_AGA)
90# define IS_AGA (0)
91#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_ECS)
92# define IS_AGA (chipset == TAG_AGA)
93#else
94# define CONFIG_FB_AMIGA_AGA_ONLY
95# define IS_AGA (1)
96#endif
97
98#ifdef DEBUG
5ae12170 99# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
1da177e4
LT
100#else
101# define DPRINTK(fmt, args...)
102#endif
103
104/*******************************************************************************
105
106
107 Generic video timings
108 ---------------------
109
110 Timings used by the frame buffer interface:
111
112 +----------+---------------------------------------------+----------+-------+
113 | | ^ | | |
114 | | |upper_margin | | |
96de0e25 115 | | v | | |
1da177e4
LT
116 +----------###############################################----------+-------+
117 | # ^ # | |
118 | # | # | |
119 | # | # | |
120 | # | # | |
121 | left # | # right | hsync |
122 | margin # | xres # margin | len |
123 |<-------->#<---------------+--------------------------->#<-------->|<----->|
124 | # | # | |
125 | # | # | |
126 | # | # | |
127 | # |yres # | |
128 | # | # | |
129 | # | # | |
130 | # | # | |
131 | # | # | |
132 | # | # | |
133 | # | # | |
134 | # | # | |
135 | # | # | |
96de0e25 136 | # v # | |
1da177e4
LT
137 +----------###############################################----------+-------+
138 | | ^ | | |
139 | | |lower_margin | | |
96de0e25 140 | | v | | |
1da177e4
LT
141 +----------+---------------------------------------------+----------+-------+
142 | | ^ | | |
143 | | |vsync_len | | |
96de0e25 144 | | v | | |
1da177e4
LT
145 +----------+---------------------------------------------+----------+-------+
146
147
148 Amiga video timings
149 -------------------
150
151 The Amiga native chipsets uses another timing scheme:
152
153 - hsstrt: Start of horizontal synchronization pulse
154 - hsstop: End of horizontal synchronization pulse
f0058b4b 155 - htotal: Last value on the line (i.e. line length = htotal + 1)
1da177e4
LT
156 - vsstrt: Start of vertical synchronization pulse
157 - vsstop: End of vertical synchronization pulse
f0058b4b 158 - vtotal: Last line value (i.e. number of lines = vtotal + 1)
1da177e4
LT
159 - hcenter: Start of vertical retrace for interlace
160
161 You can specify the blanking timings independently. Currently I just set
162 them equal to the respective synchronization values:
163
164 - hbstrt: Start of horizontal blank
165 - hbstop: End of horizontal blank
166 - vbstrt: Start of vertical blank
167 - vbstop: End of vertical blank
168
169 Horizontal values are in color clock cycles (280 ns), vertical values are in
170 scanlines.
171
172 (0, 0) is somewhere in the upper-left corner :-)
173
174
175 Amiga visible window definitions
176 --------------------------------
177
178 Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to
179 make corrections and/or additions.
180
181 Within the above synchronization specifications, the visible window is
182 defined by the following parameters (actual register resolutions may be
183 different; all horizontal values are normalized with respect to the pixel
184 clock):
185
186 - diwstrt_h: Horizontal start of the visible window
f0058b4b 187 - diwstop_h: Horizontal stop + 1(*) of the visible window
1da177e4
LT
188 - diwstrt_v: Vertical start of the visible window
189 - diwstop_v: Vertical stop of the visible window
190 - ddfstrt: Horizontal start of display DMA
191 - ddfstop: Horizontal stop of display DMA
192 - hscroll: Horizontal display output delay
193
194 Sprite positioning:
195
f0058b4b 196 - sprstrt_h: Horizontal start - 4 of sprite
1da177e4
LT
197 - sprstrt_v: Vertical start of sprite
198
199 (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1.
200
201 Horizontal values are in dotclock cycles (35 ns), vertical values are in
202 scanlines.
203
204 (0, 0) is somewhere in the upper-left corner :-)
205
206
207 Dependencies (AGA, SHRES (35 ns dotclock))
208 -------------------------------------------
209
210 Since there are much more parameters for the Amiga display than for the
211 frame buffer interface, there must be some dependencies among the Amiga
212 display parameters. Here's what I found out:
213
214 - ddfstrt and ddfstop are best aligned to 64 pixels.
f0058b4b
GU
215 - the chipset needs 64 + 4 horizontal pixels after the DMA start before
216 the first pixel is output, so diwstrt_h = ddfstrt + 64 + 4 if you want
217 to display the first pixel on the line too. Increase diwstrt_h for
218 virtual screen panning.
1da177e4 219 - the display DMA always fetches 64 pixels at a time (fmode = 3).
f0058b4b
GU
220 - ddfstop is ddfstrt+#pixels - 64.
221 - diwstop_h = diwstrt_h + xres + 1. Because of the additional 1 this can
222 be 1 more than htotal.
1da177e4 223 - hscroll simply adds a delay to the display output. Smooth horizontal
f0058b4b
GU
224 panning needs an extra 64 pixels on the left to prefetch the pixels that
225 `fall off' on the left.
1da177e4 226 - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane
f0058b4b 227 DMA, so it's best to make the DMA start as late as possible.
1da177e4 228 - you really don't want to make ddfstrt < 128, since this will steal DMA
f0058b4b 229 cycles from the other DMA channels (audio, floppy and Chip RAM refresh).
1da177e4
LT
230 - I make diwstop_h and diwstop_v as large as possible.
231
232 General dependencies
233 --------------------
234
235 - all values are SHRES pixel (35ns)
236
f0058b4b
GU
237 table 1:fetchstart table 2:prefetch table 3:fetchsize
238 ------------------ ---------------- -----------------
1da177e4
LT
239 Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES
240 -------------#------+-----+------#------+-----+------#------+-----+------
241 Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64
242 Bus width 2x # 32 | 64 | 128 # 32 | 64 | 64 # 64 | 64 | 128
243 Bus width 4x # 64 | 128 | 256 # 64 | 64 | 64 # 64 | 128 | 256
244
245 - chipset needs 4 pixels before the first pixel is output
246 - ddfstrt must be aligned to fetchstart (table 1)
247 - chipset needs also prefetch (table 2) to get first pixel data, so
f0058b4b 248 ddfstrt = ((diwstrt_h - 4) & -fetchstart) - prefetch
1da177e4
LT
249 - for horizontal panning decrease diwstrt_h
250 - the length of a fetchline must be aligned to fetchsize (table 3)
251 - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit
f0058b4b
GU
252 moved to optimize use of dma (useful for OCS/ECS overscan displays)
253 - ddfstop is ddfstrt + ddfsize - fetchsize
1da177e4 254 - If C= didn't change anything for AGA, then at following positions the
f0058b4b
GU
255 dma bus is already used:
256 ddfstrt < 48 -> memory refresh
257 < 96 -> disk dma
258 < 160 -> audio dma
259 < 192 -> sprite 0 dma
260 < 416 -> sprite dma (32 per sprite)
1da177e4 261 - in accordance with the hardware reference manual a hardware stop is at
f0058b4b 262 192, but AGA (ECS?) can go below this.
1da177e4
LT
263
264 DMA priorities
265 --------------
266
267 Since there are limits on the earliest start value for display DMA and the
268 display of sprites, I use the following policy on horizontal panning and
269 the hardware cursor:
270
271 - if you want to start display DMA too early, you lose the ability to
f0058b4b 272 do smooth horizontal panning (xpanstep 1 -> 64).
1da177e4
LT
273 - if you want to go even further, you lose the hardware cursor too.
274
275 IMHO a hardware cursor is more important for X than horizontal scrolling,
276 so that's my motivation.
277
278
279 Implementation
280 --------------
281
282 ami_decode_var() converts the frame buffer values to the Amiga values. It's
283 just a `straightforward' implementation of the above rules.
284
285
286 Standard VGA timings
287 --------------------
288
f0058b4b
GU
289 xres yres left right upper lower hsync vsync
290 ---- ---- ---- ----- ----- ----- ----- -----
1da177e4
LT
291 80x25 720 400 27 45 35 12 108 2
292 80x30 720 480 27 45 30 9 108 2
293
294 These were taken from a XFree86 configuration file, recalculated for a 28 MHz
295 dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer
296 generic timings.
297
298 As a comparison, graphics/monitor.h suggests the following:
299
f0058b4b
GU
300 xres yres left right upper lower hsync vsync
301 ---- ---- ---- ----- ----- ----- ----- -----
1da177e4
LT
302
303 VGA 640 480 52 112 24 19 112 - 2 +
304 VGA70 640 400 52 112 27 21 112 - 2 -
305
306
307 Sync polarities
308 ---------------
309
310 VSYNC HSYNC Vertical size Vertical total
311 ----- ----- ------------- --------------
f0058b4b
GU
312 + + Reserved Reserved
313 + - 400 414
314 - + 350 362
315 - - 480 496
1da177e4
LT
316
317 Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992
318
319
320 Broadcast video timings
321 -----------------------
322
323 According to the CCIR and RETMA specifications, we have the following values:
324
325 CCIR -> PAL
326 -----------
327
96de0e25 328 - a scanline is 64 µs long, of which 52.48 µs are visible. This is about
f0058b4b 329 736 visible 70 ns pixels per line.
1da177e4 330 - we have 625 scanlines, of which 575 are visible (interlaced); after
f0058b4b 331 rounding this becomes 576.
1da177e4
LT
332
333 RETMA -> NTSC
334 -------------
335
96de0e25 336 - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about
f0058b4b 337 736 visible 70 ns pixels per line.
1da177e4 338 - we have 525 scanlines, of which 485 are visible (interlaced); after
f0058b4b 339 rounding this becomes 484.
1da177e4
LT
340
341 Thus if you want a PAL compatible display, you have to do the following:
342
343 - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast
f0058b4b
GU
344 timings are to be used.
345 - make sure upper_margin + yres + lower_margin + vsync_len = 625 for an
346 interlaced, 312 for a non-interlaced and 156 for a doublescanned
347 display.
348 - make sure left_margin + xres + right_margin + hsync_len = 1816 for a
349 SHRES, 908 for a HIRES and 454 for a LORES display.
1da177e4 350 - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90),
f0058b4b 351 left_margin + 2 * hsync_len must be greater or equal.
1da177e4 352 - the upper visible part begins at 48 (interlaced; non-interlaced:24,
f0058b4b
GU
353 doublescanned:12), upper_margin + 2 * vsync_len must be greater or
354 equal.
1da177e4 355 - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync
f0058b4b 356 of 4 scanlines
1da177e4
LT
357
358 The settings for a NTSC compatible display are straightforward.
359
360 Note that in a strict sense the PAL and NTSC standards only define the
361 encoding of the color part (chrominance) of the video signal and don't say
362 anything about horizontal/vertical synchronization nor refresh rates.
363
364
f0058b4b 365 -- Geert --
1da177e4
LT
366
367*******************************************************************************/
368
369
370 /*
371 * Custom Chipset Definitions
372 */
373
374#define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld)
375
376 /*
377 * BPLCON0 -- Bitplane Control Register 0
378 */
379
380#define BPC0_HIRES (0x8000)
381#define BPC0_BPU2 (0x4000) /* Bit plane used count */
382#define BPC0_BPU1 (0x2000)
383#define BPC0_BPU0 (0x1000)
384#define BPC0_HAM (0x0800) /* HAM mode */
385#define BPC0_DPF (0x0400) /* Double playfield */
386#define BPC0_COLOR (0x0200) /* Enable colorburst */
387#define BPC0_GAUD (0x0100) /* Genlock audio enable */
388#define BPC0_UHRES (0x0080) /* Ultrahi res enable */
389#define BPC0_SHRES (0x0040) /* Super hi res mode */
390#define BPC0_BYPASS (0x0020) /* Bypass LUT - AGA */
391#define BPC0_BPU3 (0x0010) /* AGA */
392#define BPC0_LPEN (0x0008) /* Light pen enable */
393#define BPC0_LACE (0x0004) /* Interlace */
394#define BPC0_ERSY (0x0002) /* External resync */
395#define BPC0_ECSENA (0x0001) /* ECS enable */
396
397 /*
398 * BPLCON2 -- Bitplane Control Register 2
399 */
400
401#define BPC2_ZDBPSEL2 (0x4000) /* Bitplane to be used for ZD - AGA */
402#define BPC2_ZDBPSEL1 (0x2000)
403#define BPC2_ZDBPSEL0 (0x1000)
404#define BPC2_ZDBPEN (0x0800) /* Enable ZD with ZDBPSELx - AGA */
405#define BPC2_ZDCTEN (0x0400) /* Enable ZD with palette bit #31 - AGA */
406#define BPC2_KILLEHB (0x0200) /* Kill EHB mode - AGA */
407#define BPC2_RDRAM (0x0100) /* Color table accesses read, not write - AGA */
408#define BPC2_SOGEN (0x0080) /* SOG output pin high - AGA */
409#define BPC2_PF2PRI (0x0040) /* PF2 priority over PF1 */
410#define BPC2_PF2P2 (0x0020) /* PF2 priority wrt sprites */
411#define BPC2_PF2P1 (0x0010)
412#define BPC2_PF2P0 (0x0008)
413#define BPC2_PF1P2 (0x0004) /* ditto PF1 */
414#define BPC2_PF1P1 (0x0002)
415#define BPC2_PF1P0 (0x0001)
416
417 /*
418 * BPLCON3 -- Bitplane Control Register 3 (AGA)
419 */
420
421#define BPC3_BANK2 (0x8000) /* Bits to select color register bank */
422#define BPC3_BANK1 (0x4000)
423#define BPC3_BANK0 (0x2000)
424#define BPC3_PF2OF2 (0x1000) /* Bits for color table offset when PF2 */
425#define BPC3_PF2OF1 (0x0800)
426#define BPC3_PF2OF0 (0x0400)
427#define BPC3_LOCT (0x0200) /* Color register writes go to low bits */
428#define BPC3_SPRES1 (0x0080) /* Sprite resolution bits */
429#define BPC3_SPRES0 (0x0040)
430#define BPC3_BRDRBLNK (0x0020) /* Border blanked? */
431#define BPC3_BRDRTRAN (0x0010) /* Border transparent? */
432#define BPC3_ZDCLKEN (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */
433#define BPC3_BRDRSPRT (0x0002) /* Sprites in border? */
434#define BPC3_EXTBLKEN (0x0001) /* BLANK programmable */
435
436 /*
437 * BPLCON4 -- Bitplane Control Register 4 (AGA)
438 */
439
440#define BPC4_BPLAM7 (0x8000) /* bitplane color XOR field */
441#define BPC4_BPLAM6 (0x4000)
442#define BPC4_BPLAM5 (0x2000)
443#define BPC4_BPLAM4 (0x1000)
444#define BPC4_BPLAM3 (0x0800)
445#define BPC4_BPLAM2 (0x0400)
446#define BPC4_BPLAM1 (0x0200)
447#define BPC4_BPLAM0 (0x0100)
448#define BPC4_ESPRM7 (0x0080) /* 4 high bits for even sprite colors */
449#define BPC4_ESPRM6 (0x0040)
450#define BPC4_ESPRM5 (0x0020)
451#define BPC4_ESPRM4 (0x0010)
452#define BPC4_OSPRM7 (0x0008) /* 4 high bits for odd sprite colors */
453#define BPC4_OSPRM6 (0x0004)
454#define BPC4_OSPRM5 (0x0002)
455#define BPC4_OSPRM4 (0x0001)
456
457 /*
458 * BEAMCON0 -- Beam Control Register
459 */
460
461#define BMC0_HARDDIS (0x4000) /* Disable hardware limits */
462#define BMC0_LPENDIS (0x2000) /* Disable light pen latch */
463#define BMC0_VARVBEN (0x1000) /* Enable variable vertical blank */
464#define BMC0_LOLDIS (0x0800) /* Disable long/short line toggle */
465#define BMC0_CSCBEN (0x0400) /* Composite sync/blank */
466#define BMC0_VARVSYEN (0x0200) /* Enable variable vertical sync */
467#define BMC0_VARHSYEN (0x0100) /* Enable variable horizontal sync */
468#define BMC0_VARBEAMEN (0x0080) /* Enable variable beam counters */
469#define BMC0_DUAL (0x0040) /* Enable alternate horizontal beam counter */
470#define BMC0_PAL (0x0020) /* Set decodes for PAL */
471#define BMC0_VARCSYEN (0x0010) /* Enable variable composite sync */
472#define BMC0_BLANKEN (0x0008) /* Blank enable (no longer used on AGA) */
473#define BMC0_CSYTRUE (0x0004) /* CSY polarity */
474#define BMC0_VSYTRUE (0x0002) /* VSY polarity */
475#define BMC0_HSYTRUE (0x0001) /* HSY polarity */
476
477
478 /*
479 * FMODE -- Fetch Mode Control Register (AGA)
480 */
481
482#define FMODE_SSCAN2 (0x8000) /* Sprite scan-doubling */
483#define FMODE_BSCAN2 (0x4000) /* Use PF2 modulus every other line */
484#define FMODE_SPAGEM (0x0008) /* Sprite page mode */
485#define FMODE_SPR32 (0x0004) /* Sprite 32 bit fetch */
486#define FMODE_BPAGEM (0x0002) /* Bitplane page mode */
487#define FMODE_BPL32 (0x0001) /* Bitplane 32 bit fetch */
488
489 /*
490 * Tags used to indicate a specific Pixel Clock
491 *
492 * clk_shift is the shift value to get the timings in 35 ns units
493 */
494
495enum { TAG_SHRES, TAG_HIRES, TAG_LORES };
496
497 /*
498 * Tags used to indicate the specific chipset
499 */
500
501enum { TAG_OCS, TAG_ECS, TAG_AGA };
502
503 /*
504 * Tags used to indicate the memory bandwidth
505 */
506
507enum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 };
508
509
510 /*
511 * Clock Definitions, Maximum Display Depth
512 *
513 * These depend on the E-Clock or the Chipset, so they are filled in
514 * dynamically
515 */
516
517static u_long pixclock[3]; /* SHRES/HIRES/LORES: index = clk_shift */
518static u_short maxdepth[3]; /* SHRES/HIRES/LORES: index = clk_shift */
519static u_short maxfmode, chipset;
520
521
522 /*
523 * Broadcast Video Timings
524 *
525 * Horizontal values are in 35 ns (SHRES) units
526 * Vertical values are in interlaced scanlines
527 */
528
529#define PAL_DIWSTRT_H (360) /* PAL Window Limits */
530#define PAL_DIWSTRT_V (48)
531#define PAL_HTOTAL (1816)
532#define PAL_VTOTAL (625)
533
534#define NTSC_DIWSTRT_H (360) /* NTSC Window Limits */
535#define NTSC_DIWSTRT_V (40)
536#define NTSC_HTOTAL (1816)
537#define NTSC_VTOTAL (525)
538
539
540 /*
541 * Various macros
542 */
543
f0058b4b 544#define up2(v) (((v) + 1) & -2)
1da177e4
LT
545#define down2(v) ((v) & -2)
546#define div2(v) ((v)>>1)
547#define mod2(v) ((v) & 1)
548
f0058b4b 549#define up4(v) (((v) + 3) & -4)
1da177e4 550#define down4(v) ((v) & -4)
f0058b4b 551#define mul4(v) ((v) << 2)
1da177e4
LT
552#define div4(v) ((v)>>2)
553#define mod4(v) ((v) & 3)
554
f0058b4b 555#define up8(v) (((v) + 7) & -8)
1da177e4
LT
556#define down8(v) ((v) & -8)
557#define div8(v) ((v)>>3)
558#define mod8(v) ((v) & 7)
559
f0058b4b 560#define up16(v) (((v) + 15) & -16)
1da177e4
LT
561#define down16(v) ((v) & -16)
562#define div16(v) ((v)>>4)
563#define mod16(v) ((v) & 15)
564
f0058b4b 565#define up32(v) (((v) + 31) & -32)
1da177e4
LT
566#define down32(v) ((v) & -32)
567#define div32(v) ((v)>>5)
568#define mod32(v) ((v) & 31)
569
f0058b4b 570#define up64(v) (((v) + 63) & -64)
1da177e4
LT
571#define down64(v) ((v) & -64)
572#define div64(v) ((v)>>6)
573#define mod64(v) ((v) & 63)
574
f0058b4b
GU
575#define upx(x, v) (((v) + (x) - 1) & -(x))
576#define downx(x, v) ((v) & -(x))
577#define modx(x, v) ((v) & ((x) - 1))
1da177e4
LT
578
579/* if x1 is not a constant, this macro won't make real sense :-) */
580#ifdef __mc68000__
581#define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \
f0058b4b 582 "d" (x2), "d" ((long)((x1) / 0x100000000ULL)), "0" ((long)(x1))); res;})
1da177e4
LT
583#else
584/* We know a bit about the numbers, so we can do it this way */
585#define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \
586 ((((long)((unsigned long long)x1 >> 8) % x2) << 8) / x2))
587#endif
588
589#define highw(x) ((u_long)(x)>>16 & 0xffff)
590#define loww(x) ((u_long)(x) & 0xffff)
591
b4290a23
AV
592#define custom amiga_custom
593
1da177e4
LT
594#define VBlankOn() custom.intena = IF_SETCLR|IF_COPER
595#define VBlankOff() custom.intena = IF_COPER
596
597
598 /*
599 * Chip RAM we reserve for the Frame Buffer
600 *
601 * This defines the Maximum Virtual Screen Size
602 * (Setable per kernel options?)
603 */
604
605#define VIDEOMEMSIZE_AGA_2M (1310720) /* AGA (2MB) : max 1280*1024*256 */
606#define VIDEOMEMSIZE_AGA_1M (786432) /* AGA (1MB) : max 1024*768*256 */
607#define VIDEOMEMSIZE_ECS_2M (655360) /* ECS (2MB) : max 1280*1024*16 */
608#define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */
609#define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */
610
f0058b4b 611#define SPRITEMEMSIZE (64 * 64 / 4) /* max 64*64*4 */
1da177e4
LT
612#define DUMMYSPRITEMEMSIZE (8)
613static u_long spritememory;
614
615#define CHIPRAM_SAFETY_LIMIT (16384)
616
617static u_long videomemory;
618
619 /*
620 * This is the earliest allowed start of fetching display data.
621 * Only if you really want no hardware cursor and audio,
622 * set this to 128, but let it better at 192
623 */
624
625static u_long min_fstrt = 192;
626
627#define assignchunk(name, type, ptr, size) \
628{ \
629 (name) = (type)(ptr); \
630 ptr += size; \
631}
632
633
634 /*
635 * Copper Instructions
636 */
637
f0058b4b
GU
638#define CMOVE(val, reg) (CUSTOM_OFS(reg) << 16 | (val))
639#define CMOVE2(val, reg) ((CUSTOM_OFS(reg) + 2) << 16 | (val))
640#define CWAIT(x, y) (((y) & 0x1fe) << 23 | ((x) & 0x7f0) << 13 | 0x0001fffe)
1da177e4
LT
641#define CEND (0xfffffffe)
642
643
644typedef union {
645 u_long l;
646 u_short w[2];
647} copins;
648
649static struct copdisplay {
650 copins *init;
651 copins *wait;
652 copins *list[2][2];
653 copins *rebuild[2];
654} copdisplay;
655
656static u_short currentcop = 0;
657
658 /*
659 * Hardware Cursor API Definitions
660 * These used to be in linux/fb.h, but were preliminary and used by
661 * amifb only anyway
662 */
663
664#define FBIOGET_FCURSORINFO 0x4607
665#define FBIOGET_VCURSORINFO 0x4608
666#define FBIOPUT_VCURSORINFO 0x4609
667#define FBIOGET_CURSORSTATE 0x460A
668#define FBIOPUT_CURSORSTATE 0x460B
669
670
671struct fb_fix_cursorinfo {
672 __u16 crsr_width; /* width and height of the cursor in */
673 __u16 crsr_height; /* pixels (zero if no cursor) */
674 __u16 crsr_xsize; /* cursor size in display pixels */
675 __u16 crsr_ysize;
676 __u16 crsr_color1; /* colormap entry for cursor color1 */
677 __u16 crsr_color2; /* colormap entry for cursor color2 */
678};
679
680struct fb_var_cursorinfo {
681 __u16 width;
682 __u16 height;
683 __u16 xspot;
684 __u16 yspot;
685 __u8 data[1]; /* field with [height][width] */
686};
687
688struct fb_cursorstate {
689 __s16 xoffset;
690 __s16 yoffset;
691 __u16 mode;
692};
693
694#define FB_CURSOR_OFF 0
695#define FB_CURSOR_ON 1
696#define FB_CURSOR_FLASH 2
697
698
699 /*
700 * Hardware Cursor
701 */
702
703static int cursorrate = 20; /* Number of frames/flash toggle */
704static u_short cursorstate = -1;
705static u_short cursormode = FB_CURSOR_OFF;
706
707static u_short *lofsprite, *shfsprite, *dummysprite;
708
709 /*
710 * Current Video Mode
711 */
712
713static struct amifb_par {
714
715 /* General Values */
716
717 int xres; /* vmode */
718 int yres; /* vmode */
719 int vxres; /* vmode */
720 int vyres; /* vmode */
721 int xoffset; /* vmode */
722 int yoffset; /* vmode */
723 u_short bpp; /* vmode */
724 u_short clk_shift; /* vmode */
725 u_short line_shift; /* vmode */
726 int vmode; /* vmode */
727 u_short diwstrt_h; /* vmode */
728 u_short diwstop_h; /* vmode */
729 u_short diwstrt_v; /* vmode */
730 u_short diwstop_v; /* vmode */
731 u_long next_line; /* modulo for next line */
732 u_long next_plane; /* modulo for next plane */
733
734 /* Cursor Values */
735
736 struct {
737 short crsr_x; /* movecursor */
738 short crsr_y; /* movecursor */
739 short spot_x;
740 short spot_y;
741 u_short height;
742 u_short width;
743 u_short fmode;
744 } crsr;
745
746 /* OCS Hardware Registers */
747
748 u_long bplpt0; /* vmode, pan (Note: physical address) */
749 u_long bplpt0wrap; /* vmode, pan (Note: physical address) */
750 u_short ddfstrt;
751 u_short ddfstop;
752 u_short bpl1mod;
753 u_short bpl2mod;
754 u_short bplcon0; /* vmode */
755 u_short bplcon1; /* vmode */
756 u_short htotal; /* vmode */
757 u_short vtotal; /* vmode */
758
759 /* Additional ECS Hardware Registers */
760
761 u_short bplcon3; /* vmode */
762 u_short beamcon0; /* vmode */
763 u_short hsstrt; /* vmode */
764 u_short hsstop; /* vmode */
765 u_short hbstrt; /* vmode */
766 u_short hbstop; /* vmode */
767 u_short vsstrt; /* vmode */
768 u_short vsstop; /* vmode */
769 u_short vbstrt; /* vmode */
770 u_short vbstop; /* vmode */
771 u_short hcenter; /* vmode */
772
773 /* Additional AGA Hardware Registers */
774
775 u_short fmode; /* vmode */
776} currentpar;
777
778
779static struct fb_info fb_info = {
f0058b4b
GU
780 .fix = {
781 .id = "Amiga ",
782 .visual = FB_VISUAL_PSEUDOCOLOR,
783 .accel = FB_ACCEL_AMIGABLITT
784 }
1da177e4
LT
785};
786
787
788 /*
789 * Saved color entry 0 so we can restore it when unblanking
790 */
791
792static u_char red0, green0, blue0;
793
794
795#if defined(CONFIG_FB_AMIGA_ECS)
796static u_short ecs_palette[32];
797#endif
798
799
800 /*
801 * Latches for Display Changes during VBlank
802 */
803
804static u_short do_vmode_full = 0; /* Change the Video Mode */
805static u_short do_vmode_pan = 0; /* Update the Video Mode */
96de0e25 806static short do_blank = 0; /* (Un)Blank the Screen (±1) */
1da177e4
LT
807static u_short do_cursor = 0; /* Move the Cursor */
808
809
810 /*
811 * Various Flags
812 */
813
814static u_short is_blanked = 0; /* Screen is Blanked */
815static u_short is_lace = 0; /* Screen is laced */
816
817 /*
818 * Predefined Video Modes
819 *
820 */
821
822static struct fb_videomode ami_modedb[] __initdata = {
823
f0058b4b
GU
824 /*
825 * AmigaOS Video Modes
826 *
827 * If you change these, make sure to update DEFMODE_* as well!
828 */
829
830 {
831 /* 640x200, 15 kHz, 60 Hz (NTSC) */
832 "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2,
833 FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
834 }, {
835 /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
836 "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4,
837 FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
838 }, {
839 /* 640x256, 15 kHz, 50 Hz (PAL) */
840 "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2,
841 FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
842 }, {
843 /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
844 "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4,
845 FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
846 }, {
847 /* 640x480, 29 kHz, 57 Hz */
848 "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8,
849 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
850 }, {
851 /* 640x960, 29 kHz, 57 Hz interlaced */
852 "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72,
853 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,
862 10,
863 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
864 }, {
865 /* 640x400, 29 kHz, 68 Hz */
866 "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8,
867 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
868 }, {
869 /* 640x800, 29 kHz, 68 Hz interlaced */
870 "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80,
871 16,
872 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
873 }, {
874 /* 800x300, 23 kHz, 70 Hz */
875 "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7,
876 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
877 }, {
878 /* 800x600, 23 kHz, 70 Hz interlaced */
879 "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80,
880 14,
881 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
882 }, {
883 /* 640x200, 27 kHz, 57 Hz doublescan */
884 "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4,
885 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
886 }, {
887 /* 640x400, 27 kHz, 57 Hz */
888 "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7,
889 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
890 }, {
891 /* 640x800, 27 kHz, 57 Hz interlaced */
892 "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80,
893 14,
894 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
895 }, {
896 /* 640x256, 27 kHz, 47 Hz doublescan */
897 "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4,
898 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
899 }, {
900 /* 640x512, 27 kHz, 47 Hz */
901 "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7,
902 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
903 }, {
904 /* 640x1024, 27 kHz, 47 Hz interlaced */
905 "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80,
906 14,
907 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
908 },
909
910 /*
911 * VGA Video Modes
912 */
913
914 {
915 /* 640x480, 31 kHz, 60 Hz (VGA) */
916 "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2,
917 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
918 }, {
919 /* 640x400, 31 kHz, 70 Hz (VGA) */
920 "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2,
921 FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT,
922 FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
923 },
1da177e4
LT
924
925#if 0
926
f0058b4b
GU
927 /*
928 * A2024 video modes
929 * These modes don't work yet because there's no A2024 driver.
930 */
931
932 {
933 /* 1024x800, 10 Hz */
934 "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,
935 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
936 }, {
937 /* 1024x800, 15 Hz */
938 "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,
939 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
940 }
1da177e4
LT
941#endif
942};
943
944#define NUM_TOTAL_MODES ARRAY_SIZE(ami_modedb)
945
946static char *mode_option __initdata = NULL;
947static int round_down_bpp = 1; /* for mode probing */
948
949 /*
950 * Some default modes
951 */
952
953
954#define DEFMODE_PAL 2 /* "pal" for PAL OCS/ECS */
955#define DEFMODE_NTSC 0 /* "ntsc" for NTSC OCS/ECS */
956#define DEFMODE_AMBER_PAL 3 /* "pal-lace" for flicker fixed PAL (A3000) */
957#define DEFMODE_AMBER_NTSC 1 /* "ntsc-lace" for flicker fixed NTSC (A3000) */
958#define DEFMODE_AGA 19 /* "vga70" for AGA */
959
960
961static int amifb_ilbm = 0; /* interleaved or normal bitplanes */
962static int amifb_inverse = 0;
963
964
965 /*
966 * Macros for the conversion from real world values to hardware register
967 * values
968 *
969 * This helps us to keep our attention on the real stuff...
970 *
971 * Hardware limits for AGA:
972 *
973 * parameter min max step
974 * --------- --- ---- ----
975 * diwstrt_h 0 2047 1
976 * diwstrt_v 0 2047 1
977 * diwstop_h 0 4095 1
978 * diwstop_v 0 4095 1
979 *
980 * ddfstrt 0 2032 16
981 * ddfstop 0 2032 16
982 *
983 * htotal 8 2048 8
984 * hsstrt 0 2040 8
985 * hsstop 0 2040 8
986 * vtotal 1 4096 1
987 * vsstrt 0 4095 1
988 * vsstop 0 4095 1
989 * hcenter 0 2040 8
990 *
991 * hbstrt 0 2047 1
992 * hbstop 0 2047 1
993 * vbstrt 0 4095 1
994 * vbstop 0 4095 1
995 *
996 * Horizontal values are in 35 ns (SHRES) pixels
997 * Vertical values are in half scanlines
998 */
999
1000/* bplcon1 (smooth scrolling) */
1001
1002#define hscroll2hw(hscroll) \
f0058b4b
GU
1003 (((hscroll) << 12 & 0x3000) | ((hscroll) << 8 & 0xc300) | \
1004 ((hscroll) << 4 & 0x0c00) | ((hscroll) << 2 & 0x00f0) | \
1005 ((hscroll)>>2 & 0x000f))
1da177e4
LT
1006
1007/* diwstrt/diwstop/diwhigh (visible display window) */
1008
1009#define diwstrt2hw(diwstrt_h, diwstrt_v) \
f0058b4b 1010 (((diwstrt_v) << 7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
1da177e4 1011#define diwstop2hw(diwstop_h, diwstop_v) \
f0058b4b 1012 (((diwstop_v) << 7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
1da177e4 1013#define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \
f0058b4b 1014 (((diwstop_h) << 3 & 0x2000) | ((diwstop_h) << 11 & 0x1800) | \
1da177e4 1015 ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \
f0058b4b 1016 ((diwstrt_h) << 3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007))
1da177e4
LT
1017
1018/* ddfstrt/ddfstop (display DMA) */
1019
1020#define ddfstrt2hw(ddfstrt) div8(ddfstrt)
1021#define ddfstop2hw(ddfstop) div8(ddfstop)
1022
1023/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */
1024
1025#define hsstrt2hw(hsstrt) (div8(hsstrt))
1026#define hsstop2hw(hsstop) (div8(hsstop))
f0058b4b 1027#define htotal2hw(htotal) (div8(htotal) - 1)
1da177e4
LT
1028#define vsstrt2hw(vsstrt) (div2(vsstrt))
1029#define vsstop2hw(vsstop) (div2(vsstop))
f0058b4b 1030#define vtotal2hw(vtotal) (div2(vtotal) - 1)
1da177e4
LT
1031#define hcenter2hw(htotal) (div8(htotal))
1032
1033/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
1034
f0058b4b
GU
1035#define hbstrt2hw(hbstrt) (((hbstrt) << 8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))
1036#define hbstop2hw(hbstop) (((hbstop) << 8 & 0x0700) | ((hbstop)>>3 & 0x00ff))
1da177e4
LT
1037#define vbstrt2hw(vbstrt) (div2(vbstrt))
1038#define vbstop2hw(vbstop) (div2(vbstop))
1039
1040/* colour */
1041
1042#define rgb2hw8_high(red, green, blue) \
f0058b4b 1043 (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4))
1da177e4 1044#define rgb2hw8_low(red, green, blue) \
f0058b4b 1045 (((red & 0x0f) << 8) | ((green & 0x0f) << 4) | (blue & 0x0f))
1da177e4 1046#define rgb2hw4(red, green, blue) \
f0058b4b 1047 (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4))
1da177e4 1048#define rgb2hw2(red, green, blue) \
f0058b4b 1049 (((red & 0xc0) << 4) | (green & 0xc0) | ((blue & 0xc0)>>4))
1da177e4
LT
1050
1051/* sprpos/sprctl (sprite positioning) */
1052
1053#define spr2hw_pos(start_v, start_h) \
f0058b4b 1054 (((start_v) << 7 & 0xff00) | ((start_h)>>3 & 0x00ff))
1da177e4 1055#define spr2hw_ctl(start_v, start_h, stop_v) \
f0058b4b
GU
1056 (((stop_v) << 7 & 0xff00) | ((start_v)>>4 & 0x0040) | \
1057 ((stop_v)>>5 & 0x0020) | ((start_h) << 3 & 0x0018) | \
1058 ((start_v)>>7 & 0x0004) | ((stop_v)>>8 & 0x0002) | \
1059 ((start_h)>>2 & 0x0001))
1da177e4
LT
1060
1061/* get current vertical position of beam */
1062#define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe))
1063
1064 /*
1065 * Copper Initialisation List
1066 */
1067
f0058b4b 1068#define COPINITSIZE (sizeof(copins) * 40)
1da177e4
LT
1069
1070enum {
1071 cip_bplcon0
1072};
1073
1074 /*
1075 * Long Frame/Short Frame Copper List
1076 * Don't change the order, build_copper()/rebuild_copper() rely on this
1077 */
1078
f0058b4b 1079#define COPLISTSIZE (sizeof(copins) * 64)
1da177e4
LT
1080
1081enum {
1082 cop_wait, cop_bplcon0,
1083 cop_spr0ptrh, cop_spr0ptrl,
1084 cop_diwstrt, cop_diwstop,
1085 cop_diwhigh,
1086};
1087
1088 /*
1089 * Pixel modes for Bitplanes and Sprites
1090 */
1091
1092static u_short bplpixmode[3] = {
1093 BPC0_SHRES, /* 35 ns */
1094 BPC0_HIRES, /* 70 ns */
1095 0 /* 140 ns */
1096};
1097
1098static u_short sprpixmode[3] = {
1099 BPC3_SPRES1 | BPC3_SPRES0, /* 35 ns */
1100 BPC3_SPRES1, /* 70 ns */
1101 BPC3_SPRES0 /* 140 ns */
1102};
1103
1104 /*
1105 * Fetch modes for Bitplanes and Sprites
1106 */
1107
1108static u_short bplfetchmode[3] = {
1109 0, /* 1x */
1110 FMODE_BPL32, /* 2x */
1111 FMODE_BPAGEM | FMODE_BPL32 /* 4x */
1112};
1113
1114static u_short sprfetchmode[3] = {
1115 0, /* 1x */
1116 FMODE_SPR32, /* 2x */
1117 FMODE_SPAGEM | FMODE_SPR32 /* 4x */
1118};
1119
1120
1121 /*
1122 * Interface used by the world
1123 */
1124
1125int amifb_setup(char*);
1126
1127static int amifb_check_var(struct fb_var_screeninfo *var,
1128 struct fb_info *info);
1129static int amifb_set_par(struct fb_info *info);
1130static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green,
1131 unsigned blue, unsigned transp,
1132 struct fb_info *info);
1133static int amifb_blank(int blank, struct fb_info *info);
1134static int amifb_pan_display(struct fb_var_screeninfo *var,
1135 struct fb_info *info);
1136static void amifb_fillrect(struct fb_info *info,
1137 const struct fb_fillrect *rect);
1138static void amifb_copyarea(struct fb_info *info,
1139 const struct fb_copyarea *region);
1140static void amifb_imageblit(struct fb_info *info,
1141 const struct fb_image *image);
67a6680d 1142static int amifb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg);
1da177e4
LT
1143
1144
1145 /*
1146 * Interface to the low level console driver
1147 */
1148
fa6688e1 1149static void amifb_deinit(struct platform_device *pdev);
1da177e4
LT
1150
1151 /*
1152 * Internal routines
1153 */
1154
1155static int flash_cursor(void);
7d12e780 1156static irqreturn_t amifb_interrupt(int irq, void *dev_id);
1da177e4
LT
1157static u_long chipalloc(u_long size);
1158static void chipfree(void);
1159
1160 /*
1161 * Hardware routines
1162 */
1163
1164static int ami_decode_var(struct fb_var_screeninfo *var,
f0058b4b 1165 struct amifb_par *par);
1da177e4 1166static int ami_encode_var(struct fb_var_screeninfo *var,
f0058b4b 1167 struct amifb_par *par);
1da177e4
LT
1168static void ami_pan_var(struct fb_var_screeninfo *var);
1169static int ami_update_par(void);
1170static void ami_update_display(void);
1171static void ami_init_display(void);
1172static void ami_do_blank(void);
1173static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix);
3728d254
AV
1174static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data);
1175static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data);
1da177e4
LT
1176static int ami_get_cursorstate(struct fb_cursorstate *state);
1177static int ami_set_cursorstate(struct fb_cursorstate *state);
1178static void ami_set_sprite(void);
1179static void ami_init_copper(void);
1180static void ami_reinit_copper(void);
1181static void ami_build_copper(void);
1182static void ami_rebuild_copper(void);
1183
1184
1185static struct fb_ops amifb_ops = {
1186 .owner = THIS_MODULE,
1187 .fb_check_var = amifb_check_var,
1188 .fb_set_par = amifb_set_par,
1189 .fb_setcolreg = amifb_setcolreg,
1190 .fb_blank = amifb_blank,
1191 .fb_pan_display = amifb_pan_display,
1192 .fb_fillrect = amifb_fillrect,
1193 .fb_copyarea = amifb_copyarea,
1194 .fb_imageblit = amifb_imageblit,
1da177e4
LT
1195 .fb_ioctl = amifb_ioctl,
1196};
1197
1198static void __init amifb_setup_mcap(char *spec)
1199{
1200 char *p;
1201 int vmin, vmax, hmin, hmax;
1202
1203 /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
1204 * <V*> vertical freq. in Hz
1205 * <H*> horizontal freq. in kHz
1206 */
1207
1208 if (!(p = strsep(&spec, ";")) || !*p)
1209 return;
1210 vmin = simple_strtoul(p, NULL, 10);
1211 if (vmin <= 0)
1212 return;
1213 if (!(p = strsep(&spec, ";")) || !*p)
1214 return;
1215 vmax = simple_strtoul(p, NULL, 10);
1216 if (vmax <= 0 || vmax <= vmin)
1217 return;
1218 if (!(p = strsep(&spec, ";")) || !*p)
1219 return;
1220 hmin = 1000 * simple_strtoul(p, NULL, 10);
1221 if (hmin <= 0)
1222 return;
1223 if (!(p = strsep(&spec, "")) || !*p)
1224 return;
1225 hmax = 1000 * simple_strtoul(p, NULL, 10);
1226 if (hmax <= 0 || hmax <= hmin)
1227 return;
1228
1229 fb_info.monspecs.vfmin = vmin;
1230 fb_info.monspecs.vfmax = vmax;
1231 fb_info.monspecs.hfmin = hmin;
1232 fb_info.monspecs.hfmax = hmax;
1233}
1234
1235int __init amifb_setup(char *options)
1236{
1237 char *this_opt;
1238
1239 if (!options || !*options)
1240 return 0;
1241
1242 while ((this_opt = strsep(&options, ",")) != NULL) {
1243 if (!*this_opt)
1244 continue;
1245 if (!strcmp(this_opt, "inverse")) {
1246 amifb_inverse = 1;
1247 fb_invert_cmaps();
1248 } else if (!strcmp(this_opt, "ilbm"))
1249 amifb_ilbm = 1;
1250 else if (!strncmp(this_opt, "monitorcap:", 11))
f0058b4b 1251 amifb_setup_mcap(this_opt + 11);
1da177e4 1252 else if (!strncmp(this_opt, "fstart:", 7))
f0058b4b 1253 min_fstrt = simple_strtoul(this_opt + 7, NULL, 0);
1da177e4
LT
1254 else
1255 mode_option = this_opt;
1256 }
1257
1258 if (min_fstrt < 48)
1259 min_fstrt = 48;
1260
1261 return 0;
1262}
1263
1264
1265static int amifb_check_var(struct fb_var_screeninfo *var,
1266 struct fb_info *info)
1267{
1268 int err;
1269 struct amifb_par par;
1270
1271 /* Validate wanted screen parameters */
1272 if ((err = ami_decode_var(var, &par)))
1273 return err;
1274
1275 /* Encode (possibly rounded) screen parameters */
1276 ami_encode_var(var, &par);
1277 return 0;
1278}
1279
1280
1281static int amifb_set_par(struct fb_info *info)
1282{
1283 struct amifb_par *par = (struct amifb_par *)info->par;
1284
1285 do_vmode_pan = 0;
1286 do_vmode_full = 0;
1287
1288 /* Decode wanted screen parameters */
1289 ami_decode_var(&info->var, par);
1290
1291 /* Set new videomode */
1292 ami_build_copper();
1293
1294 /* Set VBlank trigger */
1295 do_vmode_full = 1;
1296
1297 /* Update fix for new screen parameters */
1298 if (par->bpp == 1) {
1299 info->fix.type = FB_TYPE_PACKED_PIXELS;
1300 info->fix.type_aux = 0;
1301 } else if (amifb_ilbm) {
1302 info->fix.type = FB_TYPE_INTERLEAVED_PLANES;
1303 info->fix.type_aux = par->next_line;
1304 } else {
1305 info->fix.type = FB_TYPE_PLANES;
1306 info->fix.type_aux = 0;
1307 }
f0058b4b 1308 info->fix.line_length = div8(upx(16 << maxfmode, par->vxres));
1da177e4
LT
1309
1310 if (par->vmode & FB_VMODE_YWRAP) {
1311 info->fix.ywrapstep = 1;
1312 info->fix.xpanstep = 0;
1313 info->fix.ypanstep = 0;
1314 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP |
f0058b4b 1315 FBINFO_READS_FAST; /* override SCROLL_REDRAW */
1da177e4
LT
1316 } else {
1317 info->fix.ywrapstep = 0;
1318 if (par->vmode & FB_VMODE_SMOOTH_XPAN)
1319 info->fix.xpanstep = 1;
1320 else
f0058b4b 1321 info->fix.xpanstep = 16 << maxfmode;
1da177e4
LT
1322 info->fix.ypanstep = 1;
1323 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1324 }
1325 return 0;
1326}
1327
1328
1329 /*
1330 * Pan or Wrap the Display
1331 *
1332 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
1333 */
1334
1335static int amifb_pan_display(struct fb_var_screeninfo *var,
1336 struct fb_info *info)
1337{
1338 if (var->vmode & FB_VMODE_YWRAP) {
1339 if (var->yoffset < 0 ||
f0058b4b
GU
1340 var->yoffset >= info->var.yres_virtual || var->xoffset)
1341 return -EINVAL;
1da177e4
LT
1342 } else {
1343 /*
1344 * TODO: There will be problems when xpan!=1, so some columns
1345 * on the right side will never be seen
1346 */
f0058b4b
GU
1347 if (var->xoffset + info->var.xres >
1348 upx(16 << maxfmode, info->var.xres_virtual) ||
1349 var->yoffset + info->var.yres > info->var.yres_virtual)
1da177e4
LT
1350 return -EINVAL;
1351 }
1352 ami_pan_var(var);
1353 info->var.xoffset = var->xoffset;
1354 info->var.yoffset = var->yoffset;
1355 if (var->vmode & FB_VMODE_YWRAP)
1356 info->var.vmode |= FB_VMODE_YWRAP;
1357 else
1358 info->var.vmode &= ~FB_VMODE_YWRAP;
1359 return 0;
1360}
1361
1362
1363#if BITS_PER_LONG == 32
1364#define BYTES_PER_LONG 4
1365#define SHIFT_PER_LONG 5
1366#elif BITS_PER_LONG == 64
1367#define BYTES_PER_LONG 8
1368#define SHIFT_PER_LONG 6
1369#else
1370#define Please update me
1371#endif
1372
1373
f0058b4b
GU
1374 /*
1375 * Compose two values, using a bitmask as decision value
1376 * This is equivalent to (a & mask) | (b & ~mask)
1377 */
1da177e4
LT
1378
1379static inline unsigned long comp(unsigned long a, unsigned long b,
1380 unsigned long mask)
1381{
1382 return ((a ^ b) & mask) ^ b;
1383}
1384
1385
1386static inline unsigned long xor(unsigned long a, unsigned long b,
1387 unsigned long mask)
1388{
1389 return (a & mask) ^ b;
1390}
1391
1392
f0058b4b
GU
1393 /*
1394 * Unaligned forward bit copy using 32-bit or 64-bit memory accesses
1395 */
1da177e4
LT
1396
1397static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
1398 int src_idx, u32 n)
1399{
1400 unsigned long first, last;
f0058b4b 1401 int shift = dst_idx - src_idx, left, right;
1da177e4
LT
1402 unsigned long d0, d1;
1403 int m;
1404
1405 if (!n)
1406 return;
1407
f0058b4b 1408 shift = dst_idx - src_idx;
1da177e4 1409 first = ~0UL >> dst_idx;
f0058b4b 1410 last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG));
1da177e4
LT
1411
1412 if (!shift) {
1413 // Same alignment for source and dest
1414
f0058b4b 1415 if (dst_idx + n <= BITS_PER_LONG) {
1da177e4
LT
1416 // Single word
1417 if (last)
1418 first &= last;
1419 *dst = comp(*src, *dst, first);
1420 } else {
1421 // Multiple destination words
1422 // Leading bits
1423 if (first) {
1424 *dst = comp(*src, *dst, first);
1425 dst++;
1426 src++;
f0058b4b 1427 n -= BITS_PER_LONG - dst_idx;
1da177e4
LT
1428 }
1429
1430 // Main chunk
1431 n /= BITS_PER_LONG;
1432 while (n >= 8) {
1433 *dst++ = *src++;
1434 *dst++ = *src++;
1435 *dst++ = *src++;
1436 *dst++ = *src++;
1437 *dst++ = *src++;
1438 *dst++ = *src++;
1439 *dst++ = *src++;
1440 *dst++ = *src++;
1441 n -= 8;
1442 }
1443 while (n--)
1444 *dst++ = *src++;
1445
1446 // Trailing bits
1447 if (last)
1448 *dst = comp(*src, *dst, last);
1449 }
1450 } else {
1451 // Different alignment for source and dest
1452
f0058b4b
GU
1453 right = shift & (BITS_PER_LONG - 1);
1454 left = -shift & (BITS_PER_LONG - 1);
1da177e4 1455
f0058b4b 1456 if (dst_idx + n <= BITS_PER_LONG) {
1da177e4
LT
1457 // Single destination word
1458 if (last)
1459 first &= last;
1460 if (shift > 0) {
1461 // Single source word
1462 *dst = comp(*src >> right, *dst, first);
f0058b4b 1463 } else if (src_idx + n <= BITS_PER_LONG) {
1da177e4
LT
1464 // Single source word
1465 *dst = comp(*src << left, *dst, first);
1466 } else {
1467 // 2 source words
1468 d0 = *src++;
1469 d1 = *src;
1470 *dst = comp(d0 << left | d1 >> right, *dst,
1471 first);
1472 }
1473 } else {
1474 // Multiple destination words
1475 d0 = *src++;
1476 // Leading bits
1477 if (shift > 0) {
1478 // Single source word
1479 *dst = comp(d0 >> right, *dst, first);
1480 dst++;
f0058b4b 1481 n -= BITS_PER_LONG - dst_idx;
1da177e4
LT
1482 } else {
1483 // 2 source words
1484 d1 = *src++;
1485 *dst = comp(d0 << left | d1 >> right, *dst,
1486 first);
1487 d0 = d1;
1488 dst++;
f0058b4b 1489 n -= BITS_PER_LONG - dst_idx;
1da177e4
LT
1490 }
1491
1492 // Main chunk
1493 m = n % BITS_PER_LONG;
1494 n /= BITS_PER_LONG;
1495 while (n >= 4) {
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 d1 = *src++;
1503 *dst++ = d0 << left | d1 >> right;
1504 d0 = d1;
1505 d1 = *src++;
1506 *dst++ = d0 << left | d1 >> right;
1507 d0 = d1;
1508 n -= 4;
1509 }
1510 while (n--) {
1511 d1 = *src++;
1512 *dst++ = d0 << left | d1 >> right;
1513 d0 = d1;
1514 }
1515
1516 // Trailing bits
1517 if (last) {
1518 if (m <= right) {
1519 // Single source word
1520 *dst = comp(d0 << left, *dst, last);
1521 } else {
1522 // 2 source words
1523 d1 = *src;
1524 *dst = comp(d0 << left | d1 >> right,
1525 *dst, last);
1526 }
1527 }
1528 }
1529 }
1530}
1531
1532
f0058b4b
GU
1533 /*
1534 * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses
1535 */
1da177e4
LT
1536
1537static void bitcpy_rev(unsigned long *dst, int dst_idx,
1538 const unsigned long *src, int src_idx, u32 n)
1539{
1540 unsigned long first, last;
f0058b4b 1541 int shift = dst_idx - src_idx, left, right;
1da177e4
LT
1542 unsigned long d0, d1;
1543 int m;
1544
1545 if (!n)
1546 return;
1547
f0058b4b
GU
1548 dst += (n - 1) / BITS_PER_LONG;
1549 src += (n - 1) / BITS_PER_LONG;
1550 if ((n - 1) % BITS_PER_LONG) {
1551 dst_idx += (n - 1) % BITS_PER_LONG;
1da177e4 1552 dst += dst_idx >> SHIFT_PER_LONG;
f0058b4b
GU
1553 dst_idx &= BITS_PER_LONG - 1;
1554 src_idx += (n - 1) % BITS_PER_LONG;
1da177e4 1555 src += src_idx >> SHIFT_PER_LONG;
f0058b4b 1556 src_idx &= BITS_PER_LONG - 1;
1da177e4
LT
1557 }
1558
f0058b4b
GU
1559 shift = dst_idx - src_idx;
1560 first = ~0UL << (BITS_PER_LONG - 1 - dst_idx);
1561 last = ~(~0UL << (BITS_PER_LONG - 1 - ((dst_idx - n) % BITS_PER_LONG)));
1da177e4
LT
1562
1563 if (!shift) {
1564 // Same alignment for source and dest
1565
f0058b4b 1566 if ((unsigned long)dst_idx + 1 >= n) {
1da177e4
LT
1567 // Single word
1568 if (last)
1569 first &= last;
1570 *dst = comp(*src, *dst, first);
1571 } else {
1572 // Multiple destination words
1573 // Leading bits
1574 if (first) {
1575 *dst = comp(*src, *dst, first);
1576 dst--;
1577 src--;
f0058b4b 1578 n -= dst_idx + 1;
1da177e4
LT
1579 }
1580
1581 // Main chunk
1582 n /= BITS_PER_LONG;
1583 while (n >= 8) {
1584 *dst-- = *src--;
1585 *dst-- = *src--;
1586 *dst-- = *src--;
1587 *dst-- = *src--;
1588 *dst-- = *src--;
1589 *dst-- = *src--;
1590 *dst-- = *src--;
1591 *dst-- = *src--;
1592 n -= 8;
1593 }
1594 while (n--)
1595 *dst-- = *src--;
1596
1597 // Trailing bits
1598 if (last)
1599 *dst = comp(*src, *dst, last);
1600 }
1601 } else {
1602 // Different alignment for source and dest
1603
f0058b4b
GU
1604 right = shift & (BITS_PER_LONG - 1);
1605 left = -shift & (BITS_PER_LONG - 1);
1da177e4 1606
f0058b4b 1607 if ((unsigned long)dst_idx + 1 >= n) {
1da177e4
LT
1608 // Single destination word
1609 if (last)
1610 first &= last;
1611 if (shift < 0) {
1612 // Single source word
1613 *dst = comp(*src << left, *dst, first);
f0058b4b 1614 } else if (1 + (unsigned long)src_idx >= n) {
1da177e4
LT
1615 // Single source word
1616 *dst = comp(*src >> right, *dst, first);
1617 } else {
1618 // 2 source words
1619 d0 = *src--;
1620 d1 = *src;
1621 *dst = comp(d0 >> right | d1 << left, *dst,
1622 first);
1623 }
1624 } else {
1625 // Multiple destination words
1626 d0 = *src--;
1627 // Leading bits
1628 if (shift < 0) {
1629 // Single source word
1630 *dst = comp(d0 << left, *dst, first);
1631 dst--;
f0058b4b 1632 n -= dst_idx + 1;
1da177e4
LT
1633 } else {
1634 // 2 source words
1635 d1 = *src--;
1636 *dst = comp(d0 >> right | d1 << left, *dst,
1637 first);
1638 d0 = d1;
1639 dst--;
f0058b4b 1640 n -= dst_idx + 1;
1da177e4
LT
1641 }
1642
1643 // Main chunk
1644 m = n % BITS_PER_LONG;
1645 n /= BITS_PER_LONG;
1646 while (n >= 4) {
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 d1 = *src--;
1654 *dst-- = d0 >> right | d1 << left;
1655 d0 = d1;
1656 d1 = *src--;
1657 *dst-- = d0 >> right | d1 << left;
1658 d0 = d1;
1659 n -= 4;
1660 }
1661 while (n--) {
1662 d1 = *src--;
1663 *dst-- = d0 >> right | d1 << left;
1664 d0 = d1;
1665 }
1666
1667 // Trailing bits
1668 if (last) {
1669 if (m <= left) {
1670 // Single source word
1671 *dst = comp(d0 >> right, *dst, last);
1672 } else {
1673 // 2 source words
1674 d1 = *src;
1675 *dst = comp(d0 >> right | d1 << left,
1676 *dst, last);
1677 }
1678 }
1679 }
1680 }
1681}
1682
1683
f0058b4b
GU
1684 /*
1685 * Unaligned forward inverting bit copy using 32-bit or 64-bit memory
1686 * accesses
1687 */
1da177e4
LT
1688
1689static void bitcpy_not(unsigned long *dst, int dst_idx,
1690 const unsigned long *src, int src_idx, u32 n)
1691{
1692 unsigned long first, last;
f0058b4b 1693 int shift = dst_idx - src_idx, left, right;
1da177e4
LT
1694 unsigned long d0, d1;
1695 int m;
1696
1697 if (!n)
1698 return;
1699
f0058b4b 1700 shift = dst_idx - src_idx;
1da177e4 1701 first = ~0UL >> dst_idx;
f0058b4b 1702 last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG));
1da177e4
LT
1703
1704 if (!shift) {
1705 // Same alignment for source and dest
1706
f0058b4b 1707 if (dst_idx + n <= BITS_PER_LONG) {
1da177e4
LT
1708 // Single word
1709 if (last)
1710 first &= last;
1711 *dst = comp(~*src, *dst, first);
1712 } else {
1713 // Multiple destination words
1714 // Leading bits
1715 if (first) {
1716 *dst = comp(~*src, *dst, first);
1717 dst++;
1718 src++;
f0058b4b 1719 n -= BITS_PER_LONG - dst_idx;
1da177e4
LT
1720 }
1721
1722 // Main chunk
1723 n /= BITS_PER_LONG;
1724 while (n >= 8) {
1725 *dst++ = ~*src++;
1726 *dst++ = ~*src++;
1727 *dst++ = ~*src++;
1728 *dst++ = ~*src++;
1729 *dst++ = ~*src++;
1730 *dst++ = ~*src++;
1731 *dst++ = ~*src++;
1732 *dst++ = ~*src++;
1733 n -= 8;
1734 }
1735 while (n--)
1736 *dst++ = ~*src++;
1737
1738 // Trailing bits
1739 if (last)
1740 *dst = comp(~*src, *dst, last);
1741 }
1742 } else {
1743 // Different alignment for source and dest
1744
f0058b4b
GU
1745 right = shift & (BITS_PER_LONG - 1);
1746 left = -shift & (BITS_PER_LONG - 1);
1da177e4 1747
f0058b4b 1748 if (dst_idx + n <= BITS_PER_LONG) {
1da177e4
LT
1749 // Single destination word
1750 if (last)
1751 first &= last;
1752 if (shift > 0) {
1753 // Single source word
1754 *dst = comp(~*src >> right, *dst, first);
f0058b4b 1755 } else if (src_idx + n <= BITS_PER_LONG) {
1da177e4
LT
1756 // Single source word
1757 *dst = comp(~*src << left, *dst, first);
1758 } else {
1759 // 2 source words
1760 d0 = ~*src++;
1761 d1 = ~*src;
1762 *dst = comp(d0 << left | d1 >> right, *dst,
1763 first);
1764 }
1765 } else {
1766 // Multiple destination words
1767 d0 = ~*src++;
1768 // Leading bits
1769 if (shift > 0) {
1770 // Single source word
1771 *dst = comp(d0 >> right, *dst, first);
1772 dst++;
f0058b4b 1773 n -= BITS_PER_LONG - dst_idx;
1da177e4
LT
1774 } else {
1775 // 2 source words
1776 d1 = ~*src++;
1777 *dst = comp(d0 << left | d1 >> right, *dst,
1778 first);
1779 d0 = d1;
1780 dst++;
f0058b4b 1781 n -= BITS_PER_LONG - dst_idx;
1da177e4
LT
1782 }
1783
1784 // Main chunk
1785 m = n % BITS_PER_LONG;
1786 n /= BITS_PER_LONG;
1787 while (n >= 4) {
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 d1 = ~*src++;
1795 *dst++ = d0 << left | d1 >> right;
1796 d0 = d1;
1797 d1 = ~*src++;
1798 *dst++ = d0 << left | d1 >> right;
1799 d0 = d1;
1800 n -= 4;
1801 }
1802 while (n--) {
1803 d1 = ~*src++;
1804 *dst++ = d0 << left | d1 >> right;
1805 d0 = d1;
1806 }
1807
1808 // Trailing bits
1809 if (last) {
1810 if (m <= right) {
1811 // Single source word
1812 *dst = comp(d0 << left, *dst, last);
1813 } else {
1814 // 2 source words
1815 d1 = ~*src;
1816 *dst = comp(d0 << left | d1 >> right,
1817 *dst, last);
1818 }
1819 }
1820 }
1821 }
1822}
1823
1824
f0058b4b
GU
1825 /*
1826 * Unaligned 32-bit pattern fill using 32/64-bit memory accesses
1827 */
1da177e4
LT
1828
1829static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
1830{
1831 unsigned long val = pat;
1832 unsigned long first, last;
1833
1834 if (!n)
1835 return;
1836
1837#if BITS_PER_LONG == 64
1838 val |= val << 32;
1839#endif
1840
1841 first = ~0UL >> dst_idx;
f0058b4b 1842 last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG));
1da177e4 1843
f0058b4b 1844 if (dst_idx + n <= BITS_PER_LONG) {
1da177e4
LT
1845 // Single word
1846 if (last)
1847 first &= last;
1848 *dst = comp(val, *dst, first);
1849 } else {
1850 // Multiple destination words
1851 // Leading bits
1852 if (first) {
1853 *dst = comp(val, *dst, first);
1854 dst++;
f0058b4b 1855 n -= BITS_PER_LONG - dst_idx;
1da177e4
LT
1856 }
1857
1858 // Main chunk
1859 n /= BITS_PER_LONG;
1860 while (n >= 8) {
1861 *dst++ = val;
1862 *dst++ = val;
1863 *dst++ = val;
1864 *dst++ = val;
1865 *dst++ = val;
1866 *dst++ = val;
1867 *dst++ = val;
1868 *dst++ = val;
1869 n -= 8;
1870 }
1871 while (n--)
1872 *dst++ = val;
1873
1874 // Trailing bits
1875 if (last)
1876 *dst = comp(val, *dst, last);
1877 }
1878}
1879
1880
f0058b4b
GU
1881 /*
1882 * Unaligned 32-bit pattern xor using 32/64-bit memory accesses
1883 */
1da177e4
LT
1884
1885static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
1886{
1887 unsigned long val = pat;
1888 unsigned long first, last;
1889
1890 if (!n)
1891 return;
1892
1893#if BITS_PER_LONG == 64
1894 val |= val << 32;
1895#endif
1896
1897 first = ~0UL >> dst_idx;
f0058b4b 1898 last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG));
1da177e4 1899
f0058b4b 1900 if (dst_idx + n <= BITS_PER_LONG) {
1da177e4
LT
1901 // Single word
1902 if (last)
1903 first &= last;
1904 *dst = xor(val, *dst, first);
1905 } else {
1906 // Multiple destination words
1907 // Leading bits
1908 if (first) {
1909 *dst = xor(val, *dst, first);
1910 dst++;
f0058b4b 1911 n -= BITS_PER_LONG - dst_idx;
1da177e4
LT
1912 }
1913
1914 // Main chunk
1915 n /= BITS_PER_LONG;
1916 while (n >= 4) {
1917 *dst++ ^= val;
1918 *dst++ ^= val;
1919 *dst++ ^= val;
1920 *dst++ ^= val;
1921 n -= 4;
1922 }
1923 while (n--)
1924 *dst++ ^= val;
1925
1926 // Trailing bits
1927 if (last)
1928 *dst = xor(val, *dst, last);
1929 }
1930}
1931
1932static inline void fill_one_line(int bpp, unsigned long next_plane,
1933 unsigned long *dst, int dst_idx, u32 n,
1934 u32 color)
1935{
1936 while (1) {
1937 dst += dst_idx >> SHIFT_PER_LONG;
f0058b4b 1938 dst_idx &= (BITS_PER_LONG - 1);
1da177e4
LT
1939 bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n);
1940 if (!--bpp)
1941 break;
1942 color >>= 1;
f0058b4b 1943 dst_idx += next_plane * 8;
1da177e4
LT
1944 }
1945}
1946
1947static inline void xor_one_line(int bpp, unsigned long next_plane,
1948 unsigned long *dst, int dst_idx, u32 n,
1949 u32 color)
1950{
1951 while (color) {
1952 dst += dst_idx >> SHIFT_PER_LONG;
f0058b4b 1953 dst_idx &= (BITS_PER_LONG - 1);
1da177e4
LT
1954 bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n);
1955 if (!--bpp)
1956 break;
1957 color >>= 1;
f0058b4b 1958 dst_idx += next_plane * 8;
1da177e4
LT
1959 }
1960}
1961
1962
1963static void amifb_fillrect(struct fb_info *info,
1964 const struct fb_fillrect *rect)
1965{
1966 struct amifb_par *par = (struct amifb_par *)info->par;
1967 int dst_idx, x2, y2;
1968 unsigned long *dst;
1969 u32 width, height;
1970
1971 if (!rect->width || !rect->height)
1972 return;
1973
1974 /*
1975 * We could use hardware clipping but on many cards you get around
1976 * hardware clipping by writing to framebuffer directly.
1977 * */
1978 x2 = rect->dx + rect->width;
1979 y2 = rect->dy + rect->height;
1980 x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
1981 y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
1982 width = x2 - rect->dx;
1983 height = y2 - rect->dy;
1984
1985 dst = (unsigned long *)
f0058b4b
GU
1986 ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));
1987 dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;
1988 dst_idx += rect->dy * par->next_line * 8 + rect->dx;
1da177e4
LT
1989 while (height--) {
1990 switch (rect->rop) {
f0058b4b 1991 case ROP_COPY:
1da177e4
LT
1992 fill_one_line(info->var.bits_per_pixel,
1993 par->next_plane, dst, dst_idx, width,
1994 rect->color);
1995 break;
1996
f0058b4b 1997 case ROP_XOR:
1da177e4
LT
1998 xor_one_line(info->var.bits_per_pixel, par->next_plane,
1999 dst, dst_idx, width, rect->color);
2000 break;
2001 }
f0058b4b 2002 dst_idx += par->next_line * 8;
1da177e4
LT
2003 }
2004}
2005
2006static inline void copy_one_line(int bpp, unsigned long next_plane,
2007 unsigned long *dst, int dst_idx,
2008 unsigned long *src, int src_idx, u32 n)
2009{
2010 while (1) {
2011 dst += dst_idx >> SHIFT_PER_LONG;
f0058b4b 2012 dst_idx &= (BITS_PER_LONG - 1);
1da177e4 2013 src += src_idx >> SHIFT_PER_LONG;
f0058b4b 2014 src_idx &= (BITS_PER_LONG - 1);
1da177e4
LT
2015 bitcpy(dst, dst_idx, src, src_idx, n);
2016 if (!--bpp)
2017 break;
f0058b4b
GU
2018 dst_idx += next_plane * 8;
2019 src_idx += next_plane * 8;
1da177e4
LT
2020 }
2021}
2022
2023static inline void copy_one_line_rev(int bpp, unsigned long next_plane,
2024 unsigned long *dst, int dst_idx,
2025 unsigned long *src, int src_idx, u32 n)
2026{
2027 while (1) {
2028 dst += dst_idx >> SHIFT_PER_LONG;
f0058b4b 2029 dst_idx &= (BITS_PER_LONG - 1);
1da177e4 2030 src += src_idx >> SHIFT_PER_LONG;
f0058b4b 2031 src_idx &= (BITS_PER_LONG - 1);
1da177e4
LT
2032 bitcpy_rev(dst, dst_idx, src, src_idx, n);
2033 if (!--bpp)
2034 break;
f0058b4b
GU
2035 dst_idx += next_plane * 8;
2036 src_idx += next_plane * 8;
1da177e4
LT
2037 }
2038}
2039
2040
2041static void amifb_copyarea(struct fb_info *info,
2042 const struct fb_copyarea *area)
2043{
2044 struct amifb_par *par = (struct amifb_par *)info->par;
2045 int x2, y2;
2046 u32 dx, dy, sx, sy, width, height;
2047 unsigned long *dst, *src;
2048 int dst_idx, src_idx;
2049 int rev_copy = 0;
2050
2051 /* clip the destination */
2052 x2 = area->dx + area->width;
2053 y2 = area->dy + area->height;
2054 dx = area->dx > 0 ? area->dx : 0;
2055 dy = area->dy > 0 ? area->dy : 0;
2056 x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
2057 y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
2058 width = x2 - dx;
2059 height = y2 - dy;
2060
091c82c0
RK
2061 if (area->sx + dx < area->dx || area->sy + dy < area->dy)
2062 return;
2063
1da177e4
LT
2064 /* update sx,sy */
2065 sx = area->sx + (dx - area->dx);
2066 sy = area->sy + (dy - area->dy);
2067
2068 /* the source must be completely inside the virtual screen */
091c82c0
RK
2069 if (sx + width > info->var.xres_virtual ||
2070 sy + height > info->var.yres_virtual)
1da177e4
LT
2071 return;
2072
2073 if (dy > sy || (dy == sy && dx > sx)) {
2074 dy += height;
2075 sy += height;
2076 rev_copy = 1;
2077 }
2078 dst = (unsigned long *)
f0058b4b 2079 ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));
1da177e4 2080 src = dst;
f0058b4b 2081 dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;
1da177e4 2082 src_idx = dst_idx;
f0058b4b
GU
2083 dst_idx += dy * par->next_line * 8 + dx;
2084 src_idx += sy * par->next_line * 8 + sx;
1da177e4
LT
2085 if (rev_copy) {
2086 while (height--) {
f0058b4b
GU
2087 dst_idx -= par->next_line * 8;
2088 src_idx -= par->next_line * 8;
1da177e4
LT
2089 copy_one_line_rev(info->var.bits_per_pixel,
2090 par->next_plane, dst, dst_idx, src,
2091 src_idx, width);
2092 }
2093 } else {
2094 while (height--) {
2095 copy_one_line(info->var.bits_per_pixel,
2096 par->next_plane, dst, dst_idx, src,
2097 src_idx, width);
f0058b4b
GU
2098 dst_idx += par->next_line * 8;
2099 src_idx += par->next_line * 8;
1da177e4
LT
2100 }
2101 }
2102}
2103
2104
2105static inline void expand_one_line(int bpp, unsigned long next_plane,
2106 unsigned long *dst, int dst_idx, u32 n,
2107 const u8 *data, u32 bgcolor, u32 fgcolor)
2108{
f0058b4b
GU
2109 const unsigned long *src;
2110 int src_idx;
2111
2112 while (1) {
2113 dst += dst_idx >> SHIFT_PER_LONG;
2114 dst_idx &= (BITS_PER_LONG - 1);
2115 if ((bgcolor ^ fgcolor) & 1) {
2116 src = (unsigned long *)
2117 ((unsigned long)data & ~(BYTES_PER_LONG - 1));
2118 src_idx = ((unsigned long)data & (BYTES_PER_LONG - 1)) * 8;
2119 if (fgcolor & 1)
2120 bitcpy(dst, dst_idx, src, src_idx, n);
2121 else
2122 bitcpy_not(dst, dst_idx, src, src_idx, n);
2123 /* set or clear */
2124 } else
2125 bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n);
2126 if (!--bpp)
2127 break;
2128 bgcolor >>= 1;
2129 fgcolor >>= 1;
2130 dst_idx += next_plane * 8;
2131 }
1da177e4
LT
2132}
2133
2134
2135static void amifb_imageblit(struct fb_info *info, const struct fb_image *image)
2136{
2137 struct amifb_par *par = (struct amifb_par *)info->par;
2138 int x2, y2;
2139 unsigned long *dst;
2140 int dst_idx;
2141 const char *src;
2142 u32 dx, dy, width, height, pitch;
2143
2144 /*
2145 * We could use hardware clipping but on many cards you get around
2146 * hardware clipping by writing to framebuffer directly like we are
2147 * doing here.
2148 */
2149 x2 = image->dx + image->width;
2150 y2 = image->dy + image->height;
2151 dx = image->dx;
2152 dy = image->dy;
2153 x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
2154 y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
2155 width = x2 - dx;
2156 height = y2 - dy;
2157
2158 if (image->depth == 1) {
2159 dst = (unsigned long *)
f0058b4b
GU
2160 ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));
2161 dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;
2162 dst_idx += dy * par->next_line * 8 + dx;
1da177e4 2163 src = image->data;
f0058b4b 2164 pitch = (image->width + 7) / 8;
1da177e4
LT
2165 while (height--) {
2166 expand_one_line(info->var.bits_per_pixel,
2167 par->next_plane, dst, dst_idx, width,
2168 src, image->bg_color,
2169 image->fg_color);
f0058b4b 2170 dst_idx += par->next_line * 8;
1da177e4
LT
2171 src += pitch;
2172 }
2173 } else {
2eab7ff8
GU
2174 c2p_planar(info->screen_base, image->data, dx, dy, width,
2175 height, par->next_line, par->next_plane,
2176 image->width, info->var.bits_per_pixel);
1da177e4
LT
2177 }
2178}
2179
2180
2181 /*
2182 * Amiga Frame Buffer Specific ioctls
2183 */
2184
67a6680d
CH
2185static int amifb_ioctl(struct fb_info *info,
2186 unsigned int cmd, unsigned long arg)
1da177e4
LT
2187{
2188 union {
2189 struct fb_fix_cursorinfo fix;
2190 struct fb_var_cursorinfo var;
2191 struct fb_cursorstate state;
2192 } crsr;
3728d254 2193 void __user *argp = (void __user *)arg;
1da177e4
LT
2194 int i;
2195
2196 switch (cmd) {
f0058b4b
GU
2197 case FBIOGET_FCURSORINFO:
2198 i = ami_get_fix_cursorinfo(&crsr.fix);
2199 if (i)
2200 return i;
2201 return copy_to_user(argp, &crsr.fix,
2202 sizeof(crsr.fix)) ? -EFAULT : 0;
2203
2204 case FBIOGET_VCURSORINFO:
2205 i = ami_get_var_cursorinfo(&crsr.var,
2206 ((struct fb_var_cursorinfo __user *)arg)->data);
2207 if (i)
2208 return i;
2209 return copy_to_user(argp, &crsr.var,
2210 sizeof(crsr.var)) ? -EFAULT : 0;
2211
2212 case FBIOPUT_VCURSORINFO:
2213 if (copy_from_user(&crsr.var, argp, sizeof(crsr.var)))
2214 return -EFAULT;
2215 return ami_set_var_cursorinfo(&crsr.var,
2216 ((struct fb_var_cursorinfo __user *)arg)->data);
2217
2218 case FBIOGET_CURSORSTATE:
2219 i = ami_get_cursorstate(&crsr.state);
2220 if (i)
2221 return i;
2222 return copy_to_user(argp, &crsr.state,
2223 sizeof(crsr.state)) ? -EFAULT : 0;
2224
2225 case FBIOPUT_CURSORSTATE:
2226 if (copy_from_user(&crsr.state, argp, sizeof(crsr.state)))
2227 return -EFAULT;
2228 return ami_set_cursorstate(&crsr.state);
1da177e4
LT
2229 }
2230 return -EINVAL;
2231}
2232
2233
2234 /*
2235 * Allocate, Clear and Align a Block of Chip Memory
2236 */
2237
8f25c01d 2238static void *aligned_chipptr;
1da177e4
LT
2239
2240static inline u_long __init chipalloc(u_long size)
2241{
8f25c01d
GU
2242 aligned_chipptr = amiga_chip_alloc(size, "amifb [RAM]");
2243 if (!aligned_chipptr) {
a707642a
GU
2244 pr_err("amifb: No Chip RAM for frame buffer");
2245 return 0;
2246 }
8f25c01d
GU
2247 memset(aligned_chipptr, 0, size);
2248 return (u_long)aligned_chipptr;
1da177e4
LT
2249}
2250
2251static inline void chipfree(void)
2252{
8f25c01d
GU
2253 if (aligned_chipptr)
2254 amiga_chip_free(aligned_chipptr);
1da177e4
LT
2255}
2256
2257
2258 /*
2259 * Initialisation
2260 */
2261
fa6688e1 2262static int __init amifb_probe(struct platform_device *pdev)
1da177e4
LT
2263{
2264 int tag, i, err = 0;
2265 u_long chipptr;
2266 u_int defmode;
2267
2268#ifndef MODULE
2269 char *option = NULL;
2270
2271 if (fb_get_options("amifb", &option)) {
2272 amifb_video_off();
2273 return -ENODEV;
2274 }
2275 amifb_setup(option);
2276#endif
1da177e4
LT
2277 custom.dmacon = DMAF_ALL | DMAF_MASTER;
2278
2279 switch (amiga_chipset) {
2280#ifdef CONFIG_FB_AMIGA_OCS
f0058b4b
GU
2281 case CS_OCS:
2282 strcat(fb_info.fix.id, "OCS");
1da177e4 2283default_chipset:
f0058b4b
GU
2284 chipset = TAG_OCS;
2285 maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */
2286 maxdepth[TAG_HIRES] = 4;
2287 maxdepth[TAG_LORES] = 6;
2288 maxfmode = TAG_FMODE_1;
2289 defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC;
2290 fb_info.fix.smem_len = VIDEOMEMSIZE_OCS;
2291 break;
1da177e4
LT
2292#endif /* CONFIG_FB_AMIGA_OCS */
2293
2294#ifdef CONFIG_FB_AMIGA_ECS
f0058b4b
GU
2295 case CS_ECS:
2296 strcat(fb_info.fix.id, "ECS");
2297 chipset = TAG_ECS;
2298 maxdepth[TAG_SHRES] = 2;
2299 maxdepth[TAG_HIRES] = 4;
2300 maxdepth[TAG_LORES] = 6;
2301 maxfmode = TAG_FMODE_1;
2302 if (AMIGAHW_PRESENT(AMBER_FF))
2303 defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL
2304 : DEFMODE_AMBER_NTSC;
2305 else
2306 defmode = amiga_vblank == 50 ? DEFMODE_PAL
2307 : DEFMODE_NTSC;
2308 if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT >
2309 VIDEOMEMSIZE_ECS_2M)
2310 fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M;
2311 else
2312 fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M;
2313 break;
1da177e4
LT
2314#endif /* CONFIG_FB_AMIGA_ECS */
2315
2316#ifdef CONFIG_FB_AMIGA_AGA
f0058b4b
GU
2317 case CS_AGA:
2318 strcat(fb_info.fix.id, "AGA");
2319 chipset = TAG_AGA;
2320 maxdepth[TAG_SHRES] = 8;
2321 maxdepth[TAG_HIRES] = 8;
2322 maxdepth[TAG_LORES] = 8;
2323 maxfmode = TAG_FMODE_4;
2324 defmode = DEFMODE_AGA;
2325 if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT >
2326 VIDEOMEMSIZE_AGA_2M)
2327 fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M;
2328 else
2329 fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M;
2330 break;
1da177e4
LT
2331#endif /* CONFIG_FB_AMIGA_AGA */
2332
f0058b4b 2333 default:
1da177e4 2334#ifdef CONFIG_FB_AMIGA_OCS
f0058b4b
GU
2335 printk("Unknown graphics chipset, defaulting to OCS\n");
2336 strcat(fb_info.fix.id, "Unknown");
2337 goto default_chipset;
1da177e4 2338#else /* CONFIG_FB_AMIGA_OCS */
f0058b4b
GU
2339 err = -ENODEV;
2340 goto amifb_error;
1da177e4 2341#endif /* CONFIG_FB_AMIGA_OCS */
f0058b4b 2342 break;
1da177e4
LT
2343 }
2344
2345 /*
2346 * Calculate the Pixel Clock Values for this Machine
2347 */
2348
2349 {
2350 u_long tmp = DIVUL(200000000000ULL, amiga_eclock);
2351
2352 pixclock[TAG_SHRES] = (tmp + 4) / 8; /* SHRES: 35 ns / 28 MHz */
2353 pixclock[TAG_HIRES] = (tmp + 2) / 4; /* HIRES: 70 ns / 14 MHz */
2354 pixclock[TAG_LORES] = (tmp + 1) / 2; /* LORES: 140 ns / 7 MHz */
2355 }
2356
2357 /*
2358 * Replace the Tag Values with the Real Pixel Clock Values
2359 */
2360
2361 for (i = 0; i < NUM_TOTAL_MODES; i++) {
2362 struct fb_videomode *mode = &ami_modedb[i];
2363 tag = mode->pixclock;
2364 if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
2365 mode->pixclock = pixclock[tag];
2366 }
2367 }
2368
2369 /*
2370 * These monitor specs are for a typical Amiga monitor (e.g. A1960)
2371 */
2372 if (fb_info.monspecs.hfmin == 0) {
f0058b4b
GU
2373 fb_info.monspecs.hfmin = 15000;
2374 fb_info.monspecs.hfmax = 38000;
2375 fb_info.monspecs.vfmin = 49;
2376 fb_info.monspecs.vfmax = 90;
1da177e4
LT
2377 }
2378
2379 fb_info.fbops = &amifb_ops;
2380 fb_info.par = &currentpar;
2381 fb_info.flags = FBINFO_DEFAULT;
fa6688e1 2382 fb_info.device = &pdev->dev;
1da177e4
LT
2383
2384 if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb,
2385 NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
2386 err = -EINVAL;
2387 goto amifb_error;
2388 }
2389
db3e5289
GU
2390 fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES,
2391 &fb_info.modelist);
2392
1da177e4 2393 round_down_bpp = 0;
f0058b4b
GU
2394 chipptr = chipalloc(fb_info.fix.smem_len + SPRITEMEMSIZE +
2395 DUMMYSPRITEMEMSIZE + COPINITSIZE +
2396 4 * COPLISTSIZE);
a707642a
GU
2397 if (!chipptr) {
2398 err = -ENOMEM;
2399 goto amifb_error;
2400 }
1da177e4
LT
2401
2402 assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len);
2403 assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
2404 assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
2405 assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
2406 assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);
2407 assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);
2408 assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);
2409 assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);
2410
2411 /*
2412 * access the videomem with writethrough cache
2413 */
2414 fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory);
2415 videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start,
2416 fb_info.fix.smem_len);
2417 if (!videomemory) {
2418 printk("amifb: WARNING! unable to map videomem cached writethrough\n");
57354c42
AL
2419 fb_info.screen_base = (char *)ZTWO_VADDR(fb_info.fix.smem_start);
2420 } else
2421 fb_info.screen_base = (char *)videomemory;
1da177e4 2422
1da177e4
LT
2423 memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
2424
2425 /*
2426 * Enable Display DMA
2427 */
2428
2429 custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
f0058b4b 2430 DMAF_BLITTER | DMAF_SPRITE;
1da177e4
LT
2431
2432 /*
2433 * Make sure the Copper has something to do
2434 */
2435
2436 ami_init_copper();
2437
2438 if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,
f0058b4b 2439 "fb vertb handler", &currentpar)) {
1da177e4
LT
2440 err = -EBUSY;
2441 goto amifb_error;
2442 }
2443
f0058b4b 2444 err = fb_alloc_cmap(&fb_info.cmap, 1 << fb_info.var.bits_per_pixel, 0);
eb8972b4
AS
2445 if (err)
2446 goto amifb_error;
1da177e4
LT
2447
2448 if (register_framebuffer(&fb_info) < 0) {
2449 err = -EINVAL;
2450 goto amifb_error;
2451 }
2452
2453 printk("fb%d: %s frame buffer device, using %dK of video memory\n",
2454 fb_info.node, fb_info.fix.id, fb_info.fix.smem_len>>10);
2455
2456 return 0;
2457
2458amifb_error:
fa6688e1 2459 amifb_deinit(pdev);
1da177e4
LT
2460 return err;
2461}
2462
fa6688e1 2463static void amifb_deinit(struct platform_device *pdev)
1da177e4 2464{
eb8972b4
AS
2465 if (fb_info.cmap.len)
2466 fb_dealloc_cmap(&fb_info.cmap);
1da177e4 2467 chipfree();
57354c42 2468 if (videomemory)
f0058b4b 2469 iounmap((void *)videomemory);
1da177e4
LT
2470 custom.dmacon = DMAF_ALL | DMAF_MASTER;
2471}
2472
2473
2474 /*
2475 * Blank the display.
2476 */
2477
2478static int amifb_blank(int blank, struct fb_info *info)
2479{
2480 do_blank = blank ? blank : -1;
2481
2482 return 0;
2483}
2484
2485 /*
2486 * Flash the cursor (called by VBlank interrupt)
2487 */
2488
2489static int flash_cursor(void)
2490{
2491 static int cursorcount = 1;
2492
2493 if (cursormode == FB_CURSOR_FLASH) {
2494 if (!--cursorcount) {
2495 cursorstate = -cursorstate;
2496 cursorcount = cursorrate;
2497 if (!is_blanked)
2498 return 1;
2499 }
2500 }
2501 return 0;
2502}
2503
2504 /*
2505 * VBlank Display Interrupt
2506 */
2507
7d12e780 2508static irqreturn_t amifb_interrupt(int irq, void *dev_id)
1da177e4
LT
2509{
2510 if (do_vmode_pan || do_vmode_full)
2511 ami_update_display();
2512
2513 if (do_vmode_full)
2514 ami_init_display();
2515
2516 if (do_vmode_pan) {
2517 flash_cursor();
2518 ami_rebuild_copper();
2519 do_cursor = do_vmode_pan = 0;
2520 } else if (do_cursor) {
2521 flash_cursor();
2522 ami_set_sprite();
2523 do_cursor = 0;
2524 } else {
2525 if (flash_cursor())
2526 ami_set_sprite();
2527 }
2528
2529 if (do_blank) {
2530 ami_do_blank();
2531 do_blank = 0;
2532 }
2533
2534 if (do_vmode_full) {
2535 ami_reinit_copper();
2536 do_vmode_full = 0;
2537 }
2538 return IRQ_HANDLED;
2539}
2540
2541/* --------------------------- Hardware routines --------------------------- */
2542
2543 /*
2544 * Get the video params out of `var'. If a value doesn't fit, round
2545 * it up, if it's too big, return -EINVAL.
2546 */
2547
2548static int ami_decode_var(struct fb_var_screeninfo *var,
f0058b4b 2549 struct amifb_par *par)
1da177e4
LT
2550{
2551 u_short clk_shift, line_shift;
2552 u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;
2553 u_int htotal, vtotal;
2554
2555 /*
2556 * Find a matching Pixel Clock
2557 */
2558
2559 for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++)
2560 if (var->pixclock <= pixclock[clk_shift])
2561 break;
2562 if (clk_shift > TAG_LORES) {
2563 DPRINTK("pixclock too high\n");
2564 return -EINVAL;
2565 }
2566 par->clk_shift = clk_shift;
2567
2568 /*
2569 * Check the Geometry Values
2570 */
2571
2572 if ((par->xres = var->xres) < 64)
2573 par->xres = 64;
2574 if ((par->yres = var->yres) < 64)
2575 par->yres = 64;
2576 if ((par->vxres = var->xres_virtual) < par->xres)
2577 par->vxres = par->xres;
2578 if ((par->vyres = var->yres_virtual) < par->yres)
2579 par->vyres = par->yres;
2580
2581 par->bpp = var->bits_per_pixel;
2582 if (!var->nonstd) {
2583 if (par->bpp < 1)
2584 par->bpp = 1;
2585 if (par->bpp > maxdepth[clk_shift]) {
2586 if (round_down_bpp && maxdepth[clk_shift])
2587 par->bpp = maxdepth[clk_shift];
2588 else {
2589 DPRINTK("invalid bpp\n");
2590 return -EINVAL;
2591 }
2592 }
2593 } else if (var->nonstd == FB_NONSTD_HAM) {
2594 if (par->bpp < 6)
2595 par->bpp = 6;
2596 if (par->bpp != 6) {
2597 if (par->bpp < 8)
2598 par->bpp = 8;
2599 if (par->bpp != 8 || !IS_AGA) {
2600 DPRINTK("invalid bpp for ham mode\n");
2601 return -EINVAL;
2602 }
2603 }
2604 } else {
2605 DPRINTK("unknown nonstd mode\n");
2606 return -EINVAL;
2607 }
2608
2609 /*
2610 * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
2611 * checks failed and smooth scrolling is not possible
2612 */
2613
2614 par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN;
2615 switch (par->vmode & FB_VMODE_MASK) {
f0058b4b
GU
2616 case FB_VMODE_INTERLACED:
2617 line_shift = 0;
2618 break;
2619 case FB_VMODE_NONINTERLACED:
2620 line_shift = 1;
2621 break;
2622 case FB_VMODE_DOUBLE:
2623 if (!IS_AGA) {
2624 DPRINTK("double mode only possible with aga\n");
1da177e4 2625 return -EINVAL;
f0058b4b
GU
2626 }
2627 line_shift = 2;
2628 break;
2629 default:
2630 DPRINTK("unknown video mode\n");
2631 return -EINVAL;
2632 break;
1da177e4
LT
2633 }
2634 par->line_shift = line_shift;
2635
2636 /*
2637 * Vertical and Horizontal Timings
2638 */
2639
f0058b4b
GU
2640 xres_n = par->xres << clk_shift;
2641 yres_n = par->yres << line_shift;
2642 par->htotal = down8((var->left_margin + par->xres + var->right_margin +
2643 var->hsync_len) << clk_shift);
2644 par->vtotal =
2645 down2(((var->upper_margin + par->yres + var->lower_margin +
2646 var->vsync_len) << line_shift) + 1);
1da177e4
LT
2647
2648 if (IS_AGA)
2649 par->bplcon3 = sprpixmode[clk_shift];
2650 else
2651 par->bplcon3 = 0;
2652 if (var->sync & FB_SYNC_BROADCAST) {
f0058b4b
GU
2653 par->diwstop_h = par->htotal -
2654 ((var->right_margin - var->hsync_len) << clk_shift);
1da177e4
LT
2655 if (IS_AGA)
2656 par->diwstop_h += mod4(var->hsync_len);
2657 else
2658 par->diwstop_h = down4(par->diwstop_h);
2659
2660 par->diwstrt_h = par->diwstop_h - xres_n;
f0058b4b
GU
2661 par->diwstop_v = par->vtotal -
2662 ((var->lower_margin - var->vsync_len) << line_shift);
1da177e4 2663 par->diwstrt_v = par->diwstop_v - yres_n;
f0058b4b 2664 if (par->diwstop_h >= par->htotal + 8) {
1da177e4
LT
2665 DPRINTK("invalid diwstop_h\n");
2666 return -EINVAL;
2667 }
2668 if (par->diwstop_v > par->vtotal) {
2669 DPRINTK("invalid diwstop_v\n");
2670 return -EINVAL;
2671 }
2672
2673 if (!IS_OCS) {
2674 /* Initialize sync with some reasonable values for pwrsave */
2675 par->hsstrt = 160;
2676 par->hsstop = 320;
2677 par->vsstrt = 30;
2678 par->vsstop = 34;
2679 } else {
2680 par->hsstrt = 0;
2681 par->hsstop = 0;
2682 par->vsstrt = 0;
2683 par->vsstop = 0;
2684 }
f0058b4b 2685 if (par->vtotal > (PAL_VTOTAL + NTSC_VTOTAL) / 2) {
1da177e4
LT
2686 /* PAL video mode */
2687 if (par->htotal != PAL_HTOTAL) {
2688 DPRINTK("htotal invalid for pal\n");
2689 return -EINVAL;
2690 }
2691 if (par->diwstrt_h < PAL_DIWSTRT_H) {
2692 DPRINTK("diwstrt_h too low for pal\n");
2693 return -EINVAL;
2694 }
2695 if (par->diwstrt_v < PAL_DIWSTRT_V) {
2696 DPRINTK("diwstrt_v too low for pal\n");
2697 return -EINVAL;
2698 }
2699 htotal = PAL_HTOTAL>>clk_shift;
2700 vtotal = PAL_VTOTAL>>1;
2701 if (!IS_OCS) {
2702 par->beamcon0 = BMC0_PAL;
2703 par->bplcon3 |= BPC3_BRDRBLNK;
2704 } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
f0058b4b 2705 AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
1da177e4
LT
2706 par->beamcon0 = BMC0_PAL;
2707 par->hsstop = 1;
2708 } else if (amiga_vblank != 50) {
2709 DPRINTK("pal not supported by this chipset\n");
2710 return -EINVAL;
2711 }
2712 } else {
2713 /* NTSC video mode
2714 * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK
2715 * and NTSC activated, so than better let diwstop_h <= 1812
2716 */
2717 if (par->htotal != NTSC_HTOTAL) {
2718 DPRINTK("htotal invalid for ntsc\n");
2719 return -EINVAL;
2720 }
2721 if (par->diwstrt_h < NTSC_DIWSTRT_H) {
2722 DPRINTK("diwstrt_h too low for ntsc\n");
2723 return -EINVAL;
2724 }
2725 if (par->diwstrt_v < NTSC_DIWSTRT_V) {
2726 DPRINTK("diwstrt_v too low for ntsc\n");
2727 return -EINVAL;
2728 }
2729 htotal = NTSC_HTOTAL>>clk_shift;
2730 vtotal = NTSC_VTOTAL>>1;
2731 if (!IS_OCS) {
2732 par->beamcon0 = 0;
2733 par->bplcon3 |= BPC3_BRDRBLNK;
2734 } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
f0058b4b 2735 AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
1da177e4
LT
2736 par->beamcon0 = 0;
2737 par->hsstop = 1;
2738 } else if (amiga_vblank != 60) {
2739 DPRINTK("ntsc not supported by this chipset\n");
2740 return -EINVAL;
2741 }
2742 }
2743 if (IS_OCS) {
2744 if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 ||
2745 par->diwstrt_v >= 512 || par->diwstop_v < 256) {
2746 DPRINTK("invalid position for display on ocs\n");
2747 return -EINVAL;
2748 }
2749 }
2750 } else if (!IS_OCS) {
2751 /* Programmable video mode */
f0058b4b
GU
2752 par->hsstrt = var->right_margin << clk_shift;
2753 par->hsstop = (var->right_margin + var->hsync_len) << clk_shift;
1da177e4
LT
2754 par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift);
2755 if (!IS_AGA)
2756 par->diwstop_h = down4(par->diwstop_h) - 16;
2757 par->diwstrt_h = par->diwstop_h - xres_n;
2758 par->hbstop = par->diwstrt_h + 4;
2759 par->hbstrt = par->diwstop_h + 4;
2760 if (par->hbstrt >= par->htotal + 8)
2761 par->hbstrt -= par->htotal;
2762 par->hcenter = par->hsstrt + (par->htotal >> 1);
f0058b4b
GU
2763 par->vsstrt = var->lower_margin << line_shift;
2764 par->vsstop = (var->lower_margin + var->vsync_len) << line_shift;
1da177e4
LT
2765 par->diwstop_v = par->vtotal;
2766 if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
2767 par->diwstop_v -= 2;
2768 par->diwstrt_v = par->diwstop_v - yres_n;
2769 par->vbstop = par->diwstrt_v - 2;
2770 par->vbstrt = par->diwstop_v - 2;
2771 if (par->vtotal > 2048) {
2772 DPRINTK("vtotal too high\n");
2773 return -EINVAL;
2774 }
2775 if (par->htotal > 2048) {
2776 DPRINTK("htotal too high\n");
2777 return -EINVAL;
2778 }
2779 par->bplcon3 |= BPC3_EXTBLKEN;
2780 par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
f0058b4b
GU
2781 BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
2782 BMC0_PAL | BMC0_VARCSYEN;
1da177e4
LT
2783 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
2784 par->beamcon0 |= BMC0_HSYTRUE;
2785 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
2786 par->beamcon0 |= BMC0_VSYTRUE;
2787 if (var->sync & FB_SYNC_COMP_HIGH_ACT)
2788 par->beamcon0 |= BMC0_CSYTRUE;
2789 htotal = par->htotal>>clk_shift;
2790 vtotal = par->vtotal>>1;
2791 } else {
2792 DPRINTK("only broadcast modes possible for ocs\n");
2793 return -EINVAL;
2794 }
2795
2796 /*
2797 * Checking the DMA timing
2798 */
2799
f0058b4b 2800 fconst = 16 << maxfmode << clk_shift;
1da177e4
LT
2801
2802 /*
2803 * smallest window start value without turn off other dma cycles
2804 * than sprite1-7, unless you change min_fstrt
2805 */
2806
2807
f0058b4b
GU
2808 fsize = ((maxfmode + clk_shift <= 1) ? fconst : 64);
2809 fstrt = downx(fconst, par->diwstrt_h - 4) - fsize;
1da177e4
LT
2810 if (fstrt < min_fstrt) {
2811 DPRINTK("fetch start too low\n");
2812 return -EINVAL;
2813 }
2814
2815 /*
2816 * smallest window start value where smooth scrolling is possible
2817 */
2818
f0058b4b
GU
2819 fstrt = downx(fconst, par->diwstrt_h - fconst + (1 << clk_shift) - 4) -
2820 fsize;
1da177e4
LT
2821 if (fstrt < min_fstrt)
2822 par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2823
2824 maxfetchstop = down16(par->htotal - 80);
2825
f0058b4b
GU
2826 fstrt = downx(fconst, par->diwstrt_h - 4) - 64 - fconst;
2827 fsize = upx(fconst, xres_n +
2828 modx(fconst, downx(1 << clk_shift, par->diwstrt_h - 4)));
1da177e4
LT
2829 if (fstrt + fsize > maxfetchstop)
2830 par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2831
2832 fsize = upx(fconst, xres_n);
2833 if (fstrt + fsize > maxfetchstop) {
2834 DPRINTK("fetch stop too high\n");
2835 return -EINVAL;
2836 }
2837
2838 if (maxfmode + clk_shift <= 1) {
2839 fsize = up64(xres_n + fconst - 1);
2840 if (min_fstrt + fsize - 64 > maxfetchstop)
2841 par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
2842
2843 fsize = up64(xres_n);
2844 if (min_fstrt + fsize - 64 > maxfetchstop) {
2845 DPRINTK("fetch size too high\n");
2846 return -EINVAL;
2847 }
2848
2849 fsize -= 64;
2850 } else
2851 fsize -= fconst;
2852
2853 /*
2854 * Check if there is enough time to update the bitplane pointers for ywrap
2855 */
2856
f0058b4b 2857 if (par->htotal - fsize - 64 < par->bpp * 64)
1da177e4
LT
2858 par->vmode &= ~FB_VMODE_YWRAP;
2859
2860 /*
2861 * Bitplane calculations and check the Memory Requirements
2862 */
2863
2864 if (amifb_ilbm) {
f0058b4b
GU
2865 par->next_plane = div8(upx(16 << maxfmode, par->vxres));
2866 par->next_line = par->bpp * par->next_plane;
1da177e4
LT
2867 if (par->next_line * par->vyres > fb_info.fix.smem_len) {
2868 DPRINTK("too few video mem\n");
2869 return -EINVAL;
2870 }
2871 } else {
f0058b4b
GU
2872 par->next_line = div8(upx(16 << maxfmode, par->vxres));
2873 par->next_plane = par->vyres * par->next_line;
1da177e4
LT
2874 if (par->next_plane * par->bpp > fb_info.fix.smem_len) {
2875 DPRINTK("too few video mem\n");
2876 return -EINVAL;
2877 }
2878 }
2879
2880 /*
2881 * Hardware Register Values
2882 */
2883
2884 par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift];
2885 if (!IS_OCS)
2886 par->bplcon0 |= BPC0_ECSENA;
2887 if (par->bpp == 8)
2888 par->bplcon0 |= BPC0_BPU3;
2889 else
f0058b4b 2890 par->bplcon0 |= par->bpp << 12;
1da177e4
LT
2891 if (var->nonstd == FB_NONSTD_HAM)
2892 par->bplcon0 |= BPC0_HAM;
2893 if (var->sync & FB_SYNC_EXT)
2894 par->bplcon0 |= BPC0_ERSY;
2895
2896 if (IS_AGA)
2897 par->fmode = bplfetchmode[maxfmode];
2898
2899 switch (par->vmode & FB_VMODE_MASK) {
f0058b4b
GU
2900 case FB_VMODE_INTERLACED:
2901 par->bplcon0 |= BPC0_LACE;
2902 break;
2903 case FB_VMODE_DOUBLE:
2904 if (IS_AGA)
2905 par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
2906 break;
1da177e4
LT
2907 }
2908
2909 if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {
2910 par->xoffset = var->xoffset;
2911 par->yoffset = var->yoffset;
2912 if (par->vmode & FB_VMODE_YWRAP) {
f0058b4b
GU
2913 if (par->xoffset || par->yoffset < 0 ||
2914 par->yoffset >= par->vyres)
1da177e4
LT
2915 par->xoffset = par->yoffset = 0;
2916 } else {
f0058b4b
GU
2917 if (par->xoffset < 0 ||
2918 par->xoffset > upx(16 << maxfmode, par->vxres - par->xres) ||
2919 par->yoffset < 0 || par->yoffset > par->vyres - par->yres)
1da177e4
LT
2920 par->xoffset = par->yoffset = 0;
2921 }
2922 } else
2923 par->xoffset = par->yoffset = 0;
2924
2925 par->crsr.crsr_x = par->crsr.crsr_y = 0;
2926 par->crsr.spot_x = par->crsr.spot_y = 0;
2927 par->crsr.height = par->crsr.width = 0;
2928
1da177e4
LT
2929 return 0;
2930}
2931
2932 /*
2933 * Fill the `var' structure based on the values in `par' and maybe
2934 * other values read out of the hardware.
2935 */
2936
2937static int ami_encode_var(struct fb_var_screeninfo *var,
f0058b4b 2938 struct amifb_par *par)
1da177e4
LT
2939{
2940 u_short clk_shift, line_shift;
2941
2942 memset(var, 0, sizeof(struct fb_var_screeninfo));
2943
2944 clk_shift = par->clk_shift;
2945 line_shift = par->line_shift;
2946
2947 var->xres = par->xres;
2948 var->yres = par->yres;
2949 var->xres_virtual = par->vxres;
2950 var->yres_virtual = par->vyres;
2951 var->xoffset = par->xoffset;
2952 var->yoffset = par->yoffset;
2953
2954 var->bits_per_pixel = par->bpp;
2955 var->grayscale = 0;
2956
2957 var->red.offset = 0;
2958 var->red.msb_right = 0;
2959 var->red.length = par->bpp;
2960 if (par->bplcon0 & BPC0_HAM)
f0058b4b 2961 var->red.length -= 2;
1da177e4
LT
2962 var->blue = var->green = var->red;
2963 var->transp.offset = 0;
2964 var->transp.length = 0;
2965 var->transp.msb_right = 0;
2966
2967 if (par->bplcon0 & BPC0_HAM)
2968 var->nonstd = FB_NONSTD_HAM;
2969 else
2970 var->nonstd = 0;
2971 var->activate = 0;
2972
2973 var->height = -1;
2974 var->width = -1;
2975
2976 var->pixclock = pixclock[clk_shift];
2977
2978 if (IS_AGA && par->fmode & FMODE_BSCAN2)
2979 var->vmode = FB_VMODE_DOUBLE;
2980 else if (par->bplcon0 & BPC0_LACE)
2981 var->vmode = FB_VMODE_INTERLACED;
2982 else
2983 var->vmode = FB_VMODE_NONINTERLACED;
2984
2985 if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) {
f0058b4b 2986 var->hsync_len = (par->hsstop - par->hsstrt)>>clk_shift;
1da177e4
LT
2987 var->right_margin = par->hsstrt>>clk_shift;
2988 var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
f0058b4b 2989 var->vsync_len = (par->vsstop - par->vsstrt)>>line_shift;
1da177e4
LT
2990 var->lower_margin = par->vsstrt>>line_shift;
2991 var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len;
2992 var->sync = 0;
2993 if (par->beamcon0 & BMC0_HSYTRUE)
2994 var->sync |= FB_SYNC_HOR_HIGH_ACT;
2995 if (par->beamcon0 & BMC0_VSYTRUE)
2996 var->sync |= FB_SYNC_VERT_HIGH_ACT;
2997 if (par->beamcon0 & BMC0_CSYTRUE)
2998 var->sync |= FB_SYNC_COMP_HIGH_ACT;
2999 } else {
3000 var->sync = FB_SYNC_BROADCAST;
3001 var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h);
3002 var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len;
3003 var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
3004 var->vsync_len = 4>>line_shift;
3005 var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len;
3006 var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres -
f0058b4b 3007 var->lower_margin - var->vsync_len;
1da177e4
LT
3008 }
3009
3010 if (par->bplcon0 & BPC0_ERSY)
3011 var->sync |= FB_SYNC_EXT;
3012 if (par->vmode & FB_VMODE_YWRAP)
3013 var->vmode |= FB_VMODE_YWRAP;
3014
3015 return 0;
3016}
3017
3018
3019 /*
3020 * Pan or Wrap the Display
3021 *
3022 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
3023 * in `var'.
3024 */
3025
3026static void ami_pan_var(struct fb_var_screeninfo *var)
3027{
3028 struct amifb_par *par = &currentpar;
3029
3030 par->xoffset = var->xoffset;
3031 par->yoffset = var->yoffset;
3032 if (var->vmode & FB_VMODE_YWRAP)
3033 par->vmode |= FB_VMODE_YWRAP;
3034 else
3035 par->vmode &= ~FB_VMODE_YWRAP;
3036
3037 do_vmode_pan = 0;
3038 ami_update_par();
3039 do_vmode_pan = 1;
3040}
3041
3042 /*
3043 * Update hardware
3044 */
3045
3046static int ami_update_par(void)
3047{
3048 struct amifb_par *par = &currentpar;
3049 short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod;
3050
3051 clk_shift = par->clk_shift;
3052
3053 if (!(par->vmode & FB_VMODE_SMOOTH_XPAN))
f0058b4b 3054 par->xoffset = upx(16 << maxfmode, par->xoffset);
1da177e4 3055
f0058b4b
GU
3056 fconst = 16 << maxfmode << clk_shift;
3057 vshift = modx(16 << maxfmode, par->xoffset);
3058 fstrt = par->diwstrt_h - (vshift << clk_shift) - 4;
3059 fsize = (par->xres + vshift) << clk_shift;
1da177e4 3060 shift = modx(fconst, fstrt);
f0058b4b 3061 move = downx(2 << maxfmode, div8(par->xoffset));
1da177e4
LT
3062 if (maxfmode + clk_shift > 1) {
3063 fstrt = downx(fconst, fstrt) - 64;
3064 fsize = upx(fconst, fsize);
3065 fstop = fstrt + fsize - fconst;
3066 } else {
3067 mod = fstrt = downx(fconst, fstrt) - fconst;
3068 fstop = fstrt + upx(fconst, fsize) - 64;
3069 fsize = up64(fsize);
3070 fstrt = fstop - fsize + 64;
3071 if (fstrt < min_fstrt) {
3072 fstop += min_fstrt - fstrt;
3073 fstrt = min_fstrt;
3074 }
f0058b4b 3075 move = move - div8((mod - fstrt)>>clk_shift);
1da177e4
LT
3076 }
3077 mod = par->next_line - div8(fsize>>clk_shift);
3078 par->ddfstrt = fstrt;
3079 par->ddfstop = fstop;
3080 par->bplcon1 = hscroll2hw(shift);
3081 par->bpl2mod = mod;
3082 if (par->bplcon0 & BPC0_LACE)
3083 par->bpl2mod += par->next_line;
3084 if (IS_AGA && (par->fmode & FMODE_BSCAN2))
3085 par->bpl1mod = -div8(fsize>>clk_shift);
3086 else
3087 par->bpl1mod = par->bpl2mod;
3088
3089 if (par->yoffset) {
f0058b4b
GU
3090 par->bplpt0 = fb_info.fix.smem_start +
3091 par->next_line * par->yoffset + move;
1da177e4 3092 if (par->vmode & FB_VMODE_YWRAP) {
f0058b4b 3093 if (par->yoffset > par->vyres - par->yres) {
1da177e4 3094 par->bplpt0wrap = fb_info.fix.smem_start + move;
f0058b4b
GU
3095 if (par->bplcon0 & BPC0_LACE &&
3096 mod2(par->diwstrt_v + par->vyres -
3097 par->yoffset))
1da177e4
LT
3098 par->bplpt0wrap += par->next_line;
3099 }
3100 }
3101 } else
3102 par->bplpt0 = fb_info.fix.smem_start + move;
3103
3104 if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
3105 par->bplpt0 += par->next_line;
3106
3107 return 0;
3108}
3109
3110
3111 /*
3112 * Set a single color register. The values supplied are already
3113 * rounded down to the hardware's capabilities (according to the
3114 * entries in the var structure). Return != 0 for invalid regno.
3115 */
3116
3117static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
f0058b4b 3118 u_int transp, struct fb_info *info)
1da177e4
LT
3119{
3120 if (IS_AGA) {
3121 if (regno > 255)
3122 return 1;
3123 } else if (currentpar.bplcon0 & BPC0_SHRES) {
3124 if (regno > 3)
3125 return 1;
3126 } else {
3127 if (regno > 31)
3128 return 1;
3129 }
3130 red >>= 8;
3131 green >>= 8;
3132 blue >>= 8;
3133 if (!regno) {
3134 red0 = red;
3135 green0 = green;
3136 blue0 = blue;
3137 }
3138
3139 /*
3140 * Update the corresponding Hardware Color Register, unless it's Color
3141 * Register 0 and the screen is blanked.
3142 *
3143 * VBlank is switched off to protect bplcon3 or ecs_palette[] from
3144 * being changed by ami_do_blank() during the VBlank.
3145 */
3146
3147 if (regno || !is_blanked) {
3148#if defined(CONFIG_FB_AMIGA_AGA)
3149 if (IS_AGA) {
3150 u_short bplcon3 = currentpar.bplcon3;
3151 VBlankOff();
f0058b4b
GU
3152 custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000);
3153 custom.color[regno & 31] = rgb2hw8_high(red, green,
3154 blue);
3155 custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000) |
3156 BPC3_LOCT;
3157 custom.color[regno & 31] = rgb2hw8_low(red, green,
3158 blue);
1da177e4
LT
3159 custom.bplcon3 = bplcon3;
3160 VBlankOn();
3161 } else
3162#endif
3163#if defined(CONFIG_FB_AMIGA_ECS)
3164 if (currentpar.bplcon0 & BPC0_SHRES) {
3165 u_short color, mask;
3166 int i;
3167
3168 mask = 0x3333;
3169 color = rgb2hw2(red, green, blue);
3170 VBlankOff();
f0058b4b 3171 for (i = regno + 12; i >= (int)regno; i -= 4)
1da177e4 3172 custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
f0058b4b
GU
3173 mask <<= 2; color >>= 2;
3174 regno = down16(regno) + mul4(mod4(regno));
3175 for (i = regno + 3; i >= (int)regno; i--)
1da177e4
LT
3176 custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3177 VBlankOn();
3178 } else
3179#endif
3180 custom.color[regno] = rgb2hw4(red, green, blue);
3181 }
3182 return 0;
3183}
3184
3185static void ami_update_display(void)
3186{
3187 struct amifb_par *par = &currentpar;
3188
3189 custom.bplcon1 = par->bplcon1;
3190 custom.bpl1mod = par->bpl1mod;
3191 custom.bpl2mod = par->bpl2mod;
3192 custom.ddfstrt = ddfstrt2hw(par->ddfstrt);
3193 custom.ddfstop = ddfstop2hw(par->ddfstop);
3194}
3195
3196 /*
3197 * Change the video mode (called by VBlank interrupt)
3198 */
3199
3200static void ami_init_display(void)
3201{
3202 struct amifb_par *par = &currentpar;
3203 int i;
3204
3205 custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
3206 custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
3207 if (!IS_OCS) {
3208 custom.bplcon3 = par->bplcon3;
3209 if (IS_AGA)
3210 custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
3211 if (par->beamcon0 & BMC0_VARBEAMEN) {
3212 custom.htotal = htotal2hw(par->htotal);
3213 custom.hbstrt = hbstrt2hw(par->hbstrt);
3214 custom.hbstop = hbstop2hw(par->hbstop);
3215 custom.hsstrt = hsstrt2hw(par->hsstrt);
3216 custom.hsstop = hsstop2hw(par->hsstop);
3217 custom.hcenter = hcenter2hw(par->hcenter);
3218 custom.vtotal = vtotal2hw(par->vtotal);
3219 custom.vbstrt = vbstrt2hw(par->vbstrt);
3220 custom.vbstop = vbstop2hw(par->vbstop);
3221 custom.vsstrt = vsstrt2hw(par->vsstrt);
3222 custom.vsstop = vsstop2hw(par->vsstop);
3223 }
3224 }
3225 if (!IS_OCS || par->hsstop)
3226 custom.beamcon0 = par->beamcon0;
3227 if (IS_AGA)
3228 custom.fmode = par->fmode;
3229
3230 /*
3231 * The minimum period for audio depends on htotal
3232 */
3233
3234 amiga_audio_min_period = div16(par->htotal);
3235
3236 is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
3237#if 1
3238 if (is_lace) {
3239 i = custom.vposr >> 15;
3240 } else {
3241 custom.vposw = custom.vposr | 0x8000;
3242 i = 1;
3243 }
3244#else
3245 i = 1;
3246 custom.vposw = custom.vposr | 0x8000;
3247#endif
3248 custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]);
3249}
3250
3251 /*
3252 * (Un)Blank the screen (called by VBlank interrupt)
3253 */
3254
3255static void ami_do_blank(void)
3256{
3257 struct amifb_par *par = &currentpar;
3258#if defined(CONFIG_FB_AMIGA_AGA)
3259 u_short bplcon3 = par->bplcon3;
3260#endif
3261 u_char red, green, blue;
3262
3263 if (do_blank > 0) {
3264 custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
3265 red = green = blue = 0;
3266 if (!IS_OCS && do_blank > 1) {
3267 switch (do_blank) {
f0058b4b
GU
3268 case FB_BLANK_VSYNC_SUSPEND:
3269 custom.hsstrt = hsstrt2hw(par->hsstrt);
3270 custom.hsstop = hsstop2hw(par->hsstop);
3271 custom.vsstrt = vsstrt2hw(par->vtotal + 4);
3272 custom.vsstop = vsstop2hw(par->vtotal + 4);
3273 break;
3274 case FB_BLANK_HSYNC_SUSPEND:
3275 custom.hsstrt = hsstrt2hw(par->htotal + 16);
3276 custom.hsstop = hsstop2hw(par->htotal + 16);
3277 custom.vsstrt = vsstrt2hw(par->vsstrt);
3278 custom.vsstop = vsstrt2hw(par->vsstop);
3279 break;
3280 case FB_BLANK_POWERDOWN:
3281 custom.hsstrt = hsstrt2hw(par->htotal + 16);
3282 custom.hsstop = hsstop2hw(par->htotal + 16);
3283 custom.vsstrt = vsstrt2hw(par->vtotal + 4);
3284 custom.vsstop = vsstop2hw(par->vtotal + 4);
3285 break;
1da177e4
LT
3286 }
3287 if (!(par->beamcon0 & BMC0_VARBEAMEN)) {
3288 custom.htotal = htotal2hw(par->htotal);
3289 custom.vtotal = vtotal2hw(par->vtotal);
3290 custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN |
f0058b4b 3291 BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN;
1da177e4
LT
3292 }
3293 }
3294 } else {
3295 custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
3296 red = red0;
3297 green = green0;
3298 blue = blue0;
3299 if (!IS_OCS) {
3300 custom.hsstrt = hsstrt2hw(par->hsstrt);
3301 custom.hsstop = hsstop2hw(par->hsstop);
3302 custom.vsstrt = vsstrt2hw(par->vsstrt);
3303 custom.vsstop = vsstop2hw(par->vsstop);
3304 custom.beamcon0 = par->beamcon0;
3305 }
3306 }
3307#if defined(CONFIG_FB_AMIGA_AGA)
3308 if (IS_AGA) {
3309 custom.bplcon3 = bplcon3;
3310 custom.color[0] = rgb2hw8_high(red, green, blue);
3311 custom.bplcon3 = bplcon3 | BPC3_LOCT;
3312 custom.color[0] = rgb2hw8_low(red, green, blue);
3313 custom.bplcon3 = bplcon3;
3314 } else
3315#endif
3316#if defined(CONFIG_FB_AMIGA_ECS)
3317 if (par->bplcon0 & BPC0_SHRES) {
3318 u_short color, mask;
3319 int i;
3320
3321 mask = 0x3333;
3322 color = rgb2hw2(red, green, blue);
3323 for (i = 12; i >= 0; i -= 4)
3324 custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
f0058b4b 3325 mask <<= 2; color >>= 2;
1da177e4
LT
3326 for (i = 3; i >= 0; i--)
3327 custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
3328 } else
3329#endif
3330 custom.color[0] = rgb2hw4(red, green, blue);
3331 is_blanked = do_blank > 0 ? do_blank : 0;
3332}
3333
3334static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix)
3335{
3336 struct amifb_par *par = &currentpar;
3337
3338 fix->crsr_width = fix->crsr_xsize = par->crsr.width;
3339 fix->crsr_height = fix->crsr_ysize = par->crsr.height;
3340 fix->crsr_color1 = 17;
3341 fix->crsr_color2 = 18;
3342 return 0;
3343}
3344
3728d254 3345static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data)
1da177e4
LT
3346{
3347 struct amifb_par *par = &currentpar;
3348 register u_short *lspr, *sspr;
3349#ifdef __mc68000__
3350 register u_long datawords asm ("d2");
3351#else
3352 register u_long datawords;
3353#endif
3354 register short delta;
3355 register u_char color;
3356 short height, width, bits, words;
3357 int size, alloc;
3358
f0058b4b
GU
3359 size = par->crsr.height * par->crsr.width;
3360 alloc = var->height * var->width;
1da177e4
LT
3361 var->height = par->crsr.height;
3362 var->width = par->crsr.width;
3363 var->xspot = par->crsr.spot_x;
3364 var->yspot = par->crsr.spot_y;
f0058b4b 3365 if (size > var->height * var->width)
1da177e4 3366 return -ENAMETOOLONG;
3728d254 3367 if (!access_ok(VERIFY_WRITE, data, size))
1da177e4 3368 return -EFAULT;
f0058b4b
GU
3369 delta = 1 << par->crsr.fmode;
3370 lspr = lofsprite + (delta << 1);
1da177e4 3371 if (par->bplcon0 & BPC0_LACE)
f0058b4b 3372 sspr = shfsprite + (delta << 1);
1da177e4 3373 else
3728d254 3374 sspr = NULL;
f0058b4b 3375 for (height = (short)var->height - 1; height >= 0; height--) {
1da177e4 3376 bits = 0; words = delta; datawords = 0;
f0058b4b 3377 for (width = (short)var->width - 1; width >= 0; width--) {
1da177e4
LT
3378 if (bits == 0) {
3379 bits = 16; --words;
3380#ifdef __mc68000__
3381 asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0"
3382 : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta));
3383#else
f0058b4b 3384 datawords = (*(lspr + delta) << 16) | (*lspr++);
1da177e4
LT
3385#endif
3386 }
3387 --bits;
3388#ifdef __mc68000__
3389 asm volatile (
3390 "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; "
3391 "swap %1 ; lslw #1,%1 ; roxlb #1,%0"
3392 : "=d" (color), "=d" (datawords) : "1" (datawords));
3393#else
3394 color = (((datawords >> 30) & 2)
3395 | ((datawords >> 15) & 1));
3396 datawords <<= 1;
3397#endif
3398 put_user(color, data++);
3399 }
3400 if (bits > 0) {
3401 --words; ++lspr;
3402 }
3403 while (--words >= 0)
3404 ++lspr;
3405#ifdef __mc68000__
3406 asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
3407 : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
3408#else
3409 lspr += delta;
3410 if (sspr) {
3411 u_short *tmp = lspr;
3412 lspr = sspr;
3413 sspr = tmp;
3414 }
3415#endif
3416 }
3417 return 0;
3418}
3419
3728d254 3420static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data)
1da177e4
LT
3421{
3422 struct amifb_par *par = &currentpar;
3423 register u_short *lspr, *sspr;
3424#ifdef __mc68000__
3425 register u_long datawords asm ("d2");
3426#else
3427 register u_long datawords;
3428#endif
3429 register short delta;
3430 u_short fmode;
3431 short height, width, bits, words;
3432
3433 if (!var->width)
3434 return -EINVAL;
3435 else if (var->width <= 16)
3436 fmode = TAG_FMODE_1;
3437 else if (var->width <= 32)
3438 fmode = TAG_FMODE_2;
3439 else if (var->width <= 64)
3440 fmode = TAG_FMODE_4;
3441 else
3442 return -EINVAL;
3443 if (fmode > maxfmode)
3444 return -EINVAL;
3445 if (!var->height)
3446 return -EINVAL;
f0058b4b 3447 if (!access_ok(VERIFY_READ, data, var->width * var->height))
1da177e4 3448 return -EFAULT;
f0058b4b 3449 delta = 1 << fmode;
1da177e4 3450 lofsprite = shfsprite = (u_short *)spritememory;
f0058b4b 3451 lspr = lofsprite + (delta << 1);
1da177e4 3452 if (par->bplcon0 & BPC0_LACE) {
f0058b4b 3453 if (((var->height + 4) << fmode << 2) > SPRITEMEMSIZE)
1da177e4 3454 return -EINVAL;
f0058b4b
GU
3455 memset(lspr, 0, (var->height + 4) << fmode << 2);
3456 shfsprite += ((var->height + 5)&-2) << fmode;
3457 sspr = shfsprite + (delta << 1);
1da177e4 3458 } else {
f0058b4b 3459 if (((var->height + 2) << fmode << 2) > SPRITEMEMSIZE)
1da177e4 3460 return -EINVAL;
f0058b4b 3461 memset(lspr, 0, (var->height + 2) << fmode << 2);
3728d254 3462 sspr = NULL;
1da177e4 3463 }
f0058b4b 3464 for (height = (short)var->height - 1; height >= 0; height--) {
1da177e4 3465 bits = 16; words = delta; datawords = 0;
f0058b4b 3466 for (width = (short)var->width - 1; width >= 0; width--) {
1da177e4 3467 unsigned long tdata = 0;
3728d254 3468 get_user(tdata, data);
1da177e4
LT
3469 data++;
3470#ifdef __mc68000__
3471 asm volatile (
3472 "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; "
3473 "lsrb #1,%2 ; roxlw #1,%0 ; swap %0"
3474 : "=d" (datawords)
3475 : "0" (datawords), "d" (tdata));
3476#else
3477 datawords = ((datawords << 1) & 0xfffefffe);
3478 datawords |= tdata & 1;
f0058b4b 3479 datawords |= (tdata & 2) << (16 - 1);
1da177e4
LT
3480#endif
3481 if (--bits == 0) {
3482 bits = 16; --words;
3483#ifdef __mc68000__
3484 asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+"
3485 : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta));
3486#else
f0058b4b 3487 *(lspr + delta) = (u_short) (datawords >> 16);
1da177e4
LT
3488 *lspr++ = (u_short) (datawords & 0xffff);
3489#endif
3490 }
3491 }
3492 if (bits < 16) {
3493 --words;
3494#ifdef __mc68000__
3495 asm volatile (
3496 "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; "
3497 "swap %2 ; lslw %4,%2 ; movew %2,%0@+"
3498 : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits));
3499#else
f0058b4b 3500 *(lspr + delta) = (u_short) (datawords >> (16 + bits));
1da177e4
LT
3501 *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits);
3502#endif
3503 }
3504 while (--words >= 0) {
3505#ifdef __mc68000__
3506 asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+"
3507 : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0");
3508#else
f0058b4b 3509 *(lspr + delta) = 0;
1da177e4
LT
3510 *lspr++ = 0;
3511#endif
3512 }
3513#ifdef __mc68000__
3514 asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
3515 : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
3516#else
3517 lspr += delta;
3518 if (sspr) {
3519 u_short *tmp = lspr;
3520 lspr = sspr;
3521 sspr = tmp;
3522 }
3523#endif
3524 }
3525 par->crsr.height = var->height;
3526 par->crsr.width = var->width;
3527 par->crsr.spot_x = var->xspot;
3528 par->crsr.spot_y = var->yspot;
3529 par->crsr.fmode = fmode;
3530 if (IS_AGA) {
3531 par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32);
3532 par->fmode |= sprfetchmode[fmode];
3533 custom.fmode = par->fmode;
3534 }
3535 return 0;
3536}
3537
3538static int ami_get_cursorstate(struct fb_cursorstate *state)
3539{
3540 struct amifb_par *par = &currentpar;
3541
3542 state->xoffset = par->crsr.crsr_x;
3543 state->yoffset = par->crsr.crsr_y;
3544 state->mode = cursormode;
3545 return 0;
3546}
3547
3548static int ami_set_cursorstate(struct fb_cursorstate *state)
3549{
3550 struct amifb_par *par = &currentpar;
3551
3552 par->crsr.crsr_x = state->xoffset;
3553 par->crsr.crsr_y = state->yoffset;
3554 if ((cursormode = state->mode) == FB_CURSOR_OFF)
3555 cursorstate = -1;
3556 do_cursor = 1;
3557 return 0;
3558}
3559
3560static void ami_set_sprite(void)
3561{
3562 struct amifb_par *par = &currentpar;
3563 copins *copl, *cops;
3564 u_short hs, vs, ve;
3565 u_long pl, ps, pt;
3566 short mx, my;
3567
3568 cops = copdisplay.list[currentcop][0];
3569 copl = copdisplay.list[currentcop][1];
3570 ps = pl = ZTWO_PADDR(dummysprite);
f0058b4b
GU
3571 mx = par->crsr.crsr_x - par->crsr.spot_x;
3572 my = par->crsr.crsr_y - par->crsr.spot_y;
1da177e4
LT
3573 if (!(par->vmode & FB_VMODE_YWRAP)) {
3574 mx -= par->xoffset;
3575 my -= par->yoffset;
3576 }
3577 if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 &&
3578 mx > -(short)par->crsr.width && mx < par->xres &&
3579 my > -(short)par->crsr.height && my < par->yres) {
3580 pl = ZTWO_PADDR(lofsprite);
f0058b4b
GU
3581 hs = par->diwstrt_h + (mx << par->clk_shift) - 4;
3582 vs = par->diwstrt_v + (my << par->line_shift);
3583 ve = vs + (par->crsr.height << par->line_shift);
1da177e4
LT
3584 if (par->bplcon0 & BPC0_LACE) {
3585 ps = ZTWO_PADDR(shfsprite);
3586 lofsprite[0] = spr2hw_pos(vs, hs);
f0058b4b 3587 shfsprite[0] = spr2hw_pos(vs + 1, hs);
1da177e4 3588 if (mod2(vs)) {
f0058b4b
GU
3589 lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
3590 shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve + 1);
1da177e4
LT
3591 pt = pl; pl = ps; ps = pt;
3592 } else {
f0058b4b
GU
3593 lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve + 1);
3594 shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve);
1da177e4
LT
3595 }
3596 } else {
3597 lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0);
f0058b4b 3598 lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
1da177e4
LT
3599 }
3600 }
3601 copl[cop_spr0ptrh].w[1] = highw(pl);
3602 copl[cop_spr0ptrl].w[1] = loww(pl);
3603 if (par->bplcon0 & BPC0_LACE) {
3604 cops[cop_spr0ptrh].w[1] = highw(ps);
3605 cops[cop_spr0ptrl].w[1] = loww(ps);
3606 }
3607}
3608
3609
3610 /*
3611 * Initialise the Copper Initialisation List
3612 */
3613
3614static void __init ami_init_copper(void)
3615{
3616 copins *cop = copdisplay.init;
3617 u_long p;
3618 int i;
3619
3620 if (!IS_OCS) {
3621 (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
3622 (cop++)->l = CMOVE(0x0181, diwstrt);
3623 (cop++)->l = CMOVE(0x0281, diwstop);
3624 (cop++)->l = CMOVE(0x0000, diwhigh);
3625 } else
3626 (cop++)->l = CMOVE(BPC0_COLOR, bplcon0);
3627 p = ZTWO_PADDR(dummysprite);
3628 for (i = 0; i < 8; i++) {
3629 (cop++)->l = CMOVE(0, spr[i].pos);
3630 (cop++)->l = CMOVE(highw(p), sprpt[i]);
3631 (cop++)->l = CMOVE2(loww(p), sprpt[i]);
3632 }
3633
3634 (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);
3635 copdisplay.wait = cop;
3636 (cop++)->l = CEND;
3637 (cop++)->l = CMOVE(0, copjmp2);
3638 cop->l = CEND;
3639
3640 custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);
3641 custom.copjmp1 = 0;
3642}
3643
3644static void ami_reinit_copper(void)
3645{
3646 struct amifb_par *par = &currentpar;
3647
3648 copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0;
f0058b4b 3649 copdisplay.wait->l = CWAIT(32, par->diwstrt_v - 4);
1da177e4
LT
3650}
3651
3652 /*
3653 * Build the Copper List
3654 */
3655
3656static void ami_build_copper(void)
3657{
3658 struct amifb_par *par = &currentpar;
3659 copins *copl, *cops;
3660 u_long p;
3661
3662 currentcop = 1 - currentcop;
3663
3664 copl = copdisplay.list[currentcop][1];
3665
3666 (copl++)->l = CWAIT(0, 10);
3667 (copl++)->l = CMOVE(par->bplcon0, bplcon0);
3668 (copl++)->l = CMOVE(0, sprpt[0]);
3669 (copl++)->l = CMOVE2(0, sprpt[0]);
3670
3671 if (par->bplcon0 & BPC0_LACE) {
3672 cops = copdisplay.list[currentcop][0];
3673
3674 (cops++)->l = CWAIT(0, 10);
3675 (cops++)->l = CMOVE(par->bplcon0, bplcon0);
3676 (cops++)->l = CMOVE(0, sprpt[0]);
3677 (cops++)->l = CMOVE2(0, sprpt[0]);
3678
f0058b4b
GU
3679 (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v + 1), diwstrt);
3680 (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v + 1), diwstop);
1da177e4
LT
3681 (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
3682 (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
3683 if (!IS_OCS) {
f0058b4b
GU
3684 (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v + 1,
3685 par->diwstop_h, par->diwstop_v + 1), diwhigh);
1da177e4 3686 (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
f0058b4b 3687 par->diwstop_h, par->diwstop_v), diwhigh);
1da177e4
LT
3688#if 0
3689 if (par->beamcon0 & BMC0_VARBEAMEN) {
3690 (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
f0058b4b
GU
3691 (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt + 1), vbstrt);
3692 (copl++)->l = CMOVE(vbstop2hw(par->vbstop + 1), vbstop);
1da177e4
LT
3693 (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3694 (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
3695 (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
3696 }
3697#endif
3698 }
3699 p = ZTWO_PADDR(copdisplay.list[currentcop][0]);
3700 (copl++)->l = CMOVE(highw(p), cop2lc);
3701 (copl++)->l = CMOVE2(loww(p), cop2lc);
3702 p = ZTWO_PADDR(copdisplay.list[currentcop][1]);
3703 (cops++)->l = CMOVE(highw(p), cop2lc);
3704 (cops++)->l = CMOVE2(loww(p), cop2lc);
3705 copdisplay.rebuild[0] = cops;
3706 } else {
3707 (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
3708 (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
3709 if (!IS_OCS) {
3710 (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
f0058b4b 3711 par->diwstop_h, par->diwstop_v), diwhigh);
1da177e4
LT
3712#if 0
3713 if (par->beamcon0 & BMC0_VARBEAMEN) {
3714 (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
3715 (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
3716 (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
3717 }
3718#endif
3719 }
3720 }
3721 copdisplay.rebuild[1] = copl;
3722
3723 ami_update_par();
3724 ami_rebuild_copper();
3725}
3726
3727 /*
3728 * Rebuild the Copper List
3729 *
3730 * We only change the things that are not static
3731 */
3732
3733static void ami_rebuild_copper(void)
3734{
3735 struct amifb_par *par = &currentpar;
3736 copins *copl, *cops;
3737 u_short line, h_end1, h_end2;
3738 short i;
3739 u_long p;
3740
3741 if (IS_AGA && maxfmode + par->clk_shift == 0)
f0058b4b 3742 h_end1 = par->diwstrt_h - 64;
1da177e4 3743 else
f0058b4b
GU
3744 h_end1 = par->htotal - 32;
3745 h_end2 = par->ddfstop + 64;
1da177e4
LT
3746
3747 ami_set_sprite();
3748
3749 copl = copdisplay.rebuild[1];
3750 p = par->bplpt0;
3751 if (par->vmode & FB_VMODE_YWRAP) {
f0058b4b
GU
3752 if ((par->vyres - par->yoffset) != 1 || !mod2(par->diwstrt_v)) {
3753 if (par->yoffset > par->vyres - par->yres) {
1da177e4
LT
3754 for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3755 (copl++)->l = CMOVE(highw(p), bplpt[i]);
3756 (copl++)->l = CMOVE2(loww(p), bplpt[i]);
3757 }
f0058b4b 3758 line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 1;
1da177e4
LT
3759 while (line >= 512) {
3760 (copl++)->l = CWAIT(h_end1, 510);
3761 line -= 512;
3762 }
3763 if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0)
3764 (copl++)->l = CWAIT(h_end1, line);
3765 else
3766 (copl++)->l = CWAIT(h_end2, line);
3767 p = par->bplpt0wrap;
3768 }
f0058b4b
GU
3769 } else
3770 p = par->bplpt0wrap;
1da177e4
LT
3771 }
3772 for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3773 (copl++)->l = CMOVE(highw(p), bplpt[i]);
3774 (copl++)->l = CMOVE2(loww(p), bplpt[i]);
3775 }
3776 copl->l = CEND;
3777
3778 if (par->bplcon0 & BPC0_LACE) {
3779 cops = copdisplay.rebuild[0];
3780 p = par->bplpt0;
3781 if (mod2(par->diwstrt_v))
3782 p -= par->next_line;
3783 else
3784 p += par->next_line;
3785 if (par->vmode & FB_VMODE_YWRAP) {
f0058b4b
GU
3786 if ((par->vyres - par->yoffset) != 1 || mod2(par->diwstrt_v)) {
3787 if (par->yoffset > par->vyres - par->yres + 1) {
1da177e4
LT
3788 for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3789 (cops++)->l = CMOVE(highw(p), bplpt[i]);
3790 (cops++)->l = CMOVE2(loww(p), bplpt[i]);
3791 }
f0058b4b 3792 line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 2;
1da177e4
LT
3793 while (line >= 512) {
3794 (cops++)->l = CWAIT(h_end1, 510);
3795 line -= 512;
3796 }
3797 if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0)
3798 (cops++)->l = CWAIT(h_end1, line);
3799 else
3800 (cops++)->l = CWAIT(h_end2, line);
3801 p = par->bplpt0wrap;
f0058b4b
GU
3802 if (mod2(par->diwstrt_v + par->vyres -
3803 par->yoffset))
1da177e4
LT
3804 p -= par->next_line;
3805 else
3806 p += par->next_line;
3807 }
f0058b4b
GU
3808 } else
3809 p = par->bplpt0wrap - par->next_line;
1da177e4
LT
3810 }
3811 for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
3812 (cops++)->l = CMOVE(highw(p), bplpt[i]);
3813 (cops++)->l = CMOVE2(loww(p), bplpt[i]);
3814 }
3815 cops->l = CEND;
3816 }
3817}
3818
fa6688e1 3819static int __exit amifb_remove(struct platform_device *pdev)
1da177e4
LT
3820{
3821 unregister_framebuffer(&fb_info);
fa6688e1 3822 amifb_deinit(pdev);
1da177e4 3823 amifb_video_off();
fa6688e1
GU
3824 return 0;
3825}
3826
3827static struct platform_driver amifb_driver = {
3828 .remove = __exit_p(amifb_remove),
3829 .driver = {
3830 .name = "amiga-video",
3831 .owner = THIS_MODULE,
3832 },
3833};
3834
3835static int __init amifb_init(void)
3836{
3837 return platform_driver_probe(&amifb_driver, amifb_probe);
1da177e4 3838}
5798712d
AB
3839
3840module_init(amifb_init);
fa6688e1
GU
3841
3842static void __exit amifb_exit(void)
3843{
3844 platform_driver_unregister(&amifb_driver);
3845}
3846
5798712d
AB
3847module_exit(amifb_exit);
3848
3849MODULE_LICENSE("GPL");
fa6688e1 3850MODULE_ALIAS("platform:amiga-video");
This page took 0.802393 seconds and 5 git commands to generate.