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