/* * Copyright 2007-2015 The Openchrome Project * [https://www.freedesktop.org/wiki/Openchrome] * Copyright 1998-2007 VIA Technologies, Inc. All Rights Reserved. * Copyright 2001-2007 S3 Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sub license, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* * Integrated LVDS power management functions. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "via_driver.h" #include "via_mode.h" #include /* * Option handling. */ enum ViaPanelOpts { OPTION_CENTER }; static OptionInfoRec ViaPanelOptions[] = { {OPTION_CENTER, "Center", OPTV_BOOLEAN, {0}, FALSE}, {-1, NULL, OPTV_NONE, {0}, FALSE} }; /* These table values were copied from lcd.c of VIA Frame * Buffer device driver. */ /* {int Width, int Height, bool useDualEdge, bool useDithering}; */ static ViaPanelModeRec ViaPanelNativeModes[] = { { 640, 480, FALSE, TRUE}, { 800, 600, FALSE, TRUE}, {1024, 768, FALSE, TRUE}, {1280, 768, FALSE, TRUE}, {1280, 1024, TRUE, TRUE}, {1400, 1050, TRUE, TRUE}, {1600, 1200, TRUE, TRUE}, {1280, 800, FALSE, TRUE}, { 800, 480, FALSE, TRUE}, {1024, 768, TRUE, TRUE}, {1024, 768, FALSE, FALSE}, {1024, 768, TRUE, FALSE}, {1280, 768, FALSE, FALSE}, {1280, 1024, TRUE, FALSE}, {1400, 1050, TRUE, FALSE}, {1600, 1200, TRUE, FALSE}, {1366, 768, FALSE, FALSE}, {1024, 600, FALSE, TRUE}, {1280, 768, TRUE, TRUE}, {1280, 800, FALSE, TRUE}, {1360, 768, FALSE, FALSE}, {1280, 768, TRUE, FALSE}, { 480, 640, FALSE, TRUE}, {1200, 900, FALSE, FALSE}}; #define MODEPREFIX(name) NULL, NULL, name, 0, M_T_DRIVER | M_T_DEFAULT #define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0 static DisplayModeRec OLPCMode = { MODEPREFIX("1200x900"), 57275, 1200, 1208, 1216, 1240, 0, 900, 905, 908, 912, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }; /* 1. Formula: 2^13 X 0.0698uSec [1/14.318MHz] = 8192 X 0.0698uSec =572.1uSec Timer = Counter x 572 uSec 2. Note: 0.0698 uSec is too small to compute for hardware. So we multiply a reference value(2^13) to make it big enough to compute for hardware. 3. Note: The meaning of the TD0~TD3 are count of the clock. TD(sec) = (sec)/(per clock) x (count of clocks) */ #define TD0 200 #define TD1 25 #define TD2 0 #define TD3 25 /* * Sets CX700 or later single chipset's LVDS1 I/O pad state. */ void viaLVDS1SetIOPadSetting(ScrnInfoPtr pScrn, CARD8 ioPadState) { vgaHWPtr hwp = VGAHWPTR(pScrn); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaLVDS1SetIOPadSetting.\n")); /* Set LVDS1 I/O pad state. */ /* 3C5.2A[1:0] - LVDS1 I/O Pad Control */ ViaSeqMask(hwp, 0x2A, ioPadState, 0x03); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS1 I/O Pad State: %d\n", (ioPadState & 0x03)); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaLVDS1SetIOPadSetting.\n")); } /* * Sets IGA1 or IGA2 as the display output source for VIA Technologies * Chrome IGP LVDS1 integrated LVDS transmitter. */ static void viaLVDS1SetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource) { vgaHWPtr hwp = VGAHWPTR(pScrn); CARD8 temp = displaySource; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaLVDS1SetDisplaySource.\n")); /* Set LVDS1 integrated LVDS transmitter display output source. */ /* 3X5.99[4] - LVDS Channel 1 Data Source Selection * 0: Primary Display * 1: Secondary Display */ ViaCrtcMask(hwp, 0x99, temp << 4, 0x10); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS1 Integrated LVDS Transmitter Display Output " "Source: IGA%d\n", (temp & 0x01) + 1); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaLVDS1SetDisplaySource.\n")); } /* * Sets LVDS1 (LVDS Channel 1) integrated LVDS transmitter format. */ static void viaLVDS1SetFormat(ScrnInfoPtr pScrn, CARD8 format) { vgaHWPtr hwp = VGAHWPTR(pScrn); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaLVDS1SetFormat.\n")); /* Set LVDS1 format. */ /* 3X5.D2[1] - LVDS Channel 1 Format Selection * 0: SPWG Mode * 1: OPENLDI Mode */ ViaCrtcMask(hwp, 0xD2, format << 1, 0x02); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS1 Format: %s\n", (format & 0x01) ? "OPENLDI" : "SPWG"); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaLVDS1SetFormat.\n")); } /* * Sets CX700 or later single chipset's LVDS2 I/O pad state. */ static void viaLVDS2SetIOPadSetting(ScrnInfoPtr pScrn, CARD8 ioPadState) { vgaHWPtr hwp = VGAHWPTR(pScrn); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaLVDS2SetIOPadSetting.\n")); /* Set LVDS2 I/O pad state. */ /* 3C5.2A[3:2] - LVDS2 I/O Pad Control */ ViaSeqMask(hwp, 0x2A, ioPadState << 2, 0x0C); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS2 I/O Pad State: %d\n", (ioPadState & 0x03)); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaLVDS2SetIOPadSetting.\n")); } /* * Sets IGA1 or IGA2 as the display output source for VIA Technologies * Chrome IGP LVDS2 integrated LVDS transmitter. */ static void viaLVDS2SetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource) { vgaHWPtr hwp = VGAHWPTR(pScrn); CARD8 temp = displaySource; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaLVDS2SetDisplaySource.\n")); /* Set LVDS2 integrated LVDS transmitter display output source. */ /* 3X5.97[4] - LVDS Channel 2 Data Source Selection * 0: Primary Display * 1: Secondary Display */ ViaCrtcMask(hwp, 0x97, temp << 4, 0x10); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS2 Integrated LVDS Transmitter Display Output " "Source: IGA%d\n", (temp & 0x01) + 1); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaLVDS2SetDisplaySource.\n")); } /* * Sets LVDS2 (LVDS Channel 2) integrated LVDS transmitter delay tap. */ static void viaLVDS2SetDelayTap(ScrnInfoPtr pScrn, CARD8 delayTap) { vgaHWPtr hwp = VGAHWPTR(pScrn); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaLVDS2SetDelayTap.\n")); /* Set LVDS2 delay tap. */ /* 3X5.97[3:0] - LVDS2 Delay Tap */ ViaCrtcMask(hwp, 0x97, delayTap, 0x0F); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS2 Delay Tap: %d\n", (delayTap & 0x0F)); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaLVDS2SetDelayTap.\n")); } /* * Sets LVDS2 (LVDS Channel 2) integrated LVDS transmitter format. */ static void viaLVDS2SetFormat(ScrnInfoPtr pScrn, CARD8 format) { vgaHWPtr hwp = VGAHWPTR(pScrn); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaLVDS2SetFormat.\n")); /* Set LVDS2 format. */ /* 3X5.D2[0] - LVDS Channel 2 Format Selection * 0: SPWG Mode * 1: OPENLDI Mode */ ViaCrtcMask(hwp, 0xD2, format, 0x01); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS2 Format: %s\n", (format & 0x01) ? "OPENLDI" : "SPWG"); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaLVDS2SetFormat.\n")); } /* * Sets IGA1 or IGA2 as the display output source for VIA Technologies * Chrome IGP DFP (Digital Flat Panel) High interface. */ static void viaDFPHighSetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource) { vgaHWPtr hwp = VGAHWPTR(pScrn); CARD8 temp = displaySource; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaDFPHighSetDisplaySource.\n")); /* Set DFP High display output source. */ /* 3X5.97[4] - DFP High Data Source Selection * 0: Primary Display * 1: Secondary Display */ ViaCrtcMask(hwp, 0x97, temp << 4, 0x10); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DFP High Display Output Source: IGA%d\n", (temp & 0x01) + 1); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaDFPHighSetDisplaySource.\n")); } /* * Sets DFP (Digital Flat Panel) Low interface delay tap. */ static void viaDFPLowSetDelayTap(ScrnInfoPtr pScrn, CARD8 delayTap) { vgaHWPtr hwp = VGAHWPTR(pScrn); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaDFPLowSetDelayTap.\n")); /* Set DFP Low interface delay tap. */ /* 3X5.99[3:0] - DFP Low Delay Tap */ ViaCrtcMask(hwp, 0x99, delayTap, 0x0F); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DFP Low Delay Tap: %d\n", (delayTap & 0x0F)); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaDFPLowSetDelayTap.\n")); } /* * Sets DFP (Digital Flat Panel) High interface delay tap. */ static void viaDFPHighSetDelayTap(ScrnInfoPtr pScrn, CARD8 delayTap) { vgaHWPtr hwp = VGAHWPTR(pScrn); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaDFPHighSetDelayTap.\n")); /* Set DFP High interface delay tap. */ /* 3X5.97[3:0] - DFP High Delay Tap */ ViaCrtcMask(hwp, 0x97, delayTap, 0x0F); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DFP High Delay Tap: %d\n", (delayTap & 0x0F)); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaDFPHighSetDelayTap.\n")); } /* * Turns LVDS2 output color dithering on or off. (18-bit color display vs. * 24-bit color display) */ static void viaLVDS2SetDithering(ScrnInfoPtr pScrn, CARD8 ditheringStatus) { vgaHWPtr hwp = VGAHWPTR(pScrn); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaLVDS2SetDithering.\n")); /* Set LVDS2 output color dithering bit. */ /* 3X5.D4[6] - LVDS Channel 2 Output Bits * 0: 24 bits (dithering off) * 1: 18 bits (dithering on) */ ViaCrtcMask(hwp, 0xD4, ditheringStatus ? 0x40 : 0x00, 0x40); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS2 Output Color Dithering: %s\n", ditheringStatus ? "On (18 bit)" : "Off (24 bit)"); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaLVDS2SetDithering.\n")); } /* * Sets output format of LVDS2 to rotation or sequential mode. */ static void viaLVDS2SetOutputFormat(ScrnInfoPtr pScrn, CARD8 outputFormat) { vgaHWPtr hwp = VGAHWPTR(pScrn); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaLVDS2SetOutputFormat.\n")); /* Set LVDS2 output format. */ /* 3X5.D4[7] - LVDS Channel 2 Output Format * 0: Rotation * 1: Sequential */ ViaCrtcMask(hwp, 0xD4, outputFormat ? 0x80 : 0x00, 0x80); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS2 Output Format: %s\n", outputFormat ? "Sequential" : "Rotation"); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaLVDS2SetOutputFormat.\n")); } /* * Sets PCIe based 2 chip chipset's pin multiplexed DVP0 I/O pad state. */ static void viaDVP0PCIeSetIOPadSetting(ScrnInfoPtr pScrn, CARD8 ioPadState) { vgaHWPtr hwp = VGAHWPTR(pScrn); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaDVP0PCIeSetIOPadSetting.\n")); /* Set pin multiplexed DVP1 I/O pad state. */ /* 3C5.2A[3:2] - DVP0 I/O Pad Control */ ViaSeqMask(hwp, 0x2A, ioPadState << 2, 0x0C); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DVP0 I/O Pad State: %d\n", (ioPadState & 0x03)); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaDVP0PCIeSetIOPadSetting.\n")); } /* * Sets PCIe based 2 chip chipset's pin multiplexed DVP1 I/O pad state. */ static void viaDVP1PCIeSetIOPadSetting(ScrnInfoPtr pScrn, CARD8 ioPadState) { vgaHWPtr hwp = VGAHWPTR(pScrn); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaDVP1PCIeSetIOPadSetting.\n")); /* Set pin multiplexed DVP0 I/O pad state. */ /* 3C5.2A[1:0] - DVP1 I/O Pad Control */ ViaSeqMask(hwp, 0x2A, ioPadState, 0x03); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DVP1 I/O Pad State: %d\n", (ioPadState & 0x03)); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaDVP1PCIeSetIOPadSetting.\n")); } static void viaFPIOPadSetting(ScrnInfoPtr pScrn, Bool ioPadOn) { vgaHWPtr hwp = VGAHWPTR(pScrn); VIAPtr pVia = VIAPTR(pScrn); CARD8 sr12, sr13, sr5a; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPIOPadSetting.\n")); if ((pVia->Chipset == VIA_CX700) || (pVia->Chipset == VIA_VX800) || (pVia->Chipset == VIA_VX855) || (pVia->Chipset == VIA_VX900)) { sr5a = hwp->readSeq(hwp, 0x5A); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SR5A: 0x%02X\n", sr5a)); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting 3C5.5A[0] to 0.\n")); ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01); } sr12 = hwp->readSeq(hwp, 0x12); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SR12: 0x%02X\n", sr12)); sr13 = hwp->readSeq(hwp, 0x13); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SR13: 0x%02X\n", sr13)); switch (pVia->Chipset) { case VIA_CLE266: break; case VIA_KM400: case VIA_K8M800: case VIA_PM800: case VIA_P4M800PRO: break; case VIA_P4M890: case VIA_K8M890: case VIA_P4M900: /* The tricky thing about VIA Technologies PCI Express based * north bridge / south bridge 2 chip chipset is that * it pin multiplexes DVP0 / DVP1 with north bridge's PCI * Express x16 link. In particular, HP 2133 Mini-Note's WLAN * is connected to north bridge's PCI Express Lane 0, but the * Lane 0 is also pin multiplexed with DVP0. What this means is * turning on DVP0 without probing the relevant strapping pin * to determine the connected panel interface type will lead to * the PCIe based WLAN to getting disabled by OpenChrome DDX * when X.Org Server starts. * The current remedy for this will be to turn on DVP0 * only when an 18-bit / 24-bit interface flat panel is * connected. */ /* 3C5.12[4] - DVP0D4 pin strapping * 0: Use DVP1 only for a flat panel. * 1: Use DVP0 and DVP1 for a flat panel */ if (sr12 & 0x10) { /* Since an 18-bit / 24-bit flat panel is being used, actively * control DVP0. */ viaDVP0PCIeSetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00); } else { /* Keep DVP0 powered down. Otherwise, it will interfere with * PCIe Lane 0 through 7. */ viaDVP0PCIeSetIOPadSetting(pScrn, 0x00); } /* Control DVP1 for a flat panel. */ viaDVP1PCIeSetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00); break; case VIA_CX700: case VIA_VX800: case VIA_VX855: case VIA_VX900: /* 3C5.13[7:6] - DVP1D15 and DVP1D14 pin strappings * 00: LVDS1 + LVDS2 * 01: DVI + LVDS2 * 10: Dual LVDS (LVDS1 + LVDS2 used * simultaneously) * 11: DVI only */ if ((((~(sr13 & 0x80)) && (~(sr13 & 0x40))) || ((sr13 & 0x80) && (~(sr13 & 0x40)))) && (!pVia->isVIANanoBook)) { viaLVDS1SetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00); } if (((~(sr13 & 0x80)) || (~(sr13 & 0x40))) || (pVia->isVIANanoBook)) { viaLVDS2SetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00); } break; default: break; } if ((pVia->Chipset == VIA_CX700) || (pVia->Chipset == VIA_VX800) || (pVia->Chipset == VIA_VX855) || (pVia->Chipset == VIA_VX900)) { hwp->writeSeq(hwp, 0x5A, sr5a); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Restoring 3C5.5A[0].\n")); } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPIOPadSetting.\n")); } static void ViaLVDSSoftwarePowerFirstSequence(ScrnInfoPtr pScrn, Bool on) { vgaHWPtr hwp = VGAHWPTR(pScrn); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaLVDSSoftwarePowerFirstSequence: %d\n", on)); if (on) { /* Software control power sequence ON*/ hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0x7F); hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x01); usleep(TD0); /* VDD ON*/ hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x10); usleep(TD1); /* DATA ON */ hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x08); usleep(TD2); /* VEE ON (unused on vt3353)*/ hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x04); usleep(TD3); /* Back-Light ON */ hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x02); } else { /* Back-Light OFF */ hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xFD); usleep(TD3); /* VEE OFF (unused on vt3353)*/ hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xFB); usleep(TD2); /* DATA OFF */ hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xF7); usleep(TD1); /* VDD OFF */ hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xEF); } } static void ViaLVDSSoftwarePowerSecondSequence(ScrnInfoPtr pScrn, Bool on) { vgaHWPtr hwp = VGAHWPTR(pScrn); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaLVDSSoftwarePowerSecondSequence: %d\n", on)); if (on) { /* Secondary power hardware power sequence enable 0:off 1: on */ hwp->writeCrtc(hwp, 0xD4, hwp->readCrtc(hwp, 0xD4) & 0xFD); /* Software control power sequence ON */ hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x01); usleep(TD0); /* VDD ON*/ hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x10); usleep(TD1); /* DATA ON */ hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x08); usleep(TD2); /* VEE ON (unused on vt3353)*/ hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x04); usleep(TD3); /* Back-Light ON */ hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x02); } else { /* Back-Light OFF */ hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xFD); usleep(TD3); /* VEE OFF */ hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xFB); /* Delay TD2 msec. */ usleep(TD2); /* DATA OFF */ hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xF7); /* Delay TD1 msec. */ usleep(TD1); /* VDD OFF */ hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xEF); } } static void ViaLVDSHardwarePowerFirstSequence(ScrnInfoPtr pScrn, Bool on) { vgaHWPtr hwp = VGAHWPTR(pScrn); if (on) { /* Use hardware control power sequence. */ hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xFE); /* Turn on back light. */ hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0x3F); /* Turn on hardware power sequence. */ hwp->writeCrtc(hwp, 0x6A, hwp->readCrtc(hwp, 0x6A) | 0x08); } else { /* Turn off power sequence. */ hwp->writeCrtc(hwp, 0x6A, hwp->readCrtc(hwp, 0x6A) & 0xF7); usleep(1); /* Turn off back light. */ hwp->writeCrtc(hwp, 0x91, 0xC0); } } static void ViaLVDSHardwarePowerSecondSequence(ScrnInfoPtr pScrn, Bool on) { vgaHWPtr hwp = VGAHWPTR(pScrn); if (on) { /* Use hardware control power sequence. */ hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xFE); /* Turn on back light. */ hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0x3F); /* Turn on hardware power sequence. */ hwp->writeCrtc(hwp, 0xD4, hwp->readCrtc(hwp, 0xD4) | 0x02); } else { /* Turn off power sequence. */ hwp->writeCrtc(hwp, 0xD4, hwp->readCrtc(hwp, 0xD4) & 0xFD); usleep(1); /* Turn off back light. */ hwp->writeCrtc(hwp, 0xD3, 0xC0); } } static void ViaLVDSPowerChannel(ScrnInfoPtr pScrn, Bool on) { vgaHWPtr hwp = VGAHWPTR(pScrn); CARD8 lvdsMask; if (on) { /* LVDS0: 0x7F, LVDS1: 0xBF */ lvdsMask = 0x7F & 0xBF; hwp->writeCrtc(hwp, 0xD2, hwp->readCrtc(hwp, 0xD2) & lvdsMask); } else { /* LVDS0: 0x80, LVDS1: 0x40 */ lvdsMask = 0x80 | 0x40; hwp->writeCrtc(hwp, 0xD2, hwp->readCrtc(hwp, 0xD2) | lvdsMask); } } static void ViaLVDSPower(ScrnInfoPtr pScrn, Bool Power_On) { vgaHWPtr hwp = VGAHWPTR(pScrn); VIAPtr pVia = VIAPTR(pScrn); CARD8 crd2; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered ViaLVDSPower.\n")); /* * VX800, CX700 have HW issue, so we'd better use SW power sequence * Fix Ticket #308 */ switch (pVia->Chipset) { case VIA_CX700: case VIA_VX800: /* Is the integrated TMDS transmitter (DVI) not in use? */ crd2 = hwp->readCrtc(hwp, 0xD2); if (((pVia->Chipset == VIA_CX700) || (pVia->Chipset == VIA_VX800) || (pVia->Chipset == VIA_VX855) || (pVia->Chipset == VIA_VX900)) && (!(crd2 & 0x10))) { ViaLVDSSoftwarePowerFirstSequence(pScrn, Power_On); } ViaLVDSSoftwarePowerSecondSequence(pScrn, Power_On); break; case VIA_VX855: case VIA_VX900: /* Is the integrated TMDS transmitter (DVI) not in use? */ crd2 = hwp->readCrtc(hwp, 0xD2); if (((pVia->Chipset == VIA_CX700) || (pVia->Chipset == VIA_VX800) || (pVia->Chipset == VIA_VX855) || (pVia->Chipset == VIA_VX900)) && (!(crd2 & 0x10))) { ViaLVDSHardwarePowerFirstSequence(pScrn, Power_On); } ViaLVDSHardwarePowerSecondSequence(pScrn, Power_On); break; default: ViaLVDSHardwarePowerFirstSequence(pScrn, Power_On); ViaLVDSHardwarePowerSecondSequence(pScrn, Power_On); break; } ViaLVDSPowerChannel(pScrn, Power_On); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Integrated LVDS Flat Panel Power: %s\n", Power_On ? "On" : "Off"); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting ViaLVDSPower.\n")); } static void ViaLCDPowerSequence(vgaHWPtr hwp, VIALCDPowerSeqRec Sequence) { int i; for (i = 0; i < Sequence.numEntry; i++) { ViaVgahwMask(hwp, 0x300 + Sequence.port[i], Sequence.offset[i], 0x301 + Sequence.port[i], Sequence.data[i], Sequence.mask[i]); usleep(Sequence.delay[i]); } } static void ViaLCDPower(xf86OutputPtr output, Bool Power_On) { ViaPanelInfoPtr Panel = output->driver_private; ScrnInfoPtr pScrn = output->scrn; vgaHWPtr hwp = VGAHWPTR(pScrn); VIAPtr pVia = VIAPTR(pScrn); VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo; int i; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered ViaLCDPower.\n")); /* Enable LCD */ if (Power_On) ViaCrtcMask(hwp, 0x6A, 0x08, 0x08); else ViaCrtcMask(hwp, 0x6A, 0x00, 0x08); if (pBIOSInfo->LCDPower) pBIOSInfo->LCDPower(pScrn, Power_On); /* Find Panel Size Index for PowerSeq Table */ if (pVia->Chipset == VIA_CLE266) { if (Panel->NativeModeIndex != VIA_PANEL_INVALID) { for (i = 0; i < NumPowerOn; i++) { if (lcdTable[Panel->PanelIndex].powerSeq == powerOn[i].powerSeq) break; } } else i = 0; } else /* KM and K8M use PowerSeq Table index 2. */ i = 2; usleep(1); if (Power_On) ViaLCDPowerSequence(hwp, powerOn[i]); else ViaLCDPowerSequence(hwp, powerOff[i]); usleep(1); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Integrated LVDS Flat Panel Power: %s\n", Power_On ? "On" : "Off"); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting ViaLCDPower.\n")); } /* * Try to interpret EDID ourselves. */ static Bool ViaPanelGetSizeFromEDID(ScrnInfoPtr pScrn, xf86MonPtr pMon, int *width, int *height) { int i, max_hsize = 0, vsize = 0; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAGetPanelSizeFromEDID\n")); /* !!! Why are we not checking VESA modes? */ /* checking standard timings */ for (i = 0; i < STD_TIMINGS; i++) if ((pMon->timings2[i].hsize > 256) && (pMon->timings2[i].hsize > max_hsize)) { max_hsize = pMon->timings2[i].hsize; vsize = pMon->timings2[i].vsize; } if (max_hsize != 0) { *width = max_hsize; *height = vsize; return TRUE; } /* checking detailed monitor section */ /* !!! skip Ranges and standard timings */ /* check detailed timings */ for (i = 0; i < DET_TIMINGS; i++) if (pMon->det_mon[i].type == DT) { struct detailed_timings timing = pMon->det_mon[i].section.d_timings; /* ignore v_active for now */ if ((timing.clock > 15000000) && (timing.h_active > max_hsize)) { max_hsize = timing.h_active; vsize = timing.v_active; } } if (max_hsize != 0) { *width = max_hsize; *height = vsize; return TRUE; } return FALSE; } static Bool ViaPanelGetSizeFromDDCv1(xf86OutputPtr output, int *width, int *height) { ScrnInfoPtr pScrn = output->scrn; VIAPtr pVia = VIAPTR(pScrn); xf86MonPtr pMon; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered VIAGetPanelSizeFromDDCv1.\n")); if (!pVia->pI2CBus2) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "I2C Bus 2 does not exist.\n"); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting VIAGetPanelSizeFromDDCv1.\n")); return FALSE; } if (!xf86I2CProbeAddress(pVia->pI2CBus2, 0xA0)) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "I2C device on I2C Bus 2 does not support EDID.\n"); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting VIAGetPanelSizeFromDDCv1.\n")); return FALSE; } /* Probe I2C Bus 2 to see if a flat panel is connected. */ xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Probing for a flat panel on I2C Bus 2.\n"); pMon = xf86OutputGetEDID(output, pVia->pI2CBus2); if (pMon && DIGITAL(pMon->features.input_type)) { xf86OutputSetEDID(output, pMon); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected a flat panel on I2C Bus 2.\n"); } else { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Did not detect a flat panel on I2C Bus 2.\n"); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting VIAGetPanelSizeFromDDCv1.\n")); return FALSE; } if (!ViaPanelGetSizeFromEDID(pScrn, pMon, width, height)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to obtain panel size from EDID information.\n"); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting VIAGetPanelSizeFromDDCv1.\n")); return FALSE; } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAGetPanelSizeFromDDCv1: (%d X %d)\n", *width, *height)); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting VIAGetPanelSizeFromDDCv1.\n")); return TRUE; } /* * Gets the native panel resolution from scratch pad registers. */ static void viaLVDSGetFPInfoFromScratchPad(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; vgaHWPtr hwp = VGAHWPTR(pScrn); ViaPanelInfoPtr panel = output->driver_private; CARD8 index; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaLVDSGetFPInfoFromScratchPad.\n")); index = hwp->readCrtc(hwp, 0x3F) & 0x0F; panel->NativeModeIndex = index; panel->NativeWidth = ViaPanelNativeModes[index].Width; panel->NativeHeight = ViaPanelNativeModes[index].Height; panel->useDualEdge = ViaPanelNativeModes[index].useDualEdge; panel->useDithering = ViaPanelNativeModes[index].useDithering; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIA Technologies VGA BIOS Scratch Pad Register " "Flat Panel Index: %d\n", panel->NativeModeIndex); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Flat Panel Native Resolution: %dx%d\n", panel->NativeWidth, panel->NativeHeight); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Flat Panel Dual Edge Transfer: %s\n", panel->useDualEdge ? "On" : "Off"); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Flat Panel Output Color Dithering: %s\n", panel->useDithering ? "On (18 bit)" : "Off (24 bit)"); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaLVDSGetFPInfoFromScratchPad.\n")); } static void ViaPanelCenterMode(DisplayModePtr mode, DisplayModePtr adjusted_mode) { int panelHSyncTime = adjusted_mode->HSyncEnd - adjusted_mode->HSyncStart; int panelVSyncTime = adjusted_mode->VSyncEnd - adjusted_mode->VSyncStart; int panelHBlankStart = adjusted_mode->HDisplay; int panelVBlankStart = adjusted_mode->VDisplay; int hBorder = (adjusted_mode->HDisplay - mode->HDisplay)/2; int vBorder = (adjusted_mode->VDisplay - mode->VDisplay)/2; int newHBlankStart = hBorder + mode->HDisplay; int newVBlankStart = vBorder + mode->VDisplay; adjusted_mode->HDisplay = mode->HDisplay; adjusted_mode->HSyncStart = (adjusted_mode->HSyncStart - panelHBlankStart) + newHBlankStart; adjusted_mode->HSyncEnd = adjusted_mode->HSyncStart + panelHSyncTime; adjusted_mode->VDisplay = mode->VDisplay; adjusted_mode->VSyncStart = (adjusted_mode->VSyncStart - panelVBlankStart) + newVBlankStart; adjusted_mode->VSyncEnd = adjusted_mode->VSyncStart + panelVSyncTime; /* Adjust Crtc H and V */ adjusted_mode->CrtcHDisplay = adjusted_mode->HDisplay; adjusted_mode->CrtcHBlankStart = newHBlankStart; adjusted_mode->CrtcHBlankEnd = adjusted_mode->CrtcHTotal - hBorder; adjusted_mode->CrtcHSyncStart = adjusted_mode->HSyncStart; adjusted_mode->CrtcHSyncEnd = adjusted_mode->HSyncEnd; adjusted_mode->CrtcVDisplay = adjusted_mode->VDisplay; adjusted_mode->CrtcVBlankStart = newVBlankStart; adjusted_mode->CrtcVBlankEnd = adjusted_mode->CrtcVTotal - vBorder; adjusted_mode->CrtcVSyncStart = adjusted_mode->VSyncStart; adjusted_mode->CrtcVSyncEnd = adjusted_mode->VSyncEnd; } static void ViaPanelScale(ScrnInfoPtr pScrn, int resWidth, int resHeight, int panelWidth, int panelHeight) { VIAPtr pVia = VIAPTR(pScrn); vgaHWPtr hwp = VGAHWPTR(pScrn); int horScalingFactor = 0; int verScalingFactor = 0; CARD8 cra2 = 0; CARD8 cr77 = 0; CARD8 cr78 = 0; CARD8 cr79 = 0; CARD8 cr9f = 0; Bool scaling = FALSE; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaPanelScale: %d,%d -> %d,%d\n", resWidth, resHeight, panelWidth, panelHeight)); if (resWidth < panelWidth) { /* Load Horizontal Scaling Factor */ if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) { horScalingFactor = ((resWidth - 1) * 4096) / (panelWidth - 1); /* Horizontal scaling enabled */ cra2 = 0xC0; cr9f = horScalingFactor & 0x0003; /* HSCaleFactor[1:0] at CR9F[1:0] */ } else { /* TODO: Need testing */ horScalingFactor = ((resWidth - 1) * 1024) / (panelWidth - 1); } cr77 = (horScalingFactor & 0x03FC) >> 2; /* HSCaleFactor[9:2] at CR77[7:0] */ cr79 = (horScalingFactor & 0x0C00) >> 10; /* HSCaleFactor[11:10] at CR79[5:4] */ cr79 <<= 4; scaling = TRUE; } if (resHeight < panelHeight) { /* Load Vertical Scaling Factor */ if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) { verScalingFactor = ((resHeight - 1) * 2048) / (panelHeight - 1); /* Vertical scaling enabled */ cra2 |= 0x08; cr79 |= ((verScalingFactor & 0x0001) << 3); /* VSCaleFactor[0] at CR79[3] */ } else { /* TODO: Need testing */ verScalingFactor = ((resHeight - 1) * 1024) / (panelHeight - 1); } cr78 |= (verScalingFactor & 0x01FE) >> 1; /* VSCaleFactor[8:1] at CR78[7:0] */ cr79 |= ((verScalingFactor & 0x0600) >> 9) << 6; /* VSCaleFactor[10:9] at CR79[7:6] */ scaling = TRUE; } if (scaling) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Scaling factor: horizontal %d (0x%x), vertical %d (0x%x)\n", horScalingFactor, horScalingFactor, verScalingFactor, verScalingFactor)); ViaCrtcMask(hwp, 0x77, cr77, 0xFF); ViaCrtcMask(hwp, 0x78, cr78, 0xFF); ViaCrtcMask(hwp, 0x79, cr79, 0xF8); if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) { ViaCrtcMask(hwp, 0x9F, cr9f, 0x03); } ViaCrtcMask(hwp, 0x79, 0x03, 0x03); } else { /* Disable panel scale */ ViaCrtcMask(hwp, 0x79, 0x00, 0x01); } if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) { ViaCrtcMask(hwp, 0xA2, cra2, 0xC8); } /* Horizontal scaling selection: interpolation */ // ViaCrtcMask(hwp, 0x79, 0x02, 0x02); // else // ViaCrtcMask(hwp, 0x79, 0x00, 0x02); /* Horizontal scaling factor selection original / linear */ //ViaCrtcMask(hwp, 0xA2, 0x40, 0x40); } static void ViaPanelScaleDisable(ScrnInfoPtr pScrn) { VIAPtr pVia = VIAPTR(pScrn); vgaHWPtr hwp = VGAHWPTR(pScrn); ViaCrtcMask(hwp, 0x79, 0x00, 0x01); /* Disable VX900 down scaling */ if (pVia->Chipset == VIA_VX900) ViaCrtcMask(hwp, 0x89, 0x00, 0x01); if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) ViaCrtcMask(hwp, 0xA2, 0x00, 0xC8); } static void via_lvds_create_resources(xf86OutputPtr output) { } static void via_lvds_dpms(xf86OutputPtr output, int mode) { ScrnInfoPtr pScrn = output->scrn; VIAPtr pVia = VIAPTR(pScrn); switch (mode) { case DPMSModeOn: switch (pVia->Chipset) { case VIA_PM800: case VIA_P4M800PRO: case VIA_P4M890: case VIA_K8M890: case VIA_P4M900: case VIA_CX700: case VIA_VX800: case VIA_VX855: case VIA_VX900: ViaLVDSPower(pScrn, TRUE); break; default: ViaLCDPower(output, TRUE); break; } viaFPIOPadSetting(pScrn, TRUE); break; case DPMSModeStandby: case DPMSModeSuspend: case DPMSModeOff: switch (pVia->Chipset) { case VIA_PM800: case VIA_P4M800PRO: case VIA_P4M890: case VIA_K8M890: case VIA_P4M900: case VIA_CX700: case VIA_VX800: case VIA_VX855: case VIA_VX900: ViaLVDSPower(pScrn, FALSE); break; default: ViaLCDPower(output, FALSE); break; } viaFPIOPadSetting(pScrn, FALSE); break; } } static void via_lvds_save(xf86OutputPtr output) { } static void via_lvds_restore(xf86OutputPtr output) { ViaLCDPower(output, TRUE); } static int via_lvds_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) { ScrnInfoPtr pScrn = output->scrn; ViaPanelInfoPtr Panel = output->driver_private; if (Panel->NativeWidth < pMode->HDisplay || Panel->NativeHeight < pMode->VDisplay) return MODE_PANEL; if (!Panel->Scale && Panel->NativeHeight != pMode->VDisplay && Panel->NativeWidth != pMode->HDisplay) return MODE_PANEL; if (!ViaModeDotClockTranslate(pScrn, pMode)) return MODE_NOCLOCK; return MODE_OK; } static Bool via_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode) { ViaPanelInfoPtr Panel = output->driver_private; xf86SetModeCrtc(adjusted_mode, 0); if (!Panel->Center && (mode->HDisplay < Panel->NativeWidth || mode->VDisplay < Panel->NativeHeight)) { Panel->Scale = TRUE; } else { Panel->Scale = FALSE; ViaPanelCenterMode(mode, adjusted_mode); } return TRUE; } static void via_lvds_prepare(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; via_lvds_dpms(output, DPMSModeOff); viaFPIOPadSetting(pScrn, FALSE); } static void via_lvds_commit(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; via_lvds_dpms(output, DPMSModeOn); viaFPIOPadSetting(pScrn, TRUE); } static void via_lvds_mode_set(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode) { ViaPanelInfoPtr Panel = output->driver_private; ScrnInfoPtr pScrn = output->scrn; drmmode_crtc_private_ptr iga = output->crtc->driver_private; VIAPtr pVia = VIAPTR(pScrn); if (output->crtc) { if (Panel->Scale) { ViaPanelScale(pScrn, mode->HDisplay, mode->VDisplay, Panel->NativeWidth, Panel->NativeHeight); } else { ViaPanelScaleDisable(pScrn); } switch (pVia->Chipset) { case VIA_P4M900: viaDFPLowSetDelayTap(pScrn, 0x08); break; case VIA_CX700: viaLVDS2SetDelayTap(pScrn, 0x01); break; default: break; } switch (pVia->Chipset) { case VIA_KM400: case VIA_K8M800: case VIA_PM800: case VIA_P4M800PRO: viaDFPLowSetDisplaySource(pScrn, iga->index ? 0x01 : 0x00); viaDFPHighSetDisplaySource(pScrn, iga->index ? 0x01 : 0x00); break; case VIA_P4M890: case VIA_K8M890: case VIA_P4M900: viaDFPLowSetDisplaySource(pScrn, iga->index ? 0x01 : 0x00); viaDVP1SetDisplaySource(pScrn, iga->index ? 0x01 : 0x00); break; case VIA_CX700: case VIA_VX800: case VIA_VX855: case VIA_VX900: viaLVDS2SetDisplaySource(pScrn, iga->index ? 0x01 : 0x00); /* Set LVDS2 output color dithering. */ viaLVDS2SetDithering(pScrn, Panel->useDithering ? TRUE : FALSE); /* Set LVDS2 output format to sequential mode. */ viaLVDS2SetOutputFormat(pScrn, 0x01); /* Set LVDS2 output to OPENLDI mode. */ viaLVDS2SetFormat(pScrn, 0x01); break; default: break; } } } static xf86OutputStatus via_lvds_detect(xf86OutputPtr output) { xf86OutputStatus status = XF86OutputStatusDisconnected; ScrnInfoPtr pScrn = output->scrn; VIAPtr pVia = VIAPTR(pScrn); ViaPanelInfoPtr panel = output->driver_private; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered via_lvds_detect.\n")); /* Hardcode panel size for the OLPC XO-1.5. */ if (pVia->IsOLPCXO15) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Setting up OLPC XO-1.5 flat panel.\n"); panel->NativeWidth = 1200; panel->NativeHeight = 900; status = XF86OutputStatusConnected; goto exit; } /* For now, FP detection code will not scan the I2C bus * in order to obtain EDID since it is often used by DVI * as well. Hence, reading off the CRTC scratch pad register * supplied by the VGA BIOS is the only method available * to figure out the FP native screen resolution. */ viaLVDSGetFPInfoFromScratchPad(output); status = XF86OutputStatusConnected; exit: DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting via_lvds_detect.\n")); return status; } static DisplayModePtr via_lvds_get_modes(xf86OutputPtr output) { ViaPanelInfoPtr pPanel = output->driver_private; ScrnInfoPtr pScrn = output->scrn; DisplayModePtr pDisplay_Mode = NULL; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered via_lvds_get_modes.\n")); if (output->status == XF86OutputStatusConnected) { if (!output->MonInfo) { /* * Generates a display mode for the native panel resolution, * using CVT. */ if (pPanel->NativeWidth && pPanel->NativeHeight) { VIAPtr pVia = VIAPTR(pScrn); if (pVia->IsOLPCXO15) { pDisplay_Mode = xf86DuplicateMode(&OLPCMode); } else { pDisplay_Mode = xf86CVTMode(pPanel->NativeWidth, pPanel->NativeHeight, 60.0f, FALSE, FALSE); xf86SetModeDefaultName(pDisplay_Mode); } if (pDisplay_Mode) { pDisplay_Mode->CrtcHDisplay = pDisplay_Mode->HDisplay; pDisplay_Mode->CrtcHSyncStart = pDisplay_Mode->HSyncStart; pDisplay_Mode->CrtcHSyncEnd = pDisplay_Mode->HSyncEnd; pDisplay_Mode->CrtcHTotal = pDisplay_Mode->HTotal; pDisplay_Mode->CrtcHSkew = pDisplay_Mode->HSkew; pDisplay_Mode->CrtcVDisplay = pDisplay_Mode->VDisplay; pDisplay_Mode->CrtcVSyncStart = pDisplay_Mode->VSyncStart; pDisplay_Mode->CrtcVSyncEnd = pDisplay_Mode->VSyncEnd; pDisplay_Mode->CrtcVTotal = pDisplay_Mode->VTotal; pDisplay_Mode->CrtcVBlankStart = min(pDisplay_Mode->CrtcVSyncStart, pDisplay_Mode->CrtcVDisplay); pDisplay_Mode->CrtcVBlankEnd = max(pDisplay_Mode->CrtcVSyncEnd, pDisplay_Mode->CrtcVTotal); pDisplay_Mode->CrtcHBlankStart = min(pDisplay_Mode->CrtcHSyncStart, pDisplay_Mode->CrtcHDisplay); pDisplay_Mode->CrtcHBlankEnd = max(pDisplay_Mode->CrtcHSyncEnd, pDisplay_Mode->CrtcHTotal); pDisplay_Mode->type = M_T_DRIVER | M_T_PREFERRED; } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Out of memory. Size: %zu bytes\n", sizeof(DisplayModeRec)); } } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Invalid Flat Panel Screen Resolution: " "%dx%d\n", pPanel->NativeWidth, pPanel->NativeHeight); } } else { pDisplay_Mode = xf86OutputGetEDIDModes(output); } } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting via_lvds_get_modes.\n")); return pDisplay_Mode; } #ifdef RANDR_12_INTERFACE static Bool via_lvds_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value) { return FALSE; } static Bool via_lvds_get_property(xf86OutputPtr output, Atom property) { return FALSE; } #endif static void via_lvds_destroy(xf86OutputPtr output) { if (output->driver_private) free(output->driver_private); output->driver_private = NULL; } static const xf86OutputFuncsRec via_lvds_funcs = { .create_resources = via_lvds_create_resources, .dpms = via_lvds_dpms, .save = via_lvds_save, .restore = via_lvds_restore, .mode_valid = via_lvds_mode_valid, .mode_fixup = via_lvds_mode_fixup, .prepare = via_lvds_prepare, .commit = via_lvds_commit, .mode_set = via_lvds_mode_set, .detect = via_lvds_detect, .get_modes = via_lvds_get_modes, #ifdef RANDR_12_INTERFACE .set_property = via_lvds_set_property, #endif #ifdef RANDR_13_INTERFACE .get_property = via_lvds_get_property, #endif .destroy = via_lvds_destroy }; void via_lvds_init(ScrnInfoPtr pScrn) { ViaPanelInfoPtr Panel = (ViaPanelInfoPtr) xnfcalloc(sizeof(ViaPanelInfoRec), 1); OptionInfoPtr Options = xnfalloc(sizeof(ViaPanelOptions)); MessageType from = X_DEFAULT; VIAPtr pVia = VIAPTR(pScrn); xf86OutputPtr output = NULL; vgaHWPtr hwp = VGAHWPTR(pScrn); CARD8 cr3b = 0x00; CARD8 cr3b_mask = 0x00; char outputNameBuffer[32]; if (!Panel) return; /* Apparently this is the way VIA Technologies passes */ /* the presence of a flat panel to the device driver */ /* via BIOS setup. */ if (pVia->Chipset == VIA_CLE266) { cr3b_mask = 0x08; } else { cr3b_mask = 0x02; } cr3b = hwp->readCrtc(hwp, 0x3B) & cr3b_mask; if (!cr3b) { return; } memcpy(Options, ViaPanelOptions, sizeof(ViaPanelOptions)); xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, Options); Panel->NativeModeIndex = VIA_PANEL_INVALID; /* LCD Center/Expend Option */ Panel->Center = FALSE; from = xf86GetOptValBool(Options, OPTION_CENTER, &Panel->Center) ? X_CONFIG : X_DEFAULT; xf86DrvMsg(pScrn->scrnIndex, from, "LVDS-0 : DVI Center is %s.\n", Panel->Center ? "enabled" : "disabled"); /* The code to dynamically designate a particular FP (i.e., FP-1, * FP-2, etc.) for xrandr was borrowed from xf86-video-r128 DDX. */ sprintf(outputNameBuffer, "FP-%d", (pVia->numberFP + 1)); output = xf86OutputCreate(pScrn, &via_lvds_funcs, outputNameBuffer); if (output) { output->driver_private = Panel; /* While there are two (2) display controllers registered with the * X.Org Server, it is often desirable to fix FP (Flat Panel) to * IGA2 since only IGA2 contains panel resolution scaling * functionality. IGA1 does not have this. */ output->possible_crtcs = 1 << 1; output->possible_clones = 0; output->interlaceAllowed = FALSE; output->doubleScanAllowed = FALSE; /* Increment the number of FP connectors. */ pVia->numberFP++; if (pVia->IsOLPCXO15) { output->mm_height = 152; output->mm_width = 114; } } else { free(Panel); } }