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