registers.c revision 90b17f1b
1249c3046Smrg/*
2 * Copyright 2009 VIA Technologies, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License as published by the Free Software Foundation;
7 * either version 2, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
11 * the implied warranty of MERCHANTABILITY or FITNESS FOR
12 * A PARTICULAR PURPOSE.See the GNU General Public License
13 * for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc.,
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21#include <stdlib.h>
22#include <stdio.h>
23#include <unistd.h>
24#include <string.h>
25#include <errno.h>
26#include <getopt.h>
27
28#include <sys/types.h>
29#include <sys/io.h>
30
31#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
32
33struct bit_desc {
34	u_int8_t mask;
35	char *name;
36};
37
38struct io_index {
39	char *name;
40	struct bit_desc *bit_desc;
41};
42
43struct io_reg {
44	u_int16_t	io_port_addr;	/* port for address */
45	u_int16_t	io_port_data;	/* port for address */
46	char *		name;
47	struct io_index	index[0xff];
48};
49
50struct io_reg attr_regs = {
51	.io_port_addr = 0x3c0,
52	.io_port_data = 0x3c1,
53	.name = "Attribute Controller",
54	.index = {
55		[0x00] = { "Palette 0", },
56		[0x01] = { "Palette 1", },
57		[0x02] = { "Palette 2", },
58		[0x03] = { "Palette 3", },
59		[0x04] = { "Palette 4", },
60		[0x05] = { "Palette 5", },
61		[0x06] = { "Palette 6", },
62		[0x07] = { "Palette 7", },
63		[0x08] = { "Palette 8", },
64		[0x09] = { "Palette 9", },
65		[0x0a] = { "Palette a", },
66		[0x0b] = { "Palette b", },
67		[0x0c] = { "Palette c", },
68		[0x0d] = { "Palette d", },
69		[0x0e] = { "Palette e", },
70		[0x0f] = { "Palette f", },
71		[0x10] = { "Mode Control", },
72		[0x11] = { "Overscan Color", },
73		[0x12] = { "Color Plane Enable", },
74		[0x13] = { "Horizontal Pixel Panning", },
75		[0x14] = { "Color Select", },
76	},
77};
78
79struct io_reg graphic_regs = {
80	.io_port_addr = 0x3ce,
81	.io_port_data = 0x3cf,
82	.name = "Graphic Controller",
83	.index = {
84		[0x00] = { "Set / Reset", },
85		[0x01] = { "Enable Set / Reset", },
86		[0x02] = { "Color Compare", },
87		[0x03] = { "Data Rotate", },
88		[0x04] = { "Read Map Select", },
89		[0x05] = { "Mode", },
90		[0x06] = { "Miscellaneous", },
91		[0x07] = { "Color Don't Care", },
92		[0x08] = { "Bit Mask", },
93		/* Extended */
94		[0x20] = { "Offset Register Control", },
95		[0x21] = { "Offset Register A", },
96		[0x22] = { "Offset Register B", },
97	},
98};
99
100
101static struct bit_desc crtc_32_desc[] = {
102	{ 0x01, "Real-Time Flipping", },
103	{ 0x02, "Digital Video Port (DVP) Grammar Correction", },
104	{ 0x04, "Display End Blanking Enable", },
105	{ 0x08, "CRT SYNC Driving Selection (0: Low, 1: High)", },
106	{ 0xE0, "HSYNC Delay Number by VCLK", },
107	{ 0 },
108};
109
110struct io_reg crtc_regs = {
111	.io_port_addr = 0x3d4,
112	.io_port_data = 0x3d5,
113	.name = "CRT controller",
114	.index = {
115		/* CRT Controller registers */
116		[0x00] = { "Horizontal Total", },
117		[0x01] = { "Horizontal Display End", },
118		[0x02] = { "Start Horizontal Blank", },
119		[0x03] = { "End Horizontal Blank", },
120		[0x04] = { "Start Horizontal Retrace", },
121		[0x05] = { "End Horizontal Retrace", },
122		[0x06] = { "Vertical Total", },
123		[0x07] = { "Overflow", },
124		[0x08] = { "Preset Row Scan", },
125		[0x09] = { "Max Scan Line", },
126		[0x0a] = { "Cursor Start", },
127		[0x0b] = { "Cursor End", },
128		[0x0c] = { "Start Address High", },
129		[0x0d] = { "Start Address Low", },
130		[0x0e] = { "Cursor Location High", },
131		[0x0f] = { "Cursor Location Low", },
132		[0x10] = { "Vertical Retrace Start", },
133		[0x11] = { "Vertical Retrace End", },
134		[0x12] = { "Vertical Display End", },
135		[0x13] = { "Offset", },
136		[0x14] = { "Underline Location", },
137		[0x15] = { "Start Vertical Blank", },
138		[0x16] = { "End Vertical Blank", },
139		[0x17] = { "CRTC Mode Control", },
140		[0x18] = { "Line Compare", },
141		/* CRT Controller Extended Register */
142		[0x30] = { "Display Fetch Blocking Control", },
143		[0x31] = { "Half Line Position", },
144		[0x32] = { "Mode Control", crtc_32_desc, },
145		[0x33] = { "Hsync Adjuster", },
146		[0x34] = { "Starting Address Overflow, Bits [23:16]", },
147		[0x35] = { "Extended Overflow", },
148		[0x36] = { "Power Management Control 3", },
149		[0x37] = { "DAC Control", },
150		[0x38] = { "Signature Data B0", },
151		[0x39] = { "Signature Data B1", },
152		[0x3a] = { "Signature Data B2", },
153		[0x3b] = { "Scratch Pad 2", },
154		[0x3c] = { "Scratch Pad 3", },
155		[0x3d] = { "Scratch Pad 4", },
156		[0x3e] = { "Scratch Pad 5", },
157		[0x3f] = { "Scratch Pad 6", },
158		[0x40] = { "Test Mode Control 0", },
159		[0x43] = { "IGA1 Display Control", },
160		[0x45] = { "Power Now Indicator Control 3", },
161		[0x46] = { "Test Mode Control 1", },
162		[0x47] = { "Test Mode Control 2", },
163		[0x48] = { "Starting Address Overflow", },
164		/* Sequencer Extended Registers */
165		[0x50] = { "Second CRTC Horizontal Total Period", },
166		[0x51] = { "Second CRTC Horizontal Active Data Period", },
167		[0x52] = { "Second CRTC Horizontal Blanking Start", },
168		[0x53] = { "Second CRTC Horizontal Blanking End", },
169		[0x54] = { "Second CRTC Horizontal Blanking Overflow", },
170		[0x55] = { "Second CRTC Horizontal Period Overflow", },
171		[0x56] = { "Second CRTC Horizontal Retrace Start", },
172		[0x57] = { "Second CRTC Horizontal Retrace End", },
173		[0x58] = { "Second CRTC Vertical Total Period", },
174		[0x59] = { "Second CRTC Vertical Active Data Period", },
175		[0x5a] = { "Second CRTC Vertical Blanking Start", },
176		[0x5b] = { "Second CRTC Vertical Blanking End", },
177		[0x5c] = { "Second CRTC Vertical Blanking Overflow", },
178		[0x5d] = { "Second CRTC Vertical Period Overflow", },
179		[0x5e] = { "Second CRTC Vertical Retrace Start", },
180		[0x5f] = { "Second CRTC Vertical Retrace End", },
181		[0x60] = { "Second CRTC Vertical Status 1", },
182		[0x61] = { "Second CRTC Vertical Status 2", },
183		[0x62] = { "Second Display Starting Address Low", },
184		[0x63] = { "Second Display Starting Address Middle", },
185		[0x64] = { "Second Display Starting Address High", },
186		[0x65] = { "Second Display Horizontal Quadword Count", },
187		[0x66] = { "Second Display Horizontal Offset", },
188		[0x67] = { "Second Display Color Depth and Horizontal Overflow", },
189		[0x68] = { "Second Display Queue Depth and Read Threshold", },
190		[0x69] = { "Second Display Interrupt Enable and Status", },
191		[0x6a] = { "Second Display Channel and LCD Enable", },
192		[0x6b] = { "Channel 1 and 2 Clock Mode Selection", },
193		[0x6c] = { "TV Clock Control", },
194		[0x6d] = { "Horizontal Total Shadow", },
195		[0x6e] = { "End Horizontal Blanking Shadow", },
196		[0x6f] = { "Vertical Total Shadow", },
197		[0x70] = { "Vertical Display Enable End Shadow", },
198		[0x71] = { "Vertical Display Overflow Shadow", },
199		[0x72] = { "Start Vertical Blank Shadow", },
200		[0x73] = { "End Vertical Blank Shadow", },
201		[0x74] = { "Vertical Blank Overflow Shadow", },
202		[0x75] = { "Vertical Retrace Start Shadow", },
203		[0x76] = { "Vertical Retrace End Shadow", },
204		[0x77] = { "LCD Horizontal Scaling Factor", },
205		[0x78] = { "LCD Vertical Scaling Factor", },
206		[0x79] = { "LCD Scaling Control", },
207		[0x7a] = { "LCD Scaling Parameter 1", },
208		[0x7b] = { "LCD Scaling Parameter 2", },
209		[0x7c] = { "LCD Scaling Parameter 3", },
210		[0x7d] = { "LCD Scaling Parameter 4", },
211		[0x7e] = { "LCD Scaling Parameter 5", },
212		[0x7f] = { "LCD Scaling Parameter 6", },
213		[0x80] = { "LCD Scaling Parameter 7", },
214		[0x81] = { "LCD Scaling Parameter 8", },
215		[0x82] = { "LCD Scaling Parameter 9", },
216		[0x83] = { "LCD Scaling Parameter 10", },
217		[0x84] = { "LCD Scaling Parameter 11", },
218		[0x85] = { "LCD Scaling Parameter 12", },
219		[0x86] = { "LCD Scaling Parameter 13", },
220		[0x87] = { "LCD Scaling Parameter 14", },
221		[0x88] = { "LCD Panel Type", },
222		[0x8a] = { "LCD Timing Control 1", },
223		[0x8b] = { "LCD Power Sequence Control 0", },
224		[0x8c] = { "LCD Power Sequence Control 1", },
225		[0x8d] = { "LCD Power Sequence Control 2", },
226		[0x8e] = { "LCD Power Sequence Control 3", },
227		[0x8f] = { "LCD Power Sequence Control 4", },
228		[0x90] = { "LCD Power Sequence Control 5", },
229		[0x91] = { "Software Control Power Sequence", },
230		[0x92] = { "Read Threshold 2", },
231		[0x94] = { "Expire Number and Display Queue Extend", },
232		[0x95] = { "Extend Threshold Bit", },
233		[0x97] = { "LVDS Channel 2 Function Select 0", },
234		[0x98] = { "LVDS Channel 2 Function Select 1", },
235		[0x99] = { "LVDS Channel 1 Function Select 0", },
236		[0x9a] = { "LVDS Channel 1 Function Select 1", },
237		[0x9b] = { "Digital Video Port 1 Function Select 0", },
238		[0x9c] = { "Digital Video Port 1 Function Select 1", },
239		[0x9d] = { "Power Now Control 2", },
240		[0x9e] = { "Power Now Control 3", },
241		[0x9f] = { "Power Now Control 4", },
242		[0xa0] = { "Horizontal Scaling Initial Value", },
243		[0xa1] = { "Vertical Scaling Initial Value", },
244		[0xa2] = { "Horizontal and Vertical Scaling Enable", },
245		[0xa3] = { "Second Display Starting Address Extended", },
246		[0xa5] = { "Second LCD Vertical Scaling Factor", },
247		[0xa6] = { "Second LCD Vertical Scaling Factor", },
248		[0xa7] = { "Expected IGA1 Vertical Display End", },
249		[0xa8] = { "Expected IGA1 Vertical Display End", },
250		[0xa9] = { "Hardware Gamma Control", },
251		[0xaa] = { "FIFO Depth + Threshold Overflow", },
252		[0xab] = { "IGA2 Interlace Half Line", },
253		[0xac] = { "IGA2 Interlace Half Line", },
254		[0xaf] = { "P-Arbiter Write Expired Number", },
255		[0xb0] = { "IGA2 Pack Circuit Request Threshold", },
256		[0xb1] = { "IGA2 Pack Circuit Request High Threshold", },
257		[0xb2] = { "IGA2 Pack Circuit Request Expire Threshold", },
258		[0xb3] = { "IGA2 Pack Circuit Control", },
259		[0xb4] = { "IGA2 Pack Circuit Target Base Address 0", },
260		[0xb5] = { "IGA2 Pack Circuit Target Base Address 0", },
261		[0xb6] = { "IGA2 Pack Circuit Target Base Address 0", },
262		[0xb7] = { "IGA2 Pack Circuit Target Base Address 0", },
263		[0xb8] = { "IGA2 Pack Circuit Target Line Pitch", },
264		[0xb9] = { "IGA2 Pack Circuit Target Line Pitch", },
265		[0xba] = { "V Counter Set Pointer", },
266		[0xbb] = { "V Counter Set Pointer", },
267		[0xbc] = { "V Counter Reset Value", },
268		[0xbd] = { "V Counter Reset Value", },
269		[0xbe] = { "Frame Buffer Limit Value", },
270		[0xbf] = { "Frame Buffer Limit Value", },
271		[0xc0] = { "Expected IGA1 Vertical Display End 1", },
272		[0xc1] = { "Expected IGA1 Vertical Display End 1", },
273		[0xc2] = { "Third LCD Vertical Scaling Factor", },
274		[0xc3] = { "Third LCD Vertical Scaling Factor", },
275		[0xc4] = { "Expected IGA1 Vertical Display End 2", },
276		[0xc5] = { "Expected IGA1 Vertical Display End 2", },
277		[0xc7] = { "Fourth LCD Vertical Scaling Factor", },
278		[0xc8] = { "IGA2 Pack Circuit Target Base Address 1", },
279		[0xc9] = { "IGA2 Pack Circuit Target Base Address 1", },
280		[0xca] = { "IGA2 Pack Circuit Target Base Address 1", },
281		[0xcb] = { "IGA2 Pack Circuit Target Base Address 1", },
282		[0xd0] = { "LVDS PLL1 Control", },
283		[0xd1] = { "LVDS PLL2 Control", },
284		[0xd2] = { "LVDS Control", },
285		[0xd3] = { "LVDS Second Power Sequence Control 0", },
286		[0xd4] = { "LVDS Second Power Sequence Control 1", },
287		[0xd5] = { "LVDS Texting Mode Control", },
288		[0xd6] = { "DCVI Control Register 0", },
289		[0xd7] = { "DCVI Control Register 1", },
290		[0xd9] = { "Scaling Down Source Data Offset Control", },
291		[0xda] = { "Scaling Down Source Data Offset Control", },
292		[0xdb] = { "Scaling Down Source Data Offset Control", },
293		[0xdc] = { "Scaling Down Vertical Scale Control", },
294		[0xdd] = { "Scaling Down Vertical Scale Control", },
295		[0xde] = { "Scaling Down Vertical Scale Control", },
296		[0xdf] = { "Scaling Down Vertical Scale Control", },
297		[0xe0] = { "Scaling Down Destination FB Starting Addr 0", },
298		[0xe1] = { "Scaling Down Destination FB Starting Addr 0", },
299		[0xe2] = { "Scaling Down Destination FB Starting Addr 0", },
300		[0xe3] = { "Scaling Down Destination FB Starting Addr 0", },
301		[0xe4] = { "Scaling Down SW Source FB Stride", },
302		[0xe5] = { "Scaling Down Destination FB Starting Addr 1", },
303		[0xe6] = { "Scaling Down Destination FB Starting Addr 1", },
304		[0xe7] = { "Scaling Down Destination FB Starting Addr 1", },
305		[0xe8] = { "Scaling Down Destination FB Starting Addr 1", },
306		[0xe9] = { "Scaling Down Destination FB Starting Addr 2", },
307		[0xea] = { "Scaling Down Destination FB Starting Addr 2", },
308		[0xeb] = { "Scaling Down Destination FB Starting Addr 2", },
309		[0xec] = { "IGA1 Down Scaling Destination Control", },
310		[0xf0] = { "Snapshot Mode - Starting Address of Disp Data", },
311		[0xf1] = { "Snapshot Mode - Starting Address of Disp Data", },
312		[0xf2] = { "Snapshot Mode - Starting Address of Disp Data", },
313		[0xf3] = { "Snapshot Mode Control", },
314		[0xf4] = { "Snapshot Mode Control", },
315		[0xf5] = { "Snapshot Mode Control", },
316		[0xf6] = { "Snapshot Mode Control", },
317	},
318};
319
320static struct bit_desc seq_19_desc[] = {
321	{ 0x01, "CPU Interface Clock Control", },
322	{ 0x02, "Display Interface Clock Control", },
323	{ 0x04, "MC Interface Clock Control", },
324	{ 0x08, "Typical Arbiter Interface Clock Control", },
325	{ 0x10, "AGP Interface Clock Control", },
326	{ 0x20, "P-Arbiter Interface Clock Control", },
327	{ 0x40, "MIU/AGP Interface Clock Control", },
328	{ 0 },
329};
330
331
332static struct bit_desc seq_1a_desc[] = {
333	{ 0x01, "LUT Shadow Access", },
334	{ 0x04, "PCI Burst Write Wait State Select (0: 0 Wait state, 1: 1 Wait state)", },
335	{ 0x08, "Extended Mode Memory Access Enable (0: Disable, 1: Enable)", },
336	{ 0x40, "Software Reset (0: Default value, 1: Reset)", },
337	{ 0x80, "Read Cache Enable (0: Disable, 1: Enable)", },
338	{ 0 },
339};
340
341static struct bit_desc seq_1b_desc[] = {
342	{ 0x01, "Primary Display's LUT Off", },
343	{ 0x18, "Primary Display Engine VCK Gating", },
344	{ 0x60, "Secondary Display Engine LCK Gating", },
345	{ 0 },
346};
347
348static struct bit_desc seq_1e_desc[] = {
349	{ 0x01, "ROC ECK", },
350	{ 0x02, "Replace ECK by MCK", },
351	{ 0x08, "Spread Spectrum", },
352	{ 0x30, "DVP1 Power Control", },
353	{ 0xc0, "VCP Power Control", },
354	{ 0 },
355};
356
357static struct bit_desc seq_2a_desc[] = {
358	{ 0x03, "LVDS Channel 1 Pad Control" },
359	{ 0x0c, "LVDS Channel 2 Pad Control" },
360	{ 0x40, "Spread Spectrum Type FIFO" },
361	{ 0 },
362};
363
364static struct bit_desc seq_2b_desc[] = {
365	{ 0x01, "MSI Pending IRQ Re-trigger", },
366	{ 0x02, "CRT Hot Plug Detect Enable", },
367	{ 0x04, "CRT Sense IRQ status", },
368	{ 0x08, "CRT Sense IRQ enable", },
369	{ 0x10, "LVDS Sense IRQ status", },
370	{ 0x20, "LVDS Sense IRQ enable", },
371	{ 0 },
372};
373
374static struct bit_desc seq_2d_desc[] = {
375	{ 0x03, "ECK Pll Power Control", },
376	{ 0x0c, "LCK PLL Power Control", },
377	{ 0x30, "VCK PLL Power Control", },
378	{ 0xc0, "E3_ECK_N Selection", },
379	{ 0 },
380};
381
382static struct bit_desc seq_2e_desc[] = {
383	{ 0x03, "Video Playback Engine V3/V4 Gated Clock VCK", },
384	{ 0x0c, "PCI Master / DMA Gated Clock ECK/CPUCK", },
385	{ 0x30, "Video Processor Gated Clock ECK", },
386	{ 0xc0, "Capturer Gated Clock ECK", },
387	{ 0 },
388};
389
390static struct bit_desc seq_3c_desc[] = {
391	{ 0x01, "AGP Bus Pack Door AGP3 Enable", },
392	{ 0x02, "Switch 3 PLLs to Prime Output", },
393	{ 0x04, "LCDCK PLL Locked Detect", },
394	{ 0x08, "VCK PLL Locked Detect", },
395	{ 0x10, "ECL PLL Locked Detect", },
396	{ 0x60, "PLL Frequency Division Select for Testing", },
397	{ 0 },
398};
399
400static struct bit_desc seq_3f_desc[] = {
401	{ 0x03, "Video Clock Control (Gated ECK)", },
402	{ 0x0c, "2D Clock Control (Gated ECK/CPUCK)", },
403	{ 0x30, "3D Clock Control (Gated ECK)", },
404	{ 0xc0, "CR Clock Control (Gated ECK)", },
405	{ 0 },
406};
407
408static struct bit_desc seq_40_desc[] = {
409	{ 0x01, "Reset ECK PLL", },
410	{ 0x02, "Reset VCK PLL", },
411	{ 0x04, "Reset LCDCK PLL", },
412	{ 0x08, "LVDS Interrupt Method", },
413	{ 0x30, "Free Run ECK Frequency within Idle Mode", },
414	{ 0x80, "CRT Sense Enable", },
415	{ 0 },
416};
417
418static struct bit_desc seq_43_desc[] = {
419	{ 0x01, "Notebook Used Flag", },
420	{ 0x04, "Typical Channel 1 Arbiter Read Back Data Overwrite Flag", },
421	{ 0x08, "Typical Channel 0 Arbiter Read Back Data Overwrite Flag", },
422	{ 0x10, "IGA1 Display FIFO Underflow Flag", },
423	{ 0x20, "IGA2 Display FIFO Underflow Flag", },
424	{ 0x40, "Windows Media Video Enable Flag", },
425	{ 0x80, "Advance Video Enable Flag", },
426	{ 0 },
427};
428
429static struct bit_desc seq_4e_desc[] = {
430	{ 0x01, "HQV/Video/Capture Engine Reset", },
431	{ 0x02, "HQV/Video/Capture Register Reset", },
432	{ 0x04, "2D Engine Reset", },
433	{ 0x08, "2D Register Reset", },
434	{ 0x10, "3D Engine Reset", },
435	{ 0x20, "3D Register Reset", },
436	{ 0x40, "CR Engine Reset", },
437	{ 0x80, "CR Register Reset", },
438	{ 0 },
439};
440
441static struct bit_desc seq_59_desc[] = {
442	{ 0x01, "GFX-NM AGP Dynamic Clock Enable", },
443	{ 0x02, "GFX-NM GMINT Channel 0 Dynamic Clock Enable", },
444	{ 0x04, "GFX-NM GMINT Channel 1 Dynamic Clock Enable", },
445	{ 0x08, "GFX-NM PCIC Dynamic Clock Enable", },
446	{ 0x10, "GFX-NM IGA Dynamic Clock Enable", },
447	{ 0x20, "IGA Low Threshold Enable", },
448	{ 0x80, "IGA1 Enable", },
449	{ 0 },
450};
451
452static struct bit_desc seq_5b_desc[] = {
453	{ 0x01, "LVDS1 Used IGA2 Source", },
454	{ 0x02, "LBDS1 Used IGA1 Source", },
455	{ 0x04, "LVDS0 Used IGA2 Source", },
456	{ 0x08, "LVDS1 Used IGA1 Source", },
457	{ 0x10, "DAC0 Used IGA2 Source", },
458	{ 0x20, "DAC0 Used IGA1 Source", },
459	{ 0x40, "DAC0 User is TV", },
460	{ 0x80, "DCVI Source Selection is TV", },
461	{ 0 },
462};
463
464static struct bit_desc seq_5c_desc[] = {
465	{ 0x01, "DVP1 Used IGA2 Source", },
466	{ 0x02, "DVP1 Used IGA1 Source", },
467	{ 0x10, "DAC1 Used IGA2 Source", },
468	{ 0x20, "DAC1 Used IGA1 Source", },
469	{ 0x40, "DAC1 User is TV", },
470	{ 0 },
471};
472
473static struct bit_desc seq_76_desc[] = {
474	{ 0x01, "Backlight Control Enable", },
475	{ 0 },
476};
477
478struct io_reg sequencer_regs = {
479	.io_port_addr = 0x3c4,
480	.io_port_data = 0x3c5,
481	.name = "Sequencer",
482	.index = {
483		/* Sequencer Registers */
484		[0x00] = { "Reset", },
485		[0x01] = { "Clocking Mode", },
486		[0x02] = { "Map Mask", },
487		[0x03] = { "Character Map Select", },
488		[0x04] = { "Memory Mode", },
489		/* Extended Sequencer Registers */
490		[0x10] = { "Extended Register Unlock", },
491		[0x11] = { "Configuration 0", },
492		[0x12] = { "Configuration 1", },
493		[0x13] = { "Configuration 2 (DVP1 strapping)", },
494		[0x14] = { "Frame Buffer Size Control", },
495		[0x15] = { "Display Mode Control", },
496		[0x16] = { "Display FIFO Threshold Control", },
497		[0x17] = { "Display FIFO Control", },
498		[0x18] = { "Display Arbiter Control 0", },
499		[0x19] = { "Power Management", seq_19_desc, },
500		[0x1a] = { "PCI Bus Control", seq_1a_desc, },
501		[0x1b] = { "Power Management Control 0", seq_1b_desc, },
502		[0x1c] = { "Horizontal Display Fetch Count Data", },
503		[0x1d] = { "Horizontal Display Fetch Count Control", },
504		[0x1e] = { "Power Management Control", seq_1e_desc, },
505		/* 1f: reserved */
506		[0x20] = { "Typical Arbiter Control 0", },
507		[0x21] = { "Typical Arbiter Control 1", },
508		[0x22] = { "Display Arbiter Control 1", },
509		[0x26] = { "IIC Serial Port Control 0", },
510		[0x2a] = { "Power Management Control 5", seq_2a_desc, },
511		[0x2b] = { "LVDS Interrupt Control", seq_2b_desc, },
512		[0x2c] = { "General Purpose I/O Port", },
513		[0x2d] = { "Power Management Control 1", seq_2d_desc, },
514		[0x2e] = { "Power Management Control 2", seq_2e_desc, },
515		[0x31] = { "IIC Serial Port Control 1", },
516		[0x35] = { "Subsystem Vendor ID Low", },
517		[0x36] = { "Subsystem Vendor ID High", },
518		[0x37] = { "Subsystem ID Low", },
519		[0x38] = { "Subsystem ID High", },
520		[0x39] = { "BIOS Reserved Register 0", },
521		[0x3a] = { "BIOS Reserved Register 1", },
522		[0x3b] = { "PCI Revision ID Back Door", },
523		[0x3c] = { "Miscellaneous", seq_3c_desc, },
524		[0x3d] = { "General Purpose I/O Port", },
525		[0x3e] = { "Miscellaneous Register for AGP Mux", },
526		[0x3f] = { "Power Management Control 2", seq_3f_desc, },
527		[0x40] = { "PLL Control", seq_40_desc, },
528		[0x41] = { "Typical Arbiter Control 1", },
529		[0x42] = { "Typical Arbiter Control 2", },
530		[0x43] = { "Graphics Bonding Option", seq_43_desc, },
531		[0x44] = { "VCK Clock Synthesizer Value 0", },
532		[0x45] = { "VCK Clock Synthesizer Value 1", },
533		[0x46] = { "VCK Clock Synthesizer Value 2", },
534		[0x47] = { "ECK Clock Synthesizer Value 0", },
535		[0x48] = { "ECK Clock Synthesizer Value 1", },
536		[0x49] = { "ECK Clock Synthesizer Value 2", },
537		[0x4a] = { "LDCK Clock Synthesizer Value 0", },
538		[0x4b] = { "LDCK Clock Synthesizer Value 1", },
539		[0x4c] = { "LDCK Clock Synthesizer Value 2", },
540		[0x4d] = { "Preemptive Arbiter Control", },
541		[0x4e] = { "Software Reset Control", seq_4e_desc, },
542		[0x4f] = { "CR Gating Clock Control", },
543		[0x50] = { "AGP Control", },
544		[0x51] = { "Display FIFO Control 1", },
545		[0x52] = { "Integrated TV Shadow Register Control", },
546		[0x53] = { "DAC Sense Control 1", },
547		[0x54] = { "DAC Sense Control 2", },
548		[0x55] = { "DAC Sense Control 3", },
549		[0x56] = { "DAC Sense Control 4", },
550		[0x57] = { "Display FIFO Control 2", },
551		[0x58] = { "GFX Power Control 1", },
552		[0x59] = { "GFX Power Control 2", seq_59_desc, },
553		[0x5a] = { "PCI Bus Control 2", },
554		[0x5b] = { "Device Used Status 0", seq_5b_desc, },
555		[0x5c] = { "Device Used Status 1", seq_5c_desc, },
556		[0x5d] = { "Timer Control", },
557		[0x5e] = { "DAC Control 2", },
558		[0x60] = { "I2C Mode Control", },
559		[0x61] = { "I2C Host Address", },
560		[0x62] = { "I2C Host Data", },
561		[0x63] = { "I2C Host Control", },
562		[0x64] = { "I2C Status", },
563		[0x65] = { "Power Management Control 6", },
564		[0x66] = { "GTI Control 0", },
565		[0x67] = { "GTI Control 1", },
566		[0x68] = { "GTI Control 2", },
567		[0x69] = { "GTI Control 3", },
568		[0x6a] = { "GTI Control 4", },
569		[0x6b] = { "GTI Control 5", },
570		[0x6c] = { "GTI Control 6", },
571		[0x6d] = { "GTI Control 7", },
572		[0x6e] = { "GTI Control 8", },
573		[0x6f] = { "GTI Control 9", },
574		[0x70] = { "GARB Control 0", },
575		[0x71] = { "Typical Arbiter Control 2", },
576		[0x72] = { "Typical Arbiter Control 3", },
577		[0x73] = { "Typical Arbiter Control 4", },
578		[0x74] = { "Typical Arbiter Control 5", },
579		[0x75] = { "Typical Arbiter Control 6", },
580		[0x76] = { "Backlight Control 1", seq_76_desc, },
581		[0x77] = { "Backlight Control 2", },
582		[0x78] = { "Backlight Control 3", },
583	},
584};
585
586static u_int8_t readb_idx_reg(u_int16_t port, u_int8_t index)
587{
588	outb(index, port-1);
589	return inb(port);
590}
591
592static void writeb_idx_reg(u_int16_t port, u_int8_t index,
593			   u_int8_t val)
594{
595	outb(index, port-1);
596	outb(val, port);
597}
598
599static void writeb_idx_mask(u_int16_t reg, u_int8_t idx, u_int8_t val,
600			    u_int8_t mask)
601{
602	u_int8_t tmp;
603
604	tmp = readb_idx_reg(reg, idx);
605	tmp &= ~ mask;
606	tmp |= (val & mask);
607	writeb_idx_reg(reg, idx, tmp);
608}
609
610
611struct io_reg *io_regs[] = {
612	//&attr_regs,
613	&sequencer_regs,
614	&graphic_regs,
615	&crtc_regs,
616	NULL
617};
618
619struct half_mode {
620	u_int16_t total;
621	u_int16_t active;
622	u_int16_t blank_start;
623	u_int16_t blank_end;
624	u_int16_t retr_start;
625	u_int16_t retr_end;
626	int n_sync;
627};
628
629struct mode {
630	struct half_mode h;
631	struct half_mode v;
632	u_int32_t addr_start;
633	u_int8_t bpp;
634	u_int16_t horiz_quad_count;
635	u_int16_t horiz_offset;
636};
637
638static int get_mode(struct mode *m, int secondary)
639{
640	u_int8_t val;
641
642	memset(m, 0, sizeof(*m));
643
644	if (!secondary) {
645		m->h.total	 = readb_idx_reg(0x3d5, 0x00);
646		m->h.active	 = readb_idx_reg(0x3d5, 0x01);
647		m->h.blank_start = readb_idx_reg(0x3d5, 0x02);
648		m->h.blank_end	 = readb_idx_reg(0x3d5, 0x03) & 0x1f;
649		m->h.retr_start	 = readb_idx_reg(0x3d5, 0x04);
650		m->h.retr_end	 = readb_idx_reg(0x3d5, 0x05) & 0x1f;
651		m->v.total	 = readb_idx_reg(0x3d5, 0x06) + 2;
652
653		m->addr_start	 = readb_idx_reg(0x3d5, 0x0d);
654		m->addr_start	|= readb_idx_reg(0x3d5, 0x0c) << 8;
655
656		m->v.retr_start	 = readb_idx_reg(0x3d5, 0x10);
657		m->v.retr_end	 = readb_idx_reg(0x3d5, 0x11) & 0x0f;
658		m->v.active	 = readb_idx_reg(0x3d5, 0x12) + 1;
659		m->horiz_offset	 = readb_idx_reg(0x3d5, 0x13);
660		m->v.blank_start = readb_idx_reg(0x3d5, 0x15) + 1;
661		m->v.blank_end	 = readb_idx_reg(0x3d5, 0x16) + 1;
662
663		/* overflow register 0x07 */
664		val = readb_idx_reg(0x3d5, 0x07);
665		m->v.total	 |= ((val >> 0) & 0x1) << 8;
666		m->v.active	 |= ((val >> 1) & 0x1) << 8;
667		m->v.retr_start	 |= ((val >> 2) & 0x1) << 8;
668		m->v.blank_start |= ((val >> 3) & 0x1) << 8;
669		/* line compare */
670		m->v.total	 |= ((val >> 5) & 0x1) << 9;
671		m->v.active	 |= ((val >> 6) & 0x1) << 9;
672		m->v.retr_start	 |= ((val >> 7) & 0x1) << 9;
673
674		val = readb_idx_reg(0x3d5, 0x09);
675		m->v.blank_start |= ((val >> 5) & 0x1) << 9;
676
677		val = readb_idx_reg(0x3d5, 0x33);
678		m->h.retr_start	 |= ((val >> 4) & 0x1) << 8;
679		m->h.blank_end	 |= ((val >> 5) & 0x1) << 6;
680
681		val = readb_idx_reg(0x3d5, 0x34);
682		m->addr_start |= val << 16;
683
684		val = readb_idx_reg(0x3d5, 0x35);
685		m->v.total 	 |= ((val >> 0) & 0x1) << 10;
686		m->v.retr_start	 |= ((val >> 1) & 0x1) << 10;
687		m->v.active	 |= ((val >> 2) & 0x1) << 10;
688		m->v.blank_start |= ((val >> 3) & 0x1) << 10;
689		//line_comp	 |= ((val >> 4) & 0x1) << 10;
690		m->horiz_offset	 |= ((val >> 5) & 0x7) << 8;
691
692		val = readb_idx_reg(0x3d5, 0x36);
693		m->h.total	 |= ((val >> 3) & 0x1) << 8;
694
695		val = readb_idx_reg(0x3d5, 0x48);
696		m->addr_start	 |= ((val >> 0) & 0x1f) << 24;
697
698		val = readb_idx_reg(0x3c5, 0x15);
699		switch ((val >> 2) & 0x3) {
700		case 0:
701			m->bpp = 8;
702			break;
703		case 1:
704			m->bpp = 16;
705			break;
706		case 2:
707			m->bpp = 30;
708			break;
709		case 3:
710			m->bpp = 32;
711			break;
712		}
713
714		val = inb(0x3cc);
715		if (val & 0x40)
716			m->h.n_sync;
717		if (val & 0x80)
718			m->v.n_sync;
719
720		/* add some weird multipliers and offsets */
721		m->h.total = (m->h.total + 5) << 3;
722		m->h.active = (m->h.active + 1) << 3;
723		m->h.blank_start = (m->h.blank_start + 1) << 3;
724		m->h.blank_end = (m->h.blank_end + 1) << 3;
725		m->h.retr_start = (m->h.retr_start << 3);
726		m->h.retr_end = (m->h.retr_end << 3);
727
728	} else {
729		/* horizontal */
730		m->h.total	 = readb_idx_reg(0x3d5, 0x50) + 1;
731		m->h.active	 = readb_idx_reg(0x3d5, 0x51) + 1;
732		m->h.blank_start = readb_idx_reg(0x3d5, 0x52) + 1;
733		m->h.blank_end 	 = readb_idx_reg(0x3d5, 0x53) + 1;
734		m->h.retr_start	 = readb_idx_reg(0x3d5, 0x56);
735		m->h.retr_end	 = readb_idx_reg(0x3d5, 0x57);
736		/* add blanking overflow */
737		val = readb_idx_reg(0x3d5, 0x54);
738		m->h.blank_start |= ((val >> 0) & 0x7) << 8;
739		m->h.blank_end	 |= ((val >> 3) & 0x7) << 8;
740		m->h.retr_start  |= ((val >> 6) & 0x3) << 8;
741		/* add period overflow */
742		val = readb_idx_reg(0x3d5, 0x55);
743		m->h.total	 |= ((val >> 0) & 0xf) << 8;
744		m->h.active	 |= ((val >> 4) & 0x7) << 8;
745
746		/* vertical */
747		m->v.total	 = readb_idx_reg(0x3d5, 0x58) + 1;
748		m->v.active	 = readb_idx_reg(0x3d5, 0x59) + 1;
749		m->v.blank_start = readb_idx_reg(0x3d5, 0x5a) + 1;
750		m->v.blank_end	 = readb_idx_reg(0x3d5, 0x5b) + 1;
751		m->v.retr_start	 = readb_idx_reg(0x3d5, 0x5e);
752		val = readb_idx_reg(0x3d5, 0x5f);
753		m->v.retr_end	 = val & 0x1f;
754		m->v.retr_start	 |= (val >> 5) << 8;
755		/* add blanking overflow */
756		val = readb_idx_reg(0x3d5, 0x5c);
757		m->v.blank_start |= ((val >> 0) & 0x7) << 8;
758		m->v.blank_end	 |= ((val >> 3) & 0x7) << 8;
759		m->h.retr_end	 |= ((val >> 6) & 0x1) << 8;
760		m->h.retr_start	 |= ((val >> 7) & 0x1) << 10;
761		/* add period overflow */
762		val = readb_idx_reg(0x3d5, 0x5d);
763		m->v.total	 |= ((val >> 0) & 0x7) << 8;
764		m->v.active	 |= ((val >> 3) & 0x7) << 8;
765		m->h.blank_end	 |= ((val >> 6) & 0x7) << 11;
766		m->h.retr_start	 |= ((val >> 7) & 0x7) << 11;
767
768		/* puzzle together the start address */
769		val = readb_idx_reg(0x3d5, 0x62);
770		m->addr_start = (val >> 1) << 3;
771		val = readb_idx_reg(0x3d5, 0x63);
772		m->addr_start |= (val << 10);
773		val = readb_idx_reg(0x3d5, 0x64);
774		m->addr_start |= (val << 18);
775		val = readb_idx_reg(0x3d5, 0xa3);
776		m->addr_start |= (val & 0x7) << 26;
777
778		m->horiz_quad_count = readb_idx_reg(0x3d5, 0x65);
779		m->horiz_offset = readb_idx_reg(0x3d5, 0x66) << 3;
780
781		val = readb_idx_reg(0x3d5, 0x67);
782		m->horiz_offset		|= ((val >> 0) & 0x3) << 11;
783		m->horiz_quad_count	|= ((val >> 2) & 0x3) << 8;
784		switch (val >> 6) {
785		case 0:
786			m->bpp = 8;
787			break;
788		case 1:
789			m->bpp = 16;
790			break;
791		case 2:
792			m->bpp = 30;
793			break;
794		case 3:
795			m->bpp = 32;
796			break;
797		}
798	}
799}
800
801static void dump_scaling(void)
802{
803	u_int32_t h_scaling, v_scaling;
804	u_int8_t val;
805
806	val = readb_idx_reg(0x3d5, 0x79);
807	if (val & 0x01) {
808		printf("Panel Scaling enabled, mode %s\n",
809			val & 0x02 ? "Interpolation" : "Duplication");
810		v_scaling = (val >> 3) & 0x1;
811		h_scaling = ((val >> 4) & 0x3) << 10;
812		v_scaling |= ((val >> 6) & 0x3) << 9;
813
814		val = readb_idx_reg(0x3d5, 0x77);
815		h_scaling |= val << 2;
816
817		val = readb_idx_reg(0x3d5, 0x78);
818		v_scaling |= val << 1;
819
820		val = readb_idx_reg(0x3d5, 0x9f);
821		h_scaling |= val & 0x3;
822		printf("Scaling Factors: horizontal=%u, vertical=%u\n",
823			h_scaling, v_scaling);
824	} else
825		printf("Panel Scaling disabled\n");
826}
827
828static void dump_registers(struct io_reg *ior)
829{
830	u_int8_t idx;
831
832	printf("%s register dump (IO Port address: 0x%03x): \n", ior->name, ior->io_port_addr);
833	for (idx = 0; idx < 0xff; idx++) {
834		u_int8_t val;
835		struct bit_desc *desc = ior->index[idx].bit_desc;
836
837		if (!ior->index[idx].name)
838			continue;
839
840		outb(idx, ior->io_port_addr);
841		val = inb(ior->io_port_data);
842		printf("   %03x.%02x = 0x%02x (%s)\n", ior->io_port_data, idx, val,
843			ior->index[idx].name);
844
845		if (!desc)
846			continue;
847
848		while (desc->mask) {
849			printf("       0x%02x %s: 0x%02x\n", desc->mask,
850				desc->name, val & desc->mask);
851			desc++;
852		}
853	}
854	printf("\n");
855}
856
857enum pll {
858	PLL_VCK,
859	PLL_ECK,
860	PLL_LDCK,
861};
862
863#define REF_FREQ	14318
864
865static void get_vck_clock(enum pll pll, unsigned int f_ref_khz)
866{
867	u_int8_t reg_ofs = 0;
868	u_int8_t val;
869	unsigned int dm, dtz, dr, dn;
870	unsigned long f_vco, f_out;
871	char *name;
872
873	switch (pll) {
874	case PLL_VCK:
875		reg_ofs = 0;
876		name = "VCK";
877		break;
878	case PLL_ECK:
879		reg_ofs = 3;
880		name = "ECK";
881		break;
882	case PLL_LDCK:
883		reg_ofs = 6;
884		name = "LDCK";
885		break;
886	default:
887		return;
888	}
889
890	dm = readb_idx_reg(0x3c5, 0x44 + reg_ofs);
891
892	val = readb_idx_reg(0x3c5, 0x45 + reg_ofs);
893	dtz = val & 0x1;
894	dr = (val >> 3) & 0x7;
895	dm |= ((val >> 6) & 0x3) << 8;
896
897	val = readb_idx_reg(0x3c5, 0x46 + reg_ofs);
898	dtz |= (val & 0x1) << 1;
899	dn = val >> 1;
900
901	printf("%s PLL: dm=%d, dtx=%d, dr=%d, dn=%d ", name, dm, dtz, dr, dn);
902
903	f_vco = f_ref_khz * (dm + 2) / (dn + 2);
904	if (dr)
905		f_out = f_ref_khz * (dm + 2) / ( (dn + 2) * (2 * dr) );
906	else
907		f_out = 0;
908
909	printf("%s Fvco=%lu kHz, Fout=%lu kHz\n", name, f_vco, f_out);
910}
911
912struct gpio_state {
913	u_int32_t mode_output;
914	u_int32_t pin_status;
915	u_int32_t output_bit;
916	u_int32_t alt_function;
917};
918
919static int get_gpio_state(struct gpio_state *s)
920{
921	u_int8_t val;
922
923	memset(s, 0, sizeof(*s));
924
925	val = readb_idx_reg(0x3c5, 0x2c);
926	if (val & 0x01)
927		s->alt_function |= (3 << 2);
928	if (val & 0x04)
929		s->pin_status |= (1 << 3);
930	if (val & 0x08)
931		s->pin_status |= (1 << 2);
932	if (val & 0x10)
933		s->output_bit |= (1 << 3);
934	if (val & 0x20)
935		s->output_bit |= (1 << 2);
936	if (val & 0x40)
937		s->mode_output |= (1 << 3);
938	if (val & 0x80)
939		s->mode_output |= (1 << 2);
940
941	val = readb_idx_reg(0x3c5, 0x3d);
942	if (val & 0x01)
943		s->alt_function |= (3 << 4);
944	if (val & 0x04)
945		s->pin_status |= (1 << 5);
946	if (val & 0x08)
947		s->pin_status |= (1 << 4);
948	if (val & 0x10)
949		s->output_bit |= (1 << 5);
950	if (val & 0x20)
951		s->output_bit |= (1 << 4);
952	if (val & 0x40)
953		s->mode_output |= (1 << 5);
954	if (val & 0x80)
955		s->mode_output |= (1 << 4);
956
957}
958
959static void dump_gpio_state(const char *pfx, const struct gpio_state *gs)
960{
961	int i;
962
963	for (i = 2; i < 6; i++) {
964		printf("%sGPIO %u: function=", pfx, i);
965
966		if (gs->alt_function & (1 << i))
967			printf("alternate\n");
968		else if (gs->mode_output & (1 << i))
969			printf("output(%u)\n", gs->output_bit & (1 <<i) ? 1 : 0);
970		else
971			printf("input(%u)\n", gs->pin_status & (1 << i) ? 1 : 0);
972	}
973}
974
975static void dump_all_registers(void)
976{
977	int i;
978
979	for (i = 0; i < ARRAY_SIZE(io_regs); i++) {
980		struct io_reg *reg = io_regs[i];
981		if (!reg)
982			break;
983		dump_registers(reg);
984	}
985
986}
987
988static void dump_mode(const char *pfx, struct mode *m)
989{
990	printf("%sH total=%u, active=%u, blank (%u-%u), sync(%u-%u)\n",
991		pfx, m->h.total, m->h.active, m->h.blank_start, m->h.blank_end,
992		m->h.retr_start, m->h.retr_end);
993	printf("%sV total=%u, active=%u, blank (%u-%u), sync(%u-%u)\n",
994		pfx, m->v.total, m->v.active, m->v.blank_start, m->v.blank_end,
995		m->v.retr_start, m->v.retr_end);
996	printf("base_addr=0x%08x, bpp=%d\n", m->addr_start, m->bpp);
997}
998
999static void dump_sl(const char *pfx)
1000{
1001	u_int8_t val;
1002	unsigned int sl_size_mb;
1003	unsigned long rtsf_in_sl_addr;
1004	u_int64_t sl_in_mem_addr;
1005
1006	val = readb_idx_reg(0x3c5, 0x68);
1007	switch (val) {
1008	case 0:
1009		sl_size_mb = 512;
1010		break;
1011	case 0x80:
1012		sl_size_mb = 256;
1013		break;
1014	case 0xc0:
1015		sl_size_mb = 128;
1016		break;
1017	case 0xe0:
1018		sl_size_mb = 64;
1019		break;
1020	case 0xf0:
1021		sl_size_mb = 32;
1022		break;
1023	case 0xf8:
1024		sl_size_mb = 16;
1025		break;
1026	case 0xfc:
1027		sl_size_mb = 8;
1028		break;
1029	case 0xfe:
1030		sl_size_mb = 4;
1031		break;
1032	case 0xff:
1033		sl_size_mb = 2;
1034		break;
1035	}
1036
1037	rtsf_in_sl_addr  = readb_idx_reg(0x3c5, 0x6a) << 12;
1038	rtsf_in_sl_addr |= readb_idx_reg(0x3c5, 0x6b) << 20;
1039	val = readb_idx_reg(0x3c5, 0x6c);
1040	rtsf_in_sl_addr |= (val & 0x1) << 28;
1041
1042	sl_in_mem_addr = readb_idx_reg(0x3c5, 0x6d) << 21;
1043	sl_in_mem_addr |= readb_idx_reg(0x3c5, 0x6d) << 29;
1044	sl_in_mem_addr |= (readb_idx_reg(0x3c5, 0x6d) & 0x7f) << 37;
1045
1046	printf("%sSL in System memory: 0x%llx, RTSF in SL: 0x%lx\n",
1047		pfx, sl_in_mem_addr, rtsf_in_sl_addr);
1048}
1049
1050static int dump_lvds(void)
1051{
1052	u_int8_t val;
1053	char *mode;
1054
1055	writeb_idx_mask(0x3c5, 0x5a, 0x01, 0x01);
1056
1057	val = readb_idx_reg(0x3c5, 0x13);
1058	switch (val >> 6) {
1059	case 0:
1060		mode = "LVDS1 + LVDS2";
1061		break;
1062	case 2:
1063		mode = "One Dual LVDS Channel";
1064		break;
1065	default:
1066		mode = "RESERVED";
1067		break;
1068	}
1069	printf("LVDS Seq Mode: %s\n", mode);
1070
1071	val = readb_idx_reg(0x3d5, 0xd2);
1072	switch ((val >> 4) & 3) {
1073	case 0:
1074		mode = "LVDS1 + LVDS2";
1075		break;
1076	case 2:
1077		mode = "One Dual LVDS Channel";
1078		break;
1079	default:
1080		mode = "RESERVED";
1081		break;
1082	}
1083	printf("LVDS CRT Mode: %s\n", mode);
1084	printf("LVDS Channel 1 Format %s, Power %s\n",
1085		val & 2 ? "OpenLDI":"SPWG", val & 0x80 ? "Down" : "Up");
1086	printf("LVDS Channel 2 Format %s, Power %s\n",
1087		val & 1 ? "OpenLDI":"SPWG", val & 0x40 ? "Down" : "Up");
1088
1089}
1090static int parse_ioreg(u_int16_t *reg, u_int8_t *index, char *str)
1091{
1092	char *dot;
1093	char buf[255];
1094
1095	memset(buf, 0, sizeof(*buf));
1096	strncpy(buf, str, sizeof(buf)-1);
1097
1098	dot = strchr(buf, '.');
1099	if (!dot)
1100		return -EINVAL;
1101	*dot = '\0';
1102
1103	*reg = strtoul(buf, NULL, 16);
1104	*index = strtoul(dot+1, NULL, 16);
1105
1106	return 0;
1107}
1108
1109static void reset_mode(int secondary)
1110{
1111	if (!secondary) {
1112		writeb_idx_mask(0x3d5, 0x11, 0x00 , 0x80);
1113		writeb_idx_mask(0x3d5, 0x03, 0x80 , 0x80);
1114	} else {
1115	}
1116}
1117
1118static void unlock_registers(void)
1119{
1120	writeb_idx_reg(0x3c5, 0x10, 0x01); /* unlock extended */
1121	writeb_idx_mask(0x3d5, 0x47, 0x00, 0x01);	/* unlock CRT */
1122	writeb_idx_mask(0x3d5, 0x03, 0x80, 0x80);	/* disable EGA lightpen */
1123	writeb_idx_mask(0x3d5, 0x11, 0x00, 0x80);	/* unlock 0..7 */
1124}
1125
1126static void usage(void)
1127{
1128	printf("Usage :\n");
1129	printf("-h | --help  : Display this usage message.\n");
1130	printf("-d | --dump  : Dump all registers.\n");
1131	printf("-p | --pll   : Display PLL.\n");
1132	printf("-m | --mode  : Display modes.\n");
1133	printf("-r | --read  : Read register. Example : $0 -r 3d5.17\n");
1134	printf("-w | --write : Write register. Example : $0 -w 3d5.17 0xa3\n");
1135	printf("-g | --gpio  : Display GPIO state.\n");
1136}
1137
1138int main(int argc, char **argv)
1139{
1140	struct mode m;
1141	struct gpio_state gs;
1142	int rc, option_index = 0;
1143
1144	printf("via-chrome-tool (C) 2009 by VIA Technologies, Inc.\n");
1145	printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n");
1146
1147	rc = iopl(3);
1148	if (rc < 0) {
1149		perror("iopl");
1150		printf("Need root privileges.\n");
1151		exit(1);
1152	}
1153
1154	if (argc <= 1) {
1155		usage();
1156		exit(1);
1157	}
1158
1159	unlock_registers();
1160
1161	while (1) {
1162		int c;
1163		u_int16_t reg;
1164		u_int8_t index;
1165		unsigned long val;
1166		static struct option long_options[] = {
1167			{ "help", 0, 0, 'h' },
1168			{ "dump", 0, 0, 'd' },
1169			{ "pll", 0, 0, 'p' },
1170			{ "mode", 0, 0, 'm' },
1171			{ "read", 1, 0, 'r' },
1172			{ "write", 1, 0, 'w' },
1173			{ "gpio", 1, 0, 'g' },
1174		};
1175
1176		c = getopt_long(argc, argv, "hdpmr:w:g", long_options,
1177				&option_index);
1178
1179		if (c == -1) {
1180			break;
1181		}
1182
1183		switch (c) {
1184		case 'h':
1185			usage();
1186			exit(1);
1187		case 'd':
1188			dump_all_registers();
1189			break;
1190		case 'p':
1191			get_vck_clock(PLL_VCK, REF_FREQ);
1192			get_vck_clock(PLL_ECK, REF_FREQ);
1193			get_vck_clock(PLL_LDCK, REF_FREQ);
1194			break;
1195		case 'm':
1196			dump_sl("");
1197			printf("Primary Display:\n");
1198			get_mode(&m, 0);
1199			dump_mode("    ", &m);
1200			printf("\n");
1201			printf("Secondary Display:\n");
1202			get_mode(&m, 1);
1203			dump_mode("    ", &m);
1204			printf("\n");
1205			dump_scaling();
1206			printf("\n");
1207			dump_lvds();
1208			printf("\n");
1209			break;
1210		case 'r':
1211			parse_ioreg(&reg, &index, optarg);
1212			printf("%03x.%02x = 0x%02x\n", reg, index,
1213				readb_idx_reg(reg, index));
1214			break;
1215		case 'w':
1216			parse_ioreg(&reg, &index, optarg);
1217			/* we need one extra argument */
1218			if (argc <= optind)
1219				exit(1);
1220			val = strtoul(argv[optind], NULL, 16);
1221			if (val > 0xff)
1222				exit(1);
1223			writeb_idx_reg(reg, index, val);
1224			printf("%03x.%02x = 0x%02x\n", reg, index,
1225				readb_idx_reg(reg, index));
1226			break;
1227		case 'g':
1228			printf("GPIO State\n");
1229			get_gpio_state(&gs);
1230			dump_gpio_state("    ", &gs);
1231			printf("\n");
1232			break;
1233		default:
1234			usage();
1235			exit(1);
1236		}
1237	}
1238
1239	exit(0);
1240}
1241