OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [video/] [amifb.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.