/* * Copyright 2017-2018 Kevin Brace. All Rights Reserved. * Copyright 2007-2015 The OpenChrome Project * [https://www.freedesktop.org/wiki/Openchrome] * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. * Copyright 2001-2008 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 #include "via_fp.h" /* 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}, {1366, 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 /* * This software controlled FP power on / off sequence code is * for CLE266's IGP which was codenamed Castle Rock. The code is * untested. The turn on sequence and register access likely * originated from the code VIA Technologies made open source around * Year 2004. */ static void viaFPCastleRockSoftPowerSeq(ScrnInfoPtr pScrn, Bool powerState) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPCastleRockSoftPowerSeq.\n")); if (powerState) { /* Wait for 25 ms. */ usleep(25); /* Turn on FP VDD rail. */ viaFPSetPrimarySoftVDD(pScrn, TRUE); /* Wait for 510 ms. */ usleep(510); /* Turn on FP data transmission. */ viaFPSetPrimarySoftData(pScrn, TRUE); /* Wait for 1 ms. */ usleep(1); /* Turn on FP VEE rail. */ viaFPSetPrimarySoftVEE(pScrn, TRUE); /* Turn on FP back light. */ viaFPSetPrimarySoftBackLight(pScrn, TRUE); } else { /* Wait for 1 ms. */ usleep(1); /* Turn off FP back light. */ viaFPSetPrimarySoftBackLight(pScrn, FALSE); /* Turn off FP VEE rail. */ viaFPSetPrimarySoftVEE(pScrn, FALSE); /* Wait for 510 ms. */ usleep(510); /* Turn off FP data transmission. */ viaFPSetPrimarySoftData(pScrn, FALSE); /* Wait for 25 ms. */ usleep(25); /* Turn off FP VDD rail. */ viaFPSetPrimarySoftVDD(pScrn, FALSE); } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPCastleRockSoftPowerSeq.\n")); } static void viaFPPrimarySoftPowerSeq(ScrnInfoPtr pScrn, Bool powerState) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPPrimarySoftPowerSeq.\n")); /* Turn off FP hardware power sequence. */ viaFPSetPrimaryHardPower(pScrn, FALSE); /* Use software FP power sequence control. */ viaFPSetPrimaryPowerSeqType(pScrn, FALSE); if (powerState) { /* Turn on FP Display Period. */ viaFPSetPrimaryDirectDisplayPeriod(pScrn, TRUE); /* Wait for TD0 ms. */ usleep(TD0); /* Turn on FP VDD rail. */ viaFPSetPrimarySoftVDD(pScrn, TRUE); /* Wait for TD1 ms. */ usleep(TD1); /* Turn on FP data transmission. */ viaFPSetPrimarySoftData(pScrn, TRUE); /* Wait for TD2 ms. */ usleep(TD2); /* Turn on FP VEE rail. */ viaFPSetPrimarySoftVEE(pScrn, TRUE); /* Wait for TD3 ms. */ usleep(TD3); /* Turn on FP back light. */ viaFPSetPrimarySoftBackLight(pScrn, TRUE); } else { /* Turn off FP back light. */ viaFPSetPrimarySoftBackLight(pScrn, FALSE); /* Wait for TD3 ms. */ usleep(TD3); /* Turn off FP VEE rail. */ viaFPSetPrimarySoftVEE(pScrn, FALSE); /* Wait for TD2 ms. */ usleep(TD2); /* Turn off FP data transmission. */ viaFPSetPrimarySoftData(pScrn, FALSE); /* Wait for TD1 ms. */ usleep(TD1); /* Turn off FP VDD rail. */ viaFPSetPrimarySoftVDD(pScrn, FALSE); /* Turn off FP Display Period. */ viaFPSetPrimaryDirectDisplayPeriod(pScrn, FALSE); } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPPrimarySoftPowerSeq.\n")); } static void viaFPSecondarySoftPowerSeq(ScrnInfoPtr pScrn, Bool powerState) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPSecondarySoftPowerSeq.\n")); /* Turn off hardware power sequence. */ viaFPSetSecondaryHardPower(pScrn, FALSE); /* Use software FP power sequence control. */ viaFPSetSecondaryPowerSeqType(pScrn, FALSE); if (powerState) { /* Turn on FP display period. */ viaFPSetSecondaryDirectDisplayPeriod(pScrn, TRUE); /* Wait for TD0 ms. */ usleep(TD0); /* Turn on FP VDD rail. */ viaFPSetSecondarySoftVDD(pScrn, TRUE); /* Wait for TD1 ms. */ usleep(TD1); /* Turn on FP data transmission. */ viaFPSetSecondarySoftData(pScrn, TRUE); /* Wait for TD2 ms. */ usleep(TD2); /* Turn on FP VEE rail. */ viaFPSetSecondarySoftVEE(pScrn, TRUE); /* Wait for TD3 ms. */ usleep(TD3); /* Turn on FP back light. */ viaFPSetSecondarySoftBackLight(pScrn, TRUE); } else { /* Turn off FP back light. */ viaFPSetSecondarySoftBackLight(pScrn, FALSE); /* Wait for TD3 ms. */ usleep(TD3); /* Turn off FP VEE rail. */ viaFPSetSecondarySoftVEE(pScrn, FALSE); /* Wait for TD2 ms. */ usleep(TD2); /* Turn off FP data transmission. */ viaFPSetSecondarySoftData(pScrn, FALSE); /* Wait for TD1 ms. */ usleep(TD1); /* Turn off FP VDD rail. */ viaFPSetSecondarySoftVDD(pScrn, FALSE); /* Turn off FP display period. */ viaFPSetSecondaryDirectDisplayPeriod(pScrn, FALSE); } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPSecondarySoftPowerSeq.\n")); } static void viaFPPrimaryHardPowerSeq(ScrnInfoPtr pScrn, Bool powerState) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPPrimaryHardPowerSeq.\n")); /* Use hardware FP power sequence control. */ viaFPSetPrimaryPowerSeqType(pScrn, TRUE); if (powerState) { /* Turn on FP display period. */ viaFPSetPrimaryDirectDisplayPeriod(pScrn, TRUE); /* Turn on FP hardware power sequence. */ viaFPSetPrimaryHardPower(pScrn, TRUE); /* Turn on FP back light. */ viaFPSetPrimaryDirectBackLightCtrl(pScrn, TRUE); } else { /* Turn off FP back light. */ viaFPSetPrimaryDirectBackLightCtrl(pScrn, FALSE); /* Turn off FP hardware power sequence. */ viaFPSetPrimaryHardPower(pScrn, FALSE); /* Turn on FP display period. */ viaFPSetPrimaryDirectDisplayPeriod(pScrn, FALSE); } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPPrimaryHardPowerSeq.\n")); } static void viaFPSecondaryHardPowerSeq(ScrnInfoPtr pScrn, Bool powerState) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPSecondaryHardPowerSeq.\n")); /* Use hardware FP power sequence control. */ viaFPSetSecondaryPowerSeqType(pScrn, TRUE); if (powerState) { /* Turn on FP display period. */ viaFPSetSecondaryDirectDisplayPeriod(pScrn, TRUE); /* Turn on FP hardware power sequence. */ viaFPSetSecondaryHardPower(pScrn, TRUE); /* Turn on FP back light. */ viaFPSetSecondaryDirectBackLightCtrl(pScrn, TRUE); } else { /* Turn off FP back light. */ viaFPSetSecondaryDirectBackLightCtrl(pScrn, FALSE); /* Turn off FP hardware power sequence. */ viaFPSetSecondaryHardPower(pScrn, FALSE); /* Turn off FP display period. */ viaFPSetSecondaryDirectDisplayPeriod(pScrn, FALSE); } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPSecondaryHardPowerSeq.\n")); } static void viaFPPower(ScrnInfoPtr pScrn, int Chipset, uint32_t diPort, Bool powerState) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPPower.\n")); switch (Chipset) { case VIA_CLE266: viaFPCastleRockSoftPowerSeq(pScrn, powerState); break; case VIA_KM400: case VIA_P4M800PRO: case VIA_PM800: case VIA_K8M800: case VIA_P4M890: case VIA_K8M890: case VIA_P4M900: viaFPPrimaryHardPowerSeq(pScrn, powerState); break; case VIA_CX700: case VIA_VX800: /* * VX800, CX700 have HW issue, so we'd better use SW power sequence. * Fix Ticket #308. */ if (diPort & VIA_DI_PORT_LVDS1) { viaFPPrimarySoftPowerSeq(pScrn, powerState); viaLVDS1SetPower(pScrn, powerState); } if (diPort & VIA_DI_PORT_LVDS2) { viaFPSecondarySoftPowerSeq(pScrn, powerState); viaLVDS2SetPower(pScrn, powerState); } break; case VIA_VX855: case VIA_VX900: viaFPPrimaryHardPowerSeq(pScrn, powerState); viaLVDS1SetPower(pScrn, powerState); break; default: break; } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPPower.\n")); } static void viaFPIOPadState(ScrnInfoPtr pScrn, uint32_t diPort, Bool ioPadOn) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPIOPadState.\n")); switch(diPort) { case VIA_DI_PORT_DVP0: viaDVP0SetIOPadState(pScrn, ioPadOn ? 0x03 : 0x00); break; case VIA_DI_PORT_DVP1: viaDVP1SetIOPadState(pScrn, ioPadOn ? 0x03 : 0x00); break; case VIA_DI_PORT_FPDPLOW: viaFPDPLowSetIOPadState(pScrn, ioPadOn ? 0x03 : 0x00); break; case VIA_DI_PORT_FPDPHIGH: viaFPDPHighSetIOPadState(pScrn, ioPadOn ? 0x03 : 0x00); break; case (VIA_DI_PORT_FPDPLOW | VIA_DI_PORT_FPDPHIGH): viaFPDPLowSetIOPadState(pScrn, ioPadOn ? 0x03 : 0x00); viaFPDPHighSetIOPadState(pScrn, ioPadOn ? 0x03 : 0x00); break; case VIA_DI_PORT_LVDS1: viaLVDS1SetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00); break; case VIA_DI_PORT_LVDS2: viaLVDS2SetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00); break; case (VIA_DI_PORT_LVDS1 | VIA_DI_PORT_LVDS2): viaLVDS1SetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00); viaLVDS2SetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00); break; default: break; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "FP I/O Pad: %s\n", ioPadOn ? "On": "Off"); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPIOPadState.\n")); } static void viaFPFormat(ScrnInfoPtr pScrn, uint32_t diPort, CARD8 format) { CARD8 temp = format & 0x01; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPFormat.\n")); switch(diPort) { case VIA_DI_PORT_LVDS1: viaLVDS1SetFormat(pScrn, temp); break; case VIA_DI_PORT_LVDS2: viaLVDS2SetFormat(pScrn, temp); break; case (VIA_DI_PORT_LVDS1 | VIA_DI_PORT_LVDS2): viaLVDS1SetFormat(pScrn, temp); viaLVDS2SetFormat(pScrn, temp); break; default: break; } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPFormat.\n")); } static void viaFPOutputFormat(ScrnInfoPtr pScrn, uint32_t diPort, CARD8 outputFormat) { CARD8 temp = outputFormat & 0x01; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPOutputFormat.\n")); switch(diPort) { case VIA_DI_PORT_LVDS1: viaLVDS1SetOutputFormat(pScrn, temp); break; case VIA_DI_PORT_LVDS2: viaLVDS2SetOutputFormat(pScrn, temp); break; case (VIA_DI_PORT_LVDS1 | VIA_DI_PORT_LVDS2): viaLVDS1SetOutputFormat(pScrn, temp); viaLVDS2SetOutputFormat(pScrn, temp); break; default: break; } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPOutputFormat.\n")); } static void viaFPDithering(ScrnInfoPtr pScrn, uint32_t diPort, Bool dithering) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPDithering.\n")); switch(diPort) { case VIA_DI_PORT_LVDS1: viaLVDS1SetDithering(pScrn, dithering); break; case VIA_DI_PORT_LVDS2: viaLVDS2SetDithering(pScrn, dithering); break; case (VIA_DI_PORT_LVDS1 | VIA_DI_PORT_LVDS2): viaLVDS1SetDithering(pScrn, dithering); viaLVDS2SetDithering(pScrn, dithering); break; default: break; } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPDithering.\n")); } /* * Set FP sync polarity. */ static void viaFPSyncPolarity(ScrnInfoPtr pScrn, uint32_t diPort, unsigned int flags) { CARD8 syncPolarity = 0x00; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPSyncPolarity.\n")); if (flags & V_NHSYNC) { syncPolarity |= BIT(0); } if (flags & V_NVSYNC) { syncPolarity |= BIT(1); } switch(diPort) { case VIA_DI_PORT_DVP0: viaDVP0SetSyncPolarity(pScrn, syncPolarity); break; case VIA_DI_PORT_DVP1: viaDVP1SetSyncPolarity(pScrn, syncPolarity); break; case VIA_DI_PORT_FPDPLOW: break; case VIA_DI_PORT_FPDPHIGH: break; case (VIA_DI_PORT_FPDPLOW | VIA_DI_PORT_FPDPHIGH): break; case VIA_DI_PORT_LVDS1: viaLVDS1SetSyncPolarity(pScrn, syncPolarity); break; case VIA_DI_PORT_LVDS2: viaLVDS2SetSyncPolarity(pScrn, syncPolarity); break; case (VIA_DI_PORT_LVDS1 | VIA_DI_PORT_LVDS2): viaLVDS1SetSyncPolarity(pScrn, syncPolarity); viaLVDS2SetSyncPolarity(pScrn, syncPolarity); break; default: break; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "FP Horizontal Sync Polarity: %s\n", (syncPolarity & BIT(0)) ? "-" : "+"); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "FP Vertical Sync Polarity: %s\n", (syncPolarity & BIT(1)) ? "-" : "+"); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPSyncPolarity.\n")); } static void viaFPDisplaySource(ScrnInfoPtr pScrn, uint32_t diPort, int index) { CARD8 displaySource = index & 0x01; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPDisplaySource.\n")); switch(diPort) { case VIA_DI_PORT_DVP0: viaDVP0SetDisplaySource(pScrn, displaySource); break; case VIA_DI_PORT_DVP1: viaDVP1SetDisplaySource(pScrn, displaySource); break; case VIA_DI_PORT_FPDPLOW: viaFPDPLowSetDisplaySource(pScrn, displaySource); viaDVP1SetDisplaySource(pScrn, displaySource); break; case VIA_DI_PORT_FPDPHIGH: viaFPDPHighSetDisplaySource(pScrn, displaySource); viaDVP0SetDisplaySource(pScrn, displaySource); break; case (VIA_DI_PORT_FPDPLOW | VIA_DI_PORT_FPDPHIGH): viaFPDPLowSetDisplaySource(pScrn, displaySource); viaFPDPHighSetDisplaySource(pScrn, displaySource); break; case VIA_DI_PORT_LVDS1: viaLVDS1SetDisplaySource(pScrn, displaySource); break; case VIA_DI_PORT_LVDS2: viaLVDS2SetDisplaySource(pScrn, displaySource); break; case (VIA_DI_PORT_LVDS1 | VIA_DI_PORT_LVDS2): viaLVDS1SetDisplaySource(pScrn, displaySource); viaLVDS2SetDisplaySource(pScrn, displaySource); break; default: break; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "FP Display Source: IGA%d\n", displaySource + 1); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPDisplaySource.\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; } /* * Gets the native panel resolution from scratch pad registers. */ static void viaFPGetFPInfoScratchPad(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; VIAPtr pVia = VIAPTR(pScrn); VIADisplayPtr pVIADisplay = pVia->pVIADisplay; VIAFPPtr pVIAFP = (VIAFPPtr) output->driver_private; VIARegPtr Regs = &pVIADisplay->SavedReg; CARD8 index; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered %s.\n", __func__)); index = Regs->CR[0x3F] & 0x0F; pVIAFP->NativeModeIndex = index; pVIAFP->NativeWidth = ViaPanelNativeModes[index].Width; pVIAFP->NativeHeight = ViaPanelNativeModes[index].Height; pVIAFP->useDualEdge = ViaPanelNativeModes[index].useDualEdge; pVIAFP->useDithering = ViaPanelNativeModes[index].useDithering; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIA Technologies VGA BIOS Scratch Pad Register " "Flat Panel Index: %d\n", pVIAFP->NativeModeIndex); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Flat Panel Native Resolution: %dx%d\n", pVIAFP->NativeWidth, pVIAFP->NativeHeight); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting %s.\n", __func__)); } 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 int viaGetClockRangeIndex(int Clock) { if (Clock < VIA_DPA_CLK_30M) { return VIA_DPA_CLK_RANGE_30M; } else if ((Clock >= VIA_DPA_CLK_30M) && (Clock < VIA_DPA_CLK_50M)) { return VIA_DPA_CLK_RANGE_30M_50M; } else if ((Clock >= VIA_DPA_CLK_50M) && (Clock < VIA_DPA_CLK_70M)) { return VIA_DPA_CLK_RANGE_50M_70M; } else if ((Clock >= VIA_DPA_CLK_70M) && (Clock < VIA_DPA_CLK_100M)) { return VIA_DPA_CLK_RANGE_70M_100M; } else if ((Clock >= VIA_DPA_CLK_100M) && (Clock < VIA_DPA_CLK_150M)) { return VIA_DPA_CLK_RANGE_100M_150M; } else { return VIA_DPA_CLK_RANGE_150M; } } static void viaLoadDPA(ScrnInfoPtr pScrn, uint32_t diPort, VIADPAPtr pVIADPA) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaLoadDPA.\n")); if (!pVIADPA) { goto exit; } switch (diPort) { case VIA_DI_PORT_DVP0: viaDVP0SetAdjustment(pScrn, pVIADPA->dvp0Adjustment); viaDVP0SetClockDriveStrength(pScrn, pVIADPA->dvp0ClockDriveStrength); viaDVP0SetDataDriveStrength(pScrn, pVIADPA->dvp0DataDriveStrength); break; case VIA_DI_PORT_DVP1: viaDVP1SetAdjustment(pScrn, pVIADPA->dvp1Adjustment); viaDVP1SetClockDriveStrength(pScrn, pVIADPA->dvp1ClockDriveStrength); viaDVP1SetDataDriveStrength(pScrn, pVIADPA->dvp1DataDriveStrength); break; case VIA_DI_PORT_FPDPLOW: viaFPDPLowSetAdjustment(pScrn, pVIADPA->fpdpLowAdjustment); break; case VIA_DI_PORT_FPDPHIGH: viaFPDPHighSetAdjustment(pScrn, pVIADPA->fpdpHighAdjustment); break; case (VIA_DI_PORT_FPDPHIGH | VIA_DI_PORT_FPDPLOW): viaFPDPLowSetAdjustment(pScrn, pVIADPA->fpdpLowAdjustment); viaFPDPHighSetAdjustment(pScrn, pVIADPA->fpdpHighAdjustment); break; default: break; } exit: DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaLoadDPA.\n")); } static void viaFPIOAdjustment(ScrnInfoPtr pScrn, int Chipset, uint32_t diPort, int Clock) { VIAPtr pVia = VIAPTR(pScrn); VIADPAInfoTablePtr pVIADPAInfoTable; VIADPAPtr pVIADPA; Bool isDPATableExist = FALSE; int clockRangeIndex = 0; int i = 0; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered viaFPIOAdjustment.\n")); for (i = 0; i < NUMBER_VIA_DPA_TABLE; i++) { if (pVia->Chipset == viaDPAIndexTable[i].Chipset) { isDPATableExist = TRUE; break; } } if (isDPATableExist) { if (viaDPAIndexTable[i].pFPDPATable) { pVIADPAInfoTable = viaDPAIndexTable[i].pFPDPATable; } clockRangeIndex = viaGetClockRangeIndex(Clock); /* Write the value to the register. */ pVIADPA = pVIADPAInfoTable[clockRangeIndex].pDPASetting; viaLoadDPA(pScrn, diPort, pVIADPA); } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPIOAdjustment.\n")); } static void via_fp_create_resources(xf86OutputPtr output) { } static void via_fp_dpms(xf86OutputPtr output, int mode) { ScrnInfoPtr pScrn = output->scrn; VIAPtr pVia = VIAPTR(pScrn); VIAFPPtr pVIAFP = (VIAFPPtr) output->driver_private; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered via_fp_dpms.\n")); switch (mode) { case DPMSModeOn: viaFPPower(pScrn, pVia->Chipset, pVIAFP->diPort, TRUE); viaFPIOPadState(pScrn, pVIAFP->diPort, TRUE); break; case DPMSModeStandby: case DPMSModeSuspend: case DPMSModeOff: viaFPPower(pScrn, pVia->Chipset, pVIAFP->diPort, FALSE); viaFPIOPadState(pScrn, pVIAFP->diPort, FALSE); break; default: break; } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting via_fp_dpms.\n")); } static void via_fp_save(xf86OutputPtr output) { } static void via_fp_restore(xf86OutputPtr output) { } static int via_fp_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) { ScrnInfoPtr pScrn = output->scrn; VIAFPPtr pVIAFP = (VIAFPPtr) output->driver_private; if (pVIAFP->NativeWidth < pMode->HDisplay || pVIAFP->NativeHeight < pMode->VDisplay) return MODE_PANEL; if (!pVIAFP->Scale && pVIAFP->NativeHeight != pMode->VDisplay && pVIAFP->NativeWidth != pMode->HDisplay) return MODE_PANEL; if (!ViaModeDotClockTranslate(pScrn, pMode)) return MODE_NOCLOCK; return MODE_OK; } static Bool via_fp_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode) { VIAFPPtr pVIAFP = (VIAFPPtr) output->driver_private; xf86SetModeCrtc(adjusted_mode, 0); if (!pVIAFP->Center && (mode->HDisplay < pVIAFP->NativeWidth || mode->VDisplay < pVIAFP->NativeHeight)) { pVIAFP->Scale = TRUE; } else { pVIAFP->Scale = FALSE; ViaPanelCenterMode(mode, adjusted_mode); } return TRUE; } static void via_fp_prepare(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; VIAPtr pVia = VIAPTR(pScrn); VIAFPPtr pVIAFP = (VIAFPPtr) output->driver_private; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered via_fp_prepare.\n")); viaFPPower(pScrn, pVia->Chipset, pVIAFP->diPort, FALSE); viaFPIOPadState(pScrn, pVIAFP->diPort, FALSE); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting via_fp_prepare.\n")); } static void via_fp_commit(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; VIAPtr pVia = VIAPTR(pScrn); VIAFPPtr pVIAFP = (VIAFPPtr) output->driver_private; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered via_fp_commit.\n")); viaFPPower(pScrn, pVia->Chipset, pVIAFP->diPort, TRUE); viaFPIOPadState(pScrn, pVIAFP->diPort, TRUE); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting via_fp_commit.\n")); } static void via_fp_mode_set(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode) { ScrnInfoPtr pScrn = output->scrn; drmmode_crtc_private_ptr iga = output->crtc->driver_private; VIAPtr pVia = VIAPTR(pScrn); VIAFPPtr pVIAFP = (VIAFPPtr) output->driver_private; if (output->crtc) { if (pVIAFP->Scale) { ViaPanelScale(pScrn, mode->HDisplay, mode->VDisplay, pVIAFP->NativeWidth, pVIAFP->NativeHeight); } else { ViaPanelScaleDisable(pScrn); } viaFPIOAdjustment(pScrn, pVia->Chipset, pVIAFP->diPort, adjusted_mode->Clock); switch (pVia->Chipset) { case VIA_CX700: case VIA_VX800: case VIA_VX855: case VIA_VX900: /* OPENLDI Mode */ viaFPFormat(pScrn, pVIAFP->diPort, 0x01); /* Sequential Mode */ viaFPOutputFormat(pScrn, pVIAFP->diPort, 0x01); viaFPDithering(pScrn, pVIAFP->diPort, pVIAFP->useDithering); break; default: break; } viaFPSyncPolarity(pScrn, pVIAFP->diPort, adjusted_mode->Flags); viaFPDisplaySource(pScrn, pVIAFP->diPort, iga->index); } } static xf86OutputStatus via_fp_detect(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; xf86MonPtr pMon; xf86OutputStatus status = XF86OutputStatusDisconnected; I2CBusPtr pI2CBus; VIAPtr pVia = VIAPTR(pScrn); VIADisplayPtr pVIADisplay = pVia->pVIADisplay; VIAFPPtr pVIAFP = (VIAFPPtr) output->driver_private; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered via_fp_detect.\n")); /* Hardcode panel size for the OLPC XO-1.5. */ if (pVIADisplay->isOLPCXO15) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Setting up OLPC XO-1.5 flat panel.\n"); pVIAFP->NativeWidth = 1200; pVIAFP->NativeHeight = 900; status = XF86OutputStatusConnected; goto exit; } if (pVIAFP->i2cBus & VIA_I2C_BUS2) { pI2CBus = pVIADisplay->pI2CBus2; } else if (pVIAFP->i2cBus & VIA_I2C_BUS3) { pI2CBus = pVIADisplay->pI2CBus3; } else { pI2CBus = NULL; } if (pI2CBus) { pMon = xf86OutputGetEDID(output, pI2CBus); if (pMon && DIGITAL(pMon->features.input_type)) { xf86OutputSetEDID(output, pMon); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected a flat panel.\n"); if (!ViaPanelGetSizeFromEDID(pScrn, pMon, &pVIAFP->NativeWidth, &pVIAFP->NativeHeight)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to obtain panel size from EDID.\n"); goto exit; } status = XF86OutputStatusConnected; } else { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Could not obtain EDID from a flat " "panel, but will obtain flat panel " "information from scratch pad register.\n"); /* For FP without I2C bus connection, CRTC scratch pad * register supplied by the VGA BIOS is the only method * available to figure out the FP native screen resolution. */ viaFPGetFPInfoScratchPad(output); status = XF86OutputStatusConnected; } } else { /* For FP without I2C bus connection, CRTC scratch pad * register supplied by the VGA BIOS is the only method * available to figure out the FP native screen resolution. */ viaFPGetFPInfoScratchPad(output); status = XF86OutputStatusConnected; } exit: DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting via_fp_detect.\n")); return status; } static DisplayModePtr via_fp_get_modes(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; DisplayModePtr pDisplay_Mode = NULL; VIAPtr pVia = VIAPTR(pScrn); VIADisplayPtr pVIADisplay = pVia->pVIADisplay; VIAFPPtr pVIAFP = (VIAFPPtr) output->driver_private; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered via_fp_get_modes.\n")); if (output->status == XF86OutputStatusConnected) { if (!output->MonInfo) { /* * Generates a display mode for the native panel resolution, * using CVT. */ if (pVIAFP->NativeWidth && pVIAFP->NativeHeight) { if (pVIADisplay->isOLPCXO15) { pDisplay_Mode = xf86DuplicateMode(&OLPCMode); } else { pDisplay_Mode = xf86CVTMode(pVIAFP->NativeWidth, pVIAFP->NativeHeight, 60.0f, FALSE, FALSE); } 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", pVIAFP->NativeWidth, pVIAFP->NativeHeight); } } else { pDisplay_Mode = xf86OutputGetEDIDModes(output); } } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting via_fp_get_modes.\n")); return pDisplay_Mode; } #ifdef RANDR_12_INTERFACE static Bool via_fp_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value) { return FALSE; } static Bool via_fp_get_property(xf86OutputPtr output, Atom property) { return FALSE; } #endif static void via_fp_destroy(xf86OutputPtr output) { if (output->driver_private) free(output->driver_private); output->driver_private = NULL; } static const xf86OutputFuncsRec via_fp_funcs = { .create_resources = via_fp_create_resources, .dpms = via_fp_dpms, .save = via_fp_save, .restore = via_fp_restore, .mode_valid = via_fp_mode_valid, .mode_fixup = via_fp_mode_fixup, .prepare = via_fp_prepare, .commit = via_fp_commit, .mode_set = via_fp_mode_set, .detect = via_fp_detect, .get_modes = via_fp_get_modes, #ifdef RANDR_12_INTERFACE .set_property = via_fp_set_property, #endif #ifdef RANDR_13_INTERFACE .get_property = via_fp_get_property, #endif .destroy = via_fp_destroy }; void viaFPProbe(ScrnInfoPtr pScrn) { vgaHWPtr hwp = VGAHWPTR(pScrn); VIAPtr pVia = VIAPTR(pScrn); VIADisplayPtr pVIADisplay = pVia->pVIADisplay; CARD8 sr12, sr13, sr5a; CARD8 cr3b; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entered %s.\n", __func__)); sr12 = hwp->readSeq(hwp, 0x12); sr13 = hwp->readSeq(hwp, 0x13); cr3b = hwp->readCrtc(hwp, 0x3B); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SR12: 0x%02X\n", sr12)); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SR13: 0x%02X\n", sr13)); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CR3B: 0x%02X\n", sr13)); /* Detect the presence of FPs. */ switch (pVia->Chipset) { case VIA_CLE266: if ((sr12 & BIT(4)) || (cr3b & BIT(3))) { pVIADisplay->intFP1Presence = TRUE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_DIP0; } else { pVIADisplay->intFP1Presence = FALSE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_NONE; } pVIADisplay->intFP2Presence = FALSE; pVIADisplay->intFP2DIPort = VIA_DI_PORT_NONE; break; case VIA_KM400: case VIA_K8M800: case VIA_P4M800PRO: case VIA_PM800: /* 3C5.13[3] - DVP0D8 pin strapping * 0: AGP pins are used for AGP * 1: AGP pins are used by FPDP * (Flat Panel Display Port) */ if ((sr13 & BIT(3)) && (cr3b & BIT(1))) { pVIADisplay->intFP1Presence = TRUE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_FPDPHIGH | VIA_DI_PORT_FPDPLOW; } else { pVIADisplay->intFP1Presence = FALSE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_NONE; } pVIADisplay->intFP2Presence = FALSE; pVIADisplay->intFP2DIPort = VIA_DI_PORT_NONE; break; case VIA_P4M890: case VIA_K8M890: case VIA_P4M900: if (cr3b & BIT(1)) { /* 3C5.12[4] - DVP0D4 pin strapping * 0: 12-bit FPDP (Flat Panel Display Port) * 1: 24-bit FPDP (Flat Panel Display Port) */ if (sr12 & BIT(4)) { pVIADisplay->intFP1Presence = TRUE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_FPDPLOW | VIA_DI_PORT_FPDPHIGH; } else { pVIADisplay->intFP1Presence = TRUE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_FPDPLOW; } } else { pVIADisplay->intFP1Presence = FALSE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_NONE; } pVIADisplay->intFP2Presence = FALSE; pVIADisplay->intFP2DIPort = VIA_DI_PORT_NONE; break; case VIA_CX700: case VIA_VX800: case VIA_VX855: case VIA_VX900: sr5a = hwp->readSeq(hwp, 0x5A); /* Setting SR5A[0] to 1. * This allows the reading out the alternative * pin strapping information from SR12 and SR13. */ ViaSeqMask(hwp, 0x5A, BIT(0), BIT(0)); sr13 = hwp->readSeq(hwp, 0x13); DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SR13: 0x%02X\n", sr13)); if (cr3b & BIT(1)) { if (pVIADisplay->isVIANanoBook) { pVIADisplay->intFP1Presence = FALSE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_NONE; pVIADisplay->intFP2Presence = TRUE; pVIADisplay->intFP2DIPort = VIA_DI_PORT_LVDS2; } else if (pVIADisplay->isQuantaIL1) { /* From the Quanta IL1 schematic. */ pVIADisplay->intFP1Presence = TRUE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_DVP1; pVIADisplay->intFP2Presence = FALSE; pVIADisplay->intFP2DIPort = VIA_DI_PORT_NONE; } else if (pVIADisplay->isSamsungNC20) { pVIADisplay->intFP1Presence = FALSE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_NONE; pVIADisplay->intFP2Presence = TRUE; pVIADisplay->intFP2DIPort = VIA_DI_PORT_LVDS2; /* 3C5.13[7:6] - Integrated LVDS / DVI Mode Select * (DVP1D15-14 pin strapping) * 00: LVDS1 + LVDS2 * 01: DVI + LVDS2 * 10: Dual LVDS Channel (High Resolution Panel) * 11: One DVI only (decrease the clock jitter) */ } else if ((!(sr13 & BIT(7))) && (!(sr13 & BIT(6)))) { pVIADisplay->intFP1Presence = TRUE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_LVDS1; /* * For now, don't support the second FP. */ pVIADisplay->intFP2Presence = FALSE; pVIADisplay->intFP2DIPort = VIA_DI_PORT_NONE; } else if ((!(sr13 & BIT(7))) && (sr13 & BIT(6))) { pVIADisplay->intFP1Presence = FALSE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_NONE; pVIADisplay->intFP2Presence = TRUE; pVIADisplay->intFP2DIPort = VIA_DI_PORT_LVDS2; } else if ((sr13 & BIT(7)) && (!(sr13 & BIT(6)))) { pVIADisplay->intFP1Presence = TRUE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_LVDS1 | VIA_DI_PORT_LVDS2; pVIADisplay->intFP2Presence = FALSE; pVIADisplay->intFP2DIPort = VIA_DI_PORT_NONE; } else { pVIADisplay->intFP1Presence = FALSE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_NONE; pVIADisplay->intFP2Presence = FALSE; pVIADisplay->intFP2DIPort = VIA_DI_PORT_NONE; } } else { pVIADisplay->intFP1Presence = FALSE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_NONE; pVIADisplay->intFP2Presence = FALSE; pVIADisplay->intFP2DIPort = VIA_DI_PORT_NONE; } hwp->writeSeq(hwp, 0x5A, sr5a); break; default: pVIADisplay->intFP1Presence = FALSE; pVIADisplay->intFP1DIPort = VIA_DI_PORT_NONE; pVIADisplay->intFP2Presence = FALSE; pVIADisplay->intFP2DIPort = VIA_DI_PORT_NONE; break; } pVIADisplay->intFP1I2CBus = VIA_I2C_NONE; pVIADisplay->intFP2I2CBus = VIA_I2C_NONE; if ((pVIADisplay->intFP1Presence) && (!(pVIADisplay->mappedI2CBus & VIA_I2C_BUS2))) { pVIADisplay->intFP1I2CBus = VIA_I2C_BUS2; pVIADisplay->mappedI2CBus |= VIA_I2C_BUS2; } if ((pVIADisplay->intFP2Presence) && (!(pVIADisplay->mappedI2CBus & VIA_I2C_BUS2))) { pVIADisplay->intFP2I2CBus = VIA_I2C_BUS2; pVIADisplay->mappedI2CBus |= VIA_I2C_BUS2; } DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting %s.\n", __func__)); } void viaFPInit(ScrnInfoPtr pScrn) { xf86OutputPtr output; VIAPtr pVia = VIAPTR(pScrn); VIADisplayPtr pVIADisplay = pVia->pVIADisplay; VIAFPPtr pVIAFP; char outputNameBuffer[32]; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Entering viaFPInit.\n")); if (pVIADisplay->intFP1Presence) { pVIAFP = (VIAFPPtr) xnfcalloc(1, sizeof(VIAFPRec)); if (!pVIAFP) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate private storage for " "FP.\n")); goto exit; } /* 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", (pVIADisplay->numberFP + 1)); output = xf86OutputCreate(pScrn, &via_fp_funcs, outputNameBuffer); if (!output) { free(pVIAFP); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate X Server display output record for " "FP.\n"); goto exit; } /* Increment the number of FP connectors. */ pVIADisplay->numberFP++; pVIAFP->diPort = pVIADisplay->intFP1DIPort; /* Hint about which I2C bus to access for obtaining EDID. */ pVIAFP->i2cBus = pVIADisplay->intFP1I2CBus; output->driver_private = pVIAFP; output->possible_crtcs = BIT(1) | BIT(0); output->possible_clones = 0; output->interlaceAllowed = FALSE; output->doubleScanAllowed = FALSE; if (pVIADisplay->isOLPCXO15) { output->mm_height = 152; output->mm_width = 114; } } if (pVIADisplay->intFP2Presence) { pVIAFP = (VIAFPPtr) xnfcalloc(1, sizeof(VIAFPRec)); if (!pVIAFP) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate private storage for " "FP.\n")); goto exit; } /* 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", (pVIADisplay->numberFP + 1)); output = xf86OutputCreate(pScrn, &via_fp_funcs, outputNameBuffer); if (!output) { free(pVIAFP); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate X Server display output record for " "FP.\n"); goto exit; } /* Increment the number of FP connectors. */ pVIADisplay->numberFP++; pVIAFP->diPort = pVIADisplay->intFP2DIPort; /* Hint about which I2C bus to access for obtaining EDID. */ pVIAFP->i2cBus = pVIADisplay->intFP2I2CBus; output->driver_private = pVIAFP; output->possible_crtcs = BIT(1) | BIT(0); output->possible_clones = 0; output->interlaceAllowed = FALSE; output->doubleScanAllowed = FALSE; } exit: DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Exiting viaFPInit.\n")); }