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