Subversion Repositories Kolibri OS

Rev

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