Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2007-2008  Luc Verhaegen <lverhaegen@novell.com>
  3.  * Copyright 2007-2008  Matthias Hopf <mhopf@novell.com>
  4.  * Copyright 2007-2008  Egbert Eich   <eich@novell.com>
  5.  * Copyright 2007-2008  Advanced Micro Devices, Inc.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a
  8.  * copy of this software and associated documentation files (the "Software"),
  9.  * to deal in the Software without restriction, including without limitation
  10.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11.  * and/or sell copies of the Software, and to permit persons to whom the
  12.  * Software is furnished to do so, subject to the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice shall be included in
  15.  * all copies or substantial portions of the Software.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  20.  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  21.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  22.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23.  * OTHER DEALINGS IN THE SOFTWARE.
  24.  */
  25.  
  26. /*
  27.  * Deals with the Shared LVDS/TMDS encoder.
  28.  *
  29.  */
  30.  
  31. #ifdef HAVE_CONFIG_H
  32. #include "config.h"
  33. #endif
  34.  
  35. #include "xf86.h"
  36.  
  37. /* for usleep */
  38. #if HAVE_XF86_ANSIC_H
  39. # include "xf86_ansic.h"
  40. #else
  41. # include <unistd.h>
  42. #endif
  43.  
  44. #include "rhd.h"
  45. #include "rhd_crtc.h"
  46.  
  47. #ifdef ATOM_BIOS
  48. #include "rhd_atombios.h"
  49. #include "rhd_atomout.h"
  50. #endif
  51.  
  52. #include "rhd_connector.h"
  53. #include "rhd_output.h"
  54. #include "rhd_regs.h"
  55. #include "rhd_card.h"
  56.  
  57. /*
  58.  * First of all, make it more managable to code for both R500 and R600, as
  59.  * there was a 1 register shift, right in the middle of the register block.
  60.  * There are of course much nicer ways to do the workaround i am doing here,
  61.  * but speed is not an issue here.
  62.  */
  63. static inline CARD16
  64. LVTMAChipGenerationSelect(int ChipSet, CARD32 R500, CARD32 R600)
  65. {
  66.     if (ChipSet >= RHD_RS600)
  67.         return R600;
  68.     else
  69.         return R500;
  70. }
  71.  
  72. #define LVTMAGENSEL(r500, r600) LVTMAChipGenerationSelect(rhdPtr->ChipSet, (r500), (r600))
  73. #define LVTMA_DATA_SYNCHRONIZATION \
  74.     LVTMAGENSEL(LVTMA_R500_DATA_SYNCHRONIZATION, LVTMA_R600_DATA_SYNCHRONIZATION)
  75. #define LVTMA_PWRSEQ_REF_DIV \
  76.     LVTMAGENSEL(LVTMA_R500_PWRSEQ_REF_DIV, LVTMA_R600_PWRSEQ_REF_DIV)
  77. #define LVTMA_PWRSEQ_DELAY1 \
  78.     LVTMAGENSEL(LVTMA_R500_PWRSEQ_DELAY1, LVTMA_R600_PWRSEQ_DELAY1)
  79. #define LVTMA_PWRSEQ_DELAY2 \
  80.     LVTMAGENSEL(LVTMA_R500_PWRSEQ_DELAY2, LVTMA_R600_PWRSEQ_DELAY2)
  81. #define LVTMA_PWRSEQ_CNTL \
  82.     LVTMAGENSEL(LVTMA_R500_PWRSEQ_CNTL, LVTMA_R600_PWRSEQ_CNTL)
  83. #define LVTMA_PWRSEQ_STATE \
  84.     LVTMAGENSEL(LVTMA_R500_PWRSEQ_STATE, LVTMA_R600_PWRSEQ_STATE)
  85. #define LVTMA_LVDS_DATA_CNTL \
  86.     LVTMAGENSEL(LVTMA_R500_LVDS_DATA_CNTL, LVTMA_R600_LVDS_DATA_CNTL)
  87. #define LVTMA_MODE LVTMAGENSEL(LVTMA_R500_MODE, LVTMA_R600_MODE)
  88. #define LVTMA_TRANSMITTER_ENABLE \
  89.     LVTMAGENSEL(LVTMA_R500_TRANSMITTER_ENABLE, LVTMA_R600_TRANSMITTER_ENABLE)
  90. #define LVTMA_MACRO_CONTROL \
  91.     LVTMAGENSEL(LVTMA_R500_MACRO_CONTROL, LVTMA_R600_MACRO_CONTROL)
  92. #define LVTMA_TRANSMITTER_CONTROL \
  93.     LVTMAGENSEL(LVTMA_R500_TRANSMITTER_CONTROL, LVTMA_R600_TRANSMITTER_CONTROL)
  94. #define LVTMA_REG_TEST_OUTPUT \
  95.     LVTMAGENSEL(LVTMA_R500_REG_TEST_OUTPUT, LVTMA_R600_REG_TEST_OUTPUT)
  96. #define LVTMA_BL_MOD_CNTL \
  97.     LVTMAGENSEL(LVTMA_R500_BL_MOD_CNTL, LVTMA_R600_BL_MOD_CNTL)
  98.  
  99. #define LVTMA_DITHER_RESET_BIT LVTMAGENSEL(0x04000000, 0x02000000)
  100.  
  101. /*
  102.  *
  103.  * Handling for LVTMA block as LVDS.
  104.  *
  105.  */
  106.  
  107. struct LVDSPrivate {
  108.     Bool DualLink;
  109.     Bool LVDS24Bit;
  110.     Bool FPDI; /* LDI otherwise */
  111.     CARD16 TXClockPattern;
  112.     int BlLevel;
  113.     CARD32 MacroControl;
  114.  
  115.     /* Power timing for LVDS */
  116.     CARD16 PowerRefDiv;
  117.     CARD16 BlonRefDiv;
  118.     CARD16 PowerDigToDE;
  119.     CARD16 PowerDEToBL;
  120.     CARD16 OffDelay;
  121.     Bool   TemporalDither;
  122.     Bool   SpatialDither;
  123.     int    GreyLevel;
  124.  
  125.     Bool Stored;
  126.  
  127.     CARD32 StoreControl;
  128.     CARD32 StoreSourceSelect;
  129.     CARD32 StoreBitDepthControl;
  130.     CARD32 StoreDataSynchronisation;
  131.     CARD32 StorePWRSEQRefDiv;
  132.     CARD32 StorePWRSEQDelay1;
  133.     CARD32 StorePWRSEQDelay2;
  134.     CARD32 StorePWRSEQControl;
  135.     CARD32 StorePWRSEQState;
  136.     CARD32 StoreLVDSDataControl;
  137.     CARD32 StoreMode;
  138.     CARD32 StoreTxEnable;
  139.     CARD32 StoreMacroControl;
  140.     CARD32 StoreTXControl;
  141.     CARD32 StoreBlModCntl;
  142. #ifdef NOT_YET
  143.     /* to hook in AtomBIOS property callback */
  144.     Bool (*WrappedPropertyCallback) (struct rhdOutput *Output,
  145.                       enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val);
  146.     void *PropertyPrivate;
  147. #endif
  148. };
  149.  
  150. /*
  151.  *
  152.  */
  153. static ModeStatus
  154. LVDSModeValid(struct rhdOutput *Output, DisplayModePtr Mode)
  155. {
  156.     RHDFUNC(Output);
  157.  
  158.     if (Mode->Flags & V_INTERLACE)
  159.         return MODE_NO_INTERLACE;
  160.  
  161.     return MODE_OK;
  162. }
  163.  
  164. /*
  165.  *
  166.  */
  167. static void
  168. LVDSDebugBacklight(struct rhdOutput *Output)
  169. {
  170.     RHDPtr rhdPtr = RHDPTRI(Output);
  171.     CARD32 tmp;
  172.     Bool Blon, BlonOvrd, BlonPol, BlModEn;
  173.     int BlModLevel, BlModRes = 0;
  174.  
  175.     if (rhdPtr->verbosity < 7)
  176.         return;
  177.  
  178.     tmp = (RHDRegRead(Output, LVTMA_PWRSEQ_STATE) >> 3) & 0x01;
  179.     RHDDebug(rhdPtr->scrnIndex, "%s: PWRSEQ BLON State: %s\n",
  180.             __func__, tmp ? "on" : "off");
  181.     tmp = RHDRegRead(rhdPtr, LVTMA_PWRSEQ_CNTL);
  182.     Blon = (tmp >> 24) & 0x1;
  183.     BlonOvrd = (tmp >> 25) & 0x1;
  184.     BlonPol = (tmp >> 26) & 0x1;
  185.  
  186.     RHDDebug(rhdPtr->scrnIndex, "%s: BLON: %s BLON_OVRD: %s BLON_POL: %s\n",
  187.             __func__, Blon ? "on" : "off",
  188.             BlonOvrd ? "enabled" : "disabled",
  189.             BlonPol ? "invert" : "non-invert");
  190.  
  191.     tmp = RHDRegRead(rhdPtr, LVTMA_BL_MOD_CNTL);
  192.     BlModEn = tmp & 0x1;
  193.     BlModLevel = (tmp >> 8) & 0xFF;
  194.     if (rhdPtr->ChipSet >= RHD_RS600)
  195.         BlModRes = (tmp >> 16) & 0xFF;
  196.  
  197.     xf86DrvMsgVerb(rhdPtr->scrnIndex, X_INFO, 3,
  198.                    "%s: BL_MOD: %s BL_MOD_LEVEL: %d BL_MOD_RES: %d\n",
  199.                    __func__, BlModEn ? "enable" : "disable",
  200.             BlModLevel, BlModRes);
  201. }
  202.  
  203. /*
  204.  *
  205.  */
  206. static void
  207. LVDSSetBacklight(struct rhdOutput *Output, int level)
  208. {
  209.     struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
  210.     RHDPtr rhdPtr = RHDPTRI(Output);
  211.  
  212.     Private->BlLevel = level;
  213.  
  214.     xf86DrvMsg(rhdPtr->scrnIndex, X_INFO,
  215.                "%s: trying to set BL_MOD_LEVEL to: %d\n",
  216.                __func__, level);
  217.  
  218.     if (rhdPtr->ChipSet >= RHD_RS600)
  219.   _RHDRegMask(rhdPtr, LVTMA_BL_MOD_CNTL,
  220.                    0xFF << 16 | (level << 8) | 0x1,
  221.                    0xFFFF01);
  222.     else
  223.   _RHDRegMask(rhdPtr, LVTMA_BL_MOD_CNTL,
  224.                    (level << 8) | 0x1,
  225.                    0xFF01);
  226.  
  227.     /*
  228.      * Poor man's debug
  229.      */
  230.     LVDSDebugBacklight(Output);
  231. }
  232.  
  233. /*
  234.  *
  235.  */
  236. static Bool
  237. LVDSPropertyControl(struct rhdOutput *Output, enum rhdPropertyAction Action,
  238.                     enum rhdOutputProperty Property, union rhdPropertyData *val)
  239. {
  240.     struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
  241.  
  242.     switch (Action) {
  243.         case rhdPropertyCheck:
  244.             switch (Property) {
  245.                 if (Private->BlLevel < 0)
  246.                     return FALSE;
  247.                 case RHD_OUTPUT_BACKLIGHT:
  248.                     return TRUE;
  249.                 default:
  250.                     return FALSE;
  251.             }
  252.         case rhdPropertyGet:
  253.             switch (Property) {
  254.                 case RHD_OUTPUT_BACKLIGHT:
  255.                     if (Private->BlLevel < 0)
  256.                         return FALSE;
  257.                     val->integer = Private->BlLevel;
  258.                     break;
  259.                 default:
  260.                     return FALSE;
  261.             }
  262.             break;
  263.         case rhdPropertySet:
  264.             switch (Property) {
  265.                 case RHD_OUTPUT_BACKLIGHT:
  266.                     if (Private->BlLevel < 0)
  267.                         return FALSE;
  268.                     LVDSSetBacklight(Output, val->integer);
  269.                     break;
  270.                 default:
  271.                     return FALSE;
  272.             }
  273.             break;
  274.     }
  275.     return TRUE;
  276. }
  277.  
  278. /*
  279.  *
  280.  */
  281. static void
  282. LVDSSet(struct rhdOutput *Output, DisplayModePtr Mode)
  283. {
  284.     struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
  285.     RHDPtr rhdPtr = RHDPTRI(Output);
  286.  
  287.     RHDFUNC(Output);
  288.  
  289.     RHDRegMask(Output, LVTMA_CNTL, 0x00000001, 0x00000001); /* enable */
  290.     usleep(20);
  291.  
  292.     RHDRegWrite(Output, LVTMA_MODE, 0); /* set to LVDS */
  293.  
  294.     /* Select CRTC, select syncA, no stereosync */
  295.     RHDRegMask(Output, LVTMA_SOURCE_SELECT, Output->Crtc->Id, 0x00010101);
  296.  
  297.     if (Private->LVDS24Bit) { /* 24bits */
  298.         RHDRegMask(Output, LVTMA_LVDS_DATA_CNTL, 0x00000001, 0x00000001); /* enable 24bits */
  299.         RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0x00101010, 0x00101010); /* dithering bit depth = 24 */
  300.  
  301.         if (Private->FPDI) /* FPDI? */
  302.             RHDRegMask(Output, LVTMA_LVDS_DATA_CNTL, 0x00000010, 0x00000010); /* 24 bit format: FPDI or LDI? */
  303.         else
  304.             RHDRegMask(Output, LVTMA_LVDS_DATA_CNTL, 0, 0x00000010);
  305.     } else {
  306.         RHDRegMask(Output, LVTMA_LVDS_DATA_CNTL, 0, 0x00000001); /* disable 24bits */
  307.         RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, 0x00101010); /* dithering bit depth != 24 */
  308.     }
  309.  
  310.     /* enable temporal dithering, disable spatial dithering and disable truncation */
  311.     RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL,
  312.                Private->TemporalDither ? 1 << 16 : 0
  313.                | Private->SpatialDither ? 1 << 8 : 0
  314.                | (Private->GreyLevel > 2) ? 1 << 24 : 0,
  315.                0x01010101);
  316.  
  317.     /* reset the temporal dithering */
  318.     RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, LVTMA_DITHER_RESET_BIT, LVTMA_DITHER_RESET_BIT);
  319.     RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, LVTMA_DITHER_RESET_BIT);
  320.  
  321.     /* go for RGB 4:4:4 RGB/YCbCr  */
  322.     RHDRegMask(Output, LVTMA_CNTL, 0, 0x00010000);
  323.  
  324.     if (Private->DualLink)
  325.         RHDRegMask(Output, LVTMA_CNTL, 0x01000000, 0x01000000);
  326.     else
  327.         RHDRegMask(Output, LVTMA_CNTL, 0, 0x01000000);
  328.  
  329.     /* PLL and TX voltages */
  330.     RHDRegWrite(Output, LVTMA_MACRO_CONTROL, Private->MacroControl);
  331.  
  332.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000010, 0x00000010); /* use pclk_lvtma_direct */
  333.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0xCC000000);
  334.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, Private->TXClockPattern << 16, 0x03FF0000);
  335.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000001, 0x00000001); /* enable PLL */
  336.     usleep(20);
  337.  
  338.     /* reset transmitter */
  339.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002);
  340.     usleep(2);
  341.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000002);
  342.     usleep(20);
  343.  
  344.     /* start data synchronisation */
  345.     RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0x00000001, 0x00000001);
  346.     RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0x00000100, 0x00000100); /* reset */
  347.     usleep(2);
  348.     RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0, 0x00000100);
  349. }
  350.  
  351. /*
  352.  *
  353.  */
  354. static void
  355. LVDSPWRSEQInit(struct rhdOutput *Output)
  356. {
  357.     struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
  358.     RHDPtr rhdPtr = RHDPTRI(Output);
  359.  
  360.     CARD32 tmp = 0;
  361.  
  362.     tmp = Private->PowerDigToDE >> 2;
  363.     RHDRegMask(Output, LVTMA_PWRSEQ_DELAY1, tmp, 0x000000FF);
  364.     RHDRegMask(Output, LVTMA_PWRSEQ_DELAY1, tmp << 24, 0xFF000000);
  365.  
  366.     tmp = Private->PowerDEToBL >> 2;
  367.     RHDRegMask(Output, LVTMA_PWRSEQ_DELAY1, tmp << 8, 0x0000FF00);
  368.     RHDRegMask(Output, LVTMA_PWRSEQ_DELAY1, tmp << 16, 0x00FF0000);
  369.  
  370.     RHDRegWrite(Output, LVTMA_PWRSEQ_DELAY2, Private->OffDelay >> 2);
  371.     RHDRegWrite(Output, LVTMA_PWRSEQ_REF_DIV,
  372.                 Private->PowerRefDiv | (Private->BlonRefDiv << 16));
  373.  
  374.     /* Enable power sequencer and allow it to override everything */
  375.     RHDRegMask(Output, LVTMA_PWRSEQ_CNTL, 0x0000000D, 0x0000000D);
  376.  
  377.     /* give full control to the sequencer */
  378.     RHDRegMask(Output, LVTMA_PWRSEQ_CNTL, 0, 0x02020200);
  379. }
  380.  
  381. /*
  382.  *
  383.  */
  384. static void
  385. LVDSEnable(struct rhdOutput *Output)
  386. {
  387.     struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
  388.     RHDPtr rhdPtr = RHDPTRI(Output);
  389.     CARD32 tmp = 0;
  390.     int i;
  391.  
  392.     RHDFUNC(Output);
  393.  
  394.     LVDSPWRSEQInit(Output);
  395.  
  396.     /* set up the transmitter */
  397.     RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x0000001E, 0x0000001E);
  398.     if (Private->LVDS24Bit) /* 24bit ? */
  399.         RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x00000020, 0x00000020);
  400.  
  401.     if (Private->DualLink) {
  402.         RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x00001E00, 0x00001E00);
  403.  
  404.         if (Private->LVDS24Bit)
  405.             RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x00002000, 0x00002000);
  406.     }
  407.  
  408.     RHDRegMask(Output, LVTMA_PWRSEQ_CNTL, 0x00000010, 0x00000010);
  409.  
  410.     for (i = 0; i <= Private->OffDelay; i++) {
  411.         usleep(1000);
  412.  
  413.         tmp = (RHDRegRead(Output, LVTMA_PWRSEQ_STATE) >> 8) & 0x0F;
  414.         if (tmp == 4)
  415.             break;
  416.     }
  417.  
  418.     if (i == Private->OffDelay) {
  419.         xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: failed to reach "
  420.              "POWERUP_DONE state after %d loops (%d)\n",
  421.              __func__, i, (int) tmp);
  422.   }
  423.     if (Private->BlLevel >= 0) {
  424.         union rhdPropertyData data;
  425.         data.integer = Private->BlLevel;
  426.         Output->Property(Output, rhdPropertySet, RHD_OUTPUT_BACKLIGHT,
  427.                          &data);
  428.     }
  429. }
  430.  
  431. /*
  432.  *
  433.  */
  434. static void
  435. LVDSDisable(struct rhdOutput *Output)
  436. {
  437.     struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
  438.     RHDPtr rhdPtr = RHDPTRI(Output);
  439.     CARD32 tmp = 0;
  440.     int i;
  441.  
  442.     RHDFUNC(Output);
  443.  
  444.     if (!(RHDRegRead(Output, LVTMA_PWRSEQ_CNTL) & 0x00000010))
  445.         return;
  446.  
  447.     LVDSPWRSEQInit(Output);
  448.  
  449.     RHDRegMask(Output, LVTMA_PWRSEQ_CNTL, 0, 0x00000010);
  450.  
  451.     for (i = 0; i <= Private->OffDelay; i++) {
  452.         usleep(1000);
  453.  
  454.         tmp = (RHDRegRead(Output, LVTMA_PWRSEQ_STATE) >> 8) & 0x0F;
  455.         if (tmp == 9)
  456.             break;
  457.     }
  458.  
  459.     if (i == Private->OffDelay) {
  460.         xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: failed to reach "
  461.                    "POWERDOWN_DONE state after %d loops (%d)\n",
  462.                    __func__, i, (int) tmp);
  463.     }
  464.  
  465.     RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x0000FFFF);
  466. }
  467.  
  468. #if 0
  469. /*
  470.  *
  471.  */
  472. static void
  473. LVDSShutdown(struct rhdOutput *Output)
  474. {
  475.     RHDPtr rhdPtr = RHDPTRI(Output);
  476.     RHDFUNC(Output);
  477.  
  478.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002); /* PLL in reset */
  479.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000001); /* disable LVDS */
  480.     RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0, 0x00000001);
  481.     RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, LVTMA_DITHER_RESET_BIT, LVTMA_DITHER_RESET_BIT); /* reset temp dithering */
  482.     RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, 0x00111111); /* disable all dithering */
  483.     RHDRegWrite(Output, LVTMA_CNTL, 0); /* disable */
  484. }
  485. #endif
  486.  
  487. /*
  488.  *
  489.  */
  490. static void
  491. LVDSPower(struct rhdOutput *Output, int Power)
  492. {
  493.     RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name,
  494.              rhdPowerString[Power]);
  495.  
  496.     switch (Power) {
  497.     case RHD_POWER_ON:
  498.         LVDSEnable(Output);
  499.         break;
  500.     case RHD_POWER_RESET:
  501.         /*      LVDSDisable(Output);
  502.                 break;*/
  503.     case RHD_POWER_SHUTDOWN:
  504.     default:
  505.         LVDSDisable(Output);
  506.         /* LVDSShutdown(Output); */
  507.         break;
  508.     }
  509.     return;
  510. }
  511.  
  512. /*
  513.  *
  514.  */
  515. static void
  516. LVDSSave(struct rhdOutput *Output)
  517. {
  518.     struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
  519.     RHDPtr rhdPtr = RHDPTRI(Output);
  520.  
  521.     RHDFUNC(Output);
  522.  
  523.     Private->StoreControl = RHDRegRead(Output, LVTMA_CNTL);
  524.     Private->StoreSourceSelect = RHDRegRead(Output,  LVTMA_SOURCE_SELECT);
  525.     Private->StoreBitDepthControl = RHDRegRead(Output, LVTMA_BIT_DEPTH_CONTROL);
  526.     Private->StoreDataSynchronisation = RHDRegRead(Output, LVTMA_DATA_SYNCHRONIZATION);
  527.     Private->StorePWRSEQRefDiv = RHDRegRead(Output, LVTMA_PWRSEQ_REF_DIV);
  528.     Private->StorePWRSEQDelay1 = RHDRegRead(Output, LVTMA_PWRSEQ_DELAY1);
  529.     Private->StorePWRSEQDelay2 = RHDRegRead(Output, LVTMA_PWRSEQ_DELAY2);
  530.     Private->StorePWRSEQControl = RHDRegRead(Output, LVTMA_PWRSEQ_CNTL);
  531.     Private->StorePWRSEQState = RHDRegRead(Output, LVTMA_PWRSEQ_STATE);
  532.     Private->StoreLVDSDataControl = RHDRegRead(Output, LVTMA_LVDS_DATA_CNTL);
  533.     Private->StoreMode = RHDRegRead(Output, LVTMA_MODE);
  534.     Private->StoreTxEnable = RHDRegRead(Output, LVTMA_TRANSMITTER_ENABLE);
  535.     Private->StoreMacroControl = RHDRegRead(Output, LVTMA_MACRO_CONTROL);
  536.     Private->StoreTXControl = RHDRegRead(Output, LVTMA_TRANSMITTER_CONTROL);
  537.     Private->StoreBlModCntl = RHDRegRead(Output, LVTMA_BL_MOD_CNTL);
  538.  
  539.     Private->Stored = TRUE;
  540. }
  541.  
  542. /*
  543.  * This needs to reset things like the temporal dithering and the TX appropriately.
  544.  * Currently it's a dumb register dump.
  545.  */
  546. static void
  547. LVDSRestore(struct rhdOutput *Output)
  548. {
  549.     struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
  550.     RHDPtr rhdPtr = RHDPTRI(Output);
  551.  
  552.     RHDFUNC(Output);
  553.  
  554.     if (!Private->Stored) {
  555.         xf86DrvMsg(Output->scrnIndex, X_ERROR,
  556.                    "%s: No registers stored.\n", __func__);
  557.         return;
  558.     }
  559.  
  560.     RHDRegWrite(Output, LVTMA_CNTL, Private->StoreControl);
  561.     RHDRegWrite(Output, LVTMA_SOURCE_SELECT, Private->StoreSourceSelect);
  562.     RHDRegWrite(Output, LVTMA_BIT_DEPTH_CONTROL,  Private->StoreBitDepthControl);
  563.     RHDRegWrite(Output, LVTMA_DATA_SYNCHRONIZATION, Private->StoreDataSynchronisation);
  564.     RHDRegWrite(Output, LVTMA_PWRSEQ_REF_DIV, Private->StorePWRSEQRefDiv);
  565.     RHDRegWrite(Output, LVTMA_PWRSEQ_DELAY1, Private->StorePWRSEQDelay1);
  566.     RHDRegWrite(Output, LVTMA_PWRSEQ_DELAY2,  Private->StorePWRSEQDelay2);
  567.     RHDRegWrite(Output, LVTMA_PWRSEQ_CNTL, Private->StorePWRSEQControl);
  568.     RHDRegWrite(Output, LVTMA_PWRSEQ_STATE, Private->StorePWRSEQState);
  569.     RHDRegWrite(Output, LVTMA_LVDS_DATA_CNTL, Private->StoreLVDSDataControl);
  570.     RHDRegWrite(Output, LVTMA_MODE, Private->StoreMode);
  571.     RHDRegWrite(Output, LVTMA_TRANSMITTER_ENABLE, Private->StoreTxEnable);
  572.     RHDRegWrite(Output, LVTMA_MACRO_CONTROL, Private->StoreMacroControl);
  573.     RHDRegWrite(Output, LVTMA_TRANSMITTER_CONTROL,  Private->StoreTXControl);
  574.     RHDRegWrite(Output, LVTMA_BL_MOD_CNTL, Private->StoreBlModCntl);
  575.  
  576.     /*
  577.      * Poor man's debug
  578.      */
  579.     LVDSDebugBacklight(Output);
  580. }
  581.  
  582. /*
  583.  * Here we pretty much assume that ATOM has either initialised the panel already
  584.  * or that we can find information from ATOM BIOS data tables. We know that the
  585.  * latter assumption is false for some values, but there is no getting around
  586.  * ATI clinging desperately to a broken concept.
  587.  */
  588. static struct LVDSPrivate *
  589. LVDSInfoRetrieve(RHDPtr rhdPtr)
  590. {
  591.     struct LVDSPrivate *Private = xnfcalloc(sizeof(struct LVDSPrivate), 1);
  592.     CARD32 tmp;
  593.  
  594.     /* These values are not available from atombios data tables at all. */
  595.     Private->MacroControl = RHDRegRead(rhdPtr, LVTMA_MACRO_CONTROL);
  596.     Private->TXClockPattern =
  597.   (_RHDRegRead(rhdPtr, LVTMA_TRANSMITTER_CONTROL) >> 16) & 0x3FF;
  598.  
  599.     /* For these values, we try to retrieve them from register space first,
  600.        and later override with atombios data table information */
  601.     Private->PowerDigToDE =
  602.   (_RHDRegRead(rhdPtr, LVTMA_PWRSEQ_DELAY1) & 0x000000FF) << 2;
  603.  
  604.     Private->PowerDEToBL =
  605.   (_RHDRegRead(rhdPtr, LVTMA_PWRSEQ_DELAY1) & 0x0000FF00) >> 6;
  606.  
  607.     Private->OffDelay = (_RHDRegRead(rhdPtr, LVTMA_PWRSEQ_DELAY2) & 0xFF) << 2;
  608.  
  609.     tmp = _RHDRegRead(rhdPtr, LVTMA_PWRSEQ_REF_DIV);
  610.     Private->PowerRefDiv = tmp & 0x0FFF;
  611.     Private->BlonRefDiv = (tmp >> 16) & 0x0FFF;
  612.     tmp = _RHDRegRead(rhdPtr, LVTMA_BL_MOD_CNTL);
  613.     if (tmp & 0x1)
  614.         Private->BlLevel = (tmp >> 8) & 0xff;
  615.     else
  616.         Private->BlLevel = -1; /* Backlight control seems to be done some other way */
  617.  
  618.     Private->DualLink = (_RHDRegRead(rhdPtr, LVTMA_CNTL) >> 24) & 0x00000001;
  619.     Private->LVDS24Bit = _RHDRegRead(rhdPtr, LVTMA_LVDS_DATA_CNTL) & 0x00000001;
  620.     Private->FPDI = _RHDRegRead(rhdPtr, LVTMA_LVDS_DATA_CNTL) & 0x00000010;
  621.  
  622.     tmp = _RHDRegRead(rhdPtr, LVTMA_BIT_DEPTH_CONTROL);
  623.     Private->TemporalDither =  ((tmp & (1 << 16)) != 0);
  624.     Private->SpatialDither = ((tmp & (1 << 8)) != 0);
  625.     Private->GreyLevel = (tmp & (1 << 24)) ? 4 : 2;
  626.  
  627. #ifdef ATOM_BIOS
  628.     {
  629.         AtomBiosArgRec data;
  630.  
  631.   if(RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
  632.                            ATOM_LVDS_SEQ_DIG_ONTO_DE, &data) == ATOM_SUCCESS)
  633.             Private->PowerDigToDE = data.val;
  634.  
  635.   if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
  636.                             ATOM_LVDS_SEQ_DE_TO_BL, &data) == ATOM_SUCCESS)
  637.             Private->PowerDEToBL = data.val;
  638.  
  639.   if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
  640.                             ATOM_LVDS_OFF_DELAY, &data) == ATOM_SUCCESS)
  641.             Private->OffDelay = data.val;
  642.  
  643.   if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
  644.                             ATOM_LVDS_DUALLINK, &data) == ATOM_SUCCESS)
  645.             Private->DualLink = data.val;
  646.  
  647.   if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
  648.                             ATOM_LVDS_24BIT, &data) == ATOM_SUCCESS)
  649.             Private->LVDS24Bit = data.val;
  650.  
  651.   if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
  652.                                  ATOM_LVDS_FPDI, &data) == ATOM_SUCCESS)
  653.             Private->FPDI = data.val;
  654.  
  655.   if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
  656.                             ATOM_LVDS_TEMPORAL_DITHER, &data) == ATOM_SUCCESS)
  657.             Private->TemporalDither = data.val;
  658.  
  659.   if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
  660.                             ATOM_LVDS_SPATIAL_DITHER, &data) == ATOM_SUCCESS)
  661.             Private->SpatialDither = data.val;
  662.  
  663.   if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
  664.                             ATOM_LVDS_GREYLVL, &data) == ATOM_SUCCESS) {
  665.             Private->GreyLevel = data.val;
  666.             xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "AtomBIOS returned %i Grey Levels\n",
  667.                        Private->GreyLevel);
  668.     }
  669.     }
  670. #endif
  671.  
  672.     if (Private->LVDS24Bit)
  673.         xf86DrvMsg(rhdPtr->scrnIndex, X_PROBED,
  674.                    "Detected a 24bit %s, %s link panel.\n",
  675.             Private->DualLink ? "dual" : "single",
  676.             Private->FPDI ? "FPDI": "LDI");
  677.     else
  678.         xf86DrvMsg(rhdPtr->scrnIndex, X_PROBED,
  679.                    "Detected a 18bit %s link panel.\n",
  680.              Private->DualLink ? "dual" : "single");
  681.  
  682.     /* extra noise */
  683.     RHDDebug(rhdPtr->scrnIndex, "Printing LVDS paramaters:\n");
  684.     xf86MsgVerb(X_NONE, LOG_DEBUG, "\tMacroControl: 0x%08X\n",
  685.                 (unsigned int) Private->MacroControl);
  686.     xf86MsgVerb(X_NONE, LOG_DEBUG, "\tTXClockPattern: 0x%04X\n",
  687.                 Private->TXClockPattern);
  688.     xf86MsgVerb(X_NONE, LOG_DEBUG, "\tPowerDigToDE: 0x%04X\n",
  689.                 Private->PowerDigToDE);
  690.     xf86MsgVerb(X_NONE, LOG_DEBUG, "\tPowerDEToBL: 0x%04X\n",
  691.                 Private->PowerDEToBL);
  692.     xf86MsgVerb(X_NONE, LOG_DEBUG, "\tOffDelay: 0x%04X\n",
  693.                 Private->OffDelay);
  694.     xf86MsgVerb(X_NONE, LOG_DEBUG, "\tPowerRefDiv: 0x%04X\n",
  695.                 Private->PowerRefDiv);
  696.     xf86MsgVerb(X_NONE, LOG_DEBUG, "\tBlonRefDiv: 0x%04X\n",
  697.                 Private->BlonRefDiv);
  698.  
  699.     return Private;
  700. }
  701.  
  702. /*
  703.  *
  704.  */
  705. static void
  706. LVDSDestroy(struct rhdOutput *Output)
  707. {
  708.  
  709.     struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
  710.  
  711.     RHDFUNC(Output);
  712.  
  713.     if (!Private)
  714.         return;
  715.  
  716. #ifdef NOT_YET
  717.     if (Private->PropertyPrivate)
  718.         RhdAtomDestroyBacklightControlProperty(Output, Private->PropertyPrivate);
  719. #endif
  720.     xfree(Private);
  721.     Output->Private = NULL;
  722. }
  723.  
  724. /*
  725.  *
  726.  * Handling for LVTMA block as TMDS.
  727.  *
  728.  */
  729. struct rhdTMDSBPrivate {
  730.     Bool RunsDualLink;
  731.     Bool Coherent;
  732.     DisplayModePtr Mode;
  733.  
  734.     struct rhdHdmi *Hdmi;
  735.  
  736.     Bool Stored;
  737.  
  738.     CARD32 StoreControl;
  739.     CARD32 StoreSource;
  740.     CARD32 StoreFormat;
  741.     CARD32 StoreForce;
  742.     CARD32 StoreReduction;
  743.     CARD32 StoreDCBalancer;
  744.     CARD32 StoreDataSynchro;
  745.     CARD32 StoreMode;
  746.     CARD32 StoreTXEnable;
  747.     CARD32 StoreMacro;
  748.     CARD32 StoreTXControl;
  749.     CARD32 StoreTXAdjust;
  750.     CARD32 StoreTestOutput;
  751.  
  752.     CARD32 StoreRs690Unknown;
  753.     CARD32 StoreRv600TXAdjust;
  754.     CARD32 StoreRv600PreEmphasis;
  755. };
  756.  
  757. /*
  758.  *
  759.  */
  760. static ModeStatus
  761. TMDSBModeValid(struct rhdOutput *Output, DisplayModePtr Mode)
  762. {
  763.     RHDFUNC(Output);
  764.  
  765.     if (Mode->Flags & V_INTERLACE)
  766.         return MODE_NO_INTERLACE;
  767.  
  768.     if (Mode->Clock < 25000)
  769.         return MODE_CLOCK_LOW;
  770.  
  771.     if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE) {
  772.     if (Mode->Clock > 165000)
  773.         return MODE_CLOCK_HIGH;
  774.     } else if (Output->Connector->Type == RHD_CONNECTOR_DVI) {
  775.         if (Mode->Clock > 330000) /* could go higher still */
  776.             return MODE_CLOCK_HIGH;
  777.     }
  778.  
  779.     return MODE_OK;
  780. }
  781.  
  782. /*
  783.  *
  784.  */
  785. static void
  786. RS600VoltageControl(struct rhdOutput *Output, DisplayModePtr Mode)
  787. {
  788.     struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
  789.  
  790.     RHDFUNC(Output);
  791. #ifdef NOTYET
  792.     if (Output->Connector == RHD_CONNECTOR_HDMI || Output->Connector == RHD_CONNECTOR_HDMI_DUAL) {
  793.         int clock = Mode->SynthClock;
  794.  
  795.         if (Private->RunsDualLink)
  796.             clock >>= 1;
  797.         if (clock <= 75000) {
  798.             RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00010213);
  799.             RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x000a0000);
  800.         } else {
  801.             RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00000213);
  802.             RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x00100000);
  803.         }
  804.     } else
  805. #endif
  806.     {
  807.         if (Private->RunsDualLink) {
  808.             RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000020f);
  809.             RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x00100000);
  810.         } else {
  811.             if (Mode->SynthClock < 39000)
  812.                 RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0002020f);
  813.             else
  814.                 RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000020f);
  815.             RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x00100000);
  816.         }
  817.     }
  818. }
  819.  
  820. /*
  821.  *
  822.  */
  823. static void
  824. RS690VoltageControl(struct rhdOutput *Output, DisplayModePtr Mode)
  825. {
  826.     RHDPtr rhdPtr = RHDPTRI(Output);
  827.     struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
  828.     CARD32 rev = (RHDRegRead(Output, CONFIG_CNTL) && RS69_CFG_ATI_REV_ID_MASK) >> RS69_CFG_ATI_REV_ID_SHIFT;
  829.  
  830.     if (rev < 3) {
  831. #ifdef NOTYET
  832.         if (Output->Connector == RHD_CONNECTOR_HDMI || Output->Connector == RHD_CONNECTOR_HDMI_DUAL) {
  833.             if (Mode->SynthClock > 75000) {
  834.                 RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0xa001632f);
  835.                 RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x05120000);
  836.                 RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
  837.             } else if (Mode->SynthClock > 41000) {
  838.                 RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000632f);
  839.                 RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x05120000);
  840.                 RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
  841.             } else {
  842.                 RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0003632f);
  843.                 RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x050b000);
  844.                 RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x0, 0x10000000);
  845.             }
  846.         } else
  847. #endif
  848.         {
  849.             int clock = Mode->SynthClock;
  850.  
  851.             if (Private->RunsDualLink)
  852.                 clock >>= 1;
  853.  
  854.             RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x05120000);
  855.  
  856.             if (clock > 75000) {
  857.                 RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0xa001631f);
  858.                 RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
  859.             } else if (clock > 41000) {
  860.                 RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000631f);
  861.                 RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
  862.             } else {
  863.                 RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0003631f);
  864.                 RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x0, 0x10000000);
  865.             }
  866.         }
  867.     } else {
  868. #ifdef NOTYET
  869.         if (Output->Connector == RHD_CONNECTOR_HDMI || Output->Connector == RHD_CONNECTOR_HDMI_DUAL) {
  870.             if (Mode->SynthClock <= 75000) {
  871.                 RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0002612f);
  872.                 RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x010b0000);
  873.                 RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x0, 0x10000000);
  874.             } else {
  875.                 RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000642f);
  876.                 RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x01120000);
  877.                 RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
  878.             }
  879.         } else
  880. #endif
  881.         {
  882.             int clock = Mode->SynthClock;
  883.  
  884.             if (Private->RunsDualLink)
  885.                 clock >>= 1;
  886.  
  887.             RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x01120000);
  888.             RHDRegMask(Output,  LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
  889.  
  890.             if (Mode->SynthClock > 75000) {
  891.                 RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00016318);
  892.             } else {
  893.                 {
  894. #ifdef ATOM_BIOS
  895.                     AtomBiosArgRec data;
  896.  
  897.         if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
  898.                                         ATOM_GET_CAPABILITY_FLAG, &data) == ATOM_SUCCESS) {
  899.                         if (((data.val & 0x60) == 0x20 || (data.val & 0x80))) {
  900.                             RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00016318);
  901.                         } else {
  902.                             RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00006318);
  903.                         }
  904.                     } else
  905. #endif
  906.                     {
  907.                         RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00006318);
  908.                     }
  909.                 }
  910.             }
  911.         }
  912.     }
  913. }
  914.  
  915. /*
  916.  * This information is not provided in an atombios data table.
  917.  */
  918. static struct R5xxTMDSBMacro {
  919.     CARD16 Device;
  920.     CARD32 MacroSingle;
  921.     CARD32 MacroDual;
  922. } R5xxTMDSBMacro[] = {
  923.     /*
  924.      * this list isn't complete yet.
  925.      *  Some more values for dual need to be dug up
  926.      */
  927.     { 0x7104, 0x00F20616, 0x00F20616 }, /* R520  */
  928.     { 0x7142, 0x00F2061C, 0x00F2061C }, /* RV515 */
  929.     { 0x7145, 0x00F1061D, 0x00F2061D }, /**/
  930.     { 0x7146, 0x00F1061D, 0x00F1061D }, /* RV515 */
  931.     { 0x7147, 0x0082041D, 0x0082041D }, /* RV505 */
  932.     { 0x7149, 0x00F1061D, 0x00D2061D }, /**/
  933.     { 0x7152, 0x00F2061C, 0x00F2061C }, /* RV515 */
  934.     { 0x7183, 0x00B2050C, 0x00B2050C }, /* RV530 */
  935.     { 0x71C0, 0x00F1061F, 0x00f2061D }, /**/
  936.     { 0x71C1, 0x0062041D, 0x0062041D }, /* RV535 *//**/
  937.     { 0x71C2, 0x00F1061D, 0x00F2061D }, /* RV530 *//**/
  938.     { 0x71C5, 0x00D1061D, 0x00D2061D }, /**/
  939.     { 0x71C6, 0x00F2061D, 0x00F2061D }, /* RV530 */
  940.     { 0x71D2, 0x00F10610, 0x00F20610 }, /* RV530: atombios uses 0x00F1061D *//**/
  941.     { 0x7249, 0x00F1061D, 0x00F1061D }, /* R580  */
  942.     { 0x724B, 0x00F10610, 0x00F10610 }, /* R580: atombios uses 0x00F1061D */
  943.     { 0x7280, 0x0042041F, 0x0042041F }, /* RV570 *//**/
  944.     { 0x7288, 0x0042041F, 0x0042041F }, /* RV570 */
  945.     { 0x791E, 0x0001642F, 0x0001642F }, /* RS690 */
  946.     { 0x791F, 0x0001642F, 0x0001642F }, /* RS690 */
  947.     { 0x9400, 0x00020213, 0x00020213 }, /* R600  */
  948.     { 0x9401, 0x00020213, 0x00020213 }, /* R600  */
  949.     { 0x9402, 0x00020213, 0x00020213 }, /* R600  */
  950.     { 0x9403, 0x00020213, 0x00020213 }, /* R600  */
  951.     { 0x9405, 0x00020213, 0x00020213 }, /* R600  */
  952.     { 0x940A, 0x00020213, 0x00020213 }, /* R600  */
  953.     { 0x940B, 0x00020213, 0x00020213 }, /* R600  */
  954.     { 0x940F, 0x00020213, 0x00020213 }, /* R600  */
  955.     { 0, 0, 0 } /* End marker */
  956. };
  957.  
  958. static struct RV6xxTMDSBMacro {
  959.     CARD16 Device;
  960.     CARD32 Macro;
  961.     CARD32 TX;
  962.     CARD32 PreEmphasis;
  963. } RV6xxTMDSBMacro[] = {
  964.     { 0x94C1, 0x01030311, 0x10001A00, 0x01801015}, /* RV610 */
  965.     { 0x94C3, 0x01030311, 0x10001A00, 0x01801015}, /* RV610 */
  966.     { 0x9501, 0x0533041A, 0x020010A0, 0x41002045}, /* RV670 */
  967.     { 0x9505, 0x0533041A, 0x020010A0, 0x41002045}, /* RV670 */
  968.     { 0x950F, 0x0533041A, 0x020010A0, 0x41002045}, /* R680  */
  969.     { 0x9587, 0x01030311, 0x10001C00, 0x01C01011}, /* RV630 */
  970.     { 0x9588, 0x01030311, 0x10001C00, 0x01C01011}, /* RV630 */
  971.     { 0x9589, 0x01030311, 0x10001C00, 0x01C01011}, /* RV630 */
  972.     { 0, 0, 0, 0} /* End marker */
  973. };
  974.  
  975. static void
  976. TMDSBVoltageControl(struct rhdOutput *Output, DisplayModePtr Mode)
  977. {
  978.     struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
  979.     RHDPtr rhdPtr = RHDPTRI(Output);
  980.   int i;
  981.  
  982.     /* IGP chipsets are rather special */
  983.     if (rhdPtr->ChipSet == RHD_RS690) {
  984.         RS690VoltageControl(Output, Mode);
  985.         return;
  986.     } else if (rhdPtr->ChipSet == RHD_RS600) {
  987.         RS600VoltageControl(Output, Mode);
  988.         return;
  989.     }
  990.  
  991.     /* TEST_OUTPUT register - IGPs are handled above */
  992.     if (rhdPtr->ChipSet < RHD_RS600) /* r5xx */
  993.         RHDRegMask(Output, LVTMA_REG_TEST_OUTPUT, 0x00200000, 0x00200000);
  994.     else if (rhdPtr->ChipSet < RHD_RV670)
  995.         RHDRegMask(Output, LVTMA_REG_TEST_OUTPUT, 0x00100000, 0x00100000);
  996.  
  997.     /* macro control values */
  998.     if (rhdPtr->ChipSet < RHD_RV610) { /* R5xx and R600 */
  999.     for (i = 0; R5xxTMDSBMacro[i].Device; i++)
  1000.             if (R5xxTMDSBMacro[i].Device == rhdPtr->PciDeviceID) {
  1001.                 if (!Private->RunsDualLink)
  1002.                     RHDRegWrite(Output, LVTMA_MACRO_CONTROL, R5xxTMDSBMacro[i].MacroSingle);
  1003.                 else
  1004.                     RHDRegWrite(Output, LVTMA_MACRO_CONTROL, R5xxTMDSBMacro[i].MacroDual);
  1005.         return;
  1006.             }
  1007.  
  1008.         xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n",
  1009.                    __func__, rhdPtr->PciDeviceID);
  1010.         xf86DrvMsg(Output->scrnIndex, X_INFO, "LVTMA_MACRO_CONTROL: 0x%08X\n",
  1011.                    (unsigned int) RHDRegRead(Output, LVTMA_MACRO_CONTROL));
  1012.     } else { /* RV6x0 and up */
  1013.     for (i = 0; RV6xxTMDSBMacro[i].Device; i++)
  1014.             if (RV6xxTMDSBMacro[i].Device == rhdPtr->PciDeviceID) {
  1015.         RHDRegWrite(Output, LVTMA_MACRO_CONTROL, RV6xxTMDSBMacro[i].Macro);
  1016.         RHDRegWrite(Output, LVTMA_TRANSMITTER_ADJUST, RV6xxTMDSBMacro[i].TX);
  1017.         RHDRegWrite(Output, LVTMA_PREEMPHASIS_CONTROL, RV6xxTMDSBMacro[i].PreEmphasis);
  1018.         return;
  1019.             }
  1020.  
  1021.         xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n",
  1022.                    __func__, rhdPtr->PciDeviceID);
  1023.         xf86DrvMsg(Output->scrnIndex, X_INFO, "LVTMA_MACRO_CONTROL: 0x%08X\n",
  1024.             (unsigned int) RHDRegRead(Output, LVTMA_MACRO_CONTROL));
  1025.         xf86DrvMsg(Output->scrnIndex, X_INFO, "LVTMA_TRANSMITTER_ADJUST: 0x%08X\n",
  1026.             (unsigned int) RHDRegRead(Output, LVTMA_TRANSMITTER_ADJUST));
  1027.         xf86DrvMsg(Output->scrnIndex, X_INFO, "LVTMA_PREEMPHASIS_CONTROL: 0x%08X\n",
  1028.             (unsigned int) RHDRegRead(Output, LVTMA_PREEMPHASIS_CONTROL));
  1029.     }
  1030. }
  1031.  
  1032. /*
  1033.  *
  1034.  */
  1035. static Bool
  1036. TMDSBPropertyControl(struct rhdOutput *Output,
  1037.              enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val)
  1038. {
  1039.     struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
  1040.  
  1041.     RHDFUNC(Output);
  1042.     switch (Action) {
  1043.         case rhdPropertyCheck:
  1044.             switch (Property) {
  1045.                 case RHD_OUTPUT_COHERENT:
  1046.                     return TRUE;
  1047.                 default:
  1048.                     return FALSE;
  1049.             }
  1050.         case rhdPropertyGet:
  1051.             switch (Property) {
  1052.                 case RHD_OUTPUT_COHERENT:
  1053.                     val->Bool = Private->Coherent;
  1054.                     return TRUE;
  1055.                 default:
  1056.                     return FALSE;
  1057.             }
  1058.             break;
  1059.         case rhdPropertySet:
  1060.             switch (Property) {
  1061.                 case RHD_OUTPUT_COHERENT:
  1062.                     Private->Coherent = val->Bool;
  1063.                     Output->Mode(Output, Private->Mode);
  1064.                     Output->Power(Output, RHD_POWER_ON);
  1065.                     break;
  1066.                 default:
  1067.                     return FALSE;
  1068.             }
  1069.             break;
  1070.     }
  1071.     return TRUE;
  1072. }
  1073.  
  1074. /*
  1075.  *
  1076.  */
  1077. static void
  1078. TMDSBSet(struct rhdOutput *Output, DisplayModePtr Mode)
  1079. {
  1080.     RHDPtr rhdPtr = RHDPTRI(Output);
  1081.     struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
  1082.  
  1083.     RHDFUNC(Output);
  1084.  
  1085.     RHDRegMask(Output, LVTMA_MODE, 0x00000001, 0x00000001); /* select TMDS */
  1086.  
  1087.     /* Clear out some HPD events first: this should be under driver control. */
  1088.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x0000000C);
  1089.     RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00070000);
  1090.     RHDRegMask(Output, LVTMA_CNTL, 0, 0x00000010);
  1091.  
  1092.     /* Disable the transmitter */
  1093.         RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00003E3E);
  1094.  
  1095.     /* Disable bit reduction and reset temporal dither */
  1096.     RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, 0x00010101);
  1097.     RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, LVTMA_DITHER_RESET_BIT, LVTMA_DITHER_RESET_BIT);
  1098.     usleep(2);
  1099.     RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, LVTMA_DITHER_RESET_BIT);
  1100.     RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, 0xF0000000); /* not documented */
  1101.  
  1102.     /* reset phase on vsync and use RGB */
  1103.     RHDRegMask(Output, LVTMA_CNTL, 0x00001000, 0x00011000);
  1104.  
  1105.     /* Select CRTC, select syncA, no stereosync */
  1106.     RHDRegMask(Output, LVTMA_SOURCE_SELECT, Output->Crtc->Id, 0x00010101);
  1107.  
  1108.     RHDRegWrite(Output, LVTMA_COLOR_FORMAT, 0);
  1109.  
  1110.     Private->Mode = Mode;
  1111.     if (Mode->SynthClock > 165000) {
  1112.         RHDRegMask(Output, LVTMA_CNTL, 0x01000000, 0x01000000);
  1113.         Private->RunsDualLink = TRUE; /* for TRANSMITTER_ENABLE in TMDSBPower */
  1114.     } else {
  1115.     RHDRegMask(Output, LVTMA_CNTL, 0, 0x01000000);
  1116.         Private->RunsDualLink = FALSE;
  1117.     }
  1118.  
  1119.     if (rhdPtr->ChipSet > RHD_R600) /* Rv6xx: disable split mode */
  1120.         RHDRegMask(Output, LVTMA_CNTL, 0, 0x20000000);
  1121.  
  1122.     /* Disable force data */
  1123.     RHDRegMask(Output, LVTMA_FORCE_OUTPUT_CNTL, 0, 0x00000001);
  1124.  
  1125.     /* DC balancer enable */
  1126.     RHDRegMask(Output, LVTMA_DCBALANCER_CONTROL, 0x00000001, 0x00000001);
  1127.  
  1128.     TMDSBVoltageControl(Output, Mode);
  1129.  
  1130.     /* use IDCLK */
  1131.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000010, 0x00000010);
  1132.     /* LVTMA only: use clock selected by next write */
  1133.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x20000000, 0x20000000);
  1134.     /* coherent mode */
  1135.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL,
  1136.                Private->Coherent ? 0 : 0x10000000, 0x10000000);
  1137.     /* clear LVDS clock pattern */
  1138.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x03FF0000);
  1139.  
  1140.     /* reset transmitter pll */
  1141.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002);
  1142.     usleep(2);
  1143.     RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000002);
  1144.     usleep(20);
  1145.  
  1146.     /* restart data synchronisation */
  1147.     RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0x00000001, 0x00000001);
  1148.     RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0x00000100, 0x00000100);
  1149.     usleep(2);
  1150.     RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0, 0x00000001);
  1151.  
  1152.     RHDHdmiSetMode(Private->Hdmi, Mode);
  1153. }
  1154.  
  1155. /*
  1156.  *
  1157.  */
  1158. static void
  1159. TMDSBPower(struct rhdOutput *Output, int Power)
  1160. {
  1161.     RHDPtr rhdPtr = RHDPTRI(Output);
  1162.     struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
  1163.  
  1164.     RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name,
  1165.              rhdPowerString[Power]);
  1166.  
  1167.     RHDRegMask(Output, LVTMA_MODE, 0x00000001, 0x00000001); /* select TMDS */
  1168.  
  1169.     switch (Power) {
  1170.     case RHD_POWER_ON:
  1171.         RHDRegMask(Output, LVTMA_CNTL, 0x1, 0x00000001);
  1172.  
  1173.         if (Private->RunsDualLink)
  1174.             RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x00003E3E,0x00003E3E);
  1175.         else
  1176.             RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x0000003E, 0x00003E3E);
  1177.  
  1178.         RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000001, 0x00000001);
  1179.         usleep(2);
  1180.         RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000002);
  1181.         if(Output->Connector != NULL && RHDConnectorEnableHDMI(Output->Connector))
  1182.             RHDHdmiEnable(Private->Hdmi, TRUE);
  1183.         else
  1184.             RHDHdmiEnable(Private->Hdmi, FALSE);
  1185.         return;
  1186.     case RHD_POWER_RESET:
  1187.         RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00003E3E);
  1188.         return;
  1189.     case RHD_POWER_SHUTDOWN:
  1190.     default:
  1191.         RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002);
  1192.         usleep(2);
  1193.         RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000001);
  1194.         RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00003E3E);
  1195.         RHDRegMask(Output, LVTMA_CNTL, 0, 0x00000001);
  1196.         RHDHdmiEnable(Private->Hdmi, FALSE);
  1197.         return;
  1198.     }
  1199. }
  1200.  
  1201. /*
  1202.  *
  1203.  */
  1204. static void
  1205. TMDSBSave(struct rhdOutput *Output)
  1206. {
  1207.     struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
  1208.     RHDPtr rhdPtr = RHDPTRI(Output);
  1209.  
  1210.     RHDFUNC(Output);
  1211.  
  1212.     Private->StoreControl = RHDRegRead(Output, LVTMA_CNTL);
  1213.     Private->StoreSource = RHDRegRead(Output, LVTMA_SOURCE_SELECT);
  1214.     Private->StoreFormat = RHDRegRead(Output, LVTMA_COLOR_FORMAT);
  1215.     Private->StoreForce = RHDRegRead(Output, LVTMA_FORCE_OUTPUT_CNTL);
  1216.     Private->StoreReduction = RHDRegRead(Output, LVTMA_BIT_DEPTH_CONTROL);
  1217.     Private->StoreDCBalancer = RHDRegRead(Output, LVTMA_DCBALANCER_CONTROL);
  1218.  
  1219.     Private->StoreDataSynchro = RHDRegRead(Output, LVTMA_DATA_SYNCHRONIZATION);
  1220.     Private->StoreMode = RHDRegRead(Output, LVTMA_MODE);
  1221.     Private->StoreTXEnable = RHDRegRead(Output, LVTMA_TRANSMITTER_ENABLE);
  1222.     Private->StoreMacro = RHDRegRead(Output, LVTMA_MACRO_CONTROL);
  1223.     Private->StoreTXControl = RHDRegRead(Output, LVTMA_TRANSMITTER_CONTROL);
  1224.     Private->StoreTestOutput = RHDRegRead(Output, LVTMA_REG_TEST_OUTPUT);
  1225.  
  1226.     if (rhdPtr->ChipSet > RHD_R600) { /* Rv6x0 */
  1227.        Private->StoreRv600TXAdjust = RHDRegRead(Output, LVTMA_TRANSMITTER_ADJUST);
  1228.        Private->StoreRv600PreEmphasis = RHDRegRead(Output, LVTMA_PREEMPHASIS_CONTROL);
  1229.     }
  1230.  
  1231.     RHDHdmiSave(Private->Hdmi);
  1232.  
  1233.     Private->Stored = TRUE;
  1234. }
  1235.  
  1236. /*
  1237.  *
  1238.  */
  1239. static void
  1240. TMDSBRestore(struct rhdOutput *Output)
  1241. {
  1242.     struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
  1243.     RHDPtr rhdPtr = RHDPTRI(Output);
  1244.  
  1245.     RHDFUNC(Output);
  1246.  
  1247.     if (!Private->Stored) {
  1248.         xf86DrvMsg(Output->scrnIndex, X_ERROR,
  1249.                    "%s: No registers stored.\n", __func__);
  1250.         return;
  1251.     }
  1252.  
  1253.     RHDRegWrite(Output, LVTMA_CNTL, Private->StoreControl);
  1254.     RHDRegWrite(Output, LVTMA_SOURCE_SELECT, Private->StoreSource);
  1255.     RHDRegWrite(Output, LVTMA_COLOR_FORMAT, Private->StoreFormat);
  1256.     RHDRegWrite(Output, LVTMA_FORCE_OUTPUT_CNTL, Private->StoreForce);
  1257.     RHDRegWrite(Output, LVTMA_BIT_DEPTH_CONTROL, Private->StoreReduction);
  1258.     RHDRegWrite(Output, LVTMA_DCBALANCER_CONTROL, Private->StoreDCBalancer);
  1259.  
  1260.     RHDRegWrite(Output, LVTMA_DATA_SYNCHRONIZATION, Private->StoreDataSynchro);
  1261.     RHDRegWrite(Output, LVTMA_MODE, Private->StoreMode);
  1262.     RHDRegWrite(Output, LVTMA_TRANSMITTER_ENABLE, Private->StoreTXEnable);
  1263.     RHDRegWrite(Output, LVTMA_MACRO_CONTROL, Private->StoreMacro);
  1264.     RHDRegWrite(Output, LVTMA_TRANSMITTER_CONTROL, Private->StoreTXControl);
  1265.     RHDRegWrite(Output, LVTMA_REG_TEST_OUTPUT, Private->StoreTestOutput);
  1266.  
  1267.     if (rhdPtr->ChipSet > RHD_R600) { /* Rv6x0 */
  1268.         RHDRegWrite(Output, LVTMA_TRANSMITTER_ADJUST, Private->StoreRv600TXAdjust);
  1269.         RHDRegWrite(Output, LVTMA_PREEMPHASIS_CONTROL, Private->StoreRv600PreEmphasis);
  1270.     }
  1271.  
  1272.     RHDHdmiRestore(Private->Hdmi);
  1273. }
  1274.  
  1275.  
  1276. /*
  1277.  *
  1278.  */
  1279. static void
  1280. TMDSBDestroy(struct rhdOutput *Output)
  1281. {
  1282.     struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private;
  1283.     RHDFUNC(Output);
  1284.  
  1285.     if (!Private)
  1286.         return;
  1287.  
  1288.     RHDHdmiDestroy(Private->Hdmi);
  1289.  
  1290.     xfree(Private);
  1291.     Output->Private = NULL;
  1292. }
  1293.  
  1294. #ifdef NOT_YET
  1295. static Bool
  1296. LVDSPropertyWrapper(struct rhdOutput *Output,
  1297.                     enum rhdPropertyAction Action,
  1298.                     enum rhdOutputProperty Property,
  1299.                     union rhdPropertyData *val)
  1300. {
  1301.     struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private;
  1302.     void *storePrivate = Output->Private;
  1303.     Bool (*func)(struct rhdOutput *,enum rhdPropertyAction, enum rhdOutputProperty,
  1304.                   union rhdPropertyData *) = Private->WrappedPropertyCallback;
  1305.     Bool ret;
  1306.  
  1307.     Output->Private = Private->PropertyPrivate;
  1308.     ret = func(Output, Action, Property, val);
  1309.     Output->Private = storePrivate;
  1310.  
  1311.     return ret;
  1312. }
  1313. #endif
  1314.  
  1315. /*
  1316.  *
  1317.  */
  1318. struct rhdOutput *
  1319. RHDLVTMAInit(RHDPtr rhdPtr, CARD8 Type)
  1320. {
  1321.     struct rhdOutput *Output;
  1322.  
  1323.     RHDFUNC(rhdPtr);
  1324.  
  1325.     /* Stop weird connector types */
  1326.     if ((Type != RHD_CONNECTOR_PANEL)
  1327.         && (Type != RHD_CONNECTOR_DVI)
  1328.         && (Type != RHD_CONNECTOR_DVI_SINGLE)) {
  1329.         xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: unhandled connector type:"
  1330.                    " %d\n", __func__, Type);
  1331.         return NULL;
  1332.     }
  1333.  
  1334.     Output = xnfcalloc(sizeof(struct rhdOutput), 1);
  1335.  
  1336.     Output->scrnIndex = rhdPtr->scrnIndex;
  1337.     Output->Id = RHD_OUTPUT_LVTMA;
  1338.  
  1339.     Output->Sense = NULL; /* not implemented in hw */
  1340.  
  1341.     if (Type == RHD_CONNECTOR_PANEL) {
  1342.         struct LVDSPrivate *Private;
  1343.  
  1344.         Output->Name = "LVDS";
  1345.  
  1346.         Output->ModeValid = LVDSModeValid;
  1347.         Output->Mode = LVDSSet;
  1348.         Output->Power = LVDSPower;
  1349.         Output->Save = LVDSSave;
  1350.         Output->Restore = LVDSRestore;
  1351.         Output->Property = LVDSPropertyControl;
  1352.         Output->Destroy = LVDSDestroy;
  1353.         Output->Private = Private =  LVDSInfoRetrieve(rhdPtr);
  1354. #ifdef NOT_YET
  1355.         if (Private->BlLevel < 0) {
  1356.             Private->BlLevel = RhdAtomSetupBacklightControlProperty(Output, &Private->WrappedPropertyCallback,
  1357.                                                                     &Private->PropertyPrivate);
  1358.             if (Private->PropertyPrivate)
  1359.                 Output->Property = LVDSPropertyWrapper;
  1360.         } else
  1361. #else
  1362.         if (Private->BlLevel >= 0)
  1363. #endif
  1364.             LVDSDebugBacklight(Output);
  1365.  
  1366.     } else {
  1367.         struct rhdTMDSBPrivate *Private = xnfcalloc(sizeof(struct rhdTMDSBPrivate), 1);
  1368.  
  1369.         Output->Name = "TMDS B";
  1370.  
  1371.         Output->ModeValid = TMDSBModeValid;
  1372.         Output->Mode = TMDSBSet;
  1373.         Output->Power = TMDSBPower;
  1374.         Output->Save = TMDSBSave;
  1375.         Output->Restore = TMDSBRestore;
  1376.         Output->Property = TMDSBPropertyControl;
  1377.         Output->Destroy = TMDSBDestroy;
  1378.  
  1379.         Private->Hdmi = RHDHdmiInit(rhdPtr, Output);
  1380.         Output->Private = Private;
  1381.  
  1382.         Private->RunsDualLink = FALSE;
  1383.         Private->Coherent = FALSE;
  1384.     }
  1385.  
  1386.     return Output;
  1387. }
  1388.