162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Portions Copyright (c) 2001 Matrox Graphics Inc.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Version: 1.65 2002/08/14
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Contributors: "menion?" <menion@mindless.com>
1562306a36Sopenharmony_ci *                     Betatesting, fixes, ideas
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *               "Kurt Garloff" <garloff@suse.de>
1862306a36Sopenharmony_ci *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *               "Tom Rini" <trini@kernel.crashing.org>
2162306a36Sopenharmony_ci *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci *               "Bibek Sahu" <scorpio@dodds.net>
2462306a36Sopenharmony_ci *                     Access device through readb|w|l and write b|w|l
2562306a36Sopenharmony_ci *                     Extensive debugging stuff
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci *               "Daniel Haun" <haund@usa.net>
2862306a36Sopenharmony_ci *                     Testing, hardware cursor fixes
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci *               "Scott Wood" <sawst46+@pitt.edu>
3162306a36Sopenharmony_ci *                     Fixes
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
3462306a36Sopenharmony_ci *                     Betatesting
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci *               "Kelly French" <targon@hazmat.com>
3762306a36Sopenharmony_ci *               "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
3862306a36Sopenharmony_ci *                     Betatesting, bug reporting
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci *               "Pablo Bianucci" <pbian@pccp.com.ar>
4162306a36Sopenharmony_ci *                     Fixes, ideas, betatesting
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
4462306a36Sopenharmony_ci *                     Fixes, enhandcements, ideas, betatesting
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
4762306a36Sopenharmony_ci *                     PPC betatesting, PPC support, backward compatibility
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci *               "Paul Womar" <Paul@pwomar.demon.co.uk>
5062306a36Sopenharmony_ci *               "Owen Waller" <O.Waller@ee.qub.ac.uk>
5162306a36Sopenharmony_ci *                     PPC betatesting
5262306a36Sopenharmony_ci *
5362306a36Sopenharmony_ci *               "Thomas Pornin" <pornin@bolet.ens.fr>
5462306a36Sopenharmony_ci *                     Alpha betatesting
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci *               "Pieter van Leuven" <pvl@iae.nl>
5762306a36Sopenharmony_ci *               "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
5862306a36Sopenharmony_ci *                     G100 testing
5962306a36Sopenharmony_ci *
6062306a36Sopenharmony_ci *               "H. Peter Arvin" <hpa@transmeta.com>
6162306a36Sopenharmony_ci *                     Ideas
6262306a36Sopenharmony_ci *
6362306a36Sopenharmony_ci *               "Cort Dougan" <cort@cs.nmt.edu>
6462306a36Sopenharmony_ci *                     CHRP fixes and PReP cleanup
6562306a36Sopenharmony_ci *
6662306a36Sopenharmony_ci *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
6762306a36Sopenharmony_ci *                     G400 support
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * (following author is not in any relation with this code, but his code
7062306a36Sopenharmony_ci *  is included in this driver)
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci * Based on framebuffer driver for VBE 2.0 compliant graphic boards
7362306a36Sopenharmony_ci *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
7462306a36Sopenharmony_ci *
7562306a36Sopenharmony_ci * (following author is not in any relation with this code, but his ideas
7662306a36Sopenharmony_ci *  were used when writing this driver)
7762306a36Sopenharmony_ci *
7862306a36Sopenharmony_ci *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci#include "matroxfb_Ti3026.h"
8462306a36Sopenharmony_ci#include "matroxfb_misc.h"
8562306a36Sopenharmony_ci#include "matroxfb_accel.h"
8662306a36Sopenharmony_ci#include <linux/matroxfb.h>
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MILLENIUM
8962306a36Sopenharmony_ci#define outTi3026 matroxfb_DAC_out
9062306a36Sopenharmony_ci#define inTi3026 matroxfb_DAC_in
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define TVP3026_INDEX		0x00
9362306a36Sopenharmony_ci#define TVP3026_PALWRADD	0x00
9462306a36Sopenharmony_ci#define TVP3026_PALDATA		0x01
9562306a36Sopenharmony_ci#define TVP3026_PIXRDMSK	0x02
9662306a36Sopenharmony_ci#define TVP3026_PALRDADD	0x03
9762306a36Sopenharmony_ci#define TVP3026_CURCOLWRADD	0x04
9862306a36Sopenharmony_ci#define     TVP3026_CLOVERSCAN		0x00
9962306a36Sopenharmony_ci#define     TVP3026_CLCOLOR0		0x01
10062306a36Sopenharmony_ci#define     TVP3026_CLCOLOR1		0x02
10162306a36Sopenharmony_ci#define     TVP3026_CLCOLOR2		0x03
10262306a36Sopenharmony_ci#define TVP3026_CURCOLDATA	0x05
10362306a36Sopenharmony_ci#define TVP3026_CURCOLRDADD	0x07
10462306a36Sopenharmony_ci#define TVP3026_CURCTRL		0x09
10562306a36Sopenharmony_ci#define TVP3026_X_DATAREG	0x0A
10662306a36Sopenharmony_ci#define TVP3026_CURRAMDATA	0x0B
10762306a36Sopenharmony_ci#define TVP3026_CURPOSXL	0x0C
10862306a36Sopenharmony_ci#define TVP3026_CURPOSXH	0x0D
10962306a36Sopenharmony_ci#define TVP3026_CURPOSYL	0x0E
11062306a36Sopenharmony_ci#define TVP3026_CURPOSYH	0x0F
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci#define TVP3026_XSILICONREV	0x01
11362306a36Sopenharmony_ci#define TVP3026_XCURCTRL	0x06
11462306a36Sopenharmony_ci#define     TVP3026_XCURCTRL_DIS	0x00	/* transparent, transparent, transparent, transparent */
11562306a36Sopenharmony_ci#define     TVP3026_XCURCTRL_3COLOR	0x01	/* transparent, 0, 1, 2 */
11662306a36Sopenharmony_ci#define     TVP3026_XCURCTRL_XGA	0x02	/* 0, 1, transparent, complement */
11762306a36Sopenharmony_ci#define     TVP3026_XCURCTRL_XWIN	0x03	/* transparent, transparent, 0, 1 */
11862306a36Sopenharmony_ci#define     TVP3026_XCURCTRL_BLANK2048	0x00
11962306a36Sopenharmony_ci#define     TVP3026_XCURCTRL_BLANK4096	0x10
12062306a36Sopenharmony_ci#define     TVP3026_XCURCTRL_INTERLACED	0x20
12162306a36Sopenharmony_ci#define     TVP3026_XCURCTRL_ODD	0x00 /* ext.signal ODD/\EVEN */
12262306a36Sopenharmony_ci#define     TVP3026_XCURCTRL_EVEN	0x40 /* ext.signal EVEN/\ODD */
12362306a36Sopenharmony_ci#define     TVP3026_XCURCTRL_INDIRECT	0x00
12462306a36Sopenharmony_ci#define     TVP3026_XCURCTRL_DIRECT	0x80
12562306a36Sopenharmony_ci#define TVP3026_XLATCHCTRL	0x0F
12662306a36Sopenharmony_ci#define     TVP3026_XLATCHCTRL_1_1	0x06
12762306a36Sopenharmony_ci#define     TVP3026_XLATCHCTRL_2_1	0x07
12862306a36Sopenharmony_ci#define     TVP3026_XLATCHCTRL_4_1	0x06
12962306a36Sopenharmony_ci#define     TVP3026_XLATCHCTRL_8_1	0x06
13062306a36Sopenharmony_ci#define     TVP3026_XLATCHCTRL_16_1	0x06
13162306a36Sopenharmony_ci#define     TVP3026A_XLATCHCTRL_4_3	0x06	/* ??? do not understand... but it works... !!! */
13262306a36Sopenharmony_ci#define     TVP3026A_XLATCHCTRL_8_3	0x07
13362306a36Sopenharmony_ci#define     TVP3026B_XLATCHCTRL_4_3	0x08
13462306a36Sopenharmony_ci#define     TVP3026B_XLATCHCTRL_8_3	0x06	/* ??? do not understand... but it works... !!! */
13562306a36Sopenharmony_ci#define TVP3026_XTRUECOLORCTRL	0x18
13662306a36Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL	0x00
13762306a36Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP	0x20
13862306a36Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR		0x80
13962306a36Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_TRUECOLOR		0x40 /* paletized */
14062306a36Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_DIRECTCOLOR		0x00
14162306a36Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_24_ALTERNATE		0x08 /* 5:4/5:2 instead of 4:3/8:3 */
14262306a36Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_RGB_888		0x16 /* 4:3/8:3 (or 5:4/5:2) */
14362306a36Sopenharmony_ci#define	    TVP3026_XTRUECOLORCTRL_BGR_888		0x17
14462306a36Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_ORGB_8888		0x06
14562306a36Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_BGRO_8888		0x07
14662306a36Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_RGB_565		0x05
14762306a36Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_ORGB_1555		0x04
14862306a36Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_RGB_664		0x03
14962306a36Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_RGBO_4444		0x01
15062306a36Sopenharmony_ci#define TVP3026_XMUXCTRL	0x19
15162306a36Sopenharmony_ci#define     TVP3026_XMUXCTRL_MEMORY_8BIT			0x01 /* - */
15262306a36Sopenharmony_ci#define     TVP3026_XMUXCTRL_MEMORY_16BIT			0x02 /* - */
15362306a36Sopenharmony_ci#define     TVP3026_XMUXCTRL_MEMORY_32BIT			0x03 /* 2MB RAM, 512K * 4 */
15462306a36Sopenharmony_ci#define     TVP3026_XMUXCTRL_MEMORY_64BIT			0x04 /* >2MB RAM, 512K * 8 & more */
15562306a36Sopenharmony_ci#define     TVP3026_XMUXCTRL_PIXEL_4BIT				0x40 /* L0,H0,L1,H1... */
15662306a36Sopenharmony_ci#define     TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED			0x60 /* H0,L0,H1,L1... */
15762306a36Sopenharmony_ci#define     TVP3026_XMUXCTRL_PIXEL_8BIT				0x48
15862306a36Sopenharmony_ci#define     TVP3026_XMUXCTRL_PIXEL_16BIT			0x50
15962306a36Sopenharmony_ci#define     TVP3026_XMUXCTRL_PIXEL_32BIT			0x58
16062306a36Sopenharmony_ci#define     TVP3026_XMUXCTRL_VGA				0x98 /* VGA MEMORY, 8BIT PIXEL */
16162306a36Sopenharmony_ci#define TVP3026_XCLKCTRL	0x1A
16262306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV1	0x00
16362306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV2	0x10
16462306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV4	0x20
16562306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV8	0x30
16662306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV16	0x40
16762306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV32	0x50
16862306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV64	0x60
16962306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_CLKSTOPPED	0x70
17062306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_CLK0	0x00
17162306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_CLK1   0x01
17262306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_CLK2	0x02	/* CLK2 is TTL source*/
17362306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_NCLK2	0x03	/* not CLK2 is TTL source */
17462306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_ECLK2	0x04	/* CLK2 and not CLK2 is ECL source */
17562306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_PLL	0x05
17662306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_DIS	0x06	/* disable & poweroff internal clock */
17762306a36Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07
17862306a36Sopenharmony_ci#define TVP3026_XPALETTEPAGE	0x1C
17962306a36Sopenharmony_ci#define TVP3026_XGENCTRL	0x1D
18062306a36Sopenharmony_ci#define     TVP3026_XGENCTRL_HSYNC_POS	0x00
18162306a36Sopenharmony_ci#define     TVP3026_XGENCTRL_HSYNC_NEG	0x01
18262306a36Sopenharmony_ci#define     TVP3026_XGENCTRL_VSYNC_POS	0x00
18362306a36Sopenharmony_ci#define     TVP3026_XGENCTRL_VSYNC_NEG	0x02
18462306a36Sopenharmony_ci#define     TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00
18562306a36Sopenharmony_ci#define     TVP3026_XGENCTRL_BIG_ENDIAN    0x08
18662306a36Sopenharmony_ci#define     TVP3026_XGENCTRL_BLACK_0IRE		0x00
18762306a36Sopenharmony_ci#define     TVP3026_XGENCTRL_BLACK_75IRE	0x10
18862306a36Sopenharmony_ci#define     TVP3026_XGENCTRL_NO_SYNC_ON_GREEN	0x00
18962306a36Sopenharmony_ci#define     TVP3026_XGENCTRL_SYNC_ON_GREEN	0x20
19062306a36Sopenharmony_ci#define     TVP3026_XGENCTRL_OVERSCAN_DIS	0x00
19162306a36Sopenharmony_ci#define     TVP3026_XGENCTRL_OVERSCAN_EN	0x40
19262306a36Sopenharmony_ci#define TVP3026_XMISCCTRL	0x1E
19362306a36Sopenharmony_ci#define     TVP3026_XMISCCTRL_DAC_PUP	0x00
19462306a36Sopenharmony_ci#define     TVP3026_XMISCCTRL_DAC_PDOWN	0x01
19562306a36Sopenharmony_ci#define     TVP3026_XMISCCTRL_DAC_EXT	0x00 /* or 8, bit 3 is ignored */
19662306a36Sopenharmony_ci#define     TVP3026_XMISCCTRL_DAC_6BIT	0x04
19762306a36Sopenharmony_ci#define     TVP3026_XMISCCTRL_DAC_8BIT	0x0C
19862306a36Sopenharmony_ci#define     TVP3026_XMISCCTRL_PSEL_DIS	0x00
19962306a36Sopenharmony_ci#define     TVP3026_XMISCCTRL_PSEL_EN	0x10
20062306a36Sopenharmony_ci#define     TVP3026_XMISCCTRL_PSEL_LOW	0x00 /* PSEL high selects directcolor */
20162306a36Sopenharmony_ci#define     TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */
20262306a36Sopenharmony_ci#define TVP3026_XGENIOCTRL	0x2A
20362306a36Sopenharmony_ci#define TVP3026_XGENIODATA	0x2B
20462306a36Sopenharmony_ci#define TVP3026_XPLLADDR	0x2C
20562306a36Sopenharmony_ci#define     TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX))
20662306a36Sopenharmony_ci#define     TVP3026_XPLLDATA_N		0x00
20762306a36Sopenharmony_ci#define     TVP3026_XPLLDATA_M		0x01
20862306a36Sopenharmony_ci#define     TVP3026_XPLLDATA_P		0x02
20962306a36Sopenharmony_ci#define     TVP3026_XPLLDATA_STAT	0x03
21062306a36Sopenharmony_ci#define TVP3026_XPIXPLLDATA	0x2D
21162306a36Sopenharmony_ci#define TVP3026_XMEMPLLDATA	0x2E
21262306a36Sopenharmony_ci#define TVP3026_XLOOPPLLDATA	0x2F
21362306a36Sopenharmony_ci#define TVP3026_XCOLKEYOVRMIN	0x30
21462306a36Sopenharmony_ci#define TVP3026_XCOLKEYOVRMAX	0x31
21562306a36Sopenharmony_ci#define TVP3026_XCOLKEYREDMIN	0x32
21662306a36Sopenharmony_ci#define TVP3026_XCOLKEYREDMAX	0x33
21762306a36Sopenharmony_ci#define TVP3026_XCOLKEYGREENMIN	0x34
21862306a36Sopenharmony_ci#define TVP3026_XCOLKEYGREENMAX	0x35
21962306a36Sopenharmony_ci#define TVP3026_XCOLKEYBLUEMIN	0x36
22062306a36Sopenharmony_ci#define TVP3026_XCOLKEYBLUEMAX	0x37
22162306a36Sopenharmony_ci#define TVP3026_XCOLKEYCTRL	0x38
22262306a36Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_OVR_EN	0x01
22362306a36Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_RED_EN	0x02
22462306a36Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_GREEN_EN 0x04
22562306a36Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_BLUE_EN	0x08
22662306a36Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_NEGATE	0x10
22762306a36Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_ZOOM1	0x00
22862306a36Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_ZOOM2	0x20
22962306a36Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_ZOOM4	0x40
23062306a36Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_ZOOM8	0x60
23162306a36Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_ZOOM16	0x80
23262306a36Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_ZOOM32	0xA0
23362306a36Sopenharmony_ci#define TVP3026_XMEMPLLCTRL	0x39
23462306a36Sopenharmony_ci#define     TVP3026_XMEMPLLCTRL_DIV(X)	(((X)-1)>>1)	/* 2,4,6,8,10,12,14,16, division applied to LOOP PLL after divide by 2^P */
23562306a36Sopenharmony_ci#define     TVP3026_XMEMPLLCTRL_STROBEMKC4	0x08
23662306a36Sopenharmony_ci#define     TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK	0x00	/* MKC4 */
23762306a36Sopenharmony_ci#define     TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL	0x10	/* MKC4 */
23862306a36Sopenharmony_ci#define     TVP3026_XMEMPLLCTRL_RCLK_PIXPLL	0x00
23962306a36Sopenharmony_ci#define     TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL	0x20
24062306a36Sopenharmony_ci#define     TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN	0x40	/* dot clock divided by loop pclk N prescaler */
24162306a36Sopenharmony_ci#define TVP3026_XSENSETEST	0x3A
24262306a36Sopenharmony_ci#define TVP3026_XTESTMODEDATA	0x3B
24362306a36Sopenharmony_ci#define TVP3026_XCRCREML	0x3C
24462306a36Sopenharmony_ci#define TVP3026_XCRCREMH	0x3D
24562306a36Sopenharmony_ci#define TVP3026_XCRCBITSEL	0x3E
24662306a36Sopenharmony_ci#define TVP3026_XID		0x3F
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic const unsigned char DACseq[] =
24962306a36Sopenharmony_ci{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL,
25062306a36Sopenharmony_ci  TVP3026_XMUXCTRL, TVP3026_XCLKCTRL,
25162306a36Sopenharmony_ci  TVP3026_XPALETTEPAGE,
25262306a36Sopenharmony_ci  TVP3026_XGENCTRL,
25362306a36Sopenharmony_ci  TVP3026_XMISCCTRL,
25462306a36Sopenharmony_ci  TVP3026_XGENIOCTRL,
25562306a36Sopenharmony_ci  TVP3026_XGENIODATA,
25662306a36Sopenharmony_ci  TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX,
25762306a36Sopenharmony_ci  TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX,
25862306a36Sopenharmony_ci  TVP3026_XCOLKEYCTRL,
25962306a36Sopenharmony_ci  TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL };
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci#define POS3026_XLATCHCTRL	0
26262306a36Sopenharmony_ci#define POS3026_XTRUECOLORCTRL	1
26362306a36Sopenharmony_ci#define POS3026_XMUXCTRL	2
26462306a36Sopenharmony_ci#define POS3026_XCLKCTRL	3
26562306a36Sopenharmony_ci#define POS3026_XGENCTRL	5
26662306a36Sopenharmony_ci#define POS3026_XMISCCTRL	6
26762306a36Sopenharmony_ci#define POS3026_XMEMPLLCTRL	18
26862306a36Sopenharmony_ci#define POS3026_XCURCTRL	20
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic const unsigned char MGADACbpp32[] =
27162306a36Sopenharmony_ci{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888,
27262306a36Sopenharmony_ci  0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL,
27362306a36Sopenharmony_ci  0x00,
27462306a36Sopenharmony_ci  TVP3026_XGENCTRL_HSYNC_POS | TVP3026_XGENCTRL_VSYNC_POS | TVP3026_XGENCTRL_LITTLE_ENDIAN | TVP3026_XGENCTRL_BLACK_0IRE | TVP3026_XGENCTRL_NO_SYNC_ON_GREEN | TVP3026_XGENCTRL_OVERSCAN_DIS,
27562306a36Sopenharmony_ci  TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH,
27662306a36Sopenharmony_ci  0x00,
27762306a36Sopenharmony_ci  0x1E,
27862306a36Sopenharmony_ci  0xFF, 0xFF, 0xFF, 0xFF,
27962306a36Sopenharmony_ci  0xFF, 0xFF, 0xFF, 0xFF,
28062306a36Sopenharmony_ci  TVP3026_XCOLKEYCTRL_ZOOM1,
28162306a36Sopenharmony_ci  0x00, 0x00, TVP3026_XCURCTRL_DIS };
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic int Ti3026_calcclock(const struct matrox_fb_info *minfo,
28462306a36Sopenharmony_ci			    unsigned int freq, unsigned int fmax, int *in,
28562306a36Sopenharmony_ci			    int *feed, int *post)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	unsigned int fvco;
28862306a36Sopenharmony_ci	unsigned int lin, lfeed, lpost;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	DBG(__func__)
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	fvco = PLL_calcclock(minfo, freq, fmax, &lin, &lfeed, &lpost);
29362306a36Sopenharmony_ci	fvco >>= (*post = lpost);
29462306a36Sopenharmony_ci	*in = 64 - lin;
29562306a36Sopenharmony_ci	*feed = 64 - lfeed;
29662306a36Sopenharmony_ci	return fvco;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic int Ti3026_setpclk(struct matrox_fb_info *minfo, int clk)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	unsigned int f_pll;
30262306a36Sopenharmony_ci	unsigned int pixfeed, pixin, pixpost;
30362306a36Sopenharmony_ci	struct matrox_hw_state *hw = &minfo->hw;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	DBG(__func__)
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	f_pll = Ti3026_calcclock(minfo, clk, minfo->max_pixel_clock, &pixin, &pixfeed, &pixpost);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	hw->DACclk[0] = pixin | 0xC0;
31062306a36Sopenharmony_ci	hw->DACclk[1] = pixfeed;
31162306a36Sopenharmony_ci	hw->DACclk[2] = pixpost | 0xB0;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	{
31462306a36Sopenharmony_ci		unsigned int loopfeed, loopin, looppost, loopdiv, z;
31562306a36Sopenharmony_ci		unsigned int Bpp;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		Bpp = minfo->curr.final_bppShift;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci		if (minfo->fbcon.var.bits_per_pixel == 24) {
32062306a36Sopenharmony_ci			loopfeed = 3;		/* set lm to any possible value */
32162306a36Sopenharmony_ci			loopin = 3 * 32 / Bpp;
32262306a36Sopenharmony_ci		} else {
32362306a36Sopenharmony_ci			loopfeed = 4;
32462306a36Sopenharmony_ci			loopin = 4 * 32 / Bpp;
32562306a36Sopenharmony_ci		}
32662306a36Sopenharmony_ci		z = (110000 * loopin) / (f_pll * loopfeed);
32762306a36Sopenharmony_ci		loopdiv = 0; /* div 2 */
32862306a36Sopenharmony_ci		if (z < 2)
32962306a36Sopenharmony_ci			looppost = 0;
33062306a36Sopenharmony_ci		else if (z < 4)
33162306a36Sopenharmony_ci			looppost = 1;
33262306a36Sopenharmony_ci		else if (z < 8)
33362306a36Sopenharmony_ci			looppost = 2;
33462306a36Sopenharmony_ci		else {
33562306a36Sopenharmony_ci			looppost = 3;
33662306a36Sopenharmony_ci			loopdiv = z/16;
33762306a36Sopenharmony_ci		}
33862306a36Sopenharmony_ci		if (minfo->fbcon.var.bits_per_pixel == 24) {
33962306a36Sopenharmony_ci			hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
34062306a36Sopenharmony_ci			hw->DACclk[4] = (65 - loopfeed) | 0x80;
34162306a36Sopenharmony_ci			if (minfo->accel.ramdac_rev > 0x20) {
34262306a36Sopenharmony_ci				if (isInterleave(minfo))
34362306a36Sopenharmony_ci					hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3;
34462306a36Sopenharmony_ci				else {
34562306a36Sopenharmony_ci					hw->DACclk[4] &= ~0xC0;
34662306a36Sopenharmony_ci					hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3;
34762306a36Sopenharmony_ci				}
34862306a36Sopenharmony_ci			} else {
34962306a36Sopenharmony_ci				if (isInterleave(minfo))
35062306a36Sopenharmony_ci					;	/* default... */
35162306a36Sopenharmony_ci				else {
35262306a36Sopenharmony_ci					hw->DACclk[4] ^= 0xC0;	/* change from 0x80 to 0x40 */
35362306a36Sopenharmony_ci					hw->DACreg[POS3026_XLATCHCTRL] = TVP3026A_XLATCHCTRL_4_3;
35462306a36Sopenharmony_ci				}
35562306a36Sopenharmony_ci			}
35662306a36Sopenharmony_ci			hw->DACclk[5] = looppost | 0xF8;
35762306a36Sopenharmony_ci			if (minfo->devflags.mga_24bpp_fix)
35862306a36Sopenharmony_ci				hw->DACclk[5] ^= 0x40;
35962306a36Sopenharmony_ci		} else {
36062306a36Sopenharmony_ci			hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
36162306a36Sopenharmony_ci			hw->DACclk[4] = 65 - loopfeed;
36262306a36Sopenharmony_ci			hw->DACclk[5] = looppost | 0xF0;
36362306a36Sopenharmony_ci		}
36462306a36Sopenharmony_ci		hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci	return 0;
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic int Ti3026_init(struct matrox_fb_info *minfo, struct my_timming *m)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	u_int8_t muxctrl = isInterleave(minfo) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT;
37262306a36Sopenharmony_ci	struct matrox_hw_state *hw = &minfo->hw;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	DBG(__func__)
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	memcpy(hw->DACreg, MGADACbpp32, sizeof(MGADACbpp32));
37762306a36Sopenharmony_ci	switch (minfo->fbcon.var.bits_per_pixel) {
37862306a36Sopenharmony_ci		case 4:	hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1;	/* or _8_1, they are same */
37962306a36Sopenharmony_ci			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
38062306a36Sopenharmony_ci			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT;
38162306a36Sopenharmony_ci			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8;
38262306a36Sopenharmony_ci			hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
38362306a36Sopenharmony_ci			break;
38462306a36Sopenharmony_ci		case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1;	/* or _4_1, they are same */
38562306a36Sopenharmony_ci			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
38662306a36Sopenharmony_ci			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT;
38762306a36Sopenharmony_ci			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
38862306a36Sopenharmony_ci			hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
38962306a36Sopenharmony_ci			break;
39062306a36Sopenharmony_ci		case 16:
39162306a36Sopenharmony_ci			/* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used every time) */
39262306a36Sopenharmony_ci			hw->DACreg[POS3026_XTRUECOLORCTRL] = (minfo->fbcon.var.green.length == 5) ? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565);
39362306a36Sopenharmony_ci			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT;
39462306a36Sopenharmony_ci			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2;
39562306a36Sopenharmony_ci			break;
39662306a36Sopenharmony_ci		case 24:
39762306a36Sopenharmony_ci			/* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */
39862306a36Sopenharmony_ci			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888;
39962306a36Sopenharmony_ci			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
40062306a36Sopenharmony_ci			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
40162306a36Sopenharmony_ci			break;
40262306a36Sopenharmony_ci		case 32:
40362306a36Sopenharmony_ci			/* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used every time) */
40462306a36Sopenharmony_ci			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
40562306a36Sopenharmony_ci			break;
40662306a36Sopenharmony_ci		default:
40762306a36Sopenharmony_ci			return 1;	/* TODO: failed */
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci	if (matroxfb_vgaHWinit(minfo, m)) return 1;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/* set SYNC */
41262306a36Sopenharmony_ci	hw->MiscOutReg = 0xCB;
41362306a36Sopenharmony_ci	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
41462306a36Sopenharmony_ci		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG;
41562306a36Sopenharmony_ci	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
41662306a36Sopenharmony_ci		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG;
41762306a36Sopenharmony_ci	if (m->sync & FB_SYNC_ON_GREEN)
41862306a36Sopenharmony_ci		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* set DELAY */
42162306a36Sopenharmony_ci	if (minfo->video.len < 0x400000)
42262306a36Sopenharmony_ci		hw->CRTCEXT[3] |= 0x08;
42362306a36Sopenharmony_ci	else if (minfo->video.len > 0x400000)
42462306a36Sopenharmony_ci		hw->CRTCEXT[3] |= 0x10;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* set HWCURSOR */
42762306a36Sopenharmony_ci	if (m->interlaced) {
42862306a36Sopenharmony_ci		hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci	if (m->HTotal >= 1536)
43162306a36Sopenharmony_ci		hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_BLANK4096;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	/* set interleaving */
43462306a36Sopenharmony_ci	hw->MXoptionReg &= ~0x00001000;
43562306a36Sopenharmony_ci	if (isInterleave(minfo)) hw->MXoptionReg |= 0x00001000;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	/* set DAC */
43862306a36Sopenharmony_ci	Ti3026_setpclk(minfo, m->pixclock);
43962306a36Sopenharmony_ci	return 0;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic void ti3026_setMCLK(struct matrox_fb_info *minfo, int fout)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	unsigned int f_pll;
44562306a36Sopenharmony_ci	unsigned int pclk_m, pclk_n, pclk_p;
44662306a36Sopenharmony_ci	unsigned int mclk_m, mclk_n, mclk_p;
44762306a36Sopenharmony_ci	unsigned int rfhcnt, mclk_ctl;
44862306a36Sopenharmony_ci	int tmout;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	DBG(__func__)
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	f_pll = Ti3026_calcclock(minfo, fout, minfo->max_pixel_clock, &mclk_n, &mclk_m, &mclk_p);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/* save pclk */
45562306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFC);
45662306a36Sopenharmony_ci	pclk_n = inTi3026(minfo, TVP3026_XPIXPLLDATA);
45762306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFD);
45862306a36Sopenharmony_ci	pclk_m = inTi3026(minfo, TVP3026_XPIXPLLDATA);
45962306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFE);
46062306a36Sopenharmony_ci	pclk_p = inTi3026(minfo, TVP3026_XPIXPLLDATA);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	/* stop pclk */
46362306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFE);
46462306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, 0x00);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	/* set pclk to new mclk */
46762306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFC);
46862306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, mclk_n | 0xC0);
46962306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, mclk_m);
47062306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, mclk_p | 0xB0);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* wait for PLL to lock */
47362306a36Sopenharmony_ci	for (tmout = 500000; tmout; tmout--) {
47462306a36Sopenharmony_ci		if (inTi3026(minfo, TVP3026_XPIXPLLDATA) & 0x40)
47562306a36Sopenharmony_ci			break;
47662306a36Sopenharmony_ci		udelay(10);
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci	if (!tmout)
47962306a36Sopenharmony_ci		printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n");
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	/* output pclk on mclk pin */
48262306a36Sopenharmony_ci	mclk_ctl = inTi3026(minfo, TVP3026_XMEMPLLCTRL);
48362306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7);
48462306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	/* stop MCLK */
48762306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFB);
48862306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLDATA, 0x00);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/* set mclk to new freq */
49162306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xF3);
49262306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLDATA, mclk_n | 0xC0);
49362306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLDATA, mclk_m);
49462306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLDATA, mclk_p | 0xB0);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	/* wait for PLL to lock */
49762306a36Sopenharmony_ci	for (tmout = 500000; tmout; tmout--) {
49862306a36Sopenharmony_ci		if (inTi3026(minfo, TVP3026_XMEMPLLDATA) & 0x40)
49962306a36Sopenharmony_ci			break;
50062306a36Sopenharmony_ci		udelay(10);
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci	if (!tmout)
50362306a36Sopenharmony_ci		printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n");
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	f_pll = f_pll * 333 / (10000 << mclk_p);
50662306a36Sopenharmony_ci	if (isMilleniumII(minfo)) {
50762306a36Sopenharmony_ci		rfhcnt = (f_pll - 128) / 256;
50862306a36Sopenharmony_ci		if (rfhcnt > 15)
50962306a36Sopenharmony_ci			rfhcnt = 15;
51062306a36Sopenharmony_ci	} else {
51162306a36Sopenharmony_ci		rfhcnt = (f_pll - 64) / 128;
51262306a36Sopenharmony_ci		if (rfhcnt > 15)
51362306a36Sopenharmony_ci			rfhcnt = 0;
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci	minfo->hw.MXoptionReg = (minfo->hw.MXoptionReg & ~0x000F0000) | (rfhcnt << 16);
51662306a36Sopenharmony_ci	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* output MCLK to MCLK pin */
51962306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
52062306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLCTRL, (mclk_ctl       ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	/* stop PCLK */
52362306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFE);
52462306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, 0x00);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	/* restore pclk */
52762306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFC);
52862306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, pclk_n);
52962306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, pclk_m);
53062306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, pclk_p);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/* wait for PLL to lock */
53362306a36Sopenharmony_ci	for (tmout = 500000; tmout; tmout--) {
53462306a36Sopenharmony_ci		if (inTi3026(minfo, TVP3026_XPIXPLLDATA) & 0x40)
53562306a36Sopenharmony_ci			break;
53662306a36Sopenharmony_ci		udelay(10);
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci	if (!tmout)
53962306a36Sopenharmony_ci		printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic void ti3026_ramdac_init(struct matrox_fb_info *minfo)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	DBG(__func__)
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	minfo->features.pll.vco_freq_min = 110000;
54762306a36Sopenharmony_ci	minfo->features.pll.ref_freq	 = 114545;
54862306a36Sopenharmony_ci	minfo->features.pll.feed_div_min = 2;
54962306a36Sopenharmony_ci	minfo->features.pll.feed_div_max = 24;
55062306a36Sopenharmony_ci	minfo->features.pll.in_div_min	 = 2;
55162306a36Sopenharmony_ci	minfo->features.pll.in_div_max	 = 63;
55262306a36Sopenharmony_ci	minfo->features.pll.post_shift_max = 3;
55362306a36Sopenharmony_ci	if (minfo->devflags.noinit)
55462306a36Sopenharmony_ci		return;
55562306a36Sopenharmony_ci	ti3026_setMCLK(minfo, 60000);
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic void Ti3026_restore(struct matrox_fb_info *minfo)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	int i;
56162306a36Sopenharmony_ci	unsigned char progdac[6];
56262306a36Sopenharmony_ci	struct matrox_hw_state *hw = &minfo->hw;
56362306a36Sopenharmony_ci	CRITFLAGS
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	DBG(__func__)
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci#ifdef DEBUG
56862306a36Sopenharmony_ci	dprintk(KERN_INFO "EXTVGA regs: ");
56962306a36Sopenharmony_ci	for (i = 0; i < 6; i++)
57062306a36Sopenharmony_ci		dprintk("%02X:", hw->CRTCEXT[i]);
57162306a36Sopenharmony_ci	dprintk("\n");
57262306a36Sopenharmony_ci#endif
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	CRITBEGIN
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	CRITEND
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	matroxfb_vgaHWrestore(minfo);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	CRITBEGIN
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	minfo->crtc1.panpos = -1;
58562306a36Sopenharmony_ci	for (i = 0; i < 6; i++)
58662306a36Sopenharmony_ci		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	for (i = 0; i < 21; i++) {
58962306a36Sopenharmony_ci		outTi3026(minfo, DACseq[i], hw->DACreg[i]);
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0x00);
59362306a36Sopenharmony_ci	progdac[0] = inTi3026(minfo, TVP3026_XPIXPLLDATA);
59462306a36Sopenharmony_ci	progdac[3] = inTi3026(minfo, TVP3026_XLOOPPLLDATA);
59562306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0x15);
59662306a36Sopenharmony_ci	progdac[1] = inTi3026(minfo, TVP3026_XPIXPLLDATA);
59762306a36Sopenharmony_ci	progdac[4] = inTi3026(minfo, TVP3026_XLOOPPLLDATA);
59862306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0x2A);
59962306a36Sopenharmony_ci	progdac[2] = inTi3026(minfo, TVP3026_XPIXPLLDATA);
60062306a36Sopenharmony_ci	progdac[5] = inTi3026(minfo, TVP3026_XLOOPPLLDATA);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	CRITEND
60362306a36Sopenharmony_ci	if (memcmp(hw->DACclk, progdac, 6)) {
60462306a36Sopenharmony_ci		/* agrhh... setting up PLL is very slow on Millennium... */
60562306a36Sopenharmony_ci		/* Mystique PLL is locked in few ms, but Millennium PLL lock takes about 0.15 s... */
60662306a36Sopenharmony_ci		/* Maybe even we should call schedule() ? */
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci		CRITBEGIN
60962306a36Sopenharmony_ci		outTi3026(minfo, TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
61062306a36Sopenharmony_ci		outTi3026(minfo, TVP3026_XPLLADDR, 0x2A);
61162306a36Sopenharmony_ci		outTi3026(minfo, TVP3026_XLOOPPLLDATA, 0);
61262306a36Sopenharmony_ci		outTi3026(minfo, TVP3026_XPIXPLLDATA, 0);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		outTi3026(minfo, TVP3026_XPLLADDR, 0x00);
61562306a36Sopenharmony_ci		for (i = 0; i < 3; i++)
61662306a36Sopenharmony_ci			outTi3026(minfo, TVP3026_XPIXPLLDATA, hw->DACclk[i]);
61762306a36Sopenharmony_ci		/* wait for PLL only if PLL clock requested (always for PowerMode, never for VGA) */
61862306a36Sopenharmony_ci		if (hw->MiscOutReg & 0x08) {
61962306a36Sopenharmony_ci			int tmout;
62062306a36Sopenharmony_ci			outTi3026(minfo, TVP3026_XPLLADDR, 0x3F);
62162306a36Sopenharmony_ci			for (tmout = 500000; tmout; --tmout) {
62262306a36Sopenharmony_ci				if (inTi3026(minfo, TVP3026_XPIXPLLDATA) & 0x40)
62362306a36Sopenharmony_ci					break;
62462306a36Sopenharmony_ci				udelay(10);
62562306a36Sopenharmony_ci			}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci			CRITEND
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci			if (!tmout)
63062306a36Sopenharmony_ci				printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
63162306a36Sopenharmony_ci			else
63262306a36Sopenharmony_ci				dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
63362306a36Sopenharmony_ci			CRITBEGIN
63462306a36Sopenharmony_ci		}
63562306a36Sopenharmony_ci		outTi3026(minfo, TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
63662306a36Sopenharmony_ci		outTi3026(minfo, TVP3026_XPLLADDR, 0x00);
63762306a36Sopenharmony_ci		for (i = 3; i < 6; i++)
63862306a36Sopenharmony_ci			outTi3026(minfo, TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
63962306a36Sopenharmony_ci		CRITEND
64062306a36Sopenharmony_ci		if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) {
64162306a36Sopenharmony_ci			int tmout;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci			CRITBEGIN
64462306a36Sopenharmony_ci			outTi3026(minfo, TVP3026_XPLLADDR, 0x3F);
64562306a36Sopenharmony_ci			for (tmout = 500000; tmout; --tmout) {
64662306a36Sopenharmony_ci				if (inTi3026(minfo, TVP3026_XLOOPPLLDATA) & 0x40)
64762306a36Sopenharmony_ci					break;
64862306a36Sopenharmony_ci				udelay(10);
64962306a36Sopenharmony_ci			}
65062306a36Sopenharmony_ci			CRITEND
65162306a36Sopenharmony_ci			if (!tmout)
65262306a36Sopenharmony_ci				printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
65362306a36Sopenharmony_ci			else
65462306a36Sopenharmony_ci				dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout);
65562306a36Sopenharmony_ci		}
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci#ifdef DEBUG
65962306a36Sopenharmony_ci	dprintk(KERN_DEBUG "3026DACregs ");
66062306a36Sopenharmony_ci	for (i = 0; i < 21; i++) {
66162306a36Sopenharmony_ci		dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]);
66262306a36Sopenharmony_ci		if ((i & 0x7) == 0x7) dprintk(KERN_DEBUG "continuing... ");
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci	dprintk(KERN_DEBUG "DACclk ");
66562306a36Sopenharmony_ci	for (i = 0; i < 6; i++)
66662306a36Sopenharmony_ci		dprintk("C%02X=%02X ", i, hw->DACclk[i]);
66762306a36Sopenharmony_ci	dprintk("\n");
66862306a36Sopenharmony_ci#endif
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic void Ti3026_reset(struct matrox_fb_info *minfo)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	DBG(__func__)
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	ti3026_ramdac_init(minfo);
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic struct matrox_altout ti3026_output = {
67962306a36Sopenharmony_ci	.name	 = "Primary output",
68062306a36Sopenharmony_ci};
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_cistatic int Ti3026_preinit(struct matrox_fb_info *minfo)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	static const int vxres_mill2[] = { 512,        640, 768,  800,  832,  960,
68562306a36Sopenharmony_ci					  1024, 1152, 1280,      1600, 1664, 1920,
68662306a36Sopenharmony_ci					  2048, 0};
68762306a36Sopenharmony_ci	static const int vxres_mill1[] = {             640, 768,  800,        960,
68862306a36Sopenharmony_ci					  1024, 1152, 1280,      1600,       1920,
68962306a36Sopenharmony_ci					  2048, 0};
69062306a36Sopenharmony_ci	struct matrox_hw_state *hw = &minfo->hw;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	DBG(__func__)
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	minfo->millenium = 1;
69562306a36Sopenharmony_ci	minfo->milleniumII = (minfo->pcidev->device != PCI_DEVICE_ID_MATROX_MIL);
69662306a36Sopenharmony_ci	minfo->capable.cfb4 = 1;
69762306a36Sopenharmony_ci	minfo->capable.text = 1; /* isMilleniumII(minfo); */
69862306a36Sopenharmony_ci	minfo->capable.vxres = isMilleniumII(minfo) ? vxres_mill2 : vxres_mill1;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	minfo->outputs[0].data = minfo;
70162306a36Sopenharmony_ci	minfo->outputs[0].output = &ti3026_output;
70262306a36Sopenharmony_ci	minfo->outputs[0].src = minfo->outputs[0].default_src;
70362306a36Sopenharmony_ci	minfo->outputs[0].mode = MATROXFB_OUTPUT_MODE_MONITOR;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	if (minfo->devflags.noinit)
70662306a36Sopenharmony_ci		return 0;
70762306a36Sopenharmony_ci	/* preserve VGA I/O, BIOS and PPC */
70862306a36Sopenharmony_ci	hw->MXoptionReg &= 0xC0000100;
70962306a36Sopenharmony_ci	hw->MXoptionReg |= 0x002C0000;
71062306a36Sopenharmony_ci	if (minfo->devflags.novga)
71162306a36Sopenharmony_ci		hw->MXoptionReg &= ~0x00000100;
71262306a36Sopenharmony_ci	if (minfo->devflags.nobios)
71362306a36Sopenharmony_ci		hw->MXoptionReg &= ~0x40000000;
71462306a36Sopenharmony_ci	if (minfo->devflags.nopciretry)
71562306a36Sopenharmony_ci		hw->MXoptionReg |=  0x20000000;
71662306a36Sopenharmony_ci	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	minfo->accel.ramdac_rev = inTi3026(minfo, TVP3026_XSILICONREV);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED);
72162306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR);
72262306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0x2A);
72562306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XLOOPPLLDATA, 0x00);
72662306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, 0x00);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	mga_outb(M_MISC_REG, 0x67);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	mga_outl(M_RESET, 1);
73362306a36Sopenharmony_ci	udelay(250);
73462306a36Sopenharmony_ci	mga_outl(M_RESET, 0);
73562306a36Sopenharmony_ci	udelay(250);
73662306a36Sopenharmony_ci	mga_outl(M_MACCESS, 0x00008000);
73762306a36Sopenharmony_ci	udelay(10);
73862306a36Sopenharmony_ci	return 0;
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistruct matrox_switch matrox_millennium = {
74262306a36Sopenharmony_ci	.preinit	= Ti3026_preinit,
74362306a36Sopenharmony_ci	.reset		= Ti3026_reset,
74462306a36Sopenharmony_ci	.init		= Ti3026_init,
74562306a36Sopenharmony_ci	.restore	= Ti3026_restore
74662306a36Sopenharmony_ci};
74762306a36Sopenharmony_ciEXPORT_SYMBOL(matrox_millennium);
74862306a36Sopenharmony_ci#endif
74962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
750