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