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