18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Portions Copyright (c) 2001 Matrox Graphics Inc.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Version: 1.65 2002/08/14
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Contributors: "menion?" <menion@mindless.com>
158c2ecf20Sopenharmony_ci *                     Betatesting, fixes, ideas
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci *               "Kurt Garloff" <garloff@suse.de>
188c2ecf20Sopenharmony_ci *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci *               "Tom Rini" <trini@kernel.crashing.org>
218c2ecf20Sopenharmony_ci *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci *               "Bibek Sahu" <scorpio@dodds.net>
248c2ecf20Sopenharmony_ci *                     Access device through readb|w|l and write b|w|l
258c2ecf20Sopenharmony_ci *                     Extensive debugging stuff
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci *               "Daniel Haun" <haund@usa.net>
288c2ecf20Sopenharmony_ci *                     Testing, hardware cursor fixes
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci *               "Scott Wood" <sawst46+@pitt.edu>
318c2ecf20Sopenharmony_ci *                     Fixes
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
348c2ecf20Sopenharmony_ci *                     Betatesting
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci *               "Kelly French" <targon@hazmat.com>
378c2ecf20Sopenharmony_ci *               "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
388c2ecf20Sopenharmony_ci *                     Betatesting, bug reporting
398c2ecf20Sopenharmony_ci *
408c2ecf20Sopenharmony_ci *               "Pablo Bianucci" <pbian@pccp.com.ar>
418c2ecf20Sopenharmony_ci *                     Fixes, ideas, betatesting
428c2ecf20Sopenharmony_ci *
438c2ecf20Sopenharmony_ci *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
448c2ecf20Sopenharmony_ci *                     Fixes, enhandcements, ideas, betatesting
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
478c2ecf20Sopenharmony_ci *                     PPC betatesting, PPC support, backward compatibility
488c2ecf20Sopenharmony_ci *
498c2ecf20Sopenharmony_ci *               "Paul Womar" <Paul@pwomar.demon.co.uk>
508c2ecf20Sopenharmony_ci *               "Owen Waller" <O.Waller@ee.qub.ac.uk>
518c2ecf20Sopenharmony_ci *                     PPC betatesting
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci *               "Thomas Pornin" <pornin@bolet.ens.fr>
548c2ecf20Sopenharmony_ci *                     Alpha betatesting
558c2ecf20Sopenharmony_ci *
568c2ecf20Sopenharmony_ci *               "Pieter van Leuven" <pvl@iae.nl>
578c2ecf20Sopenharmony_ci *               "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
588c2ecf20Sopenharmony_ci *                     G100 testing
598c2ecf20Sopenharmony_ci *
608c2ecf20Sopenharmony_ci *               "H. Peter Arvin" <hpa@transmeta.com>
618c2ecf20Sopenharmony_ci *                     Ideas
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci *               "Cort Dougan" <cort@cs.nmt.edu>
648c2ecf20Sopenharmony_ci *                     CHRP fixes and PReP cleanup
658c2ecf20Sopenharmony_ci *
668c2ecf20Sopenharmony_ci *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
678c2ecf20Sopenharmony_ci *                     G400 support
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci * (following author is not in any relation with this code, but his code
708c2ecf20Sopenharmony_ci *  is included in this driver)
718c2ecf20Sopenharmony_ci *
728c2ecf20Sopenharmony_ci * Based on framebuffer driver for VBE 2.0 compliant graphic boards
738c2ecf20Sopenharmony_ci *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
748c2ecf20Sopenharmony_ci *
758c2ecf20Sopenharmony_ci * (following author is not in any relation with this code, but his ideas
768c2ecf20Sopenharmony_ci *  were used when writing this driver)
778c2ecf20Sopenharmony_ci *
788c2ecf20Sopenharmony_ci *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci */
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#include "matroxfb_Ti3026.h"
848c2ecf20Sopenharmony_ci#include "matroxfb_misc.h"
858c2ecf20Sopenharmony_ci#include "matroxfb_accel.h"
868c2ecf20Sopenharmony_ci#include <linux/matroxfb.h>
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MILLENIUM
898c2ecf20Sopenharmony_ci#define outTi3026 matroxfb_DAC_out
908c2ecf20Sopenharmony_ci#define inTi3026 matroxfb_DAC_in
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#define TVP3026_INDEX		0x00
938c2ecf20Sopenharmony_ci#define TVP3026_PALWRADD	0x00
948c2ecf20Sopenharmony_ci#define TVP3026_PALDATA		0x01
958c2ecf20Sopenharmony_ci#define TVP3026_PIXRDMSK	0x02
968c2ecf20Sopenharmony_ci#define TVP3026_PALRDADD	0x03
978c2ecf20Sopenharmony_ci#define TVP3026_CURCOLWRADD	0x04
988c2ecf20Sopenharmony_ci#define     TVP3026_CLOVERSCAN		0x00
998c2ecf20Sopenharmony_ci#define     TVP3026_CLCOLOR0		0x01
1008c2ecf20Sopenharmony_ci#define     TVP3026_CLCOLOR1		0x02
1018c2ecf20Sopenharmony_ci#define     TVP3026_CLCOLOR2		0x03
1028c2ecf20Sopenharmony_ci#define TVP3026_CURCOLDATA	0x05
1038c2ecf20Sopenharmony_ci#define TVP3026_CURCOLRDADD	0x07
1048c2ecf20Sopenharmony_ci#define TVP3026_CURCTRL		0x09
1058c2ecf20Sopenharmony_ci#define TVP3026_X_DATAREG	0x0A
1068c2ecf20Sopenharmony_ci#define TVP3026_CURRAMDATA	0x0B
1078c2ecf20Sopenharmony_ci#define TVP3026_CURPOSXL	0x0C
1088c2ecf20Sopenharmony_ci#define TVP3026_CURPOSXH	0x0D
1098c2ecf20Sopenharmony_ci#define TVP3026_CURPOSYL	0x0E
1108c2ecf20Sopenharmony_ci#define TVP3026_CURPOSYH	0x0F
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci#define TVP3026_XSILICONREV	0x01
1138c2ecf20Sopenharmony_ci#define TVP3026_XCURCTRL	0x06
1148c2ecf20Sopenharmony_ci#define     TVP3026_XCURCTRL_DIS	0x00	/* transparent, transparent, transparent, transparent */
1158c2ecf20Sopenharmony_ci#define     TVP3026_XCURCTRL_3COLOR	0x01	/* transparent, 0, 1, 2 */
1168c2ecf20Sopenharmony_ci#define     TVP3026_XCURCTRL_XGA	0x02	/* 0, 1, transparent, complement */
1178c2ecf20Sopenharmony_ci#define     TVP3026_XCURCTRL_XWIN	0x03	/* transparent, transparent, 0, 1 */
1188c2ecf20Sopenharmony_ci#define     TVP3026_XCURCTRL_BLANK2048	0x00
1198c2ecf20Sopenharmony_ci#define     TVP3026_XCURCTRL_BLANK4096	0x10
1208c2ecf20Sopenharmony_ci#define     TVP3026_XCURCTRL_INTERLACED	0x20
1218c2ecf20Sopenharmony_ci#define     TVP3026_XCURCTRL_ODD	0x00 /* ext.signal ODD/\EVEN */
1228c2ecf20Sopenharmony_ci#define     TVP3026_XCURCTRL_EVEN	0x40 /* ext.signal EVEN/\ODD */
1238c2ecf20Sopenharmony_ci#define     TVP3026_XCURCTRL_INDIRECT	0x00
1248c2ecf20Sopenharmony_ci#define     TVP3026_XCURCTRL_DIRECT	0x80
1258c2ecf20Sopenharmony_ci#define TVP3026_XLATCHCTRL	0x0F
1268c2ecf20Sopenharmony_ci#define     TVP3026_XLATCHCTRL_1_1	0x06
1278c2ecf20Sopenharmony_ci#define     TVP3026_XLATCHCTRL_2_1	0x07
1288c2ecf20Sopenharmony_ci#define     TVP3026_XLATCHCTRL_4_1	0x06
1298c2ecf20Sopenharmony_ci#define     TVP3026_XLATCHCTRL_8_1	0x06
1308c2ecf20Sopenharmony_ci#define     TVP3026_XLATCHCTRL_16_1	0x06
1318c2ecf20Sopenharmony_ci#define     TVP3026A_XLATCHCTRL_4_3	0x06	/* ??? do not understand... but it works... !!! */
1328c2ecf20Sopenharmony_ci#define     TVP3026A_XLATCHCTRL_8_3	0x07
1338c2ecf20Sopenharmony_ci#define     TVP3026B_XLATCHCTRL_4_3	0x08
1348c2ecf20Sopenharmony_ci#define     TVP3026B_XLATCHCTRL_8_3	0x06	/* ??? do not understand... but it works... !!! */
1358c2ecf20Sopenharmony_ci#define TVP3026_XTRUECOLORCTRL	0x18
1368c2ecf20Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL	0x00
1378c2ecf20Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP	0x20
1388c2ecf20Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR		0x80
1398c2ecf20Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_TRUECOLOR		0x40 /* paletized */
1408c2ecf20Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_DIRECTCOLOR		0x00
1418c2ecf20Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_24_ALTERNATE		0x08 /* 5:4/5:2 instead of 4:3/8:3 */
1428c2ecf20Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_RGB_888		0x16 /* 4:3/8:3 (or 5:4/5:2) */
1438c2ecf20Sopenharmony_ci#define	    TVP3026_XTRUECOLORCTRL_BGR_888		0x17
1448c2ecf20Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_ORGB_8888		0x06
1458c2ecf20Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_BGRO_8888		0x07
1468c2ecf20Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_RGB_565		0x05
1478c2ecf20Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_ORGB_1555		0x04
1488c2ecf20Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_RGB_664		0x03
1498c2ecf20Sopenharmony_ci#define     TVP3026_XTRUECOLORCTRL_RGBO_4444		0x01
1508c2ecf20Sopenharmony_ci#define TVP3026_XMUXCTRL	0x19
1518c2ecf20Sopenharmony_ci#define     TVP3026_XMUXCTRL_MEMORY_8BIT			0x01 /* - */
1528c2ecf20Sopenharmony_ci#define     TVP3026_XMUXCTRL_MEMORY_16BIT			0x02 /* - */
1538c2ecf20Sopenharmony_ci#define     TVP3026_XMUXCTRL_MEMORY_32BIT			0x03 /* 2MB RAM, 512K * 4 */
1548c2ecf20Sopenharmony_ci#define     TVP3026_XMUXCTRL_MEMORY_64BIT			0x04 /* >2MB RAM, 512K * 8 & more */
1558c2ecf20Sopenharmony_ci#define     TVP3026_XMUXCTRL_PIXEL_4BIT				0x40 /* L0,H0,L1,H1... */
1568c2ecf20Sopenharmony_ci#define     TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED			0x60 /* H0,L0,H1,L1... */
1578c2ecf20Sopenharmony_ci#define     TVP3026_XMUXCTRL_PIXEL_8BIT				0x48
1588c2ecf20Sopenharmony_ci#define     TVP3026_XMUXCTRL_PIXEL_16BIT			0x50
1598c2ecf20Sopenharmony_ci#define     TVP3026_XMUXCTRL_PIXEL_32BIT			0x58
1608c2ecf20Sopenharmony_ci#define     TVP3026_XMUXCTRL_VGA				0x98 /* VGA MEMORY, 8BIT PIXEL */
1618c2ecf20Sopenharmony_ci#define TVP3026_XCLKCTRL	0x1A
1628c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV1	0x00
1638c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV2	0x10
1648c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV4	0x20
1658c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV8	0x30
1668c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV16	0x40
1678c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV32	0x50
1688c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_DIV64	0x60
1698c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_CLKSTOPPED	0x70
1708c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_CLK0	0x00
1718c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_CLK1   0x01
1728c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_CLK2	0x02	/* CLK2 is TTL source*/
1738c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_NCLK2	0x03	/* not CLK2 is TTL source */
1748c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_ECLK2	0x04	/* CLK2 and not CLK2 is ECL source */
1758c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_PLL	0x05
1768c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_DIS	0x06	/* disable & poweroff internal clock */
1778c2ecf20Sopenharmony_ci#define     TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07
1788c2ecf20Sopenharmony_ci#define TVP3026_XPALETTEPAGE	0x1C
1798c2ecf20Sopenharmony_ci#define TVP3026_XGENCTRL	0x1D
1808c2ecf20Sopenharmony_ci#define     TVP3026_XGENCTRL_HSYNC_POS	0x00
1818c2ecf20Sopenharmony_ci#define     TVP3026_XGENCTRL_HSYNC_NEG	0x01
1828c2ecf20Sopenharmony_ci#define     TVP3026_XGENCTRL_VSYNC_POS	0x00
1838c2ecf20Sopenharmony_ci#define     TVP3026_XGENCTRL_VSYNC_NEG	0x02
1848c2ecf20Sopenharmony_ci#define     TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00
1858c2ecf20Sopenharmony_ci#define     TVP3026_XGENCTRL_BIG_ENDIAN    0x08
1868c2ecf20Sopenharmony_ci#define     TVP3026_XGENCTRL_BLACK_0IRE		0x00
1878c2ecf20Sopenharmony_ci#define     TVP3026_XGENCTRL_BLACK_75IRE	0x10
1888c2ecf20Sopenharmony_ci#define     TVP3026_XGENCTRL_NO_SYNC_ON_GREEN	0x00
1898c2ecf20Sopenharmony_ci#define     TVP3026_XGENCTRL_SYNC_ON_GREEN	0x20
1908c2ecf20Sopenharmony_ci#define     TVP3026_XGENCTRL_OVERSCAN_DIS	0x00
1918c2ecf20Sopenharmony_ci#define     TVP3026_XGENCTRL_OVERSCAN_EN	0x40
1928c2ecf20Sopenharmony_ci#define TVP3026_XMISCCTRL	0x1E
1938c2ecf20Sopenharmony_ci#define     TVP3026_XMISCCTRL_DAC_PUP	0x00
1948c2ecf20Sopenharmony_ci#define     TVP3026_XMISCCTRL_DAC_PDOWN	0x01
1958c2ecf20Sopenharmony_ci#define     TVP3026_XMISCCTRL_DAC_EXT	0x00 /* or 8, bit 3 is ignored */
1968c2ecf20Sopenharmony_ci#define     TVP3026_XMISCCTRL_DAC_6BIT	0x04
1978c2ecf20Sopenharmony_ci#define     TVP3026_XMISCCTRL_DAC_8BIT	0x0C
1988c2ecf20Sopenharmony_ci#define     TVP3026_XMISCCTRL_PSEL_DIS	0x00
1998c2ecf20Sopenharmony_ci#define     TVP3026_XMISCCTRL_PSEL_EN	0x10
2008c2ecf20Sopenharmony_ci#define     TVP3026_XMISCCTRL_PSEL_LOW	0x00 /* PSEL high selects directcolor */
2018c2ecf20Sopenharmony_ci#define     TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */
2028c2ecf20Sopenharmony_ci#define TVP3026_XGENIOCTRL	0x2A
2038c2ecf20Sopenharmony_ci#define TVP3026_XGENIODATA	0x2B
2048c2ecf20Sopenharmony_ci#define TVP3026_XPLLADDR	0x2C
2058c2ecf20Sopenharmony_ci#define     TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX))
2068c2ecf20Sopenharmony_ci#define     TVP3026_XPLLDATA_N		0x00
2078c2ecf20Sopenharmony_ci#define     TVP3026_XPLLDATA_M		0x01
2088c2ecf20Sopenharmony_ci#define     TVP3026_XPLLDATA_P		0x02
2098c2ecf20Sopenharmony_ci#define     TVP3026_XPLLDATA_STAT	0x03
2108c2ecf20Sopenharmony_ci#define TVP3026_XPIXPLLDATA	0x2D
2118c2ecf20Sopenharmony_ci#define TVP3026_XMEMPLLDATA	0x2E
2128c2ecf20Sopenharmony_ci#define TVP3026_XLOOPPLLDATA	0x2F
2138c2ecf20Sopenharmony_ci#define TVP3026_XCOLKEYOVRMIN	0x30
2148c2ecf20Sopenharmony_ci#define TVP3026_XCOLKEYOVRMAX	0x31
2158c2ecf20Sopenharmony_ci#define TVP3026_XCOLKEYREDMIN	0x32
2168c2ecf20Sopenharmony_ci#define TVP3026_XCOLKEYREDMAX	0x33
2178c2ecf20Sopenharmony_ci#define TVP3026_XCOLKEYGREENMIN	0x34
2188c2ecf20Sopenharmony_ci#define TVP3026_XCOLKEYGREENMAX	0x35
2198c2ecf20Sopenharmony_ci#define TVP3026_XCOLKEYBLUEMIN	0x36
2208c2ecf20Sopenharmony_ci#define TVP3026_XCOLKEYBLUEMAX	0x37
2218c2ecf20Sopenharmony_ci#define TVP3026_XCOLKEYCTRL	0x38
2228c2ecf20Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_OVR_EN	0x01
2238c2ecf20Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_RED_EN	0x02
2248c2ecf20Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_GREEN_EN 0x04
2258c2ecf20Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_BLUE_EN	0x08
2268c2ecf20Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_NEGATE	0x10
2278c2ecf20Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_ZOOM1	0x00
2288c2ecf20Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_ZOOM2	0x20
2298c2ecf20Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_ZOOM4	0x40
2308c2ecf20Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_ZOOM8	0x60
2318c2ecf20Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_ZOOM16	0x80
2328c2ecf20Sopenharmony_ci#define     TVP3026_XCOLKEYCTRL_ZOOM32	0xA0
2338c2ecf20Sopenharmony_ci#define TVP3026_XMEMPLLCTRL	0x39
2348c2ecf20Sopenharmony_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 */
2358c2ecf20Sopenharmony_ci#define     TVP3026_XMEMPLLCTRL_STROBEMKC4	0x08
2368c2ecf20Sopenharmony_ci#define     TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK	0x00	/* MKC4 */
2378c2ecf20Sopenharmony_ci#define     TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL	0x10	/* MKC4 */
2388c2ecf20Sopenharmony_ci#define     TVP3026_XMEMPLLCTRL_RCLK_PIXPLL	0x00
2398c2ecf20Sopenharmony_ci#define     TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL	0x20
2408c2ecf20Sopenharmony_ci#define     TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN	0x40	/* dot clock divided by loop pclk N prescaler */
2418c2ecf20Sopenharmony_ci#define TVP3026_XSENSETEST	0x3A
2428c2ecf20Sopenharmony_ci#define TVP3026_XTESTMODEDATA	0x3B
2438c2ecf20Sopenharmony_ci#define TVP3026_XCRCREML	0x3C
2448c2ecf20Sopenharmony_ci#define TVP3026_XCRCREMH	0x3D
2458c2ecf20Sopenharmony_ci#define TVP3026_XCRCBITSEL	0x3E
2468c2ecf20Sopenharmony_ci#define TVP3026_XID		0x3F
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic const unsigned char DACseq[] =
2498c2ecf20Sopenharmony_ci{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL,
2508c2ecf20Sopenharmony_ci  TVP3026_XMUXCTRL, TVP3026_XCLKCTRL,
2518c2ecf20Sopenharmony_ci  TVP3026_XPALETTEPAGE,
2528c2ecf20Sopenharmony_ci  TVP3026_XGENCTRL,
2538c2ecf20Sopenharmony_ci  TVP3026_XMISCCTRL,
2548c2ecf20Sopenharmony_ci  TVP3026_XGENIOCTRL,
2558c2ecf20Sopenharmony_ci  TVP3026_XGENIODATA,
2568c2ecf20Sopenharmony_ci  TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX,
2578c2ecf20Sopenharmony_ci  TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX,
2588c2ecf20Sopenharmony_ci  TVP3026_XCOLKEYCTRL,
2598c2ecf20Sopenharmony_ci  TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL };
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci#define POS3026_XLATCHCTRL	0
2628c2ecf20Sopenharmony_ci#define POS3026_XTRUECOLORCTRL	1
2638c2ecf20Sopenharmony_ci#define POS3026_XMUXCTRL	2
2648c2ecf20Sopenharmony_ci#define POS3026_XCLKCTRL	3
2658c2ecf20Sopenharmony_ci#define POS3026_XGENCTRL	5
2668c2ecf20Sopenharmony_ci#define POS3026_XMISCCTRL	6
2678c2ecf20Sopenharmony_ci#define POS3026_XMEMPLLCTRL	18
2688c2ecf20Sopenharmony_ci#define POS3026_XCURCTRL	20
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic const unsigned char MGADACbpp32[] =
2718c2ecf20Sopenharmony_ci{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888,
2728c2ecf20Sopenharmony_ci  0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL,
2738c2ecf20Sopenharmony_ci  0x00,
2748c2ecf20Sopenharmony_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,
2758c2ecf20Sopenharmony_ci  TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH,
2768c2ecf20Sopenharmony_ci  0x00,
2778c2ecf20Sopenharmony_ci  0x1E,
2788c2ecf20Sopenharmony_ci  0xFF, 0xFF, 0xFF, 0xFF,
2798c2ecf20Sopenharmony_ci  0xFF, 0xFF, 0xFF, 0xFF,
2808c2ecf20Sopenharmony_ci  TVP3026_XCOLKEYCTRL_ZOOM1,
2818c2ecf20Sopenharmony_ci  0x00, 0x00, TVP3026_XCURCTRL_DIS };
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic int Ti3026_calcclock(const struct matrox_fb_info *minfo,
2848c2ecf20Sopenharmony_ci			    unsigned int freq, unsigned int fmax, int *in,
2858c2ecf20Sopenharmony_ci			    int *feed, int *post)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	unsigned int fvco;
2888c2ecf20Sopenharmony_ci	unsigned int lin, lfeed, lpost;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	DBG(__func__)
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	fvco = PLL_calcclock(minfo, freq, fmax, &lin, &lfeed, &lpost);
2938c2ecf20Sopenharmony_ci	fvco >>= (*post = lpost);
2948c2ecf20Sopenharmony_ci	*in = 64 - lin;
2958c2ecf20Sopenharmony_ci	*feed = 64 - lfeed;
2968c2ecf20Sopenharmony_ci	return fvco;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic int Ti3026_setpclk(struct matrox_fb_info *minfo, int clk)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	unsigned int f_pll;
3028c2ecf20Sopenharmony_ci	unsigned int pixfeed, pixin, pixpost;
3038c2ecf20Sopenharmony_ci	struct matrox_hw_state *hw = &minfo->hw;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	DBG(__func__)
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	f_pll = Ti3026_calcclock(minfo, clk, minfo->max_pixel_clock, &pixin, &pixfeed, &pixpost);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	hw->DACclk[0] = pixin | 0xC0;
3108c2ecf20Sopenharmony_ci	hw->DACclk[1] = pixfeed;
3118c2ecf20Sopenharmony_ci	hw->DACclk[2] = pixpost | 0xB0;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	{
3148c2ecf20Sopenharmony_ci		unsigned int loopfeed, loopin, looppost, loopdiv, z;
3158c2ecf20Sopenharmony_ci		unsigned int Bpp;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		Bpp = minfo->curr.final_bppShift;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci		if (minfo->fbcon.var.bits_per_pixel == 24) {
3208c2ecf20Sopenharmony_ci			loopfeed = 3;		/* set lm to any possible value */
3218c2ecf20Sopenharmony_ci			loopin = 3 * 32 / Bpp;
3228c2ecf20Sopenharmony_ci		} else {
3238c2ecf20Sopenharmony_ci			loopfeed = 4;
3248c2ecf20Sopenharmony_ci			loopin = 4 * 32 / Bpp;
3258c2ecf20Sopenharmony_ci		}
3268c2ecf20Sopenharmony_ci		z = (110000 * loopin) / (f_pll * loopfeed);
3278c2ecf20Sopenharmony_ci		loopdiv = 0; /* div 2 */
3288c2ecf20Sopenharmony_ci		if (z < 2)
3298c2ecf20Sopenharmony_ci			looppost = 0;
3308c2ecf20Sopenharmony_ci		else if (z < 4)
3318c2ecf20Sopenharmony_ci			looppost = 1;
3328c2ecf20Sopenharmony_ci		else if (z < 8)
3338c2ecf20Sopenharmony_ci			looppost = 2;
3348c2ecf20Sopenharmony_ci		else {
3358c2ecf20Sopenharmony_ci			looppost = 3;
3368c2ecf20Sopenharmony_ci			loopdiv = z/16;
3378c2ecf20Sopenharmony_ci		}
3388c2ecf20Sopenharmony_ci		if (minfo->fbcon.var.bits_per_pixel == 24) {
3398c2ecf20Sopenharmony_ci			hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
3408c2ecf20Sopenharmony_ci			hw->DACclk[4] = (65 - loopfeed) | 0x80;
3418c2ecf20Sopenharmony_ci			if (minfo->accel.ramdac_rev > 0x20) {
3428c2ecf20Sopenharmony_ci				if (isInterleave(minfo))
3438c2ecf20Sopenharmony_ci					hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3;
3448c2ecf20Sopenharmony_ci				else {
3458c2ecf20Sopenharmony_ci					hw->DACclk[4] &= ~0xC0;
3468c2ecf20Sopenharmony_ci					hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3;
3478c2ecf20Sopenharmony_ci				}
3488c2ecf20Sopenharmony_ci			} else {
3498c2ecf20Sopenharmony_ci				if (isInterleave(minfo))
3508c2ecf20Sopenharmony_ci					;	/* default... */
3518c2ecf20Sopenharmony_ci				else {
3528c2ecf20Sopenharmony_ci					hw->DACclk[4] ^= 0xC0;	/* change from 0x80 to 0x40 */
3538c2ecf20Sopenharmony_ci					hw->DACreg[POS3026_XLATCHCTRL] = TVP3026A_XLATCHCTRL_4_3;
3548c2ecf20Sopenharmony_ci				}
3558c2ecf20Sopenharmony_ci			}
3568c2ecf20Sopenharmony_ci			hw->DACclk[5] = looppost | 0xF8;
3578c2ecf20Sopenharmony_ci			if (minfo->devflags.mga_24bpp_fix)
3588c2ecf20Sopenharmony_ci				hw->DACclk[5] ^= 0x40;
3598c2ecf20Sopenharmony_ci		} else {
3608c2ecf20Sopenharmony_ci			hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
3618c2ecf20Sopenharmony_ci			hw->DACclk[4] = 65 - loopfeed;
3628c2ecf20Sopenharmony_ci			hw->DACclk[5] = looppost | 0xF0;
3638c2ecf20Sopenharmony_ci		}
3648c2ecf20Sopenharmony_ci		hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL;
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci	return 0;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic int Ti3026_init(struct matrox_fb_info *minfo, struct my_timming *m)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	u_int8_t muxctrl = isInterleave(minfo) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT;
3728c2ecf20Sopenharmony_ci	struct matrox_hw_state *hw = &minfo->hw;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	DBG(__func__)
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	memcpy(hw->DACreg, MGADACbpp32, sizeof(MGADACbpp32));
3778c2ecf20Sopenharmony_ci	switch (minfo->fbcon.var.bits_per_pixel) {
3788c2ecf20Sopenharmony_ci		case 4:	hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1;	/* or _8_1, they are same */
3798c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
3808c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT;
3818c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8;
3828c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
3838c2ecf20Sopenharmony_ci			break;
3848c2ecf20Sopenharmony_ci		case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1;	/* or _4_1, they are same */
3858c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
3868c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT;
3878c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
3888c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
3898c2ecf20Sopenharmony_ci			break;
3908c2ecf20Sopenharmony_ci		case 16:
3918c2ecf20Sopenharmony_ci			/* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used every time) */
3928c2ecf20Sopenharmony_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);
3938c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT;
3948c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2;
3958c2ecf20Sopenharmony_ci			break;
3968c2ecf20Sopenharmony_ci		case 24:
3978c2ecf20Sopenharmony_ci			/* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */
3988c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888;
3998c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
4008c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
4018c2ecf20Sopenharmony_ci			break;
4028c2ecf20Sopenharmony_ci		case 32:
4038c2ecf20Sopenharmony_ci			/* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used every time) */
4048c2ecf20Sopenharmony_ci			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
4058c2ecf20Sopenharmony_ci			break;
4068c2ecf20Sopenharmony_ci		default:
4078c2ecf20Sopenharmony_ci			return 1;	/* TODO: failed */
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci	if (matroxfb_vgaHWinit(minfo, m)) return 1;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/* set SYNC */
4128c2ecf20Sopenharmony_ci	hw->MiscOutReg = 0xCB;
4138c2ecf20Sopenharmony_ci	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
4148c2ecf20Sopenharmony_ci		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG;
4158c2ecf20Sopenharmony_ci	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
4168c2ecf20Sopenharmony_ci		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG;
4178c2ecf20Sopenharmony_ci	if (m->sync & FB_SYNC_ON_GREEN)
4188c2ecf20Sopenharmony_ci		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	/* set DELAY */
4218c2ecf20Sopenharmony_ci	if (minfo->video.len < 0x400000)
4228c2ecf20Sopenharmony_ci		hw->CRTCEXT[3] |= 0x08;
4238c2ecf20Sopenharmony_ci	else if (minfo->video.len > 0x400000)
4248c2ecf20Sopenharmony_ci		hw->CRTCEXT[3] |= 0x10;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	/* set HWCURSOR */
4278c2ecf20Sopenharmony_ci	if (m->interlaced) {
4288c2ecf20Sopenharmony_ci		hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED;
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci	if (m->HTotal >= 1536)
4318c2ecf20Sopenharmony_ci		hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_BLANK4096;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	/* set interleaving */
4348c2ecf20Sopenharmony_ci	hw->MXoptionReg &= ~0x00001000;
4358c2ecf20Sopenharmony_ci	if (isInterleave(minfo)) hw->MXoptionReg |= 0x00001000;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	/* set DAC */
4388c2ecf20Sopenharmony_ci	Ti3026_setpclk(minfo, m->pixclock);
4398c2ecf20Sopenharmony_ci	return 0;
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic void ti3026_setMCLK(struct matrox_fb_info *minfo, int fout)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	unsigned int f_pll;
4458c2ecf20Sopenharmony_ci	unsigned int pclk_m, pclk_n, pclk_p;
4468c2ecf20Sopenharmony_ci	unsigned int mclk_m, mclk_n, mclk_p;
4478c2ecf20Sopenharmony_ci	unsigned int rfhcnt, mclk_ctl;
4488c2ecf20Sopenharmony_ci	int tmout;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	DBG(__func__)
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	f_pll = Ti3026_calcclock(minfo, fout, minfo->max_pixel_clock, &mclk_n, &mclk_m, &mclk_p);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	/* save pclk */
4558c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFC);
4568c2ecf20Sopenharmony_ci	pclk_n = inTi3026(minfo, TVP3026_XPIXPLLDATA);
4578c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFD);
4588c2ecf20Sopenharmony_ci	pclk_m = inTi3026(minfo, TVP3026_XPIXPLLDATA);
4598c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFE);
4608c2ecf20Sopenharmony_ci	pclk_p = inTi3026(minfo, TVP3026_XPIXPLLDATA);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	/* stop pclk */
4638c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFE);
4648c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, 0x00);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/* set pclk to new mclk */
4678c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFC);
4688c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, mclk_n | 0xC0);
4698c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, mclk_m);
4708c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, mclk_p | 0xB0);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	/* wait for PLL to lock */
4738c2ecf20Sopenharmony_ci	for (tmout = 500000; tmout; tmout--) {
4748c2ecf20Sopenharmony_ci		if (inTi3026(minfo, TVP3026_XPIXPLLDATA) & 0x40)
4758c2ecf20Sopenharmony_ci			break;
4768c2ecf20Sopenharmony_ci		udelay(10);
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci	if (!tmout)
4798c2ecf20Sopenharmony_ci		printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n");
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	/* output pclk on mclk pin */
4828c2ecf20Sopenharmony_ci	mclk_ctl = inTi3026(minfo, TVP3026_XMEMPLLCTRL);
4838c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7);
4848c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	/* stop MCLK */
4878c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFB);
4888c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLDATA, 0x00);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	/* set mclk to new freq */
4918c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xF3);
4928c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLDATA, mclk_n | 0xC0);
4938c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLDATA, mclk_m);
4948c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLDATA, mclk_p | 0xB0);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	/* wait for PLL to lock */
4978c2ecf20Sopenharmony_ci	for (tmout = 500000; tmout; tmout--) {
4988c2ecf20Sopenharmony_ci		if (inTi3026(minfo, TVP3026_XMEMPLLDATA) & 0x40)
4998c2ecf20Sopenharmony_ci			break;
5008c2ecf20Sopenharmony_ci		udelay(10);
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci	if (!tmout)
5038c2ecf20Sopenharmony_ci		printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n");
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	f_pll = f_pll * 333 / (10000 << mclk_p);
5068c2ecf20Sopenharmony_ci	if (isMilleniumII(minfo)) {
5078c2ecf20Sopenharmony_ci		rfhcnt = (f_pll - 128) / 256;
5088c2ecf20Sopenharmony_ci		if (rfhcnt > 15)
5098c2ecf20Sopenharmony_ci			rfhcnt = 15;
5108c2ecf20Sopenharmony_ci	} else {
5118c2ecf20Sopenharmony_ci		rfhcnt = (f_pll - 64) / 128;
5128c2ecf20Sopenharmony_ci		if (rfhcnt > 15)
5138c2ecf20Sopenharmony_ci			rfhcnt = 0;
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci	minfo->hw.MXoptionReg = (minfo->hw.MXoptionReg & ~0x000F0000) | (rfhcnt << 16);
5168c2ecf20Sopenharmony_ci	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	/* output MCLK to MCLK pin */
5198c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
5208c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLCTRL, (mclk_ctl       ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	/* stop PCLK */
5238c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFE);
5248c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, 0x00);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	/* restore pclk */
5278c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0xFC);
5288c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, pclk_n);
5298c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, pclk_m);
5308c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, pclk_p);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	/* wait for PLL to lock */
5338c2ecf20Sopenharmony_ci	for (tmout = 500000; tmout; tmout--) {
5348c2ecf20Sopenharmony_ci		if (inTi3026(minfo, TVP3026_XPIXPLLDATA) & 0x40)
5358c2ecf20Sopenharmony_ci			break;
5368c2ecf20Sopenharmony_ci		udelay(10);
5378c2ecf20Sopenharmony_ci	}
5388c2ecf20Sopenharmony_ci	if (!tmout)
5398c2ecf20Sopenharmony_ci		printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic void ti3026_ramdac_init(struct matrox_fb_info *minfo)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	DBG(__func__)
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	minfo->features.pll.vco_freq_min = 110000;
5478c2ecf20Sopenharmony_ci	minfo->features.pll.ref_freq	 = 114545;
5488c2ecf20Sopenharmony_ci	minfo->features.pll.feed_div_min = 2;
5498c2ecf20Sopenharmony_ci	minfo->features.pll.feed_div_max = 24;
5508c2ecf20Sopenharmony_ci	minfo->features.pll.in_div_min	 = 2;
5518c2ecf20Sopenharmony_ci	minfo->features.pll.in_div_max	 = 63;
5528c2ecf20Sopenharmony_ci	minfo->features.pll.post_shift_max = 3;
5538c2ecf20Sopenharmony_ci	if (minfo->devflags.noinit)
5548c2ecf20Sopenharmony_ci		return;
5558c2ecf20Sopenharmony_ci	ti3026_setMCLK(minfo, 60000);
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_cistatic void Ti3026_restore(struct matrox_fb_info *minfo)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	int i;
5618c2ecf20Sopenharmony_ci	unsigned char progdac[6];
5628c2ecf20Sopenharmony_ci	struct matrox_hw_state *hw = &minfo->hw;
5638c2ecf20Sopenharmony_ci	CRITFLAGS
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	DBG(__func__)
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci#ifdef DEBUG
5688c2ecf20Sopenharmony_ci	dprintk(KERN_INFO "EXTVGA regs: ");
5698c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++)
5708c2ecf20Sopenharmony_ci		dprintk("%02X:", hw->CRTCEXT[i]);
5718c2ecf20Sopenharmony_ci	dprintk("\n");
5728c2ecf20Sopenharmony_ci#endif
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	CRITBEGIN
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	CRITEND
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	matroxfb_vgaHWrestore(minfo);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	CRITBEGIN
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	minfo->crtc1.panpos = -1;
5858c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++)
5868c2ecf20Sopenharmony_ci		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	for (i = 0; i < 21; i++) {
5898c2ecf20Sopenharmony_ci		outTi3026(minfo, DACseq[i], hw->DACreg[i]);
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0x00);
5938c2ecf20Sopenharmony_ci	progdac[0] = inTi3026(minfo, TVP3026_XPIXPLLDATA);
5948c2ecf20Sopenharmony_ci	progdac[3] = inTi3026(minfo, TVP3026_XLOOPPLLDATA);
5958c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0x15);
5968c2ecf20Sopenharmony_ci	progdac[1] = inTi3026(minfo, TVP3026_XPIXPLLDATA);
5978c2ecf20Sopenharmony_ci	progdac[4] = inTi3026(minfo, TVP3026_XLOOPPLLDATA);
5988c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0x2A);
5998c2ecf20Sopenharmony_ci	progdac[2] = inTi3026(minfo, TVP3026_XPIXPLLDATA);
6008c2ecf20Sopenharmony_ci	progdac[5] = inTi3026(minfo, TVP3026_XLOOPPLLDATA);
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	CRITEND
6038c2ecf20Sopenharmony_ci	if (memcmp(hw->DACclk, progdac, 6)) {
6048c2ecf20Sopenharmony_ci		/* agrhh... setting up PLL is very slow on Millennium... */
6058c2ecf20Sopenharmony_ci		/* Mystique PLL is locked in few ms, but Millennium PLL lock takes about 0.15 s... */
6068c2ecf20Sopenharmony_ci		/* Maybe even we should call schedule() ? */
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci		CRITBEGIN
6098c2ecf20Sopenharmony_ci		outTi3026(minfo, TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
6108c2ecf20Sopenharmony_ci		outTi3026(minfo, TVP3026_XPLLADDR, 0x2A);
6118c2ecf20Sopenharmony_ci		outTi3026(minfo, TVP3026_XLOOPPLLDATA, 0);
6128c2ecf20Sopenharmony_ci		outTi3026(minfo, TVP3026_XPIXPLLDATA, 0);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci		outTi3026(minfo, TVP3026_XPLLADDR, 0x00);
6158c2ecf20Sopenharmony_ci		for (i = 0; i < 3; i++)
6168c2ecf20Sopenharmony_ci			outTi3026(minfo, TVP3026_XPIXPLLDATA, hw->DACclk[i]);
6178c2ecf20Sopenharmony_ci		/* wait for PLL only if PLL clock requested (always for PowerMode, never for VGA) */
6188c2ecf20Sopenharmony_ci		if (hw->MiscOutReg & 0x08) {
6198c2ecf20Sopenharmony_ci			int tmout;
6208c2ecf20Sopenharmony_ci			outTi3026(minfo, TVP3026_XPLLADDR, 0x3F);
6218c2ecf20Sopenharmony_ci			for (tmout = 500000; tmout; --tmout) {
6228c2ecf20Sopenharmony_ci				if (inTi3026(minfo, TVP3026_XPIXPLLDATA) & 0x40)
6238c2ecf20Sopenharmony_ci					break;
6248c2ecf20Sopenharmony_ci				udelay(10);
6258c2ecf20Sopenharmony_ci			}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci			CRITEND
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci			if (!tmout)
6308c2ecf20Sopenharmony_ci				printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
6318c2ecf20Sopenharmony_ci			else
6328c2ecf20Sopenharmony_ci				dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
6338c2ecf20Sopenharmony_ci			CRITBEGIN
6348c2ecf20Sopenharmony_ci		}
6358c2ecf20Sopenharmony_ci		outTi3026(minfo, TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
6368c2ecf20Sopenharmony_ci		outTi3026(minfo, TVP3026_XPLLADDR, 0x00);
6378c2ecf20Sopenharmony_ci		for (i = 3; i < 6; i++)
6388c2ecf20Sopenharmony_ci			outTi3026(minfo, TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
6398c2ecf20Sopenharmony_ci		CRITEND
6408c2ecf20Sopenharmony_ci		if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) {
6418c2ecf20Sopenharmony_ci			int tmout;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci			CRITBEGIN
6448c2ecf20Sopenharmony_ci			outTi3026(minfo, TVP3026_XPLLADDR, 0x3F);
6458c2ecf20Sopenharmony_ci			for (tmout = 500000; tmout; --tmout) {
6468c2ecf20Sopenharmony_ci				if (inTi3026(minfo, TVP3026_XLOOPPLLDATA) & 0x40)
6478c2ecf20Sopenharmony_ci					break;
6488c2ecf20Sopenharmony_ci				udelay(10);
6498c2ecf20Sopenharmony_ci			}
6508c2ecf20Sopenharmony_ci			CRITEND
6518c2ecf20Sopenharmony_ci			if (!tmout)
6528c2ecf20Sopenharmony_ci				printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
6538c2ecf20Sopenharmony_ci			else
6548c2ecf20Sopenharmony_ci				dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout);
6558c2ecf20Sopenharmony_ci		}
6568c2ecf20Sopenharmony_ci	}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci#ifdef DEBUG
6598c2ecf20Sopenharmony_ci	dprintk(KERN_DEBUG "3026DACregs ");
6608c2ecf20Sopenharmony_ci	for (i = 0; i < 21; i++) {
6618c2ecf20Sopenharmony_ci		dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]);
6628c2ecf20Sopenharmony_ci		if ((i & 0x7) == 0x7) dprintk(KERN_DEBUG "continuing... ");
6638c2ecf20Sopenharmony_ci	}
6648c2ecf20Sopenharmony_ci	dprintk(KERN_DEBUG "DACclk ");
6658c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++)
6668c2ecf20Sopenharmony_ci		dprintk("C%02X=%02X ", i, hw->DACclk[i]);
6678c2ecf20Sopenharmony_ci	dprintk("\n");
6688c2ecf20Sopenharmony_ci#endif
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic void Ti3026_reset(struct matrox_fb_info *minfo)
6728c2ecf20Sopenharmony_ci{
6738c2ecf20Sopenharmony_ci	DBG(__func__)
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	ti3026_ramdac_init(minfo);
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_cistatic struct matrox_altout ti3026_output = {
6798c2ecf20Sopenharmony_ci	.name	 = "Primary output",
6808c2ecf20Sopenharmony_ci};
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_cistatic int Ti3026_preinit(struct matrox_fb_info *minfo)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	static const int vxres_mill2[] = { 512,        640, 768,  800,  832,  960,
6858c2ecf20Sopenharmony_ci					  1024, 1152, 1280,      1600, 1664, 1920,
6868c2ecf20Sopenharmony_ci					  2048, 0};
6878c2ecf20Sopenharmony_ci	static const int vxres_mill1[] = {             640, 768,  800,        960,
6888c2ecf20Sopenharmony_ci					  1024, 1152, 1280,      1600,       1920,
6898c2ecf20Sopenharmony_ci					  2048, 0};
6908c2ecf20Sopenharmony_ci	struct matrox_hw_state *hw = &minfo->hw;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	DBG(__func__)
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	minfo->millenium = 1;
6958c2ecf20Sopenharmony_ci	minfo->milleniumII = (minfo->pcidev->device != PCI_DEVICE_ID_MATROX_MIL);
6968c2ecf20Sopenharmony_ci	minfo->capable.cfb4 = 1;
6978c2ecf20Sopenharmony_ci	minfo->capable.text = 1; /* isMilleniumII(minfo); */
6988c2ecf20Sopenharmony_ci	minfo->capable.vxres = isMilleniumII(minfo) ? vxres_mill2 : vxres_mill1;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	minfo->outputs[0].data = minfo;
7018c2ecf20Sopenharmony_ci	minfo->outputs[0].output = &ti3026_output;
7028c2ecf20Sopenharmony_ci	minfo->outputs[0].src = minfo->outputs[0].default_src;
7038c2ecf20Sopenharmony_ci	minfo->outputs[0].mode = MATROXFB_OUTPUT_MODE_MONITOR;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	if (minfo->devflags.noinit)
7068c2ecf20Sopenharmony_ci		return 0;
7078c2ecf20Sopenharmony_ci	/* preserve VGA I/O, BIOS and PPC */
7088c2ecf20Sopenharmony_ci	hw->MXoptionReg &= 0xC0000100;
7098c2ecf20Sopenharmony_ci	hw->MXoptionReg |= 0x002C0000;
7108c2ecf20Sopenharmony_ci	if (minfo->devflags.novga)
7118c2ecf20Sopenharmony_ci		hw->MXoptionReg &= ~0x00000100;
7128c2ecf20Sopenharmony_ci	if (minfo->devflags.nobios)
7138c2ecf20Sopenharmony_ci		hw->MXoptionReg &= ~0x40000000;
7148c2ecf20Sopenharmony_ci	if (minfo->devflags.nopciretry)
7158c2ecf20Sopenharmony_ci		hw->MXoptionReg |=  0x20000000;
7168c2ecf20Sopenharmony_ci	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	minfo->accel.ramdac_rev = inTi3026(minfo, TVP3026_XSILICONREV);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED);
7218c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR);
7228c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA);
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPLLADDR, 0x2A);
7258c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XLOOPPLLDATA, 0x00);
7268c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XPIXPLLDATA, 0x00);
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	mga_outb(M_MISC_REG, 0x67);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	outTi3026(minfo, TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	mga_outl(M_RESET, 1);
7338c2ecf20Sopenharmony_ci	udelay(250);
7348c2ecf20Sopenharmony_ci	mga_outl(M_RESET, 0);
7358c2ecf20Sopenharmony_ci	udelay(250);
7368c2ecf20Sopenharmony_ci	mga_outl(M_MACCESS, 0x00008000);
7378c2ecf20Sopenharmony_ci	udelay(10);
7388c2ecf20Sopenharmony_ci	return 0;
7398c2ecf20Sopenharmony_ci}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_cistruct matrox_switch matrox_millennium = {
7428c2ecf20Sopenharmony_ci	.preinit	= Ti3026_preinit,
7438c2ecf20Sopenharmony_ci	.reset		= Ti3026_reset,
7448c2ecf20Sopenharmony_ci	.init		= Ti3026_init,
7458c2ecf20Sopenharmony_ci	.restore	= Ti3026_restore
7468c2ecf20Sopenharmony_ci};
7478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(matrox_millennium);
7488c2ecf20Sopenharmony_ci#endif
7498c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
750